Browse Source

Refactor: Expand tabs to 4 spaces

Richard 10 years ago
parent
commit
83de707587
100 changed files with 28886 additions and 28891 deletions
  1. 744 744
      code/3DSConverter.cpp
  2. 446 446
      code/3DSExporter.cpp
  3. 15 15
      code/3DSExporter.h
  4. 433 433
      code/3DSHelper.h
  5. 1177 1177
      code/3DSLoader.cpp
  6. 190 190
      code/3DSLoader.h
  7. 743 743
      code/ACLoader.cpp
  8. 162 162
      code/ACLoader.h
  9. 1138 1138
      code/ASELoader.cpp
  10. 98 98
      code/ASELoader.h
  11. 1879 1879
      code/ASEParser.cpp
  12. 457 457
      code/ASEParser.h
  13. 590 590
      code/AssbinExporter.cpp
  14. 477 477
      code/AssbinLoader.cpp
  15. 1 1
      code/AssbinLoader.h
  16. 306 306
      code/Assimp.cpp
  17. 27 27
      code/AssimpCExport.cpp
  18. 523 523
      code/AssxmlExporter.cpp
  19. 467 467
      code/B3DImporter.cpp
  20. 57 57
      code/B3DImporter.h
  21. 368 368
      code/BVHLoader.cpp
  22. 70 70
      code/BVHLoader.h
  23. 388 392
      code/BaseImporter.cpp
  24. 259 259
      code/BaseImporter.h
  25. 19 19
      code/BaseProcess.cpp
  26. 172 172
      code/BaseProcess.h
  27. 90 90
      code/Bitmap.cpp
  28. 50 50
      code/Bitmap.h
  29. 79 79
      code/BlenderBMesh.cpp
  30. 40 40
      code/BlenderBMesh.h
  31. 241 241
      code/BlenderDNA.cpp
  32. 415 415
      code/BlenderDNA.h
  33. 126 126
      code/BlenderIntermediate.h
  34. 935 935
      code/BlenderLoader.cpp
  35. 134 134
      code/BlenderLoader.h
  36. 204 204
      code/BlenderModifier.cpp
  37. 48 48
      code/BlenderModifier.h
  38. 55 55
      code/BlenderScene.cpp
  39. 400 400
      code/BlenderScene.h
  40. 3 3
      code/BlenderSceneGen.h
  41. 252 252
      code/BlenderTessellator.cpp
  42. 125 125
      code/BlenderTessellator.h
  43. 199 199
      code/BlobIOSystem.h
  44. 160 160
      code/ByteSwapper.h
  45. 499 499
      code/C4DImporter.cpp
  46. 31 31
      code/C4DImporter.h
  47. 84 84
      code/CInterfaceIOWrapper.h
  48. 692 692
      code/COBLoader.cpp
  49. 76 76
      code/COBLoader.h
  50. 115 115
      code/COBScene.h
  51. 201 201
      code/CSMLoader.cpp
  52. 14 14
      code/CSMLoader.h
  53. 181 181
      code/CalcTangentsProcess.cpp
  54. 38 38
      code/CalcTangentsProcess.h
  55. 662 663
      code/ColladaExporter.cpp
  56. 59 59
      code/ColladaExporter.h
  57. 356 356
      code/ColladaHelper.h
  58. 1225 1225
      code/ColladaLoader.cpp
  59. 162 162
      code/ColladaLoader.h
  60. 1289 1289
      code/ColladaParser.cpp
  61. 190 190
      code/ColladaParser.h
  62. 386 386
      code/ComputeUVMappingProcess.cpp
  63. 72 72
      code/ComputeUVMappingProcess.h
  64. 135 135
      code/ConvertToLHProcess.cpp
  65. 54 54
      code/ConvertToLHProcess.h
  66. 115 115
      code/DXFHelper.h
  67. 543 543
      code/DXFLoader.cpp
  68. 64 64
      code/DXFLoader.h
  69. 345 345
      code/DeboneProcess.cpp
  70. 46 46
      code/DeboneProcess.h
  71. 43 43
      code/DefaultIOStream.cpp
  72. 43 43
      code/DefaultIOStream.h
  73. 51 51
      code/DefaultIOSystem.cpp
  74. 31 31
      code/DefaultIOSystem.h
  75. 221 221
      code/DefaultLogger.cpp
  76. 5 5
      code/DefaultProgressHandler.h
  77. 2 2
      code/Defines.h
  78. 36 36
      code/Exceptional.h
  79. 262 262
      code/Exporter.cpp
  80. 180 180
      code/FBXAnimation.cpp
  81. 248 248
      code/FBXBinaryTokenizer.cpp
  82. 12 12
      code/FBXCompileConfig.h
  83. 2873 2873
      code/FBXConverter.cpp
  84. 1 1
      code/FBXConverter.h
  85. 58 58
      code/FBXDeformer.cpp
  86. 434 434
      code/FBXDocument.cpp
  87. 399 399
      code/FBXDocument.h
  88. 42 42
      code/FBXDocumentUtil.cpp
  89. 38 38
      code/FBXDocumentUtil.h
  90. 82 82
      code/FBXImportSettings.h
  91. 77 77
      code/FBXImporter.cpp
  92. 23 23
      code/FBXImporter.h
  93. 148 148
      code/FBXMaterial.cpp
  94. 380 380
      code/FBXMeshGeometry.cpp
  95. 64 64
      code/FBXModel.cpp
  96. 26 26
      code/FBXNodeAttribute.cpp
  97. 486 486
      code/FBXParser.cpp
  98. 56 56
      code/FBXParser.h
  99. 108 108
      code/FBXProperties.cpp
  100. 61 61
      code/FBXProperties.h

+ 744 - 744
code/3DSConverter.cpp

@@ -60,807 +60,807 @@ using namespace Assimp;
 void Discreet3DSImporter::ReplaceDefaultMaterial()
 {
 
-	// Try to find an existing material that matches the
-	// typical default material setting:
-	// - no textures
-	// - diffuse color (in grey!)
-	// NOTE: This is here to workaround the fact that some
-	// exporters are writing a default material, too.
-	unsigned int idx = 0xcdcdcdcd;
-	for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
-	{
-		std::string s = mScene->mMaterials[i].mName;
-		for (std::string::iterator it = s.begin(); it != s.end(); ++it)
-			*it = ::tolower(*it);
-
-		if (std::string::npos == s.find("default"))continue;
-
-		if (mScene->mMaterials[i].mDiffuse.r !=
-			mScene->mMaterials[i].mDiffuse.g ||
-			mScene->mMaterials[i].mDiffuse.r !=
-			mScene->mMaterials[i].mDiffuse.b)continue;
-
-		if (mScene->mMaterials[i].sTexDiffuse.mMapName.length()   != 0	||
-			mScene->mMaterials[i].sTexBump.mMapName.length()      != 0	||
-			mScene->mMaterials[i].sTexOpacity.mMapName.length()   != 0	||
-			mScene->mMaterials[i].sTexEmissive.mMapName.length()  != 0	||
-			mScene->mMaterials[i].sTexSpecular.mMapName.length()  != 0	||
-			mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
-		{
-			continue;
-		}
-		idx = i;
-	}
-	if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
-
-	// now iterate through all meshes and through all faces and
-	// find all faces that are using the default material
-	unsigned int cnt = 0;
-	for (std::vector<D3DS::Mesh>::iterator
-		i =  mScene->mMeshes.begin();
-		i != mScene->mMeshes.end();++i)
-	{
-		for (std::vector<unsigned int>::iterator
-			a =  (*i).mFaceMaterials.begin();
-			a != (*i).mFaceMaterials.end();++a)
-		{
-			// NOTE: The additional check seems to be necessary,
-			// some exporters seem to generate invalid data here
-			if (0xcdcdcdcd == (*a))
-			{
-				(*a) = idx;
-				++cnt;
-			}
-			else if ( (*a) >= mScene->mMaterials.size())
-			{
-				(*a) = idx;
-				DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
-				++cnt;
-			}
-		}
-	}
-	if (cnt && idx == mScene->mMaterials.size())
-	{
-		// We need to create our own default material
-		D3DS::Material sMat;
-		sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
-		sMat.mName = "%%%DEFAULT";
-		mScene->mMaterials.push_back(sMat);
-
-		DefaultLogger::get()->info("3DS: Generating default material");
-	}
+    // Try to find an existing material that matches the
+    // typical default material setting:
+    // - no textures
+    // - diffuse color (in grey!)
+    // NOTE: This is here to workaround the fact that some
+    // exporters are writing a default material, too.
+    unsigned int idx = 0xcdcdcdcd;
+    for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
+    {
+        std::string s = mScene->mMaterials[i].mName;
+        for (std::string::iterator it = s.begin(); it != s.end(); ++it)
+            *it = ::tolower(*it);
+
+        if (std::string::npos == s.find("default"))continue;
+
+        if (mScene->mMaterials[i].mDiffuse.r !=
+            mScene->mMaterials[i].mDiffuse.g ||
+            mScene->mMaterials[i].mDiffuse.r !=
+            mScene->mMaterials[i].mDiffuse.b)continue;
+
+        if (mScene->mMaterials[i].sTexDiffuse.mMapName.length()   != 0  ||
+            mScene->mMaterials[i].sTexBump.mMapName.length()      != 0  ||
+            mScene->mMaterials[i].sTexOpacity.mMapName.length()   != 0  ||
+            mScene->mMaterials[i].sTexEmissive.mMapName.length()  != 0  ||
+            mScene->mMaterials[i].sTexSpecular.mMapName.length()  != 0  ||
+            mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
+        {
+            continue;
+        }
+        idx = i;
+    }
+    if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
+
+    // now iterate through all meshes and through all faces and
+    // find all faces that are using the default material
+    unsigned int cnt = 0;
+    for (std::vector<D3DS::Mesh>::iterator
+        i =  mScene->mMeshes.begin();
+        i != mScene->mMeshes.end();++i)
+    {
+        for (std::vector<unsigned int>::iterator
+            a =  (*i).mFaceMaterials.begin();
+            a != (*i).mFaceMaterials.end();++a)
+        {
+            // NOTE: The additional check seems to be necessary,
+            // some exporters seem to generate invalid data here
+            if (0xcdcdcdcd == (*a))
+            {
+                (*a) = idx;
+                ++cnt;
+            }
+            else if ( (*a) >= mScene->mMaterials.size())
+            {
+                (*a) = idx;
+                DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
+                ++cnt;
+            }
+        }
+    }
+    if (cnt && idx == mScene->mMaterials.size())
+    {
+        // We need to create our own default material
+        D3DS::Material sMat;
+        sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
+        sMat.mName = "%%%DEFAULT";
+        mScene->mMaterials.push_back(sMat);
+
+        DefaultLogger::get()->info("3DS: Generating default material");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
 void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
 {
-	for (std::vector< D3DS::Face >::iterator i =  sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
-	{
-		// check whether all indices are in range
-		for (unsigned int a = 0; a < 3;++a)
-		{
-			if ((*i).mIndices[a] >= sMesh.mPositions.size())
-			{
-				DefaultLogger::get()->warn("3DS: Vertex index overflow)");
-				(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
-			}
-			if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
-			{
-				DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
-				(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
-			}
-		}
-	}
+    for (std::vector< D3DS::Face >::iterator i =  sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
+    {
+        // check whether all indices are in range
+        for (unsigned int a = 0; a < 3;++a)
+        {
+            if ((*i).mIndices[a] >= sMesh.mPositions.size())
+            {
+                DefaultLogger::get()->warn("3DS: Vertex index overflow)");
+                (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
+            }
+            if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
+            {
+                DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
+                (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
+            }
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Generate out unique verbose format representation
 void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
 {
-	// TODO: really necessary? I don't think. Just a waste of memory and time
-	// to do it now in a separate buffer.
-
-	// Allocate output storage
-	std::vector<aiVector3D> vNew  (sMesh.mFaces.size() * 3);
-	std::vector<aiVector3D> vNew2;
-	if (sMesh.mTexCoords.size())
-		vNew2.resize(sMesh.mFaces.size() * 3);
-
-	for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
-	{
-		D3DS::Face& face = sMesh.mFaces[i];
-
-		// Positions
-		for (unsigned int a = 0; a < 3;++a,++base)
-		{
-			vNew[base] = sMesh.mPositions[face.mIndices[a]];
-			if (sMesh.mTexCoords.size())
-				vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
-
-			face.mIndices[a] = base;
-		}
-	}
-	sMesh.mPositions = vNew;
-	sMesh.mTexCoords = vNew2;
+    // TODO: really necessary? I don't think. Just a waste of memory and time
+    // to do it now in a separate buffer.
+
+    // Allocate output storage
+    std::vector<aiVector3D> vNew  (sMesh.mFaces.size() * 3);
+    std::vector<aiVector3D> vNew2;
+    if (sMesh.mTexCoords.size())
+        vNew2.resize(sMesh.mFaces.size() * 3);
+
+    for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
+    {
+        D3DS::Face& face = sMesh.mFaces[i];
+
+        // Positions
+        for (unsigned int a = 0; a < 3;++a,++base)
+        {
+            vNew[base] = sMesh.mPositions[face.mIndices[a]];
+            if (sMesh.mTexCoords.size())
+                vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
+
+            face.mIndices[a] = base;
+        }
+    }
+    sMesh.mPositions = vNew;
+    sMesh.mTexCoords = vNew2;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert a 3DS texture to texture keys in an aiMaterial
 void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
 {
-	// Setup the texture name
-	aiString tex;
-	tex.Set( texture.mMapName);
-	mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
-
-	// Setup the texture blend factor
-	if (is_not_qnan(texture.mTextureBlend))
-		mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
-
-	// Setup the texture mapping mode
-	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
-	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
-
-	// Mirroring - double the scaling values
-	// FIXME: this is not really correct ...
-	if (texture.mMapMode == aiTextureMapMode_Mirror)
-	{
-		texture.mScaleU *= 2.f;
-		texture.mScaleV *= 2.f;
-		texture.mOffsetU /= 2.f;
-		texture.mOffsetV /= 2.f;
-	}
-
-	// Setup texture UV transformations
-	mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
+    // Setup the texture name
+    aiString tex;
+    tex.Set( texture.mMapName);
+    mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
+
+    // Setup the texture blend factor
+    if (is_not_qnan(texture.mTextureBlend))
+        mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
+
+    // Setup the texture mapping mode
+    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
+    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
+
+    // Mirroring - double the scaling values
+    // FIXME: this is not really correct ...
+    if (texture.mMapMode == aiTextureMapMode_Mirror)
+    {
+        texture.mScaleU *= 2.f;
+        texture.mScaleV *= 2.f;
+        texture.mOffsetU /= 2.f;
+        texture.mOffsetV /= 2.f;
+    }
+
+    // Setup texture UV transformations
+    mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert a 3DS material to an aiMaterial
 void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
-	aiMaterial& mat)
+    aiMaterial& mat)
 {
-	// NOTE: Pass the background image to the viewer by bypassing the
-	// material system. This is an evil hack, never do it again!
-	if (0 != mBackgroundImage.length() && bHasBG)
-	{
-		aiString tex;
-		tex.Set( mBackgroundImage);
-		mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
-
-		// Be sure this is only done for the first material
-		mBackgroundImage = std::string("");
-	}
-
-	// At first add the base ambient color of the scene to the material
-	oldMat.mAmbient.r += mClrAmbient.r;
-	oldMat.mAmbient.g += mClrAmbient.g;
-	oldMat.mAmbient.b += mClrAmbient.b;
-
-	aiString name;
-	name.Set( oldMat.mName);
-	mat.AddProperty( &name, AI_MATKEY_NAME);
-
-	// Material colors
-	mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
-	mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
-	mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
-	mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
-
-	// Phong shininess and shininess strength
-	if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
-		D3DS::Discreet3DS::Metal == oldMat.mShading)
-	{
-		if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
-		{
-			oldMat.mShading = D3DS::Discreet3DS::Gouraud;
-		}
-		else
-		{
-			mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
-			mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
-		}
-	}
-
-	// Opacity
-	mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
-
-	// Bump height scaling
-	mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
-
-	// Two sided rendering?
-	if (oldMat.mTwoSided)
-	{
-		int i = 1;
-		mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
-	}
-
-	// Shading mode
-	aiShadingMode eShading = aiShadingMode_NoShading;
-	switch (oldMat.mShading)
-	{
-		case D3DS::Discreet3DS::Flat:
-			eShading = aiShadingMode_Flat; break;
-
-		// I don't know what "Wire" shading should be,
-		// assume it is simple lambertian diffuse shading
-		case D3DS::Discreet3DS::Wire:
-			{
-				// Set the wireframe flag
-				unsigned int iWire = 1;
-				mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
-			}
-
-		case D3DS::Discreet3DS::Gouraud:
-			eShading = aiShadingMode_Gouraud; break;
-
-		// assume cook-torrance shading for metals.
-		case D3DS::Discreet3DS::Phong :
-			eShading = aiShadingMode_Phong; break;
-
-		case D3DS::Discreet3DS::Metal :
-			eShading = aiShadingMode_CookTorrance; break;
-
-			// FIX to workaround a warning with GCC 4 who complained
-			// about a missing case Blinn: here - Blinn isn't a valid
-			// value in the 3DS Loader, it is just needed for ASE
-		case D3DS::Discreet3DS::Blinn :
-			eShading = aiShadingMode_Blinn; break;
-	}
-	mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
-
-	// DIFFUSE texture
-	if( oldMat.sTexDiffuse.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
-
-	// SPECULAR texture
-	if( oldMat.sTexSpecular.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
-
-	// OPACITY texture
-	if( oldMat.sTexOpacity.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
-
-	// EMISSIVE texture
-	if( oldMat.sTexEmissive.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
-
-	// BUMP texture
-	if( oldMat.sTexBump.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
-
-	// SHININESS texture
-	if( oldMat.sTexShininess.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
-
-	// REFLECTION texture
-	if( oldMat.sTexReflective.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
-
-	// Store the name of the material itself, too
-	if( oldMat.mName.length())	{
-		aiString tex;
-		tex.Set( oldMat.mName);
-		mat.AddProperty( &tex, AI_MATKEY_NAME);
-	}
+    // NOTE: Pass the background image to the viewer by bypassing the
+    // material system. This is an evil hack, never do it again!
+    if (0 != mBackgroundImage.length() && bHasBG)
+    {
+        aiString tex;
+        tex.Set( mBackgroundImage);
+        mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
+
+        // Be sure this is only done for the first material
+        mBackgroundImage = std::string("");
+    }
+
+    // At first add the base ambient color of the scene to the material
+    oldMat.mAmbient.r += mClrAmbient.r;
+    oldMat.mAmbient.g += mClrAmbient.g;
+    oldMat.mAmbient.b += mClrAmbient.b;
+
+    aiString name;
+    name.Set( oldMat.mName);
+    mat.AddProperty( &name, AI_MATKEY_NAME);
+
+    // Material colors
+    mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
+    mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
+    mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
+    mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
+
+    // Phong shininess and shininess strength
+    if (D3DS::Discreet3DS::Phong == oldMat.mShading ||
+        D3DS::Discreet3DS::Metal == oldMat.mShading)
+    {
+        if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
+        {
+            oldMat.mShading = D3DS::Discreet3DS::Gouraud;
+        }
+        else
+        {
+            mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
+            mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
+        }
+    }
+
+    // Opacity
+    mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
+
+    // Bump height scaling
+    mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
+
+    // Two sided rendering?
+    if (oldMat.mTwoSided)
+    {
+        int i = 1;
+        mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
+    }
+
+    // Shading mode
+    aiShadingMode eShading = aiShadingMode_NoShading;
+    switch (oldMat.mShading)
+    {
+        case D3DS::Discreet3DS::Flat:
+            eShading = aiShadingMode_Flat; break;
+
+        // I don't know what "Wire" shading should be,
+        // assume it is simple lambertian diffuse shading
+        case D3DS::Discreet3DS::Wire:
+            {
+                // Set the wireframe flag
+                unsigned int iWire = 1;
+                mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
+            }
+
+        case D3DS::Discreet3DS::Gouraud:
+            eShading = aiShadingMode_Gouraud; break;
+
+        // assume cook-torrance shading for metals.
+        case D3DS::Discreet3DS::Phong :
+            eShading = aiShadingMode_Phong; break;
+
+        case D3DS::Discreet3DS::Metal :
+            eShading = aiShadingMode_CookTorrance; break;
+
+            // FIX to workaround a warning with GCC 4 who complained
+            // about a missing case Blinn: here - Blinn isn't a valid
+            // value in the 3DS Loader, it is just needed for ASE
+        case D3DS::Discreet3DS::Blinn :
+            eShading = aiShadingMode_Blinn; break;
+    }
+    mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
+
+    // DIFFUSE texture
+    if( oldMat.sTexDiffuse.mMapName.length() > 0)
+        CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
+
+    // SPECULAR texture
+    if( oldMat.sTexSpecular.mMapName.length() > 0)
+        CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
+
+    // OPACITY texture
+    if( oldMat.sTexOpacity.mMapName.length() > 0)
+        CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
+
+    // EMISSIVE texture
+    if( oldMat.sTexEmissive.mMapName.length() > 0)
+        CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
+
+    // BUMP texture
+    if( oldMat.sTexBump.mMapName.length() > 0)
+        CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
+
+    // SHININESS texture
+    if( oldMat.sTexShininess.mMapName.length() > 0)
+        CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
+
+    // REFLECTION texture
+    if( oldMat.sTexReflective.mMapName.length() > 0)
+        CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
+
+    // Store the name of the material itself, too
+    if( oldMat.mName.length())  {
+        aiString tex;
+        tex.Set( oldMat.mName);
+        mat.AddProperty( &tex, AI_MATKEY_NAME);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Split meshes by their materials and generate output aiMesh'es
 void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
 {
-	std::vector<aiMesh*> avOutMeshes;
-	avOutMeshes.reserve(mScene->mMeshes.size() * 2);
-
-	unsigned int iFaceCnt = 0,num = 0;
-	aiString name;
-
-	// we need to split all meshes by their materials
-	for (std::vector<D3DS::Mesh>::iterator i =  mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i)	{
-		boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
-
-		name.length = ASSIMP_itoa10(name.data,num++);
-
-		unsigned int iNum = 0;
-		for (std::vector<unsigned int>::const_iterator a =  (*i).mFaceMaterials.begin();
-			a != (*i).mFaceMaterials.end();++a,++iNum)
-		{
-			aiSplit[*a].push_back(iNum);
-		}
-		// now generate submeshes
-		for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
-		{
-			if (aiSplit[p].empty())	{
-				continue;
-			}
-			aiMesh* meshOut = new aiMesh();
-			meshOut->mName = name;
-			meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
-
-			// be sure to setup the correct material index
-			meshOut->mMaterialIndex = p;
-
-			// use the color data as temporary storage
-			meshOut->mColors[0] = (aiColor4D*)(&*i);
-			avOutMeshes.push_back(meshOut);
-
-			// convert vertices
-			meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
-			meshOut->mNumVertices = meshOut->mNumFaces*3;
-
-			// allocate enough storage for faces
-			meshOut->mFaces = new aiFace[meshOut->mNumFaces];
-			iFaceCnt += meshOut->mNumFaces;
-
-			meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
-			meshOut->mNormals  = new aiVector3D[meshOut->mNumVertices];
-			if ((*i).mTexCoords.size())
-			{
-				meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
-			}
-			for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
-			{
-				unsigned int index = aiSplit[p][q];
-				aiFace& face = meshOut->mFaces[q];
-
-				face.mIndices = new unsigned int[3];
-				face.mNumIndices = 3;
-
-				for (unsigned int a = 0; a < 3;++a,++base)
-				{
-					unsigned int idx = (*i).mFaces[index].mIndices[a];
-					meshOut->mVertices[base]  = (*i).mPositions[idx];
-					meshOut->mNormals [base]  = (*i).mNormals[idx];
-
-					if ((*i).mTexCoords.size())
-						meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
-
-					face.mIndices[a] = base;
-				}
-			}
-		}
-	}
-
-	// Copy them to the output array
-	pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
-	pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
-	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
-		pcOut->mMeshes[a] = avOutMeshes[a];
-	}
-
-	// We should have at least one face here
-	if (!iFaceCnt) {
-		throw DeadlyImportError("No faces loaded. The mesh is empty");
-	}
+    std::vector<aiMesh*> avOutMeshes;
+    avOutMeshes.reserve(mScene->mMeshes.size() * 2);
+
+    unsigned int iFaceCnt = 0,num = 0;
+    aiString name;
+
+    // we need to split all meshes by their materials
+    for (std::vector<D3DS::Mesh>::iterator i =  mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i)    {
+        boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
+
+        name.length = ASSIMP_itoa10(name.data,num++);
+
+        unsigned int iNum = 0;
+        for (std::vector<unsigned int>::const_iterator a =  (*i).mFaceMaterials.begin();
+            a != (*i).mFaceMaterials.end();++a,++iNum)
+        {
+            aiSplit[*a].push_back(iNum);
+        }
+        // now generate submeshes
+        for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
+        {
+            if (aiSplit[p].empty()) {
+                continue;
+            }
+            aiMesh* meshOut = new aiMesh();
+            meshOut->mName = name;
+            meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+            // be sure to setup the correct material index
+            meshOut->mMaterialIndex = p;
+
+            // use the color data as temporary storage
+            meshOut->mColors[0] = (aiColor4D*)(&*i);
+            avOutMeshes.push_back(meshOut);
+
+            // convert vertices
+            meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
+            meshOut->mNumVertices = meshOut->mNumFaces*3;
+
+            // allocate enough storage for faces
+            meshOut->mFaces = new aiFace[meshOut->mNumFaces];
+            iFaceCnt += meshOut->mNumFaces;
+
+            meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
+            meshOut->mNormals  = new aiVector3D[meshOut->mNumVertices];
+            if ((*i).mTexCoords.size())
+            {
+                meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
+            }
+            for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
+            {
+                unsigned int index = aiSplit[p][q];
+                aiFace& face = meshOut->mFaces[q];
+
+                face.mIndices = new unsigned int[3];
+                face.mNumIndices = 3;
+
+                for (unsigned int a = 0; a < 3;++a,++base)
+                {
+                    unsigned int idx = (*i).mFaces[index].mIndices[a];
+                    meshOut->mVertices[base]  = (*i).mPositions[idx];
+                    meshOut->mNormals [base]  = (*i).mNormals[idx];
+
+                    if ((*i).mTexCoords.size())
+                        meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
+
+                    face.mIndices[a] = base;
+                }
+            }
+        }
+    }
+
+    // Copy them to the output array
+    pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
+    pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
+    for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
+        pcOut->mMeshes[a] = avOutMeshes[a];
+    }
+
+    // We should have at least one face here
+    if (!iFaceCnt) {
+        throw DeadlyImportError("No faces loaded. The mesh is empty");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Add a node to the scenegraph and setup its final transformation
 void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
-	D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
+    D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
 {
-	std::vector<unsigned int> iArray;
-	iArray.reserve(3);
-
-	aiMatrix4x4 abs;
-
-	// Find all meshes with the same name as the node
-	for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
-	{
-		const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
-		ai_assert(NULL != pcMesh);
-
-		if (pcIn->mName == pcMesh->mName)
-			iArray.push_back(a);
-	}
-	if (!iArray.empty())
-	{
-		// The matrix should be identical for all meshes with the
-		// same name. It HAS to be identical for all meshes .....
-		D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
-
-		// Compute the inverse of the transformation matrix to move the
-		// vertices back to their relative and local space
-		aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
-		mInv.Inverse();mInvTransposed.Transpose();
-		aiVector3D pivot = pcIn->vPivot;
-
-		pcOut->mNumMeshes = (unsigned int)iArray.size();
-		pcOut->mMeshes = new unsigned int[iArray.size()];
-		for (unsigned int i = 0;i < iArray.size();++i)	{
-			const unsigned int iIndex = iArray[i];
-			aiMesh* const mesh = pcSOut->mMeshes[iIndex];
-
-			if (mesh->mColors[1] == NULL)
-			{
-				// Transform the vertices back into their local space
-				// fixme: consider computing normals after this, so we don't need to transform them
-				const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices;
-				aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
-
-				for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
-					*pvCurrent = mInv * (*pvCurrent);
-					*t2 = mInvTransposed * (*t2);
-				}
-
-				// Handle negative transformation matrix determinant -> invert vertex x
-				if (imesh->mMat.Determinant() < 0.0f)
-				{
-					/* we *must* have normals */
-					for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
-						pvCurrent->x *= -1.f;
-						t2->x *= -1.f;
-					}
-					DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
-				}
-
-				// Handle pivot point
-				if (pivot.x || pivot.y || pivot.z)
-				{
-					for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent)	{
-						*pvCurrent -= pivot;
-					}
-				}
-
-				mesh->mColors[1] = (aiColor4D*)1;
-			}
-			else
-				mesh->mColors[1] = (aiColor4D*)1;
-
-			// Setup the mesh index
-			pcOut->mMeshes[i] = iIndex;
-		}
-	}
-
-	// Setup the name of the node
-	// First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
-	if (pcIn->mInstanceNumber > 1)
-	{
-		char tmp[12];
-		ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
-		std::string tempStr = pcIn->mName + "_inst_";
-		tempStr += tmp;
-		pcOut->mName.Set(tempStr);
-	}
-	else
-		pcOut->mName.Set(pcIn->mName);
-
-	// Now build the transformation matrix of the node
-	// ROTATION
-	if (pcIn->aRotationKeys.size()){
-
-		// FIX to get to Assimp's quaternion conventions
-		for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
-			(*it).mValue.w *= -1.f;
-		}
-
-		pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
-	}
-	else if (pcIn->aCameraRollKeys.size())
-	{
-		aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
-			pcOut->mTransformation);
-	}
-
-	// SCALING
-	aiMatrix4x4& m = pcOut->mTransformation;
-	if (pcIn->aScalingKeys.size())
-	{
-		const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
-		m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
-		m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
-		m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
-	}
-
-	// TRANSLATION
-	if (pcIn->aPositionKeys.size())
-	{
-		const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
-		m.a4 += v.x;
-		m.b4 += v.y;
-		m.c4 += v.z;
-	}
-
-	// Generate animation channels for the node
-	if (pcIn->aPositionKeys.size()  > 1  || pcIn->aRotationKeys.size()   > 1 ||
-		pcIn->aScalingKeys.size()   > 1  || pcIn->aCameraRollKeys.size() > 1 ||
-		pcIn->aTargetPositionKeys.size() > 1)
-	{
-		aiAnimation* anim = pcSOut->mAnimations[0];
-		ai_assert(NULL != anim);
-
-		if (pcIn->aCameraRollKeys.size() > 1)
-		{
-			DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
-
-			// Camera roll keys - in fact they're just rotations
-			// around the camera's z axis. The angles are given
-			// in degrees (and they're clockwise).
-			pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
-			for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
-			{
-				aiQuatKey&  q = pcIn->aRotationKeys[i];
-				aiFloatKey& f = pcIn->aCameraRollKeys[i];
-
-				q.mTime  = f.mTime;
-
-				// FIX to get to Assimp quaternion conventions
-				q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
-			}
-		}
+    std::vector<unsigned int> iArray;
+    iArray.reserve(3);
+
+    aiMatrix4x4 abs;
+
+    // Find all meshes with the same name as the node
+    for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
+    {
+        const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
+        ai_assert(NULL != pcMesh);
+
+        if (pcIn->mName == pcMesh->mName)
+            iArray.push_back(a);
+    }
+    if (!iArray.empty())
+    {
+        // The matrix should be identical for all meshes with the
+        // same name. It HAS to be identical for all meshes .....
+        D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
+
+        // Compute the inverse of the transformation matrix to move the
+        // vertices back to their relative and local space
+        aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
+        mInv.Inverse();mInvTransposed.Transpose();
+        aiVector3D pivot = pcIn->vPivot;
+
+        pcOut->mNumMeshes = (unsigned int)iArray.size();
+        pcOut->mMeshes = new unsigned int[iArray.size()];
+        for (unsigned int i = 0;i < iArray.size();++i)  {
+            const unsigned int iIndex = iArray[i];
+            aiMesh* const mesh = pcSOut->mMeshes[iIndex];
+
+            if (mesh->mColors[1] == NULL)
+            {
+                // Transform the vertices back into their local space
+                // fixme: consider computing normals after this, so we don't need to transform them
+                const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices;
+                aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
+
+                for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
+                    *pvCurrent = mInv * (*pvCurrent);
+                    *t2 = mInvTransposed * (*t2);
+                }
+
+                // Handle negative transformation matrix determinant -> invert vertex x
+                if (imesh->mMat.Determinant() < 0.0f)
+                {
+                    /* we *must* have normals */
+                    for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
+                        pvCurrent->x *= -1.f;
+                        t2->x *= -1.f;
+                    }
+                    DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
+                }
+
+                // Handle pivot point
+                if (pivot.x || pivot.y || pivot.z)
+                {
+                    for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent)  {
+                        *pvCurrent -= pivot;
+                    }
+                }
+
+                mesh->mColors[1] = (aiColor4D*)1;
+            }
+            else
+                mesh->mColors[1] = (aiColor4D*)1;
+
+            // Setup the mesh index
+            pcOut->mMeshes[i] = iIndex;
+        }
+    }
+
+    // Setup the name of the node
+    // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
+    if (pcIn->mInstanceNumber > 1)
+    {
+        char tmp[12];
+        ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
+        std::string tempStr = pcIn->mName + "_inst_";
+        tempStr += tmp;
+        pcOut->mName.Set(tempStr);
+    }
+    else
+        pcOut->mName.Set(pcIn->mName);
+
+    // Now build the transformation matrix of the node
+    // ROTATION
+    if (pcIn->aRotationKeys.size()){
+
+        // FIX to get to Assimp's quaternion conventions
+        for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
+            (*it).mValue.w *= -1.f;
+        }
+
+        pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
+    }
+    else if (pcIn->aCameraRollKeys.size())
+    {
+        aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
+            pcOut->mTransformation);
+    }
+
+    // SCALING
+    aiMatrix4x4& m = pcOut->mTransformation;
+    if (pcIn->aScalingKeys.size())
+    {
+        const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
+        m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
+        m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
+        m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
+    }
+
+    // TRANSLATION
+    if (pcIn->aPositionKeys.size())
+    {
+        const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
+        m.a4 += v.x;
+        m.b4 += v.y;
+        m.c4 += v.z;
+    }
+
+    // Generate animation channels for the node
+    if (pcIn->aPositionKeys.size()  > 1  || pcIn->aRotationKeys.size()   > 1 ||
+        pcIn->aScalingKeys.size()   > 1  || pcIn->aCameraRollKeys.size() > 1 ||
+        pcIn->aTargetPositionKeys.size() > 1)
+    {
+        aiAnimation* anim = pcSOut->mAnimations[0];
+        ai_assert(NULL != anim);
+
+        if (pcIn->aCameraRollKeys.size() > 1)
+        {
+            DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
+
+            // Camera roll keys - in fact they're just rotations
+            // around the camera's z axis. The angles are given
+            // in degrees (and they're clockwise).
+            pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
+            for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
+            {
+                aiQuatKey&  q = pcIn->aRotationKeys[i];
+                aiFloatKey& f = pcIn->aCameraRollKeys[i];
+
+                q.mTime  = f.mTime;
+
+                // FIX to get to Assimp quaternion conventions
+                q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
+            }
+        }
 #if 0
-		if (pcIn->aTargetPositionKeys.size() > 1)
-		{
-			DefaultLogger::get()->debug("3DS: Converting target track ...");
-
-			// Camera or spot light - need to convert the separate
-			// target position channel to our representation
-			TargetAnimationHelper helper;
-
-			if (pcIn->aPositionKeys.empty())
-			{
-				// We can just pass zero here ...
-				helper.SetFixedMainAnimationChannel(aiVector3D());
-			}
-			else  helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
-			helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
-
-			// Do the conversion
-			std::vector<aiVectorKey> distanceTrack;
-			helper.Process(&distanceTrack);
-
-			// Now add a new node as child, name it <ourName>.Target
-			// and assign the distance track to it. This is that the
-			// information where the target is and how it moves is
-			// not lost
-			D3DS::Node* nd = new D3DS::Node();
-			pcIn->push_back(nd);
-
-			nd->mName = pcIn->mName + ".Target";
-
-			aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
-			nda->mNodeName.Set(nd->mName);
-
-			nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
-			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
-			::memcpy(nda->mPositionKeys,&distanceTrack[0],
-				sizeof(aiVectorKey)*nda->mNumPositionKeys);
-		}
+        if (pcIn->aTargetPositionKeys.size() > 1)
+        {
+            DefaultLogger::get()->debug("3DS: Converting target track ...");
+
+            // Camera or spot light - need to convert the separate
+            // target position channel to our representation
+            TargetAnimationHelper helper;
+
+            if (pcIn->aPositionKeys.empty())
+            {
+                // We can just pass zero here ...
+                helper.SetFixedMainAnimationChannel(aiVector3D());
+            }
+            else  helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
+            helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
+
+            // Do the conversion
+            std::vector<aiVectorKey> distanceTrack;
+            helper.Process(&distanceTrack);
+
+            // Now add a new node as child, name it <ourName>.Target
+            // and assign the distance track to it. This is that the
+            // information where the target is and how it moves is
+            // not lost
+            D3DS::Node* nd = new D3DS::Node();
+            pcIn->push_back(nd);
+
+            nd->mName = pcIn->mName + ".Target";
+
+            aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
+            nda->mNodeName.Set(nd->mName);
+
+            nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
+            nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
+            ::memcpy(nda->mPositionKeys,&distanceTrack[0],
+                sizeof(aiVectorKey)*nda->mNumPositionKeys);
+        }
 #endif
 
-		// Cameras or lights define their transformation in their parent node and in the
-		// corresponding light or camera chunks. However, we read and process the latter
-		// to to be able to return valid cameras/lights even if no scenegraph is given.
-		for (unsigned int n = 0; n < pcSOut->mNumCameras;++n)	{
-			if (pcSOut->mCameras[n]->mName == pcOut->mName) {
-				pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
-			}
-		}
-		for (unsigned int n = 0; n < pcSOut->mNumLights;++n)	{
-			if (pcSOut->mLights[n]->mName == pcOut->mName) {
-				pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
-			}
-		}
-
-		// Allocate a new node anim and setup its name
-		aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
-		nda->mNodeName.Set(pcIn->mName);
-
-		// POSITION keys
-		if (pcIn->aPositionKeys.size()  > 0)
-		{
-			nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
-			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
-			::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
-				sizeof(aiVectorKey)*nda->mNumPositionKeys);
-		}
-
-		// ROTATION keys
-		if (pcIn->aRotationKeys.size()  > 0)
-		{
-			nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
-			nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
-
-			// Rotations are quaternion offsets
-			aiQuaternion abs;
-			for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
-			{
-				const aiQuatKey& q = pcIn->aRotationKeys[n];
-
-				abs = (n ? abs * q.mValue : q.mValue);
-				nda->mRotationKeys[n].mTime  = q.mTime;
-				nda->mRotationKeys[n].mValue = abs.Normalize();
-			}
-		}
-
-		// SCALING keys
-		if (pcIn->aScalingKeys.size()  > 0)
-		{
-			nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
-			nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
-			::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
-				sizeof(aiVectorKey)*nda->mNumScalingKeys);
-		}
-	}
-
-	// Allocate storage for children
-	pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
-	pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
-
-	// Recursively process all children
-	const unsigned int size = pcIn->mChildren.size();
-	for (unsigned int i = 0; i < size;++i)
-	{
-		pcOut->mChildren[i] = new aiNode();
-		pcOut->mChildren[i]->mParent = pcOut;
-		AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
-	}
+        // Cameras or lights define their transformation in their parent node and in the
+        // corresponding light or camera chunks. However, we read and process the latter
+        // to to be able to return valid cameras/lights even if no scenegraph is given.
+        for (unsigned int n = 0; n < pcSOut->mNumCameras;++n)   {
+            if (pcSOut->mCameras[n]->mName == pcOut->mName) {
+                pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
+            }
+        }
+        for (unsigned int n = 0; n < pcSOut->mNumLights;++n)    {
+            if (pcSOut->mLights[n]->mName == pcOut->mName) {
+                pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
+            }
+        }
+
+        // Allocate a new node anim and setup its name
+        aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
+        nda->mNodeName.Set(pcIn->mName);
+
+        // POSITION keys
+        if (pcIn->aPositionKeys.size()  > 0)
+        {
+            nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
+            nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
+            ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
+                sizeof(aiVectorKey)*nda->mNumPositionKeys);
+        }
+
+        // ROTATION keys
+        if (pcIn->aRotationKeys.size()  > 0)
+        {
+            nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
+            nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
+
+            // Rotations are quaternion offsets
+            aiQuaternion abs;
+            for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
+            {
+                const aiQuatKey& q = pcIn->aRotationKeys[n];
+
+                abs = (n ? abs * q.mValue : q.mValue);
+                nda->mRotationKeys[n].mTime  = q.mTime;
+                nda->mRotationKeys[n].mValue = abs.Normalize();
+            }
+        }
+
+        // SCALING keys
+        if (pcIn->aScalingKeys.size()  > 0)
+        {
+            nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
+            nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
+            ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
+                sizeof(aiVectorKey)*nda->mNumScalingKeys);
+        }
+    }
+
+    // Allocate storage for children
+    pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
+    pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
+
+    // Recursively process all children
+    const unsigned int size = pcIn->mChildren.size();
+    for (unsigned int i = 0; i < size;++i)
+    {
+        pcOut->mChildren[i] = new aiNode();
+        pcOut->mChildren[i]->mParent = pcOut;
+        AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Find out how many node animation channels we'll have finally
 void CountTracks(D3DS::Node* node, unsigned int& cnt)
 {
-	//////////////////////////////////////////////////////////////////////////////
-	// We will never generate more than one channel for a node, so
-	// this is rather easy here.
-
-	if (node->aPositionKeys.size()  > 1  || node->aRotationKeys.size()   > 1   ||
-		node->aScalingKeys.size()   > 1  || node->aCameraRollKeys.size() > 1 ||
-		node->aTargetPositionKeys.size()  > 1)
-	{
-		++cnt;
-
-		// account for the additional channel for the camera/spotlight target position
-		if (node->aTargetPositionKeys.size()  > 1)++cnt;
-	}
-
-	// Recursively process all children
-	for (unsigned int i = 0; i < node->mChildren.size();++i)
-		CountTracks(node->mChildren[i],cnt);
+    //////////////////////////////////////////////////////////////////////////////
+    // We will never generate more than one channel for a node, so
+    // this is rather easy here.
+
+    if (node->aPositionKeys.size()  > 1  || node->aRotationKeys.size()   > 1   ||
+        node->aScalingKeys.size()   > 1  || node->aCameraRollKeys.size() > 1 ||
+        node->aTargetPositionKeys.size()  > 1)
+    {
+        ++cnt;
+
+        // account for the additional channel for the camera/spotlight target position
+        if (node->aTargetPositionKeys.size()  > 1)++cnt;
+    }
+
+    // Recursively process all children
+    for (unsigned int i = 0; i < node->mChildren.size();++i)
+        CountTracks(node->mChildren[i],cnt);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Generate the output node graph
 void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
 {
-	pcOut->mRootNode = new aiNode();
-	if (0 == mRootNode->mChildren.size())
-	{
-		//////////////////////////////////////////////////////////////////////////////
-		// It seems the file is so messed up that it has not even a hierarchy.
-		// generate a flat hiearachy which looks like this:
-		//
-		//                ROOT_NODE
-		//                   |
-		//   ----------------------------------------
-		//   |       |       |            |         |
-		// MESH_0  MESH_1  MESH_2  ...  MESH_N    CAMERA_0 ....
-		//
-		DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
-
-		pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
-			mScene->mCameras.size() + mScene->mLights.size();
-
-		pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
-		pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
-
-		// Build dummy nodes for all meshes
-		unsigned int a = 0;
-		for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
-		{
-			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
-			pcNode->mParent = pcOut->mRootNode;
-			pcNode->mMeshes = new unsigned int[1];
-			pcNode->mMeshes[0] = i;
-			pcNode->mNumMeshes = 1;
-
-			// Build a name for the node
-			pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%u",i);
-		}
-
-		// Build dummy nodes for all cameras
-		for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
-		{
-			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
-			pcNode->mParent = pcOut->mRootNode;
-
-			// Build a name for the node
-			pcNode->mName = mScene->mCameras[i]->mName;
-		}
-
-		// Build dummy nodes for all lights
-		for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
-		{
-			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
-			pcNode->mParent = pcOut->mRootNode;
-
-			// Build a name for the node
-			pcNode->mName = mScene->mLights[i]->mName;
-		}
-	}
-	else
-	{
-		// First of all: find out how many scaling, rotation and translation
-		// animation tracks we'll have afterwards
-		unsigned int numChannel = 0;
-		CountTracks(mRootNode,numChannel);
-
-		if (numChannel)
-		{
-			// Allocate a primary animation channel
-			pcOut->mNumAnimations = 1;
-			pcOut->mAnimations    = new aiAnimation*[1];
-			aiAnimation* anim     = pcOut->mAnimations[0] = new aiAnimation();
-
-			anim->mName.Set("3DSMasterAnim");
-
-			// Allocate enough storage for all node animation channels,
-			// but don't set the mNumChannels member - we'll use it to
-			// index into the array
-			anim->mChannels = new aiNodeAnim*[numChannel];
-		}
-
-		aiMatrix4x4 m;
-		AddNodeToGraph(pcOut,  pcOut->mRootNode, mRootNode,m);
-	}
-
-	// We used the first and second vertex color set to store some temporary values so we need to cleanup here
-	for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
-	{
-		pcOut->mMeshes[a]->mColors[0] = NULL;
-		pcOut->mMeshes[a]->mColors[1] = NULL;
-	}
-
-	pcOut->mRootNode->mTransformation = aiMatrix4x4(
-		1.f,0.f,0.f,0.f,
-		0.f,0.f,1.f,0.f,
-		0.f,-1.f,0.f,0.f,
-		0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
-
-	// If the root node is unnamed name it "<3DSRoot>"
-	if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
-		(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
-	{
-		pcOut->mRootNode->mName.Set("<3DSRoot>");
-	}
+    pcOut->mRootNode = new aiNode();
+    if (0 == mRootNode->mChildren.size())
+    {
+        //////////////////////////////////////////////////////////////////////////////
+        // It seems the file is so messed up that it has not even a hierarchy.
+        // generate a flat hiearachy which looks like this:
+        //
+        //                ROOT_NODE
+        //                   |
+        //   ----------------------------------------
+        //   |       |       |            |         |
+        // MESH_0  MESH_1  MESH_2  ...  MESH_N    CAMERA_0 ....
+        //
+        DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
+
+        pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
+            mScene->mCameras.size() + mScene->mLights.size();
+
+        pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
+        pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
+
+        // Build dummy nodes for all meshes
+        unsigned int a = 0;
+        for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
+        {
+            aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
+            pcNode->mParent = pcOut->mRootNode;
+            pcNode->mMeshes = new unsigned int[1];
+            pcNode->mMeshes[0] = i;
+            pcNode->mNumMeshes = 1;
+
+            // Build a name for the node
+            pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%u",i);
+        }
+
+        // Build dummy nodes for all cameras
+        for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
+        {
+            aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
+            pcNode->mParent = pcOut->mRootNode;
+
+            // Build a name for the node
+            pcNode->mName = mScene->mCameras[i]->mName;
+        }
+
+        // Build dummy nodes for all lights
+        for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
+        {
+            aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
+            pcNode->mParent = pcOut->mRootNode;
+
+            // Build a name for the node
+            pcNode->mName = mScene->mLights[i]->mName;
+        }
+    }
+    else
+    {
+        // First of all: find out how many scaling, rotation and translation
+        // animation tracks we'll have afterwards
+        unsigned int numChannel = 0;
+        CountTracks(mRootNode,numChannel);
+
+        if (numChannel)
+        {
+            // Allocate a primary animation channel
+            pcOut->mNumAnimations = 1;
+            pcOut->mAnimations    = new aiAnimation*[1];
+            aiAnimation* anim     = pcOut->mAnimations[0] = new aiAnimation();
+
+            anim->mName.Set("3DSMasterAnim");
+
+            // Allocate enough storage for all node animation channels,
+            // but don't set the mNumChannels member - we'll use it to
+            // index into the array
+            anim->mChannels = new aiNodeAnim*[numChannel];
+        }
+
+        aiMatrix4x4 m;
+        AddNodeToGraph(pcOut,  pcOut->mRootNode, mRootNode,m);
+    }
+
+    // We used the first and second vertex color set to store some temporary values so we need to cleanup here
+    for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
+    {
+        pcOut->mMeshes[a]->mColors[0] = NULL;
+        pcOut->mMeshes[a]->mColors[1] = NULL;
+    }
+
+    pcOut->mRootNode->mTransformation = aiMatrix4x4(
+        1.f,0.f,0.f,0.f,
+        0.f,0.f,1.f,0.f,
+        0.f,-1.f,0.f,0.f,
+        0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
+
+    // If the root node is unnamed name it "<3DSRoot>"
+    if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
+        (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
+    {
+        pcOut->mRootNode->mName.Set("<3DSRoot>");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert all meshes in the scene and generate the final output scene.
 void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
 {
-	// Allocate enough storage for all output materials
-	pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
-	pcOut->mMaterials    = new aiMaterial*[pcOut->mNumMaterials];
-
-	//  ... and convert the 3DS materials to aiMaterial's
-	for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
-	{
-		aiMaterial* pcNew = new aiMaterial();
-		ConvertMaterial(mScene->mMaterials[i],*pcNew);
-		pcOut->mMaterials[i] = pcNew;
-	}
-
-	// Generate the output mesh list
-	ConvertMeshes(pcOut);
-
-	// Now copy all light sources to the output scene
-	pcOut->mNumLights = (unsigned int)mScene->mLights.size();
-	if (pcOut->mNumLights)
-	{
-		pcOut->mLights = new aiLight*[pcOut->mNumLights];
-		::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
-	}
-
-	// Now copy all cameras to the output scene
-	pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
-	if (pcOut->mNumCameras)
-	{
-		pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
-		::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
-	}
+    // Allocate enough storage for all output materials
+    pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
+    pcOut->mMaterials    = new aiMaterial*[pcOut->mNumMaterials];
+
+    //  ... and convert the 3DS materials to aiMaterial's
+    for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
+    {
+        aiMaterial* pcNew = new aiMaterial();
+        ConvertMaterial(mScene->mMaterials[i],*pcNew);
+        pcOut->mMaterials[i] = pcNew;
+    }
+
+    // Generate the output mesh list
+    ConvertMeshes(pcOut);
+
+    // Now copy all light sources to the output scene
+    pcOut->mNumLights = (unsigned int)mScene->mLights.size();
+    if (pcOut->mNumLights)
+    {
+        pcOut->mLights = new aiLight*[pcOut->mNumLights];
+        ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
+    }
+
+    // Now copy all cameras to the output scene
+    pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
+    if (pcOut->mNumCameras)
+    {
+        pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
+        ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
+    }
 }
 
 #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER

+ 446 - 446
code/3DSExporter.cpp

@@ -53,129 +53,129 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory>
 
 using namespace Assimp;
-namespace Assimp	{
+namespace Assimp    {
 
 namespace {
 
-	//////////////////////////////////////////////////////////////////////////////////////
-	// Scope utility to write a 3DS file chunk.
-	//
-	// Upon construction, the chunk header is written with the chunk type (flags)
-	// filled out, but the chunk size left empty. Upon destruction, the correct chunk
-	// size based on the then-position of the output stream cursor is filled in.
-	class ChunkWriter {
-		enum {
-			  CHUNK_SIZE_NOT_SET = 0xdeadbeef
-			, SIZE_OFFSET        = 2
-		};
-	public:
-
-		ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
-			: writer(writer)
-		{
-			chunk_start_pos = writer.GetCurrentPos();
-			writer.PutU2(chunk_type);
-			writer.PutU4(CHUNK_SIZE_NOT_SET);
-		}
-
-		~ChunkWriter() {
-			std::size_t head_pos = writer.GetCurrentPos();
-
-			ai_assert(head_pos > chunk_start_pos);
-			const std::size_t chunk_size = head_pos - chunk_start_pos;
-
-			writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
-			writer.PutU4(chunk_size);
-			writer.SetCurrentPos(head_pos);
-		}
-
-	private:
-		StreamWriterLE& writer;
-		std::size_t chunk_start_pos;
-	};
-
-
-	// Return an unique name for a given |mesh| attached to |node| that
-	// preserves the mesh's given name if it has one. |index| is the index
-	// of the mesh in |aiScene::mMeshes|.
-	std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
-		static const std::string underscore = "_";
-		char postfix[10] = {0};
-		ASSIMP_itoa10(postfix, index);
-
-		std::string result = node.mName.C_Str();
-		if (mesh.mName.length > 0) {
-			result += underscore + mesh.mName.C_Str();
-		}
-		return result + underscore + postfix;
-	}
-
-	// Return an unique name for a given |mat| with original position |index|
-	// in |aiScene::mMaterials|. The name preserves the original material
-	// name if possible.
-	std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
-		static const std::string underscore = "_";
-		char postfix[10] = {0};
-		ASSIMP_itoa10(postfix, index);
-
-		aiString mat_name;
-		if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
-			return mat_name.C_Str() + underscore + postfix;
-		}
-
-		return "Material" + underscore + postfix;
-	}
-
-	// Collect world transformations for each node
-	void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
-		const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
-		trafos[node] = parent * node->mTransformation;
-		for (unsigned int i = 0; i < node->mNumChildren; ++i) {
-			CollectTrafos(node->mChildren[i], trafos);
-		}
-	}
-
-	// Generate a flat list of the meshes (by index) assigned to each node
-	void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
-		for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
-			meshes.insert(std::make_pair(node, node->mMeshes[i]));
-		}
-		for (unsigned int i = 0; i < node->mNumChildren; ++i) {
-			CollectMeshes(node->mChildren[i], meshes);
-		}
-	}
+    //////////////////////////////////////////////////////////////////////////////////////
+    // Scope utility to write a 3DS file chunk.
+    //
+    // Upon construction, the chunk header is written with the chunk type (flags)
+    // filled out, but the chunk size left empty. Upon destruction, the correct chunk
+    // size based on the then-position of the output stream cursor is filled in.
+    class ChunkWriter {
+        enum {
+              CHUNK_SIZE_NOT_SET = 0xdeadbeef
+            , SIZE_OFFSET        = 2
+        };
+    public:
+
+        ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
+            : writer(writer)
+        {
+            chunk_start_pos = writer.GetCurrentPos();
+            writer.PutU2(chunk_type);
+            writer.PutU4(CHUNK_SIZE_NOT_SET);
+        }
+
+        ~ChunkWriter() {
+            std::size_t head_pos = writer.GetCurrentPos();
+
+            ai_assert(head_pos > chunk_start_pos);
+            const std::size_t chunk_size = head_pos - chunk_start_pos;
+
+            writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
+            writer.PutU4(chunk_size);
+            writer.SetCurrentPos(head_pos);
+        }
+
+    private:
+        StreamWriterLE& writer;
+        std::size_t chunk_start_pos;
+    };
+
+
+    // Return an unique name for a given |mesh| attached to |node| that
+    // preserves the mesh's given name if it has one. |index| is the index
+    // of the mesh in |aiScene::mMeshes|.
+    std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
+        static const std::string underscore = "_";
+        char postfix[10] = {0};
+        ASSIMP_itoa10(postfix, index);
+
+        std::string result = node.mName.C_Str();
+        if (mesh.mName.length > 0) {
+            result += underscore + mesh.mName.C_Str();
+        }
+        return result + underscore + postfix;
+    }
+
+    // Return an unique name for a given |mat| with original position |index|
+    // in |aiScene::mMaterials|. The name preserves the original material
+    // name if possible.
+    std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
+        static const std::string underscore = "_";
+        char postfix[10] = {0};
+        ASSIMP_itoa10(postfix, index);
+
+        aiString mat_name;
+        if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
+            return mat_name.C_Str() + underscore + postfix;
+        }
+
+        return "Material" + underscore + postfix;
+    }
+
+    // Collect world transformations for each node
+    void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
+        const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
+        trafos[node] = parent * node->mTransformation;
+        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+            CollectTrafos(node->mChildren[i], trafos);
+        }
+    }
+
+    // Generate a flat list of the meshes (by index) assigned to each node
+    void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
+        for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
+            meshes.insert(std::make_pair(node, node->mMeshes[i]));
+        }
+        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+            CollectMeshes(node->mChildren[i], meshes);
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
 void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
-	boost::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
-	if(!outfile) {
-		throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
-	}
-
-	// TODO: This extra copy should be avoided and all of this made a preprocess
-	// requirement of the 3DS exporter.
-	//
-	// 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively.
-	// SplitLargeMeshes can do this, but it requires the correct limit to be set
-	// which is not possible with the current way of specifying preprocess steps
-	// in |Exporter::ExportFormatEntry|.
-	aiScene* scenecopy_tmp;
-	SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
-	std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
-
-	SplitLargeMeshesProcess_Triangle tri_splitter;
-	tri_splitter.SetLimit(0xffff);
-	tri_splitter.Execute(scenecopy.get());
-
-	SplitLargeMeshesProcess_Vertex vert_splitter;
-	vert_splitter.SetLimit(0xffff);
-	vert_splitter.Execute(scenecopy.get());
-
-	// Invoke the actual exporter
-	Discreet3DSExporter exporter(outfile, scenecopy.get());
+    boost::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
+    if(!outfile) {
+        throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
+    }
+
+    // TODO: This extra copy should be avoided and all of this made a preprocess
+    // requirement of the 3DS exporter.
+    //
+    // 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively.
+    // SplitLargeMeshes can do this, but it requires the correct limit to be set
+    // which is not possible with the current way of specifying preprocess steps
+    // in |Exporter::ExportFormatEntry|.
+    aiScene* scenecopy_tmp;
+    SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
+    std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
+
+    SplitLargeMeshesProcess_Triangle tri_splitter;
+    tri_splitter.SetLimit(0xffff);
+    tri_splitter.Execute(scenecopy.get());
+
+    SplitLargeMeshesProcess_Vertex vert_splitter;
+    vert_splitter.SetLimit(0xffff);
+    vert_splitter.Execute(scenecopy.get());
+
+    // Invoke the actual exporter
+    Discreet3DSExporter exporter(outfile, scenecopy.get());
 }
 
 } // end of namespace Assimp
@@ -185,379 +185,379 @@ Discreet3DSExporter:: Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, c
 : scene(scene)
 , writer(outfile)
 {
-	CollectTrafos(scene->mRootNode, trafos);
-	CollectMeshes(scene->mRootNode, meshes);
-
-	ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
-
-	{
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
-		WriteMaterials();
-		WriteMeshes();
-
-		{
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
-			writer.PutF4(1.0f);
-		}
-	}
-
-	{
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
-		WriteHierarchy(*scene->mRootNode, -1, -1);
-	}
+    CollectTrafos(scene->mRootNode, trafos);
+    CollectMeshes(scene->mRootNode, meshes);
+
+    ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
+
+    {
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
+        WriteMaterials();
+        WriteMeshes();
+
+        {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
+            writer.PutF4(1.0f);
+        }
+    }
+
+    {
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
+        WriteHierarchy(*scene->mRootNode, -1, -1);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
 {
-	// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
-	{
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
-		{
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
-
-			// Assimp node names are unique and distinct from all mesh-node
-			// names we generate; thus we can use them as-is
-			WriteString(node.mName);
-
-			// Two unknown int16 values - it is even unclear if 0 is a safe value
-			// but luckily importers do not know better either.
-			writer.PutI4(0);
-
-			int16_t hierarchy_pos = static_cast<int16_t>(seq);
-			if (sibling_level != -1) {
-				hierarchy_pos = sibling_level;
-			}
-
-			// Write the hierarchy position
-			writer.PutI2(hierarchy_pos);
-		}
-	}
-
-	// TODO: write transformation chunks
-
-	++seq;
-	sibling_level = seq;
-
-	// Write all children
-	for (unsigned int i = 0; i < node.mNumChildren; ++i) {
-		seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level);
-	}
-
-	// Write all meshes as separate nodes to be able to reference the meshes by name
-	for (unsigned int i = 0; i < node.mNumMeshes; ++i) {
-		const bool first_child = node.mNumChildren == 0 && i == 0;
-
-		const unsigned int mesh_idx = node.mMeshes[i];
-		const aiMesh& mesh = *scene->mMeshes[mesh_idx];
-
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
-		{
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
-			WriteString(GetMeshName(mesh, mesh_idx, node));
-
-			writer.PutI4(0);
-			writer.PutI2(static_cast<int16_t>(first_child ? seq : sibling_level));
-			++seq;
-		}
-	}
-	return seq;
+    // 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
+    {
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
+        {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
+
+            // Assimp node names are unique and distinct from all mesh-node
+            // names we generate; thus we can use them as-is
+            WriteString(node.mName);
+
+            // Two unknown int16 values - it is even unclear if 0 is a safe value
+            // but luckily importers do not know better either.
+            writer.PutI4(0);
+
+            int16_t hierarchy_pos = static_cast<int16_t>(seq);
+            if (sibling_level != -1) {
+                hierarchy_pos = sibling_level;
+            }
+
+            // Write the hierarchy position
+            writer.PutI2(hierarchy_pos);
+        }
+    }
+
+    // TODO: write transformation chunks
+
+    ++seq;
+    sibling_level = seq;
+
+    // Write all children
+    for (unsigned int i = 0; i < node.mNumChildren; ++i) {
+        seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level);
+    }
+
+    // Write all meshes as separate nodes to be able to reference the meshes by name
+    for (unsigned int i = 0; i < node.mNumMeshes; ++i) {
+        const bool first_child = node.mNumChildren == 0 && i == 0;
+
+        const unsigned int mesh_idx = node.mMeshes[i];
+        const aiMesh& mesh = *scene->mMeshes[mesh_idx];
+
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
+        {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
+            WriteString(GetMeshName(mesh, mesh_idx, node));
+
+            writer.PutI4(0);
+            writer.PutI2(static_cast<int16_t>(first_child ? seq : sibling_level));
+            ++seq;
+        }
+    }
+    return seq;
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WriteMaterials()
 {
-	for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
-		const aiMaterial& mat = *scene->mMaterials[i];
-
-		{
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
-			const std::string& name = GetMaterialName(mat, i);
-			WriteString(name);
-		}
-
-		aiColor3D color;
-		if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
-			WriteColor(color);
-		}
-
-		if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
-			WriteColor(color);
-		}
-
-		if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
-			WriteColor(color);
-		}
-
-		if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
-			WriteColor(color);
-		}
-
-		aiShadingMode shading_mode = aiShadingMode_Flat;
-		if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
-
-			Discreet3DS::shadetype3ds shading_mode_out;
-			switch(shading_mode) {
-			case aiShadingMode_Flat:
-			case aiShadingMode_NoShading:
-				shading_mode_out = Discreet3DS::Flat;
-				break;
-
-			case aiShadingMode_Gouraud:
-			case aiShadingMode_Toon:
-			case aiShadingMode_OrenNayar:
-			case aiShadingMode_Minnaert:
-				shading_mode_out = Discreet3DS::Gouraud;
-				break;
-
-			case aiShadingMode_Phong:
-			case aiShadingMode_Blinn:
-			case aiShadingMode_CookTorrance:
-			case aiShadingMode_Fresnel:
-				shading_mode_out = Discreet3DS::Phong;
-				break;
-
-			default:
-				shading_mode_out = Discreet3DS::Flat;
-				ai_assert(false);
-			};
-			writer.PutU2(static_cast<uint16_t>(shading_mode_out));
-		}
-
-
-		float f;
-		if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
-			WritePercentChunk(f);
-		}
-
-		if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT);
-			WritePercentChunk(f);
-		}
-
-		int twosided;
-		if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE);
-			writer.PutI2(1);
-		}
-
-		WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
-		WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
-		WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
-		WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
-		WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP);
-		WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP);
-		WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP);
-	}
+    for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
+        const aiMaterial& mat = *scene->mMaterials[i];
+
+        {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
+            const std::string& name = GetMaterialName(mat, i);
+            WriteString(name);
+        }
+
+        aiColor3D color;
+        if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
+            WriteColor(color);
+        }
+
+        if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
+            WriteColor(color);
+        }
+
+        if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
+            WriteColor(color);
+        }
+
+        if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
+            WriteColor(color);
+        }
+
+        aiShadingMode shading_mode = aiShadingMode_Flat;
+        if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
+
+            Discreet3DS::shadetype3ds shading_mode_out;
+            switch(shading_mode) {
+            case aiShadingMode_Flat:
+            case aiShadingMode_NoShading:
+                shading_mode_out = Discreet3DS::Flat;
+                break;
+
+            case aiShadingMode_Gouraud:
+            case aiShadingMode_Toon:
+            case aiShadingMode_OrenNayar:
+            case aiShadingMode_Minnaert:
+                shading_mode_out = Discreet3DS::Gouraud;
+                break;
+
+            case aiShadingMode_Phong:
+            case aiShadingMode_Blinn:
+            case aiShadingMode_CookTorrance:
+            case aiShadingMode_Fresnel:
+                shading_mode_out = Discreet3DS::Phong;
+                break;
+
+            default:
+                shading_mode_out = Discreet3DS::Flat;
+                ai_assert(false);
+            };
+            writer.PutU2(static_cast<uint16_t>(shading_mode_out));
+        }
+
+
+        float f;
+        if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
+            WritePercentChunk(f);
+        }
+
+        if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT);
+            WritePercentChunk(f);
+        }
+
+        int twosided;
+        if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE);
+            writer.PutI2(1);
+        }
+
+        WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
+        WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
+        WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
+        WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
+        WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP);
+        WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP);
+        WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
 {
-	aiString path;
-	aiTextureMapMode map_mode[2] = {
-		aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
-	};
-	float blend = 1.0f;
-	if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
-		return;
-	}
-
-	// TODO: handle embedded textures properly
-	if (path.data[0] == '*') {
-		DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str()));
-		return;
-	}
-
-	ChunkWriter chunk(writer, chunk_flags);
-	{
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
-		WriteString(path);
-	}
-
-	WritePercentChunk(blend);
-
-	{
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
-		uint16_t val = 0; // WRAP
-		if (map_mode[0] == aiTextureMapMode_Mirror) {
-			val = 0x2;
-		}
-		else if (map_mode[0] == aiTextureMapMode_Decal) {
-			val = 0x10;
-		}
-		writer.PutU2(val);
-	}
-	// TODO: export texture transformation (i.e. UV offset, scale, rotation)
+    aiString path;
+    aiTextureMapMode map_mode[2] = {
+        aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
+    };
+    float blend = 1.0f;
+    if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
+        return;
+    }
+
+    // TODO: handle embedded textures properly
+    if (path.data[0] == '*') {
+        DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str()));
+        return;
+    }
+
+    ChunkWriter chunk(writer, chunk_flags);
+    {
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
+        WriteString(path);
+    }
+
+    WritePercentChunk(blend);
+
+    {
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
+        uint16_t val = 0; // WRAP
+        if (map_mode[0] == aiTextureMapMode_Mirror) {
+            val = 0x2;
+        }
+        else if (map_mode[0] == aiTextureMapMode_Decal) {
+            val = 0x10;
+        }
+        writer.PutU2(val);
+    }
+    // TODO: export texture transformation (i.e. UV offset, scale, rotation)
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WriteMeshes()
 {
-	// NOTE: 3DS allows for instances. However:
-	//   i)  not all importers support reading them
-	//   ii) instances are not as flexible as they are in assimp, in particular,
-	//        nodes can carry (and instance) only one mesh.
-	//
-	// This exporter currently deep clones all instanced meshes, i.e. for each mesh
-	// attached to a node a full TRIMESH chunk is written to the file.
-	//
-	// Furthermore, the TRIMESH is transformed into world space so that it will
-	// appear correctly if importers don't read the scene hierarchy at all.
-	for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
-		const aiNode& node = *(*it).first;
-		const unsigned int mesh_idx = (*it).second;
-
-		const aiMesh& mesh = *scene->mMeshes[mesh_idx];
-
-		// This should not happen if the SLM step is correctly executed
-		// before the scene is handed to the exporter
-		ai_assert(mesh.mNumVertices <= 0xffff);
-		ai_assert(mesh.mNumFaces <= 0xffff);
-
-		const aiMatrix4x4& trafo = trafos[&node];
-
-		ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
-
-		// Mesh name is tied to the node it is attached to so it can later be referenced
-		const std::string& name = GetMeshName(mesh, mesh_idx, node);
-		WriteString(name);
-
-
-		// TRIMESH chunk
-		ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
-
-		// Vertices in world space
-		{
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
-
-			const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
-			writer.PutU2(count);
-			for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
-				const aiVector3D& v = trafo * mesh.mVertices[i];
-				writer.PutF4(v.x);
-				writer.PutF4(v.y);
-				writer.PutF4(v.z);
-			}
-		}
-
-		// UV coordinates
-		if (mesh.HasTextureCoords(0)) {
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
-			const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
-			writer.PutU2(count);
-
-			for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
-				const aiVector3D& v = mesh.mTextureCoords[0][i];
-				writer.PutF4(v.x);
-				writer.PutF4(v.y);
-			}
-		}
-
-		// Faces (indices)
-		{
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
-
-			ai_assert(mesh.mNumFaces <= 0xffff);
-
-			// Count triangles, discard lines and points
-			uint16_t count = 0;
-			for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
-				const aiFace& f = mesh.mFaces[i];
-				if (f.mNumIndices < 3) {
-					continue;
-				}
-				// TRIANGULATE step is a pre-requisite so we should not see polys here
-				ai_assert(f.mNumIndices == 3);
-				++count;
-			}
-
-			writer.PutU2(count);
-			for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
-				const aiFace& f = mesh.mFaces[i];
-				if (f.mNumIndices < 3) {
-					continue;
-				}
-
-				for (unsigned int j = 0; j < 3; ++j) {
-					ai_assert(f.mIndices[j] <= 0xffff);
-					writer.PutI2(static_cast<uint16_t>(f.mIndices[j]));
-				}
-
-				// Edge visibility flag
-				writer.PutI2(0x0);
-			}
-
-			// TODO: write smoothing groups (CHUNK_SMOOLIST)
-
-			WriteFaceMaterialChunk(mesh);
-		}
-
-		// Transformation matrix by which the mesh vertices have been pre-transformed with.
-		{
-			ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
-			for (unsigned int r = 0; r < 4; ++r) {
-				for (unsigned int c = 0; c < 3; ++c) {
-					writer.PutF4(trafo[r][c]);
-				}
-			}
-		}
-	}
+    // NOTE: 3DS allows for instances. However:
+    //   i)  not all importers support reading them
+    //   ii) instances are not as flexible as they are in assimp, in particular,
+    //        nodes can carry (and instance) only one mesh.
+    //
+    // This exporter currently deep clones all instanced meshes, i.e. for each mesh
+    // attached to a node a full TRIMESH chunk is written to the file.
+    //
+    // Furthermore, the TRIMESH is transformed into world space so that it will
+    // appear correctly if importers don't read the scene hierarchy at all.
+    for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
+        const aiNode& node = *(*it).first;
+        const unsigned int mesh_idx = (*it).second;
+
+        const aiMesh& mesh = *scene->mMeshes[mesh_idx];
+
+        // This should not happen if the SLM step is correctly executed
+        // before the scene is handed to the exporter
+        ai_assert(mesh.mNumVertices <= 0xffff);
+        ai_assert(mesh.mNumFaces <= 0xffff);
+
+        const aiMatrix4x4& trafo = trafos[&node];
+
+        ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
+
+        // Mesh name is tied to the node it is attached to so it can later be referenced
+        const std::string& name = GetMeshName(mesh, mesh_idx, node);
+        WriteString(name);
+
+
+        // TRIMESH chunk
+        ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
+
+        // Vertices in world space
+        {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
+
+            const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
+            writer.PutU2(count);
+            for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
+                const aiVector3D& v = trafo * mesh.mVertices[i];
+                writer.PutF4(v.x);
+                writer.PutF4(v.y);
+                writer.PutF4(v.z);
+            }
+        }
+
+        // UV coordinates
+        if (mesh.HasTextureCoords(0)) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
+            const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
+            writer.PutU2(count);
+
+            for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
+                const aiVector3D& v = mesh.mTextureCoords[0][i];
+                writer.PutF4(v.x);
+                writer.PutF4(v.y);
+            }
+        }
+
+        // Faces (indices)
+        {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
+
+            ai_assert(mesh.mNumFaces <= 0xffff);
+
+            // Count triangles, discard lines and points
+            uint16_t count = 0;
+            for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
+                const aiFace& f = mesh.mFaces[i];
+                if (f.mNumIndices < 3) {
+                    continue;
+                }
+                // TRIANGULATE step is a pre-requisite so we should not see polys here
+                ai_assert(f.mNumIndices == 3);
+                ++count;
+            }
+
+            writer.PutU2(count);
+            for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
+                const aiFace& f = mesh.mFaces[i];
+                if (f.mNumIndices < 3) {
+                    continue;
+                }
+
+                for (unsigned int j = 0; j < 3; ++j) {
+                    ai_assert(f.mIndices[j] <= 0xffff);
+                    writer.PutI2(static_cast<uint16_t>(f.mIndices[j]));
+                }
+
+                // Edge visibility flag
+                writer.PutI2(0x0);
+            }
+
+            // TODO: write smoothing groups (CHUNK_SMOOLIST)
+
+            WriteFaceMaterialChunk(mesh);
+        }
+
+        // Transformation matrix by which the mesh vertices have been pre-transformed with.
+        {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
+            for (unsigned int r = 0; r < 4; ++r) {
+                for (unsigned int c = 0; c < 3; ++c) {
+                    writer.PutF4(trafo[r][c]);
+                }
+            }
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
 {
-	ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
-	const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
-	WriteString(name);
-
-	// Because assimp splits meshes by material, only a single
-	// FACEMAT chunk needs to be written
-	ai_assert(mesh.mNumFaces <= 0xffff);
-	const uint16_t count = static_cast<uint16_t>(mesh.mNumFaces);
-	writer.PutU2(count);
-
-	for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
-		writer.PutU2(static_cast<uint16_t>(i));
-	}
+    ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
+    const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
+    WriteString(name);
+
+    // Because assimp splits meshes by material, only a single
+    // FACEMAT chunk needs to be written
+    ai_assert(mesh.mNumFaces <= 0xffff);
+    const uint16_t count = static_cast<uint16_t>(mesh.mNumFaces);
+    writer.PutU2(count);
+
+    for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
+        writer.PutU2(static_cast<uint16_t>(i));
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WriteString(const std::string& s) {
-	for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
-		writer.PutI1(*it);
-	}
-	writer.PutI1('\0');
+    for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
+        writer.PutI1(*it);
+    }
+    writer.PutI1('\0');
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WriteString(const aiString& s) {
-	for (std::size_t i = 0; i < s.length; ++i) {
-		writer.PutI1(s.data[i]);
-	}
-	writer.PutI1('\0');
+    for (std::size_t i = 0; i < s.length; ++i) {
+        writer.PutI1(s.data[i]);
+    }
+    writer.PutI1('\0');
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
-	ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
-	writer.PutF4(color.r);
-	writer.PutF4(color.g);
-	writer.PutF4(color.b);
+    ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
+    writer.PutF4(color.r);
+    writer.PutF4(color.g);
+    writer.PutF4(color.b);
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSExporter::WritePercentChunk(float f) {
-	ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
-	writer.PutF4(f);
+    ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
+    writer.PutF4(f);
 }
 
 

+ 15 - 15
code/3DSExporter.h

@@ -64,32 +64,32 @@ namespace Assimp
 class Discreet3DSExporter
 {
 public:
-	Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, const aiScene* pScene);
+    Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, const aiScene* pScene);
 
 private:
 
-	void WriteMeshes();
-	void WriteMaterials();
-	void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
+    void WriteMeshes();
+    void WriteMaterials();
+    void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
 
-	void WriteFaceMaterialChunk(const aiMesh& mesh);
+    void WriteFaceMaterialChunk(const aiMesh& mesh);
 
-	int WriteHierarchy(const aiNode& node, int level, int sibling_level);
+    int WriteHierarchy(const aiNode& node, int level, int sibling_level);
 
-	void WriteString(const std::string& s);
-	void WriteString(const aiString& s);
-	void WriteColor(const aiColor3D& color);
-	void WritePercentChunk(float f);
+    void WriteString(const std::string& s);
+    void WriteString(const aiString& s);
+    void WriteColor(const aiColor3D& color);
+    void WritePercentChunk(float f);
 
 private:
 
-	const aiScene* const scene;
-	StreamWriterLE writer;
+    const aiScene* const scene;
+    StreamWriterLE writer;
 
-	std::map<const aiNode*, aiMatrix4x4> trafos;
+    std::map<const aiNode*, aiMatrix4x4> trafos;
 
-	typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap;
-	MeshesByNodeMap meshes;
+    typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap;
+    MeshesByNodeMap meshes;
 
 };
 

+ 433 - 433
code/3DSHelper.h

@@ -53,8 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "./../include/assimp/anim.h"
 #include <stdio.h> //sprintf
 
-namespace Assimp	{
-namespace D3DS	{
+namespace Assimp    {
+namespace D3DS  {
 
 #include "./../include/assimp/Compiler/pushpack1.h"
 
@@ -65,253 +65,253 @@ namespace D3DS	{
 class Discreet3DS
 {
 private:
-	inline Discreet3DS() {}
+    inline Discreet3DS() {}
 
 public:
 
-	//! data structure for a single chunk in a .3ds file
-	struct Chunk
-	{
-		uint16_t	Flag;
-		uint32_t	Size;
-	} PACK_STRUCT;
-
-
-	//! Used for shading field in material3ds structure
-	//! From AutoDesk 3ds SDK
-	typedef enum
-	{
-		// translated to gouraud shading with wireframe active
-		Wire = 0x0,
-
-		// if this material is set, no vertex normals will
-		// be calculated for the model. Face normals + gouraud
-		Flat = 0x1,
-
-		// standard gouraud shading
-		Gouraud = 0x2,
-
-		// phong shading
-		Phong = 0x3,
-
-		// cooktorrance or anistropic phong shading ...
-		// the exact meaning is unknown, if you know it
-		// feel free to tell me ;-)
-		Metal = 0x4,
-
-		// required by the ASE loader
-		Blinn = 0x5
-	} shadetype3ds;
-
-	// Flags for animated keys
-	enum
-	{
-		KEY_USE_TENS         = 0x1,
-		KEY_USE_CONT         = 0x2,
-		KEY_USE_BIAS         = 0x4,
-		KEY_USE_EASE_TO      = 0x8,
-		KEY_USE_EASE_FROM    = 0x10
-	} ;
-
-	enum
-	{
-
-		// ********************************************************************
-		// Basic chunks which can be found everywhere in the file
-		CHUNK_VERSION	= 0x0002,
-		CHUNK_RGBF      = 0x0010,		// float4 R; float4 G; float4 B
-		CHUNK_RGBB      = 0x0011,		// int1 R; int1 G; int B
-
-		// Linear color values (gamma = 2.2?)
-		CHUNK_LINRGBF      = 0x0013,	// float4 R; float4 G; float4 B
-		CHUNK_LINRGBB      = 0x0012,	// int1 R; int1 G; int B
-
-		CHUNK_PERCENTW	= 0x0030,		// int2   percentage
-		CHUNK_PERCENTF	= 0x0031,		// float4  percentage
-		// ********************************************************************
-
-		// Prj master chunk
-		CHUNK_PRJ       = 0xC23D,
-
-		// MDLI master chunk
-		CHUNK_MLI       = 0x3DAA,
-
-		// Primary main chunk of the .3ds file
-		CHUNK_MAIN      = 0x4D4D,
-
-		// Mesh main chunk
-		CHUNK_OBJMESH   = 0x3D3D,
-
-		// Specifies the background color of the .3ds file
-		// This is passed through the material system for
-		// viewing purposes.
-		CHUNK_BKGCOLOR  = 0x1200,
-
-		// Specifies the ambient base color of the scene.
-		// This is added to all materials in the file
-		CHUNK_AMBCOLOR  = 0x2100,
-
-		// Specifies the background image for the whole scene
-		// This value is passed through the material system
-		// to the viewer
-		CHUNK_BIT_MAP   = 0x1100,
-		CHUNK_BIT_MAP_EXISTS  = 0x1101,
-
-		// ********************************************************************
-		// Viewport related stuff. Ignored
-		CHUNK_DEFAULT_VIEW = 0x3000,
-		CHUNK_VIEW_TOP = 0x3010,
-		CHUNK_VIEW_BOTTOM = 0x3020,
-		CHUNK_VIEW_LEFT = 0x3030,
-		CHUNK_VIEW_RIGHT = 0x3040,
-		CHUNK_VIEW_FRONT = 0x3050,
-		CHUNK_VIEW_BACK = 0x3060,
-		CHUNK_VIEW_USER = 0x3070,
-		CHUNK_VIEW_CAMERA = 0x3080,
-		// ********************************************************************
-
-		// Mesh chunks
-		CHUNK_OBJBLOCK  = 0x4000,
-		CHUNK_TRIMESH   = 0x4100,
-		CHUNK_VERTLIST  = 0x4110,
-		CHUNK_VERTFLAGS = 0x4111,
-		CHUNK_FACELIST  = 0x4120,
-		CHUNK_FACEMAT   = 0x4130,
-		CHUNK_MAPLIST   = 0x4140,
-		CHUNK_SMOOLIST  = 0x4150,
-		CHUNK_TRMATRIX  = 0x4160,
-		CHUNK_MESHCOLOR = 0x4165,
-		CHUNK_TXTINFO   = 0x4170,
-		CHUNK_LIGHT     = 0x4600,
-		CHUNK_CAMERA    = 0x4700,
-		CHUNK_HIERARCHY = 0x4F00,
-
-		// Specifies the global scaling factor. This is applied
-		// to the root node's transformation matrix
-		CHUNK_MASTER_SCALE    = 0x0100,
-
-		// ********************************************************************
-		// Material chunks
-		CHUNK_MAT_MATERIAL  = 0xAFFF,
-
-			// asciiz containing the name of the material
-			CHUNK_MAT_MATNAME   = 0xA000,
-			CHUNK_MAT_AMBIENT   = 0xA010, // followed by color chunk
-			CHUNK_MAT_DIFFUSE   = 0xA020, // followed by color chunk
-			CHUNK_MAT_SPECULAR  = 0xA030, // followed by color chunk
-
-			// Specifies the shininess of the material
-			// followed by percentage chunk
-			CHUNK_MAT_SHININESS  = 0xA040,
-			CHUNK_MAT_SHININESS_PERCENT  = 0xA041 ,
-
-			// Specifies the shading mode to be used
-			// followed by a short
-			CHUNK_MAT_SHADING  = 0xA100,
-
-			// NOTE: Emissive color (self illumination) seems not
-			// to be a color but a single value, type is unknown.
-			// Make the parser accept both of them.
-			// followed by percentage chunk (?)
-			CHUNK_MAT_SELF_ILLUM = 0xA080,
-
-			// Always followed by percentage chunk	(?)
-			CHUNK_MAT_SELF_ILPCT = 0xA084,
-
-			// Always followed by percentage chunk
-			CHUNK_MAT_TRANSPARENCY = 0xA050,
-
-			// Diffuse texture channel 0
-			CHUNK_MAT_TEXTURE   = 0xA200,
-
-			// Contains opacity information for each texel
-			CHUNK_MAT_OPACMAP = 0xA210,
-
-			// Contains a reflection map to be used to reflect
-			// the environment. This is partially supported.
-			CHUNK_MAT_REFLMAP = 0xA220,
-
-			// Self Illumination map (emissive colors)
-			CHUNK_MAT_SELFIMAP = 0xA33d,
-
-			// Bumpmap. Not specified whether it is a heightmap
-			// or a normal map. Assme it is a heightmap since
-			// artist normally prefer this format.
-			CHUNK_MAT_BUMPMAP = 0xA230,
-
-			// Specular map. Seems to influence the specular color
-			CHUNK_MAT_SPECMAP = 0xA204,
-
-			// Holds shininess data.
-			CHUNK_MAT_MAT_SHINMAP = 0xA33C,
-
-			// Scaling in U/V direction.
-			// (need to gen separate UV coordinate set
-			// and do this by hand)
-			CHUNK_MAT_MAP_USCALE 	  = 0xA354,
-			CHUNK_MAT_MAP_VSCALE 	  = 0xA356,
-
-			// Translation in U/V direction.
-			// (need to gen separate UV coordinate set
-			// and do this by hand)
-			CHUNK_MAT_MAP_UOFFSET 	  = 0xA358,
-			CHUNK_MAT_MAP_VOFFSET 	  = 0xA35a,
-
-			// UV-coordinates rotation around the z-axis
-			// Assumed to be in radians.
-			CHUNK_MAT_MAP_ANG = 0xA35C,
-
-			// Tiling flags for 3DS files
-			CHUNK_MAT_MAP_TILING = 0xa351,
-
-			// Specifies the file name of a texture
-			CHUNK_MAPFILE   = 0xA300,
-
-			// Specifies whether a materail requires two-sided rendering
-			CHUNK_MAT_TWO_SIDE = 0xA081,
-		// ********************************************************************
-
-		// Main keyframer chunk. Contains translation/rotation/scaling data
-		CHUNK_KEYFRAMER		= 0xB000,
-
-		// Supported sub chunks
-		CHUNK_TRACKINFO		= 0xB002,
-		CHUNK_TRACKOBJNAME  = 0xB010,
-		CHUNK_TRACKDUMMYOBJNAME  = 0xB011,
-		CHUNK_TRACKPIVOT    = 0xB013,
-		CHUNK_TRACKPOS      = 0xB020,
-		CHUNK_TRACKROTATE   = 0xB021,
-		CHUNK_TRACKSCALE    = 0xB022,
-
-		// ********************************************************************
-		// Keyframes for various other stuff in the file
-		// Partially ignored
-		CHUNK_AMBIENTKEY    = 0xB001,
-		CHUNK_TRACKMORPH    = 0xB026,
-		CHUNK_TRACKHIDE     = 0xB029,
-		CHUNK_OBJNUMBER     = 0xB030,
-		CHUNK_TRACKCAMERA	= 0xB003,
-		CHUNK_TRACKFOV		= 0xB023,
-		CHUNK_TRACKROLL		= 0xB024,
-		CHUNK_TRACKCAMTGT	= 0xB004,
-		CHUNK_TRACKLIGHT	= 0xB005,
-		CHUNK_TRACKLIGTGT	= 0xB006,
-		CHUNK_TRACKSPOTL	= 0xB007,
-		CHUNK_FRAMES		= 0xB008,
-		// ********************************************************************
-
-		// light sub-chunks
-		CHUNK_DL_OFF                 = 0x4620,
-		CHUNK_DL_OUTER_RANGE         = 0x465A,
-		CHUNK_DL_INNER_RANGE         = 0x4659,
-		CHUNK_DL_MULTIPLIER          = 0x465B,
-		CHUNK_DL_EXCLUDE             = 0x4654,
-		CHUNK_DL_ATTENUATE           = 0x4625,
-		CHUNK_DL_SPOTLIGHT           = 0x4610,
-
-		// camera sub-chunks
-		CHUNK_CAM_RANGES             = 0x4720
-	};
+    //! data structure for a single chunk in a .3ds file
+    struct Chunk
+    {
+        uint16_t    Flag;
+        uint32_t    Size;
+    } PACK_STRUCT;
+
+
+    //! Used for shading field in material3ds structure
+    //! From AutoDesk 3ds SDK
+    typedef enum
+    {
+        // translated to gouraud shading with wireframe active
+        Wire = 0x0,
+
+        // if this material is set, no vertex normals will
+        // be calculated for the model. Face normals + gouraud
+        Flat = 0x1,
+
+        // standard gouraud shading
+        Gouraud = 0x2,
+
+        // phong shading
+        Phong = 0x3,
+
+        // cooktorrance or anistropic phong shading ...
+        // the exact meaning is unknown, if you know it
+        // feel free to tell me ;-)
+        Metal = 0x4,
+
+        // required by the ASE loader
+        Blinn = 0x5
+    } shadetype3ds;
+
+    // Flags for animated keys
+    enum
+    {
+        KEY_USE_TENS         = 0x1,
+        KEY_USE_CONT         = 0x2,
+        KEY_USE_BIAS         = 0x4,
+        KEY_USE_EASE_TO      = 0x8,
+        KEY_USE_EASE_FROM    = 0x10
+    } ;
+
+    enum
+    {
+
+        // ********************************************************************
+        // Basic chunks which can be found everywhere in the file
+        CHUNK_VERSION   = 0x0002,
+        CHUNK_RGBF      = 0x0010,       // float4 R; float4 G; float4 B
+        CHUNK_RGBB      = 0x0011,       // int1 R; int1 G; int B
+
+        // Linear color values (gamma = 2.2?)
+        CHUNK_LINRGBF      = 0x0013,    // float4 R; float4 G; float4 B
+        CHUNK_LINRGBB      = 0x0012,    // int1 R; int1 G; int B
+
+        CHUNK_PERCENTW  = 0x0030,       // int2   percentage
+        CHUNK_PERCENTF  = 0x0031,       // float4  percentage
+        // ********************************************************************
+
+        // Prj master chunk
+        CHUNK_PRJ       = 0xC23D,
+
+        // MDLI master chunk
+        CHUNK_MLI       = 0x3DAA,
+
+        // Primary main chunk of the .3ds file
+        CHUNK_MAIN      = 0x4D4D,
+
+        // Mesh main chunk
+        CHUNK_OBJMESH   = 0x3D3D,
+
+        // Specifies the background color of the .3ds file
+        // This is passed through the material system for
+        // viewing purposes.
+        CHUNK_BKGCOLOR  = 0x1200,
+
+        // Specifies the ambient base color of the scene.
+        // This is added to all materials in the file
+        CHUNK_AMBCOLOR  = 0x2100,
+
+        // Specifies the background image for the whole scene
+        // This value is passed through the material system
+        // to the viewer
+        CHUNK_BIT_MAP   = 0x1100,
+        CHUNK_BIT_MAP_EXISTS  = 0x1101,
+
+        // ********************************************************************
+        // Viewport related stuff. Ignored
+        CHUNK_DEFAULT_VIEW = 0x3000,
+        CHUNK_VIEW_TOP = 0x3010,
+        CHUNK_VIEW_BOTTOM = 0x3020,
+        CHUNK_VIEW_LEFT = 0x3030,
+        CHUNK_VIEW_RIGHT = 0x3040,
+        CHUNK_VIEW_FRONT = 0x3050,
+        CHUNK_VIEW_BACK = 0x3060,
+        CHUNK_VIEW_USER = 0x3070,
+        CHUNK_VIEW_CAMERA = 0x3080,
+        // ********************************************************************
+
+        // Mesh chunks
+        CHUNK_OBJBLOCK  = 0x4000,
+        CHUNK_TRIMESH   = 0x4100,
+        CHUNK_VERTLIST  = 0x4110,
+        CHUNK_VERTFLAGS = 0x4111,
+        CHUNK_FACELIST  = 0x4120,
+        CHUNK_FACEMAT   = 0x4130,
+        CHUNK_MAPLIST   = 0x4140,
+        CHUNK_SMOOLIST  = 0x4150,
+        CHUNK_TRMATRIX  = 0x4160,
+        CHUNK_MESHCOLOR = 0x4165,
+        CHUNK_TXTINFO   = 0x4170,
+        CHUNK_LIGHT     = 0x4600,
+        CHUNK_CAMERA    = 0x4700,
+        CHUNK_HIERARCHY = 0x4F00,
+
+        // Specifies the global scaling factor. This is applied
+        // to the root node's transformation matrix
+        CHUNK_MASTER_SCALE    = 0x0100,
+
+        // ********************************************************************
+        // Material chunks
+        CHUNK_MAT_MATERIAL  = 0xAFFF,
+
+            // asciiz containing the name of the material
+            CHUNK_MAT_MATNAME   = 0xA000,
+            CHUNK_MAT_AMBIENT   = 0xA010, // followed by color chunk
+            CHUNK_MAT_DIFFUSE   = 0xA020, // followed by color chunk
+            CHUNK_MAT_SPECULAR  = 0xA030, // followed by color chunk
+
+            // Specifies the shininess of the material
+            // followed by percentage chunk
+            CHUNK_MAT_SHININESS  = 0xA040,
+            CHUNK_MAT_SHININESS_PERCENT  = 0xA041 ,
+
+            // Specifies the shading mode to be used
+            // followed by a short
+            CHUNK_MAT_SHADING  = 0xA100,
+
+            // NOTE: Emissive color (self illumination) seems not
+            // to be a color but a single value, type is unknown.
+            // Make the parser accept both of them.
+            // followed by percentage chunk (?)
+            CHUNK_MAT_SELF_ILLUM = 0xA080,
+
+            // Always followed by percentage chunk  (?)
+            CHUNK_MAT_SELF_ILPCT = 0xA084,
+
+            // Always followed by percentage chunk
+            CHUNK_MAT_TRANSPARENCY = 0xA050,
+
+            // Diffuse texture channel 0
+            CHUNK_MAT_TEXTURE   = 0xA200,
+
+            // Contains opacity information for each texel
+            CHUNK_MAT_OPACMAP = 0xA210,
+
+            // Contains a reflection map to be used to reflect
+            // the environment. This is partially supported.
+            CHUNK_MAT_REFLMAP = 0xA220,
+
+            // Self Illumination map (emissive colors)
+            CHUNK_MAT_SELFIMAP = 0xA33d,
+
+            // Bumpmap. Not specified whether it is a heightmap
+            // or a normal map. Assme it is a heightmap since
+            // artist normally prefer this format.
+            CHUNK_MAT_BUMPMAP = 0xA230,
+
+            // Specular map. Seems to influence the specular color
+            CHUNK_MAT_SPECMAP = 0xA204,
+
+            // Holds shininess data.
+            CHUNK_MAT_MAT_SHINMAP = 0xA33C,
+
+            // Scaling in U/V direction.
+            // (need to gen separate UV coordinate set
+            // and do this by hand)
+            CHUNK_MAT_MAP_USCALE      = 0xA354,
+            CHUNK_MAT_MAP_VSCALE      = 0xA356,
+
+            // Translation in U/V direction.
+            // (need to gen separate UV coordinate set
+            // and do this by hand)
+            CHUNK_MAT_MAP_UOFFSET     = 0xA358,
+            CHUNK_MAT_MAP_VOFFSET     = 0xA35a,
+
+            // UV-coordinates rotation around the z-axis
+            // Assumed to be in radians.
+            CHUNK_MAT_MAP_ANG = 0xA35C,
+
+            // Tiling flags for 3DS files
+            CHUNK_MAT_MAP_TILING = 0xa351,
+
+            // Specifies the file name of a texture
+            CHUNK_MAPFILE   = 0xA300,
+
+            // Specifies whether a materail requires two-sided rendering
+            CHUNK_MAT_TWO_SIDE = 0xA081,
+        // ********************************************************************
+
+        // Main keyframer chunk. Contains translation/rotation/scaling data
+        CHUNK_KEYFRAMER     = 0xB000,
+
+        // Supported sub chunks
+        CHUNK_TRACKINFO     = 0xB002,
+        CHUNK_TRACKOBJNAME  = 0xB010,
+        CHUNK_TRACKDUMMYOBJNAME  = 0xB011,
+        CHUNK_TRACKPIVOT    = 0xB013,
+        CHUNK_TRACKPOS      = 0xB020,
+        CHUNK_TRACKROTATE   = 0xB021,
+        CHUNK_TRACKSCALE    = 0xB022,
+
+        // ********************************************************************
+        // Keyframes for various other stuff in the file
+        // Partially ignored
+        CHUNK_AMBIENTKEY    = 0xB001,
+        CHUNK_TRACKMORPH    = 0xB026,
+        CHUNK_TRACKHIDE     = 0xB029,
+        CHUNK_OBJNUMBER     = 0xB030,
+        CHUNK_TRACKCAMERA   = 0xB003,
+        CHUNK_TRACKFOV      = 0xB023,
+        CHUNK_TRACKROLL     = 0xB024,
+        CHUNK_TRACKCAMTGT   = 0xB004,
+        CHUNK_TRACKLIGHT    = 0xB005,
+        CHUNK_TRACKLIGTGT   = 0xB006,
+        CHUNK_TRACKSPOTL    = 0xB007,
+        CHUNK_FRAMES        = 0xB008,
+        // ********************************************************************
+
+        // light sub-chunks
+        CHUNK_DL_OFF                 = 0x4620,
+        CHUNK_DL_OUTER_RANGE         = 0x465A,
+        CHUNK_DL_INNER_RANGE         = 0x4659,
+        CHUNK_DL_MULTIPLIER          = 0x465B,
+        CHUNK_DL_EXCLUDE             = 0x4654,
+        CHUNK_DL_ATTENUATE           = 0x4625,
+        CHUNK_DL_SPOTLIGHT           = 0x4610,
+
+        // camera sub-chunks
+        CHUNK_CAM_RANGES             = 0x4720
+    };
 };
 
 // ---------------------------------------------------------------------------
@@ -324,38 +324,38 @@ struct Face : public FaceWithSmoothingGroup
 /** Helper structure representing a texture */
 struct Texture
 {
-	//! Default constructor
-	Texture()
-		: mOffsetU	(0.0f)
-		, mOffsetV	(0.0f)
-		, mScaleU	(1.0f)
-		, mScaleV	(1.0f)
-		, mRotation	(0.0f)
-		, mMapMode	(aiTextureMapMode_Wrap)
-		, iUVSrc	(0)
-	{
-		mTextureBlend = get_qnan();
-	}
-
-	//! Specifies the blend factor for the texture
-	float mTextureBlend;
-
-	//! Specifies the filename of the texture
-	std::string mMapName;
-
-	//! Specifies texture coordinate offsets/scaling/rotations
-	float mOffsetU;
-	float mOffsetV;
-	float mScaleU;
-	float mScaleV;
-	float mRotation;
-
-	//! Specifies the mapping mode to be used for the texture
-	aiTextureMapMode mMapMode;
-
-	//! Used internally
-	bool bPrivate;
-	int iUVSrc;
+    //! Default constructor
+    Texture()
+        : mOffsetU  (0.0f)
+        , mOffsetV  (0.0f)
+        , mScaleU   (1.0f)
+        , mScaleV   (1.0f)
+        , mRotation (0.0f)
+        , mMapMode  (aiTextureMapMode_Wrap)
+        , iUVSrc    (0)
+    {
+        mTextureBlend = get_qnan();
+    }
+
+    //! Specifies the blend factor for the texture
+    float mTextureBlend;
+
+    //! Specifies the filename of the texture
+    std::string mMapName;
+
+    //! Specifies texture coordinate offsets/scaling/rotations
+    float mOffsetU;
+    float mOffsetV;
+    float mScaleU;
+    float mScaleV;
+    float mRotation;
+
+    //! Specifies the mapping mode to be used for the texture
+    aiTextureMapMode mMapMode;
+
+    //! Used internally
+    bool bPrivate;
+    int iUVSrc;
 };
 
 #include "./../include/assimp/Compiler/poppack1.h"
@@ -364,91 +364,91 @@ struct Texture
 /** Helper structure representing a 3ds material */
 struct Material
 {
-	//! Default constructor. Builds a default name for the material
-	Material()
-		:
-	mDiffuse			(0.6f,0.6f,0.6f), // FIX ... we won't want object to be black
-	mSpecularExponent	(0.0f),
-	mShininessStrength	(1.0f),
-	mShading(Discreet3DS::Gouraud),
-	mTransparency		(1.0f),
-	mBumpHeight			(1.0f),
-	mTwoSided			(false)
-	{
-		static int iCnt = 0;
-
-		char szTemp[128];
-		sprintf(szTemp,"UNNAMED_%i",iCnt++);
-		mName = szTemp;
-	}
-
-	//! Name of the material
-	std::string mName;
-	//! Diffuse color of the material
-	aiColor3D mDiffuse;
-	//! Specular exponent
-	float mSpecularExponent;
-	//! Shininess strength, in percent
-	float mShininessStrength;
-	//! Specular color of the material
-	aiColor3D mSpecular;
-	//! Ambient color of the material
-	aiColor3D mAmbient;
-	//! Shading type to be used
-	Discreet3DS::shadetype3ds mShading;
-	//! Opacity of the material
-	float mTransparency;
-	//! Diffuse texture channel
-	Texture sTexDiffuse;
-	//! Opacity texture channel
-	Texture sTexOpacity;
-	//! Specular texture channel
-	Texture sTexSpecular;
-	//! Reflective texture channel
-	Texture sTexReflective;
-	//! Bump texture channel
-	Texture sTexBump;
-	//! Emissive texture channel
-	Texture sTexEmissive;
-	//! Shininess texture channel
-	Texture sTexShininess;
-	//! Scaling factor for the bump values
-	float mBumpHeight;
-	//! Emissive color
-	aiColor3D mEmissive;
-	//! Ambient texture channel
-	//! (used by the ASE format)
-	Texture sTexAmbient;
-	//! True if the material must be rendered from two sides
-	bool mTwoSided;
+    //! Default constructor. Builds a default name for the material
+    Material()
+        :
+    mDiffuse            (0.6f,0.6f,0.6f), // FIX ... we won't want object to be black
+    mSpecularExponent   (0.0f),
+    mShininessStrength  (1.0f),
+    mShading(Discreet3DS::Gouraud),
+    mTransparency       (1.0f),
+    mBumpHeight         (1.0f),
+    mTwoSided           (false)
+    {
+        static int iCnt = 0;
+
+        char szTemp[128];
+        sprintf(szTemp,"UNNAMED_%i",iCnt++);
+        mName = szTemp;
+    }
+
+    //! Name of the material
+    std::string mName;
+    //! Diffuse color of the material
+    aiColor3D mDiffuse;
+    //! Specular exponent
+    float mSpecularExponent;
+    //! Shininess strength, in percent
+    float mShininessStrength;
+    //! Specular color of the material
+    aiColor3D mSpecular;
+    //! Ambient color of the material
+    aiColor3D mAmbient;
+    //! Shading type to be used
+    Discreet3DS::shadetype3ds mShading;
+    //! Opacity of the material
+    float mTransparency;
+    //! Diffuse texture channel
+    Texture sTexDiffuse;
+    //! Opacity texture channel
+    Texture sTexOpacity;
+    //! Specular texture channel
+    Texture sTexSpecular;
+    //! Reflective texture channel
+    Texture sTexReflective;
+    //! Bump texture channel
+    Texture sTexBump;
+    //! Emissive texture channel
+    Texture sTexEmissive;
+    //! Shininess texture channel
+    Texture sTexShininess;
+    //! Scaling factor for the bump values
+    float mBumpHeight;
+    //! Emissive color
+    aiColor3D mEmissive;
+    //! Ambient texture channel
+    //! (used by the ASE format)
+    Texture sTexAmbient;
+    //! True if the material must be rendered from two sides
+    bool mTwoSided;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent a 3ds file mesh */
 struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
 {
-	//! Default constructor
-	Mesh()
-	{
-		static int iCnt = 0;
+    //! Default constructor
+    Mesh()
+    {
+        static int iCnt = 0;
 
-		// Generate a default name for the mesh
-		char szTemp[128];
-		::sprintf(szTemp,"UNNAMED_%i",iCnt++);
-		mName = szTemp;
-	}
+        // Generate a default name for the mesh
+        char szTemp[128];
+        ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
+        mName = szTemp;
+    }
 
-	//! Name of the mesh
-	std::string mName;
+    //! Name of the mesh
+    std::string mName;
 
-	//! Texture coordinates
-	std::vector<aiVector3D> mTexCoords;
+    //! Texture coordinates
+    std::vector<aiVector3D> mTexCoords;
 
-	//! Face materials
-	std::vector<unsigned int> mFaceMaterials;
+    //! Face materials
+    std::vector<unsigned int> mFaceMaterials;
 
-	//! Local transformation matrix
-	aiMatrix4x4 mMat;
+    //! Local transformation matrix
+    aiMatrix4x4 mMat;
 };
 
 // ---------------------------------------------------------------------------
@@ -456,25 +456,25 @@ struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
     C-API, so it would be difficult to make them a template. */
 struct aiFloatKey
 {
-	double mTime;      ///< The time of this key
-	float mValue;	///< The value of this key
+    double mTime;      ///< The time of this key
+    float mValue;   ///< The value of this key
 
 #ifdef __cplusplus
 
-	// time is not compared
-	bool operator == (const aiFloatKey& o) const
-		{return o.mValue == this->mValue;}
+    // time is not compared
+    bool operator == (const aiFloatKey& o) const
+        {return o.mValue == this->mValue;}
 
-	bool operator != (const aiFloatKey& o) const
-		{return o.mValue != this->mValue;}
+    bool operator != (const aiFloatKey& o) const
+        {return o.mValue != this->mValue;}
 
-	// Only time is compared. This operator is defined
-	// for use with std::sort
-	bool operator < (const aiFloatKey& o) const
-		{return mTime < o.mTime;}
+    // Only time is compared. This operator is defined
+    // for use with std::sort
+    bool operator < (const aiFloatKey& o) const
+        {return mTime < o.mTime;}
 
-	bool operator > (const aiFloatKey& o) const
-		{return mTime > o.mTime;}
+    bool operator > (const aiFloatKey& o) const
+        {return mTime > o.mTime;}
 
 #endif
 };
@@ -483,104 +483,104 @@ struct aiFloatKey
 /** Helper structure to represent a 3ds file node */
 struct Node
 {
-	Node()
+    Node()
 
-		:	mHierarchyPos		(0)
-		,	mHierarchyIndex		(0)
-		,	mInstanceCount		(1)
+        :   mHierarchyPos       (0)
+        ,   mHierarchyIndex     (0)
+        ,   mInstanceCount      (1)
 
-	{
-		static int iCnt = 0;
+    {
+        static int iCnt = 0;
 
-		// Generate a default name for the node
-		char szTemp[128];
-		::sprintf(szTemp,"UNNAMED_%i",iCnt++);
-		mName = szTemp;
+        // Generate a default name for the node
+        char szTemp[128];
+        ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
+        mName = szTemp;
 
-		aRotationKeys.reserve (20);
-		aPositionKeys.reserve (20);
-		aScalingKeys.reserve  (20);
-	}
+        aRotationKeys.reserve (20);
+        aPositionKeys.reserve (20);
+        aScalingKeys.reserve  (20);
+    }
 
-	~Node()
-	{
-		for (unsigned int i = 0; i < mChildren.size();++i)
-			delete mChildren[i];
-	}
+    ~Node()
+    {
+        for (unsigned int i = 0; i < mChildren.size();++i)
+            delete mChildren[i];
+    }
 
-	//! Pointer to the parent node
-	Node* mParent;
+    //! Pointer to the parent node
+    Node* mParent;
 
-	//! Holds all child nodes
-	std::vector<Node*> mChildren;
+    //! Holds all child nodes
+    std::vector<Node*> mChildren;
 
-	//! Name of the node
-	std::string mName;
+    //! Name of the node
+    std::string mName;
 
-	//! InstanceNumber of the node
-	int32_t mInstanceNumber;
+    //! InstanceNumber of the node
+    int32_t mInstanceNumber;
 
-	//! Dummy nodes: real name to be combined with the $$$DUMMY
-	std::string mDummyName;
+    //! Dummy nodes: real name to be combined with the $$$DUMMY
+    std::string mDummyName;
 
-	//! Position of the node in the hierarchy (tree depth)
-	int16_t mHierarchyPos;
+    //! Position of the node in the hierarchy (tree depth)
+    int16_t mHierarchyPos;
 
-	//! Index of the node
-	int16_t mHierarchyIndex;
+    //! Index of the node
+    int16_t mHierarchyIndex;
 
-	//! Rotation keys loaded from the file
-	std::vector<aiQuatKey> aRotationKeys;
+    //! Rotation keys loaded from the file
+    std::vector<aiQuatKey> aRotationKeys;
 
-	//! Position keys loaded from the file
-	std::vector<aiVectorKey> aPositionKeys;
+    //! Position keys loaded from the file
+    std::vector<aiVectorKey> aPositionKeys;
 
-	//! Scaling keys loaded from the file
-	std::vector<aiVectorKey> aScalingKeys;
+    //! Scaling keys loaded from the file
+    std::vector<aiVectorKey> aScalingKeys;
 
 
-	// For target lights (spot lights and directional lights):
-	// The position of the target
-	std::vector< aiVectorKey > aTargetPositionKeys;
+    // For target lights (spot lights and directional lights):
+    // The position of the target
+    std::vector< aiVectorKey > aTargetPositionKeys;
 
-	// For cameras: the camera roll angle
-	std::vector< aiFloatKey > aCameraRollKeys;
+    // For cameras: the camera roll angle
+    std::vector< aiFloatKey > aCameraRollKeys;
 
-	//! Pivot position loaded from the file
-	aiVector3D vPivot;
+    //! Pivot position loaded from the file
+    aiVector3D vPivot;
 
-	//instance count, will be kept only for the first node
-	int32_t mInstanceCount;
+    //instance count, will be kept only for the first node
+    int32_t mInstanceCount;
 
-	//! Add a child node, setup the right parent node for it
-	//! \param pc Node to be 'adopted'
-	inline Node& push_back(Node* pc)
-	{
-		mChildren.push_back(pc);
-		pc->mParent = this;
-		return *this;
-	}
+    //! Add a child node, setup the right parent node for it
+    //! \param pc Node to be 'adopted'
+    inline Node& push_back(Node* pc)
+    {
+        mChildren.push_back(pc);
+        pc->mParent = this;
+        return *this;
+    }
 };
 // ---------------------------------------------------------------------------
 /** Helper structure analogue to aiScene */
 struct Scene
 {
-	//! List of all materials loaded
-	//! NOTE: 3ds references materials globally
-	std::vector<Material> mMaterials;
+    //! List of all materials loaded
+    //! NOTE: 3ds references materials globally
+    std::vector<Material> mMaterials;
 
-	//! List of all meshes loaded
-	std::vector<Mesh> mMeshes;
+    //! List of all meshes loaded
+    std::vector<Mesh> mMeshes;
 
-	//! List of all cameras loaded
-	std::vector<aiCamera*> mCameras;
+    //! List of all cameras loaded
+    std::vector<aiCamera*> mCameras;
 
-	//! List of all lights loaded
-	std::vector<aiLight*> mLights;
+    //! List of all lights loaded
+    std::vector<aiLight*> mLights;
 
-	//! Pointer to the root node of the scene
-	// --- moved to main class
-	// Node* pcRootNode;
+    //! Pointer to the root node of the scene
+    // --- moved to main class
+    // Node* pcRootNode;
 };
 
 

+ 1177 - 1177
code/3DSLoader.cpp

@@ -59,16 +59,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-	"Discreet 3DS Importer",
-	"",
-	"",
-	"Limited animation support",
-	aiImporterFlags_SupportBinaryFlavour,
-	0,
-	0,
-	0,
-	0,
-	"3ds prj"
+    "Discreet 3DS Importer",
+    "",
+    "",
+    "Limited animation support",
+    aiImporterFlags_SupportBinaryFlavour,
+    0,
+    0,
+    0,
+    0,
+    "3ds prj"
 };
 
 
@@ -77,28 +77,28 @@ static const aiImporterDesc desc = {
 // - Reads the current chunk and validates it
 // - computes its length
 #define ASSIMP_3DS_BEGIN_CHUNK()                                         \
-	while (true) {                                                       \
-	if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \
-		return;                                                          \
-	}                                                                    \
-	Discreet3DS::Chunk chunk;                                            \
-	ReadChunk(&chunk);                                                   \
-	int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk);	             \
+    while (true) {                                                       \
+    if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)){ \
+        return;                                                          \
+    }                                                                    \
+    Discreet3DS::Chunk chunk;                                            \
+    ReadChunk(&chunk);                                                   \
+    int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk);               \
     if(chunkSize <= 0)                                                   \
         continue;                                                        \
-	const int oldReadLimit = stream->GetReadLimit();                     \
-	stream->SetReadLimit(stream->GetCurrentPos() + chunkSize);           \
+    const int oldReadLimit = stream->GetReadLimit();                     \
+    stream->SetReadLimit(stream->GetCurrentPos() + chunkSize);           \
 
 
 // ------------------------------------------------------------------------------------------------
 // End a parsing block
 // Must follow at the end of each parsing block, reset chunk end marker to previous value
 #define ASSIMP_3DS_END_CHUNK()                  \
-	stream->SkipToReadLimit();                  \
-	stream->SetReadLimit(oldReadLimit);         \
-	if (stream->GetRemainingSizeToLimit() == 0) \
-		return;                                 \
-	}
+    stream->SkipToReadLimit();                  \
+    stream->SetReadLimit(oldReadLimit);         \
+    if (stream->GetRemainingSizeToLimit() == 0) \
+        return;                                 \
+    }
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
@@ -114,494 +114,494 @@ Discreet3DSImporter::~Discreet3DSImporter()
 // Returns whether the class can handle the format of the given file.
 bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-	std::string extension = GetExtension(pFile);
-	if(extension == "3ds" || extension == "prj" ) {
-		return true;
-	}
-	if (!extension.length() || checkSig) {
-		uint16_t token[3];
-		token[0] = 0x4d4d;
-		token[1] = 0x3dc2;
-		//token[2] = 0x3daa;
-		return CheckMagicToken(pIOHandler,pFile,token,2,0,2);
-	}
-	return false;
+    std::string extension = GetExtension(pFile);
+    if(extension == "3ds" || extension == "prj" ) {
+        return true;
+    }
+    if (!extension.length() || checkSig) {
+        uint16_t token[3];
+        token[0] = 0x4d4d;
+        token[1] = 0x3dc2;
+        //token[2] = 0x3daa;
+        return CheckMagicToken(pIOHandler,pFile,token,2,0,2);
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Loader registry entry
 const aiImporterDesc* Discreet3DSImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup configuration properties
 void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/)
 {
-	// nothing to be done for the moment
+    // nothing to be done for the moment
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void Discreet3DSImporter::InternReadFile( const std::string& pFile,
-	aiScene* pScene, IOSystem* pIOHandler)
+    aiScene* pScene, IOSystem* pIOHandler)
 {
-	StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
-	this->stream = &stream;
-
-	// We should have at least one chunk
-	if (stream.GetRemainingSize() < 16) {
-		throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
-	}
-
-	// Allocate our temporary 3DS representation
-	mScene = new D3DS::Scene();
-
-	// Initialize members
-	mLastNodeIndex             = -1;
-	mCurrentNode               = new D3DS::Node();
-	mRootNode                  = mCurrentNode;
-	mRootNode->mHierarchyPos   = -1;
-	mRootNode->mHierarchyIndex = -1;
-	mRootNode->mParent         = NULL;
-	mMasterScale               = 1.0f;
-	mBackgroundImage           = "";
-	bHasBG                     = false;
-	bIsPrj                     = false;
-
-	// Parse the file
-	ParseMainChunk();
-
-	// Process all meshes in the file. First check whether all
-	// face indices haev valid values. The generate our
-	// internal verbose representation. Finally compute normal
-	// vectors from the smoothing groups we read from the
-	// file.
-	for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(),
-		 end = mScene->mMeshes.end(); i != end;++i)	{
-		if ((*i).mFaces.size() > 0 && (*i).mPositions.size() == 0)	{
-			delete mScene;
-			throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile);
-		}
-		CheckIndices(*i);
-		MakeUnique  (*i);
-		ComputeNormalsWithSmoothingsGroups<D3DS::Face>(*i);
-	}
-
-	// Replace all occurences of the default material with a
-	// valid material. Generate it if no material containing
-	// DEFAULT in its name has been found in the file
-	ReplaceDefaultMaterial();
-
-	// Convert the scene from our internal representation to an
-	// aiScene object. This involves copying all meshes, lights
-	// and cameras to the scene
-	ConvertScene(pScene);
-
-	// Generate the node graph for the scene. This is a little bit
-	// tricky since we'll need to split some meshes into submeshes
-	GenerateNodeGraph(pScene);
-
-	// Now apply the master scaling factor to the scene
-	ApplyMasterScale(pScene);
-
-	// Delete our internal scene representation and the root
-	// node, so the whole hierarchy will follow
-	delete mRootNode;
-	delete mScene;
-
-	AI_DEBUG_INVALIDATE_PTR(mRootNode);
-	AI_DEBUG_INVALIDATE_PTR(mScene);
-	AI_DEBUG_INVALIDATE_PTR(this->stream);
+    StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
+    this->stream = &stream;
+
+    // We should have at least one chunk
+    if (stream.GetRemainingSize() < 16) {
+        throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
+    }
+
+    // Allocate our temporary 3DS representation
+    mScene = new D3DS::Scene();
+
+    // Initialize members
+    mLastNodeIndex             = -1;
+    mCurrentNode               = new D3DS::Node();
+    mRootNode                  = mCurrentNode;
+    mRootNode->mHierarchyPos   = -1;
+    mRootNode->mHierarchyIndex = -1;
+    mRootNode->mParent         = NULL;
+    mMasterScale               = 1.0f;
+    mBackgroundImage           = "";
+    bHasBG                     = false;
+    bIsPrj                     = false;
+
+    // Parse the file
+    ParseMainChunk();
+
+    // Process all meshes in the file. First check whether all
+    // face indices haev valid values. The generate our
+    // internal verbose representation. Finally compute normal
+    // vectors from the smoothing groups we read from the
+    // file.
+    for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(),
+         end = mScene->mMeshes.end(); i != end;++i) {
+        if ((*i).mFaces.size() > 0 && (*i).mPositions.size() == 0)  {
+            delete mScene;
+            throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile);
+        }
+        CheckIndices(*i);
+        MakeUnique  (*i);
+        ComputeNormalsWithSmoothingsGroups<D3DS::Face>(*i);
+    }
+
+    // Replace all occurences of the default material with a
+    // valid material. Generate it if no material containing
+    // DEFAULT in its name has been found in the file
+    ReplaceDefaultMaterial();
+
+    // Convert the scene from our internal representation to an
+    // aiScene object. This involves copying all meshes, lights
+    // and cameras to the scene
+    ConvertScene(pScene);
+
+    // Generate the node graph for the scene. This is a little bit
+    // tricky since we'll need to split some meshes into submeshes
+    GenerateNodeGraph(pScene);
+
+    // Now apply the master scaling factor to the scene
+    ApplyMasterScale(pScene);
+
+    // Delete our internal scene representation and the root
+    // node, so the whole hierarchy will follow
+    delete mRootNode;
+    delete mScene;
+
+    AI_DEBUG_INVALIDATE_PTR(mRootNode);
+    AI_DEBUG_INVALIDATE_PTR(mScene);
+    AI_DEBUG_INVALIDATE_PTR(this->stream);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Applies a master-scaling factor to the imported scene
 void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
 {
-	// There are some 3DS files with a zero scaling factor
-	if (!mMasterScale)mMasterScale = 1.0f;
-	else mMasterScale = 1.0f / mMasterScale;
-
-	// Construct an uniform scaling matrix and multiply with it
-	pScene->mRootNode->mTransformation *= aiMatrix4x4(
-		mMasterScale,0.0f, 0.0f, 0.0f,
-		0.0f, mMasterScale,0.0f, 0.0f,
-		0.0f, 0.0f, mMasterScale,0.0f,
-		0.0f, 0.0f, 0.0f, 1.0f);
-
-	// Check whether a scaling track is assigned to the root node.
+    // There are some 3DS files with a zero scaling factor
+    if (!mMasterScale)mMasterScale = 1.0f;
+    else mMasterScale = 1.0f / mMasterScale;
+
+    // Construct an uniform scaling matrix and multiply with it
+    pScene->mRootNode->mTransformation *= aiMatrix4x4(
+        mMasterScale,0.0f, 0.0f, 0.0f,
+        0.0f, mMasterScale,0.0f, 0.0f,
+        0.0f, 0.0f, mMasterScale,0.0f,
+        0.0f, 0.0f, 0.0f, 1.0f);
+
+    // Check whether a scaling track is assigned to the root node.
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads a new chunk from the file
 void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
 {
-	ai_assert(pcOut != NULL);
+    ai_assert(pcOut != NULL);
 
-	pcOut->Flag = stream->GetI2();
-	pcOut->Size = stream->GetI4();
+    pcOut->Flag = stream->GetI2();
+    pcOut->Size = stream->GetI4();
 
-	if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize())
-		throw DeadlyImportError("Chunk is too large");
+    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize())
+        throw DeadlyImportError("Chunk is too large");
 
-	if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit())
-		DefaultLogger::get()->error("3DS: Chunk overflow");
+    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit())
+        DefaultLogger::get()->error("3DS: Chunk overflow");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Skip a chunk
 void Discreet3DSImporter::SkipChunk()
 {
-	Discreet3DS::Chunk psChunk;
-	ReadChunk(&psChunk);
+    Discreet3DS::Chunk psChunk;
+    ReadChunk(&psChunk);
 
-	stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk));
-	return;
+    stream->IncPtr(psChunk.Size-sizeof(Discreet3DS::Chunk));
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Process the primary chunk of the file
 void Discreet3DSImporter::ParseMainChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-
-	case Discreet3DS::CHUNK_PRJ:
-		bIsPrj = true;
-	case Discreet3DS::CHUNK_MAIN:
-		ParseEditorChunk();
-		break;
-	};
-
-	ASSIMP_3DS_END_CHUNK();
-	// recursively continue processing this hierarchy level
-	return ParseMainChunk();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+
+    case Discreet3DS::CHUNK_PRJ:
+        bIsPrj = true;
+    case Discreet3DS::CHUNK_MAIN:
+        ParseEditorChunk();
+        break;
+    };
+
+    ASSIMP_3DS_END_CHUNK();
+    // recursively continue processing this hierarchy level
+    return ParseMainChunk();
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseEditorChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_OBJMESH:
-
-		ParseObjectChunk();
-		break;
-
-	// NOTE: In several documentations in the internet this
-	// chunk appears at different locations
-	case Discreet3DS::CHUNK_KEYFRAMER:
-
-		ParseKeyframeChunk();
-		break;
-
-	case Discreet3DS::CHUNK_VERSION:
-		{
-		// print the version number
-		char buff[10];
-		ASSIMP_itoa10(buff,stream->GetI2());
-		DefaultLogger::get()->info(std::string("3DS file format version: ") + buff);
-		}
-		break;
-	};
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_OBJMESH:
+
+        ParseObjectChunk();
+        break;
+
+    // NOTE: In several documentations in the internet this
+    // chunk appears at different locations
+    case Discreet3DS::CHUNK_KEYFRAMER:
+
+        ParseKeyframeChunk();
+        break;
+
+    case Discreet3DS::CHUNK_VERSION:
+        {
+        // print the version number
+        char buff[10];
+        ASSIMP_itoa10(buff,stream->GetI2());
+        DefaultLogger::get()->info(std::string("3DS file format version: ") + buff);
+        }
+        break;
+    };
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseObjectChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_OBJBLOCK:
-		{
-		unsigned int cnt = 0;
-		const char* sz = (const char*)stream->GetPtr();
-
-		// Get the name of the geometry object
-		while (stream->GetI1())++cnt;
-		ParseChunk(sz,cnt);
-		}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_MATERIAL:
-
-		// Add a new material to the list
-		mScene->mMaterials.push_back(D3DS::Material());
-		ParseMaterialChunk();
-		break;
-
-	case Discreet3DS::CHUNK_AMBCOLOR:
-
-		// This is the ambient base color of the scene.
-		// We add it to the ambient color of all materials
-		ParseColorChunk(&mClrAmbient,true);
-		if (is_qnan(mClrAmbient.r))
-		{
-			// We failed to read the ambient base color.
-			DefaultLogger::get()->error("3DS: Failed to read ambient base color");
-			mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
-		}
-		break;
-
-	case Discreet3DS::CHUNK_BIT_MAP:
-		{
-		// Specifies the background image. The string should already be
-		// properly 0 terminated but we need to be sure
-		unsigned int cnt = 0;
-		const char* sz = (const char*)stream->GetPtr();
-		while (stream->GetI1())++cnt;
-		mBackgroundImage = std::string(sz,cnt);
-		}
-		break;
-
-	case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
-		bHasBG = true;
-		break;
-
-	case Discreet3DS::CHUNK_MASTER_SCALE:
-		// Scene master scaling factor
-		mMasterScale = stream->GetF4();
-		break;
-	};
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_OBJBLOCK:
+        {
+        unsigned int cnt = 0;
+        const char* sz = (const char*)stream->GetPtr();
+
+        // Get the name of the geometry object
+        while (stream->GetI1())++cnt;
+        ParseChunk(sz,cnt);
+        }
+        break;
+
+    case Discreet3DS::CHUNK_MAT_MATERIAL:
+
+        // Add a new material to the list
+        mScene->mMaterials.push_back(D3DS::Material());
+        ParseMaterialChunk();
+        break;
+
+    case Discreet3DS::CHUNK_AMBCOLOR:
+
+        // This is the ambient base color of the scene.
+        // We add it to the ambient color of all materials
+        ParseColorChunk(&mClrAmbient,true);
+        if (is_qnan(mClrAmbient.r))
+        {
+            // We failed to read the ambient base color.
+            DefaultLogger::get()->error("3DS: Failed to read ambient base color");
+            mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
+        }
+        break;
+
+    case Discreet3DS::CHUNK_BIT_MAP:
+        {
+        // Specifies the background image. The string should already be
+        // properly 0 terminated but we need to be sure
+        unsigned int cnt = 0;
+        const char* sz = (const char*)stream->GetPtr();
+        while (stream->GetI1())++cnt;
+        mBackgroundImage = std::string(sz,cnt);
+        }
+        break;
+
+    case Discreet3DS::CHUNK_BIT_MAP_EXISTS:
+        bHasBG = true;
+        break;
+
+    case Discreet3DS::CHUNK_MASTER_SCALE:
+        // Scene master scaling factor
+        mMasterScale = stream->GetF4();
+        break;
+    };
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// IMPLEMENTATION NOTE;
-	// Cameras or lights define their transformation in their parent node and in the
-	// corresponding light or camera chunks. However, we read and process the latter
-	// to to be able to return valid cameras/lights even if no scenegraph is given.
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_TRIMESH:
-		{
-		// this starts a new triangle mesh
-		mScene->mMeshes.push_back(D3DS::Mesh());
-		D3DS::Mesh& m = mScene->mMeshes.back();
-
-		// Setup the name of the mesh
-		m.mName = std::string(name, num);
-
-		// Read mesh chunks
-		ParseMeshChunk();
-		}
-		break;
-
-	case Discreet3DS::CHUNK_LIGHT:
-		{
-		// This starts a new light
-		aiLight* light = new aiLight();
-		mScene->mLights.push_back(light);
-
-		light->mName.Set(std::string(name, num));
-
-		// First read the position of the light
-		light->mPosition.x = stream->GetF4();
-		light->mPosition.y = stream->GetF4();
-		light->mPosition.z = stream->GetF4();
-
-		light->mColorDiffuse = aiColor3D(1.f,1.f,1.f);
-
-		// Now check for further subchunks
-		if (!bIsPrj) /* fixme */
-			ParseLightChunk();
-
-		// The specular light color is identical the the diffuse light color. The ambient light color
-		// is equal to the ambient base color of the whole scene.
-		light->mColorSpecular = light->mColorDiffuse;
-		light->mColorAmbient  = mClrAmbient;
-
-		if (light->mType == aiLightSource_UNDEFINED)
-		{
-			// It must be a point light
-			light->mType = aiLightSource_POINT;
-		}}
-		break;
-
-	case Discreet3DS::CHUNK_CAMERA:
-		{
-		// This starts a new camera
-		aiCamera* camera = new aiCamera();
-		mScene->mCameras.push_back(camera);
-		camera->mName.Set(std::string(name, num));
-
-		// First read the position of the camera
-		camera->mPosition.x = stream->GetF4();
-		camera->mPosition.y = stream->GetF4();
-		camera->mPosition.z = stream->GetF4();
-
-		// Then the camera target
-		camera->mLookAt.x = stream->GetF4() - camera->mPosition.x;
-		camera->mLookAt.y = stream->GetF4() - camera->mPosition.y;
-		camera->mLookAt.z = stream->GetF4() - camera->mPosition.z;
-		float len = camera->mLookAt.Length();
-		if (len < 1e-5f) {
-
-			// There are some files with lookat == position. Don't know why or whether it's ok or not.
-			DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector");
-			camera->mLookAt = aiVector3D(0.f,1.f,0.f);
-
-		}
-		else camera->mLookAt /= len;
-
-		// And finally - the camera rotation angle, in counter clockwise direction
-		const float angle =  AI_DEG_TO_RAD( stream->GetF4() );
-		aiQuaternion quat(camera->mLookAt,angle);
-		camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f);
-
-		// Read the lense angle
-		camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() );
-		if (camera->mHorizontalFOV < 0.001f)  {
-			camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f);
-		}
-
-		// Now check for further subchunks
-		if (!bIsPrj) /* fixme */ {
-			ParseCameraChunk();
-		}}
-		break;
-	};
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // IMPLEMENTATION NOTE;
+    // Cameras or lights define their transformation in their parent node and in the
+    // corresponding light or camera chunks. However, we read and process the latter
+    // to to be able to return valid cameras/lights even if no scenegraph is given.
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_TRIMESH:
+        {
+        // this starts a new triangle mesh
+        mScene->mMeshes.push_back(D3DS::Mesh());
+        D3DS::Mesh& m = mScene->mMeshes.back();
+
+        // Setup the name of the mesh
+        m.mName = std::string(name, num);
+
+        // Read mesh chunks
+        ParseMeshChunk();
+        }
+        break;
+
+    case Discreet3DS::CHUNK_LIGHT:
+        {
+        // This starts a new light
+        aiLight* light = new aiLight();
+        mScene->mLights.push_back(light);
+
+        light->mName.Set(std::string(name, num));
+
+        // First read the position of the light
+        light->mPosition.x = stream->GetF4();
+        light->mPosition.y = stream->GetF4();
+        light->mPosition.z = stream->GetF4();
+
+        light->mColorDiffuse = aiColor3D(1.f,1.f,1.f);
+
+        // Now check for further subchunks
+        if (!bIsPrj) /* fixme */
+            ParseLightChunk();
+
+        // The specular light color is identical the the diffuse light color. The ambient light color
+        // is equal to the ambient base color of the whole scene.
+        light->mColorSpecular = light->mColorDiffuse;
+        light->mColorAmbient  = mClrAmbient;
+
+        if (light->mType == aiLightSource_UNDEFINED)
+        {
+            // It must be a point light
+            light->mType = aiLightSource_POINT;
+        }}
+        break;
+
+    case Discreet3DS::CHUNK_CAMERA:
+        {
+        // This starts a new camera
+        aiCamera* camera = new aiCamera();
+        mScene->mCameras.push_back(camera);
+        camera->mName.Set(std::string(name, num));
+
+        // First read the position of the camera
+        camera->mPosition.x = stream->GetF4();
+        camera->mPosition.y = stream->GetF4();
+        camera->mPosition.z = stream->GetF4();
+
+        // Then the camera target
+        camera->mLookAt.x = stream->GetF4() - camera->mPosition.x;
+        camera->mLookAt.y = stream->GetF4() - camera->mPosition.y;
+        camera->mLookAt.z = stream->GetF4() - camera->mPosition.z;
+        float len = camera->mLookAt.Length();
+        if (len < 1e-5f) {
+
+            // There are some files with lookat == position. Don't know why or whether it's ok or not.
+            DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector");
+            camera->mLookAt = aiVector3D(0.f,1.f,0.f);
+
+        }
+        else camera->mLookAt /= len;
+
+        // And finally - the camera rotation angle, in counter clockwise direction
+        const float angle =  AI_DEG_TO_RAD( stream->GetF4() );
+        aiQuaternion quat(camera->mLookAt,angle);
+        camera->mUp = quat.GetMatrix() * aiVector3D(0.f,1.f,0.f);
+
+        // Read the lense angle
+        camera->mHorizontalFOV = AI_DEG_TO_RAD ( stream->GetF4() );
+        if (camera->mHorizontalFOV < 0.001f)  {
+            camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f);
+        }
+
+        // Now check for further subchunks
+        if (!bIsPrj) /* fixme */ {
+            ParseCameraChunk();
+        }}
+        break;
+    };
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseLightChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-	aiLight* light = mScene->mLights.back();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_DL_SPOTLIGHT:
-		// Now we can be sure that the light is a spot light
-		light->mType = aiLightSource_SPOT;
-
-		// We wouldn't need to normalize here, but we do it
-		light->mDirection.x = stream->GetF4() - light->mPosition.x;
-		light->mDirection.y = stream->GetF4() - light->mPosition.y;
-		light->mDirection.z = stream->GetF4() - light->mPosition.z;
-		light->mDirection.Normalize();
-
-		// Now the hotspot and falloff angles - in degrees
-		light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() );
-
-		// FIX: the falloff angle is just an offset
-		light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() );
-		break;
-
-		// intensity multiplier
-	case Discreet3DS::CHUNK_DL_MULTIPLIER:
-		light->mColorDiffuse = light->mColorDiffuse * stream->GetF4();
-		break;
-
-		// light color
-	case Discreet3DS::CHUNK_RGBF:
-	case Discreet3DS::CHUNK_LINRGBF:
-		light->mColorDiffuse.r *= stream->GetF4();
-		light->mColorDiffuse.g *= stream->GetF4();
-		light->mColorDiffuse.b *= stream->GetF4();
-		break;
-
-		// light attenuation
-	case Discreet3DS::CHUNK_DL_ATTENUATE:
-		light->mAttenuationLinear = stream->GetF4();
-		break;
-	};
-
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+    aiLight* light = mScene->mLights.back();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_DL_SPOTLIGHT:
+        // Now we can be sure that the light is a spot light
+        light->mType = aiLightSource_SPOT;
+
+        // We wouldn't need to normalize here, but we do it
+        light->mDirection.x = stream->GetF4() - light->mPosition.x;
+        light->mDirection.y = stream->GetF4() - light->mPosition.y;
+        light->mDirection.z = stream->GetF4() - light->mPosition.z;
+        light->mDirection.Normalize();
+
+        // Now the hotspot and falloff angles - in degrees
+        light->mAngleInnerCone = AI_DEG_TO_RAD( stream->GetF4() );
+
+        // FIX: the falloff angle is just an offset
+        light->mAngleOuterCone = light->mAngleInnerCone+AI_DEG_TO_RAD( stream->GetF4() );
+        break;
+
+        // intensity multiplier
+    case Discreet3DS::CHUNK_DL_MULTIPLIER:
+        light->mColorDiffuse = light->mColorDiffuse * stream->GetF4();
+        break;
+
+        // light color
+    case Discreet3DS::CHUNK_RGBF:
+    case Discreet3DS::CHUNK_LINRGBF:
+        light->mColorDiffuse.r *= stream->GetF4();
+        light->mColorDiffuse.g *= stream->GetF4();
+        light->mColorDiffuse.b *= stream->GetF4();
+        break;
+
+        // light attenuation
+    case Discreet3DS::CHUNK_DL_ATTENUATE:
+        light->mAttenuationLinear = stream->GetF4();
+        break;
+    };
+
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseCameraChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-	aiCamera* camera = mScene->mCameras.back();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-		// near and far clip plane
-	case Discreet3DS::CHUNK_CAM_RANGES:
-		camera->mClipPlaneNear = stream->GetF4();
-		camera->mClipPlaneFar  = stream->GetF4();
-		break;
-	}
-
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+    aiCamera* camera = mScene->mCameras.back();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+        // near and far clip plane
+    case Discreet3DS::CHUNK_CAM_RANGES:
+        camera->mClipPlaneNear = stream->GetF4();
+        camera->mClipPlaneFar  = stream->GetF4();
+        break;
+    }
+
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseKeyframeChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_TRACKCAMTGT:
-	case Discreet3DS::CHUNK_TRACKSPOTL:
-	case Discreet3DS::CHUNK_TRACKCAMERA:
-	case Discreet3DS::CHUNK_TRACKINFO:
-	case Discreet3DS::CHUNK_TRACKLIGHT:
-	case Discreet3DS::CHUNK_TRACKLIGTGT:
-
-		// this starts a new mesh hierarchy chunk
-		ParseHierarchyChunk(chunk.Flag);
-		break;
-	};
-
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_TRACKCAMTGT:
+    case Discreet3DS::CHUNK_TRACKSPOTL:
+    case Discreet3DS::CHUNK_TRACKCAMERA:
+    case Discreet3DS::CHUNK_TRACKINFO:
+    case Discreet3DS::CHUNK_TRACKLIGHT:
+    case Discreet3DS::CHUNK_TRACKLIGTGT:
+
+        // this starts a new mesh hierarchy chunk
+        ParseHierarchyChunk(chunk.Flag);
+        break;
+    };
+
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Little helper function for ParseHierarchyChunk
 void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent)
 {
-	if (!pcCurrent)	{
-		mRootNode->push_back(pcNode);
-		return;
-	}
-
-	if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos)	{
-		if(pcCurrent->mParent) {
-			pcCurrent->mParent->push_back(pcNode);
-		}
-		else pcCurrent->push_back(pcNode);
-		return;
-	}
-	return InverseNodeSearch(pcNode,pcCurrent->mParent);
+    if (!pcCurrent) {
+        mRootNode->push_back(pcNode);
+        return;
+    }
+
+    if (pcCurrent->mHierarchyPos == pcNode->mHierarchyPos)  {
+        if(pcCurrent->mParent) {
+            pcCurrent->mParent->push_back(pcNode);
+        }
+        else pcCurrent->push_back(pcNode);
+        return;
+    }
+    return InverseNodeSearch(pcNode,pcCurrent->mParent);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Find a node with a specific name in the import hierarchy
 D3DS::Node* FindNode(D3DS::Node* root, const std::string& name)
 {
-	if (root->mName == name)
-		return root;
-	for (std::vector<D3DS::Node*>::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it)	{
-		D3DS::Node* nd;
-		if (( nd = FindNode(*it,name)))
-			return nd;
-	}
-	return NULL;
+    if (root->mName == name)
+        return root;
+    for (std::vector<D3DS::Node*>::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) {
+        D3DS::Node* nd;
+        if (( nd = FindNode(*it,name)))
+            return nd;
+    }
+    return NULL;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -609,806 +609,806 @@ D3DS::Node* FindNode(D3DS::Node* root, const std::string& name)
 template <class T>
 bool KeyUniqueCompare(const T& first, const T& second)
 {
-	return first.mTime == second.mTime;
+    return first.mTime == second.mTime;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Skip some additional import data.
 void Discreet3DSImporter::SkipTCBInfo()
 {
-	unsigned int flags = stream->GetI2();
-
-	if (!flags)	{
-		// Currently we can't do anything with these values. They occur
-		// quite rare, so it wouldn't be worth the effort implementing
-		// them. 3DS ist not really suitable for complex animations,
-		// so full support is not required.
-		DefaultLogger::get()->warn("3DS: Skipping TCB animation info");
-	}
-
-	if (flags & Discreet3DS::KEY_USE_TENS) {
-		stream->IncPtr(4);
-	}
-	if (flags & Discreet3DS::KEY_USE_BIAS) {
-		stream->IncPtr(4);
-	}
-	if (flags & Discreet3DS::KEY_USE_CONT) {
-		stream->IncPtr(4);
-	}
-	if (flags & Discreet3DS::KEY_USE_EASE_FROM) {
-		stream->IncPtr(4);
-	}
-	if (flags & Discreet3DS::KEY_USE_EASE_TO) {
-		stream->IncPtr(4);
-	}
+    unsigned int flags = stream->GetI2();
+
+    if (!flags) {
+        // Currently we can't do anything with these values. They occur
+        // quite rare, so it wouldn't be worth the effort implementing
+        // them. 3DS ist not really suitable for complex animations,
+        // so full support is not required.
+        DefaultLogger::get()->warn("3DS: Skipping TCB animation info");
+    }
+
+    if (flags & Discreet3DS::KEY_USE_TENS) {
+        stream->IncPtr(4);
+    }
+    if (flags & Discreet3DS::KEY_USE_BIAS) {
+        stream->IncPtr(4);
+    }
+    if (flags & Discreet3DS::KEY_USE_CONT) {
+        stream->IncPtr(4);
+    }
+    if (flags & Discreet3DS::KEY_USE_EASE_FROM) {
+        stream->IncPtr(4);
+    }
+    if (flags & Discreet3DS::KEY_USE_EASE_TO) {
+        stream->IncPtr(4);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Read hierarchy and keyframe info
 void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_TRACKOBJNAME:
-
-		// This is the name of the object to which the track applies. The chunk also
-		// defines the position of this object in the hierarchy.
-		{
-
-		// First of all: get the name of the object
-		unsigned int cnt = 0;
-		const char* sz = (const char*)stream->GetPtr();
-
-		while (stream->GetI1())++cnt;
-		std::string name = std::string(sz,cnt);
-
-		// Now find out whether we have this node already (target animation channels
-		// are stored with a separate object ID)
-		D3DS::Node* pcNode = FindNode(mRootNode,name);
-		int instanceNumber = 1;
-
-		if ( pcNode)
-		{
-			// if the source is not a CHUNK_TRACKINFO block it wont be an object instance
-			if (parent != Discreet3DS::CHUNK_TRACKINFO)
-			{
-				mCurrentNode = pcNode;
-				break;
-			}
-			pcNode->mInstanceCount++;
-			instanceNumber = pcNode->mInstanceCount;
-		}
-		pcNode = new D3DS::Node();
-		pcNode->mName = name;
-		pcNode->mInstanceNumber = instanceNumber;
-
-		// There are two unknown values which we can safely ignore
-		stream->IncPtr(4);
-
-		// Now read the hierarchy position of the object
-		uint16_t hierarchy = stream->GetI2() + 1;
-		pcNode->mHierarchyPos   = hierarchy;
-		pcNode->mHierarchyIndex = mLastNodeIndex;
-
-		// And find a proper position in the graph for it
-		if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy)	{
-
-			// add to the parent of the last touched node
-			mCurrentNode->mParent->push_back(pcNode);
-			mLastNodeIndex++;
-		}
-		else if(hierarchy >= mLastNodeIndex)	{
-
-			// place it at the current position in the hierarchy
-			mCurrentNode->push_back(pcNode);
-			mLastNodeIndex = hierarchy;
-		}
-		else	{
-			// need to go back to the specified position in the hierarchy.
-			InverseNodeSearch(pcNode,mCurrentNode);
-			mLastNodeIndex++;
-		}
-		// Make this node the current node
-		mCurrentNode = pcNode;
-		}
-		break;
-
-	case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME:
-
-		// This is the "real" name of a $$$DUMMY object
-		{
-			const char* sz = (const char*) stream->GetPtr();
-			while (stream->GetI1());
-
-			// If object name is DUMMY, take this one instead
-			if (mCurrentNode->mName == "$$$DUMMY")	{
-				//DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object");
-				mCurrentNode->mName = std::string(sz);
-				break;
-			}
-		}
-		break;
-
-	case Discreet3DS::CHUNK_TRACKPIVOT:
-
-		if ( Discreet3DS::CHUNK_TRACKINFO != parent)
-		{
-			DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object");
-			break;
-		}
-
-		// Pivot = origin of rotation and scaling
-		mCurrentNode->vPivot.x = stream->GetF4();
-		mCurrentNode->vPivot.y = stream->GetF4();
-		mCurrentNode->vPivot.z = stream->GetF4();
-		break;
-
-
-		// ////////////////////////////////////////////////////////////////////
-		// POSITION KEYFRAME
-	case Discreet3DS::CHUNK_TRACKPOS:
-		{
-		stream->IncPtr(10);
-		const unsigned int numFrames = stream->GetI4();
-		bool sortKeys = false;
-
-		// This could also be meant as the target position for
-		// (targeted) lights and cameras
-		std::vector<aiVectorKey>* l;
-		if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent)	{
-			l = & mCurrentNode->aTargetPositionKeys;
-		}
-		else l = & mCurrentNode->aPositionKeys;
-
-		l->reserve(numFrames);
-		for (unsigned int i = 0; i < numFrames;++i)	{
-			const unsigned int fidx = stream->GetI4();
-
-			// Setup a new position key
-			aiVectorKey v;
-			v.mTime = (double)fidx;
-
-			SkipTCBInfo();
-			v.mValue.x = stream->GetF4();
-			v.mValue.y = stream->GetF4();
-			v.mValue.z = stream->GetF4();
-
-			// check whether we'll need to sort the keys
-			if (!l->empty() && v.mTime <= l->back().mTime)
-				sortKeys = true;
-
-			// Add the new keyframe to the list
-			l->push_back(v);
-		}
-
-		// Sort all keys with ascending time values and remove duplicates?
-		if (sortKeys)	{
-			std::stable_sort(l->begin(),l->end());
-			l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
-		}}
-
-		break;
-
-		// ////////////////////////////////////////////////////////////////////
-		// CAMERA ROLL KEYFRAME
-	case Discreet3DS::CHUNK_TRACKROLL:
-		{
-		// roll keys are accepted for cameras only
-		if (parent != Discreet3DS::CHUNK_TRACKCAMERA)	{
-			DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object");
-			break;
-		}
-		bool sortKeys = false;
-		std::vector<aiFloatKey>* l = &mCurrentNode->aCameraRollKeys;
-
-		stream->IncPtr(10);
-		const unsigned int numFrames = stream->GetI4();
-		l->reserve(numFrames);
-		for (unsigned int i = 0; i < numFrames;++i)	{
-			const unsigned int fidx = stream->GetI4();
-
-			// Setup a new position key
-			aiFloatKey v;
-			v.mTime = (double)fidx;
-
-			// This is just a single float
-			SkipTCBInfo();
-			v.mValue = stream->GetF4();
-
-			// Check whether we'll need to sort the keys
-			if (!l->empty() && v.mTime <= l->back().mTime)
-				sortKeys = true;
-
-			// Add the new keyframe to the list
-			l->push_back(v);
-		}
-
-		// Sort all keys with ascending time values and remove duplicates?
-		if (sortKeys)	{
-			std::stable_sort(l->begin(),l->end());
-			l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiFloatKey>), l->end() );
-		}}
-		break;
-
-
-		// ////////////////////////////////////////////////////////////////////
-		// CAMERA FOV KEYFRAME
-	case Discreet3DS::CHUNK_TRACKFOV:
-		{
-			DefaultLogger::get()->error("3DS: Skipping FOV animation track. "
-				"This is not supported");
-		}
-		break;
-
-
-		// ////////////////////////////////////////////////////////////////////
-		// ROTATION KEYFRAME
-	case Discreet3DS::CHUNK_TRACKROTATE:
-		{
-		stream->IncPtr(10);
-		const unsigned int numFrames = stream->GetI4();
-
-		bool sortKeys = false;
-		std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys;
-		l->reserve(numFrames);
-
-		for (unsigned int i = 0; i < numFrames;++i)	{
-			const unsigned int fidx = stream->GetI4();
-			SkipTCBInfo();
-
-			aiQuatKey v;
-			v.mTime = (double)fidx;
-
-			// The rotation keyframe is given as an axis-angle pair
-			const float rad = stream->GetF4();
-			aiVector3D axis;
-			axis.x = stream->GetF4();
-			axis.y = stream->GetF4();
-			axis.z = stream->GetF4();
-
-			if (!axis.x && !axis.y && !axis.z)
-				axis.y = 1.f;
-
-			// Construct a rotation quaternion from the axis-angle pair
-			v.mValue = aiQuaternion(axis,rad);
-
-			// Check whether we'll need to sort the keys
-			if (!l->empty() && v.mTime <= l->back().mTime)
-				sortKeys = true;
-
-			// add the new keyframe to the list
-			l->push_back(v);
-		}
-		// Sort all keys with ascending time values and remove duplicates?
-		if (sortKeys)	{
-			std::stable_sort(l->begin(),l->end());
-			l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiQuatKey>), l->end() );
-		}}
-		break;
-
-		// ////////////////////////////////////////////////////////////////////
-		// SCALING KEYFRAME
-	case Discreet3DS::CHUNK_TRACKSCALE:
-		{
-		stream->IncPtr(10);
-		const unsigned int numFrames = stream->GetI2();
-		stream->IncPtr(2);
-
-		bool sortKeys = false;
-		std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys;
-		l->reserve(numFrames);
-
-		for (unsigned int i = 0; i < numFrames;++i)	{
-			const unsigned int fidx = stream->GetI4();
-			SkipTCBInfo();
-
-			// Setup a new key
-			aiVectorKey v;
-			v.mTime = (double)fidx;
-
-			// ... and read its value
-			v.mValue.x = stream->GetF4();
-			v.mValue.y = stream->GetF4();
-			v.mValue.z = stream->GetF4();
-
-			// check whether we'll need to sort the keys
-			if (!l->empty() && v.mTime <= l->back().mTime)
-				sortKeys = true;
-
-			// Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files
-			if (!v.mValue.x) v.mValue.x = 1.f;
-			if (!v.mValue.y) v.mValue.y = 1.f;
-			if (!v.mValue.z) v.mValue.z = 1.f;
-
-			l->push_back(v);
-		}
-		// Sort all keys with ascending time values and remove duplicates?
-		if (sortKeys)	{
-			std::stable_sort(l->begin(),l->end());
-			l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
-		}}
-		break;
-	};
-
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_TRACKOBJNAME:
+
+        // This is the name of the object to which the track applies. The chunk also
+        // defines the position of this object in the hierarchy.
+        {
+
+        // First of all: get the name of the object
+        unsigned int cnt = 0;
+        const char* sz = (const char*)stream->GetPtr();
+
+        while (stream->GetI1())++cnt;
+        std::string name = std::string(sz,cnt);
+
+        // Now find out whether we have this node already (target animation channels
+        // are stored with a separate object ID)
+        D3DS::Node* pcNode = FindNode(mRootNode,name);
+        int instanceNumber = 1;
+
+        if ( pcNode)
+        {
+            // if the source is not a CHUNK_TRACKINFO block it wont be an object instance
+            if (parent != Discreet3DS::CHUNK_TRACKINFO)
+            {
+                mCurrentNode = pcNode;
+                break;
+            }
+            pcNode->mInstanceCount++;
+            instanceNumber = pcNode->mInstanceCount;
+        }
+        pcNode = new D3DS::Node();
+        pcNode->mName = name;
+        pcNode->mInstanceNumber = instanceNumber;
+
+        // There are two unknown values which we can safely ignore
+        stream->IncPtr(4);
+
+        // Now read the hierarchy position of the object
+        uint16_t hierarchy = stream->GetI2() + 1;
+        pcNode->mHierarchyPos   = hierarchy;
+        pcNode->mHierarchyIndex = mLastNodeIndex;
+
+        // And find a proper position in the graph for it
+        if (mCurrentNode && mCurrentNode->mHierarchyPos == hierarchy)   {
+
+            // add to the parent of the last touched node
+            mCurrentNode->mParent->push_back(pcNode);
+            mLastNodeIndex++;
+        }
+        else if(hierarchy >= mLastNodeIndex)    {
+
+            // place it at the current position in the hierarchy
+            mCurrentNode->push_back(pcNode);
+            mLastNodeIndex = hierarchy;
+        }
+        else    {
+            // need to go back to the specified position in the hierarchy.
+            InverseNodeSearch(pcNode,mCurrentNode);
+            mLastNodeIndex++;
+        }
+        // Make this node the current node
+        mCurrentNode = pcNode;
+        }
+        break;
+
+    case Discreet3DS::CHUNK_TRACKDUMMYOBJNAME:
+
+        // This is the "real" name of a $$$DUMMY object
+        {
+            const char* sz = (const char*) stream->GetPtr();
+            while (stream->GetI1());
+
+            // If object name is DUMMY, take this one instead
+            if (mCurrentNode->mName == "$$$DUMMY")  {
+                //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object");
+                mCurrentNode->mName = std::string(sz);
+                break;
+            }
+        }
+        break;
+
+    case Discreet3DS::CHUNK_TRACKPIVOT:
+
+        if ( Discreet3DS::CHUNK_TRACKINFO != parent)
+        {
+            DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object");
+            break;
+        }
+
+        // Pivot = origin of rotation and scaling
+        mCurrentNode->vPivot.x = stream->GetF4();
+        mCurrentNode->vPivot.y = stream->GetF4();
+        mCurrentNode->vPivot.z = stream->GetF4();
+        break;
+
+
+        // ////////////////////////////////////////////////////////////////////
+        // POSITION KEYFRAME
+    case Discreet3DS::CHUNK_TRACKPOS:
+        {
+        stream->IncPtr(10);
+        const unsigned int numFrames = stream->GetI4();
+        bool sortKeys = false;
+
+        // This could also be meant as the target position for
+        // (targeted) lights and cameras
+        std::vector<aiVectorKey>* l;
+        if ( Discreet3DS::CHUNK_TRACKCAMTGT == parent || Discreet3DS::CHUNK_TRACKLIGTGT == parent)  {
+            l = & mCurrentNode->aTargetPositionKeys;
+        }
+        else l = & mCurrentNode->aPositionKeys;
+
+        l->reserve(numFrames);
+        for (unsigned int i = 0; i < numFrames;++i) {
+            const unsigned int fidx = stream->GetI4();
+
+            // Setup a new position key
+            aiVectorKey v;
+            v.mTime = (double)fidx;
+
+            SkipTCBInfo();
+            v.mValue.x = stream->GetF4();
+            v.mValue.y = stream->GetF4();
+            v.mValue.z = stream->GetF4();
+
+            // check whether we'll need to sort the keys
+            if (!l->empty() && v.mTime <= l->back().mTime)
+                sortKeys = true;
+
+            // Add the new keyframe to the list
+            l->push_back(v);
+        }
+
+        // Sort all keys with ascending time values and remove duplicates?
+        if (sortKeys)   {
+            std::stable_sort(l->begin(),l->end());
+            l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
+        }}
+
+        break;
+
+        // ////////////////////////////////////////////////////////////////////
+        // CAMERA ROLL KEYFRAME
+    case Discreet3DS::CHUNK_TRACKROLL:
+        {
+        // roll keys are accepted for cameras only
+        if (parent != Discreet3DS::CHUNK_TRACKCAMERA)   {
+            DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object");
+            break;
+        }
+        bool sortKeys = false;
+        std::vector<aiFloatKey>* l = &mCurrentNode->aCameraRollKeys;
+
+        stream->IncPtr(10);
+        const unsigned int numFrames = stream->GetI4();
+        l->reserve(numFrames);
+        for (unsigned int i = 0; i < numFrames;++i) {
+            const unsigned int fidx = stream->GetI4();
+
+            // Setup a new position key
+            aiFloatKey v;
+            v.mTime = (double)fidx;
+
+            // This is just a single float
+            SkipTCBInfo();
+            v.mValue = stream->GetF4();
+
+            // Check whether we'll need to sort the keys
+            if (!l->empty() && v.mTime <= l->back().mTime)
+                sortKeys = true;
+
+            // Add the new keyframe to the list
+            l->push_back(v);
+        }
+
+        // Sort all keys with ascending time values and remove duplicates?
+        if (sortKeys)   {
+            std::stable_sort(l->begin(),l->end());
+            l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiFloatKey>), l->end() );
+        }}
+        break;
+
+
+        // ////////////////////////////////////////////////////////////////////
+        // CAMERA FOV KEYFRAME
+    case Discreet3DS::CHUNK_TRACKFOV:
+        {
+            DefaultLogger::get()->error("3DS: Skipping FOV animation track. "
+                "This is not supported");
+        }
+        break;
+
+
+        // ////////////////////////////////////////////////////////////////////
+        // ROTATION KEYFRAME
+    case Discreet3DS::CHUNK_TRACKROTATE:
+        {
+        stream->IncPtr(10);
+        const unsigned int numFrames = stream->GetI4();
+
+        bool sortKeys = false;
+        std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys;
+        l->reserve(numFrames);
+
+        for (unsigned int i = 0; i < numFrames;++i) {
+            const unsigned int fidx = stream->GetI4();
+            SkipTCBInfo();
+
+            aiQuatKey v;
+            v.mTime = (double)fidx;
+
+            // The rotation keyframe is given as an axis-angle pair
+            const float rad = stream->GetF4();
+            aiVector3D axis;
+            axis.x = stream->GetF4();
+            axis.y = stream->GetF4();
+            axis.z = stream->GetF4();
+
+            if (!axis.x && !axis.y && !axis.z)
+                axis.y = 1.f;
+
+            // Construct a rotation quaternion from the axis-angle pair
+            v.mValue = aiQuaternion(axis,rad);
+
+            // Check whether we'll need to sort the keys
+            if (!l->empty() && v.mTime <= l->back().mTime)
+                sortKeys = true;
+
+            // add the new keyframe to the list
+            l->push_back(v);
+        }
+        // Sort all keys with ascending time values and remove duplicates?
+        if (sortKeys)   {
+            std::stable_sort(l->begin(),l->end());
+            l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiQuatKey>), l->end() );
+        }}
+        break;
+
+        // ////////////////////////////////////////////////////////////////////
+        // SCALING KEYFRAME
+    case Discreet3DS::CHUNK_TRACKSCALE:
+        {
+        stream->IncPtr(10);
+        const unsigned int numFrames = stream->GetI2();
+        stream->IncPtr(2);
+
+        bool sortKeys = false;
+        std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys;
+        l->reserve(numFrames);
+
+        for (unsigned int i = 0; i < numFrames;++i) {
+            const unsigned int fidx = stream->GetI4();
+            SkipTCBInfo();
+
+            // Setup a new key
+            aiVectorKey v;
+            v.mTime = (double)fidx;
+
+            // ... and read its value
+            v.mValue.x = stream->GetF4();
+            v.mValue.y = stream->GetF4();
+            v.mValue.z = stream->GetF4();
+
+            // check whether we'll need to sort the keys
+            if (!l->empty() && v.mTime <= l->back().mTime)
+                sortKeys = true;
+
+            // Remove zero-scalings on singular axes - they've been reported to be there erroneously in some strange files
+            if (!v.mValue.x) v.mValue.x = 1.f;
+            if (!v.mValue.y) v.mValue.y = 1.f;
+            if (!v.mValue.z) v.mValue.z = 1.f;
+
+            l->push_back(v);
+        }
+        // Sort all keys with ascending time values and remove duplicates?
+        if (sortKeys)   {
+            std::stable_sort(l->begin(),l->end());
+            l->erase ( std::unique (l->begin(),l->end(),&KeyUniqueCompare<aiVectorKey>), l->end() );
+        }}
+        break;
+    };
+
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Read a face chunk - it contains smoothing groups and material assignments
 void Discreet3DSImporter::ParseFaceChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// Get the mesh we're currently working on
-	D3DS::Mesh& mMesh = mScene->mMeshes.back();
-
-	// Get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_SMOOLIST:
-		{
-		// This is the list of smoothing groups - a bitfield for every face.
-		// Up to 32 smoothing groups assigned to a single face.
-		unsigned int num = chunkSize/4, m = 0;
-		if (num > mMesh.mFaces.size())	{
-			throw DeadlyImportError("3DS: More smoothing groups than faces");
-		}
-		for (std::vector<D3DS::Face>::iterator i =  mMesh.mFaces.begin(); m != num;++i, ++m)	{
-			// nth bit is set for nth smoothing group
-			(*i).iSmoothGroup = stream->GetI4();
-		}}
-		break;
-
-	case Discreet3DS::CHUNK_FACEMAT:
-		{
-		// at fist an asciiz with the material name
-		const char* sz = (const char*)stream->GetPtr();
-		while (stream->GetI1());
-
-		// find the index of the material
-		unsigned int idx = 0xcdcdcdcd, cnt = 0;
-		for (std::vector<D3DS::Material>::const_iterator i =  mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt)	{
-			// use case independent comparisons. hopefully it will work.
-			if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str()))	{
-				idx = cnt;
-				break;
-			}
-		}
-		if (0xcdcdcdcd == idx)	{
-			DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz);
-		}
-
-		// Now continue and read all material indices
-		cnt = (uint16_t)stream->GetI2();
-		for (unsigned int i = 0; i < cnt;++i)	{
-			unsigned int fidx = (uint16_t)stream->GetI2();
-
-			// check range
-			if (fidx >= mMesh.mFaceMaterials.size())	{
-				DefaultLogger::get()->error("3DS: Invalid face index in face material list");
-			}
-			else mMesh.mFaceMaterials[fidx] = idx;
-		}}
-		break;
-	};
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // Get the mesh we're currently working on
+    D3DS::Mesh& mMesh = mScene->mMeshes.back();
+
+    // Get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_SMOOLIST:
+        {
+        // This is the list of smoothing groups - a bitfield for every face.
+        // Up to 32 smoothing groups assigned to a single face.
+        unsigned int num = chunkSize/4, m = 0;
+        if (num > mMesh.mFaces.size())  {
+            throw DeadlyImportError("3DS: More smoothing groups than faces");
+        }
+        for (std::vector<D3DS::Face>::iterator i =  mMesh.mFaces.begin(); m != num;++i, ++m)    {
+            // nth bit is set for nth smoothing group
+            (*i).iSmoothGroup = stream->GetI4();
+        }}
+        break;
+
+    case Discreet3DS::CHUNK_FACEMAT:
+        {
+        // at fist an asciiz with the material name
+        const char* sz = (const char*)stream->GetPtr();
+        while (stream->GetI1());
+
+        // find the index of the material
+        unsigned int idx = 0xcdcdcdcd, cnt = 0;
+        for (std::vector<D3DS::Material>::const_iterator i =  mScene->mMaterials.begin();i != mScene->mMaterials.end();++i,++cnt)   {
+            // use case independent comparisons. hopefully it will work.
+            if ((*i).mName.length() && !ASSIMP_stricmp(sz, (*i).mName.c_str())) {
+                idx = cnt;
+                break;
+            }
+        }
+        if (0xcdcdcdcd == idx)  {
+            DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz);
+        }
+
+        // Now continue and read all material indices
+        cnt = (uint16_t)stream->GetI2();
+        for (unsigned int i = 0; i < cnt;++i)   {
+            unsigned int fidx = (uint16_t)stream->GetI2();
+
+            // check range
+            if (fidx >= mMesh.mFaceMaterials.size())    {
+                DefaultLogger::get()->error("3DS: Invalid face index in face material list");
+            }
+            else mMesh.mFaceMaterials[fidx] = idx;
+        }}
+        break;
+    };
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Read a mesh chunk. Here's the actual mesh data
 void Discreet3DSImporter::ParseMeshChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// Get the mesh we're currently working on
-	D3DS::Mesh& mMesh = mScene->mMeshes.back();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_VERTLIST:
-		{
-		// This is the list of all vertices in the current mesh
-		int num = (int)(uint16_t)stream->GetI2();
-		mMesh.mPositions.reserve(num);
-		while (num-- > 0)	{
-			aiVector3D v;
-			v.x = stream->GetF4();
-			v.y = stream->GetF4();
-			v.z = stream->GetF4();
-			mMesh.mPositions.push_back(v);
-		}}
-		break;
-	case Discreet3DS::CHUNK_TRMATRIX:
-		{
-		// This is the RLEATIVE transformation matrix of the current mesh. Vertices are
-		// pretransformed by this matrix wonder.
-		mMesh.mMat.a1 = stream->GetF4();
-		mMesh.mMat.b1 = stream->GetF4();
-		mMesh.mMat.c1 = stream->GetF4();
-		mMesh.mMat.a2 = stream->GetF4();
-		mMesh.mMat.b2 = stream->GetF4();
-		mMesh.mMat.c2 = stream->GetF4();
-		mMesh.mMat.a3 = stream->GetF4();
-		mMesh.mMat.b3 = stream->GetF4();
-		mMesh.mMat.c3 = stream->GetF4();
-		mMesh.mMat.a4 = stream->GetF4();
-		mMesh.mMat.b4 = stream->GetF4();
-		mMesh.mMat.c4 = stream->GetF4();
-		}
-		break;
-
-	case Discreet3DS::CHUNK_MAPLIST:
-		{
-		// This is the list of all UV coords in the current mesh
-		int num = (int)(uint16_t)stream->GetI2();
-		mMesh.mTexCoords.reserve(num);
-		while (num-- > 0)	{
-			aiVector3D v;
-			v.x = stream->GetF4();
-			v.y = stream->GetF4();
-			mMesh.mTexCoords.push_back(v);
-		}}
-		break;
-
-	case Discreet3DS::CHUNK_FACELIST:
-		{
-		// This is the list of all faces in the current mesh
-		int num = (int)(uint16_t)stream->GetI2();
-		mMesh.mFaces.reserve(num);
-		while (num-- > 0)	{
-			// 3DS faces are ALWAYS triangles
-			mMesh.mFaces.push_back(D3DS::Face());
-			D3DS::Face& sFace = mMesh.mFaces.back();
-
-			sFace.mIndices[0] = (uint16_t)stream->GetI2();
-			sFace.mIndices[1] = (uint16_t)stream->GetI2();
-			sFace.mIndices[2] = (uint16_t)stream->GetI2();
-
-			stream->IncPtr(2); // skip edge visibility flag
-		}
-
-		// Resize the material array (0xcdcdcdcd marks the default material; so if a face is
-		// not referenced by a material, $$DEFAULT will be assigned to it)
-		mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd);
-
-		// Larger 3DS files could have multiple FACE chunks here
-		chunkSize = stream->GetRemainingSizeToLimit();
-		if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) )
-			ParseFaceChunk();
-		}
-		break;
-	};
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // Get the mesh we're currently working on
+    D3DS::Mesh& mMesh = mScene->mMeshes.back();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_VERTLIST:
+        {
+        // This is the list of all vertices in the current mesh
+        int num = (int)(uint16_t)stream->GetI2();
+        mMesh.mPositions.reserve(num);
+        while (num-- > 0)   {
+            aiVector3D v;
+            v.x = stream->GetF4();
+            v.y = stream->GetF4();
+            v.z = stream->GetF4();
+            mMesh.mPositions.push_back(v);
+        }}
+        break;
+    case Discreet3DS::CHUNK_TRMATRIX:
+        {
+        // This is the RLEATIVE transformation matrix of the current mesh. Vertices are
+        // pretransformed by this matrix wonder.
+        mMesh.mMat.a1 = stream->GetF4();
+        mMesh.mMat.b1 = stream->GetF4();
+        mMesh.mMat.c1 = stream->GetF4();
+        mMesh.mMat.a2 = stream->GetF4();
+        mMesh.mMat.b2 = stream->GetF4();
+        mMesh.mMat.c2 = stream->GetF4();
+        mMesh.mMat.a3 = stream->GetF4();
+        mMesh.mMat.b3 = stream->GetF4();
+        mMesh.mMat.c3 = stream->GetF4();
+        mMesh.mMat.a4 = stream->GetF4();
+        mMesh.mMat.b4 = stream->GetF4();
+        mMesh.mMat.c4 = stream->GetF4();
+        }
+        break;
+
+    case Discreet3DS::CHUNK_MAPLIST:
+        {
+        // This is the list of all UV coords in the current mesh
+        int num = (int)(uint16_t)stream->GetI2();
+        mMesh.mTexCoords.reserve(num);
+        while (num-- > 0)   {
+            aiVector3D v;
+            v.x = stream->GetF4();
+            v.y = stream->GetF4();
+            mMesh.mTexCoords.push_back(v);
+        }}
+        break;
+
+    case Discreet3DS::CHUNK_FACELIST:
+        {
+        // This is the list of all faces in the current mesh
+        int num = (int)(uint16_t)stream->GetI2();
+        mMesh.mFaces.reserve(num);
+        while (num-- > 0)   {
+            // 3DS faces are ALWAYS triangles
+            mMesh.mFaces.push_back(D3DS::Face());
+            D3DS::Face& sFace = mMesh.mFaces.back();
+
+            sFace.mIndices[0] = (uint16_t)stream->GetI2();
+            sFace.mIndices[1] = (uint16_t)stream->GetI2();
+            sFace.mIndices[2] = (uint16_t)stream->GetI2();
+
+            stream->IncPtr(2); // skip edge visibility flag
+        }
+
+        // Resize the material array (0xcdcdcdcd marks the default material; so if a face is
+        // not referenced by a material, $$DEFAULT will be assigned to it)
+        mMesh.mFaceMaterials.resize(mMesh.mFaces.size(),0xcdcdcdcd);
+
+        // Larger 3DS files could have multiple FACE chunks here
+        chunkSize = stream->GetRemainingSizeToLimit();
+        if ( chunkSize > (int) sizeof(Discreet3DS::Chunk ) )
+            ParseFaceChunk();
+        }
+        break;
+    };
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Read a 3DS material chunk
 void Discreet3DSImporter::ParseMaterialChunk()
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_MAT_MATNAME:
-
-		{
-		// The material name string is already zero-terminated, but we need to be sure ...
-		const char* sz = (const char*)stream->GetPtr();
-		unsigned int cnt = 0;
-		while (stream->GetI1())
-			++cnt;
-
-		if (!cnt)	{
-			// This may not be, we use the default name instead
-			DefaultLogger::get()->error("3DS: Empty material name");
-		}
-		else mScene->mMaterials.back().mName = std::string(sz,cnt);
-		}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_DIFFUSE:
-		{
-		// This is the diffuse material color
-		aiColor3D* pc = &mScene->mMaterials.back().mDiffuse;
-		ParseColorChunk(pc);
-		if (is_qnan(pc->r))	{
-			// color chunk is invalid. Simply ignore it
-			DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk");
-			pc->r = pc->g = pc->b = 1.0f;
-		}}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_SPECULAR:
-		{
-		// This is the specular material color
-		aiColor3D* pc = &mScene->mMaterials.back().mSpecular;
-		ParseColorChunk(pc);
-		if (is_qnan(pc->r))	{
-			// color chunk is invalid. Simply ignore it
-			DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk");
-			pc->r = pc->g = pc->b = 1.0f;
-		}}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_AMBIENT:
-		{
-		// This is the ambient material color
-		aiColor3D* pc = &mScene->mMaterials.back().mAmbient;
-		ParseColorChunk(pc);
-		if (is_qnan(pc->r))	{
-			// color chunk is invalid. Simply ignore it
-			DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk");
-			pc->r = pc->g = pc->b = 0.0f;
-		}}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_SELF_ILLUM:
-		{
-		// This is the emissive material color
-		aiColor3D* pc = &mScene->mMaterials.back().mEmissive;
-		ParseColorChunk(pc);
-		if (is_qnan(pc->r))	{
-			// color chunk is invalid. Simply ignore it
-			DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk");
-			pc->r = pc->g = pc->b = 0.0f;
-		}}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
-		{
-		// This is the material's transparency
-		float* pcf = &mScene->mMaterials.back().mTransparency;
-		*pcf = ParsePercentageChunk();
-
-		// NOTE: transparency, not opacity
-		if (is_qnan(*pcf))
-			*pcf = 1.0f;
-		else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
-		}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_SHADING:
-		// This is the material shading mode
-		mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2();
-		break;
-
-	case Discreet3DS::CHUNK_MAT_TWO_SIDE:
-		// This is the two-sided flag
-		mScene->mMaterials.back().mTwoSided = true;
-		break;
-
-	case Discreet3DS::CHUNK_MAT_SHININESS:
-		{ // This is the shininess of the material
-		float* pcf = &mScene->mMaterials.back().mSpecularExponent;
-		*pcf = ParsePercentageChunk();
-		if (is_qnan(*pcf))
-			*pcf = 0.0f;
-		else *pcf *= (float)0xFFFF;
-		}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
-		{ // This is the shininess strength of the material
-		float* pcf = &mScene->mMaterials.back().mShininessStrength;
-		*pcf = ParsePercentageChunk();
-		if (is_qnan(*pcf))
-			*pcf = 0.0f;
-		else *pcf *= (float)0xffff / 100.0f;
-		}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
-		{ // This is the self illumination strength of the material
-		float f = ParsePercentageChunk();
-		if (is_qnan(f))
-			f = 0.0f;
-		else f *= (float)0xFFFF / 100.0f;
-		mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f);
-		}
-		break;
-
-	// Parse texture chunks
-	case Discreet3DS::CHUNK_MAT_TEXTURE:
-		// Diffuse texture
-		ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse);
-		break;
-	case Discreet3DS::CHUNK_MAT_BUMPMAP:
-		// Height map
-		ParseTextureChunk(&mScene->mMaterials.back().sTexBump);
-		break;
-	case Discreet3DS::CHUNK_MAT_OPACMAP:
-		// Opacity texture
-		ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity);
-		break;
-	case Discreet3DS::CHUNK_MAT_MAT_SHINMAP:
-		// Shininess map
-		ParseTextureChunk(&mScene->mMaterials.back().sTexShininess);
-		break;
-	case Discreet3DS::CHUNK_MAT_SPECMAP:
-		// Specular map
-		ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular);
-		break;
-	case Discreet3DS::CHUNK_MAT_SELFIMAP:
-		// Self-illumination (emissive) map
-		ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive);
-		break;
-	case Discreet3DS::CHUNK_MAT_REFLMAP:
-		// Reflection map
-		ParseTextureChunk(&mScene->mMaterials.back().sTexReflective);
-		break;
-	};
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_MAT_MATNAME:
+
+        {
+        // The material name string is already zero-terminated, but we need to be sure ...
+        const char* sz = (const char*)stream->GetPtr();
+        unsigned int cnt = 0;
+        while (stream->GetI1())
+            ++cnt;
+
+        if (!cnt)   {
+            // This may not be, we use the default name instead
+            DefaultLogger::get()->error("3DS: Empty material name");
+        }
+        else mScene->mMaterials.back().mName = std::string(sz,cnt);
+        }
+        break;
+
+    case Discreet3DS::CHUNK_MAT_DIFFUSE:
+        {
+        // This is the diffuse material color
+        aiColor3D* pc = &mScene->mMaterials.back().mDiffuse;
+        ParseColorChunk(pc);
+        if (is_qnan(pc->r)) {
+            // color chunk is invalid. Simply ignore it
+            DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk");
+            pc->r = pc->g = pc->b = 1.0f;
+        }}
+        break;
+
+    case Discreet3DS::CHUNK_MAT_SPECULAR:
+        {
+        // This is the specular material color
+        aiColor3D* pc = &mScene->mMaterials.back().mSpecular;
+        ParseColorChunk(pc);
+        if (is_qnan(pc->r)) {
+            // color chunk is invalid. Simply ignore it
+            DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk");
+            pc->r = pc->g = pc->b = 1.0f;
+        }}
+        break;
+
+    case Discreet3DS::CHUNK_MAT_AMBIENT:
+        {
+        // This is the ambient material color
+        aiColor3D* pc = &mScene->mMaterials.back().mAmbient;
+        ParseColorChunk(pc);
+        if (is_qnan(pc->r)) {
+            // color chunk is invalid. Simply ignore it
+            DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk");
+            pc->r = pc->g = pc->b = 0.0f;
+        }}
+        break;
+
+    case Discreet3DS::CHUNK_MAT_SELF_ILLUM:
+        {
+        // This is the emissive material color
+        aiColor3D* pc = &mScene->mMaterials.back().mEmissive;
+        ParseColorChunk(pc);
+        if (is_qnan(pc->r)) {
+            // color chunk is invalid. Simply ignore it
+            DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk");
+            pc->r = pc->g = pc->b = 0.0f;
+        }}
+        break;
+
+    case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
+        {
+        // This is the material's transparency
+        float* pcf = &mScene->mMaterials.back().mTransparency;
+        *pcf = ParsePercentageChunk();
+
+        // NOTE: transparency, not opacity
+        if (is_qnan(*pcf))
+            *pcf = 1.0f;
+        else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
+        }
+        break;
+
+    case Discreet3DS::CHUNK_MAT_SHADING:
+        // This is the material shading mode
+        mScene->mMaterials.back().mShading = (D3DS::Discreet3DS::shadetype3ds)stream->GetI2();
+        break;
+
+    case Discreet3DS::CHUNK_MAT_TWO_SIDE:
+        // This is the two-sided flag
+        mScene->mMaterials.back().mTwoSided = true;
+        break;
+
+    case Discreet3DS::CHUNK_MAT_SHININESS:
+        { // This is the shininess of the material
+        float* pcf = &mScene->mMaterials.back().mSpecularExponent;
+        *pcf = ParsePercentageChunk();
+        if (is_qnan(*pcf))
+            *pcf = 0.0f;
+        else *pcf *= (float)0xFFFF;
+        }
+        break;
+
+    case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
+        { // This is the shininess strength of the material
+        float* pcf = &mScene->mMaterials.back().mShininessStrength;
+        *pcf = ParsePercentageChunk();
+        if (is_qnan(*pcf))
+            *pcf = 0.0f;
+        else *pcf *= (float)0xffff / 100.0f;
+        }
+        break;
+
+    case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
+        { // This is the self illumination strength of the material
+        float f = ParsePercentageChunk();
+        if (is_qnan(f))
+            f = 0.0f;
+        else f *= (float)0xFFFF / 100.0f;
+        mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f);
+        }
+        break;
+
+    // Parse texture chunks
+    case Discreet3DS::CHUNK_MAT_TEXTURE:
+        // Diffuse texture
+        ParseTextureChunk(&mScene->mMaterials.back().sTexDiffuse);
+        break;
+    case Discreet3DS::CHUNK_MAT_BUMPMAP:
+        // Height map
+        ParseTextureChunk(&mScene->mMaterials.back().sTexBump);
+        break;
+    case Discreet3DS::CHUNK_MAT_OPACMAP:
+        // Opacity texture
+        ParseTextureChunk(&mScene->mMaterials.back().sTexOpacity);
+        break;
+    case Discreet3DS::CHUNK_MAT_MAT_SHINMAP:
+        // Shininess map
+        ParseTextureChunk(&mScene->mMaterials.back().sTexShininess);
+        break;
+    case Discreet3DS::CHUNK_MAT_SPECMAP:
+        // Specular map
+        ParseTextureChunk(&mScene->mMaterials.back().sTexSpecular);
+        break;
+    case Discreet3DS::CHUNK_MAT_SELFIMAP:
+        // Self-illumination (emissive) map
+        ParseTextureChunk(&mScene->mMaterials.back().sTexEmissive);
+        break;
+    case Discreet3DS::CHUNK_MAT_REFLMAP:
+        // Reflection map
+        ParseTextureChunk(&mScene->mMaterials.back().sTexReflective);
+        break;
+    };
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 {
-	ASSIMP_3DS_BEGIN_CHUNK();
-
-	// get chunk type
-	switch (chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_MAPFILE:
-		{
-		// The material name string is already zero-terminated, but we need to be sure ...
-		const char* sz = (const char*)stream->GetPtr();
-		unsigned int cnt = 0;
-		while (stream->GetI1())
-			++cnt;
-		pcOut->mMapName = std::string(sz,cnt);
-		}
-		break;
-
-
-	case Discreet3DS::CHUNK_PERCENTF:
-		// Manually parse the blend factor
-		pcOut->mTextureBlend = stream->GetF4();
-		break;
-
-	case Discreet3DS::CHUNK_PERCENTW:
-		// Manually parse the blend factor
-		pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f;
-		break;
-
-	case Discreet3DS::CHUNK_MAT_MAP_USCALE:
-		// Texture coordinate scaling in the U direction
-		pcOut->mScaleU = stream->GetF4();
-		if (0.0f == pcOut->mScaleU)
-		{
-			DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1.");
-			pcOut->mScaleU = 1.0f;
-		}
-		break;
-	case Discreet3DS::CHUNK_MAT_MAP_VSCALE:
-		// Texture coordinate scaling in the V direction
-		pcOut->mScaleV = stream->GetF4();
-		if (0.0f == pcOut->mScaleV)
-		{
-			DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1.");
-			pcOut->mScaleV = 1.0f;
-		}
-		break;
-
-	case Discreet3DS::CHUNK_MAT_MAP_UOFFSET:
-		// Texture coordinate offset in the U direction
-		pcOut->mOffsetU = -stream->GetF4();
-		break;
-
-	case Discreet3DS::CHUNK_MAT_MAP_VOFFSET:
-		// Texture coordinate offset in the V direction
-		pcOut->mOffsetV = stream->GetF4();
-		break;
-
-	case Discreet3DS::CHUNK_MAT_MAP_ANG:
-		// Texture coordinate rotation, CCW in DEGREES
-		pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() );
-		break;
-
-	case Discreet3DS::CHUNK_MAT_MAP_TILING:
-		{
-		const uint16_t iFlags = stream->GetI2();
-
-		// Get the mapping mode (for both axes)
-		if (iFlags & 0x2u)
-			pcOut->mMapMode = aiTextureMapMode_Mirror;
-
-		else if (iFlags & 0x10u)
-			pcOut->mMapMode = aiTextureMapMode_Decal;
-
-		// wrapping in all remaining cases
-		else pcOut->mMapMode = aiTextureMapMode_Wrap;
-		}
-		break;
-	};
-
-	ASSIMP_3DS_END_CHUNK();
+    ASSIMP_3DS_BEGIN_CHUNK();
+
+    // get chunk type
+    switch (chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_MAPFILE:
+        {
+        // The material name string is already zero-terminated, but we need to be sure ...
+        const char* sz = (const char*)stream->GetPtr();
+        unsigned int cnt = 0;
+        while (stream->GetI1())
+            ++cnt;
+        pcOut->mMapName = std::string(sz,cnt);
+        }
+        break;
+
+
+    case Discreet3DS::CHUNK_PERCENTF:
+        // Manually parse the blend factor
+        pcOut->mTextureBlend = stream->GetF4();
+        break;
+
+    case Discreet3DS::CHUNK_PERCENTW:
+        // Manually parse the blend factor
+        pcOut->mTextureBlend = (float)((uint16_t)stream->GetI2()) / 100.0f;
+        break;
+
+    case Discreet3DS::CHUNK_MAT_MAP_USCALE:
+        // Texture coordinate scaling in the U direction
+        pcOut->mScaleU = stream->GetF4();
+        if (0.0f == pcOut->mScaleU)
+        {
+            DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1.");
+            pcOut->mScaleU = 1.0f;
+        }
+        break;
+    case Discreet3DS::CHUNK_MAT_MAP_VSCALE:
+        // Texture coordinate scaling in the V direction
+        pcOut->mScaleV = stream->GetF4();
+        if (0.0f == pcOut->mScaleV)
+        {
+            DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1.");
+            pcOut->mScaleV = 1.0f;
+        }
+        break;
+
+    case Discreet3DS::CHUNK_MAT_MAP_UOFFSET:
+        // Texture coordinate offset in the U direction
+        pcOut->mOffsetU = -stream->GetF4();
+        break;
+
+    case Discreet3DS::CHUNK_MAT_MAP_VOFFSET:
+        // Texture coordinate offset in the V direction
+        pcOut->mOffsetV = stream->GetF4();
+        break;
+
+    case Discreet3DS::CHUNK_MAT_MAP_ANG:
+        // Texture coordinate rotation, CCW in DEGREES
+        pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() );
+        break;
+
+    case Discreet3DS::CHUNK_MAT_MAP_TILING:
+        {
+        const uint16_t iFlags = stream->GetI2();
+
+        // Get the mapping mode (for both axes)
+        if (iFlags & 0x2u)
+            pcOut->mMapMode = aiTextureMapMode_Mirror;
+
+        else if (iFlags & 0x10u)
+            pcOut->mMapMode = aiTextureMapMode_Decal;
+
+        // wrapping in all remaining cases
+        else pcOut->mMapMode = aiTextureMapMode_Wrap;
+        }
+        break;
+    };
+
+    ASSIMP_3DS_END_CHUNK();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Read a percentage chunk
 float Discreet3DSImporter::ParsePercentageChunk()
 {
-	Discreet3DS::Chunk chunk;
-	ReadChunk(&chunk);
-
-	if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag)
-		return stream->GetF4();
-	else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag)
-		return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF;
-	return get_qnan();
+    Discreet3DS::Chunk chunk;
+    ReadChunk(&chunk);
+
+    if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag)
+        return stream->GetF4();
+    else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag)
+        return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF;
+    return get_qnan();
 }
 
 // ------------------------------------------------------------------------------------------------
 // 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)
+    bool acceptPercent)
 {
-	ai_assert(out != NULL);
-
-	// error return value
-	const float qnan = get_qnan();
-	static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan);
-
-	Discreet3DS::Chunk chunk;
-	ReadChunk(&chunk);
-	const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk);
-
-	bool bGamma = false;
-
-	// Get the type of the chunk
-	switch(chunk.Flag)
-	{
-	case Discreet3DS::CHUNK_LINRGBF:
-		bGamma = true;
-
-	case Discreet3DS::CHUNK_RGBF:
-		if (sizeof(float) * 3 > diff)	{
-			*out = clrError;
-			return;
-		}
-		out->r = stream->GetF4();
-		out->g = stream->GetF4();
-		out->b = stream->GetF4();
-		break;
-
-	case Discreet3DS::CHUNK_LINRGBB:
-		bGamma = true;
-	case Discreet3DS::CHUNK_RGBB:
-		if (sizeof(char) * 3 > diff)	{
-			*out = clrError;
-			return;
-		}
-		out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
-		out->g = (float)(uint8_t)stream->GetI1() / 255.0f;
-		out->b = (float)(uint8_t)stream->GetI1() / 255.0f;
-		break;
-
-	// Percentage chunks are accepted, too.
-	case Discreet3DS::CHUNK_PERCENTF:
-		if (acceptPercent && 4 <= diff)	{
-			out->g = out->b = out->r = stream->GetF4();
-			break;
-		}
-		*out = clrError;
-		return;
-
-	case Discreet3DS::CHUNK_PERCENTW:
-		if (acceptPercent && 1 <= diff)	{
-			out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
-			break;
-		}
-		*out = clrError;
-		return;
-
-	default:
-		stream->IncPtr(diff);
-		// Skip unknown chunks, hope this won't cause any problems.
-		return ParseColorChunk(out,acceptPercent);
-	};
-	(void)bGamma;
+    ai_assert(out != NULL);
+
+    // error return value
+    const float qnan = get_qnan();
+    static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan);
+
+    Discreet3DS::Chunk chunk;
+    ReadChunk(&chunk);
+    const unsigned int diff = chunk.Size - sizeof(Discreet3DS::Chunk);
+
+    bool bGamma = false;
+
+    // Get the type of the chunk
+    switch(chunk.Flag)
+    {
+    case Discreet3DS::CHUNK_LINRGBF:
+        bGamma = true;
+
+    case Discreet3DS::CHUNK_RGBF:
+        if (sizeof(float) * 3 > diff)   {
+            *out = clrError;
+            return;
+        }
+        out->r = stream->GetF4();
+        out->g = stream->GetF4();
+        out->b = stream->GetF4();
+        break;
+
+    case Discreet3DS::CHUNK_LINRGBB:
+        bGamma = true;
+    case Discreet3DS::CHUNK_RGBB:
+        if (sizeof(char) * 3 > diff)    {
+            *out = clrError;
+            return;
+        }
+        out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
+        out->g = (float)(uint8_t)stream->GetI1() / 255.0f;
+        out->b = (float)(uint8_t)stream->GetI1() / 255.0f;
+        break;
+
+    // Percentage chunks are accepted, too.
+    case Discreet3DS::CHUNK_PERCENTF:
+        if (acceptPercent && 4 <= diff) {
+            out->g = out->b = out->r = stream->GetF4();
+            break;
+        }
+        *out = clrError;
+        return;
+
+    case Discreet3DS::CHUNK_PERCENTW:
+        if (acceptPercent && 1 <= diff) {
+            out->g = out->b = out->r = (float)(uint8_t)stream->GetI1() / 255.0f;
+            break;
+        }
+        *out = clrError;
+        return;
+
+    default:
+        stream->IncPtr(diff);
+        // Skip unknown chunks, hope this won't cause any problems.
+        return ParseColorChunk(out,acceptPercent);
+    };
+    (void)bGamma;
 }
 
 #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER

+ 190 - 190
code/3DSLoader.h

@@ -55,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiNode;
 
-namespace Assimp	{
+namespace Assimp    {
 
 
 using namespace D3DS;
@@ -67,212 +67,212 @@ class Discreet3DSImporter : public BaseImporter
 {
 public:
 
-	Discreet3DSImporter();
-	~Discreet3DSImporter();
+    Discreet3DSImporter();
+    ~Discreet3DSImporter();
 
 public:
 
-	// -------------------------------------------------------------------
-	/** Returns whether the class can handle the format of the given file.
-	 * See BaseImporter::CanRead() for details.
-	 */
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-		bool checkSig) const;
+    // -------------------------------------------------------------------
+    /** Returns whether the class can handle the format of the given file.
+     * See BaseImporter::CanRead() for details.
+     */
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
 
-	// -------------------------------------------------------------------
-	/** Called prior to ReadFile().
-	 * The function is a request to the importer to update its configuration
-	 * basing on the Importer's configuration property list.
-	 */
-	void SetupProperties(const Importer* pImp);
+    // -------------------------------------------------------------------
+    /** Called prior to ReadFile().
+     * The function is a request to the importer to update its configuration
+     * basing on the Importer's configuration property list.
+     */
+    void SetupProperties(const Importer* pImp);
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Return importer meta information.
-	 * See #BaseImporter::GetInfo for the details
-	 */
-	const aiImporterDesc* GetInfo () const;
-
-	// -------------------------------------------------------------------
-	/** Imports the given file into the given scene structure.
-	 * See BaseImporter::InternReadFile() for details
-	 */
-	void InternReadFile( const std::string& pFile, aiScene* pScene,
-		IOSystem* pIOHandler);
-
-	// -------------------------------------------------------------------
-	/** Converts a temporary material to the outer representation
-	 */
-	void ConvertMaterial(D3DS::Material& p_cMat,
-		aiMaterial& p_pcOut);
-
-	// -------------------------------------------------------------------
-	/** Read a chunk
-	 *
-	 *  @param pcOut Receives the current chunk
-	 */
-	void ReadChunk(Discreet3DS::Chunk* pcOut);
-
-	// -------------------------------------------------------------------
-	/** Parse a percentage chunk. mCurrent will point to the next
-	* chunk behind afterwards. If no percentage chunk is found
-	* QNAN is returned.
-	*/
-	float ParsePercentageChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a color chunk. mCurrent will point to the next
-	* chunk behind afterwards. If no color chunk is found
-	* QNAN is returned in all members.
-	*/
-	void ParseColorChunk(aiColor3D* p_pcOut,
-		bool p_bAcceptPercent = true);
-
-
-	// -------------------------------------------------------------------
-	/** Skip a chunk in the file
-	*/
-	void SkipChunk();
-
-	// -------------------------------------------------------------------
-	/** Generate the nodegraph
-	*/
-	void GenerateNodeGraph(aiScene* pcOut);
-
-	// -------------------------------------------------------------------
-	/** Parse a main top-level chunk in the file
-	*/
-	void ParseMainChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a top-level chunk in the file
-	*/
-	void ParseChunk(const char* name, unsigned int num);
-
-	// -------------------------------------------------------------------
-	/** Parse a top-level editor chunk in the file
-	*/
-	void ParseEditorChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a top-level object chunk in the file
-	*/
-	void ParseObjectChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a material chunk in the file
-	*/
-	void ParseMaterialChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a mesh chunk in the file
-	*/
-	void ParseMeshChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a light chunk in the file
-	*/
-	void ParseLightChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a camera chunk in the file
-	*/
-	void ParseCameraChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a face list chunk in the file
-	*/
-	void ParseFaceChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a keyframe chunk in the file
-	*/
-	void ParseKeyframeChunk();
-
-	// -------------------------------------------------------------------
-	/** Parse a hierarchy chunk in the file
-	*/
-	void ParseHierarchyChunk(uint16_t parent);
-
-	// -------------------------------------------------------------------
-	/** Parse a texture chunk in the file
-	*/
-	void ParseTextureChunk(D3DS::Texture* pcOut);
-
-	// -------------------------------------------------------------------
-	/** Convert the meshes in the file
-	*/
-	void ConvertMeshes(aiScene* pcOut);
-
-	// -------------------------------------------------------------------
-	/** Replace the default material in the scene
-	*/
-	void ReplaceDefaultMaterial();
-
-	// -------------------------------------------------------------------
-	/** Convert the whole scene
-	*/
-	void ConvertScene(aiScene* pcOut);
-
-	// -------------------------------------------------------------------
-	/** generate unique vertices for a mesh
-	*/
-	void MakeUnique(D3DS::Mesh& sMesh);
-
-	// -------------------------------------------------------------------
-	/** Add a node to the node graph
-	*/
-	void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn,
-		aiMatrix4x4& absTrafo);
-
-	// -------------------------------------------------------------------
-	/** Search for a node in the graph.
-	* Called recursively
-	*/
-	void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent);
-
-	// -------------------------------------------------------------------
-	/** Apply the master scaling factor to the mesh
-	*/
-	void ApplyMasterScale(aiScene* pScene);
-
-	// -------------------------------------------------------------------
-	/** Clamp all indices in the file to a valid range
-	*/
-	void CheckIndices(D3DS::Mesh& sMesh);
-
-	// -------------------------------------------------------------------
-	/** Skip the TCB info in a track key
-	*/
-	void SkipTCBInfo();
+    // -------------------------------------------------------------------
+    /** Return importer meta information.
+     * See #BaseImporter::GetInfo for the details
+     */
+    const aiImporterDesc* GetInfo () const;
+
+    // -------------------------------------------------------------------
+    /** Imports the given file into the given scene structure.
+     * See BaseImporter::InternReadFile() for details
+     */
+    void InternReadFile( const std::string& pFile, aiScene* pScene,
+        IOSystem* pIOHandler);
+
+    // -------------------------------------------------------------------
+    /** Converts a temporary material to the outer representation
+     */
+    void ConvertMaterial(D3DS::Material& p_cMat,
+        aiMaterial& p_pcOut);
+
+    // -------------------------------------------------------------------
+    /** Read a chunk
+     *
+     *  @param pcOut Receives the current chunk
+     */
+    void ReadChunk(Discreet3DS::Chunk* pcOut);
+
+    // -------------------------------------------------------------------
+    /** Parse a percentage chunk. mCurrent will point to the next
+    * chunk behind afterwards. If no percentage chunk is found
+    * QNAN is returned.
+    */
+    float ParsePercentageChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a color chunk. mCurrent will point to the next
+    * chunk behind afterwards. If no color chunk is found
+    * QNAN is returned in all members.
+    */
+    void ParseColorChunk(aiColor3D* p_pcOut,
+        bool p_bAcceptPercent = true);
+
+
+    // -------------------------------------------------------------------
+    /** Skip a chunk in the file
+    */
+    void SkipChunk();
+
+    // -------------------------------------------------------------------
+    /** Generate the nodegraph
+    */
+    void GenerateNodeGraph(aiScene* pcOut);
+
+    // -------------------------------------------------------------------
+    /** Parse a main top-level chunk in the file
+    */
+    void ParseMainChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a top-level chunk in the file
+    */
+    void ParseChunk(const char* name, unsigned int num);
+
+    // -------------------------------------------------------------------
+    /** Parse a top-level editor chunk in the file
+    */
+    void ParseEditorChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a top-level object chunk in the file
+    */
+    void ParseObjectChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a material chunk in the file
+    */
+    void ParseMaterialChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a mesh chunk in the file
+    */
+    void ParseMeshChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a light chunk in the file
+    */
+    void ParseLightChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a camera chunk in the file
+    */
+    void ParseCameraChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a face list chunk in the file
+    */
+    void ParseFaceChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a keyframe chunk in the file
+    */
+    void ParseKeyframeChunk();
+
+    // -------------------------------------------------------------------
+    /** Parse a hierarchy chunk in the file
+    */
+    void ParseHierarchyChunk(uint16_t parent);
+
+    // -------------------------------------------------------------------
+    /** Parse a texture chunk in the file
+    */
+    void ParseTextureChunk(D3DS::Texture* pcOut);
+
+    // -------------------------------------------------------------------
+    /** Convert the meshes in the file
+    */
+    void ConvertMeshes(aiScene* pcOut);
+
+    // -------------------------------------------------------------------
+    /** Replace the default material in the scene
+    */
+    void ReplaceDefaultMaterial();
+
+    // -------------------------------------------------------------------
+    /** Convert the whole scene
+    */
+    void ConvertScene(aiScene* pcOut);
+
+    // -------------------------------------------------------------------
+    /** generate unique vertices for a mesh
+    */
+    void MakeUnique(D3DS::Mesh& sMesh);
+
+    // -------------------------------------------------------------------
+    /** Add a node to the node graph
+    */
+    void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn,
+        aiMatrix4x4& absTrafo);
+
+    // -------------------------------------------------------------------
+    /** Search for a node in the graph.
+    * Called recursively
+    */
+    void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent);
+
+    // -------------------------------------------------------------------
+    /** Apply the master scaling factor to the mesh
+    */
+    void ApplyMasterScale(aiScene* pScene);
+
+    // -------------------------------------------------------------------
+    /** Clamp all indices in the file to a valid range
+    */
+    void CheckIndices(D3DS::Mesh& sMesh);
+
+    // -------------------------------------------------------------------
+    /** Skip the TCB info in a track key
+    */
+    void SkipTCBInfo();
 
 protected:
 
-	/** Stream to read from */
-	StreamReaderLE* stream;
+    /** Stream to read from */
+    StreamReaderLE* stream;
 
-	/** Last touched node index */
-	short mLastNodeIndex;
+    /** Last touched node index */
+    short mLastNodeIndex;
 
-	/** Current node, root node */
-	D3DS::Node* mCurrentNode, *mRootNode;
+    /** Current node, root node */
+    D3DS::Node* mCurrentNode, *mRootNode;
 
-	/** Scene under construction */
-	D3DS::Scene* mScene;
+    /** Scene under construction */
+    D3DS::Scene* mScene;
 
-	/** Ambient base color of the scene */
-	aiColor3D mClrAmbient;
+    /** Ambient base color of the scene */
+    aiColor3D mClrAmbient;
 
-	/** Master scaling factor of the scene */
-	float mMasterScale;
+    /** Master scaling factor of the scene */
+    float mMasterScale;
 
-	/** Path to the background image of the scene */
-	std::string mBackgroundImage;
-	bool bHasBG;
+    /** Path to the background image of the scene */
+    std::string mBackgroundImage;
+    bool bHasBG;
 
-	/** true if PRJ file */
-	bool bIsPrj;
+    /** true if PRJ file */
+    bool bIsPrj;
 };
 
 } // end of namespace Assimp

+ 743 - 743
code/ACLoader.cpp

@@ -65,822 +65,822 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-	"AC3D Importer",
-	"",
-	"",
-	"",
-	aiImporterFlags_SupportTextFlavour,
-	0,
-	0,
-	0,
-	0,
-	"ac acc ac3d"
+    "AC3D Importer",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "ac acc ac3d"
 };
 
 // ------------------------------------------------------------------------------------------------
 // skip to the next token
 #define AI_AC_SKIP_TO_NEXT_TOKEN() \
-	if (!SkipSpaces(&buffer)) \
-	{ \
-		DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \
-		continue; \
-	}
+    if (!SkipSpaces(&buffer)) \
+    { \
+        DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \
+        continue; \
+    }
 
 // ------------------------------------------------------------------------------------------------
 // read a string (may be enclosed in double quotation marks). buffer must point to "
 #define AI_AC_GET_STRING(out) \
-	++buffer; \
-	const char* sz = buffer; \
-	while ('\"' != *buffer) \
-	{ \
-		if (IsLineEnd( *buffer )) \
-		{ \
-			DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \
-			out = "ERROR"; \
-			break; \
-		} \
-		++buffer; \
-	} \
-	if (IsLineEnd( *buffer ))continue; \
-	out = std::string(sz,(unsigned int)(buffer-sz)); \
-	++buffer;
+    ++buffer; \
+    const char* sz = buffer; \
+    while ('\"' != *buffer) \
+    { \
+        if (IsLineEnd( *buffer )) \
+        { \
+            DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \
+            out = "ERROR"; \
+            break; \
+        } \
+        ++buffer; \
+    } \
+    if (IsLineEnd( *buffer ))continue; \
+    out = std::string(sz,(unsigned int)(buffer-sz)); \
+    ++buffer;
 
 
 // ------------------------------------------------------------------------------------------------
 // read 1 to n floats prefixed with an optional predefined identifier
 #define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \
-	AI_AC_SKIP_TO_NEXT_TOKEN(); \
-	if (name_length) \
-	{ \
-		if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
-		{ \
-			DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \
-			continue; \
-		} \
-		buffer += name_length+1; \
-	} \
-	for (unsigned int i = 0; i < num;++i) \
-	{ \
-		AI_AC_SKIP_TO_NEXT_TOKEN(); \
-		buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \
-	}
+    AI_AC_SKIP_TO_NEXT_TOKEN(); \
+    if (name_length) \
+    { \
+        if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
+        { \
+            DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \
+            continue; \
+        } \
+        buffer += name_length+1; \
+    } \
+    for (unsigned int i = 0; i < num;++i) \
+    { \
+        AI_AC_SKIP_TO_NEXT_TOKEN(); \
+        buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \
+    }
 
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 AC3DImporter::AC3DImporter()
 {
-	// nothing to be done here
+    // nothing to be done here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 AC3DImporter::~AC3DImporter()
 {
-	// nothing to be done here
+    // nothing to be done here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-	std::string extension = GetExtension(pFile);
-
-	// fixme: are acc and ac3d *really* used? Some sources say they are
-	if(extension == "ac" || extension == "ac3d" || extension == "acc") {
-		return true;
-	}
-	if (!extension.length() || checkSig) {
-		uint32_t token = AI_MAKE_MAGIC("AC3D");
-		return CheckMagicToken(pIOHandler,pFile,&token,1,0);
-	}
-	return false;
+    std::string extension = GetExtension(pFile);
+
+    // fixme: are acc and ac3d *really* used? Some sources say they are
+    if(extension == "ac" || extension == "ac3d" || extension == "acc") {
+        return true;
+    }
+    if (!extension.length() || checkSig) {
+        uint32_t token = AI_MAKE_MAGIC("AC3D");
+        return CheckMagicToken(pIOHandler,pFile,&token,1,0);
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Loader meta information
 const aiImporterDesc* AC3DImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get a pointer to the next line from the file
 bool AC3DImporter::GetNextLine( )
 {
-	SkipLine(&buffer);
-	return SkipSpaces(&buffer);
+    SkipLine(&buffer);
+    return SkipSpaces(&buffer);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Parse an object section in an AC file
 void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
 {
-	if (!TokenMatch(buffer,"OBJECT",6))
-		return;
-
-	SkipSpaces(&buffer);
-
-	++mNumMeshes;
-
-	objects.push_back(Object());
-	Object& obj = objects.back();
-
-	aiLight* light = NULL;
-	if (!ASSIMP_strincmp(buffer,"light",5))
-	{
-		// This is a light source. Add it to the list
-		mLights->push_back(light = new aiLight());
-
-		// Return a point light with no attenuation
-		light->mType = aiLightSource_POINT;
-		light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f);
-		light->mAttenuationConstant = 1.f;
-
-		// Generate a default name for both the light source and the node
-		// FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
-		light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
-		obj.name = std::string( light->mName.data );
-
-		DefaultLogger::get()->debug("AC3D: Light source encountered");
-		obj.type = Object::Light;
-	}
-	else if (!ASSIMP_strincmp(buffer,"group",5))
-	{
-		obj.type = Object::Group;
-	}
-	else if (!ASSIMP_strincmp(buffer,"world",5))
-	{
-		obj.type = Object::World;
-	}
-	else obj.type = Object::Poly;
-	while (GetNextLine())
-	{
-		if (TokenMatch(buffer,"kids",4))
-		{
-			SkipSpaces(&buffer);
-			unsigned int num = strtoul10(buffer,&buffer);
-			GetNextLine();
-			if (num)
-			{
-				// load the children of this object recursively
-				obj.children.reserve(num);
-				for (unsigned int i = 0; i < num; ++i)
-					LoadObjectSection(obj.children);
-			}
-			return;
-		}
-		else if (TokenMatch(buffer,"name",4))
-		{
-			SkipSpaces(&buffer);
-			AI_AC_GET_STRING(obj.name);
-
-			// If this is a light source, we'll also need to store
-			// the name of the node in it.
-			if (light)
-			{
-				light->mName.Set(obj.name);
-			}
-		}
-		else if (TokenMatch(buffer,"texture",7))
-		{
-			SkipSpaces(&buffer);
-			AI_AC_GET_STRING(obj.texture);
-		}
-		else if (TokenMatch(buffer,"texrep",6))
-		{
-			SkipSpaces(&buffer);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
-			if (!obj.texRepeat.x || !obj.texRepeat.y)
-				obj.texRepeat = aiVector2D (1.f,1.f);
-		}
-		else if (TokenMatch(buffer,"texoff",6))
-		{
-			SkipSpaces(&buffer);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
-		}
-		else if (TokenMatch(buffer,"rot",3))
-		{
-			SkipSpaces(&buffer);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation);
-		}
-		else if (TokenMatch(buffer,"loc",3))
-		{
-			SkipSpaces(&buffer);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
-		}
-		else if (TokenMatch(buffer,"subdiv",6))
-		{
-			SkipSpaces(&buffer);
-			obj.subDiv = strtoul10(buffer,&buffer);
-		}
-		else if (TokenMatch(buffer,"crease",6))
-		{
-			SkipSpaces(&buffer);
-			obj.crease = fast_atof(buffer);
-		}
-		else if (TokenMatch(buffer,"numvert",7))
-		{
-			SkipSpaces(&buffer);
-
-			unsigned int t = strtoul10(buffer,&buffer);
-			if (t >= std::numeric_limits<int32_t>::max() / sizeof(aiVector3D)) {
-				throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
-			}
-			obj.vertices.reserve(t);
-			for (unsigned int i = 0; i < t;++i)
-			{
-				if (!GetNextLine())
-				{
-					DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet");
-					break;
-				}
-				else if (!IsNumeric(*buffer))
-				{
-					DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet");
-					--buffer; // make sure the line is processed a second time
-					break;
-				}
-				obj.vertices.push_back(aiVector3D());
-				aiVector3D& v = obj.vertices.back();
-				AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
-			}
-		}
-		else if (TokenMatch(buffer,"numsurf",7))
-		{
-			SkipSpaces(&buffer);
-
-			bool Q3DWorkAround = false;
-
-			const unsigned int t = strtoul10(buffer,&buffer);
-			obj.surfaces.reserve(t);
-			for (unsigned int i = 0; i < t;++i)
-			{
-				GetNextLine();
-				if (!TokenMatch(buffer,"SURF",4))
-				{
-					// FIX: this can occur for some files - Quick 3D for
-					// example writes no surf chunks
-					if (!Q3DWorkAround)
-					{
-						DefaultLogger::get()->warn("AC3D: SURF token was expected");
-						DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled");
-					}
-					--buffer; // make sure the line is processed a second time
-					// break; --- see fix notes above
-
-					Q3DWorkAround = true;
-				}
-				SkipSpaces(&buffer);
-				obj.surfaces.push_back(Surface());
-				Surface& surf = obj.surfaces.back();
-				surf.flags = strtoul_cppstyle(buffer);
-
-				while (1)
-				{
-					if(!GetNextLine())
-					{
-						DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete");
-						break;
-					}
-					if (TokenMatch(buffer,"mat",3))
-					{
-						SkipSpaces(&buffer);
-						surf.mat = strtoul10(buffer);
-					}
-					else if (TokenMatch(buffer,"refs",4))
-					{
-						// --- see fix notes above
-						if (Q3DWorkAround)
-						{
-							if (!surf.entries.empty())
-							{
-								buffer -= 6;
-								break;
-							}
-						}
-
-						SkipSpaces(&buffer);
-						const unsigned int m = strtoul10(buffer);
-						surf.entries.reserve(m);
-
-						obj.numRefs += m;
-
-						for (unsigned int k = 0; k < m; ++k)
-						{
-							if(!GetNextLine())
-							{
-								DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete");
-								break;
-							}
-							surf.entries.push_back(Surface::SurfaceEntry());
-							Surface::SurfaceEntry& entry = surf.entries.back();
-
-							entry.first = strtoul10(buffer,&buffer);
-							SkipSpaces(&buffer);
-							AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second);
-						}
-					}
-					else
-					{
-
-						--buffer; // make sure the line is processed a second time
-						break;
-					}
-				}
-			}
-		}
-	}
-	DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected");
+    if (!TokenMatch(buffer,"OBJECT",6))
+        return;
+
+    SkipSpaces(&buffer);
+
+    ++mNumMeshes;
+
+    objects.push_back(Object());
+    Object& obj = objects.back();
+
+    aiLight* light = NULL;
+    if (!ASSIMP_strincmp(buffer,"light",5))
+    {
+        // This is a light source. Add it to the list
+        mLights->push_back(light = new aiLight());
+
+        // Return a point light with no attenuation
+        light->mType = aiLightSource_POINT;
+        light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f);
+        light->mAttenuationConstant = 1.f;
+
+        // Generate a default name for both the light source and the node
+        // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
+        light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
+        obj.name = std::string( light->mName.data );
+
+        DefaultLogger::get()->debug("AC3D: Light source encountered");
+        obj.type = Object::Light;
+    }
+    else if (!ASSIMP_strincmp(buffer,"group",5))
+    {
+        obj.type = Object::Group;
+    }
+    else if (!ASSIMP_strincmp(buffer,"world",5))
+    {
+        obj.type = Object::World;
+    }
+    else obj.type = Object::Poly;
+    while (GetNextLine())
+    {
+        if (TokenMatch(buffer,"kids",4))
+        {
+            SkipSpaces(&buffer);
+            unsigned int num = strtoul10(buffer,&buffer);
+            GetNextLine();
+            if (num)
+            {
+                // load the children of this object recursively
+                obj.children.reserve(num);
+                for (unsigned int i = 0; i < num; ++i)
+                    LoadObjectSection(obj.children);
+            }
+            return;
+        }
+        else if (TokenMatch(buffer,"name",4))
+        {
+            SkipSpaces(&buffer);
+            AI_AC_GET_STRING(obj.name);
+
+            // If this is a light source, we'll also need to store
+            // the name of the node in it.
+            if (light)
+            {
+                light->mName.Set(obj.name);
+            }
+        }
+        else if (TokenMatch(buffer,"texture",7))
+        {
+            SkipSpaces(&buffer);
+            AI_AC_GET_STRING(obj.texture);
+        }
+        else if (TokenMatch(buffer,"texrep",6))
+        {
+            SkipSpaces(&buffer);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
+            if (!obj.texRepeat.x || !obj.texRepeat.y)
+                obj.texRepeat = aiVector2D (1.f,1.f);
+        }
+        else if (TokenMatch(buffer,"texoff",6))
+        {
+            SkipSpaces(&buffer);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
+        }
+        else if (TokenMatch(buffer,"rot",3))
+        {
+            SkipSpaces(&buffer);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation);
+        }
+        else if (TokenMatch(buffer,"loc",3))
+        {
+            SkipSpaces(&buffer);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
+        }
+        else if (TokenMatch(buffer,"subdiv",6))
+        {
+            SkipSpaces(&buffer);
+            obj.subDiv = strtoul10(buffer,&buffer);
+        }
+        else if (TokenMatch(buffer,"crease",6))
+        {
+            SkipSpaces(&buffer);
+            obj.crease = fast_atof(buffer);
+        }
+        else if (TokenMatch(buffer,"numvert",7))
+        {
+            SkipSpaces(&buffer);
+
+            unsigned int t = strtoul10(buffer,&buffer);
+            if (t >= std::numeric_limits<int32_t>::max() / sizeof(aiVector3D)) {
+                throw DeadlyImportError("AC3D: Too many vertices, would run out of memory");
+            }
+            obj.vertices.reserve(t);
+            for (unsigned int i = 0; i < t;++i)
+            {
+                if (!GetNextLine())
+                {
+                    DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet");
+                    break;
+                }
+                else if (!IsNumeric(*buffer))
+                {
+                    DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet");
+                    --buffer; // make sure the line is processed a second time
+                    break;
+                }
+                obj.vertices.push_back(aiVector3D());
+                aiVector3D& v = obj.vertices.back();
+                AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
+            }
+        }
+        else if (TokenMatch(buffer,"numsurf",7))
+        {
+            SkipSpaces(&buffer);
+
+            bool Q3DWorkAround = false;
+
+            const unsigned int t = strtoul10(buffer,&buffer);
+            obj.surfaces.reserve(t);
+            for (unsigned int i = 0; i < t;++i)
+            {
+                GetNextLine();
+                if (!TokenMatch(buffer,"SURF",4))
+                {
+                    // FIX: this can occur for some files - Quick 3D for
+                    // example writes no surf chunks
+                    if (!Q3DWorkAround)
+                    {
+                        DefaultLogger::get()->warn("AC3D: SURF token was expected");
+                        DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled");
+                    }
+                    --buffer; // make sure the line is processed a second time
+                    // break; --- see fix notes above
+
+                    Q3DWorkAround = true;
+                }
+                SkipSpaces(&buffer);
+                obj.surfaces.push_back(Surface());
+                Surface& surf = obj.surfaces.back();
+                surf.flags = strtoul_cppstyle(buffer);
+
+                while (1)
+                {
+                    if(!GetNextLine())
+                    {
+                        DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete");
+                        break;
+                    }
+                    if (TokenMatch(buffer,"mat",3))
+                    {
+                        SkipSpaces(&buffer);
+                        surf.mat = strtoul10(buffer);
+                    }
+                    else if (TokenMatch(buffer,"refs",4))
+                    {
+                        // --- see fix notes above
+                        if (Q3DWorkAround)
+                        {
+                            if (!surf.entries.empty())
+                            {
+                                buffer -= 6;
+                                break;
+                            }
+                        }
+
+                        SkipSpaces(&buffer);
+                        const unsigned int m = strtoul10(buffer);
+                        surf.entries.reserve(m);
+
+                        obj.numRefs += m;
+
+                        for (unsigned int k = 0; k < m; ++k)
+                        {
+                            if(!GetNextLine())
+                            {
+                                DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete");
+                                break;
+                            }
+                            surf.entries.push_back(Surface::SurfaceEntry());
+                            Surface::SurfaceEntry& entry = surf.entries.back();
+
+                            entry.first = strtoul10(buffer,&buffer);
+                            SkipSpaces(&buffer);
+                            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second);
+                        }
+                    }
+                    else
+                    {
+
+                        --buffer; // make sure the line is processed a second time
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert a material from AC3DImporter::Material to aiMaterial
 void AC3DImporter::ConvertMaterial(const Object& object,
-	const Material& matSrc,
-	aiMaterial& matDest)
+    const Material& matSrc,
+    aiMaterial& matDest)
 {
-	aiString s;
-
-	if (matSrc.name.length())
-	{
-		s.Set(matSrc.name);
-		matDest.AddProperty(&s,AI_MATKEY_NAME);
-	}
-	if (object.texture.length())
-	{
-		s.Set(object.texture);
-		matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
-
-		// UV transformation
-		if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
-			object.texOffset.x        || object.texOffset.y)
-		{
-			aiUVTransform transform;
-			transform.mScaling = object.texRepeat;
-			transform.mTranslation = object.texOffset;
-			matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
-		}
-	}
-
-	matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE);
-	matDest.AddProperty<aiColor3D>(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT);
-	matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE);
-	matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR);
-
-	int n;
-	if (matSrc.shin)
-	{
-		n = aiShadingMode_Phong;
-		matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
-	}
-	else n = aiShadingMode_Gouraud;
-	matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL);
-
-	float f = 1.f - matSrc.trans;
-	matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
+    aiString s;
+
+    if (matSrc.name.length())
+    {
+        s.Set(matSrc.name);
+        matDest.AddProperty(&s,AI_MATKEY_NAME);
+    }
+    if (object.texture.length())
+    {
+        s.Set(object.texture);
+        matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
+
+        // UV transformation
+        if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
+            object.texOffset.x        || object.texOffset.y)
+        {
+            aiUVTransform transform;
+            transform.mScaling = object.texRepeat;
+            transform.mTranslation = object.texOffset;
+            matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
+        }
+    }
+
+    matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE);
+    matDest.AddProperty<aiColor3D>(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT);
+    matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE);
+    matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR);
+
+    int n;
+    if (matSrc.shin)
+    {
+        n = aiShadingMode_Phong;
+        matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
+    }
+    else n = aiShadingMode_Gouraud;
+    matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL);
+
+    float f = 1.f - matSrc.trans;
+    matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Converts the loaded data to the internal verbose representation
 aiNode* AC3DImporter::ConvertObjectSection(Object& object,
-	std::vector<aiMesh*>& meshes,
-	std::vector<aiMaterial*>& outMaterials,
-	const std::vector<Material>& materials,
-	aiNode* parent)
+    std::vector<aiMesh*>& meshes,
+    std::vector<aiMaterial*>& outMaterials,
+    const std::vector<Material>& materials,
+    aiNode* parent)
 {
-	aiNode* node = new aiNode();
-	node->mParent = parent;
-	if (object.vertices.size())
-	{
-		if (!object.surfaces.size() || !object.numRefs)
-		{
-			/* " An object with 7 vertices (no surfaces, no materials defined).
-			     This is a good way of getting point data into AC3D.
-			     The Vertex->create convex-surface/object can be used on these
-			     vertices to 'wrap' a 3d shape around them "
-				 (http://www.opencity.info/html/ac3dfileformat.html)
-
-				 therefore: if no surfaces are defined return point data only
-			 */
-
-			DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, "
-				"a point list is returned");
-
-			meshes.push_back(new aiMesh());
-			aiMesh* mesh = meshes.back();
-
-			mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size();
-			aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
-			aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
-
-			for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts)
-			{
-				*verts = object.vertices[i];
-				faces->mNumIndices = 1;
-				faces->mIndices = new unsigned int[1];
-				faces->mIndices[0] = i;
-			}
-
-			// use the primary material in this case. this should be the
-			// default material if all objects of the file contain points
-			// and no faces.
-			mesh->mMaterialIndex = 0;
-			outMaterials.push_back(new aiMaterial());
-			ConvertMaterial(object, materials[0], *outMaterials.back());
-		}
-		else
-		{
-			// need to generate one or more meshes for this object.
-			// find out how many different materials we have
-			typedef std::pair< unsigned int, unsigned int > IntPair;
-			typedef std::vector< IntPair > MatTable;
-			MatTable needMat(materials.size(),IntPair(0,0));
-
-			std::vector<Surface>::iterator it,end = object.surfaces.end();
-			std::vector<Surface::SurfaceEntry>::iterator it2,end2;
-
-			for (it = object.surfaces.begin(); it != end; ++it)
-			{
-				unsigned int idx = (*it).mat;
-				if (idx >= needMat.size())
-				{
-					DefaultLogger::get()->error("AC3D: material index is out of range");
-					idx = 0;
-				}
-				if ((*it).entries.empty())
-				{
-					DefaultLogger::get()->warn("AC3D: surface her zero vertex references");
-				}
-
-				// validate all vertex indices to make sure we won't crash here
-				for (it2  = (*it).entries.begin(),
-					 end2 = (*it).entries.end(); it2 != end2; ++it2)
-				{
-					if ((*it2).first >= object.vertices.size())
-					{
-						DefaultLogger::get()->warn("AC3D: Invalid vertex reference");
-						(*it2).first = 0;
-					}
-				}
-
-				if (!needMat[idx].first)++node->mNumMeshes;
-
-				switch ((*it).flags & 0xf)
-				{
-					// closed line
-				case 0x1:
-
-					needMat[idx].first  += (unsigned int)(*it).entries.size();
-					needMat[idx].second += (unsigned int)(*it).entries.size()<<1u;
-					break;
-
-					// unclosed line
-				case 0x2:
-
-					needMat[idx].first  += (unsigned int)(*it).entries.size()-1;
-					needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u;
-					break;
-
-					// 0 == polygon, else unknown
-				default:
-
-					if ((*it).flags & 0xf)
-					{
-						DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown");
-						(*it).flags &= ~(0xf);
-					}
-
-					// the number of faces increments by one, the number
-					// of vertices by surface.numref.
-					needMat[idx].first++;
-					needMat[idx].second += (unsigned int)(*it).entries.size();
-				};
-			}
-			unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes];
-			unsigned int mat = 0;
-			const size_t oldm = meshes.size();
-			for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
-				cit != cend; ++cit, ++mat)
-			{
-				if (!(*cit).first)continue;
-
-				// allocate a new aiMesh object
-				*pip++ = (unsigned int)meshes.size();
-				aiMesh* mesh = new aiMesh();
-				meshes.push_back(mesh);
-
-				mesh->mMaterialIndex = (unsigned int)outMaterials.size();
-				outMaterials.push_back(new aiMaterial());
-				ConvertMaterial(object, materials[mat], *outMaterials.back());
-
-				// allocate storage for vertices and normals
-				mesh->mNumFaces = (*cit).first;
-				aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
-
-				mesh->mNumVertices = (*cit).second;
-				aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
-				unsigned int cur = 0;
-
-				// allocate UV coordinates, but only if the texture name for the
-				// surface is not empty
-				aiVector3D* uv = NULL;
-				if(object.texture.length())
-				{
-					uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
-					mesh->mNumUVComponents[0] = 2;
-				}
-
-				for (it = object.surfaces.begin(); it != end; ++it)
-				{
-					if (mat == (*it).mat)
-					{
-						const Surface& src = *it;
-
-						// closed polygon
-						unsigned int type = (*it).flags & 0xf;
-						if (!type)
-						{
-							aiFace& face = *faces++;
-							if((face.mNumIndices = (unsigned int)src.entries.size()))
-							{
-								face.mIndices = new unsigned int[face.mNumIndices];
-								for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices)
-								{
-									const Surface::SurfaceEntry& entry = src.entries[i];
-									face.mIndices[i] = cur++;
-
-									// copy vertex positions
-									if ((vertices - mesh->mVertices) >= mesh->mNumVertices) {
-										throw DeadlyImportError("AC3D: Invalid number of vertices");
-									}
-									*vertices = object.vertices[entry.first] + object.translation;
-
-
-									// copy texture coordinates
-									if (uv)
-									{
-										uv->x =  entry.second.x;
-										uv->y =  entry.second.y;
-										++uv;
-									}
-								}
-							}
-						}
-						else
-						{
-
-							it2  = (*it).entries.begin();
-
-							// either a closed or an unclosed line
-							unsigned int tmp = (unsigned int)(*it).entries.size();
-							if (0x2 == type)--tmp;
-							for (unsigned int m = 0; m < tmp;++m)
-							{
-								aiFace& face = *faces++;
-
-								face.mNumIndices = 2;
-								face.mIndices = new unsigned int[2];
-								face.mIndices[0] = cur++;
-								face.mIndices[1] = cur++;
-
-								// copy vertex positions
-								if (it2 == (*it).entries.end() ) {
-									throw DeadlyImportError("AC3D: Bad line");
-								}
-								ai_assert((*it2).first < object.vertices.size());
-								*vertices++ = object.vertices[(*it2).first];
-
-								// copy texture coordinates
-								if (uv)
-								{
-									uv->x =  (*it2).second.x;
-									uv->y =  (*it2).second.y;
-									++uv;
-								}
-
-
-								if (0x1 == type && tmp-1 == m)
-								{
-									// if this is a closed line repeat its beginning now
-									it2  = (*it).entries.begin();
-								}
-								else ++it2;
-
-								// second point
-								*vertices++ = object.vertices[(*it2).first];
-
-								if (uv)
-								{
-									uv->x =  (*it2).second.x;
-									uv->y =  (*it2).second.y;
-									++uv;
-								}
-							}
-						}
-					}
-				}
-			}
-
-			// Now apply catmull clark subdivision if necessary. We split meshes into
-			// materials which is not done by AC3D during smoothing, so we need to
-			// collect all meshes using the same material group.
-			if (object.subDiv)	{
-				if (configEvalSubdivision) {
-					boost::scoped_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
-					DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
-
-					std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
-					div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
-					std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm);
-
-					// previous meshes are deleted vy Subdivide().
-				}
-				else {
-					DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
-						+object.name);
-				}
-			}
-		}
-	}
-
-	if (object.name.length())
-		node->mName.Set(object.name);
-	else
-	{
-		// generate a name depending on the type of the node
-		switch (object.type)
-		{
-		case Object::Group:
-			node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++);
-			break;
-		case Object::Poly:
-			node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++);
-			break;
-		case Object::Light:
-			node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++);
-			break;
-
-			// there shouldn't be more than one world, but we don't care
-		case Object::World:
-			node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++);
-			break;
-		}
-	}
-
-
-	// setup the local transformation matrix of the object
-	// compute the transformation offset to the parent node
-	node->mTransformation = aiMatrix4x4 ( object.rotation );
-
-	if (object.type == Object::Group || !object.numRefs)
-	{
-		node->mTransformation.a4 = object.translation.x;
-		node->mTransformation.b4 = object.translation.y;
-		node->mTransformation.c4 = object.translation.z;
-	}
-
-	// add children to the object
-	if (object.children.size())
-	{
-		node->mNumChildren = (unsigned int)object.children.size();
-		node->mChildren = new aiNode*[node->mNumChildren];
-		for (unsigned int i = 0; i < node->mNumChildren;++i)
-		{
-			node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node);
-		}
-	}
-
-	return node;
+    aiNode* node = new aiNode();
+    node->mParent = parent;
+    if (object.vertices.size())
+    {
+        if (!object.surfaces.size() || !object.numRefs)
+        {
+            /* " An object with 7 vertices (no surfaces, no materials defined).
+                 This is a good way of getting point data into AC3D.
+                 The Vertex->create convex-surface/object can be used on these
+                 vertices to 'wrap' a 3d shape around them "
+                 (http://www.opencity.info/html/ac3dfileformat.html)
+
+                 therefore: if no surfaces are defined return point data only
+             */
+
+            DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, "
+                "a point list is returned");
+
+            meshes.push_back(new aiMesh());
+            aiMesh* mesh = meshes.back();
+
+            mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size();
+            aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
+            aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+
+            for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts)
+            {
+                *verts = object.vertices[i];
+                faces->mNumIndices = 1;
+                faces->mIndices = new unsigned int[1];
+                faces->mIndices[0] = i;
+            }
+
+            // use the primary material in this case. this should be the
+            // default material if all objects of the file contain points
+            // and no faces.
+            mesh->mMaterialIndex = 0;
+            outMaterials.push_back(new aiMaterial());
+            ConvertMaterial(object, materials[0], *outMaterials.back());
+        }
+        else
+        {
+            // need to generate one or more meshes for this object.
+            // find out how many different materials we have
+            typedef std::pair< unsigned int, unsigned int > IntPair;
+            typedef std::vector< IntPair > MatTable;
+            MatTable needMat(materials.size(),IntPair(0,0));
+
+            std::vector<Surface>::iterator it,end = object.surfaces.end();
+            std::vector<Surface::SurfaceEntry>::iterator it2,end2;
+
+            for (it = object.surfaces.begin(); it != end; ++it)
+            {
+                unsigned int idx = (*it).mat;
+                if (idx >= needMat.size())
+                {
+                    DefaultLogger::get()->error("AC3D: material index is out of range");
+                    idx = 0;
+                }
+                if ((*it).entries.empty())
+                {
+                    DefaultLogger::get()->warn("AC3D: surface her zero vertex references");
+                }
+
+                // validate all vertex indices to make sure we won't crash here
+                for (it2  = (*it).entries.begin(),
+                     end2 = (*it).entries.end(); it2 != end2; ++it2)
+                {
+                    if ((*it2).first >= object.vertices.size())
+                    {
+                        DefaultLogger::get()->warn("AC3D: Invalid vertex reference");
+                        (*it2).first = 0;
+                    }
+                }
+
+                if (!needMat[idx].first)++node->mNumMeshes;
+
+                switch ((*it).flags & 0xf)
+                {
+                    // closed line
+                case 0x1:
+
+                    needMat[idx].first  += (unsigned int)(*it).entries.size();
+                    needMat[idx].second += (unsigned int)(*it).entries.size()<<1u;
+                    break;
+
+                    // unclosed line
+                case 0x2:
+
+                    needMat[idx].first  += (unsigned int)(*it).entries.size()-1;
+                    needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u;
+                    break;
+
+                    // 0 == polygon, else unknown
+                default:
+
+                    if ((*it).flags & 0xf)
+                    {
+                        DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown");
+                        (*it).flags &= ~(0xf);
+                    }
+
+                    // the number of faces increments by one, the number
+                    // of vertices by surface.numref.
+                    needMat[idx].first++;
+                    needMat[idx].second += (unsigned int)(*it).entries.size();
+                };
+            }
+            unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes];
+            unsigned int mat = 0;
+            const size_t oldm = meshes.size();
+            for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
+                cit != cend; ++cit, ++mat)
+            {
+                if (!(*cit).first)continue;
+
+                // allocate a new aiMesh object
+                *pip++ = (unsigned int)meshes.size();
+                aiMesh* mesh = new aiMesh();
+                meshes.push_back(mesh);
+
+                mesh->mMaterialIndex = (unsigned int)outMaterials.size();
+                outMaterials.push_back(new aiMaterial());
+                ConvertMaterial(object, materials[mat], *outMaterials.back());
+
+                // allocate storage for vertices and normals
+                mesh->mNumFaces = (*cit).first;
+                aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
+
+                mesh->mNumVertices = (*cit).second;
+                aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+                unsigned int cur = 0;
+
+                // allocate UV coordinates, but only if the texture name for the
+                // surface is not empty
+                aiVector3D* uv = NULL;
+                if(object.texture.length())
+                {
+                    uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
+                    mesh->mNumUVComponents[0] = 2;
+                }
+
+                for (it = object.surfaces.begin(); it != end; ++it)
+                {
+                    if (mat == (*it).mat)
+                    {
+                        const Surface& src = *it;
+
+                        // closed polygon
+                        unsigned int type = (*it).flags & 0xf;
+                        if (!type)
+                        {
+                            aiFace& face = *faces++;
+                            if((face.mNumIndices = (unsigned int)src.entries.size()))
+                            {
+                                face.mIndices = new unsigned int[face.mNumIndices];
+                                for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices)
+                                {
+                                    const Surface::SurfaceEntry& entry = src.entries[i];
+                                    face.mIndices[i] = cur++;
+
+                                    // copy vertex positions
+                                    if ((vertices - mesh->mVertices) >= mesh->mNumVertices) {
+                                        throw DeadlyImportError("AC3D: Invalid number of vertices");
+                                    }
+                                    *vertices = object.vertices[entry.first] + object.translation;
+
+
+                                    // copy texture coordinates
+                                    if (uv)
+                                    {
+                                        uv->x =  entry.second.x;
+                                        uv->y =  entry.second.y;
+                                        ++uv;
+                                    }
+                                }
+                            }
+                        }
+                        else
+                        {
+
+                            it2  = (*it).entries.begin();
+
+                            // either a closed or an unclosed line
+                            unsigned int tmp = (unsigned int)(*it).entries.size();
+                            if (0x2 == type)--tmp;
+                            for (unsigned int m = 0; m < tmp;++m)
+                            {
+                                aiFace& face = *faces++;
+
+                                face.mNumIndices = 2;
+                                face.mIndices = new unsigned int[2];
+                                face.mIndices[0] = cur++;
+                                face.mIndices[1] = cur++;
+
+                                // copy vertex positions
+                                if (it2 == (*it).entries.end() ) {
+                                    throw DeadlyImportError("AC3D: Bad line");
+                                }
+                                ai_assert((*it2).first < object.vertices.size());
+                                *vertices++ = object.vertices[(*it2).first];
+
+                                // copy texture coordinates
+                                if (uv)
+                                {
+                                    uv->x =  (*it2).second.x;
+                                    uv->y =  (*it2).second.y;
+                                    ++uv;
+                                }
+
+
+                                if (0x1 == type && tmp-1 == m)
+                                {
+                                    // if this is a closed line repeat its beginning now
+                                    it2  = (*it).entries.begin();
+                                }
+                                else ++it2;
+
+                                // second point
+                                *vertices++ = object.vertices[(*it2).first];
+
+                                if (uv)
+                                {
+                                    uv->x =  (*it2).second.x;
+                                    uv->y =  (*it2).second.y;
+                                    ++uv;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            // Now apply catmull clark subdivision if necessary. We split meshes into
+            // materials which is not done by AC3D during smoothing, so we need to
+            // collect all meshes using the same material group.
+            if (object.subDiv)  {
+                if (configEvalSubdivision) {
+                    boost::scoped_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
+                    DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
+
+                    std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
+                    div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
+                    std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm);
+
+                    // previous meshes are deleted vy Subdivide().
+                }
+                else {
+                    DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
+                        +object.name);
+                }
+            }
+        }
+    }
+
+    if (object.name.length())
+        node->mName.Set(object.name);
+    else
+    {
+        // generate a name depending on the type of the node
+        switch (object.type)
+        {
+        case Object::Group:
+            node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++);
+            break;
+        case Object::Poly:
+            node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++);
+            break;
+        case Object::Light:
+            node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++);
+            break;
+
+            // there shouldn't be more than one world, but we don't care
+        case Object::World:
+            node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++);
+            break;
+        }
+    }
+
+
+    // setup the local transformation matrix of the object
+    // compute the transformation offset to the parent node
+    node->mTransformation = aiMatrix4x4 ( object.rotation );
+
+    if (object.type == Object::Group || !object.numRefs)
+    {
+        node->mTransformation.a4 = object.translation.x;
+        node->mTransformation.b4 = object.translation.y;
+        node->mTransformation.c4 = object.translation.z;
+    }
+
+    // add children to the object
+    if (object.children.size())
+    {
+        node->mNumChildren = (unsigned int)object.children.size();
+        node->mChildren = new aiNode*[node->mNumChildren];
+        for (unsigned int i = 0; i < node->mNumChildren;++i)
+        {
+            node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node);
+        }
+    }
+
+    return node;
 }
 
 // ------------------------------------------------------------------------------------------------
 void AC3DImporter::SetupProperties(const Importer* pImp)
 {
-	configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false;
-	configEvalSubdivision =  pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false;
+    configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false;
+    configEvalSubdivision =  pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void AC3DImporter::InternReadFile( const std::string& pFile,
-	aiScene* pScene, IOSystem* pIOHandler)
+    aiScene* pScene, IOSystem* pIOHandler)
 {
-	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
-
-	// Check whether we can read from the file
-	if( file.get() == NULL)
-		throw DeadlyImportError( "Failed to open AC3D file " + pFile + ".");
-
-	// allocate storage and copy the contents of the file to a memory buffer
-	std::vector<char> mBuffer2;
-	TextFileToBuffer(file.get(),mBuffer2);
-
-	buffer = &mBuffer2[0];
-	mNumMeshes = 0;
-
-	lights = polys = worlds = groups = 0;
-
-	if (::strncmp(buffer,"AC3D",4)) {
-		throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
-	}
-
-	// print the file format version to the console
-	unsigned int version = HexDigitToDecimal( buffer[4] );
-	char msg[3];
-	ASSIMP_itoa10(msg,3,version);
-	DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg);
-
-	std::vector<Material> materials;
-	materials.reserve(5);
-
-	std::vector<Object> rootObjects;
-	rootObjects.reserve(5);
-
-	std::vector<aiLight*> lights;
-	mLights = & lights;
-
-	while (GetNextLine())
-	{
-		if (TokenMatch(buffer,"MATERIAL",8))
-		{
-			materials.push_back(Material());
-			Material& mat = materials.back();
-
-			// manually parse the material ... sscanf would use the buldin atof ...
-			// Format: (name) rgb %f %f %f  amb %f %f %f  emis %f %f %f  spec %f %f %f  shi %d  trans %f
-
-			AI_AC_SKIP_TO_NEXT_TOKEN();
-			if ('\"' == *buffer)
-			{
-				AI_AC_GET_STRING(mat.name);
-				AI_AC_SKIP_TO_NEXT_TOKEN();
-			}
-
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
-		}
-		LoadObjectSection(rootObjects);
-	}
-
-	if (rootObjects.empty() || !mNumMeshes)
-	{
-		throw DeadlyImportError("AC3D: No meshes have been loaded");
-	}
-	if (materials.empty())
-	{
-		DefaultLogger::get()->warn("AC3D: No material has been found");
-		materials.push_back(Material());
-	}
-
-	mNumMeshes += (mNumMeshes>>2u) + 1;
-	std::vector<aiMesh*> meshes;
-	meshes.reserve(mNumMeshes);
-
-	std::vector<aiMaterial*> omaterials;
-	materials.reserve(mNumMeshes);
-
-	// generate a dummy root if there are multiple objects on the top layer
-	Object* root;
-	if (1 == rootObjects.size())
-		root = &rootObjects[0];
-	else
-	{
-		root = new Object();
-	}
-
-	// now convert the imported stuff to our output data structure
-	pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
-	if (1 != rootObjects.size())delete root;
-
-	if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
-		pScene->mRootNode->mName.Set("<AC3DWorld>");
-
-	// copy meshes
-	if (meshes.empty())
-	{
-		throw DeadlyImportError("An unknown error occured during converting");
-	}
-	pScene->mNumMeshes = (unsigned int)meshes.size();
-	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-	::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
-
-	// copy materials
-	pScene->mNumMaterials = (unsigned int)omaterials.size();
-	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
-	::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
-
-	// copy lights
-	pScene->mNumLights = (unsigned int)lights.size();
-	if (lights.size())
-	{
-		pScene->mLights = new aiLight*[lights.size()];
-		::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*));
-	}
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
+
+    // Check whether we can read from the file
+    if( file.get() == NULL)
+        throw DeadlyImportError( "Failed to open AC3D file " + pFile + ".");
+
+    // allocate storage and copy the contents of the file to a memory buffer
+    std::vector<char> mBuffer2;
+    TextFileToBuffer(file.get(),mBuffer2);
+
+    buffer = &mBuffer2[0];
+    mNumMeshes = 0;
+
+    lights = polys = worlds = groups = 0;
+
+    if (::strncmp(buffer,"AC3D",4)) {
+        throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
+    }
+
+    // print the file format version to the console
+    unsigned int version = HexDigitToDecimal( buffer[4] );
+    char msg[3];
+    ASSIMP_itoa10(msg,3,version);
+    DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg);
+
+    std::vector<Material> materials;
+    materials.reserve(5);
+
+    std::vector<Object> rootObjects;
+    rootObjects.reserve(5);
+
+    std::vector<aiLight*> lights;
+    mLights = & lights;
+
+    while (GetNextLine())
+    {
+        if (TokenMatch(buffer,"MATERIAL",8))
+        {
+            materials.push_back(Material());
+            Material& mat = materials.back();
+
+            // manually parse the material ... sscanf would use the buldin atof ...
+            // Format: (name) rgb %f %f %f  amb %f %f %f  emis %f %f %f  spec %f %f %f  shi %d  trans %f
+
+            AI_AC_SKIP_TO_NEXT_TOKEN();
+            if ('\"' == *buffer)
+            {
+                AI_AC_GET_STRING(mat.name);
+                AI_AC_SKIP_TO_NEXT_TOKEN();
+            }
+
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin);
+            AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
+        }
+        LoadObjectSection(rootObjects);
+    }
+
+    if (rootObjects.empty() || !mNumMeshes)
+    {
+        throw DeadlyImportError("AC3D: No meshes have been loaded");
+    }
+    if (materials.empty())
+    {
+        DefaultLogger::get()->warn("AC3D: No material has been found");
+        materials.push_back(Material());
+    }
+
+    mNumMeshes += (mNumMeshes>>2u) + 1;
+    std::vector<aiMesh*> meshes;
+    meshes.reserve(mNumMeshes);
+
+    std::vector<aiMaterial*> omaterials;
+    materials.reserve(mNumMeshes);
+
+    // generate a dummy root if there are multiple objects on the top layer
+    Object* root;
+    if (1 == rootObjects.size())
+        root = &rootObjects[0];
+    else
+    {
+        root = new Object();
+    }
+
+    // now convert the imported stuff to our output data structure
+    pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
+    if (1 != rootObjects.size())delete root;
+
+    if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
+        pScene->mRootNode->mName.Set("<AC3DWorld>");
+
+    // copy meshes
+    if (meshes.empty())
+    {
+        throw DeadlyImportError("An unknown error occured during converting");
+    }
+    pScene->mNumMeshes = (unsigned int)meshes.size();
+    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+    ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
+
+    // copy materials
+    pScene->mNumMaterials = (unsigned int)omaterials.size();
+    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
+    ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
+
+    // copy lights
+    pScene->mNumLights = (unsigned int)lights.size();
+    if (lights.size())
+    {
+        pScene->mLights = new aiLight*[lights.size()];
+        ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*));
+    }
 }
 
 #endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER

+ 162 - 162
code/ACLoader.h

@@ -55,7 +55,7 @@ struct aiMaterial;
 struct aiLight;
 
 
-namespace Assimp	{
+namespace Assimp    {
 
 // ---------------------------------------------------------------------------
 /** AC3D (*.ac) importer class
@@ -63,209 +63,209 @@ namespace Assimp	{
 class AC3DImporter : public BaseImporter
 {
 public:
-	AC3DImporter();
-	~AC3DImporter();
-
-
-
-	// Represents an AC3D material
-	struct Material
-	{
-		Material()
-			:	rgb		(0.6f,0.6f,0.6f)
-			,	spec	(1.f,1.f,1.f)
-			,	shin	(0.f)
-			,	trans	(0.f)
-		{}
+    AC3DImporter();
+    ~AC3DImporter();
+
+
+
+    // Represents an AC3D material
+    struct Material
+    {
+        Material()
+            :   rgb     (0.6f,0.6f,0.6f)
+            ,   spec    (1.f,1.f,1.f)
+            ,   shin    (0.f)
+            ,   trans   (0.f)
+        {}
 
-		// base color of the material
-		aiColor3D rgb;
+        // base color of the material
+        aiColor3D rgb;
 
-		// ambient color of the material
-		aiColor3D amb;
+        // ambient color of the material
+        aiColor3D amb;
 
-		// emissive color of the material
-		aiColor3D emis;
+        // emissive color of the material
+        aiColor3D emis;
 
-		// specular color of the material
-		aiColor3D spec;
+        // specular color of the material
+        aiColor3D spec;
 
-		// shininess exponent
-		float shin;
+        // shininess exponent
+        float shin;
 
-		// transparency. 0 == opaque
-		float trans;
+        // transparency. 0 == opaque
+        float trans;
 
-		// name of the material. optional.
-		std::string name;
-	};
+        // name of the material. optional.
+        std::string name;
+    };
 
-	// Represents an AC3D surface
-	struct Surface
-	{
-		Surface()
-			:	mat		(0)
-			,	flags	(0)
-		{}
+    // Represents an AC3D surface
+    struct Surface
+    {
+        Surface()
+            :   mat     (0)
+            ,   flags   (0)
+        {}
 
-		unsigned int mat,flags;
+        unsigned int mat,flags;
 
-		typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
-		std::vector< SurfaceEntry > entries;
-	};
+        typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
+        std::vector< SurfaceEntry > entries;
+    };
 
-	// Represents an AC3D object
-	struct Object
-	{
-		Object()
-			:	type	(World)
-			,	name( "" )
-			,	children()
-			,	texture( "" )
-			,	texRepeat( 1.f, 1.f )
-			,	texOffset( 0.0f, 0.0f )
-			,	rotation()
-			,	translation()
-			,	vertices()
-			,	surfaces()
-			,	numRefs (0)
-			,	subDiv	(0)
-		{}
+    // Represents an AC3D object
+    struct Object
+    {
+        Object()
+            :   type    (World)
+            ,   name( "" )
+            ,   children()
+            ,   texture( "" )
+            ,   texRepeat( 1.f, 1.f )
+            ,   texOffset( 0.0f, 0.0f )
+            ,   rotation()
+            ,   translation()
+            ,   vertices()
+            ,   surfaces()
+            ,   numRefs (0)
+            ,   subDiv  (0)
+        {}
 
-		// Type description
-		enum Type
-		{
-			World = 0x0,
-			Poly  = 0x1,
-			Group = 0x2,
-			Light = 0x4
-		} type;
+        // Type description
+        enum Type
+        {
+            World = 0x0,
+            Poly  = 0x1,
+            Group = 0x2,
+            Light = 0x4
+        } type;
 
-		// name of the object
-		std::string name;
+        // name of the object
+        std::string name;
 
-		// object children
-		std::vector<Object> children;
+        // object children
+        std::vector<Object> children;
 
-		// texture to be assigned to all surfaces of the object
-		std::string texture;
+        // texture to be assigned to all surfaces of the object
+        std::string texture;
 
-		// texture repat factors (scaling for all coordinates)
-		aiVector2D texRepeat, texOffset;
+        // texture repat factors (scaling for all coordinates)
+        aiVector2D texRepeat, texOffset;
 
-		// rotation matrix
-		aiMatrix3x3 rotation;
+        // rotation matrix
+        aiMatrix3x3 rotation;
 
-		// translation vector
-		aiVector3D translation;
+        // translation vector
+        aiVector3D translation;
 
-		// vertices
-		std::vector<aiVector3D> vertices;
+        // vertices
+        std::vector<aiVector3D> vertices;
 
-		// surfaces
-		std::vector<Surface> surfaces;
+        // surfaces
+        std::vector<Surface> surfaces;
 
-		// number of indices (= num verts in verbose format)
-		unsigned int numRefs;
-
-		// number of subdivisions to be performed on the
-		// imported data
-		unsigned int subDiv;
-
-		// max angle limit for smoothing
-		float crease;
-	};
+        // number of indices (= num verts in verbose format)
+        unsigned int numRefs;
+
+        // number of subdivisions to be performed on the
+        // imported data
+        unsigned int subDiv;
+
+        // max angle limit for smoothing
+        float crease;
+    };
 
 
 public:
 
-	// -------------------------------------------------------------------
-	/** Returns whether the class can handle the format of the given file.
-	 * See BaseImporter::CanRead() for details.
-	 */
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-		bool checkSig) const;
+    // -------------------------------------------------------------------
+    /** Returns whether the class can handle the format of the given file.
+     * See BaseImporter::CanRead() for details.
+     */
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Return importer meta information.
-	 * See #BaseImporter::GetInfo for the details */
-	const aiImporterDesc* GetInfo () const;
+    // -------------------------------------------------------------------
+    /** Return importer meta information.
+     * See #BaseImporter::GetInfo for the details */
+    const aiImporterDesc* GetInfo () const;
 
-	// -------------------------------------------------------------------
-	/** Imports the given file into the given scene structure.
-	 * See BaseImporter::InternReadFile() for details*/
-	void InternReadFile( const std::string& pFile, aiScene* pScene,
-		IOSystem* pIOHandler);
+    // -------------------------------------------------------------------
+    /** Imports the given file into the given scene structure.
+     * See BaseImporter::InternReadFile() for details*/
+    void InternReadFile( const std::string& pFile, aiScene* pScene,
+        IOSystem* pIOHandler);
 
-	// -------------------------------------------------------------------
-	/** Called prior to ReadFile().
-	* The function is a request to the importer to update its configuration
-	* basing on the Importer's configuration property list.*/
-	void SetupProperties(const Importer* pImp);
+    // -------------------------------------------------------------------
+    /** Called prior to ReadFile().
+    * The function is a request to the importer to update its configuration
+    * basing on the Importer's configuration property list.*/
+    void SetupProperties(const Importer* pImp);
 
 private:
 
-	// -------------------------------------------------------------------
-	/** Get the next line from the file.
-	 *  @return false if the end of the file was reached*/
-	bool GetNextLine();
-
-	// -------------------------------------------------------------------
-	/** Load the object section. This method is called recursively to
-	 *  load subobjects, the method returns after a 'kids 0' was
-	 *  encountered.
-	 *  @objects List of output objects*/
-	void LoadObjectSection(std::vector<Object>& objects);
-
-	// -------------------------------------------------------------------
-	/** Convert all objects into meshes and nodes.
-	 *  @param object Current object to work on
-	 *  @param meshes Pointer to the list of output meshes
-	 *  @param outMaterials List of output materials
-	 *  @param materials Material list
-	 *  @param Scenegraph node for the object */
-	aiNode* ConvertObjectSection(Object& object,
-		std::vector<aiMesh*>& meshes,
-		std::vector<aiMaterial*>& outMaterials,
-		const std::vector<Material>& materials,
-		aiNode* parent = NULL);
-
-	// -------------------------------------------------------------------
-	/** Convert a material
-	 *  @param object Current object
-	 *  @param matSrc Source material description
-	 *  @param matDest Destination material to be filled */
-	void ConvertMaterial(const Object& object,
-		const Material& matSrc,
-		aiMaterial& matDest);
+    // -------------------------------------------------------------------
+    /** Get the next line from the file.
+     *  @return false if the end of the file was reached*/
+    bool GetNextLine();
+
+    // -------------------------------------------------------------------
+    /** Load the object section. This method is called recursively to
+     *  load subobjects, the method returns after a 'kids 0' was
+     *  encountered.
+     *  @objects List of output objects*/
+    void LoadObjectSection(std::vector<Object>& objects);
+
+    // -------------------------------------------------------------------
+    /** Convert all objects into meshes and nodes.
+     *  @param object Current object to work on
+     *  @param meshes Pointer to the list of output meshes
+     *  @param outMaterials List of output materials
+     *  @param materials Material list
+     *  @param Scenegraph node for the object */
+    aiNode* ConvertObjectSection(Object& object,
+        std::vector<aiMesh*>& meshes,
+        std::vector<aiMaterial*>& outMaterials,
+        const std::vector<Material>& materials,
+        aiNode* parent = NULL);
+
+    // -------------------------------------------------------------------
+    /** Convert a material
+     *  @param object Current object
+     *  @param matSrc Source material description
+     *  @param matDest Destination material to be filled */
+    void ConvertMaterial(const Object& object,
+        const Material& matSrc,
+        aiMaterial& matDest);
 
 private:
 
 
-	// points to the next data line
-	const char* buffer;
+    // points to the next data line
+    const char* buffer;
 
-	// Configuration option: if enabled, up to two meshes
-	// are generated per material: those faces who have
-	// their bf cull flags set are separated.
-	bool configSplitBFCull;
+    // Configuration option: if enabled, up to two meshes
+    // are generated per material: those faces who have
+    // their bf cull flags set are separated.
+    bool configSplitBFCull;
 
-	// Configuration switch: subdivision surfaces are only
-	// evaluated if the value is true.
-	bool configEvalSubdivision;
+    // Configuration switch: subdivision surfaces are only
+    // evaluated if the value is true.
+    bool configEvalSubdivision;
 
-	// counts how many objects we have in the tree.
-	// basing on this information we can find a
-	// good estimate how many meshes we'll have in the final scene.
-	unsigned int mNumMeshes;
+    // counts how many objects we have in the tree.
+    // basing on this information we can find a
+    // good estimate how many meshes we'll have in the final scene.
+    unsigned int mNumMeshes;
 
-	// current list of light sources
-	std::vector<aiLight*>* mLights;
+    // current list of light sources
+    std::vector<aiLight*>* mLights;
 
-	// name counters
-	unsigned int lights, groups, polys, worlds;
+    // name counters
+    unsigned int lights, groups, polys, worlds;
 };
 
 } // end of namespace Assimp

+ 1138 - 1138
code/ASELoader.cpp

@@ -64,16 +64,16 @@ using namespace Assimp;
 using namespace Assimp::ASE;
 
 static const aiImporterDesc desc = {
-	"ASE Importer",
-	"",
-	"",
-	"Similar to 3DS but text-encoded",
-	aiImporterFlags_SupportTextFlavour,
-	0,
-	0,
-	0,
-	0,
-	"ase ask"
+    "ASE Importer",
+    "",
+    "",
+    "Similar to 3DS but text-encoded",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "ase ask"
 };
 
 // ------------------------------------------------------------------------------------------------
@@ -91,1231 +91,1231 @@ ASEImporter::~ASEImporter()
 // Returns whether the class can handle the format of the given file.
 bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
 {
-	// check file extension
-	const std::string extension = GetExtension(pFile);
+    // check file extension
+    const std::string extension = GetExtension(pFile);
 
-	if( extension == "ase" || extension == "ask")
-		return true;
+    if( extension == "ase" || extension == "ask")
+        return true;
 
-	if ((!extension.length() || cs) && pIOHandler) {
-		const char* tokens[] = {"*3dsmax_asciiexport"};
-		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-	}
-	return false;
+    if ((!extension.length() || cs) && pIOHandler) {
+        const char* tokens[] = {"*3dsmax_asciiexport"};
+        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Loader meta information
 const aiImporterDesc* ASEImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup configuration options
 void ASEImporter::SetupProperties(const Importer* pImp)
 {
-	configRecomputeNormals = (pImp->GetPropertyInteger(
-		AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
+    configRecomputeNormals = (pImp->GetPropertyInteger(
+        AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
 
-	noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
+    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void ASEImporter::InternReadFile( const std::string& pFile,
-	aiScene* pScene, IOSystem* pIOHandler)
+    aiScene* pScene, IOSystem* pIOHandler)
 {
-	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
-
-	// Check whether we can read from the file
-	if( file.get() == NULL) {
-		throw DeadlyImportError( "Failed to open ASE file " + pFile + ".");
-	}
-
-	// Allocate storage and copy the contents of the file to a memory buffer
-	std::vector<char> mBuffer2;
-	TextFileToBuffer(file.get(),mBuffer2);
-
-	this->mBuffer = &mBuffer2[0];
-	this->pcScene = pScene;
-
-	// ------------------------------------------------------------------
-	// Guess the file format by looking at the extension
-	// ASC is considered to be the older format 110,
-	// ASE is the actual version 200 (that is currently written by max)
-	// ------------------------------------------------------------------
-	unsigned int defaultFormat;
-	std::string::size_type s = pFile.length()-1;
-	switch (pFile.c_str()[s])	{
-
-	case 'C':
-	case 'c':
-		defaultFormat = AI_ASE_OLD_FILE_FORMAT;
-		break;
-	default:
-		defaultFormat = AI_ASE_NEW_FILE_FORMAT;
-	};
-
-	// Construct an ASE parser and parse the file
-	ASE::Parser parser(mBuffer,defaultFormat);
-	mParser = &parser;
-	mParser->Parse();
-
-	//------------------------------------------------------------------
-	// Check whether we god at least one mesh. If we did - generate
-	// materials and copy meshes.
-	// ------------------------------------------------------------------
-	if ( !mParser->m_vMeshes.empty())	{
-
-		// If absolutely no material has been loaded from the file
-		// we need to generate a default material
-		GenerateDefaultMaterial();
-
-		// process all meshes
-		bool tookNormals = false;
-		std::vector<aiMesh*> avOutMeshes;
-		avOutMeshes.reserve(mParser->m_vMeshes.size()*2);
-		for (std::vector<ASE::Mesh>::iterator i =  mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i)	{
-			if ((*i).bSkip) {
-				continue;
-			}
-			BuildUniqueRepresentation(*i);
-
-			// Need to generate proper vertex normals if necessary
-			if(GenerateNormals(*i)) {
-				tookNormals = true;
-			}
-
-			// Convert all meshes to aiMesh objects
-			ConvertMeshes(*i,avOutMeshes);
-		}
-		if (tookNormals)	{
-			DefaultLogger::get()->debug("ASE: Taking normals from the file. Use "
-				"the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you "
-				"experience problems");
-		}
-
-		// Now build the output mesh list. Remove dummies
-		pScene->mNumMeshes = (unsigned int)avOutMeshes.size();
-		aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-		for (std::vector<aiMesh*>::const_iterator i =  avOutMeshes.begin();i != avOutMeshes.end();++i) {
-			if (!(*i)->mNumFaces) {
-				continue;
-			}
-			*pp++ = *i;
-		}
-		pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes);
-
-		// Build final material indices (remove submaterials and setup
-		// the final list)
-		BuildMaterialIndices();
-	}
-
-	// ------------------------------------------------------------------
-	// Copy all scene graph nodes - lights, cameras, dummies and meshes
-	// into one huge list.
-	//------------------------------------------------------------------
-	std::vector<BaseNode*> nodes;
-	nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
-		+ mParser->m_vCameras.size() + mParser->m_vDummies.size());
-
-	// Lights
-	for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(),
-		 end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it));
-	// Cameras
-	for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(),
-		 end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it));
-	// Meshes
-	for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(),
-		end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it));
-	// Dummies
-	for (std::vector<ASE::Dummy>::iterator it = mParser->m_vDummies.begin(),
-		end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it));
-
-	// build the final node graph
-	BuildNodes(nodes);
-
-	// build output animations
-	BuildAnimations(nodes);
-
-	// build output cameras
-	BuildCameras();
-
-	// build output lights
-	BuildLights();
-
-	// ------------------------------------------------------------------
-	// If we have no meshes use the SkeletonMeshBuilder helper class
-	// to build a mesh for the animation skeleton
-	// FIXME: very strange results
-	// ------------------------------------------------------------------
-	if (!pScene->mNumMeshes)	{
-		pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
-		if (!noSkeletonMesh) {
-			SkeletonMeshBuilder skeleton(pScene);
-		}
-	}
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
+
+    // Check whether we can read from the file
+    if( file.get() == NULL) {
+        throw DeadlyImportError( "Failed to open ASE file " + pFile + ".");
+    }
+
+    // Allocate storage and copy the contents of the file to a memory buffer
+    std::vector<char> mBuffer2;
+    TextFileToBuffer(file.get(),mBuffer2);
+
+    this->mBuffer = &mBuffer2[0];
+    this->pcScene = pScene;
+
+    // ------------------------------------------------------------------
+    // Guess the file format by looking at the extension
+    // ASC is considered to be the older format 110,
+    // ASE is the actual version 200 (that is currently written by max)
+    // ------------------------------------------------------------------
+    unsigned int defaultFormat;
+    std::string::size_type s = pFile.length()-1;
+    switch (pFile.c_str()[s])   {
+
+    case 'C':
+    case 'c':
+        defaultFormat = AI_ASE_OLD_FILE_FORMAT;
+        break;
+    default:
+        defaultFormat = AI_ASE_NEW_FILE_FORMAT;
+    };
+
+    // Construct an ASE parser and parse the file
+    ASE::Parser parser(mBuffer,defaultFormat);
+    mParser = &parser;
+    mParser->Parse();
+
+    //------------------------------------------------------------------
+    // Check whether we god at least one mesh. If we did - generate
+    // materials and copy meshes.
+    // ------------------------------------------------------------------
+    if ( !mParser->m_vMeshes.empty())   {
+
+        // If absolutely no material has been loaded from the file
+        // we need to generate a default material
+        GenerateDefaultMaterial();
+
+        // process all meshes
+        bool tookNormals = false;
+        std::vector<aiMesh*> avOutMeshes;
+        avOutMeshes.reserve(mParser->m_vMeshes.size()*2);
+        for (std::vector<ASE::Mesh>::iterator i =  mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i)    {
+            if ((*i).bSkip) {
+                continue;
+            }
+            BuildUniqueRepresentation(*i);
+
+            // Need to generate proper vertex normals if necessary
+            if(GenerateNormals(*i)) {
+                tookNormals = true;
+            }
+
+            // Convert all meshes to aiMesh objects
+            ConvertMeshes(*i,avOutMeshes);
+        }
+        if (tookNormals)    {
+            DefaultLogger::get()->debug("ASE: Taking normals from the file. Use "
+                "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you "
+                "experience problems");
+        }
+
+        // Now build the output mesh list. Remove dummies
+        pScene->mNumMeshes = (unsigned int)avOutMeshes.size();
+        aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+        for (std::vector<aiMesh*>::const_iterator i =  avOutMeshes.begin();i != avOutMeshes.end();++i) {
+            if (!(*i)->mNumFaces) {
+                continue;
+            }
+            *pp++ = *i;
+        }
+        pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes);
+
+        // Build final material indices (remove submaterials and setup
+        // the final list)
+        BuildMaterialIndices();
+    }
+
+    // ------------------------------------------------------------------
+    // Copy all scene graph nodes - lights, cameras, dummies and meshes
+    // into one huge list.
+    //------------------------------------------------------------------
+    std::vector<BaseNode*> nodes;
+    nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
+        + mParser->m_vCameras.size() + mParser->m_vDummies.size());
+
+    // Lights
+    for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(),
+         end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it));
+    // Cameras
+    for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(),
+         end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it));
+    // Meshes
+    for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(),
+        end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it));
+    // Dummies
+    for (std::vector<ASE::Dummy>::iterator it = mParser->m_vDummies.begin(),
+        end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it));
+
+    // build the final node graph
+    BuildNodes(nodes);
+
+    // build output animations
+    BuildAnimations(nodes);
+
+    // build output cameras
+    BuildCameras();
+
+    // build output lights
+    BuildLights();
+
+    // ------------------------------------------------------------------
+    // If we have no meshes use the SkeletonMeshBuilder helper class
+    // to build a mesh for the animation skeleton
+    // FIXME: very strange results
+    // ------------------------------------------------------------------
+    if (!pScene->mNumMeshes)    {
+        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
+        if (!noSkeletonMesh) {
+            SkeletonMeshBuilder skeleton(pScene);
+        }
+    }
 }
 // ------------------------------------------------------------------------------------------------
 void ASEImporter::GenerateDefaultMaterial()
 {
-	ai_assert(NULL != mParser);
-
-	bool bHas = false;
-	for (std::vector<ASE::Mesh>::iterator i =  mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) {
-		if ((*i).bSkip)continue;
-		if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex)	{
-			(*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size();
-			bHas = true;
-		}
-	}
-	if (bHas || mParser->m_vMaterials.empty())	{
-		// add a simple material without submaterials to the parser's list
-		mParser->m_vMaterials.push_back ( ASE::Material() );
-		ASE::Material& mat = mParser->m_vMaterials.back();
-
-		mat.mDiffuse  = aiColor3D(0.6f,0.6f,0.6f);
-		mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f);
-		mat.mAmbient  = aiColor3D(0.05f,0.05f,0.05f);
-		mat.mShading  = Discreet3DS::Gouraud;
-		mat.mName     = AI_DEFAULT_MATERIAL_NAME;
-	}
+    ai_assert(NULL != mParser);
+
+    bool bHas = false;
+    for (std::vector<ASE::Mesh>::iterator i =  mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) {
+        if ((*i).bSkip)continue;
+        if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) {
+            (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size();
+            bHas = true;
+        }
+    }
+    if (bHas || mParser->m_vMaterials.empty())  {
+        // add a simple material without submaterials to the parser's list
+        mParser->m_vMaterials.push_back ( ASE::Material() );
+        ASE::Material& mat = mParser->m_vMaterials.back();
+
+        mat.mDiffuse  = aiColor3D(0.6f,0.6f,0.6f);
+        mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f);
+        mat.mAmbient  = aiColor3D(0.05f,0.05f,0.05f);
+        mat.mShading  = Discreet3DS::Gouraud;
+        mat.mName     = AI_DEFAULT_MATERIAL_NAME;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
 {
-	// check whether we have at least one mesh which has animations
-	std::vector<ASE::BaseNode*>::const_iterator i =  nodes.begin();
-	unsigned int iNum = 0;
-	for (;i != nodes.end();++i)	{
-
-		// TODO: Implement Bezier & TCB support
-		if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK)	{
-			DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
-				"This is not supported.");
-		}
-		if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK)	{
-			DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. "
-				"This is not supported.");
-		}
-		if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK)	{
-			DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
-				"This is not supported.");
-		}
-
-		// We compare against 1 here - firstly one key is not
-		// really an animation and secondly MAX writes dummies
-		// that represent the node transformation.
-		if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){
-			++iNum;
-		}
-		if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) {
-			++iNum;
-		}
-	}
-	if (iNum)	{
-		// Generate a new animation channel and setup everything for it
-		pcScene->mNumAnimations = 1;
-		pcScene->mAnimations    = new aiAnimation*[1];
-		aiAnimation* pcAnim     = pcScene->mAnimations[0] = new aiAnimation();
-		pcAnim->mNumChannels    = iNum;
-		pcAnim->mChannels       = new aiNodeAnim*[iNum];
-		pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame;
-
-		iNum = 0;
-
-		// Now iterate through all meshes and collect all data we can find
-		for (i =  nodes.begin();i != nodes.end();++i)	{
-
-			ASE::BaseNode* me = *i;
-			if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x ))	{
-				// Generate an extra channel for the camera/light target.
-				// BuildNodes() does also generate an extra node, named
-				// <baseName>.Target.
-				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
-				nd->mNodeName.Set(me->mName + ".Target");
-
-				// If there is no input position channel we will need
-				// to supply the default position from the node's
-				// local transformation matrix.
-				/*TargetAnimationHelper helper;
-				if (me->mAnim.akeyPositions.empty())
-				{
-					aiMatrix4x4& mat = (*i)->mTransform;
-					helper.SetFixedMainAnimationChannel(aiVector3D(
-						mat.a4, mat.b4, mat.c4));
-				}
-				else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
-				helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
-
-				helper.Process(&me->mTargetAnim.akeyPositions);*/
-
-				// Allocate the key array and fill it
-				nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size();
-				nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
-
-				::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0],
-					nd->mNumPositionKeys * sizeof(aiVectorKey));
-			}
-
-			if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1)	{
-				// Begin a new node animation channel for this node
-				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
-				nd->mNodeName.Set(me->mName);
-
-				// copy position keys
-				if (me->mAnim.akeyPositions.size() > 1 )
-				{
-					// Allocate the key array and fill it
-					nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size();
-					nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
-
-					::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0],
-						nd->mNumPositionKeys * sizeof(aiVectorKey));
-				}
-				// copy rotation keys
-				if (me->mAnim.akeyRotations.size() > 1 )	{
-					// Allocate the key array and fill it
-					nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size();
-					nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
-
-					// --------------------------------------------------------------------
-					// Rotation keys are offsets to the previous keys.
-					// We have the quaternion representations of all
-					// of them, so we just need to concatenate all
-					// (unit-length) quaternions to get the absolute
-					// rotations.
-					// Rotation keys are ABSOLUTE for older files
-					// --------------------------------------------------------------------
-
-					aiQuaternion cur;
-					for (unsigned int a = 0; a < nd->mNumRotationKeys;++a)	{
-						aiQuatKey q = me->mAnim.akeyRotations[a];
-
-						if (mParser->iFileFormat > 110)	{
-							cur = (a ? cur*q.mValue : q.mValue);
-							q.mValue = cur.Normalize();
-						}
-						nd->mRotationKeys[a] = q;
-
-						// need this to get to Assimp quaternion conventions
-						nd->mRotationKeys[a].mValue.w *= -1.f;
-					}
-				}
-				// copy scaling keys
-				if (me->mAnim.akeyScaling.size() > 1 )	{
-					// Allocate the key array and fill it
-					nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size();
-					nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
-
-					::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0],
-						nd->mNumScalingKeys * sizeof(aiVectorKey));
-				}
-			}
-		}
-	}
+    // check whether we have at least one mesh which has animations
+    std::vector<ASE::BaseNode*>::const_iterator i =  nodes.begin();
+    unsigned int iNum = 0;
+    for (;i != nodes.end();++i) {
+
+        // TODO: Implement Bezier & TCB support
+        if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) {
+            DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
+                "This is not supported.");
+        }
+        if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) {
+            DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. "
+                "This is not supported.");
+        }
+        if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK)  {
+            DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
+                "This is not supported.");
+        }
+
+        // We compare against 1 here - firstly one key is not
+        // really an animation and secondly MAX writes dummies
+        // that represent the node transformation.
+        if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){
+            ++iNum;
+        }
+        if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) {
+            ++iNum;
+        }
+    }
+    if (iNum)   {
+        // Generate a new animation channel and setup everything for it
+        pcScene->mNumAnimations = 1;
+        pcScene->mAnimations    = new aiAnimation*[1];
+        aiAnimation* pcAnim     = pcScene->mAnimations[0] = new aiAnimation();
+        pcAnim->mNumChannels    = iNum;
+        pcAnim->mChannels       = new aiNodeAnim*[iNum];
+        pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame;
+
+        iNum = 0;
+
+        // Now iterate through all meshes and collect all data we can find
+        for (i =  nodes.begin();i != nodes.end();++i)   {
+
+            ASE::BaseNode* me = *i;
+            if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x ))  {
+                // Generate an extra channel for the camera/light target.
+                // BuildNodes() does also generate an extra node, named
+                // <baseName>.Target.
+                aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
+                nd->mNodeName.Set(me->mName + ".Target");
+
+                // If there is no input position channel we will need
+                // to supply the default position from the node's
+                // local transformation matrix.
+                /*TargetAnimationHelper helper;
+                if (me->mAnim.akeyPositions.empty())
+                {
+                    aiMatrix4x4& mat = (*i)->mTransform;
+                    helper.SetFixedMainAnimationChannel(aiVector3D(
+                        mat.a4, mat.b4, mat.c4));
+                }
+                else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
+                helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
+
+                helper.Process(&me->mTargetAnim.akeyPositions);*/
+
+                // Allocate the key array and fill it
+                nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size();
+                nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
+
+                ::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0],
+                    nd->mNumPositionKeys * sizeof(aiVectorKey));
+            }
+
+            if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1)   {
+                // Begin a new node animation channel for this node
+                aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
+                nd->mNodeName.Set(me->mName);
+
+                // copy position keys
+                if (me->mAnim.akeyPositions.size() > 1 )
+                {
+                    // Allocate the key array and fill it
+                    nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size();
+                    nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
+
+                    ::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0],
+                        nd->mNumPositionKeys * sizeof(aiVectorKey));
+                }
+                // copy rotation keys
+                if (me->mAnim.akeyRotations.size() > 1 )    {
+                    // Allocate the key array and fill it
+                    nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size();
+                    nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
+
+                    // --------------------------------------------------------------------
+                    // Rotation keys are offsets to the previous keys.
+                    // We have the quaternion representations of all
+                    // of them, so we just need to concatenate all
+                    // (unit-length) quaternions to get the absolute
+                    // rotations.
+                    // Rotation keys are ABSOLUTE for older files
+                    // --------------------------------------------------------------------
+
+                    aiQuaternion cur;
+                    for (unsigned int a = 0; a < nd->mNumRotationKeys;++a)  {
+                        aiQuatKey q = me->mAnim.akeyRotations[a];
+
+                        if (mParser->iFileFormat > 110) {
+                            cur = (a ? cur*q.mValue : q.mValue);
+                            q.mValue = cur.Normalize();
+                        }
+                        nd->mRotationKeys[a] = q;
+
+                        // need this to get to Assimp quaternion conventions
+                        nd->mRotationKeys[a].mValue.w *= -1.f;
+                    }
+                }
+                // copy scaling keys
+                if (me->mAnim.akeyScaling.size() > 1 )  {
+                    // Allocate the key array and fill it
+                    nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size();
+                    nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
+
+                    ::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0],
+                        nd->mNumScalingKeys * sizeof(aiVectorKey));
+                }
+            }
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Build output cameras
 void ASEImporter::BuildCameras()
 {
-	if (!mParser->m_vCameras.empty())	{
-		pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
-		pcScene->mCameras = new aiCamera*[pcScene->mNumCameras];
-
-		for (unsigned int i = 0; i < pcScene->mNumCameras;++i)	{
-			aiCamera* out = pcScene->mCameras[i] = new aiCamera();
-			ASE::Camera& in = mParser->m_vCameras[i];
-
-			// copy members
-			out->mClipPlaneFar  = in.mFar;
-			out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f);
-			out->mHorizontalFOV = in.mFOV;
-
-			out->mName.Set(in.mName);
-		}
-	}
+    if (!mParser->m_vCameras.empty())   {
+        pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
+        pcScene->mCameras = new aiCamera*[pcScene->mNumCameras];
+
+        for (unsigned int i = 0; i < pcScene->mNumCameras;++i)  {
+            aiCamera* out = pcScene->mCameras[i] = new aiCamera();
+            ASE::Camera& in = mParser->m_vCameras[i];
+
+            // copy members
+            out->mClipPlaneFar  = in.mFar;
+            out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f);
+            out->mHorizontalFOV = in.mFOV;
+
+            out->mName.Set(in.mName);
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Build output lights
 void ASEImporter::BuildLights()
 {
-	if (!mParser->m_vLights.empty())	{
-		pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
-		pcScene->mLights    = new aiLight*[pcScene->mNumLights];
-
-		for (unsigned int i = 0; i < pcScene->mNumLights;++i)	{
-			aiLight* out = pcScene->mLights[i] = new aiLight();
-			ASE::Light& in = mParser->m_vLights[i];
-
-			// The direction is encoded in the transformation matrix of the node.
-			// In 3DS MAX the light source points into negative Z direction if
-			// the node transformation is the identity.
-			out->mDirection = aiVector3D(0.f,0.f,-1.f);
-
-			out->mName.Set(in.mName);
-			switch (in.mLightType)
-			{
-			case ASE::Light::TARGET:
-				out->mType = aiLightSource_SPOT;
-				out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
-				out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone);
-				break;
-
-			case ASE::Light::DIRECTIONAL:
-				out->mType = aiLightSource_DIRECTIONAL;
-				break;
-
-			default:
-			//case ASE::Light::OMNI:
-				out->mType = aiLightSource_POINT;
-				break;
-			};
-			out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity;
-		}
-	}
+    if (!mParser->m_vLights.empty())    {
+        pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
+        pcScene->mLights    = new aiLight*[pcScene->mNumLights];
+
+        for (unsigned int i = 0; i < pcScene->mNumLights;++i)   {
+            aiLight* out = pcScene->mLights[i] = new aiLight();
+            ASE::Light& in = mParser->m_vLights[i];
+
+            // The direction is encoded in the transformation matrix of the node.
+            // In 3DS MAX the light source points into negative Z direction if
+            // the node transformation is the identity.
+            out->mDirection = aiVector3D(0.f,0.f,-1.f);
+
+            out->mName.Set(in.mName);
+            switch (in.mLightType)
+            {
+            case ASE::Light::TARGET:
+                out->mType = aiLightSource_SPOT;
+                out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
+                out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone);
+                break;
+
+            case ASE::Light::DIRECTIONAL:
+                out->mType = aiLightSource_DIRECTIONAL;
+                break;
+
+            default:
+            //case ASE::Light::OMNI:
+                out->mType = aiLightSource_POINT;
+                break;
+            };
+            out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity;
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void ASEImporter::AddNodes(const std::vector<BaseNode*>& nodes,
-	aiNode* pcParent,const char* szName)
+    aiNode* pcParent,const char* szName)
 {
-	aiMatrix4x4 m;
-	AddNodes(nodes,pcParent,szName,m);
+    aiMatrix4x4 m;
+    AddNodes(nodes,pcParent,szName,m);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Add meshes to a given node
 void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
 {
-	for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)	{
-		// Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
-		const aiMesh* pcMesh  = pcScene->mMeshes[i];
-		const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
-
-		if (mesh == snode) {
-			++node->mNumMeshes;
-		}
-	}
-
-	if(node->mNumMeshes)	{
-		node->mMeshes = new unsigned int[node->mNumMeshes];
-		for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i)	{
-
-			const aiMesh* pcMesh  = pcScene->mMeshes[i];
-			const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
-			if (mesh == snode)	{
-				node->mMeshes[p++] = i;
-
-				// Transform all vertices of the mesh back into their local space ->
-				// at the moment they are pretransformed
-				aiMatrix4x4 m  = mesh->mTransform;
-				m.Inverse();
-
-				aiVector3D* pvCurPtr = pcMesh->mVertices;
-				const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
-				while (pvCurPtr != pvEndPtr)	{
-					*pvCurPtr = m * (*pvCurPtr);
-					pvCurPtr++;
-				}
-
-				// Do the same for the normal vectors, if we have them.
-				// As always, inverse transpose.
-				if (pcMesh->mNormals)	{
-					aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform );
-					m3.Transpose();
-
-					pvCurPtr = pcMesh->mNormals;
-					pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
-					while (pvCurPtr != pvEndPtr)	{
-						*pvCurPtr = m3 * (*pvCurPtr);
-						pvCurPtr++;
-					}
-				}
-			}
-		}
-	}
+    for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)   {
+        // Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
+        const aiMesh* pcMesh  = pcScene->mMeshes[i];
+        const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
+
+        if (mesh == snode) {
+            ++node->mNumMeshes;
+        }
+    }
+
+    if(node->mNumMeshes)    {
+        node->mMeshes = new unsigned int[node->mNumMeshes];
+        for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i)    {
+
+            const aiMesh* pcMesh  = pcScene->mMeshes[i];
+            const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
+            if (mesh == snode)  {
+                node->mMeshes[p++] = i;
+
+                // Transform all vertices of the mesh back into their local space ->
+                // at the moment they are pretransformed
+                aiMatrix4x4 m  = mesh->mTransform;
+                m.Inverse();
+
+                aiVector3D* pvCurPtr = pcMesh->mVertices;
+                const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
+                while (pvCurPtr != pvEndPtr)    {
+                    *pvCurPtr = m * (*pvCurPtr);
+                    pvCurPtr++;
+                }
+
+                // Do the same for the normal vectors, if we have them.
+                // As always, inverse transpose.
+                if (pcMesh->mNormals)   {
+                    aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform );
+                    m3.Transpose();
+
+                    pvCurPtr = pcMesh->mNormals;
+                    pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
+                    while (pvCurPtr != pvEndPtr)    {
+                        *pvCurPtr = m3 * (*pvCurPtr);
+                        pvCurPtr++;
+                    }
+                }
+            }
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Add child nodes to a given parent node
 void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
-	aiNode* pcParent, const char* szName,
-	const aiMatrix4x4& mat)
+    aiNode* pcParent, const char* szName,
+    const aiMatrix4x4& mat)
 {
-	const size_t len = szName ? ::strlen(szName) : 0;
-	ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
-
-	// Receives child nodes for the pcParent node
-	std::vector<aiNode*> apcNodes;
-
-	// Now iterate through all nodes in the scene and search for one
-	// which has *us* as parent.
-	for (std::vector<BaseNode*>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
-		const BaseNode* snode = *it;
-		if (szName)	{
-			if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str()))
-				continue;
-		}
-		else if (snode->mParent.length())
-			continue;
-
-		(*it)->mProcessed = true;
-
-		// Allocate a new node and add it to the output data structure
-		apcNodes.push_back(new aiNode());
-		aiNode* node = apcNodes.back();
-
-		node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
-		node->mParent = pcParent;
-
-		// Setup the transformation matrix of the node
-		aiMatrix4x4 mParentAdjust  = mat;
-		mParentAdjust.Inverse();
-		node->mTransformation = mParentAdjust*snode->mTransform;
-
-		// Add sub nodes - prevent stack overflow due to recursive parenting
-		if (node->mName != node->mParent->mName) {
-			AddNodes(nodes,node,node->mName.data,snode->mTransform);
-		}
-
-		// Further processing depends on the type of the node
-		if (snode->mType == ASE::BaseNode::Mesh)	{
-			// If the type of this node is "Mesh" we need to search
-			// the list of output meshes in the data structure for
-			// all those that belonged to this node once. This is
-			// slightly inconvinient here and a better solution should
-			// be used when this code is refactored next.
-			AddMeshes(snode,node);
-		}
-		else if (is_not_qnan( snode->mTargetPosition.x ))	{
-			// If this is a target camera or light we generate a small
-			// child node which marks the position of the camera
-			// target (the direction information is contained in *this*
-			// node's animation track but the exact target position
-			// would be lost otherwise)
-			if (!node->mNumChildren)	{
-				node->mChildren = new aiNode*[1];
-			}
-
-			aiNode* nd = new aiNode();
-
-			nd->mName.Set ( snode->mName + ".Target" );
-
-			nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4;
-			nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4;
-			nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4;
-
-			nd->mParent = node;
-
-			// The .Target node is always the first child node
-			for (unsigned int m = 0; m < node->mNumChildren;++m)
-				node->mChildren[m+1] = node->mChildren[m];
-
-			node->mChildren[0] = nd;
-			node->mNumChildren++;
-
-			// What we did is so great, it is at least worth a debug message
-			DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")");
-		}
-	}
-
-	// Allocate enough space for the child nodes
-	// We allocate one slot more  in case this is a target camera/light
-	pcParent->mNumChildren = (unsigned int)apcNodes.size();
-	if (pcParent->mNumChildren)	{
-		pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */];
-
-		// now build all nodes for our nice new children
-		for (unsigned int p = 0; p < apcNodes.size();++p)
-			pcParent->mChildren[p] = apcNodes[p];
-	}
-	return;
+    const size_t len = szName ? ::strlen(szName) : 0;
+    ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
+
+    // Receives child nodes for the pcParent node
+    std::vector<aiNode*> apcNodes;
+
+    // Now iterate through all nodes in the scene and search for one
+    // which has *us* as parent.
+    for (std::vector<BaseNode*>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
+        const BaseNode* snode = *it;
+        if (szName) {
+            if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str()))
+                continue;
+        }
+        else if (snode->mParent.length())
+            continue;
+
+        (*it)->mProcessed = true;
+
+        // Allocate a new node and add it to the output data structure
+        apcNodes.push_back(new aiNode());
+        aiNode* node = apcNodes.back();
+
+        node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
+        node->mParent = pcParent;
+
+        // Setup the transformation matrix of the node
+        aiMatrix4x4 mParentAdjust  = mat;
+        mParentAdjust.Inverse();
+        node->mTransformation = mParentAdjust*snode->mTransform;
+
+        // Add sub nodes - prevent stack overflow due to recursive parenting
+        if (node->mName != node->mParent->mName) {
+            AddNodes(nodes,node,node->mName.data,snode->mTransform);
+        }
+
+        // Further processing depends on the type of the node
+        if (snode->mType == ASE::BaseNode::Mesh)    {
+            // If the type of this node is "Mesh" we need to search
+            // the list of output meshes in the data structure for
+            // all those that belonged to this node once. This is
+            // slightly inconvinient here and a better solution should
+            // be used when this code is refactored next.
+            AddMeshes(snode,node);
+        }
+        else if (is_not_qnan( snode->mTargetPosition.x ))   {
+            // If this is a target camera or light we generate a small
+            // child node which marks the position of the camera
+            // target (the direction information is contained in *this*
+            // node's animation track but the exact target position
+            // would be lost otherwise)
+            if (!node->mNumChildren)    {
+                node->mChildren = new aiNode*[1];
+            }
+
+            aiNode* nd = new aiNode();
+
+            nd->mName.Set ( snode->mName + ".Target" );
+
+            nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4;
+            nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4;
+            nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4;
+
+            nd->mParent = node;
+
+            // The .Target node is always the first child node
+            for (unsigned int m = 0; m < node->mNumChildren;++m)
+                node->mChildren[m+1] = node->mChildren[m];
+
+            node->mChildren[0] = nd;
+            node->mNumChildren++;
+
+            // What we did is so great, it is at least worth a debug message
+            DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")");
+        }
+    }
+
+    // Allocate enough space for the child nodes
+    // We allocate one slot more  in case this is a target camera/light
+    pcParent->mNumChildren = (unsigned int)apcNodes.size();
+    if (pcParent->mNumChildren) {
+        pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */];
+
+        // now build all nodes for our nice new children
+        for (unsigned int p = 0; p < apcNodes.size();++p)
+            pcParent->mChildren[p] = apcNodes[p];
+    }
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Build the output node graph
-void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes)	{
-	ai_assert(NULL != pcScene);
-
-	// allocate the one and only root node
-	aiNode* root = pcScene->mRootNode = new aiNode();
-	root->mName.Set("<ASERoot>");
-
-	// Setup the coordinate system transformation
-	pcScene->mRootNode->mNumChildren = 1;
-	pcScene->mRootNode->mChildren = new aiNode*[1];
-	aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode();
-	ch->mParent = root;
-
-	// Change the transformation matrix of all nodes
-	for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it)	{
-		aiMatrix4x4& m = (*it)->mTransform;
-		m.Transpose(); // row-order vs column-order
-	}
-
-	// add all nodes
-	AddNodes(nodes,ch,NULL);
-
-	// now iterate through al nodes and find those that have not yet
-	// been added to the nodegraph (= their parent could not be recognized)
-	std::vector<const BaseNode*> aiList;
-	for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it)	{
-		if ((*it)->mProcessed) {
-			continue;
-		}
-
-		// check whether our parent is known
-		bool bKnowParent = false;
-
-		// search the list another time, starting *here* and try to find out whether
-		// there is a node that references *us* as a parent
-		for (std::vector<BaseNode*>::const_iterator it2 = nodes.begin();it2 != end; ++it2) {
-			if (it2 == it) {
-				continue;
-			}
-
-			if ((*it2)->mName == (*it)->mParent)	{
-				bKnowParent = true;
-				break;
-			}
-		}
-		if (!bKnowParent)	{
-			aiList.push_back(*it);
-		}
-	}
-
-	// Are there ane orphaned nodes?
-	if (!aiList.empty())	{
-		std::vector<aiNode*> apcNodes;
-		apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren);
-
-		for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i)
-			apcNodes.push_back(pcScene->mRootNode->mChildren[i]);
-
-		delete[] pcScene->mRootNode->mChildren;
-		for (std::vector<const BaseNode*>::/*const_*/iterator i =  aiList.begin();i != aiList.end();++i)	{
-			const ASE::BaseNode* src = *i;
-
-			// The parent is not known, so we can assume that we must add
-			// this node to the root node of the whole scene
-			aiNode* pcNode = new aiNode();
-			pcNode->mParent = pcScene->mRootNode;
-			pcNode->mName.Set(src->mName);
-			AddMeshes(src,pcNode);
-			AddNodes(nodes,pcNode,pcNode->mName.data);
-			apcNodes.push_back(pcNode);
-		}
-
-		// Regenerate our output array
-		pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()];
-		for (unsigned int i = 0; i < apcNodes.size();++i)
-			pcScene->mRootNode->mChildren[i] = apcNodes[i];
-
-		pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
-	}
-
-	// Reset the third color set to NULL - we used this field to store a temporary pointer
-	for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
-		pcScene->mMeshes[i]->mColors[2] = NULL;
-
-	// The root node should not have at least one child or the file is valid
-	if (!pcScene->mRootNode->mNumChildren) {
-		throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt");
-	}
-
-	// Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
-	pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
-		0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
+void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes) {
+    ai_assert(NULL != pcScene);
+
+    // allocate the one and only root node
+    aiNode* root = pcScene->mRootNode = new aiNode();
+    root->mName.Set("<ASERoot>");
+
+    // Setup the coordinate system transformation
+    pcScene->mRootNode->mNumChildren = 1;
+    pcScene->mRootNode->mChildren = new aiNode*[1];
+    aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode();
+    ch->mParent = root;
+
+    // Change the transformation matrix of all nodes
+    for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it)    {
+        aiMatrix4x4& m = (*it)->mTransform;
+        m.Transpose(); // row-order vs column-order
+    }
+
+    // add all nodes
+    AddNodes(nodes,ch,NULL);
+
+    // now iterate through al nodes and find those that have not yet
+    // been added to the nodegraph (= their parent could not be recognized)
+    std::vector<const BaseNode*> aiList;
+    for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it)    {
+        if ((*it)->mProcessed) {
+            continue;
+        }
+
+        // check whether our parent is known
+        bool bKnowParent = false;
+
+        // search the list another time, starting *here* and try to find out whether
+        // there is a node that references *us* as a parent
+        for (std::vector<BaseNode*>::const_iterator it2 = nodes.begin();it2 != end; ++it2) {
+            if (it2 == it) {
+                continue;
+            }
+
+            if ((*it2)->mName == (*it)->mParent)    {
+                bKnowParent = true;
+                break;
+            }
+        }
+        if (!bKnowParent)   {
+            aiList.push_back(*it);
+        }
+    }
+
+    // Are there ane orphaned nodes?
+    if (!aiList.empty())    {
+        std::vector<aiNode*> apcNodes;
+        apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren);
+
+        for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i)
+            apcNodes.push_back(pcScene->mRootNode->mChildren[i]);
+
+        delete[] pcScene->mRootNode->mChildren;
+        for (std::vector<const BaseNode*>::/*const_*/iterator i =  aiList.begin();i != aiList.end();++i)    {
+            const ASE::BaseNode* src = *i;
+
+            // The parent is not known, so we can assume that we must add
+            // this node to the root node of the whole scene
+            aiNode* pcNode = new aiNode();
+            pcNode->mParent = pcScene->mRootNode;
+            pcNode->mName.Set(src->mName);
+            AddMeshes(src,pcNode);
+            AddNodes(nodes,pcNode,pcNode->mName.data);
+            apcNodes.push_back(pcNode);
+        }
+
+        // Regenerate our output array
+        pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()];
+        for (unsigned int i = 0; i < apcNodes.size();++i)
+            pcScene->mRootNode->mChildren[i] = apcNodes[i];
+
+        pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
+    }
+
+    // Reset the third color set to NULL - we used this field to store a temporary pointer
+    for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
+        pcScene->mMeshes[i]->mColors[2] = NULL;
+
+    // The root node should not have at least one child or the file is valid
+    if (!pcScene->mRootNode->mNumChildren) {
+        throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt");
+    }
+
+    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
+    pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
+        0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert the imported data to the internal verbose representation
-void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)	{
-	// allocate output storage
-	std::vector<aiVector3D> mPositions;
-	std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
-	std::vector<aiColor4D>  mVertexColors;
-	std::vector<aiVector3D> mNormals;
-	std::vector<BoneVertex> mBoneVertices;
-
-	unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3;
-	mPositions.resize(iSize);
-
-	// optional texture coordinates
-	for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)	{
-		if (!mesh.amTexCoords[i].empty())	{
-			amTexCoords[i].resize(iSize);
-		}
-	}
-	// optional vertex colors
-	if (!mesh.mVertexColors.empty())	{
-		mVertexColors.resize(iSize);
-	}
-
-	// optional vertex normals (vertex normals can simply be copied)
-	if (!mesh.mNormals.empty())	{
-		mNormals.resize(iSize);
-	}
-	// bone vertices. There is no need to change the bone list
-	if (!mesh.mBoneVertices.empty())	{
-		mBoneVertices.resize(iSize);
-	}
-
-	// iterate through all faces in the mesh
-	unsigned int iCurrent = 0, fi = 0;
-	for (std::vector<ASE::Face>::iterator i =  mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi)	{
-		for (unsigned int n = 0; n < 3;++n,++iCurrent)
-		{
-			mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
-
-			// add texture coordinates
-			for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)	{
-				if (mesh.amTexCoords[c].empty())break;
-				amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]];
-			}
-			// add vertex colors
-			if (!mesh.mVertexColors.empty())	{
-				mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]];
-			}
-			// add normal vectors
-			if (!mesh.mNormals.empty())	{
-				mNormals[iCurrent] = mesh.mNormals[fi*3+n];
-				mNormals[iCurrent].Normalize();
-			}
-
-			// handle bone vertices
-			if ((*i).mIndices[n] < mesh.mBoneVertices.size())	{
-				// (sometimes this will cause bone verts to be duplicated
-				//  however, I' quite sure Schrompf' JoinVerticesStep
-				//  will fix that again ...)
-				mBoneVertices[iCurrent] =  mesh.mBoneVertices[(*i).mIndices[n]];
-			}
-			(*i).mIndices[n] = iCurrent;
-		}
-	}
-
-	// replace the old arrays
-	mesh.mNormals = mNormals;
-	mesh.mPositions = mPositions;
-	mesh.mVertexColors = mVertexColors;
-
-	for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
-		mesh.amTexCoords[c] = amTexCoords[c];
+void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)    {
+    // allocate output storage
+    std::vector<aiVector3D> mPositions;
+    std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+    std::vector<aiColor4D>  mVertexColors;
+    std::vector<aiVector3D> mNormals;
+    std::vector<BoneVertex> mBoneVertices;
+
+    unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3;
+    mPositions.resize(iSize);
+
+    // optional texture coordinates
+    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)    {
+        if (!mesh.amTexCoords[i].empty())   {
+            amTexCoords[i].resize(iSize);
+        }
+    }
+    // optional vertex colors
+    if (!mesh.mVertexColors.empty())    {
+        mVertexColors.resize(iSize);
+    }
+
+    // optional vertex normals (vertex normals can simply be copied)
+    if (!mesh.mNormals.empty()) {
+        mNormals.resize(iSize);
+    }
+    // bone vertices. There is no need to change the bone list
+    if (!mesh.mBoneVertices.empty())    {
+        mBoneVertices.resize(iSize);
+    }
+
+    // iterate through all faces in the mesh
+    unsigned int iCurrent = 0, fi = 0;
+    for (std::vector<ASE::Face>::iterator i =  mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi) {
+        for (unsigned int n = 0; n < 3;++n,++iCurrent)
+        {
+            mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
+
+            // add texture coordinates
+            for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)    {
+                if (mesh.amTexCoords[c].empty())break;
+                amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]];
+            }
+            // add vertex colors
+            if (!mesh.mVertexColors.empty())    {
+                mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]];
+            }
+            // add normal vectors
+            if (!mesh.mNormals.empty()) {
+                mNormals[iCurrent] = mesh.mNormals[fi*3+n];
+                mNormals[iCurrent].Normalize();
+            }
+
+            // handle bone vertices
+            if ((*i).mIndices[n] < mesh.mBoneVertices.size())   {
+                // (sometimes this will cause bone verts to be duplicated
+                //  however, I' quite sure Schrompf' JoinVerticesStep
+                //  will fix that again ...)
+                mBoneVertices[iCurrent] =  mesh.mBoneVertices[(*i).mIndices[n]];
+            }
+            (*i).mIndices[n] = iCurrent;
+        }
+    }
+
+    // replace the old arrays
+    mesh.mNormals = mNormals;
+    mesh.mPositions = mPositions;
+    mesh.mVertexColors = mVertexColors;
+
+    for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
+        mesh.amTexCoords[c] = amTexCoords[c];
 }
 
 // ------------------------------------------------------------------------------------------------
 // Copy a texture from the ASE structs to the output material
 void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
 {
-	// Setup the texture name
-	aiString tex;
-	tex.Set( texture.mMapName);
-	mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
+    // Setup the texture name
+    aiString tex;
+    tex.Set( texture.mMapName);
+    mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
 
-	// Setup the texture blend factor
-	if (is_not_qnan(texture.mTextureBlend))
-		mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
+    // Setup the texture blend factor
+    if (is_not_qnan(texture.mTextureBlend))
+        mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
 
-	// Setup texture UV transformations
-	mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
+    // Setup texture UV transformations
+    mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert from ASE material to output material
 void ASEImporter::ConvertMaterial(ASE::Material& mat)
 {
-	// LARGE TODO: Much code her is copied from 3DS ... join them maybe?
-
-	// Allocate the output material
-	mat.pcInstance = new aiMaterial();
-
-	// At first add the base ambient color of the
-	// scene to	the material
-	mat.mAmbient.r += mParser->m_clrAmbient.r;
-	mat.mAmbient.g += mParser->m_clrAmbient.g;
-	mat.mAmbient.b += mParser->m_clrAmbient.b;
-
-	aiString name;
-	name.Set( mat.mName);
-	mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME);
-
-	// material colors
-	mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
-	mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
-	mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
-	mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
-
-	// shininess
-	if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength)
-	{
-		mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
-		mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
-	}
-	// If there is no shininess, we can disable phong lighting
-	else if (D3DS::Discreet3DS::Metal == mat.mShading ||
-		D3DS::Discreet3DS::Phong == mat.mShading ||
-		D3DS::Discreet3DS::Blinn == mat.mShading)
-	{
-		mat.mShading = D3DS::Discreet3DS::Gouraud;
-	}
-
-	// opacity
-	mat.pcInstance->AddProperty<float>( &mat.mTransparency,1,AI_MATKEY_OPACITY);
-
-	// Two sided rendering?
-	if (mat.mTwoSided)
-	{
-		int i = 1;
-		mat.pcInstance->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
-	}
-
-	// shading mode
-	aiShadingMode eShading = aiShadingMode_NoShading;
-	switch (mat.mShading)
-	{
-		case D3DS::Discreet3DS::Flat:
-			eShading = aiShadingMode_Flat; break;
-		case D3DS::Discreet3DS::Phong :
-			eShading = aiShadingMode_Phong; break;
-		case D3DS::Discreet3DS::Blinn :
-			eShading = aiShadingMode_Blinn; break;
-
-			// I don't know what "Wire" shading should be,
-			// assume it is simple lambertian diffuse (L dot N) shading
-		case D3DS::Discreet3DS::Wire:
-			{
-				// set the wireframe flag
-				unsigned int iWire = 1;
-				mat.pcInstance->AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
-			}
-		case D3DS::Discreet3DS::Gouraud:
-			eShading = aiShadingMode_Gouraud; break;
-		case D3DS::Discreet3DS::Metal :
-			eShading = aiShadingMode_CookTorrance; break;
-	}
-	mat.pcInstance->AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
-
-	// DIFFUSE texture
-	if( mat.sTexDiffuse.mMapName.length() > 0)
-		CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE);
-
-	// SPECULAR texture
-	if( mat.sTexSpecular.mMapName.length() > 0)
-		CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR);
-
-	// AMBIENT texture
-	if( mat.sTexAmbient.mMapName.length() > 0)
-		CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT);
-
-	// OPACITY texture
-	if( mat.sTexOpacity.mMapName.length() > 0)
-		CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY);
-
-	// EMISSIVE texture
-	if( mat.sTexEmissive.mMapName.length() > 0)
-		CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE);
-
-	// BUMP texture
-	if( mat.sTexBump.mMapName.length() > 0)
-		CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT);
-
-	// SHININESS texture
-	if( mat.sTexShininess.mMapName.length() > 0)
-		CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS);
-
-	// store the name of the material itself, too
-	if( mat.mName.length() > 0)	{
-		aiString tex;tex.Set( mat.mName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME);
-	}
-	return;
+    // LARGE TODO: Much code her is copied from 3DS ... join them maybe?
+
+    // Allocate the output material
+    mat.pcInstance = new aiMaterial();
+
+    // At first add the base ambient color of the
+    // scene to the material
+    mat.mAmbient.r += mParser->m_clrAmbient.r;
+    mat.mAmbient.g += mParser->m_clrAmbient.g;
+    mat.mAmbient.b += mParser->m_clrAmbient.b;
+
+    aiString name;
+    name.Set( mat.mName);
+    mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME);
+
+    // material colors
+    mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
+    mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
+    mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
+    mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
+
+    // shininess
+    if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength)
+    {
+        mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
+        mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
+    }
+    // If there is no shininess, we can disable phong lighting
+    else if (D3DS::Discreet3DS::Metal == mat.mShading ||
+        D3DS::Discreet3DS::Phong == mat.mShading ||
+        D3DS::Discreet3DS::Blinn == mat.mShading)
+    {
+        mat.mShading = D3DS::Discreet3DS::Gouraud;
+    }
+
+    // opacity
+    mat.pcInstance->AddProperty<float>( &mat.mTransparency,1,AI_MATKEY_OPACITY);
+
+    // Two sided rendering?
+    if (mat.mTwoSided)
+    {
+        int i = 1;
+        mat.pcInstance->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
+    }
+
+    // shading mode
+    aiShadingMode eShading = aiShadingMode_NoShading;
+    switch (mat.mShading)
+    {
+        case D3DS::Discreet3DS::Flat:
+            eShading = aiShadingMode_Flat; break;
+        case D3DS::Discreet3DS::Phong :
+            eShading = aiShadingMode_Phong; break;
+        case D3DS::Discreet3DS::Blinn :
+            eShading = aiShadingMode_Blinn; break;
+
+            // I don't know what "Wire" shading should be,
+            // assume it is simple lambertian diffuse (L dot N) shading
+        case D3DS::Discreet3DS::Wire:
+            {
+                // set the wireframe flag
+                unsigned int iWire = 1;
+                mat.pcInstance->AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
+            }
+        case D3DS::Discreet3DS::Gouraud:
+            eShading = aiShadingMode_Gouraud; break;
+        case D3DS::Discreet3DS::Metal :
+            eShading = aiShadingMode_CookTorrance; break;
+    }
+    mat.pcInstance->AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
+
+    // DIFFUSE texture
+    if( mat.sTexDiffuse.mMapName.length() > 0)
+        CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE);
+
+    // SPECULAR texture
+    if( mat.sTexSpecular.mMapName.length() > 0)
+        CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR);
+
+    // AMBIENT texture
+    if( mat.sTexAmbient.mMapName.length() > 0)
+        CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT);
+
+    // OPACITY texture
+    if( mat.sTexOpacity.mMapName.length() > 0)
+        CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY);
+
+    // EMISSIVE texture
+    if( mat.sTexEmissive.mMapName.length() > 0)
+        CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE);
+
+    // BUMP texture
+    if( mat.sTexBump.mMapName.length() > 0)
+        CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT);
+
+    // SHININESS texture
+    if( mat.sTexShininess.mMapName.length() > 0)
+        CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS);
+
+    // store the name of the material itself, too
+    if( mat.mName.length() > 0) {
+        aiString tex;tex.Set( mat.mName);
+        mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME);
+    }
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Build output meshes
 void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes)
 {
-	// validate the material index of the mesh
-	if (mesh.iMaterialIndex >= mParser->m_vMaterials.size())	{
-		mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1;
-		DefaultLogger::get()->warn("Material index is out of range");
-	}
-
-	// If the material the mesh is assigned to is consisting of submeshes, split it
-	if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty())	{
-		std::vector<ASE::Material> vSubMaterials = mParser->
-			m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
-
-		std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
-
-		// build a list of all faces per submaterial
-		for (unsigned int i = 0; i < mesh.mFaces.size();++i)	{
-			// check range
-			if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) {
-				DefaultLogger::get()->warn("Submaterial index is out of range");
-
-				// use the last material instead
-				aiSplit[vSubMaterials.size()-1].push_back(i);
-			}
-			else aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
-		}
-
-		// now generate submeshes
-		for (unsigned int p = 0; p < vSubMaterials.size();++p)	{
-			if (!aiSplit[p].empty())	{
-
-				aiMesh* p_pcOut = new aiMesh();
-				p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
-
-				// let the sub material index
-				p_pcOut->mMaterialIndex = p;
-
-				// we will need this material
-				mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true;
-
-				// store the real index here ... color channel 3
-				p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
-
-				// store a pointer to the mesh in color channel 2
-				p_pcOut->mColors[2] = (aiColor4D*) &mesh;
-				avOutMeshes.push_back(p_pcOut);
-
-				// convert vertices
-				p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3;
-				p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
-
-				// receive output vertex weights
-				std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL;
-				if (!mesh.mBones.empty())	{
-					avOutputBones = new std::vector<std::pair<unsigned int, float> >[mesh.mBones.size()];
-				}
-
-				// allocate enough storage for faces
-				p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
-
-				unsigned int iBase = 0,iIndex;
-				if (p_pcOut->mNumVertices)	{
-					p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
-					p_pcOut->mNormals  = new aiVector3D[p_pcOut->mNumVertices];
-					for (unsigned int q = 0; q < aiSplit[p].size();++q)	{
-
-						iIndex = aiSplit[p][q];
-
-						p_pcOut->mFaces[q].mIndices = new unsigned int[3];
-						p_pcOut->mFaces[q].mNumIndices = 3;
-
-						for (unsigned int t = 0; t < 3;++t, ++iBase)	{
-							const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
-
-							p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2];
-							p_pcOut->mNormals [iBase] = mesh.mNormals   [iIndex2];
-
-							// convert bones, if existing
-							if (!mesh.mBones.empty()) {
-								// check whether there is a vertex weight for this vertex index
-								if (iIndex2 < mesh.mBoneVertices.size())	{
-
-									for (std::vector<std::pair<int,float> >::const_iterator
-										blubb =  mesh.mBoneVertices[iIndex2].mBoneWeights.begin();
-										blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb)	{
-
-										// NOTE: illegal cases have already been filtered out
-										avOutputBones[(*blubb).first].push_back(std::pair<unsigned int, float>(
-											iBase,(*blubb).second));
-									}
-								}
-							}
-							p_pcOut->mFaces[q].mIndices[t] = iBase;
-						}
-					}
-				}
-				// convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
-				for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
-					if (!mesh.amTexCoords[c].empty())
-					{
-						p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
-						iBase = 0;
-						for (unsigned int q = 0; q < aiSplit[p].size();++q)	{
-							iIndex = aiSplit[p][q];
-							for (unsigned int t = 0; t < 3;++t)	{
-								p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
-							}
-						}
-						// Setup the number of valid vertex components
-						p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
-					}
-				}
-
-				// Convert vertex colors (only one set supported)
-				if (!mesh.mVertexColors.empty()){
-					p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
-					iBase = 0;
-					for (unsigned int q = 0; q < aiSplit[p].size();++q)	{
-						iIndex = aiSplit[p][q];
-						for (unsigned int t = 0; t < 3;++t)	{
-							p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]];
-						}
-					}
-				}
-				// Copy bones
-				if (!mesh.mBones.empty())	{
-					p_pcOut->mNumBones = 0;
-					for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
-						if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++;
-
-					p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ];
-					aiBone** pcBone = p_pcOut->mBones;
-					for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
-					{
-						if (!avOutputBones[mrspock].empty())	{
-							// we will need this bone. add it to the output mesh and
-							// add all per-vertex weights
-							aiBone* pc = *pcBone = new aiBone();
-							pc->mName.Set(mesh.mBones[mrspock].mName);
-
-							pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
-							pc->mWeights = new aiVertexWeight[pc->mNumWeights];
-
-							for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk)
-							{
-								const std::pair<unsigned int,float>& ref = avOutputBones[mrspock][captainkirk];
-								pc->mWeights[captainkirk].mVertexId = ref.first;
-								pc->mWeights[captainkirk].mWeight = ref.second;
-							}
-							++pcBone;
-						}
-					}
-					// delete allocated storage
-					delete[] avOutputBones;
-				}
-			}
-		}
-		// delete storage
-		delete[] aiSplit;
-	}
-	else
-	{
-		// Otherwise we can simply copy the data to one output mesh
-		// This codepath needs less memory and uses fast memcpy()s
-		// to do the actual copying. So I think it is worth the
-		// effort here.
-
-		aiMesh* p_pcOut = new aiMesh();
-		p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
-
-		// set an empty sub material index
-		p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX;
-		mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true;
-
-		// store the real index here ... in color channel 3
-		p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
-
-		// store a pointer to the mesh in color channel 2
-		p_pcOut->mColors[2] = (aiColor4D*) &mesh;
-		avOutMeshes.push_back(p_pcOut);
-
-		// If the mesh hasn't faces or vertices, there are two cases
-		// possible: 1. the model is invalid. 2. This is a dummy
-		// helper object which we are going to remove later ...
-		if (mesh.mFaces.empty() || mesh.mPositions.empty())	{
-			return;
-		}
-
-		// convert vertices
-		p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size();
-		p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size();
-
-		// allocate enough storage for faces
-		p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
-
-		// copy vertices
-		p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()];
-		memcpy(p_pcOut->mVertices,&mesh.mPositions[0],
-			mesh.mPositions.size() * sizeof(aiVector3D));
-
-		// copy normals
-		p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()];
-		memcpy(p_pcOut->mNormals,&mesh.mNormals[0],
-			mesh.mNormals.size() * sizeof(aiVector3D));
-
-		// copy texture coordinates
-		for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)	{
-			if (!mesh.amTexCoords[c].empty())	{
-				p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()];
-				memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0],
-					mesh.amTexCoords[c].size() * sizeof(aiVector3D));
-
-				// setup the number of valid vertex components
-				p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
-			}
-		}
-
-		// copy vertex colors
-		if (!mesh.mVertexColors.empty())	{
-			p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()];
-			memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0],
-				mesh.mVertexColors.size() * sizeof(aiColor4D));
-		}
-
-		// copy faces
-		for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace)	{
-			p_pcOut->mFaces[iFace].mNumIndices = 3;
-			p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
-
-			// copy indices
-			p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0];
-			p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1];
-			p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2];
-		}
-
-		// copy vertex bones
-		if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty())	{
-			std::vector<std::vector<aiVertexWeight> > avBonesOut( mesh.mBones.size() );
-
-			// find all vertex weights for this bone
-			unsigned int quak = 0;
-			for (std::vector<BoneVertex>::const_iterator harrypotter =  mesh.mBoneVertices.begin();
-				harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak)	{
-
-				for (std::vector<std::pair<int,float> >::const_iterator
-					ronaldweasley  = (*harrypotter).mBoneWeights.begin();
-					ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley)
-				{
-					aiVertexWeight weight;
-					weight.mVertexId = quak;
-					weight.mWeight = (*ronaldweasley).second;
-					avBonesOut[(*ronaldweasley).first].push_back(weight);
-				}
-			}
-
-			// now build a final bone list
-			p_pcOut->mNumBones = 0;
-			for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy)
-				if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++;
-
-			p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones];
-			aiBone** pcBone = p_pcOut->mBones;
-			for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy)	{
-				if (!avBonesOut[jfkennedy].empty())	{
-					aiBone* pc = *pcBone = new aiBone();
-					pc->mName.Set(mesh.mBones[jfkennedy].mName);
-					pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size();
-					pc->mWeights = new aiVertexWeight[pc->mNumWeights];
-					::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0],
-						sizeof(aiVertexWeight) * pc->mNumWeights);
-					++pcBone;
-				}
-			}
-		}
-	}
+    // validate the material index of the mesh
+    if (mesh.iMaterialIndex >= mParser->m_vMaterials.size())    {
+        mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1;
+        DefaultLogger::get()->warn("Material index is out of range");
+    }
+
+    // If the material the mesh is assigned to is consisting of submeshes, split it
+    if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) {
+        std::vector<ASE::Material> vSubMaterials = mParser->
+            m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
+
+        std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
+
+        // build a list of all faces per submaterial
+        for (unsigned int i = 0; i < mesh.mFaces.size();++i)    {
+            // check range
+            if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) {
+                DefaultLogger::get()->warn("Submaterial index is out of range");
+
+                // use the last material instead
+                aiSplit[vSubMaterials.size()-1].push_back(i);
+            }
+            else aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
+        }
+
+        // now generate submeshes
+        for (unsigned int p = 0; p < vSubMaterials.size();++p)  {
+            if (!aiSplit[p].empty())    {
+
+                aiMesh* p_pcOut = new aiMesh();
+                p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+                // let the sub material index
+                p_pcOut->mMaterialIndex = p;
+
+                // we will need this material
+                mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true;
+
+                // store the real index here ... color channel 3
+                p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
+
+                // store a pointer to the mesh in color channel 2
+                p_pcOut->mColors[2] = (aiColor4D*) &mesh;
+                avOutMeshes.push_back(p_pcOut);
+
+                // convert vertices
+                p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3;
+                p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
+
+                // receive output vertex weights
+                std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL;
+                if (!mesh.mBones.empty())   {
+                    avOutputBones = new std::vector<std::pair<unsigned int, float> >[mesh.mBones.size()];
+                }
+
+                // allocate enough storage for faces
+                p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
+
+                unsigned int iBase = 0,iIndex;
+                if (p_pcOut->mNumVertices)  {
+                    p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
+                    p_pcOut->mNormals  = new aiVector3D[p_pcOut->mNumVertices];
+                    for (unsigned int q = 0; q < aiSplit[p].size();++q) {
+
+                        iIndex = aiSplit[p][q];
+
+                        p_pcOut->mFaces[q].mIndices = new unsigned int[3];
+                        p_pcOut->mFaces[q].mNumIndices = 3;
+
+                        for (unsigned int t = 0; t < 3;++t, ++iBase)    {
+                            const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
+
+                            p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2];
+                            p_pcOut->mNormals [iBase] = mesh.mNormals   [iIndex2];
+
+                            // convert bones, if existing
+                            if (!mesh.mBones.empty()) {
+                                // check whether there is a vertex weight for this vertex index
+                                if (iIndex2 < mesh.mBoneVertices.size())    {
+
+                                    for (std::vector<std::pair<int,float> >::const_iterator
+                                        blubb =  mesh.mBoneVertices[iIndex2].mBoneWeights.begin();
+                                        blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb)    {
+
+                                        // NOTE: illegal cases have already been filtered out
+                                        avOutputBones[(*blubb).first].push_back(std::pair<unsigned int, float>(
+                                            iBase,(*blubb).second));
+                                    }
+                                }
+                            }
+                            p_pcOut->mFaces[q].mIndices[t] = iBase;
+                        }
+                    }
+                }
+                // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
+                for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
+                    if (!mesh.amTexCoords[c].empty())
+                    {
+                        p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
+                        iBase = 0;
+                        for (unsigned int q = 0; q < aiSplit[p].size();++q) {
+                            iIndex = aiSplit[p][q];
+                            for (unsigned int t = 0; t < 3;++t) {
+                                p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
+                            }
+                        }
+                        // Setup the number of valid vertex components
+                        p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
+                    }
+                }
+
+                // Convert vertex colors (only one set supported)
+                if (!mesh.mVertexColors.empty()){
+                    p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
+                    iBase = 0;
+                    for (unsigned int q = 0; q < aiSplit[p].size();++q) {
+                        iIndex = aiSplit[p][q];
+                        for (unsigned int t = 0; t < 3;++t) {
+                            p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]];
+                        }
+                    }
+                }
+                // Copy bones
+                if (!mesh.mBones.empty())   {
+                    p_pcOut->mNumBones = 0;
+                    for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
+                        if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++;
+
+                    p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ];
+                    aiBone** pcBone = p_pcOut->mBones;
+                    for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
+                    {
+                        if (!avOutputBones[mrspock].empty())    {
+                            // we will need this bone. add it to the output mesh and
+                            // add all per-vertex weights
+                            aiBone* pc = *pcBone = new aiBone();
+                            pc->mName.Set(mesh.mBones[mrspock].mName);
+
+                            pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
+                            pc->mWeights = new aiVertexWeight[pc->mNumWeights];
+
+                            for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk)
+                            {
+                                const std::pair<unsigned int,float>& ref = avOutputBones[mrspock][captainkirk];
+                                pc->mWeights[captainkirk].mVertexId = ref.first;
+                                pc->mWeights[captainkirk].mWeight = ref.second;
+                            }
+                            ++pcBone;
+                        }
+                    }
+                    // delete allocated storage
+                    delete[] avOutputBones;
+                }
+            }
+        }
+        // delete storage
+        delete[] aiSplit;
+    }
+    else
+    {
+        // Otherwise we can simply copy the data to one output mesh
+        // This codepath needs less memory and uses fast memcpy()s
+        // to do the actual copying. So I think it is worth the
+        // effort here.
+
+        aiMesh* p_pcOut = new aiMesh();
+        p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+        // set an empty sub material index
+        p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX;
+        mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true;
+
+        // store the real index here ... in color channel 3
+        p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
+
+        // store a pointer to the mesh in color channel 2
+        p_pcOut->mColors[2] = (aiColor4D*) &mesh;
+        avOutMeshes.push_back(p_pcOut);
+
+        // If the mesh hasn't faces or vertices, there are two cases
+        // possible: 1. the model is invalid. 2. This is a dummy
+        // helper object which we are going to remove later ...
+        if (mesh.mFaces.empty() || mesh.mPositions.empty()) {
+            return;
+        }
+
+        // convert vertices
+        p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size();
+        p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size();
+
+        // allocate enough storage for faces
+        p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
+
+        // copy vertices
+        p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()];
+        memcpy(p_pcOut->mVertices,&mesh.mPositions[0],
+            mesh.mPositions.size() * sizeof(aiVector3D));
+
+        // copy normals
+        p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()];
+        memcpy(p_pcOut->mNormals,&mesh.mNormals[0],
+            mesh.mNormals.size() * sizeof(aiVector3D));
+
+        // copy texture coordinates
+        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)    {
+            if (!mesh.amTexCoords[c].empty())   {
+                p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()];
+                memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0],
+                    mesh.amTexCoords[c].size() * sizeof(aiVector3D));
+
+                // setup the number of valid vertex components
+                p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
+            }
+        }
+
+        // copy vertex colors
+        if (!mesh.mVertexColors.empty())    {
+            p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()];
+            memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0],
+                mesh.mVertexColors.size() * sizeof(aiColor4D));
+        }
+
+        // copy faces
+        for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace)    {
+            p_pcOut->mFaces[iFace].mNumIndices = 3;
+            p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
+
+            // copy indices
+            p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0];
+            p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1];
+            p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2];
+        }
+
+        // copy vertex bones
+        if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty())    {
+            std::vector<std::vector<aiVertexWeight> > avBonesOut( mesh.mBones.size() );
+
+            // find all vertex weights for this bone
+            unsigned int quak = 0;
+            for (std::vector<BoneVertex>::const_iterator harrypotter =  mesh.mBoneVertices.begin();
+                harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak)   {
+
+                for (std::vector<std::pair<int,float> >::const_iterator
+                    ronaldweasley  = (*harrypotter).mBoneWeights.begin();
+                    ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley)
+                {
+                    aiVertexWeight weight;
+                    weight.mVertexId = quak;
+                    weight.mWeight = (*ronaldweasley).second;
+                    avBonesOut[(*ronaldweasley).first].push_back(weight);
+                }
+            }
+
+            // now build a final bone list
+            p_pcOut->mNumBones = 0;
+            for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy)
+                if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++;
+
+            p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones];
+            aiBone** pcBone = p_pcOut->mBones;
+            for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy)    {
+                if (!avBonesOut[jfkennedy].empty()) {
+                    aiBone* pc = *pcBone = new aiBone();
+                    pc->mName.Set(mesh.mBones[jfkennedy].mName);
+                    pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size();
+                    pc->mWeights = new aiVertexWeight[pc->mNumWeights];
+                    ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0],
+                        sizeof(aiVertexWeight) * pc->mNumWeights);
+                    ++pcBone;
+                }
+            }
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup proper material indices and build output materials
 void ASEImporter::BuildMaterialIndices()
 {
-	ai_assert(NULL != pcScene);
-
-	// iterate through all materials and check whether we need them
-	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
-	{
-		ASE::Material& mat = mParser->m_vMaterials[iMat];
-		if (mat.bNeed)	{
-			// Convert it to the aiMaterial layout
-			ConvertMaterial(mat);
-			++pcScene->mNumMaterials;
-		}
-		for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
-		{
-			ASE::Material& submat = mat.avSubMaterials[iSubMat];
-			if (submat.bNeed)	{
-				// Convert it to the aiMaterial layout
-				ConvertMaterial(submat);
-				++pcScene->mNumMaterials;
-			}
-		}
-	}
-
-	// allocate the output material array
-	pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials];
-	D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials];
-
-	unsigned int iNum = 0;
-	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) {
-		ASE::Material& mat = mParser->m_vMaterials[iMat];
-		if (mat.bNeed)
-		{
-			ai_assert(NULL != mat.pcInstance);
-			pcScene->mMaterials[iNum] = mat.pcInstance;
-
-			// Store the internal material, too
-			pcIntMaterials[iNum] = &mat;
-
-			// Iterate through all meshes and search for one which is using
-			// this top-level material index
-			for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
-			{
-				aiMesh* mesh = pcScene->mMeshes[iMesh];
-				if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
-					iMat == (uintptr_t)mesh->mColors[3])
-				{
-					mesh->mMaterialIndex = iNum;
-					mesh->mColors[3] = NULL;
-				}
-			}
-			iNum++;
-		}
-		for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)	{
-			ASE::Material& submat = mat.avSubMaterials[iSubMat];
-			if (submat.bNeed)	{
-				ai_assert(NULL != submat.pcInstance);
-				pcScene->mMaterials[iNum] = submat.pcInstance;
-
-				// Store the internal material, too
-				pcIntMaterials[iNum] = &submat;
-
-				// Iterate through all meshes and search for one which is using
-				// this sub-level material index
-				for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)	{
-					aiMesh* mesh = pcScene->mMeshes[iMesh];
-
-					if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3])	{
-						mesh->mMaterialIndex = iNum;
-						mesh->mColors[3]     = NULL;
-					}
-				}
-				iNum++;
-			}
-		}
-	}
-
-	// Dekete our temporary array
-	delete[] pcIntMaterials;
+    ai_assert(NULL != pcScene);
+
+    // iterate through all materials and check whether we need them
+    for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
+    {
+        ASE::Material& mat = mParser->m_vMaterials[iMat];
+        if (mat.bNeed)  {
+            // Convert it to the aiMaterial layout
+            ConvertMaterial(mat);
+            ++pcScene->mNumMaterials;
+        }
+        for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
+        {
+            ASE::Material& submat = mat.avSubMaterials[iSubMat];
+            if (submat.bNeed)   {
+                // Convert it to the aiMaterial layout
+                ConvertMaterial(submat);
+                ++pcScene->mNumMaterials;
+            }
+        }
+    }
+
+    // allocate the output material array
+    pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials];
+    D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials];
+
+    unsigned int iNum = 0;
+    for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) {
+        ASE::Material& mat = mParser->m_vMaterials[iMat];
+        if (mat.bNeed)
+        {
+            ai_assert(NULL != mat.pcInstance);
+            pcScene->mMaterials[iNum] = mat.pcInstance;
+
+            // Store the internal material, too
+            pcIntMaterials[iNum] = &mat;
+
+            // Iterate through all meshes and search for one which is using
+            // this top-level material index
+            for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
+            {
+                aiMesh* mesh = pcScene->mMeshes[iMesh];
+                if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
+                    iMat == (uintptr_t)mesh->mColors[3])
+                {
+                    mesh->mMaterialIndex = iNum;
+                    mesh->mColors[3] = NULL;
+                }
+            }
+            iNum++;
+        }
+        for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)   {
+            ASE::Material& submat = mat.avSubMaterials[iSubMat];
+            if (submat.bNeed)   {
+                ai_assert(NULL != submat.pcInstance);
+                pcScene->mMaterials[iNum] = submat.pcInstance;
+
+                // Store the internal material, too
+                pcIntMaterials[iNum] = &submat;
+
+                // Iterate through all meshes and search for one which is using
+                // this sub-level material index
+                for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)   {
+                    aiMesh* mesh = pcScene->mMeshes[iMesh];
+
+                    if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3]) {
+                        mesh->mMaterialIndex = iNum;
+                        mesh->mColors[3]     = NULL;
+                    }
+                }
+                iNum++;
+            }
+        }
+    }
+
+    // Dekete our temporary array
+    delete[] pcIntMaterials;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Generate normal vectors basing on smoothing groups
-bool ASEImporter::GenerateNormals(ASE::Mesh& mesh)	{
-
-	if (!mesh.mNormals.empty() && !configRecomputeNormals)
-	{
-		// Check whether there are only uninitialized normals. If there are
-		// some, skip all normals from the file and compute them on our own
-		for (std::vector<aiVector3D>::const_iterator qq =  mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) {
-			if ((*qq).x || (*qq).y || (*qq).z)
-			{
-				return true;
-			}
-		}
-	}
-	// The array is reused.
-	ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
-	return false;
+bool ASEImporter::GenerateNormals(ASE::Mesh& mesh)  {
+
+    if (!mesh.mNormals.empty() && !configRecomputeNormals)
+    {
+        // Check whether there are only uninitialized normals. If there are
+        // some, skip all normals from the file and compute them on our own
+        for (std::vector<aiVector3D>::const_iterator qq =  mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) {
+            if ((*qq).x || (*qq).y || (*qq).z)
+            {
+                return true;
+            }
+        }
+    }
+    // The array is reused.
+    ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
+    return false;
 }
 
 #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER

+ 98 - 98
code/ASELoader.h

@@ -57,147 +57,147 @@ namespace Assimp {
 /** Importer class for the 3DS ASE ASCII format.
  *
  */
-class ASEImporter : public BaseImporter	{
+class ASEImporter : public BaseImporter {
 public:
-	ASEImporter();
-	~ASEImporter();
+    ASEImporter();
+    ~ASEImporter();
 
 
 public:
 
-	// -------------------------------------------------------------------
-	/** Returns whether the class can handle the format of the given file.
-	 * See BaseImporter::CanRead() for details.
-	 */
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-		bool checkSig) const;
+    // -------------------------------------------------------------------
+    /** Returns whether the class can handle the format of the given file.
+     * See BaseImporter::CanRead() for details.
+     */
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Return importer meta information.
-	 * See #BaseImporter::GetInfo for the details
-	 */
-	const aiImporterDesc* GetInfo () const;
+    // -------------------------------------------------------------------
+    /** Return importer meta information.
+     * See #BaseImporter::GetInfo for the details
+     */
+    const aiImporterDesc* GetInfo () const;
 
 
-	// -------------------------------------------------------------------
-	/** Imports the given file into the given scene structure.
-	* See BaseImporter::InternReadFile() for details
-	*/
-	void InternReadFile( const std::string& pFile, aiScene* pScene,
-		IOSystem* pIOHandler);
+    // -------------------------------------------------------------------
+    /** Imports the given file into the given scene structure.
+    * See BaseImporter::InternReadFile() for details
+    */
+    void InternReadFile( const std::string& pFile, aiScene* pScene,
+        IOSystem* pIOHandler);
 
 
-	// -------------------------------------------------------------------
-	/** Called prior to ReadFile().
-	* The function is a request to the importer to update its configuration
-	* basing on the Importer's configuration property list.
-	*/
-	void SetupProperties(const Importer* pImp);
+    // -------------------------------------------------------------------
+    /** Called prior to ReadFile().
+    * The function is a request to the importer to update its configuration
+    * basing on the Importer's configuration property list.
+    */
+    void SetupProperties(const Importer* pImp);
 
 
 private:
 
-	// -------------------------------------------------------------------
-	/** Generate normal vectors basing on smoothing groups
-	 * (in some cases the normal are already contained in the file)
-	 * \param mesh Mesh to work on
-	 * \return false if the normals have been recomputed
-	 */
-	bool GenerateNormals(ASE::Mesh& mesh);
+    // -------------------------------------------------------------------
+    /** Generate normal vectors basing on smoothing groups
+     * (in some cases the normal are already contained in the file)
+     * \param mesh Mesh to work on
+     * \return false if the normals have been recomputed
+     */
+    bool GenerateNormals(ASE::Mesh& mesh);
 
 
-	// -------------------------------------------------------------------
-	/** Create valid vertex/normal/UV/color/face lists.
-	 *  All elements are unique, faces have only one set of indices
-	 *  after this step occurs.
-	 * \param mesh Mesh to work on
-	 */
-	void BuildUniqueRepresentation(ASE::Mesh& mesh);
+    // -------------------------------------------------------------------
+    /** Create valid vertex/normal/UV/color/face lists.
+     *  All elements are unique, faces have only one set of indices
+     *  after this step occurs.
+     * \param mesh Mesh to work on
+     */
+    void BuildUniqueRepresentation(ASE::Mesh& mesh);
 
 
-	/** Create one-material-per-mesh meshes ;-)
-	 * \param mesh Mesh to work with
-	 *  \param Receives the list of all created meshes
-	 */
-	void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut);
+    /** Create one-material-per-mesh meshes ;-)
+     * \param mesh Mesh to work with
+     *  \param Receives the list of all created meshes
+     */
+    void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut);
 
 
-	// -------------------------------------------------------------------
-	/** Convert a material to a aiMaterial object
-	 * \param mat Input material
-	 */
-	void ConvertMaterial(ASE::Material& mat);
+    // -------------------------------------------------------------------
+    /** Convert a material to a aiMaterial object
+     * \param mat Input material
+     */
+    void ConvertMaterial(ASE::Material& mat);
 
 
-	// -------------------------------------------------------------------
-	/** Setup the final material indices for each mesh
-	 */
-	void BuildMaterialIndices();
+    // -------------------------------------------------------------------
+    /** Setup the final material indices for each mesh
+     */
+    void BuildMaterialIndices();
 
 
-	// -------------------------------------------------------------------
-	/** Build the node graph
-	 */
-	void BuildNodes(std::vector<ASE::BaseNode*>& nodes);
+    // -------------------------------------------------------------------
+    /** Build the node graph
+     */
+    void BuildNodes(std::vector<ASE::BaseNode*>& nodes);
 
 
-	// -------------------------------------------------------------------
-	/** Build output cameras
-	 */
-	void BuildCameras();
+    // -------------------------------------------------------------------
+    /** Build output cameras
+     */
+    void BuildCameras();
 
 
-	// -------------------------------------------------------------------
-	/** Build output lights
-	 */
-	void BuildLights();
+    // -------------------------------------------------------------------
+    /** Build output lights
+     */
+    void BuildLights();
 
 
-	// -------------------------------------------------------------------
-	/** Build output animations
-	 */
-	void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes);
+    // -------------------------------------------------------------------
+    /** Build output animations
+     */
+    void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes);
 
 
-	// -------------------------------------------------------------------
-	/** Add sub nodes to a node
-	 *  \param pcParent parent node to be filled
-	 *  \param szName Name of the parent node
-	 *  \param matrix Current transform
-	 */
-	void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
-		aiNode* pcParent,const char* szName);
+    // -------------------------------------------------------------------
+    /** Add sub nodes to a node
+     *  \param pcParent parent node to be filled
+     *  \param szName Name of the parent node
+     *  \param matrix Current transform
+     */
+    void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
+        aiNode* pcParent,const char* szName);
 
-	void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
-		aiNode* pcParent,const char* szName,
-		const aiMatrix4x4& matrix);
+    void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
+        aiNode* pcParent,const char* szName,
+        const aiMatrix4x4& matrix);
 
-	void AddMeshes(const ASE::BaseNode* snode,aiNode* node);
+    void AddMeshes(const ASE::BaseNode* snode,aiNode* node);
 
-	// -------------------------------------------------------------------
-	/** Generate a default material and add it to the parser's list
-	 *  Called if no material has been found in the file (rare for ASE,
-	 *  but not impossible)
-	 */
-	void GenerateDefaultMaterial();
+    // -------------------------------------------------------------------
+    /** Generate a default material and add it to the parser's list
+     *  Called if no material has been found in the file (rare for ASE,
+     *  but not impossible)
+     */
+    void GenerateDefaultMaterial();
 
 protected:
 
-	/** Parser instance */
-	ASE::Parser* mParser;
+    /** Parser instance */
+    ASE::Parser* mParser;
 
-	/** Buffer to hold the loaded file */
-	char* mBuffer;
+    /** Buffer to hold the loaded file */
+    char* mBuffer;
 
-	/** Scene to be filled */
-	aiScene* pcScene;
+    /** Scene to be filled */
+    aiScene* pcScene;
 
-	/** Config options: Recompute the normals in every case - WA
-	    for 3DS Max broken ASE normal export */
-	bool configRecomputeNormals;
-	bool noSkeletonMesh;
+    /** Config options: Recompute the normals in every case - WA
+        for 3DS Max broken ASE normal export */
+    bool configRecomputeNormals;
+    bool noSkeletonMesh;
 };
 
 } // end of namespace Assimp

+ 1879 - 1879
code/ASEParser.cpp

@@ -61,32 +61,32 @@ using namespace Assimp::ASE;
 // Begin an ASE parsing function
 
 #define AI_ASE_PARSER_INIT() \
-	int iDepth = 0;
+    int iDepth = 0;
 
 // ------------------------------------------------------------------------------------------------
 // Handle a "top-level" section in the file. EOF is no error in this case.
 
 #define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \
-	else if ('{' == *filePtr)iDepth++; \
-	else if ('}' == *filePtr) \
-	{ \
-		if (0 == --iDepth) \
-		{ \
-			++filePtr; \
-			SkipToNextToken(); \
-			return; \
-		} \
-	} \
-	else if ('\0' == *filePtr) \
-	{ \
-		return; \
-	} \
-	if(IsLineEnd(*filePtr) && !bLastWasEndLine) \
-	{ \
-		++iLineNumber; \
-		bLastWasEndLine = true; \
-	} else bLastWasEndLine = false; \
-	++filePtr;
+    else if ('{' == *filePtr)iDepth++; \
+    else if ('}' == *filePtr) \
+    { \
+        if (0 == --iDepth) \
+        { \
+            ++filePtr; \
+            SkipToNextToken(); \
+            return; \
+        } \
+    } \
+    else if ('\0' == *filePtr) \
+    { \
+        return; \
+    } \
+    if(IsLineEnd(*filePtr) && !bLastWasEndLine) \
+    { \
+        ++iLineNumber; \
+        bLastWasEndLine = true; \
+    } else bLastWasEndLine = false; \
+    ++filePtr;
 
 // ------------------------------------------------------------------------------------------------
 // Handle a nested section in the file. EOF is an error in this case
@@ -94,2061 +94,2061 @@ using namespace Assimp::ASE;
 // @param msg Full name of the section (including the asterisk)
 
 #define AI_ASE_HANDLE_SECTION(level, msg) \
-	if ('{' == *filePtr)iDepth++; \
-	else if ('}' == *filePtr) \
-	{ \
-		if (0 == --iDepth) \
-		{ \
-			++filePtr; \
-			SkipToNextToken(); \
-			return; \
-		} \
-	} \
-	else if ('\0' == *filePtr) \
-	{ \
-		LogError("Encountered unexpected EOL while parsing a " msg \
-		" chunk (Level " level ")"); \
-	} \
-	if(IsLineEnd(*filePtr) && !bLastWasEndLine) \
-		{ \
-		++iLineNumber; \
-		bLastWasEndLine = true; \
-	} else bLastWasEndLine = false; \
-	++filePtr;
+    if ('{' == *filePtr)iDepth++; \
+    else if ('}' == *filePtr) \
+    { \
+        if (0 == --iDepth) \
+        { \
+            ++filePtr; \
+            SkipToNextToken(); \
+            return; \
+        } \
+    } \
+    else if ('\0' == *filePtr) \
+    { \
+        LogError("Encountered unexpected EOL while parsing a " msg \
+        " chunk (Level " level ")"); \
+    } \
+    if(IsLineEnd(*filePtr) && !bLastWasEndLine) \
+        { \
+        ++iLineNumber; \
+        bLastWasEndLine = true; \
+    } else bLastWasEndLine = false; \
+    ++filePtr;
 
 // ------------------------------------------------------------------------------------------------
 Parser::Parser (const char* szFile, unsigned int fileFormatDefault)
 {
-	ai_assert(NULL != szFile);
-	filePtr = szFile;
-	iFileFormat = fileFormatDefault;
-
-	// make sure that the color values are invalid
-	m_clrBackground.r = get_qnan();
-	m_clrAmbient.r    = get_qnan();
-
-	// setup some default values
-	iLineNumber = 0;
-	iFirstFrame = 0;
-	iLastFrame = 0;
-	iFrameSpeed = 30;        // use 30 as default value for this property
-	iTicksPerFrame = 1;      // use 1 as default value for this property
-	bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping
+    ai_assert(NULL != szFile);
+    filePtr = szFile;
+    iFileFormat = fileFormatDefault;
+
+    // make sure that the color values are invalid
+    m_clrBackground.r = get_qnan();
+    m_clrAmbient.r    = get_qnan();
+
+    // setup some default values
+    iLineNumber = 0;
+    iFirstFrame = 0;
+    iLastFrame = 0;
+    iFrameSpeed = 30;        // use 30 as default value for this property
+    iTicksPerFrame = 1;      // use 1 as default value for this property
+    bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::LogWarning(const char* szWarn)
 {
-	ai_assert(NULL != szWarn);
+    ai_assert(NULL != szWarn);
 
-	char szTemp[1024];
+    char szTemp[1024];
 #if _MSC_VER >= 1400
-	sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn);
+    sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn);
 #else
-	snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn);
+    snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn);
 #endif
 
-	// output the warning to the logger ...
-	DefaultLogger::get()->warn(szTemp);
+    // output the warning to the logger ...
+    DefaultLogger::get()->warn(szTemp);
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::LogInfo(const char* szWarn)
 {
-	ai_assert(NULL != szWarn);
+    ai_assert(NULL != szWarn);
 
-	char szTemp[1024];
+    char szTemp[1024];
 #if _MSC_VER >= 1400
-	sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn);
+    sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn);
 #else
-	snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn);
+    snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn);
 #endif
 
-	// output the information to the logger ...
-	DefaultLogger::get()->info(szTemp);
+    // output the information to the logger ...
+    DefaultLogger::get()->info(szTemp);
 }
 
 // ------------------------------------------------------------------------------------------------
 AI_WONT_RETURN void Parser::LogError(const char* szWarn)
 {
-	ai_assert(NULL != szWarn);
+    ai_assert(NULL != szWarn);
 
-	char szTemp[1024];
+    char szTemp[1024];
 #if _MSC_VER >= 1400
-	sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn);
+    sprintf_s(szTemp,"Line %u: %s",iLineNumber,szWarn);
 #else
-	snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn);
+    snprintf(szTemp,1024,"Line %u: %s",iLineNumber,szWarn);
 #endif
 
-	// throw an exception
-	throw DeadlyImportError(szTemp);
+    // throw an exception
+    throw DeadlyImportError(szTemp);
 }
 
 // ------------------------------------------------------------------------------------------------
 bool Parser::SkipToNextToken()
 {
-	while (true)
-	{
-		char me = *filePtr;
-
-		// increase the line number counter if necessary
-		if (IsLineEnd(me) && !bLastWasEndLine)
-		{
-			++iLineNumber;
-			bLastWasEndLine = true;
-		}
-		else bLastWasEndLine = false;
-		if ('*' == me || '}' == me || '{' == me)return true;
-		if ('\0' == me)return false;
-
-		++filePtr;
-	}
+    while (true)
+    {
+        char me = *filePtr;
+
+        // increase the line number counter if necessary
+        if (IsLineEnd(me) && !bLastWasEndLine)
+        {
+            ++iLineNumber;
+            bLastWasEndLine = true;
+        }
+        else bLastWasEndLine = false;
+        if ('*' == me || '}' == me || '{' == me)return true;
+        if ('\0' == me)return false;
+
+        ++filePtr;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 bool Parser::SkipSection()
 {
-	// must handle subsections ...
-	int iCnt = 0;
-	while (true)
-	{
-		if ('}' == *filePtr)
-		{
-			--iCnt;
-			if (0 == iCnt)
-			{
-				// go to the next valid token ...
-				++filePtr;
-				SkipToNextToken();
-				return true;
-			}
-		}
-		else if ('{' == *filePtr)
-		{
-			++iCnt;
-		}
-		else if ('\0' == *filePtr)
-		{
-			LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]");
-			return false;
-		}
-		else if(IsLineEnd(*filePtr))++iLineNumber;
-		++filePtr;
-	}
+    // must handle subsections ...
+    int iCnt = 0;
+    while (true)
+    {
+        if ('}' == *filePtr)
+        {
+            --iCnt;
+            if (0 == iCnt)
+            {
+                // go to the next valid token ...
+                ++filePtr;
+                SkipToNextToken();
+                return true;
+            }
+        }
+        else if ('{' == *filePtr)
+        {
+            ++iCnt;
+        }
+        else if ('\0' == *filePtr)
+        {
+            LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]");
+            return false;
+        }
+        else if(IsLineEnd(*filePtr))++iLineNumber;
+        ++filePtr;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::Parse()
 {
-	AI_ASE_PARSER_INIT();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Version should be 200. Validate this ...
-			if (TokenMatch(filePtr,"3DSMAX_ASCIIEXPORT",18))
-			{
-				unsigned int fmt;
-				ParseLV4MeshLong(fmt);
-
-				if (fmt > 200)
-				{
-					LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \
-							   be <= 200");
-				}
-				// *************************************************************
-				// - fmt will be 0 if we're unable to read the version number
-				// there are some faulty files without a version number ...
-				// in this case we'll guess the exact file format by looking
-				// at the file extension (ASE, ASK, ASC)
-				// *************************************************************
-
-				if (fmt)iFileFormat = fmt;
-				continue;
-			}
-			// main scene information
-			if (TokenMatch(filePtr,"SCENE",5))
-			{
-				ParseLV1SceneBlock();
-				continue;
-			}
-			// "group" - no implementation yet, in facte
-			// we're just ignoring them for the moment
-			if (TokenMatch(filePtr,"GROUP",5))
-			{
-				Parse();
-				continue;
-			}
-			// material list
-			if (TokenMatch(filePtr,"MATERIAL_LIST",13))
-			{
-				ParseLV1MaterialListBlock();
-				continue;
-			}
-			// geometric object (mesh)
-			if (TokenMatch(filePtr,"GEOMOBJECT",10))
-
-			{
-				m_vMeshes.push_back(Mesh());
-				ParseLV1ObjectBlock(m_vMeshes.back());
-				continue;
-			}
-			// helper object = dummy in the hierarchy
-			if (TokenMatch(filePtr,"HELPEROBJECT",12))
-
-			{
-				m_vDummies.push_back(Dummy());
-				ParseLV1ObjectBlock(m_vDummies.back());
-				continue;
-			}
-			// light object
-			if (TokenMatch(filePtr,"LIGHTOBJECT",11))
-
-			{
-				m_vLights.push_back(Light());
-				ParseLV1ObjectBlock(m_vLights.back());
-				continue;
-			}
-			// camera object
-			if (TokenMatch(filePtr,"CAMERAOBJECT",12))
-			{
-				m_vCameras.push_back(Camera());
-				ParseLV1ObjectBlock(m_vCameras.back());
-				continue;
-			}
-			// comment - print it on the console
-			if (TokenMatch(filePtr,"COMMENT",7))
-			{
-				std::string out = "<unknown>";
-				ParseString(out,"*COMMENT");
-				LogInfo(("Comment: " + out).c_str());
-				continue;
-			}
-			// ASC bone weights
-			if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr,"MESH_SOFTSKINVERTS",18))
-			{
-				ParseLV1SoftSkinBlock();
-			}
-		}
-		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Version should be 200. Validate this ...
+            if (TokenMatch(filePtr,"3DSMAX_ASCIIEXPORT",18))
+            {
+                unsigned int fmt;
+                ParseLV4MeshLong(fmt);
+
+                if (fmt > 200)
+                {
+                    LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \
+                               be <= 200");
+                }
+                // *************************************************************
+                // - fmt will be 0 if we're unable to read the version number
+                // there are some faulty files without a version number ...
+                // in this case we'll guess the exact file format by looking
+                // at the file extension (ASE, ASK, ASC)
+                // *************************************************************
+
+                if (fmt)iFileFormat = fmt;
+                continue;
+            }
+            // main scene information
+            if (TokenMatch(filePtr,"SCENE",5))
+            {
+                ParseLV1SceneBlock();
+                continue;
+            }
+            // "group" - no implementation yet, in facte
+            // we're just ignoring them for the moment
+            if (TokenMatch(filePtr,"GROUP",5))
+            {
+                Parse();
+                continue;
+            }
+            // material list
+            if (TokenMatch(filePtr,"MATERIAL_LIST",13))
+            {
+                ParseLV1MaterialListBlock();
+                continue;
+            }
+            // geometric object (mesh)
+            if (TokenMatch(filePtr,"GEOMOBJECT",10))
+
+            {
+                m_vMeshes.push_back(Mesh());
+                ParseLV1ObjectBlock(m_vMeshes.back());
+                continue;
+            }
+            // helper object = dummy in the hierarchy
+            if (TokenMatch(filePtr,"HELPEROBJECT",12))
+
+            {
+                m_vDummies.push_back(Dummy());
+                ParseLV1ObjectBlock(m_vDummies.back());
+                continue;
+            }
+            // light object
+            if (TokenMatch(filePtr,"LIGHTOBJECT",11))
+
+            {
+                m_vLights.push_back(Light());
+                ParseLV1ObjectBlock(m_vLights.back());
+                continue;
+            }
+            // camera object
+            if (TokenMatch(filePtr,"CAMERAOBJECT",12))
+            {
+                m_vCameras.push_back(Camera());
+                ParseLV1ObjectBlock(m_vCameras.back());
+                continue;
+            }
+            // comment - print it on the console
+            if (TokenMatch(filePtr,"COMMENT",7))
+            {
+                std::string out = "<unknown>";
+                ParseString(out,"*COMMENT");
+                LogInfo(("Comment: " + out).c_str());
+                continue;
+            }
+            // ASC bone weights
+            if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr,"MESH_SOFTSKINVERTS",18))
+            {
+                ParseLV1SoftSkinBlock();
+            }
+        }
+        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
+    }
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV1SoftSkinBlock()
 {
-	// TODO: fix line counting here
-
-	// **************************************************************
-	// The soft skin block is formatted differently. There are no
-	// nested sections supported and the single elements aren't
-	// marked by keywords starting with an asterisk.
-
-	/**
-	FORMAT BEGIN
-
-	*MESH_SOFTSKINVERTS {
-	<nodename>
-	<number of vertices>
-
-	[for <number of vertices> times:]
-		<number of weights>	[for <number of weights> times:] <bone name> <weight>
-	}
-
-	FORMAT END
-	*/
-	// **************************************************************
-	while (true)
-	{
-		if (*filePtr == '}'      )	{++filePtr;return;}
-		else if (*filePtr == '\0')	return;
-		else if (*filePtr == '{' )	++filePtr;
-
-		else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr))
-		{
-			ASE::Mesh* curMesh		= NULL;
-			unsigned int numVerts	= 0;
-
-			const char* sz = filePtr;
-			while (!IsSpaceOrNewLine(*filePtr))++filePtr;
-
-			const unsigned int diff = (unsigned int)(filePtr-sz);
-			if (diff)
-			{
-				std::string name = std::string(sz,diff);
-				for (std::vector<ASE::Mesh>::iterator it = m_vMeshes.begin();
-					it != m_vMeshes.end(); ++it)
-				{
-					if ((*it).mName == name)
-					{
-						curMesh = & (*it);
-						break;
-					}
-				}
-				if (!curMesh)
-				{
-					LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section");
-
-					// Skip the mesh data - until we find a new mesh
-					// or the end of the *MESH_SOFTSKINVERTS section
-					while (true)
-					{
-						SkipSpacesAndLineEnd(&filePtr);
-						if (*filePtr == '}')
-							{++filePtr;return;}
-						else if (!IsNumeric(*filePtr))
-							break;
-
-						SkipLine(&filePtr);
-					}
-				}
-				else
-				{
-					SkipSpacesAndLineEnd(&filePtr);
-					ParseLV4MeshLong(numVerts);
-
-					// Reserve enough storage
-					curMesh->mBoneVertices.reserve(numVerts);
-
-					for (unsigned int i = 0; i < numVerts;++i)
-					{
-						SkipSpacesAndLineEnd(&filePtr);
-						unsigned int numWeights;
-						ParseLV4MeshLong(numWeights);
-
-						curMesh->mBoneVertices.push_back(ASE::BoneVertex());
-						ASE::BoneVertex& vert = curMesh->mBoneVertices.back();
-
-						// Reserve enough storage
-						vert.mBoneWeights.reserve(numWeights);
-
-						for (unsigned int w = 0; w < numWeights;++w)
-						{
-							std::string bone;
-							ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
-
-							// Find the bone in the mesh's list
-							std::pair<int,float> me;
-							me.first = -1;
-
-							for (unsigned int n = 0; n < curMesh->mBones.size();++n)
-							{
-								if (curMesh->mBones[n].mName == bone)
-								{
-									me.first = n;
-									break;
-								}
-							}
-							if (-1 == me.first)
-							{
-								// We don't have this bone yet, so add it to the list
-								me.first = (int)curMesh->mBones.size();
-								curMesh->mBones.push_back(ASE::Bone(bone));
-							}
-							ParseLV4MeshFloat( me.second );
-
-							// Add the new bone weight to list
-							vert.mBoneWeights.push_back(me);
-						}
-					}
-				}
-			}
-		}
-		++filePtr;
-		SkipSpacesAndLineEnd(&filePtr);
-	}
+    // TODO: fix line counting here
+
+    // **************************************************************
+    // The soft skin block is formatted differently. There are no
+    // nested sections supported and the single elements aren't
+    // marked by keywords starting with an asterisk.
+
+    /**
+    FORMAT BEGIN
+
+    *MESH_SOFTSKINVERTS {
+    <nodename>
+    <number of vertices>
+
+    [for <number of vertices> times:]
+        <number of weights> [for <number of weights> times:] <bone name> <weight>
+    }
+
+    FORMAT END
+    */
+    // **************************************************************
+    while (true)
+    {
+        if (*filePtr == '}'      )  {++filePtr;return;}
+        else if (*filePtr == '\0')  return;
+        else if (*filePtr == '{' )  ++filePtr;
+
+        else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr))
+        {
+            ASE::Mesh* curMesh      = NULL;
+            unsigned int numVerts   = 0;
+
+            const char* sz = filePtr;
+            while (!IsSpaceOrNewLine(*filePtr))++filePtr;
+
+            const unsigned int diff = (unsigned int)(filePtr-sz);
+            if (diff)
+            {
+                std::string name = std::string(sz,diff);
+                for (std::vector<ASE::Mesh>::iterator it = m_vMeshes.begin();
+                    it != m_vMeshes.end(); ++it)
+                {
+                    if ((*it).mName == name)
+                    {
+                        curMesh = & (*it);
+                        break;
+                    }
+                }
+                if (!curMesh)
+                {
+                    LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section");
+
+                    // Skip the mesh data - until we find a new mesh
+                    // or the end of the *MESH_SOFTSKINVERTS section
+                    while (true)
+                    {
+                        SkipSpacesAndLineEnd(&filePtr);
+                        if (*filePtr == '}')
+                            {++filePtr;return;}
+                        else if (!IsNumeric(*filePtr))
+                            break;
+
+                        SkipLine(&filePtr);
+                    }
+                }
+                else
+                {
+                    SkipSpacesAndLineEnd(&filePtr);
+                    ParseLV4MeshLong(numVerts);
+
+                    // Reserve enough storage
+                    curMesh->mBoneVertices.reserve(numVerts);
+
+                    for (unsigned int i = 0; i < numVerts;++i)
+                    {
+                        SkipSpacesAndLineEnd(&filePtr);
+                        unsigned int numWeights;
+                        ParseLV4MeshLong(numWeights);
+
+                        curMesh->mBoneVertices.push_back(ASE::BoneVertex());
+                        ASE::BoneVertex& vert = curMesh->mBoneVertices.back();
+
+                        // Reserve enough storage
+                        vert.mBoneWeights.reserve(numWeights);
+
+                        for (unsigned int w = 0; w < numWeights;++w)
+                        {
+                            std::string bone;
+                            ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
+
+                            // Find the bone in the mesh's list
+                            std::pair<int,float> me;
+                            me.first = -1;
+
+                            for (unsigned int n = 0; n < curMesh->mBones.size();++n)
+                            {
+                                if (curMesh->mBones[n].mName == bone)
+                                {
+                                    me.first = n;
+                                    break;
+                                }
+                            }
+                            if (-1 == me.first)
+                            {
+                                // We don't have this bone yet, so add it to the list
+                                me.first = (int)curMesh->mBones.size();
+                                curMesh->mBones.push_back(ASE::Bone(bone));
+                            }
+                            ParseLV4MeshFloat( me.second );
+
+                            // Add the new bone weight to list
+                            vert.mBoneWeights.push_back(me);
+                        }
+                    }
+                }
+            }
+        }
+        ++filePtr;
+        SkipSpacesAndLineEnd(&filePtr);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV1SceneBlock()
 {
-	AI_ASE_PARSER_INIT();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			if (TokenMatch(filePtr,"SCENE_BACKGROUND_STATIC",23))
-
-			{
-				// parse a color triple and assume it is really the bg color
-				ParseLV4MeshFloatTriple( &m_clrBackground.r );
-				continue;
-			}
-			if (TokenMatch(filePtr,"SCENE_AMBIENT_STATIC",20))
-
-			{
-				// parse a color triple and assume it is really the bg color
-				ParseLV4MeshFloatTriple( &m_clrAmbient.r );
-				continue;
-			}
-			if (TokenMatch(filePtr,"SCENE_FIRSTFRAME",16))
-			{
-				ParseLV4MeshLong(iFirstFrame);
-				continue;
-			}
-			if (TokenMatch(filePtr,"SCENE_LASTFRAME",15))
-			{
-				ParseLV4MeshLong(iLastFrame);
-				continue;
-			}
-			if (TokenMatch(filePtr,"SCENE_FRAMESPEED",16))
-			{
-				ParseLV4MeshLong(iFrameSpeed);
-				continue;
-			}
-			if (TokenMatch(filePtr,"SCENE_TICKSPERFRAME",19))
-			{
-				ParseLV4MeshLong(iTicksPerFrame);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
-	}
+    AI_ASE_PARSER_INIT();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            if (TokenMatch(filePtr,"SCENE_BACKGROUND_STATIC",23))
+
+            {
+                // parse a color triple and assume it is really the bg color
+                ParseLV4MeshFloatTriple( &m_clrBackground.r );
+                continue;
+            }
+            if (TokenMatch(filePtr,"SCENE_AMBIENT_STATIC",20))
+
+            {
+                // parse a color triple and assume it is really the bg color
+                ParseLV4MeshFloatTriple( &m_clrAmbient.r );
+                continue;
+            }
+            if (TokenMatch(filePtr,"SCENE_FIRSTFRAME",16))
+            {
+                ParseLV4MeshLong(iFirstFrame);
+                continue;
+            }
+            if (TokenMatch(filePtr,"SCENE_LASTFRAME",15))
+            {
+                ParseLV4MeshLong(iLastFrame);
+                continue;
+            }
+            if (TokenMatch(filePtr,"SCENE_FRAMESPEED",16))
+            {
+                ParseLV4MeshLong(iFrameSpeed);
+                continue;
+            }
+            if (TokenMatch(filePtr,"SCENE_TICKSPERFRAME",19))
+            {
+                ParseLV4MeshLong(iTicksPerFrame);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV1MaterialListBlock()
 {
-	AI_ASE_PARSER_INIT();
-
-	unsigned int iMaterialCount = 0;
-	unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			if (TokenMatch(filePtr,"MATERIAL_COUNT",14))
-			{
-				ParseLV4MeshLong(iMaterialCount);
-
-				// now allocate enough storage to hold all materials
-				m_vMaterials.resize(iOldMaterialCount+iMaterialCount);
-				continue;
-			}
-			if (TokenMatch(filePtr,"MATERIAL",8))
-			{
-				unsigned int iIndex = 0;
-				ParseLV4MeshLong(iIndex);
-
-				if (iIndex >= iMaterialCount)
-				{
-					LogWarning("Out of range: material index is too large");
-					iIndex = iMaterialCount-1;
-				}
-
-				// get a reference to the material
-				Material& sMat = m_vMaterials[iIndex+iOldMaterialCount];
-				// parse the material block
-				ParseLV2MaterialBlock(sMat);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
-	}
+    AI_ASE_PARSER_INIT();
+
+    unsigned int iMaterialCount = 0;
+    unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            if (TokenMatch(filePtr,"MATERIAL_COUNT",14))
+            {
+                ParseLV4MeshLong(iMaterialCount);
+
+                // now allocate enough storage to hold all materials
+                m_vMaterials.resize(iOldMaterialCount+iMaterialCount);
+                continue;
+            }
+            if (TokenMatch(filePtr,"MATERIAL",8))
+            {
+                unsigned int iIndex = 0;
+                ParseLV4MeshLong(iIndex);
+
+                if (iIndex >= iMaterialCount)
+                {
+                    LogWarning("Out of range: material index is too large");
+                    iIndex = iMaterialCount-1;
+                }
+
+                // get a reference to the material
+                Material& sMat = m_vMaterials[iIndex+iOldMaterialCount];
+                // parse the material block
+                ParseLV2MaterialBlock(sMat);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV2MaterialBlock(ASE::Material& mat)
 {
-	AI_ASE_PARSER_INIT();
-
-	unsigned int iNumSubMaterials = 0;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			if (TokenMatch(filePtr,"MATERIAL_NAME",13))
-			{
-				if (!ParseString(mat.mName,"*MATERIAL_NAME"))
-					SkipToNextToken();
-				continue;
-			}
-			// ambient material color
-			if (TokenMatch(filePtr,"MATERIAL_AMBIENT",16))
-			{
-				ParseLV4MeshFloatTriple(&mat.mAmbient.r);
-				continue;
-			}
-			// diffuse material color
-			if (TokenMatch(filePtr,"MATERIAL_DIFFUSE",16) )
-			{
-				ParseLV4MeshFloatTriple(&mat.mDiffuse.r);
-				continue;
-			}
-			// specular material color
-			if (TokenMatch(filePtr,"MATERIAL_SPECULAR",17))
-			{
-				ParseLV4MeshFloatTriple(&mat.mSpecular.r);
-				continue;
-			}
-			// material shading type
-			if (TokenMatch(filePtr,"MATERIAL_SHADING",16))
-			{
-				if (TokenMatch(filePtr,"Blinn",5))
-				{
-					mat.mShading = Discreet3DS::Blinn;
-				}
-				else if (TokenMatch(filePtr,"Phong",5))
-				{
-					mat.mShading = Discreet3DS::Phong;
-				}
-				else if (TokenMatch(filePtr,"Flat",4))
-				{
-					mat.mShading = Discreet3DS::Flat;
-				}
-				else if (TokenMatch(filePtr,"Wire",4))
-				{
-					mat.mShading = Discreet3DS::Wire;
-				}
-				else
-				{
-					// assume gouraud shading
-					mat.mShading = Discreet3DS::Gouraud;
-					SkipToNextToken();
-				}
-				continue;
-			}
-			// material transparency
-			if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21))
-			{
-				ParseLV4MeshFloat(mat.mTransparency);
-				mat.mTransparency = 1.0f - mat.mTransparency;continue;
-			}
-			// material self illumination
-			if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18))
-			{
-				float f = 0.0f;
-				ParseLV4MeshFloat(f);
-
-				mat.mEmissive.r = f;
-				mat.mEmissive.g = f;
-				mat.mEmissive.b = f;
-				continue;
-			}
-			// material shininess
-			if (TokenMatch(filePtr,"MATERIAL_SHINE",14) )
-			{
-				ParseLV4MeshFloat(mat.mSpecularExponent);
-				mat.mSpecularExponent *= 15;
-				continue;
-			}
-			// two-sided material
-			if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) )
-			{
-				mat.mTwoSided = true;
-				continue;
-			}
-			// material shininess strength
-			if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22))
-			{
-				ParseLV4MeshFloat(mat.mShininessStrength);
-				continue;
-			}
-			// diffuse color map
-			if (TokenMatch(filePtr,"MAP_DIFFUSE",11))
-			{
-				// parse the texture block
-				ParseLV3MapBlock(mat.sTexDiffuse);
-				continue;
-			}
-			// ambient color map
-			if (TokenMatch(filePtr,"MAP_AMBIENT",11))
-			{
-				// parse the texture block
-				ParseLV3MapBlock(mat.sTexAmbient);
-				continue;
-			}
-			// specular color map
-			if (TokenMatch(filePtr,"MAP_SPECULAR",12))
-			{
-				// parse the texture block
-				ParseLV3MapBlock(mat.sTexSpecular);
-				continue;
-			}
-			// opacity map
-			if (TokenMatch(filePtr,"MAP_OPACITY",11))
-			{
-				// parse the texture block
-				ParseLV3MapBlock(mat.sTexOpacity);
-				continue;
-			}
-			// emissive map
-			if (TokenMatch(filePtr,"MAP_SELFILLUM",13))
-			{
-				// parse the texture block
-				ParseLV3MapBlock(mat.sTexEmissive);
-				continue;
-			}
-			// bump map
-			if (TokenMatch(filePtr,"MAP_BUMP",8))
-			{
-				// parse the texture block
-				ParseLV3MapBlock(mat.sTexBump);
-			}
-			// specular/shininess map
-			if (TokenMatch(filePtr,"MAP_SHINESTRENGTH",17))
-			{
-				// parse the texture block
-				ParseLV3MapBlock(mat.sTexShininess);
-				continue;
-			}
-			// number of submaterials
-			if (TokenMatch(filePtr,"NUMSUBMTLS",10))
-			{
-				ParseLV4MeshLong(iNumSubMaterials);
-
-				// allocate enough storage
-				mat.avSubMaterials.resize(iNumSubMaterials);
-			}
-			// submaterial chunks
-			if (TokenMatch(filePtr,"SUBMATERIAL",11))
-			{
-
-				unsigned int iIndex = 0;
-				ParseLV4MeshLong(iIndex);
-
-				if (iIndex >= iNumSubMaterials)
-				{
-					LogWarning("Out of range: submaterial index is too large");
-					iIndex = iNumSubMaterials-1;
-				}
-
-				// get a reference to the material
-				Material& sMat = mat.avSubMaterials[iIndex];
-
-				// parse the material block
-				ParseLV2MaterialBlock(sMat);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("2","*MATERIAL");
-	}
+    AI_ASE_PARSER_INIT();
+
+    unsigned int iNumSubMaterials = 0;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            if (TokenMatch(filePtr,"MATERIAL_NAME",13))
+            {
+                if (!ParseString(mat.mName,"*MATERIAL_NAME"))
+                    SkipToNextToken();
+                continue;
+            }
+            // ambient material color
+            if (TokenMatch(filePtr,"MATERIAL_AMBIENT",16))
+            {
+                ParseLV4MeshFloatTriple(&mat.mAmbient.r);
+                continue;
+            }
+            // diffuse material color
+            if (TokenMatch(filePtr,"MATERIAL_DIFFUSE",16) )
+            {
+                ParseLV4MeshFloatTriple(&mat.mDiffuse.r);
+                continue;
+            }
+            // specular material color
+            if (TokenMatch(filePtr,"MATERIAL_SPECULAR",17))
+            {
+                ParseLV4MeshFloatTriple(&mat.mSpecular.r);
+                continue;
+            }
+            // material shading type
+            if (TokenMatch(filePtr,"MATERIAL_SHADING",16))
+            {
+                if (TokenMatch(filePtr,"Blinn",5))
+                {
+                    mat.mShading = Discreet3DS::Blinn;
+                }
+                else if (TokenMatch(filePtr,"Phong",5))
+                {
+                    mat.mShading = Discreet3DS::Phong;
+                }
+                else if (TokenMatch(filePtr,"Flat",4))
+                {
+                    mat.mShading = Discreet3DS::Flat;
+                }
+                else if (TokenMatch(filePtr,"Wire",4))
+                {
+                    mat.mShading = Discreet3DS::Wire;
+                }
+                else
+                {
+                    // assume gouraud shading
+                    mat.mShading = Discreet3DS::Gouraud;
+                    SkipToNextToken();
+                }
+                continue;
+            }
+            // material transparency
+            if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21))
+            {
+                ParseLV4MeshFloat(mat.mTransparency);
+                mat.mTransparency = 1.0f - mat.mTransparency;continue;
+            }
+            // material self illumination
+            if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18))
+            {
+                float f = 0.0f;
+                ParseLV4MeshFloat(f);
+
+                mat.mEmissive.r = f;
+                mat.mEmissive.g = f;
+                mat.mEmissive.b = f;
+                continue;
+            }
+            // material shininess
+            if (TokenMatch(filePtr,"MATERIAL_SHINE",14) )
+            {
+                ParseLV4MeshFloat(mat.mSpecularExponent);
+                mat.mSpecularExponent *= 15;
+                continue;
+            }
+            // two-sided material
+            if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) )
+            {
+                mat.mTwoSided = true;
+                continue;
+            }
+            // material shininess strength
+            if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22))
+            {
+                ParseLV4MeshFloat(mat.mShininessStrength);
+                continue;
+            }
+            // diffuse color map
+            if (TokenMatch(filePtr,"MAP_DIFFUSE",11))
+            {
+                // parse the texture block
+                ParseLV3MapBlock(mat.sTexDiffuse);
+                continue;
+            }
+            // ambient color map
+            if (TokenMatch(filePtr,"MAP_AMBIENT",11))
+            {
+                // parse the texture block
+                ParseLV3MapBlock(mat.sTexAmbient);
+                continue;
+            }
+            // specular color map
+            if (TokenMatch(filePtr,"MAP_SPECULAR",12))
+            {
+                // parse the texture block
+                ParseLV3MapBlock(mat.sTexSpecular);
+                continue;
+            }
+            // opacity map
+            if (TokenMatch(filePtr,"MAP_OPACITY",11))
+            {
+                // parse the texture block
+                ParseLV3MapBlock(mat.sTexOpacity);
+                continue;
+            }
+            // emissive map
+            if (TokenMatch(filePtr,"MAP_SELFILLUM",13))
+            {
+                // parse the texture block
+                ParseLV3MapBlock(mat.sTexEmissive);
+                continue;
+            }
+            // bump map
+            if (TokenMatch(filePtr,"MAP_BUMP",8))
+            {
+                // parse the texture block
+                ParseLV3MapBlock(mat.sTexBump);
+            }
+            // specular/shininess map
+            if (TokenMatch(filePtr,"MAP_SHINESTRENGTH",17))
+            {
+                // parse the texture block
+                ParseLV3MapBlock(mat.sTexShininess);
+                continue;
+            }
+            // number of submaterials
+            if (TokenMatch(filePtr,"NUMSUBMTLS",10))
+            {
+                ParseLV4MeshLong(iNumSubMaterials);
+
+                // allocate enough storage
+                mat.avSubMaterials.resize(iNumSubMaterials);
+            }
+            // submaterial chunks
+            if (TokenMatch(filePtr,"SUBMATERIAL",11))
+            {
+
+                unsigned int iIndex = 0;
+                ParseLV4MeshLong(iIndex);
+
+                if (iIndex >= iNumSubMaterials)
+                {
+                    LogWarning("Out of range: submaterial index is too large");
+                    iIndex = iNumSubMaterials-1;
+                }
+
+                // get a reference to the material
+                Material& sMat = mat.avSubMaterials[iIndex];
+
+                // parse the material block
+                ParseLV2MaterialBlock(sMat);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("2","*MATERIAL");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MapBlock(Texture& map)
 {
-	AI_ASE_PARSER_INIT();
-
-	// ***********************************************************
-	// *BITMAP should not be there if *MAP_CLASS is not BITMAP,
-	// but we need to expect that case ... if the path is
-	// empty the texture won't be used later.
-	// ***********************************************************
-	bool parsePath = true;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			// type of map
-			if (TokenMatch(filePtr,"MAP_CLASS" ,9))
-			{
-				std::string temp;
-				if(!ParseString(temp,"*MAP_CLASS"))
-					SkipToNextToken();
-				if (temp != "Bitmap" && temp != "Normal Bump")
-				{
-					DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp);
-					parsePath = false;
-				}
-				continue;
-			}
-			// path to the texture
-			if (parsePath && TokenMatch(filePtr,"BITMAP" ,6))
-			{
-				if(!ParseString(map.mMapName,"*BITMAP"))
-					SkipToNextToken();
-
-				if (map.mMapName == "None")
-				{
-					// Files with 'None' as map name are produced by
-					// an Maja to ASE exporter which name I forgot ..
-					DefaultLogger::get()->warn("ASE: Skipping invalid map entry");
-					map.mMapName = "";
-				}
-
-				continue;
-			}
-			// offset on the u axis
-			if (TokenMatch(filePtr,"UVW_U_OFFSET" ,12))
-			{
-				ParseLV4MeshFloat(map.mOffsetU);
-				continue;
-			}
-			// offset on the v axis
-			if (TokenMatch(filePtr,"UVW_V_OFFSET" ,12))
-			{
-				ParseLV4MeshFloat(map.mOffsetV);
-				continue;
-			}
-			// tiling on the u axis
-			if (TokenMatch(filePtr,"UVW_U_TILING" ,12))
-			{
-				ParseLV4MeshFloat(map.mScaleU);
-				continue;
-			}
-			// tiling on the v axis
-			if (TokenMatch(filePtr,"UVW_V_TILING" ,12))
-			{
-				ParseLV4MeshFloat(map.mScaleV);
-				continue;
-			}
-			// rotation around the z-axis
-			if (TokenMatch(filePtr,"UVW_ANGLE" ,9))
-			{
-				ParseLV4MeshFloat(map.mRotation);
-				continue;
-			}
-			// map blending factor
-			if (TokenMatch(filePtr,"MAP_AMOUNT" ,10))
-			{
-				ParseLV4MeshFloat(map.mTextureBlend);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MAP_XXXXXX");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    // ***********************************************************
+    // *BITMAP should not be there if *MAP_CLASS is not BITMAP,
+    // but we need to expect that case ... if the path is
+    // empty the texture won't be used later.
+    // ***********************************************************
+    bool parsePath = true;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            // type of map
+            if (TokenMatch(filePtr,"MAP_CLASS" ,9))
+            {
+                std::string temp;
+                if(!ParseString(temp,"*MAP_CLASS"))
+                    SkipToNextToken();
+                if (temp != "Bitmap" && temp != "Normal Bump")
+                {
+                    DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp);
+                    parsePath = false;
+                }
+                continue;
+            }
+            // path to the texture
+            if (parsePath && TokenMatch(filePtr,"BITMAP" ,6))
+            {
+                if(!ParseString(map.mMapName,"*BITMAP"))
+                    SkipToNextToken();
+
+                if (map.mMapName == "None")
+                {
+                    // Files with 'None' as map name are produced by
+                    // an Maja to ASE exporter which name I forgot ..
+                    DefaultLogger::get()->warn("ASE: Skipping invalid map entry");
+                    map.mMapName = "";
+                }
+
+                continue;
+            }
+            // offset on the u axis
+            if (TokenMatch(filePtr,"UVW_U_OFFSET" ,12))
+            {
+                ParseLV4MeshFloat(map.mOffsetU);
+                continue;
+            }
+            // offset on the v axis
+            if (TokenMatch(filePtr,"UVW_V_OFFSET" ,12))
+            {
+                ParseLV4MeshFloat(map.mOffsetV);
+                continue;
+            }
+            // tiling on the u axis
+            if (TokenMatch(filePtr,"UVW_U_TILING" ,12))
+            {
+                ParseLV4MeshFloat(map.mScaleU);
+                continue;
+            }
+            // tiling on the v axis
+            if (TokenMatch(filePtr,"UVW_V_TILING" ,12))
+            {
+                ParseLV4MeshFloat(map.mScaleV);
+                continue;
+            }
+            // rotation around the z-axis
+            if (TokenMatch(filePtr,"UVW_ANGLE" ,9))
+            {
+                ParseLV4MeshFloat(map.mRotation);
+                continue;
+            }
+            // map blending factor
+            if (TokenMatch(filePtr,"MAP_AMOUNT" ,10))
+            {
+                ParseLV4MeshFloat(map.mTextureBlend);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MAP_XXXXXX");
+    }
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 bool Parser::ParseString(std::string& out,const char* szName)
 {
-	char szBuffer[1024];
-	if (!SkipSpaces(&filePtr))
-	{
-
-		sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName);
-		LogWarning(szBuffer);
-		return false;
-	}
-	// there must be '"'
-	if ('\"' != *filePtr)
-	{
-
-		sprintf(szBuffer,"Unable to parse %s block: Strings are expected "
-			"to be enclosed in double quotation marks",szName);
-		LogWarning(szBuffer);
-		return false;
-	}
-	++filePtr;
-	const char* sz = filePtr;
-	while (true)
-	{
-		if ('\"' == *sz)break;
-		else if ('\0' == *sz)
-		{
-			sprintf(szBuffer,"Unable to parse %s block: Strings are expected to "
-				"be enclosed in double quotation marks but EOF was reached before "
-				"a closing quotation mark was encountered",szName);
-			LogWarning(szBuffer);
-			return false;
-		}
-		sz++;
-	}
-	out = std::string(filePtr,(uintptr_t)sz-(uintptr_t)filePtr);
-	filePtr = sz+1;
-	return true;
+    char szBuffer[1024];
+    if (!SkipSpaces(&filePtr))
+    {
+
+        sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName);
+        LogWarning(szBuffer);
+        return false;
+    }
+    // there must be '"'
+    if ('\"' != *filePtr)
+    {
+
+        sprintf(szBuffer,"Unable to parse %s block: Strings are expected "
+            "to be enclosed in double quotation marks",szName);
+        LogWarning(szBuffer);
+        return false;
+    }
+    ++filePtr;
+    const char* sz = filePtr;
+    while (true)
+    {
+        if ('\"' == *sz)break;
+        else if ('\0' == *sz)
+        {
+            sprintf(szBuffer,"Unable to parse %s block: Strings are expected to "
+                "be enclosed in double quotation marks but EOF was reached before "
+                "a closing quotation mark was encountered",szName);
+            LogWarning(szBuffer);
+            return false;
+        }
+        sz++;
+    }
+    out = std::string(filePtr,(uintptr_t)sz-(uintptr_t)filePtr);
+    filePtr = sz+1;
+    return true;
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV1ObjectBlock(ASE::BaseNode& node)
 {
-	AI_ASE_PARSER_INIT();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// first process common tokens such as node name and transform
-			// name of the mesh/node
-			if (TokenMatch(filePtr,"NODE_NAME" ,9))
-			{
-				if(!ParseString(node.mName,"*NODE_NAME"))
-					SkipToNextToken();
-				continue;
-			}
-			// name of the parent of the node
-			if (TokenMatch(filePtr,"NODE_PARENT" ,11) )
-			{
-				if(!ParseString(node.mParent,"*NODE_PARENT"))
-					SkipToNextToken();
-				continue;
-			}
-			// transformation matrix of the node
-			if (TokenMatch(filePtr,"NODE_TM" ,7))
-			{
-				ParseLV2NodeTransformBlock(node);
-				continue;
-			}
-			// animation data of the node
-			if (TokenMatch(filePtr,"TM_ANIMATION" ,12))
-			{
-				ParseLV2AnimationBlock(node);
-				continue;
-			}
-
-			if (node.mType == BaseNode::Light)
-			{
-				// light settings
-				if (TokenMatch(filePtr,"LIGHT_SETTINGS" ,14))
-				{
-					ParseLV2LightSettingsBlock((ASE::Light&)node);
-					continue;
-				}
-				// type of the light source
-				if (TokenMatch(filePtr,"LIGHT_TYPE" ,10))
-				{
-					if (!ASSIMP_strincmp("omni",filePtr,4))
-					{
-						((ASE::Light&)node).mLightType = ASE::Light::OMNI;
-					}
-					else if (!ASSIMP_strincmp("target",filePtr,6))
-					{
-						((ASE::Light&)node).mLightType = ASE::Light::TARGET;
-					}
-					else if (!ASSIMP_strincmp("free",filePtr,4))
-					{
-						((ASE::Light&)node).mLightType = ASE::Light::FREE;
-					}
-					else if (!ASSIMP_strincmp("directional",filePtr,11))
-					{
-						((ASE::Light&)node).mLightType = ASE::Light::DIRECTIONAL;
-					}
-					else
-					{
-						LogWarning("Unknown kind of light source");
-					}
-					continue;
-				}
-			}
-			else if (node.mType == BaseNode::Camera)
-			{
-				// Camera settings
-				if (TokenMatch(filePtr,"CAMERA_SETTINGS" ,15))
-				{
-					ParseLV2CameraSettingsBlock((ASE::Camera&)node);
-					continue;
-				}
-				else if (TokenMatch(filePtr,"CAMERA_TYPE" ,11))
-				{
-					if (!ASSIMP_strincmp("target",filePtr,6))
-					{
-						((ASE::Camera&)node).mCameraType = ASE::Camera::TARGET;
-					}
-					else if (!ASSIMP_strincmp("free",filePtr,4))
-					{
-						((ASE::Camera&)node).mCameraType = ASE::Camera::FREE;
-					}
-					else
-					{
-						LogWarning("Unknown kind of camera");
-					}
-					continue;
-				}
-			}
-			else if (node.mType == BaseNode::Mesh)
-			{
-				// mesh data
-				// FIX: Older files use MESH_SOFTSKIN
-				if (TokenMatch(filePtr,"MESH" ,4) ||
-					TokenMatch(filePtr,"MESH_SOFTSKIN",13))
-				{
-					ParseLV2MeshBlock((ASE::Mesh&)node);
-					continue;
-				}
-				// mesh material index
-				if (TokenMatch(filePtr,"MATERIAL_REF" ,12))
-				{
-					ParseLV4MeshLong(((ASE::Mesh&)node).iMaterialIndex);
-					continue;
-				}
-			}
-		}
-		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // first process common tokens such as node name and transform
+            // name of the mesh/node
+            if (TokenMatch(filePtr,"NODE_NAME" ,9))
+            {
+                if(!ParseString(node.mName,"*NODE_NAME"))
+                    SkipToNextToken();
+                continue;
+            }
+            // name of the parent of the node
+            if (TokenMatch(filePtr,"NODE_PARENT" ,11) )
+            {
+                if(!ParseString(node.mParent,"*NODE_PARENT"))
+                    SkipToNextToken();
+                continue;
+            }
+            // transformation matrix of the node
+            if (TokenMatch(filePtr,"NODE_TM" ,7))
+            {
+                ParseLV2NodeTransformBlock(node);
+                continue;
+            }
+            // animation data of the node
+            if (TokenMatch(filePtr,"TM_ANIMATION" ,12))
+            {
+                ParseLV2AnimationBlock(node);
+                continue;
+            }
+
+            if (node.mType == BaseNode::Light)
+            {
+                // light settings
+                if (TokenMatch(filePtr,"LIGHT_SETTINGS" ,14))
+                {
+                    ParseLV2LightSettingsBlock((ASE::Light&)node);
+                    continue;
+                }
+                // type of the light source
+                if (TokenMatch(filePtr,"LIGHT_TYPE" ,10))
+                {
+                    if (!ASSIMP_strincmp("omni",filePtr,4))
+                    {
+                        ((ASE::Light&)node).mLightType = ASE::Light::OMNI;
+                    }
+                    else if (!ASSIMP_strincmp("target",filePtr,6))
+                    {
+                        ((ASE::Light&)node).mLightType = ASE::Light::TARGET;
+                    }
+                    else if (!ASSIMP_strincmp("free",filePtr,4))
+                    {
+                        ((ASE::Light&)node).mLightType = ASE::Light::FREE;
+                    }
+                    else if (!ASSIMP_strincmp("directional",filePtr,11))
+                    {
+                        ((ASE::Light&)node).mLightType = ASE::Light::DIRECTIONAL;
+                    }
+                    else
+                    {
+                        LogWarning("Unknown kind of light source");
+                    }
+                    continue;
+                }
+            }
+            else if (node.mType == BaseNode::Camera)
+            {
+                // Camera settings
+                if (TokenMatch(filePtr,"CAMERA_SETTINGS" ,15))
+                {
+                    ParseLV2CameraSettingsBlock((ASE::Camera&)node);
+                    continue;
+                }
+                else if (TokenMatch(filePtr,"CAMERA_TYPE" ,11))
+                {
+                    if (!ASSIMP_strincmp("target",filePtr,6))
+                    {
+                        ((ASE::Camera&)node).mCameraType = ASE::Camera::TARGET;
+                    }
+                    else if (!ASSIMP_strincmp("free",filePtr,4))
+                    {
+                        ((ASE::Camera&)node).mCameraType = ASE::Camera::FREE;
+                    }
+                    else
+                    {
+                        LogWarning("Unknown kind of camera");
+                    }
+                    continue;
+                }
+            }
+            else if (node.mType == BaseNode::Mesh)
+            {
+                // mesh data
+                // FIX: Older files use MESH_SOFTSKIN
+                if (TokenMatch(filePtr,"MESH" ,4) ||
+                    TokenMatch(filePtr,"MESH_SOFTSKIN",13))
+                {
+                    ParseLV2MeshBlock((ASE::Mesh&)node);
+                    continue;
+                }
+                // mesh material index
+                if (TokenMatch(filePtr,"MATERIAL_REF" ,12))
+                {
+                    ParseLV4MeshLong(((ASE::Mesh&)node).iMaterialIndex);
+                    continue;
+                }
+            }
+        }
+        AI_ASE_HANDLE_TOP_LEVEL_SECTION();
+    }
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV2CameraSettingsBlock(ASE::Camera& camera)
 {
-	AI_ASE_PARSER_INIT();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			if (TokenMatch(filePtr,"CAMERA_NEAR" ,11))
-			{
-				ParseLV4MeshFloat(camera.mNear);
-				continue;
-			}
-			if (TokenMatch(filePtr,"CAMERA_FAR" ,10))
-			{
-				ParseLV4MeshFloat(camera.mFar);
-				continue;
-			}
-			if (TokenMatch(filePtr,"CAMERA_FOV" ,10))
-			{
-				ParseLV4MeshFloat(camera.mFOV);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("2","CAMERA_SETTINGS");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            if (TokenMatch(filePtr,"CAMERA_NEAR" ,11))
+            {
+                ParseLV4MeshFloat(camera.mNear);
+                continue;
+            }
+            if (TokenMatch(filePtr,"CAMERA_FAR" ,10))
+            {
+                ParseLV4MeshFloat(camera.mFar);
+                continue;
+            }
+            if (TokenMatch(filePtr,"CAMERA_FOV" ,10))
+            {
+                ParseLV4MeshFloat(camera.mFOV);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("2","CAMERA_SETTINGS");
+    }
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV2LightSettingsBlock(ASE::Light& light)
 {
-	AI_ASE_PARSER_INIT();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			if (TokenMatch(filePtr,"LIGHT_COLOR" ,11))
-			{
-				ParseLV4MeshFloatTriple(&light.mColor.r);
-				continue;
-			}
-			if (TokenMatch(filePtr,"LIGHT_INTENS" ,12))
-			{
-				ParseLV4MeshFloat(light.mIntensity);
-				continue;
-			}
-			if (TokenMatch(filePtr,"LIGHT_HOTSPOT" ,13))
-			{
-				ParseLV4MeshFloat(light.mAngle);
-				continue;
-			}
-			if (TokenMatch(filePtr,"LIGHT_FALLOFF" ,13))
-			{
-				ParseLV4MeshFloat(light.mFalloff);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("2","LIGHT_SETTINGS");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            if (TokenMatch(filePtr,"LIGHT_COLOR" ,11))
+            {
+                ParseLV4MeshFloatTriple(&light.mColor.r);
+                continue;
+            }
+            if (TokenMatch(filePtr,"LIGHT_INTENS" ,12))
+            {
+                ParseLV4MeshFloat(light.mIntensity);
+                continue;
+            }
+            if (TokenMatch(filePtr,"LIGHT_HOTSPOT" ,13))
+            {
+                ParseLV4MeshFloat(light.mAngle);
+                continue;
+            }
+            if (TokenMatch(filePtr,"LIGHT_FALLOFF" ,13))
+            {
+                ParseLV4MeshFloat(light.mFalloff);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("2","LIGHT_SETTINGS");
+    }
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	ASE::Animation* anim = &mesh.mAnim;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			if (TokenMatch(filePtr,"NODE_NAME" ,9))
-			{
-				std::string temp;
-				if(!ParseString(temp,"*NODE_NAME"))
-					SkipToNextToken();
-
-				// If the name of the node contains .target it
-				// represents an animated camera or spot light
-				// target.
-				if (std::string::npos != temp.find(".Target"))
-				{
-					if  ((mesh.mType != BaseNode::Camera || ((ASE::Camera&)mesh).mCameraType != ASE::Camera::TARGET)  &&
-						( mesh.mType != BaseNode::Light  || ((ASE::Light&)mesh).mLightType   != ASE::Light::TARGET))
-					{
-
-						DefaultLogger::get()->error("ASE: Found target animation channel "
-							"but the node is neither a camera nor a spot light");
-						anim = NULL;
-					}
-					else anim = &mesh.mTargetAnim;
-				}
-				continue;
-			}
-
-			// position keyframes
-			if (TokenMatch(filePtr,"CONTROL_POS_TRACK"  ,17)  ||
-				TokenMatch(filePtr,"CONTROL_POS_BEZIER" ,18)  ||
-				TokenMatch(filePtr,"CONTROL_POS_TCB"    ,15))
-			{
-				if (!anim)SkipSection();
-				else ParseLV3PosAnimationBlock(*anim);
-				continue;
-			}
-			// scaling keyframes
-			if (TokenMatch(filePtr,"CONTROL_SCALE_TRACK"  ,19) ||
-				TokenMatch(filePtr,"CONTROL_SCALE_BEZIER" ,20) ||
-				TokenMatch(filePtr,"CONTROL_SCALE_TCB"    ,17))
-			{
-				if (!anim || anim == &mesh.mTargetAnim)
-				{
-					// Target animation channels may have no rotation channels
-					DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation");
-					SkipSection();
-				}
-				else ParseLV3ScaleAnimationBlock(*anim);
-				continue;
-			}
-			// rotation keyframes
-			if (TokenMatch(filePtr,"CONTROL_ROT_TRACK"  ,17) ||
-				TokenMatch(filePtr,"CONTROL_ROT_BEZIER" ,18) ||
-				TokenMatch(filePtr,"CONTROL_ROT_TCB"    ,15))
-			{
-				if (!anim || anim == &mesh.mTargetAnim)
-				{
-					// Target animation channels may have no rotation channels
-					DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation");
-					SkipSection();
-				}
-				else ParseLV3RotAnimationBlock(*anim);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("2","TM_ANIMATION");
-	}
+    AI_ASE_PARSER_INIT();
+
+    ASE::Animation* anim = &mesh.mAnim;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            if (TokenMatch(filePtr,"NODE_NAME" ,9))
+            {
+                std::string temp;
+                if(!ParseString(temp,"*NODE_NAME"))
+                    SkipToNextToken();
+
+                // If the name of the node contains .target it
+                // represents an animated camera or spot light
+                // target.
+                if (std::string::npos != temp.find(".Target"))
+                {
+                    if  ((mesh.mType != BaseNode::Camera || ((ASE::Camera&)mesh).mCameraType != ASE::Camera::TARGET)  &&
+                        ( mesh.mType != BaseNode::Light  || ((ASE::Light&)mesh).mLightType   != ASE::Light::TARGET))
+                    {
+
+                        DefaultLogger::get()->error("ASE: Found target animation channel "
+                            "but the node is neither a camera nor a spot light");
+                        anim = NULL;
+                    }
+                    else anim = &mesh.mTargetAnim;
+                }
+                continue;
+            }
+
+            // position keyframes
+            if (TokenMatch(filePtr,"CONTROL_POS_TRACK"  ,17)  ||
+                TokenMatch(filePtr,"CONTROL_POS_BEZIER" ,18)  ||
+                TokenMatch(filePtr,"CONTROL_POS_TCB"    ,15))
+            {
+                if (!anim)SkipSection();
+                else ParseLV3PosAnimationBlock(*anim);
+                continue;
+            }
+            // scaling keyframes
+            if (TokenMatch(filePtr,"CONTROL_SCALE_TRACK"  ,19) ||
+                TokenMatch(filePtr,"CONTROL_SCALE_BEZIER" ,20) ||
+                TokenMatch(filePtr,"CONTROL_SCALE_TCB"    ,17))
+            {
+                if (!anim || anim == &mesh.mTargetAnim)
+                {
+                    // Target animation channels may have no rotation channels
+                    DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation");
+                    SkipSection();
+                }
+                else ParseLV3ScaleAnimationBlock(*anim);
+                continue;
+            }
+            // rotation keyframes
+            if (TokenMatch(filePtr,"CONTROL_ROT_TRACK"  ,17) ||
+                TokenMatch(filePtr,"CONTROL_ROT_BEZIER" ,18) ||
+                TokenMatch(filePtr,"CONTROL_ROT_TCB"    ,15))
+            {
+                if (!anim || anim == &mesh.mTargetAnim)
+                {
+                    // Target animation channels may have no rotation channels
+                    DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation");
+                    SkipSection();
+                }
+                else ParseLV3RotAnimationBlock(*anim);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("2","TM_ANIMATION");
+    }
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation& anim)
 {
-	AI_ASE_PARSER_INIT();
-	unsigned int iIndex;
-
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			bool b = false;
-
-			// For the moment we're just reading the three floats -
-			// we ignore the ádditional information for bezier's and TCBs
-
-			// simple scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20))
-			{
-				b = true;
-				anim.mScalingType = ASE::Animation::TRACK;
-			}
-
-			// Bezier scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_BEZIER_SCALE_KEY" ,24))
-			{
-				b = true;
-				anim.mScalingType = ASE::Animation::BEZIER;
-			}
-			// TCB scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_TCB_SCALE_KEY" ,21))
-			{
-				b = true;
-				anim.mScalingType = ASE::Animation::TCB;
-			}
-			if (b)
-			{
-				anim.akeyScaling.push_back(aiVectorKey());
-				aiVectorKey& key = anim.akeyScaling.back();
-				ParseLV4MeshFloatTriple(&key.mValue.x,iIndex);
-				key.mTime = (double)iIndex;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK");
-	}
+    AI_ASE_PARSER_INIT();
+    unsigned int iIndex;
+
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            bool b = false;
+
+            // For the moment we're just reading the three floats -
+            // we ignore the ádditional information for bezier's and TCBs
+
+            // simple scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20))
+            {
+                b = true;
+                anim.mScalingType = ASE::Animation::TRACK;
+            }
+
+            // Bezier scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_BEZIER_SCALE_KEY" ,24))
+            {
+                b = true;
+                anim.mScalingType = ASE::Animation::BEZIER;
+            }
+            // TCB scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_TCB_SCALE_KEY" ,21))
+            {
+                b = true;
+                anim.mScalingType = ASE::Animation::TCB;
+            }
+            if (b)
+            {
+                anim.akeyScaling.push_back(aiVectorKey());
+                aiVectorKey& key = anim.akeyScaling.back();
+                ParseLV4MeshFloatTriple(&key.mValue.x,iIndex);
+                key.mTime = (double)iIndex;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK");
+    }
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3PosAnimationBlock(ASE::Animation& anim)
 {
-	AI_ASE_PARSER_INIT();
-	unsigned int iIndex;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			bool b = false;
-
-			// For the moment we're just reading the three floats -
-			// we ignore the ádditional information for bezier's and TCBs
-
-			// simple scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18))
-			{
-				b = true;
-				anim.mPositionType = ASE::Animation::TRACK;
-			}
-
-			// Bezier scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_BEZIER_POS_KEY" ,22))
-			{
-				b = true;
-				anim.mPositionType = ASE::Animation::BEZIER;
-			}
-			// TCB scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_TCB_POS_KEY" ,19))
-			{
-				b = true;
-				anim.mPositionType = ASE::Animation::TCB;
-			}
-			if (b)
-			{
-				anim.akeyPositions.push_back(aiVectorKey());
-				aiVectorKey& key = anim.akeyPositions.back();
-				ParseLV4MeshFloatTriple(&key.mValue.x,iIndex);
-				key.mTime = (double)iIndex;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK");
-	}
+    AI_ASE_PARSER_INIT();
+    unsigned int iIndex;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            bool b = false;
+
+            // For the moment we're just reading the three floats -
+            // we ignore the ádditional information for bezier's and TCBs
+
+            // simple scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18))
+            {
+                b = true;
+                anim.mPositionType = ASE::Animation::TRACK;
+            }
+
+            // Bezier scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_BEZIER_POS_KEY" ,22))
+            {
+                b = true;
+                anim.mPositionType = ASE::Animation::BEZIER;
+            }
+            // TCB scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_TCB_POS_KEY" ,19))
+            {
+                b = true;
+                anim.mPositionType = ASE::Animation::TCB;
+            }
+            if (b)
+            {
+                anim.akeyPositions.push_back(aiVectorKey());
+                aiVectorKey& key = anim.akeyPositions.back();
+                ParseLV4MeshFloatTriple(&key.mValue.x,iIndex);
+                key.mTime = (double)iIndex;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK");
+    }
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3RotAnimationBlock(ASE::Animation& anim)
 {
-	AI_ASE_PARSER_INIT();
-	unsigned int iIndex;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			bool b = false;
-
-			// For the moment we're just reading the  floats -
-			// we ignore the ádditional information for bezier's and TCBs
-
-			// simple scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18))
-			{
-				b = true;
-				anim.mRotationType = ASE::Animation::TRACK;
-			}
-
-			// Bezier scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_BEZIER_ROT_KEY" ,22))
-			{
-				b = true;
-				anim.mRotationType = ASE::Animation::BEZIER;
-			}
-			// TCB scaling keyframe
-			if (TokenMatch(filePtr,"CONTROL_TCB_ROT_KEY" ,19))
-			{
-				b = true;
-				anim.mRotationType = ASE::Animation::TCB;
-			}
-			if (b)
-			{
-				anim.akeyRotations.push_back(aiQuatKey());
-				aiQuatKey& key = anim.akeyRotations.back();
-				aiVector3D v;float f;
-				ParseLV4MeshFloatTriple(&v.x,iIndex);
-				ParseLV4MeshFloat(f);
-				key.mTime = (double)iIndex;
-				key.mValue = aiQuaternion(v,f);
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*CONTROL_ROT_TRACK");
-	}
+    AI_ASE_PARSER_INIT();
+    unsigned int iIndex;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            bool b = false;
+
+            // For the moment we're just reading the  floats -
+            // we ignore the ádditional information for bezier's and TCBs
+
+            // simple scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18))
+            {
+                b = true;
+                anim.mRotationType = ASE::Animation::TRACK;
+            }
+
+            // Bezier scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_BEZIER_ROT_KEY" ,22))
+            {
+                b = true;
+                anim.mRotationType = ASE::Animation::BEZIER;
+            }
+            // TCB scaling keyframe
+            if (TokenMatch(filePtr,"CONTROL_TCB_ROT_KEY" ,19))
+            {
+                b = true;
+                anim.mRotationType = ASE::Animation::TCB;
+            }
+            if (b)
+            {
+                anim.akeyRotations.push_back(aiQuatKey());
+                aiQuatKey& key = anim.akeyRotations.back();
+                aiVector3D v;float f;
+                ParseLV4MeshFloatTriple(&v.x,iIndex);
+                ParseLV4MeshFloat(f);
+                key.mTime = (double)iIndex;
+                key.mValue = aiQuaternion(v,f);
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*CONTROL_ROT_TRACK");
+    }
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode& mesh)
 {
-	AI_ASE_PARSER_INIT();
-	int mode   = 0;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			// name of the node
-			if (TokenMatch(filePtr,"NODE_NAME" ,9))
-			{
-				std::string temp;
-				if(!ParseString(temp,"*NODE_NAME"))
-					SkipToNextToken();
-
-				std::string::size_type s;
-				if (temp == mesh.mName)
-				{
-					mode = 1;
-				}
-				else if (std::string::npos != (s = temp.find(".Target")) &&
-					mesh.mName == temp.substr(0,s))
-				{
-					// This should be either a target light or a target camera
-					if ( (mesh.mType == BaseNode::Light &&  ((ASE::Light&)mesh) .mLightType  == ASE::Light::TARGET) ||
-						 (mesh.mType == BaseNode::Camera && ((ASE::Camera&)mesh).mCameraType == ASE::Camera::TARGET))
-					{
-						mode = 2;
-					}
-					else DefaultLogger::get()->error("ASE: Ignoring target transform, "
-						"this is no spot light or target camera");
-				}
-				else
-				{
-					DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp);
-					// mode = 0
-				}
-				continue;
-			}
-			if (mode)
-			{
-				// fourth row of the transformation matrix - and also the
-				// only information here that is interesting for targets
-				if (TokenMatch(filePtr,"TM_ROW3" ,7))
-				{
-					ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x));
-					continue;
-				}
-				if (mode == 1)
-				{
-					// first row of the transformation matrix
-					if (TokenMatch(filePtr,"TM_ROW0" ,7))
-					{
-						ParseLV4MeshFloatTriple(mesh.mTransform[0]);
-						continue;
-					}
-					// second row of the transformation matrix
-					if (TokenMatch(filePtr,"TM_ROW1" ,7))
-					{
-						ParseLV4MeshFloatTriple(mesh.mTransform[1]);
-						continue;
-					}
-					// third row of the transformation matrix
-					if (TokenMatch(filePtr,"TM_ROW2" ,7))
-					{
-						ParseLV4MeshFloatTriple(mesh.mTransform[2]);
-						continue;
-					}
-					// inherited position axes
-					if (TokenMatch(filePtr,"INHERIT_POS" ,11))
-					{
-						unsigned int aiVal[3];
-						ParseLV4MeshLongTriple(aiVal);
-
-						for (unsigned int i = 0; i < 3;++i)
-							mesh.inherit.abInheritPosition[i] = aiVal[i] != 0;
-						continue;
-					}
-					// inherited rotation axes
-					if (TokenMatch(filePtr,"INHERIT_ROT" ,11))
-					{
-						unsigned int aiVal[3];
-						ParseLV4MeshLongTriple(aiVal);
-
-						for (unsigned int i = 0; i < 3;++i)
-							mesh.inherit.abInheritRotation[i] = aiVal[i] != 0;
-						continue;
-					}
-					// inherited scaling axes
-					if (TokenMatch(filePtr,"INHERIT_SCL" ,11))
-					{
-						unsigned int aiVal[3];
-						ParseLV4MeshLongTriple(aiVal);
-
-						for (unsigned int i = 0; i < 3;++i)
-							mesh.inherit.abInheritScaling[i] = aiVal[i] != 0;
-						continue;
-					}
-				}
-			}
-		}
-		AI_ASE_HANDLE_SECTION("2","*NODE_TM");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    int mode   = 0;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            // name of the node
+            if (TokenMatch(filePtr,"NODE_NAME" ,9))
+            {
+                std::string temp;
+                if(!ParseString(temp,"*NODE_NAME"))
+                    SkipToNextToken();
+
+                std::string::size_type s;
+                if (temp == mesh.mName)
+                {
+                    mode = 1;
+                }
+                else if (std::string::npos != (s = temp.find(".Target")) &&
+                    mesh.mName == temp.substr(0,s))
+                {
+                    // This should be either a target light or a target camera
+                    if ( (mesh.mType == BaseNode::Light &&  ((ASE::Light&)mesh) .mLightType  == ASE::Light::TARGET) ||
+                         (mesh.mType == BaseNode::Camera && ((ASE::Camera&)mesh).mCameraType == ASE::Camera::TARGET))
+                    {
+                        mode = 2;
+                    }
+                    else DefaultLogger::get()->error("ASE: Ignoring target transform, "
+                        "this is no spot light or target camera");
+                }
+                else
+                {
+                    DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp);
+                    // mode = 0
+                }
+                continue;
+            }
+            if (mode)
+            {
+                // fourth row of the transformation matrix - and also the
+                // only information here that is interesting for targets
+                if (TokenMatch(filePtr,"TM_ROW3" ,7))
+                {
+                    ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x));
+                    continue;
+                }
+                if (mode == 1)
+                {
+                    // first row of the transformation matrix
+                    if (TokenMatch(filePtr,"TM_ROW0" ,7))
+                    {
+                        ParseLV4MeshFloatTriple(mesh.mTransform[0]);
+                        continue;
+                    }
+                    // second row of the transformation matrix
+                    if (TokenMatch(filePtr,"TM_ROW1" ,7))
+                    {
+                        ParseLV4MeshFloatTriple(mesh.mTransform[1]);
+                        continue;
+                    }
+                    // third row of the transformation matrix
+                    if (TokenMatch(filePtr,"TM_ROW2" ,7))
+                    {
+                        ParseLV4MeshFloatTriple(mesh.mTransform[2]);
+                        continue;
+                    }
+                    // inherited position axes
+                    if (TokenMatch(filePtr,"INHERIT_POS" ,11))
+                    {
+                        unsigned int aiVal[3];
+                        ParseLV4MeshLongTriple(aiVal);
+
+                        for (unsigned int i = 0; i < 3;++i)
+                            mesh.inherit.abInheritPosition[i] = aiVal[i] != 0;
+                        continue;
+                    }
+                    // inherited rotation axes
+                    if (TokenMatch(filePtr,"INHERIT_ROT" ,11))
+                    {
+                        unsigned int aiVal[3];
+                        ParseLV4MeshLongTriple(aiVal);
+
+                        for (unsigned int i = 0; i < 3;++i)
+                            mesh.inherit.abInheritRotation[i] = aiVal[i] != 0;
+                        continue;
+                    }
+                    // inherited scaling axes
+                    if (TokenMatch(filePtr,"INHERIT_SCL" ,11))
+                    {
+                        unsigned int aiVal[3];
+                        ParseLV4MeshLongTriple(aiVal);
+
+                        for (unsigned int i = 0; i < 3;++i)
+                            mesh.inherit.abInheritScaling[i] = aiVal[i] != 0;
+                        continue;
+                    }
+                }
+            }
+        }
+        AI_ASE_HANDLE_SECTION("2","*NODE_TM");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	unsigned int iNumVertices = 0;
-	unsigned int iNumFaces = 0;
-	unsigned int iNumTVertices = 0;
-	unsigned int iNumTFaces = 0;
-	unsigned int iNumCVertices = 0;
-	unsigned int iNumCFaces = 0;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-			// Number of vertices in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14))
-			{
-				ParseLV4MeshLong(iNumVertices);
-				continue;
-			}
-			// Number of texture coordinates in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15))
-			{
-				ParseLV4MeshLong(iNumTVertices);
-				continue;
-			}
-			// Number of vertex colors in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15))
-			{
-				ParseLV4MeshLong(iNumCVertices);
-				continue;
-			}
-			// Number of regular faces in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMFACES" ,13))
-			{
-				ParseLV4MeshLong(iNumFaces);
-				continue;
-			}
-			// Number of UVWed faces in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15))
-			{
-				ParseLV4MeshLong(iNumTFaces);
-				continue;
-			}
-			// Number of colored faces in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMCVFACES" ,15))
-			{
-				ParseLV4MeshLong(iNumCFaces);
-				continue;
-			}
-			// mesh vertex list block
-			if (TokenMatch(filePtr,"MESH_VERTEX_LIST" ,16))
-			{
-				ParseLV3MeshVertexListBlock(iNumVertices,mesh);
-				continue;
-			}
-			// mesh face list block
-			if (TokenMatch(filePtr,"MESH_FACE_LIST" ,14))
-			{
-				ParseLV3MeshFaceListBlock(iNumFaces,mesh);
-				continue;
-			}
-			// mesh texture vertex list block
-			if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14))
-			{
-				ParseLV3MeshTListBlock(iNumTVertices,mesh);
-				continue;
-			}
-			// mesh texture face block
-			if (TokenMatch(filePtr,"MESH_TFACELIST" ,14))
-			{
-				ParseLV3MeshTFaceListBlock(iNumTFaces,mesh);
-				continue;
-			}
-			// mesh color vertex list block
-			if (TokenMatch(filePtr,"MESH_CVERTLIST" ,14))
-			{
-				ParseLV3MeshCListBlock(iNumCVertices,mesh);
-				continue;
-			}
-			// mesh color face block
-			if (TokenMatch(filePtr,"MESH_CFACELIST" ,14))
-			{
-				ParseLV3MeshCFaceListBlock(iNumCFaces,mesh);
-				continue;
-			}
-			// mesh normals
-			if (TokenMatch(filePtr,"MESH_NORMALS" ,12))
-			{
-				ParseLV3MeshNormalListBlock(mesh);
-				continue;
-			}
-			// another mesh UV channel ...
-			if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19))
-			{
-
-				unsigned int iIndex = 0;
-				ParseLV4MeshLong(iIndex);
-
-				if (iIndex < 2)
-				{
-					LogWarning("Mapping channel has an invalid index. Skipping UV channel");
-					// skip it ...
-					SkipSection();
-				}
-				if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS)
-				{
-					LogWarning("Too many UV channels specified. Skipping channel ..");
-					// skip it ...
-					SkipSection();
-				}
-				else
-				{
-					// parse the mapping channel
-					ParseLV3MappingChannel(iIndex-1,mesh);
-				}
-				continue;
-			}
-			// mesh animation keyframe. Not supported
-			if (TokenMatch(filePtr,"MESH_ANIMATION" ,14))
-			{
-
-				LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
-					"Keyframe animation is not supported by Assimp, this element "
-					"will be ignored");
-				//SkipSection();
-				continue;
-			}
-			if (TokenMatch(filePtr,"MESH_WEIGHTS" ,12))
-			{
-				ParseLV3MeshWeightsBlock(mesh);continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("2","*MESH");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    unsigned int iNumVertices = 0;
+    unsigned int iNumFaces = 0;
+    unsigned int iNumTVertices = 0;
+    unsigned int iNumTFaces = 0;
+    unsigned int iNumCVertices = 0;
+    unsigned int iNumCFaces = 0;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+            // Number of vertices in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14))
+            {
+                ParseLV4MeshLong(iNumVertices);
+                continue;
+            }
+            // Number of texture coordinates in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15))
+            {
+                ParseLV4MeshLong(iNumTVertices);
+                continue;
+            }
+            // Number of vertex colors in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15))
+            {
+                ParseLV4MeshLong(iNumCVertices);
+                continue;
+            }
+            // Number of regular faces in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMFACES" ,13))
+            {
+                ParseLV4MeshLong(iNumFaces);
+                continue;
+            }
+            // Number of UVWed faces in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15))
+            {
+                ParseLV4MeshLong(iNumTFaces);
+                continue;
+            }
+            // Number of colored faces in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMCVFACES" ,15))
+            {
+                ParseLV4MeshLong(iNumCFaces);
+                continue;
+            }
+            // mesh vertex list block
+            if (TokenMatch(filePtr,"MESH_VERTEX_LIST" ,16))
+            {
+                ParseLV3MeshVertexListBlock(iNumVertices,mesh);
+                continue;
+            }
+            // mesh face list block
+            if (TokenMatch(filePtr,"MESH_FACE_LIST" ,14))
+            {
+                ParseLV3MeshFaceListBlock(iNumFaces,mesh);
+                continue;
+            }
+            // mesh texture vertex list block
+            if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14))
+            {
+                ParseLV3MeshTListBlock(iNumTVertices,mesh);
+                continue;
+            }
+            // mesh texture face block
+            if (TokenMatch(filePtr,"MESH_TFACELIST" ,14))
+            {
+                ParseLV3MeshTFaceListBlock(iNumTFaces,mesh);
+                continue;
+            }
+            // mesh color vertex list block
+            if (TokenMatch(filePtr,"MESH_CVERTLIST" ,14))
+            {
+                ParseLV3MeshCListBlock(iNumCVertices,mesh);
+                continue;
+            }
+            // mesh color face block
+            if (TokenMatch(filePtr,"MESH_CFACELIST" ,14))
+            {
+                ParseLV3MeshCFaceListBlock(iNumCFaces,mesh);
+                continue;
+            }
+            // mesh normals
+            if (TokenMatch(filePtr,"MESH_NORMALS" ,12))
+            {
+                ParseLV3MeshNormalListBlock(mesh);
+                continue;
+            }
+            // another mesh UV channel ...
+            if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19))
+            {
+
+                unsigned int iIndex = 0;
+                ParseLV4MeshLong(iIndex);
+
+                if (iIndex < 2)
+                {
+                    LogWarning("Mapping channel has an invalid index. Skipping UV channel");
+                    // skip it ...
+                    SkipSection();
+                }
+                if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS)
+                {
+                    LogWarning("Too many UV channels specified. Skipping channel ..");
+                    // skip it ...
+                    SkipSection();
+                }
+                else
+                {
+                    // parse the mapping channel
+                    ParseLV3MappingChannel(iIndex-1,mesh);
+                }
+                continue;
+            }
+            // mesh animation keyframe. Not supported
+            if (TokenMatch(filePtr,"MESH_ANIMATION" ,14))
+            {
+
+                LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
+                    "Keyframe animation is not supported by Assimp, this element "
+                    "will be ignored");
+                //SkipSection();
+                continue;
+            }
+            if (TokenMatch(filePtr,"MESH_WEIGHTS" ,12))
+            {
+                ParseLV3MeshWeightsBlock(mesh);continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("2","*MESH");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	unsigned int iNumVertices = 0, iNumBones = 0;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Number of bone vertices ...
-			if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14))
-			{
-				ParseLV4MeshLong(iNumVertices);
-				continue;
-			}
-			// Number of bones
-			if (TokenMatch(filePtr,"MESH_NUMBONE" ,12))
-			{
-				ParseLV4MeshLong(iNumBones);
-				continue;
-			}
-			// parse the list of bones
-			if (TokenMatch(filePtr,"MESH_BONE_LIST" ,14))
-			{
-				ParseLV4MeshBones(iNumBones,mesh);
-				continue;
-			}
-			// parse the list of bones vertices
-			if (TokenMatch(filePtr,"MESH_BONE_VERTEX_LIST" ,21) )
-			{
-				ParseLV4MeshBonesVertices(iNumVertices,mesh);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_WEIGHTS");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    unsigned int iNumVertices = 0, iNumBones = 0;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Number of bone vertices ...
+            if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14))
+            {
+                ParseLV4MeshLong(iNumVertices);
+                continue;
+            }
+            // Number of bones
+            if (TokenMatch(filePtr,"MESH_NUMBONE" ,12))
+            {
+                ParseLV4MeshLong(iNumBones);
+                continue;
+            }
+            // parse the list of bones
+            if (TokenMatch(filePtr,"MESH_BONE_LIST" ,14))
+            {
+                ParseLV4MeshBones(iNumBones,mesh);
+                continue;
+            }
+            // parse the list of bones vertices
+            if (TokenMatch(filePtr,"MESH_BONE_VERTEX_LIST" ,21) )
+            {
+                ParseLV4MeshBonesVertices(iNumVertices,mesh);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_WEIGHTS");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-	mesh.mBones.resize(iNumBones);
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Mesh bone with name ...
-			if (TokenMatch(filePtr,"MESH_BONE_NAME" ,14))
-			{
-				// parse an index ...
-				if(SkipSpaces(&filePtr))
-				{
-					unsigned int iIndex = strtoul10(filePtr,&filePtr);
-					if (iIndex >= iNumBones)
-					{
-						LogWarning("Bone index is out of bounds");
-						continue;
-					}
-					if (!ParseString(mesh.mBones[iIndex].mName,"*MESH_BONE_NAME"))
-						SkipToNextToken();
-					continue;
-				}
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_BONE_LIST");
-	}
+    AI_ASE_PARSER_INIT();
+    mesh.mBones.resize(iNumBones);
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Mesh bone with name ...
+            if (TokenMatch(filePtr,"MESH_BONE_NAME" ,14))
+            {
+                // parse an index ...
+                if(SkipSpaces(&filePtr))
+                {
+                    unsigned int iIndex = strtoul10(filePtr,&filePtr);
+                    if (iIndex >= iNumBones)
+                    {
+                        LogWarning("Bone index is out of bounds");
+                        continue;
+                    }
+                    if (!ParseString(mesh.mBones[iIndex].mName,"*MESH_BONE_NAME"))
+                        SkipToNextToken();
+                    continue;
+                }
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_BONE_LIST");
+    }
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices,ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-	mesh.mBoneVertices.resize(iNumVertices);
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Mesh bone vertex
-			if (TokenMatch(filePtr,"MESH_BONE_VERTEX" ,16))
-			{
-				// read the vertex index
-				unsigned int iIndex = strtoul10(filePtr,&filePtr);
-				if (iIndex >= mesh.mPositions.size())
-				{
-					iIndex = (unsigned int)mesh.mPositions.size()-1;
-					LogWarning("Bone vertex index is out of bounds. Using the largest valid "
-						"bone vertex index instead");
-				}
-
-				// --- ignored
-				float afVert[3];
-				ParseLV4MeshFloatTriple(afVert);
-
-				std::pair<int,float> pairOut;
-				while (true)
-				{
-					// first parse the bone index ...
-					if (!SkipSpaces(&filePtr))break;
-					pairOut.first = strtoul10(filePtr,&filePtr);
-
-					// then parse the vertex weight
-					if (!SkipSpaces(&filePtr))break;
-					filePtr = fast_atoreal_move<float>(filePtr,pairOut.second);
-
-					// -1 marks unused entries
-					if (-1 != pairOut.first)
-					{
-						mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut);
-					}
-				}
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("4","*MESH_BONE_VERTEX");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    mesh.mBoneVertices.resize(iNumVertices);
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Mesh bone vertex
+            if (TokenMatch(filePtr,"MESH_BONE_VERTEX" ,16))
+            {
+                // read the vertex index
+                unsigned int iIndex = strtoul10(filePtr,&filePtr);
+                if (iIndex >= mesh.mPositions.size())
+                {
+                    iIndex = (unsigned int)mesh.mPositions.size()-1;
+                    LogWarning("Bone vertex index is out of bounds. Using the largest valid "
+                        "bone vertex index instead");
+                }
+
+                // --- ignored
+                float afVert[3];
+                ParseLV4MeshFloatTriple(afVert);
+
+                std::pair<int,float> pairOut;
+                while (true)
+                {
+                    // first parse the bone index ...
+                    if (!SkipSpaces(&filePtr))break;
+                    pairOut.first = strtoul10(filePtr,&filePtr);
+
+                    // then parse the vertex weight
+                    if (!SkipSpaces(&filePtr))break;
+                    filePtr = fast_atoreal_move<float>(filePtr,pairOut.second);
+
+                    // -1 marks unused entries
+                    if (-1 != pairOut.first)
+                    {
+                        mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut);
+                    }
+                }
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("4","*MESH_BONE_VERTEX");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshVertexListBlock(
-	unsigned int iNumVertices, ASE::Mesh& mesh)
+    unsigned int iNumVertices, ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	// allocate enough storage in the array
-	mesh.mPositions.resize(iNumVertices);
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Vertex entry
-			if (TokenMatch(filePtr,"MESH_VERTEX" ,11))
-			{
-
-				aiVector3D vTemp;
-				unsigned int iIndex;
-				ParseLV4MeshFloatTriple(&vTemp.x,iIndex);
-
-				if (iIndex >= iNumVertices)
-				{
-					LogWarning("Invalid vertex index. It will be ignored");
-				}
-				else mesh.mPositions[iIndex] = vTemp;
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_VERTEX_LIST");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    // allocate enough storage in the array
+    mesh.mPositions.resize(iNumVertices);
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Vertex entry
+            if (TokenMatch(filePtr,"MESH_VERTEX" ,11))
+            {
+
+                aiVector3D vTemp;
+                unsigned int iIndex;
+                ParseLV4MeshFloatTriple(&vTemp.x,iIndex);
+
+                if (iIndex >= iNumVertices)
+                {
+                    LogWarning("Invalid vertex index. It will be ignored");
+                }
+                else mesh.mPositions[iIndex] = vTemp;
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_VERTEX_LIST");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	// allocate enough storage in the face array
-	mesh.mFaces.resize(iNumFaces);
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Face entry
-			if (TokenMatch(filePtr,"MESH_FACE" ,9))
-			{
-
-				ASE::Face mFace;
-				ParseLV4MeshFace(mFace);
-
-				if (mFace.iFace >= iNumFaces)
-				{
-					LogWarning("Face has an invalid index. It will be ignored");
-				}
-				else mesh.mFaces[mFace.iFace] = mFace;
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_FACE_LIST");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    // allocate enough storage in the face array
+    mesh.mFaces.resize(iNumFaces);
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Face entry
+            if (TokenMatch(filePtr,"MESH_FACE" ,9))
+            {
+
+                ASE::Face mFace;
+                ParseLV4MeshFace(mFace);
+
+                if (mFace.iFace >= iNumFaces)
+                {
+                    LogWarning("Face has an invalid index. It will be ignored");
+                }
+                else mesh.mFaces[mFace.iFace] = mFace;
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_FACE_LIST");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
-	ASE::Mesh& mesh, unsigned int iChannel)
+    ASE::Mesh& mesh, unsigned int iChannel)
 {
-	AI_ASE_PARSER_INIT();
-
-	// allocate enough storage in the array
-	mesh.amTexCoords[iChannel].resize(iNumVertices);
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Vertex entry
-			if (TokenMatch(filePtr,"MESH_TVERT" ,10))
-			{
-				aiVector3D vTemp;
-				unsigned int iIndex;
-				ParseLV4MeshFloatTriple(&vTemp.x,iIndex);
-
-				if (iIndex >= iNumVertices)
-				{
-					LogWarning("Tvertex has an invalid index. It will be ignored");
-				}
-				else mesh.amTexCoords[iChannel][iIndex] = vTemp;
-
-				if (0.0f != vTemp.z)
-				{
-					// we need 3 coordinate channels
-					mesh.mNumUVComponents[iChannel] = 3;
-				}
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_TVERT_LIST");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    // allocate enough storage in the array
+    mesh.amTexCoords[iChannel].resize(iNumVertices);
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Vertex entry
+            if (TokenMatch(filePtr,"MESH_TVERT" ,10))
+            {
+                aiVector3D vTemp;
+                unsigned int iIndex;
+                ParseLV4MeshFloatTriple(&vTemp.x,iIndex);
+
+                if (iIndex >= iNumVertices)
+                {
+                    LogWarning("Tvertex has an invalid index. It will be ignored");
+                }
+                else mesh.amTexCoords[iChannel][iIndex] = vTemp;
+
+                if (0.0f != vTemp.z)
+                {
+                    // we need 3 coordinate channels
+                    mesh.mNumUVComponents[iChannel] = 3;
+                }
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_TVERT_LIST");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
-	ASE::Mesh& mesh, unsigned int iChannel)
+    ASE::Mesh& mesh, unsigned int iChannel)
 {
-	AI_ASE_PARSER_INIT();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Face entry
-			if (TokenMatch(filePtr,"MESH_TFACE" ,10))
-			{
-				unsigned int aiValues[3];
-				unsigned int iIndex = 0;
-
-				ParseLV4MeshLongTriple(aiValues,iIndex);
-				if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size())
-				{
-					LogWarning("UV-Face has an invalid index. It will be ignored");
-				}
-				else
-				{
-					// copy UV indices
-					mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0];
-					mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1];
-					mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2];
-				}
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_TFACE_LIST");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Face entry
+            if (TokenMatch(filePtr,"MESH_TFACE" ,10))
+            {
+                unsigned int aiValues[3];
+                unsigned int iIndex = 0;
+
+                ParseLV4MeshLongTriple(aiValues,iIndex);
+                if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size())
+                {
+                    LogWarning("UV-Face has an invalid index. It will be ignored");
+                }
+                else
+                {
+                    // copy UV indices
+                    mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0];
+                    mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1];
+                    mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2];
+                }
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_TFACE_LIST");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	unsigned int iNumTVertices = 0;
-	unsigned int iNumTFaces = 0;
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Number of texture coordinates in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15))
-			{
-				ParseLV4MeshLong(iNumTVertices);
-				continue;
-			}
-			// Number of UVWed faces in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15))
-			{
-				ParseLV4MeshLong(iNumTFaces);
-				continue;
-			}
-			// mesh texture vertex list block
-			if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14))
-			{
-				ParseLV3MeshTListBlock(iNumTVertices,mesh,iChannel);
-				continue;
-			}
-			// mesh texture face block
-			if (TokenMatch(filePtr,"MESH_TFACELIST" ,14))
-			{
-				ParseLV3MeshTFaceListBlock(iNumTFaces,mesh, iChannel);
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_MAPPING_CHANNEL");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    unsigned int iNumTVertices = 0;
+    unsigned int iNumTFaces = 0;
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Number of texture coordinates in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15))
+            {
+                ParseLV4MeshLong(iNumTVertices);
+                continue;
+            }
+            // Number of UVWed faces in the mesh
+            if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15))
+            {
+                ParseLV4MeshLong(iNumTFaces);
+                continue;
+            }
+            // mesh texture vertex list block
+            if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14))
+            {
+                ParseLV3MeshTListBlock(iNumTVertices,mesh,iChannel);
+                continue;
+            }
+            // mesh texture face block
+            if (TokenMatch(filePtr,"MESH_TFACELIST" ,14))
+            {
+                ParseLV3MeshTFaceListBlock(iNumTFaces,mesh, iChannel);
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_MAPPING_CHANNEL");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	// allocate enough storage in the array
-	mesh.mVertexColors.resize(iNumVertices);
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Vertex entry
-			if (TokenMatch(filePtr,"MESH_VERTCOL" ,12))
-			{
-				aiColor4D vTemp;
-				vTemp.a = 1.0f;
-				unsigned int iIndex;
-				ParseLV4MeshFloatTriple(&vTemp.r,iIndex);
-
-				if (iIndex >= iNumVertices)
-				{
-					LogWarning("Vertex color has an invalid index. It will be ignored");
-				}
-				else mesh.mVertexColors[iIndex] = vTemp;
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_CVERTEX_LIST");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    // allocate enough storage in the array
+    mesh.mVertexColors.resize(iNumVertices);
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Vertex entry
+            if (TokenMatch(filePtr,"MESH_VERTCOL" ,12))
+            {
+                aiColor4D vTemp;
+                vTemp.a = 1.0f;
+                unsigned int iIndex;
+                ParseLV4MeshFloatTriple(&vTemp.r,iIndex);
+
+                if (iIndex >= iNumVertices)
+                {
+                    LogWarning("Vertex color has an invalid index. It will be ignored");
+                }
+                else mesh.mVertexColors[iIndex] = vTemp;
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_CVERTEX_LIST");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh)
 {
-	AI_ASE_PARSER_INIT();
-	while (true)
-	{
-		if ('*' == *filePtr)
-		{
-			++filePtr;
-
-			// Face entry
-			if (TokenMatch(filePtr,"MESH_CFACE" ,11))
-			{
-				unsigned int aiValues[3];
-				unsigned int iIndex = 0;
-
-				ParseLV4MeshLongTriple(aiValues,iIndex);
-				if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size())
-				{
-					LogWarning("UV-Face has an invalid index. It will be ignored");
-				}
-				else
-				{
-					// copy color indices
-					mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0];
-					mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1];
-					mesh.mFaces[iIndex].mColorIndices[2] = aiValues[2];
-				}
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_CFACE_LIST");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+    while (true)
+    {
+        if ('*' == *filePtr)
+        {
+            ++filePtr;
+
+            // Face entry
+            if (TokenMatch(filePtr,"MESH_CFACE" ,11))
+            {
+                unsigned int aiValues[3];
+                unsigned int iIndex = 0;
+
+                ParseLV4MeshLongTriple(aiValues,iIndex);
+                if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size())
+                {
+                    LogWarning("UV-Face has an invalid index. It will be ignored");
+                }
+                else
+                {
+                    // copy color indices
+                    mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0];
+                    mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1];
+                    mesh.mFaces[iIndex].mColorIndices[2] = aiValues[2];
+                }
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_CFACE_LIST");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
 {
-	AI_ASE_PARSER_INIT();
-
-	// Allocate enough storage for the normals
-	sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f ));
-	unsigned int index, faceIdx = UINT_MAX;
-
-	// FIXME: rewrite this and find out how to interpret the normals
-	// correctly. This is crap.
-
-	// Smooth the vertex and face normals together. The result
-	// will be edgy then, but otherwise everything would be soft ...
-	while (true)	{
-		if ('*' == *filePtr)	{
-			++filePtr;
-			if (faceIdx != UINT_MAX && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17))	{
-				aiVector3D vNormal;
-				ParseLV4MeshFloatTriple(&vNormal.x,index);
-				if (faceIdx >=  sMesh.mFaces.size())
-					continue;
-
-				// Make sure we assign it to the correct face
-				const ASE::Face& face = sMesh.mFaces[faceIdx];
-				if (index == face.mIndices[0])
-					index = 0;
-				else if (index == face.mIndices[1])
-					index = 1;
-				else if (index == face.mIndices[2])
-					index = 2;
-				else	{
-					DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
-					continue;
-				}
-				// We'll renormalize later
-				sMesh.mNormals[faceIdx*3+index] += vNormal;
-				continue;
-			}
-			if (TokenMatch(filePtr,"MESH_FACENORMAL",15))	{
-				aiVector3D vNormal;
-				ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
-
-				if (faceIdx >= sMesh.mFaces.size())	{
-					DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section");
-					continue;
-				}
-
-				// We'll renormalize later
-				sMesh.mNormals[faceIdx*3] += vNormal;
-				sMesh.mNormals[faceIdx*3+1] += vNormal;
-				sMesh.mNormals[faceIdx*3+2] += vNormal;
-				continue;
-			}
-		}
-		AI_ASE_HANDLE_SECTION("3","*MESH_NORMALS");
-	}
-	return;
+    AI_ASE_PARSER_INIT();
+
+    // Allocate enough storage for the normals
+    sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f ));
+    unsigned int index, faceIdx = UINT_MAX;
+
+    // FIXME: rewrite this and find out how to interpret the normals
+    // correctly. This is crap.
+
+    // Smooth the vertex and face normals together. The result
+    // will be edgy then, but otherwise everything would be soft ...
+    while (true)    {
+        if ('*' == *filePtr)    {
+            ++filePtr;
+            if (faceIdx != UINT_MAX && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17))  {
+                aiVector3D vNormal;
+                ParseLV4MeshFloatTriple(&vNormal.x,index);
+                if (faceIdx >=  sMesh.mFaces.size())
+                    continue;
+
+                // Make sure we assign it to the correct face
+                const ASE::Face& face = sMesh.mFaces[faceIdx];
+                if (index == face.mIndices[0])
+                    index = 0;
+                else if (index == face.mIndices[1])
+                    index = 1;
+                else if (index == face.mIndices[2])
+                    index = 2;
+                else    {
+                    DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
+                    continue;
+                }
+                // We'll renormalize later
+                sMesh.mNormals[faceIdx*3+index] += vNormal;
+                continue;
+            }
+            if (TokenMatch(filePtr,"MESH_FACENORMAL",15))   {
+                aiVector3D vNormal;
+                ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
+
+                if (faceIdx >= sMesh.mFaces.size()) {
+                    DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section");
+                    continue;
+                }
+
+                // We'll renormalize later
+                sMesh.mNormals[faceIdx*3] += vNormal;
+                sMesh.mNormals[faceIdx*3+1] += vNormal;
+                sMesh.mNormals[faceIdx*3+2] += vNormal;
+                continue;
+            }
+        }
+        AI_ASE_HANDLE_SECTION("3","*MESH_NORMALS");
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshFace(ASE::Face& out)
 {
-	// skip spaces and tabs
-	if(!SkipSpaces(&filePtr))
-	{
-		LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
-		SkipToNextToken();
-		return;
-	}
-
-	// parse the face index
-	out.iFace = strtoul10(filePtr,&filePtr);
-
-	// next character should be ':'
-	if(!SkipSpaces(&filePtr))
-	{
-		// FIX: there are some ASE files which haven't got : here ....
-		LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
-		SkipToNextToken();
-		return;
-	}
-	// FIX: There are some ASE files which haven't got ':' here
-	if(':' == *filePtr)++filePtr;
-
-	// Parse all mesh indices
-	for (unsigned int i = 0; i < 3;++i)
-	{
-		unsigned int iIndex = 0;
-		if(!SkipSpaces(&filePtr))
-		{
-			LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
-			SkipToNextToken();
-			return;
-		}
-		switch (*filePtr)
-		{
-		case 'A':
-		case 'a':
-			break;
-		case 'B':
-		case 'b':
-			iIndex = 1;
-			break;
-		case 'C':
-		case 'c':
-			iIndex = 2;
-			break;
-		default:
-			LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
-				"A,B or C expected [#3]");
-			SkipToNextToken();
-			return;
-		};
-		++filePtr;
-
-		// next character should be ':'
-		if(!SkipSpaces(&filePtr) || ':' != *filePtr)
-		{
-			LogWarning("Unable to parse *MESH_FACE Element: "
-				"Unexpected EOL. \':\' expected [#2]");
-			SkipToNextToken();
-			return;
-		}
-
-		++filePtr;
-		if(!SkipSpaces(&filePtr))
-		{
-			LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
-				"Vertex index ecpected [#4]");
-			SkipToNextToken();
-			return;
-		}
-		out.mIndices[iIndex] = strtoul10(filePtr,&filePtr);
-	}
-
-	// now we need to skip the AB, BC, CA blocks.
-	while (true)
-	{
-		if ('*' == *filePtr)break;
-		if (IsLineEnd(*filePtr))
-		{
-			//iLineNumber++;
-			return;
-		}
-		filePtr++;
-	}
-
-	// parse the smoothing group of the face
-	if (TokenMatch(filePtr,"*MESH_SMOOTHING",15))
-	{
-		if(!SkipSpaces(&filePtr))
-		{
-			LogWarning("Unable to parse *MESH_SMOOTHING Element: "
-				"Unexpected EOL. Smoothing group(s) expected [#5]");
-			SkipToNextToken();
-			return;
-		}
-
-		// Parse smoothing groups until we don't anymore see commas
-		// FIX: There needn't always be a value, sad but true
-		while (true)
-		{
-			if (*filePtr < '9' && *filePtr >= '0')
-			{
-				out.iSmoothGroup |= (1 << strtoul10(filePtr,&filePtr));
-			}
-			SkipSpaces(&filePtr);
-			if (',' != *filePtr)
-			{
-				break;
-			}
-			++filePtr;
-			SkipSpaces(&filePtr);
-		}
-	}
-
-	// *MESH_MTLID  is optional, too
-	while (true)
-	{
-		if ('*' == *filePtr)break;
-		if (IsLineEnd(*filePtr))
-		{
-			return;
-		}
-		filePtr++;
-	}
-
-	if (TokenMatch(filePtr,"*MESH_MTLID",11))
-	{
-		if(!SkipSpaces(&filePtr))
-		{
-			LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
-				"Material index expected [#6]");
-			SkipToNextToken();
-			return;
-		}
-		out.iMaterial = strtoul10(filePtr,&filePtr);
-	}
-	return;
+    // skip spaces and tabs
+    if(!SkipSpaces(&filePtr))
+    {
+        LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
+        SkipToNextToken();
+        return;
+    }
+
+    // parse the face index
+    out.iFace = strtoul10(filePtr,&filePtr);
+
+    // next character should be ':'
+    if(!SkipSpaces(&filePtr))
+    {
+        // FIX: there are some ASE files which haven't got : here ....
+        LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
+        SkipToNextToken();
+        return;
+    }
+    // FIX: There are some ASE files which haven't got ':' here
+    if(':' == *filePtr)++filePtr;
+
+    // Parse all mesh indices
+    for (unsigned int i = 0; i < 3;++i)
+    {
+        unsigned int iIndex = 0;
+        if(!SkipSpaces(&filePtr))
+        {
+            LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
+            SkipToNextToken();
+            return;
+        }
+        switch (*filePtr)
+        {
+        case 'A':
+        case 'a':
+            break;
+        case 'B':
+        case 'b':
+            iIndex = 1;
+            break;
+        case 'C':
+        case 'c':
+            iIndex = 2;
+            break;
+        default:
+            LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
+                "A,B or C expected [#3]");
+            SkipToNextToken();
+            return;
+        };
+        ++filePtr;
+
+        // next character should be ':'
+        if(!SkipSpaces(&filePtr) || ':' != *filePtr)
+        {
+            LogWarning("Unable to parse *MESH_FACE Element: "
+                "Unexpected EOL. \':\' expected [#2]");
+            SkipToNextToken();
+            return;
+        }
+
+        ++filePtr;
+        if(!SkipSpaces(&filePtr))
+        {
+            LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
+                "Vertex index ecpected [#4]");
+            SkipToNextToken();
+            return;
+        }
+        out.mIndices[iIndex] = strtoul10(filePtr,&filePtr);
+    }
+
+    // now we need to skip the AB, BC, CA blocks.
+    while (true)
+    {
+        if ('*' == *filePtr)break;
+        if (IsLineEnd(*filePtr))
+        {
+            //iLineNumber++;
+            return;
+        }
+        filePtr++;
+    }
+
+    // parse the smoothing group of the face
+    if (TokenMatch(filePtr,"*MESH_SMOOTHING",15))
+    {
+        if(!SkipSpaces(&filePtr))
+        {
+            LogWarning("Unable to parse *MESH_SMOOTHING Element: "
+                "Unexpected EOL. Smoothing group(s) expected [#5]");
+            SkipToNextToken();
+            return;
+        }
+
+        // Parse smoothing groups until we don't anymore see commas
+        // FIX: There needn't always be a value, sad but true
+        while (true)
+        {
+            if (*filePtr < '9' && *filePtr >= '0')
+            {
+                out.iSmoothGroup |= (1 << strtoul10(filePtr,&filePtr));
+            }
+            SkipSpaces(&filePtr);
+            if (',' != *filePtr)
+            {
+                break;
+            }
+            ++filePtr;
+            SkipSpaces(&filePtr);
+        }
+    }
+
+    // *MESH_MTLID  is optional, too
+    while (true)
+    {
+        if ('*' == *filePtr)break;
+        if (IsLineEnd(*filePtr))
+        {
+            return;
+        }
+        filePtr++;
+    }
+
+    if (TokenMatch(filePtr,"*MESH_MTLID",11))
+    {
+        if(!SkipSpaces(&filePtr))
+        {
+            LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
+                "Material index expected [#6]");
+            SkipToNextToken();
+            return;
+        }
+        out.iMaterial = strtoul10(filePtr,&filePtr);
+    }
+    return;
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshLongTriple(unsigned int* apOut)
 {
-	ai_assert(NULL != apOut);
+    ai_assert(NULL != apOut);
 
-	for (unsigned int i = 0; i < 3;++i)
-		ParseLV4MeshLong(apOut[i]);
+    for (unsigned int i = 0; i < 3;++i)
+        ParseLV4MeshLong(apOut[i]);
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut)
 {
-	ai_assert(NULL != apOut);
+    ai_assert(NULL != apOut);
 
-	// parse the index
-	ParseLV4MeshLong(rIndexOut);
+    // parse the index
+    ParseLV4MeshLong(rIndexOut);
 
-	// parse the three others
-	ParseLV4MeshLongTriple(apOut);
+    // parse the three others
+    ParseLV4MeshLongTriple(apOut);
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut)
 {
-	ai_assert(NULL != apOut);
+    ai_assert(NULL != apOut);
 
-	// parse the index
-	ParseLV4MeshLong(rIndexOut);
+    // parse the index
+    ParseLV4MeshLong(rIndexOut);
 
-	// parse the three others
-	ParseLV4MeshFloatTriple(apOut);
+    // parse the three others
+    ParseLV4MeshFloatTriple(apOut);
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshFloatTriple(float* apOut)
 {
-	ai_assert(NULL != apOut);
+    ai_assert(NULL != apOut);
 
-	for (unsigned int i = 0; i < 3;++i)
-		ParseLV4MeshFloat(apOut[i]);
+    for (unsigned int i = 0; i < 3;++i)
+        ParseLV4MeshFloat(apOut[i]);
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshFloat(float& fOut)
 {
-	// skip spaces and tabs
-	if(!SkipSpaces(&filePtr))
-	{
-		// LOG
-		LogWarning("Unable to parse float: unexpected EOL [#1]");
-		fOut = 0.0f;
-		++iLineNumber;
-		return;
-	}
-	// parse the first float
-	filePtr = fast_atoreal_move<float>(filePtr,fOut);
+    // skip spaces and tabs
+    if(!SkipSpaces(&filePtr))
+    {
+        // LOG
+        LogWarning("Unable to parse float: unexpected EOL [#1]");
+        fOut = 0.0f;
+        ++iLineNumber;
+        return;
+    }
+    // parse the first float
+    filePtr = fast_atoreal_move<float>(filePtr,fOut);
 }
 // ------------------------------------------------------------------------------------------------
 void Parser::ParseLV4MeshLong(unsigned int& iOut)
 {
-	// Skip spaces and tabs
-	if(!SkipSpaces(&filePtr))
-	{
-		// LOG
-		LogWarning("Unable to parse long: unexpected EOL [#1]");
-		iOut = 0;
-		++iLineNumber;
-		return;
-	}
-	// parse the value
-	iOut = strtoul10(filePtr,&filePtr);
+    // Skip spaces and tabs
+    if(!SkipSpaces(&filePtr))
+    {
+        // LOG
+        LogWarning("Unable to parse long: unexpected EOL [#1]");
+        iOut = 0;
+        ++iLineNumber;
+        return;
+    }
+    // parse the value
+    iOut = strtoul10(filePtr,&filePtr);
 }
 
 #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER

+ 457 - 457
code/ASEParser.h

@@ -60,8 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // ASE is quite similar to 3ds. We can reuse some structures
 #include "3DSLoader.h"
 
-namespace Assimp	{
-namespace ASE	{
+namespace Assimp    {
+namespace ASE   {
 
 using namespace D3DS;
 
@@ -69,121 +69,121 @@ using namespace D3DS;
 /** Helper structure representing an ASE material */
 struct Material : public D3DS::Material
 {
-	//! Default constructor
-	Material() : pcInstance(NULL), bNeed (false)
-	{}
+    //! Default constructor
+    Material() : pcInstance(NULL), bNeed (false)
+    {}
 
-	//! Contains all sub materials of this material
-	std::vector<Material> avSubMaterials;
+    //! Contains all sub materials of this material
+    std::vector<Material> avSubMaterials;
 
-	//! aiMaterial object
-	aiMaterial* pcInstance;
+    //! aiMaterial object
+    aiMaterial* pcInstance;
 
-	//! Can we remove this material?
-	bool bNeed;
+    //! Can we remove this material?
+    bool bNeed;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file face */
 struct Face : public FaceWithSmoothingGroup
 {
-	//! Default constructor. Initializes everything with 0
-	Face()
-	{
-		mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0;
-		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
-		{
-			amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0;
-		}
+    //! Default constructor. Initializes everything with 0
+    Face()
+    {
+        mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0;
+        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
+        {
+            amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0;
+        }
 
-		iMaterial = DEFAULT_MATINDEX;
-		iFace = 0;
-	}
+        iMaterial = DEFAULT_MATINDEX;
+        iFace = 0;
+    }
 
-	//! special value to indicate that no material index has
-	//! been assigned to a face. The default material index
-	//! will replace this value later.
-	static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF;
+    //! special value to indicate that no material index has
+    //! been assigned to a face. The default material index
+    //! will replace this value later.
+    static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF;
 
 
 
-	//! Indices into each list of texture coordinates
-	unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3];
+    //! Indices into each list of texture coordinates
+    unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3];
 
-	//! Index into the list of vertex colors
-	unsigned int mColorIndices[3];
+    //! Index into the list of vertex colors
+    unsigned int mColorIndices[3];
 
-	//! (Sub)Material index to be assigned to this face
-	unsigned int iMaterial;
+    //! (Sub)Material index to be assigned to this face
+    unsigned int iMaterial;
 
-	//! Index of the face. It is not specified whether it is
-	//! a requirement of the file format that all faces are
-	//! written in sequential order, so we have to expect this case
-	unsigned int iFace;
+    //! Index of the face. It is not specified whether it is
+    //! a requirement of the file format that all faces are
+    //! written in sequential order, so we have to expect this case
+    unsigned int iFace;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file bone */
 struct Bone
 {
-	//! Constructor
-	Bone()
-	{
-		static int iCnt = 0;
-
-		// Generate a default name for the bone
-		char szTemp[128];
-		::sprintf(szTemp,"UNNAMED_%i",iCnt++);
-		mName = szTemp;
-	}
-
-	//! Construction from an existing name
-	Bone( const std::string& name)
-		:	mName	(name)
-	{}
-
-	//! Name of the bone
-	std::string mName;
+    //! Constructor
+    Bone()
+    {
+        static int iCnt = 0;
+
+        // Generate a default name for the bone
+        char szTemp[128];
+        ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
+        mName = szTemp;
+    }
+
+    //! Construction from an existing name
+    Bone( const std::string& name)
+        :   mName   (name)
+    {}
+
+    //! Name of the bone
+    std::string mName;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file bone vertex */
 struct BoneVertex
 {
-	//! Bone and corresponding vertex weight.
-	//! -1 for unrequired bones ....
-	std::vector<std::pair<int,float> > mBoneWeights;
+    //! Bone and corresponding vertex weight.
+    //! -1 for unrequired bones ....
+    std::vector<std::pair<int,float> > mBoneWeights;
 
-	//! Position of the bone vertex.
-	//! MUST be identical to the vertex position
-	//aiVector3D mPosition;
+    //! Position of the bone vertex.
+    //! MUST be identical to the vertex position
+    //aiVector3D mPosition;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file animation */
 struct Animation
 {
-	enum Type
-	{
-		TRACK   = 0x0,
-		BEZIER  = 0x1,
-		TCB		= 0x2
-	} mRotationType, mScalingType, mPositionType;
+    enum Type
+    {
+        TRACK   = 0x0,
+        BEZIER  = 0x1,
+        TCB     = 0x2
+    } mRotationType, mScalingType, mPositionType;
 
-	Animation()
-		:	mRotationType	(TRACK)
-		,	mScalingType	(TRACK)
-		,	mPositionType	(TRACK)
-	{}
+    Animation()
+        :   mRotationType   (TRACK)
+        ,   mScalingType    (TRACK)
+        ,   mPositionType   (TRACK)
+    {}
 
-	//! List of track rotation keyframes
-	std::vector< aiQuatKey > akeyRotations;
+    //! List of track rotation keyframes
+    std::vector< aiQuatKey > akeyRotations;
 
-	//! List of track position keyframes
-	std::vector< aiVectorKey > akeyPositions;
+    //! List of track position keyframes
+    std::vector< aiVectorKey > akeyPositions;
 
-	//! List of track scaling keyframes
-	std::vector< aiVectorKey > akeyScaling;
+    //! List of track scaling keyframes
+    std::vector< aiVectorKey > akeyScaling;
 
 };
 
@@ -191,175 +191,175 @@ struct Animation
 /** Helper structure to represent the inheritance information of an ASE node */
 struct InheritanceInfo
 {
-	//! Default constructor
-	InheritanceInfo()
-	{
-		// set the inheritance flag for all axes by default to true
-		for (unsigned int i = 0; i < 3;++i)
-			abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
-	}
-
-	//! Inherit the parent's position?, axis order is x,y,z
-	bool abInheritPosition[3];
-
-	//! Inherit the parent's rotation?, axis order is x,y,z
-	bool abInheritRotation[3];
-
-	//! Inherit the parent's scaling?, axis order is x,y,z
-	bool abInheritScaling[3];
+    //! Default constructor
+    InheritanceInfo()
+    {
+        // set the inheritance flag for all axes by default to true
+        for (unsigned int i = 0; i < 3;++i)
+            abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
+    }
+
+    //! Inherit the parent's position?, axis order is x,y,z
+    bool abInheritPosition[3];
+
+    //! Inherit the parent's rotation?, axis order is x,y,z
+    bool abInheritRotation[3];
+
+    //! Inherit the parent's scaling?, axis order is x,y,z
+    bool abInheritScaling[3];
 };
 
 // ---------------------------------------------------------------------------
 /** Represents an ASE file node. Base class for mesh, light and cameras */
 struct BaseNode
 {
-	enum Type {Light, Camera, Mesh, Dummy} mType;
+    enum Type {Light, Camera, Mesh, Dummy} mType;
 
-	//! Constructor. Creates a default name for the node
-	BaseNode(Type _mType)
-		: mType			(_mType)
-		, mProcessed	(false)
-	{
-		// generate a default name for the  node
-		static int iCnt = 0;
-		char szTemp[128]; // should be sufficiently large
-		::sprintf(szTemp,"UNNAMED_%i",iCnt++);
-		mName = szTemp;
+    //! Constructor. Creates a default name for the node
+    BaseNode(Type _mType)
+        : mType         (_mType)
+        , mProcessed    (false)
+    {
+        // generate a default name for the  node
+        static int iCnt = 0;
+        char szTemp[128]; // should be sufficiently large
+        ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
+        mName = szTemp;
 
-		// Set mTargetPosition to qnan
-		const float qnan = get_qnan();
-		mTargetPosition.x = qnan;
-	}
+        // Set mTargetPosition to qnan
+        const float qnan = get_qnan();
+        mTargetPosition.x = qnan;
+    }
 
-	//! Name of the mesh
-	std::string mName;
+    //! Name of the mesh
+    std::string mName;
 
-	//! Name of the parent of the node
-	//! "" if there is no parent ...
-	std::string mParent;
+    //! Name of the parent of the node
+    //! "" if there is no parent ...
+    std::string mParent;
 
-	//! Transformation matrix of the node
-	aiMatrix4x4 mTransform;
+    //! Transformation matrix of the node
+    aiMatrix4x4 mTransform;
 
-	//! Target position (target lights and cameras)
-	aiVector3D mTargetPosition;
+    //! Target position (target lights and cameras)
+    aiVector3D mTargetPosition;
 
-	//! Specifies which axes transformations a node inherits
-	//! from its parent ...
-	InheritanceInfo inherit;
+    //! Specifies which axes transformations a node inherits
+    //! from its parent ...
+    InheritanceInfo inherit;
 
-	//! Animation channels for the node
-	Animation mAnim;
+    //! Animation channels for the node
+    Animation mAnim;
 
-	//! Needed for lights and cameras: target animation channel
-	//! Should contain position keys only.
-	Animation mTargetAnim;
+    //! Needed for lights and cameras: target animation channel
+    //! Should contain position keys only.
+    Animation mTargetAnim;
 
-	bool mProcessed;
+    bool mProcessed;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file mesh */
 struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode
 {
-	//! Constructor.
-	Mesh()
-		: BaseNode	(BaseNode::Mesh)
-		, bSkip		(false)
-	{
-		// use 2 texture vertex components by default
-		for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
-			this->mNumUVComponents[c] = 2;
+    //! Constructor.
+    Mesh()
+        : BaseNode  (BaseNode::Mesh)
+        , bSkip     (false)
+    {
+        // use 2 texture vertex components by default
+        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
+            this->mNumUVComponents[c] = 2;
 
-		// setup the default material index by default
-		iMaterialIndex = Face::DEFAULT_MATINDEX;
-	}
+        // setup the default material index by default
+        iMaterialIndex = Face::DEFAULT_MATINDEX;
+    }
 
-	//! List of all texture coordinate sets
-	std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+    //! List of all texture coordinate sets
+    std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 
-	//! List of all vertex color sets.
-	std::vector<aiColor4D> mVertexColors;
+    //! List of all vertex color sets.
+    std::vector<aiColor4D> mVertexColors;
 
-	//! List of all bone vertices
-	std::vector<BoneVertex> mBoneVertices;
+    //! List of all bone vertices
+    std::vector<BoneVertex> mBoneVertices;
 
-	//! List of all bones
-	std::vector<Bone> mBones;
+    //! List of all bones
+    std::vector<Bone> mBones;
 
-	//! Material index of the mesh
-	unsigned int iMaterialIndex;
+    //! Material index of the mesh
+    unsigned int iMaterialIndex;
 
-	//! Number of vertex components for each UVW set
-	unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+    //! Number of vertex components for each UVW set
+    unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 
-	//! used internally
-	bool bSkip;
+    //! used internally
+    bool bSkip;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE light source */
 struct Light : public BaseNode
 {
-	enum LightType
-	{
-		OMNI,
-		TARGET,
-		FREE,
-		DIRECTIONAL
-	};
-
-	//! Constructor.
-	Light()
-		: BaseNode	 (BaseNode::Light)
-		, mLightType (OMNI)
-		, mColor	 (1.f,1.f,1.f)
-		, mIntensity (1.f) // light is white by default
-		, mAngle	 (45.f)
-		, mFalloff	 (0.f)
-	{
-	}
-
-	LightType mLightType;
-	aiColor3D mColor;
-	float mIntensity;
-	float mAngle; // in degrees
-	float mFalloff;
+    enum LightType
+    {
+        OMNI,
+        TARGET,
+        FREE,
+        DIRECTIONAL
+    };
+
+    //! Constructor.
+    Light()
+        : BaseNode   (BaseNode::Light)
+        , mLightType (OMNI)
+        , mColor     (1.f,1.f,1.f)
+        , mIntensity (1.f) // light is white by default
+        , mAngle     (45.f)
+        , mFalloff   (0.f)
+    {
+    }
+
+    LightType mLightType;
+    aiColor3D mColor;
+    float mIntensity;
+    float mAngle; // in degrees
+    float mFalloff;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE camera */
 struct Camera : public BaseNode
 {
-	enum CameraType
-	{
-		FREE,
-		TARGET
-	};
-
-	//! Constructor
-	Camera()
-		: BaseNode	  (BaseNode::Camera)
-		, mFOV        (0.75f)   // in radians
-		, mNear       (0.1f)
-		, mFar        (1000.f)  // could be zero
-		, mCameraType (FREE)
-	{
-	}
-
-	float mFOV, mNear, mFar;
-	CameraType mCameraType;
+    enum CameraType
+    {
+        FREE,
+        TARGET
+    };
+
+    //! Constructor
+    Camera()
+        : BaseNode    (BaseNode::Camera)
+        , mFOV        (0.75f)   // in radians
+        , mNear       (0.1f)
+        , mFar        (1000.f)  // could be zero
+        , mCameraType (FREE)
+    {
+    }
+
+    float mFOV, mNear, mFar;
+    CameraType mCameraType;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE helper object (dummy) */
 struct Dummy : public BaseNode
 {
-	//! Constructor
-	Dummy()
-		: BaseNode	(BaseNode::Dummy)
-	{
-	}
+    //! Constructor
+    Dummy()
+        : BaseNode  (BaseNode::Dummy)
+    {
+    }
 };
 
 // Parameters to Parser::Parse()
@@ -367,8 +367,8 @@ struct Dummy : public BaseNode
 #define AI_ASE_OLD_FILE_FORMAT 110
 
 // Internally we're a little bit more tolerant
-#define AI_ASE_IS_NEW_FILE_FORMAT()	(iFileFormat >= 200)
-#define AI_ASE_IS_OLD_FILE_FORMAT()	(iFileFormat < 200)
+#define AI_ASE_IS_NEW_FILE_FORMAT() (iFileFormat >= 200)
+#define AI_ASE_IS_OLD_FILE_FORMAT() (iFileFormat < 200)
 
 // -------------------------------------------------------------------------------
 /** \brief Class to parse ASE files
@@ -378,288 +378,288 @@ class Parser
 
 private:
 
-	Parser() {}
+    Parser() {}
 
 public:
 
-	// -------------------------------------------------------------------
-	//! Construct a parser from a given input file which is
-	//! guaranted to be terminated with zero.
-	//! @param szFile Input file
-	//! @param fileFormatDefault Assumed file format version. If the
-	//!   file format is specified in the file the new value replaces
-	//!   the default value.
-	Parser (const char* szFile, unsigned int fileFormatDefault);
+    // -------------------------------------------------------------------
+    //! Construct a parser from a given input file which is
+    //! guaranted to be terminated with zero.
+    //! @param szFile Input file
+    //! @param fileFormatDefault Assumed file format version. If the
+    //!   file format is specified in the file the new value replaces
+    //!   the default value.
+    Parser (const char* szFile, unsigned int fileFormatDefault);
 
-	// -------------------------------------------------------------------
-	//! Parses the file into the parsers internal representation
-	void Parse();
+    // -------------------------------------------------------------------
+    //! Parses the file into the parsers internal representation
+    void Parse();
 
 
 private:
 
-	// -------------------------------------------------------------------
-	//! Parse the *SCENE block in a file
-	void ParseLV1SceneBlock();
-
-	// -------------------------------------------------------------------
-	//! Parse the *MESH_SOFTSKINVERTS block in a file
-	void ParseLV1SoftSkinBlock();
-
-	// -------------------------------------------------------------------
-	//! Parse the *MATERIAL_LIST block in a file
-	void ParseLV1MaterialListBlock();
-
-	// -------------------------------------------------------------------
-	//! Parse a *<xxx>OBJECT block in a file
-	//! \param mesh Node to be filled
-	void ParseLV1ObjectBlock(BaseNode& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MATERIAL blocks in a material list
-	//! \param mat Material structure to be filled
-	void ParseLV2MaterialBlock(Material& mat);
-
-	// -------------------------------------------------------------------
-	//! Parse a *NODE_TM block in a file
-	//! \param mesh Node (!) object to be filled
-	void ParseLV2NodeTransformBlock(BaseNode& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *TM_ANIMATION block in a file
-	//! \param mesh Mesh object to be filled
-	void ParseLV2AnimationBlock(BaseNode& mesh);
-	void ParseLV3PosAnimationBlock(ASE::Animation& anim);
-	void ParseLV3ScaleAnimationBlock(ASE::Animation& anim);
-	void ParseLV3RotAnimationBlock(ASE::Animation& anim);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH block in a file
-	//! \param mesh Mesh object to be filled
-	void ParseLV2MeshBlock(Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *LIGHT_SETTINGS block in a file
-	//! \param light Light object to be filled
-	void ParseLV2LightSettingsBlock(Light& light);
-
-	// -------------------------------------------------------------------
-	//! Parse a *CAMERA_SETTINGS block in a file
-	//! \param cam Camera object to be filled
-	void ParseLV2CameraSettingsBlock(Camera& cam);
-
-	// -------------------------------------------------------------------
-	//! Parse the *MAP_XXXXXX blocks in a material
-	//! \param map Texture structure to be filled
-	void ParseLV3MapBlock(Texture& map);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_VERTEX_LIST block in a file
-	//! \param iNumVertices Value of *MESH_NUMVERTEX, if present.
-	//! Otherwise zero. This is used to check the consistency of the file.
-	//! A warning is sent to the logger if the validations fails.
-	//! \param mesh Mesh object to be filled
-	void ParseLV3MeshVertexListBlock(
-		unsigned int iNumVertices,Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_FACE_LIST block in a file
-	//! \param iNumFaces Value of *MESH_NUMFACES, if present.
-	//! Otherwise zero. This is used to check the consistency of the file.
-	//! A warning is sent to the logger if the validations fails.
-	//! \param mesh Mesh object to be filled
-	void ParseLV3MeshFaceListBlock(
-		unsigned int iNumFaces,Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_TVERT_LIST block in a file
-	//! \param iNumVertices Value of *MESH_NUMTVERTEX, if present.
-	//! Otherwise zero. This is used to check the consistency of the file.
-	//! A warning is sent to the logger if the validations fails.
-	//! \param mesh Mesh object to be filled
-	//! \param iChannel Output UVW channel
-	void ParseLV3MeshTListBlock(
-		unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_TFACELIST block in a file
-	//! \param iNumFaces Value of *MESH_NUMTVFACES, if present.
-	//! Otherwise zero. This is used to check the consistency of the file.
-	//! A warning is sent to the logger if the validations fails.
-	//! \param mesh Mesh object to be filled
-	//! \param iChannel Output UVW channel
-	void ParseLV3MeshTFaceListBlock(
-		unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0);
-
-	// -------------------------------------------------------------------
-	//! Parse an additional mapping channel
-	//! (specified via *MESH_MAPPINGCHANNEL)
-	//! \param iChannel Channel index to be filled
-	//! \param mesh Mesh object to be filled
-	void ParseLV3MappingChannel(
-		unsigned int iChannel, Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_CVERTLIST block in a file
-	//! \param iNumVertices Value of *MESH_NUMCVERTEX, if present.
-	//! Otherwise zero. This is used to check the consistency of the file.
-	//! A warning is sent to the logger if the validations fails.
-	//! \param mesh Mesh object to be filled
-	void ParseLV3MeshCListBlock(
-		unsigned int iNumVertices, Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_CFACELIST block in a file
-	//! \param iNumFaces Value of *MESH_NUMCVFACES, if present.
-	//! Otherwise zero. This is used to check the consistency of the file.
-	//! A warning is sent to the logger if the validations fails.
-	//! \param mesh Mesh object to be filled
-	void ParseLV3MeshCFaceListBlock(
-		unsigned int iNumFaces, Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_NORMALS block in a file
-	//! \param mesh Mesh object to be filled
-	void ParseLV3MeshNormalListBlock(Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_WEIGHTSblock in a file
-	//! \param mesh Mesh object to be filled
-	void ParseLV3MeshWeightsBlock(Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse the bone list of a file
-	//! \param mesh Mesh object to be filled
-	//! \param iNumBones Number of bones in the mesh
-	void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse the bone vertices list of a file
-	//! \param mesh Mesh object to be filled
-	//! \param iNumVertices Number of vertices to be parsed
-	void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_FACE block in a file
-	//! \param out receive the face data
-	void ParseLV4MeshFace(ASE::Face& out);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_VERT block in a file
-	//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL  ...)
-	//! \param apOut Output buffer (3 floats)
-	//! \param rIndexOut Output index
-	void ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_VERT block in a file
-	//! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL  ...)
-	//! \param apOut Output buffer (3 floats)
-	void ParseLV4MeshFloatTriple(float* apOut);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_TFACE block in a file
-	//! (also works for MESH_CFACE)
-	//! \param apOut Output buffer (3 ints)
-	//! \param rIndexOut Output index
-	void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut);
-
-	// -------------------------------------------------------------------
-	//! Parse a *MESH_TFACE block in a file
-	//! (also works for MESH_CFACE)
-	//! \param apOut Output buffer (3 ints)
-	void ParseLV4MeshLongTriple(unsigned int* apOut);
-
-	// -------------------------------------------------------------------
-	//! Parse a single float element
-	//! \param fOut Output float
-	void ParseLV4MeshFloat(float& fOut);
-
-	// -------------------------------------------------------------------
-	//! Parse a single int element
-	//! \param iOut Output integer
-	void ParseLV4MeshLong(unsigned int& iOut);
-
-	// -------------------------------------------------------------------
-	//! Skip everything to the next: '*' or '\0'
-	bool SkipToNextToken();
-
-	// -------------------------------------------------------------------
-	//! Skip the current section until the token after the closing }.
-	//! This function handles embedded subsections correctly
-	bool SkipSection();
-
-	// -------------------------------------------------------------------
-	//! Output a warning to the logger
-	//! \param szWarn Warn message
-	void LogWarning(const char* szWarn);
-
-	// -------------------------------------------------------------------
-	//! Output a message to the logger
-	//! \param szWarn Message
-	void LogInfo(const char* szWarn);
-
-	// -------------------------------------------------------------------
-	//! Output an error to the logger
-	//! \param szWarn Error message
-	AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX;
-
-	// -------------------------------------------------------------------
-	//! Parse a string, enclosed in double quotation marks
-	//! \param out Output string
-	//! \param szName Name of the enclosing element -> used in error
-	//! messages.
-	//! \return false if an error occured
-	bool ParseString(std::string& out,const char* szName);
+    // -------------------------------------------------------------------
+    //! Parse the *SCENE block in a file
+    void ParseLV1SceneBlock();
+
+    // -------------------------------------------------------------------
+    //! Parse the *MESH_SOFTSKINVERTS block in a file
+    void ParseLV1SoftSkinBlock();
+
+    // -------------------------------------------------------------------
+    //! Parse the *MATERIAL_LIST block in a file
+    void ParseLV1MaterialListBlock();
+
+    // -------------------------------------------------------------------
+    //! Parse a *<xxx>OBJECT block in a file
+    //! \param mesh Node to be filled
+    void ParseLV1ObjectBlock(BaseNode& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MATERIAL blocks in a material list
+    //! \param mat Material structure to be filled
+    void ParseLV2MaterialBlock(Material& mat);
+
+    // -------------------------------------------------------------------
+    //! Parse a *NODE_TM block in a file
+    //! \param mesh Node (!) object to be filled
+    void ParseLV2NodeTransformBlock(BaseNode& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *TM_ANIMATION block in a file
+    //! \param mesh Mesh object to be filled
+    void ParseLV2AnimationBlock(BaseNode& mesh);
+    void ParseLV3PosAnimationBlock(ASE::Animation& anim);
+    void ParseLV3ScaleAnimationBlock(ASE::Animation& anim);
+    void ParseLV3RotAnimationBlock(ASE::Animation& anim);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH block in a file
+    //! \param mesh Mesh object to be filled
+    void ParseLV2MeshBlock(Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *LIGHT_SETTINGS block in a file
+    //! \param light Light object to be filled
+    void ParseLV2LightSettingsBlock(Light& light);
+
+    // -------------------------------------------------------------------
+    //! Parse a *CAMERA_SETTINGS block in a file
+    //! \param cam Camera object to be filled
+    void ParseLV2CameraSettingsBlock(Camera& cam);
+
+    // -------------------------------------------------------------------
+    //! Parse the *MAP_XXXXXX blocks in a material
+    //! \param map Texture structure to be filled
+    void ParseLV3MapBlock(Texture& map);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_VERTEX_LIST block in a file
+    //! \param iNumVertices Value of *MESH_NUMVERTEX, if present.
+    //! Otherwise zero. This is used to check the consistency of the file.
+    //! A warning is sent to the logger if the validations fails.
+    //! \param mesh Mesh object to be filled
+    void ParseLV3MeshVertexListBlock(
+        unsigned int iNumVertices,Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_FACE_LIST block in a file
+    //! \param iNumFaces Value of *MESH_NUMFACES, if present.
+    //! Otherwise zero. This is used to check the consistency of the file.
+    //! A warning is sent to the logger if the validations fails.
+    //! \param mesh Mesh object to be filled
+    void ParseLV3MeshFaceListBlock(
+        unsigned int iNumFaces,Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_TVERT_LIST block in a file
+    //! \param iNumVertices Value of *MESH_NUMTVERTEX, if present.
+    //! Otherwise zero. This is used to check the consistency of the file.
+    //! A warning is sent to the logger if the validations fails.
+    //! \param mesh Mesh object to be filled
+    //! \param iChannel Output UVW channel
+    void ParseLV3MeshTListBlock(
+        unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_TFACELIST block in a file
+    //! \param iNumFaces Value of *MESH_NUMTVFACES, if present.
+    //! Otherwise zero. This is used to check the consistency of the file.
+    //! A warning is sent to the logger if the validations fails.
+    //! \param mesh Mesh object to be filled
+    //! \param iChannel Output UVW channel
+    void ParseLV3MeshTFaceListBlock(
+        unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0);
+
+    // -------------------------------------------------------------------
+    //! Parse an additional mapping channel
+    //! (specified via *MESH_MAPPINGCHANNEL)
+    //! \param iChannel Channel index to be filled
+    //! \param mesh Mesh object to be filled
+    void ParseLV3MappingChannel(
+        unsigned int iChannel, Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_CVERTLIST block in a file
+    //! \param iNumVertices Value of *MESH_NUMCVERTEX, if present.
+    //! Otherwise zero. This is used to check the consistency of the file.
+    //! A warning is sent to the logger if the validations fails.
+    //! \param mesh Mesh object to be filled
+    void ParseLV3MeshCListBlock(
+        unsigned int iNumVertices, Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_CFACELIST block in a file
+    //! \param iNumFaces Value of *MESH_NUMCVFACES, if present.
+    //! Otherwise zero. This is used to check the consistency of the file.
+    //! A warning is sent to the logger if the validations fails.
+    //! \param mesh Mesh object to be filled
+    void ParseLV3MeshCFaceListBlock(
+        unsigned int iNumFaces, Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_NORMALS block in a file
+    //! \param mesh Mesh object to be filled
+    void ParseLV3MeshNormalListBlock(Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_WEIGHTSblock in a file
+    //! \param mesh Mesh object to be filled
+    void ParseLV3MeshWeightsBlock(Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse the bone list of a file
+    //! \param mesh Mesh object to be filled
+    //! \param iNumBones Number of bones in the mesh
+    void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse the bone vertices list of a file
+    //! \param mesh Mesh object to be filled
+    //! \param iNumVertices Number of vertices to be parsed
+    void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_FACE block in a file
+    //! \param out receive the face data
+    void ParseLV4MeshFace(ASE::Face& out);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_VERT block in a file
+    //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL  ...)
+    //! \param apOut Output buffer (3 floats)
+    //! \param rIndexOut Output index
+    void ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_VERT block in a file
+    //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL  ...)
+    //! \param apOut Output buffer (3 floats)
+    void ParseLV4MeshFloatTriple(float* apOut);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_TFACE block in a file
+    //! (also works for MESH_CFACE)
+    //! \param apOut Output buffer (3 ints)
+    //! \param rIndexOut Output index
+    void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut);
+
+    // -------------------------------------------------------------------
+    //! Parse a *MESH_TFACE block in a file
+    //! (also works for MESH_CFACE)
+    //! \param apOut Output buffer (3 ints)
+    void ParseLV4MeshLongTriple(unsigned int* apOut);
+
+    // -------------------------------------------------------------------
+    //! Parse a single float element
+    //! \param fOut Output float
+    void ParseLV4MeshFloat(float& fOut);
+
+    // -------------------------------------------------------------------
+    //! Parse a single int element
+    //! \param iOut Output integer
+    void ParseLV4MeshLong(unsigned int& iOut);
+
+    // -------------------------------------------------------------------
+    //! Skip everything to the next: '*' or '\0'
+    bool SkipToNextToken();
+
+    // -------------------------------------------------------------------
+    //! Skip the current section until the token after the closing }.
+    //! This function handles embedded subsections correctly
+    bool SkipSection();
+
+    // -------------------------------------------------------------------
+    //! Output a warning to the logger
+    //! \param szWarn Warn message
+    void LogWarning(const char* szWarn);
+
+    // -------------------------------------------------------------------
+    //! Output a message to the logger
+    //! \param szWarn Message
+    void LogInfo(const char* szWarn);
+
+    // -------------------------------------------------------------------
+    //! Output an error to the logger
+    //! \param szWarn Error message
+    AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX;
+
+    // -------------------------------------------------------------------
+    //! Parse a string, enclosed in double quotation marks
+    //! \param out Output string
+    //! \param szName Name of the enclosing element -> used in error
+    //! messages.
+    //! \return false if an error occured
+    bool ParseString(std::string& out,const char* szName);
 
 public:
 
-	//! Pointer to current data
-	const char* filePtr;
+    //! Pointer to current data
+    const char* filePtr;
 
-	//! background color to be passed to the viewer
-	//! QNAN if none was found
-	aiColor3D m_clrBackground;
+    //! background color to be passed to the viewer
+    //! QNAN if none was found
+    aiColor3D m_clrBackground;
 
-	//! Base ambient color to be passed to all materials
-	//! QNAN if none was found
-	aiColor3D m_clrAmbient;
+    //! Base ambient color to be passed to all materials
+    //! QNAN if none was found
+    aiColor3D m_clrAmbient;
 
-	//! List of all materials found in the file
-	std::vector<Material> m_vMaterials;
+    //! List of all materials found in the file
+    std::vector<Material> m_vMaterials;
 
-	//! List of all meshes found in the file
-	std::vector<Mesh> m_vMeshes;
+    //! List of all meshes found in the file
+    std::vector<Mesh> m_vMeshes;
 
-	//! List of all dummies found in the file
-	std::vector<Dummy> m_vDummies;
+    //! List of all dummies found in the file
+    std::vector<Dummy> m_vDummies;
 
-	//! List of all lights found in the file
-	std::vector<Light> m_vLights;
+    //! List of all lights found in the file
+    std::vector<Light> m_vLights;
 
-	//! List of all cameras found in the file
-	std::vector<Camera> m_vCameras;
+    //! List of all cameras found in the file
+    std::vector<Camera> m_vCameras;
 
-	//! Current line in the file
-	unsigned int iLineNumber;
+    //! Current line in the file
+    unsigned int iLineNumber;
 
-	//! First frame
-	unsigned int iFirstFrame;
+    //! First frame
+    unsigned int iFirstFrame;
 
-	//! Last frame
-	unsigned int iLastFrame;
+    //! Last frame
+    unsigned int iLastFrame;
 
-	//! Frame speed - frames per second
-	unsigned int iFrameSpeed;
+    //! Frame speed - frames per second
+    unsigned int iFrameSpeed;
 
-	//! Ticks per frame
-	unsigned int iTicksPerFrame;
+    //! Ticks per frame
+    unsigned int iTicksPerFrame;
 
-	//! true if the last character read was an end-line character
-	bool bLastWasEndLine;
+    //! true if the last character read was an end-line character
+    bool bLastWasEndLine;
 
-	//! File format version
-	unsigned int iFileFormat;
+    //! File format version
+    unsigned int iFileFormat;
 };
 
 

+ 590 - 590
code/AssbinExporter.cpp

@@ -50,9 +50,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <boost/static_assert.hpp>
 
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#	include <zlib.h>
+#   include <zlib.h>
 #else
-#	include "../contrib/zlib/zlib.h"
+#   include "../contrib/zlib/zlib.h"
 #endif
 
 #include <time.h>
@@ -63,12 +63,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-namespace Assimp	{
+namespace Assimp    {
 
 template <typename T>
 size_t Write(IOStream * stream, const T& v)
 {
-	return stream->Write( &v, sizeof(T), 1 );
+    return stream->Write( &v, sizeof(T), 1 );
 }
 
 
@@ -77,10 +77,10 @@ size_t Write(IOStream * stream, const T& v)
 template <>
 inline size_t Write<aiString>(IOStream * stream, const aiString& s)
 {
-	const size_t s2 = (uint32_t)s.length;
-	stream->Write(&s,4,1);
-	stream->Write(s.data,s2,1);
-	return s2+4;
+    const size_t s2 = (uint32_t)s.length;
+    stream->Write(&s,4,1);
+    stream->Write(s.data,s2,1);
+    return s2+4;
 }
 
 // -----------------------------------------------------------------------------------
@@ -88,14 +88,14 @@ inline size_t Write<aiString>(IOStream * stream, const aiString& s)
 template <>
 inline size_t Write<unsigned int>(IOStream * stream, const unsigned int& w)
 {
-	const uint32_t t = (uint32_t)w;
-	if (w > t) {
-		// this shouldn't happen, integers in Assimp data structures never exceed 2^32
-		throw new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
-	}
-
-	stream->Write(&t,4,1);
-	return 4;
+    const uint32_t t = (uint32_t)w;
+    if (w > t) {
+        // this shouldn't happen, integers in Assimp data structures never exceed 2^32
+        throw new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
+    }
+
+    stream->Write(&t,4,1);
+    return 4;
 }
 
 // -----------------------------------------------------------------------------------
@@ -103,9 +103,9 @@ inline size_t Write<unsigned int>(IOStream * stream, const unsigned int& w)
 template <>
 inline size_t Write<uint16_t>(IOStream * stream, const uint16_t& w)
 {
-	BOOST_STATIC_ASSERT(sizeof(uint16_t)==2);
-	stream->Write(&w,2,1);
-	return 2;
+    BOOST_STATIC_ASSERT(sizeof(uint16_t)==2);
+    stream->Write(&w,2,1);
+    return 2;
 }
 
 // -----------------------------------------------------------------------------------
@@ -113,9 +113,9 @@ inline size_t Write<uint16_t>(IOStream * stream, const uint16_t& w)
 template <>
 inline size_t Write<float>(IOStream * stream, const float& f)
 {
-	BOOST_STATIC_ASSERT(sizeof(float)==4);
-	stream->Write(&f,4,1);
-	return 4;
+    BOOST_STATIC_ASSERT(sizeof(float)==4);
+    stream->Write(&f,4,1);
+    return 4;
 }
 
 // -----------------------------------------------------------------------------------
@@ -123,9 +123,9 @@ inline size_t Write<float>(IOStream * stream, const float& f)
 template <>
 inline size_t Write<double>(IOStream * stream, const double& f)
 {
-	BOOST_STATIC_ASSERT(sizeof(double)==8);
-	stream->Write(&f,8,1);
-	return 8;
+    BOOST_STATIC_ASSERT(sizeof(double)==8);
+    stream->Write(&f,8,1);
+    return 8;
 }
 
 // -----------------------------------------------------------------------------------
@@ -133,10 +133,10 @@ inline size_t Write<double>(IOStream * stream, const double& f)
 template <>
 inline size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v)
 {
-	size_t t = Write<float>(stream,v.x);
-	t += Write<float>(stream,v.y);
-	t += Write<float>(stream,v.z);
-	return t;
+    size_t t = Write<float>(stream,v.x);
+    t += Write<float>(stream,v.y);
+    t += Write<float>(stream,v.z);
+    return t;
 }
 
 // -----------------------------------------------------------------------------------
@@ -144,11 +144,11 @@ inline size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v)
 template <>
 inline size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v)
 {
-	size_t t = Write<float>(stream,v.r);
-	t += Write<float>(stream,v.g);
-	t += Write<float>(stream,v.b);
-	t += Write<float>(stream,v.a);
-	return t;
+    size_t t = Write<float>(stream,v.r);
+    t += Write<float>(stream,v.g);
+    t += Write<float>(stream,v.b);
+    t += Write<float>(stream,v.a);
+    return t;
 }
 
 // -----------------------------------------------------------------------------------
@@ -156,11 +156,11 @@ inline size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v)
 template <>
 inline size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v)
 {
-	size_t t = Write<float>(stream,v.w);
-	t += Write<float>(stream,v.x);
-	t += Write<float>(stream,v.y);
-	t += Write<float>(stream,v.z);
-	return 16;
+    size_t t = Write<float>(stream,v.w);
+    t += Write<float>(stream,v.x);
+    t += Write<float>(stream,v.y);
+    t += Write<float>(stream,v.z);
+    return 16;
 }
 
 
@@ -169,8 +169,8 @@ inline size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v)
 template <>
 inline size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v)
 {
-	size_t t = Write<unsigned int>(stream,v.mVertexId);
-	return t+Write<float>(stream,v.mWeight);
+    size_t t = Write<unsigned int>(stream,v.mVertexId);
+    return t+Write<float>(stream,v.mWeight);
 }
 
 // -----------------------------------------------------------------------------------
@@ -178,12 +178,12 @@ inline size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v)
 template <>
 inline size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m)
 {
-	for (unsigned int i = 0; i < 4;++i) {
-		for (unsigned int i2 = 0; i2 < 4;++i2) {
-			Write<float>(stream,m[i][i2]);
-		}
-	}
-	return 64;
+    for (unsigned int i = 0; i < 4;++i) {
+        for (unsigned int i2 = 0; i2 < 4;++i2) {
+            Write<float>(stream,m[i][i2]);
+        }
+    }
+    return 64;
 }
 
 // -----------------------------------------------------------------------------------
@@ -191,8 +191,8 @@ inline size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m)
 template <>
 inline size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v)
 {
-	const size_t t = Write<double>(stream,v.mTime);
-	return t + Write<aiVector3D>(stream,v.mValue);
+    const size_t t = Write<double>(stream,v.mTime);
+    return t + Write<aiVector3D>(stream,v.mValue);
 }
 
 // -----------------------------------------------------------------------------------
@@ -200,18 +200,18 @@ inline size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v)
 template <>
 inline size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v)
 {
-	const size_t t = Write<double>(stream,v.mTime);
-	return t + Write<aiQuaternion>(stream,v.mValue);
+    const size_t t = Write<double>(stream,v.mTime);
+    return t + Write<aiQuaternion>(stream,v.mValue);
 }
 
 template <typename T>
 inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size)
 {
-	T minc,maxc;
-	ArrayBounds(in,size,minc,maxc);
+    T minc,maxc;
+    ArrayBounds(in,size,minc,maxc);
 
-	const size_t t = Write<T>(stream,minc);
-	return t + Write<T>(stream,maxc);
+    const size_t t = Write<T>(stream,minc);
+    return t + Write<T>(stream,maxc);
 }
 
 // We use this to write out non-byte arrays so that we write using the specializations.
@@ -219,549 +219,549 @@ inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size)
 template <typename T>
 inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
 {
-	size_t n = 0;
-	for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
-	return n;
+    size_t n = 0;
+    for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
+    return n;
 }
 
-	// ----------------------------------------------------------------------------------
-	/**	@class	AssbinChunkWriter
-	 *	@brief	Chunk writer mechanism for the .assbin file structure
-	 *
-	 *  This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
-	 *  the difference being that this takes another IOStream as a "container" in the
-	 *  constructor, and when it is destroyed, it appends the magic number, the chunk size,
-	 *  and the chunk contents to the container stream. This allows relatively easy chunk
-	 *  chunk construction, even recursively.
-	 */
-	class AssbinChunkWriter : public IOStream
-	{
-	private:
-
-		uint8_t* buffer;
-		uint32_t magic;
-		IOStream * container;
-		size_t cur_size, cursor, initial;
-
-	private:
-		// -------------------------------------------------------------------
-		void Grow(size_t need = 0)
-		{
-			size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
-
-			const uint8_t* const old = buffer;
-			buffer = new uint8_t[new_size];
-
-			if (old) {
-				memcpy(buffer,old,cur_size);
-				delete[] old;
-			}
-
-			cur_size = new_size;
-		}
-
-	public:
-
-		AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
-			: buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
-		{
-		}
-
-		virtual ~AssbinChunkWriter()
-		{
-			if (container) {
-				container->Write( &magic, sizeof(uint32_t), 1 );
-				container->Write( &cursor, sizeof(uint32_t), 1 );
-				container->Write( buffer, 1, cursor );
-			}
-			if (buffer) delete[] buffer;
-		}
-
-		void * GetBufferPointer() { return buffer; }
-
-		// -------------------------------------------------------------------
-		virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; }
-		virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; }
-		virtual size_t Tell() const { return cursor; }
-		virtual void Flush() { }
-
-		virtual size_t FileSize() const
-		{
-			return cursor;
-		}
-
-		// -------------------------------------------------------------------
-		virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount)
-		{
-			pSize *= pCount;
-			if (cursor + pSize > cur_size) {
-				Grow(cursor + pSize);
-			}
-
-			memcpy(buffer+cursor, pvBuffer, pSize);
-			cursor += pSize;
-
-			return pCount;
-		}
-
-	};
-
-	// ----------------------------------------------------------------------------------
-	/**	@class	AssbinExport
-	 *	@brief	Assbin exporter class
-	 *
-	 *  This class performs the .assbin exporting, and is responsible for the file layout.
-	 */
-	class AssbinExport
-	{
-	private:
-		bool shortened;
-		bool compressed;
-
-	protected:
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryNode( IOStream * container, const aiNode* node)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
-
-			Write<aiString>(&chunk,node->mName);
-			Write<aiMatrix4x4>(&chunk,node->mTransformation);
-			Write<unsigned int>(&chunk,node->mNumChildren);
-			Write<unsigned int>(&chunk,node->mNumMeshes);
-
-			for (unsigned int i = 0; i < node->mNumMeshes;++i) {
-				Write<unsigned int>(&chunk,node->mMeshes[i]);
-			}
-
-			for (unsigned int i = 0; i < node->mNumChildren;++i) {
-				WriteBinaryNode( &chunk, node->mChildren[i] );
-			}
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
-
-			Write<unsigned int>(&chunk,tex->mWidth);
-			Write<unsigned int>(&chunk,tex->mHeight);
-			chunk.Write( tex->achFormatHint, sizeof(char), 4 );
-
-			if(!shortened) {
-				if (!tex->mHeight) {
-					chunk.Write(tex->pcData,1,tex->mWidth);
-				}
-				else {
-					chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
-				}
-			}
-
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryBone(IOStream * container, const aiBone* b)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
-
-			Write<aiString>(&chunk,b->mName);
-			Write<unsigned int>(&chunk,b->mNumWeights);
-			Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
-
-			// for the moment we write dumb min/max values for the bones, too.
-			// maybe I'll add a better, hash-like solution later
-			if (shortened) {
-				WriteBounds(&chunk,b->mWeights,b->mNumWeights);
-			} // else write as usual
-			else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
-
-			Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
-			Write<unsigned int>(&chunk,mesh->mNumVertices);
-			Write<unsigned int>(&chunk,mesh->mNumFaces);
-			Write<unsigned int>(&chunk,mesh->mNumBones);
-			Write<unsigned int>(&chunk,mesh->mMaterialIndex);
-
-			// first of all, write bits for all existent vertex components
-			unsigned int c = 0;
-			if (mesh->mVertices) {
-				c |= ASSBIN_MESH_HAS_POSITIONS;
-			}
-			if (mesh->mNormals) {
-				c |= ASSBIN_MESH_HAS_NORMALS;
-			}
-			if (mesh->mTangents && mesh->mBitangents) {
-				c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
-			}
-			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
-				if (!mesh->mTextureCoords[n]) {
-					break;
-				}
-				c |= ASSBIN_MESH_HAS_TEXCOORD(n);
-			}
-			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
-				if (!mesh->mColors[n]) {
-					break;
-				}
-				c |= ASSBIN_MESH_HAS_COLOR(n);
-			}
-			Write<unsigned int>(&chunk,c);
-
-			aiVector3D minVec, maxVec;
-			if (mesh->mVertices) {
-				if (shortened) {
-					WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
-				} // else write as usual
-				else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
-			}
-			if (mesh->mNormals) {
-				if (shortened) {
-					WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
-				} // else write as usual
-				else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
-			}
-			if (mesh->mTangents && mesh->mBitangents) {
-				if (shortened) {
-					WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
-					WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
-				} // else write as usual
-				else {
-					WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
-					WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
-				}
-			}
-			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
-				if (!mesh->mColors[n])
-					break;
-
-				if (shortened) {
-					WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
-				} // else write as usual
-				else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
-			}
-			for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
-				if (!mesh->mTextureCoords[n])
-					break;
-
-				// write number of UV components
-				Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
-
-				if (shortened) {
-					WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
-				} // else write as usual
-				else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
-			}
-
-			// write faces. There are no floating-point calculations involved
-			// in these, so we can write a simple hash over the face data
-			// to the dump file. We generate a single 32 Bit hash for 512 faces
-			// using Assimp's standard hashing function.
-			if (shortened) {
-				unsigned int processed = 0;
-				for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
-
-					uint32_t hash = 0;
-					for (unsigned int a = 0; a < job;++a) {
-
-						const aiFace& f = mesh->mFaces[processed+a];
-						uint32_t tmp = f.mNumIndices;
-						hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
-						for (unsigned int i = 0; i < f.mNumIndices; ++i) {
-							BOOST_STATIC_ASSERT(AI_MAX_VERTICES <= 0xffffffff);
-							tmp = static_cast<uint32_t>( f.mIndices[i] );
-							hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
-						}
-					}
-					Write<unsigned int>(&chunk,hash);
-				}
-			}
-			else // else write as usual
-			{
-				// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
-				for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
-					const aiFace& f = mesh->mFaces[i];
-
-					BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff);
-					Write<uint16_t>(&chunk,f.mNumIndices);
-
-					for (unsigned int a = 0; a < f.mNumIndices;++a) {
-						if (mesh->mNumVertices < (1u<<16)) {
-							Write<uint16_t>(&chunk,f.mIndices[a]);
-						}
-						else Write<unsigned int>(&chunk,f.mIndices[a]);
-					}
-				}
-			}
-
-			// write bones
-			if (mesh->mNumBones) {
-				for (unsigned int a = 0; a < mesh->mNumBones;++a) {
-					const aiBone* b = mesh->mBones[a];
-					WriteBinaryBone(&chunk,b);
-				}
-			}
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
-
-			Write<aiString>(&chunk,prop->mKey);
-			Write<unsigned int>(&chunk,prop->mSemantic);
-			Write<unsigned int>(&chunk,prop->mIndex);
-
-			Write<unsigned int>(&chunk,prop->mDataLength);
-			Write<unsigned int>(&chunk,(unsigned int)prop->mType);
-			chunk.Write(prop->mData,1,prop->mDataLength);
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
-
-			Write<unsigned int>(&chunk,mat->mNumProperties);
-			for (unsigned int i = 0; i < mat->mNumProperties;++i) {
-				WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
-			}
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
-
-			Write<aiString>(&chunk,nd->mNodeName);
-			Write<unsigned int>(&chunk,nd->mNumPositionKeys);
-			Write<unsigned int>(&chunk,nd->mNumRotationKeys);
-			Write<unsigned int>(&chunk,nd->mNumScalingKeys);
-			Write<unsigned int>(&chunk,nd->mPreState);
-			Write<unsigned int>(&chunk,nd->mPostState);
-
-			if (nd->mPositionKeys) {
-				if (shortened) {
-					WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
-
-				} // else write as usual
-				else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
-			}
-			if (nd->mRotationKeys) {
-				if (shortened) {
-					WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
-
-				} // else write as usual
-				else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
-			}
-			if (nd->mScalingKeys) {
-				if (shortened) {
-					WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
-
-				} // else write as usual
-				else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
-			}
-		}
-
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
-
-			Write<aiString>(&chunk,anim->mName);
-			Write<double>(&chunk,anim->mDuration);
-			Write<double>(&chunk,anim->mTicksPerSecond);
-			Write<unsigned int>(&chunk,anim->mNumChannels);
-
-			for (unsigned int a = 0; a < anim->mNumChannels;++a) {
-				const aiNodeAnim* nd = anim->mChannels[a];
-				WriteBinaryNodeAnim(&chunk,nd);
-			}
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryLight( IOStream * container, const aiLight* l )
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
-
-			Write<aiString>(&chunk,l->mName);
-			Write<unsigned int>(&chunk,l->mType);
-
-			if (l->mType != aiLightSource_DIRECTIONAL) {
-				Write<float>(&chunk,l->mAttenuationConstant);
-				Write<float>(&chunk,l->mAttenuationLinear);
-				Write<float>(&chunk,l->mAttenuationQuadratic);
-			}
-
-			Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorDiffuse);
-			Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorSpecular);
-			Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorAmbient);
-
-			if (l->mType == aiLightSource_SPOT) {
-				Write<float>(&chunk,l->mAngleInnerCone);
-				Write<float>(&chunk,l->mAngleOuterCone);
-			}
-
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
-
-			Write<aiString>(&chunk,cam->mName);
-			Write<aiVector3D>(&chunk,cam->mPosition);
-			Write<aiVector3D>(&chunk,cam->mLookAt);
-			Write<aiVector3D>(&chunk,cam->mUp);
-			Write<float>(&chunk,cam->mHorizontalFOV);
-			Write<float>(&chunk,cam->mClipPlaneNear);
-			Write<float>(&chunk,cam->mClipPlaneFar);
-			Write<float>(&chunk,cam->mAspect);
-		}
-
-		// -----------------------------------------------------------------------------------
-		void WriteBinaryScene( IOStream * container, const aiScene* scene)
-		{
-			AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
-
-			// basic scene information
-			Write<unsigned int>(&chunk,scene->mFlags);
-			Write<unsigned int>(&chunk,scene->mNumMeshes);
-			Write<unsigned int>(&chunk,scene->mNumMaterials);
-			Write<unsigned int>(&chunk,scene->mNumAnimations);
-			Write<unsigned int>(&chunk,scene->mNumTextures);
-			Write<unsigned int>(&chunk,scene->mNumLights);
-			Write<unsigned int>(&chunk,scene->mNumCameras);
-
-			// write node graph
-			WriteBinaryNode( &chunk, scene->mRootNode );
-
-			// write all meshes
-			for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
-				const aiMesh* mesh = scene->mMeshes[i];
-				WriteBinaryMesh( &chunk,mesh);
-			}
-
-			// write materials
-			for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
-				const aiMaterial* mat = scene->mMaterials[i];
-				WriteBinaryMaterial(&chunk,mat);
-			}
-
-			// write all animations
-			for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
-				const aiAnimation* anim = scene->mAnimations[i];
-				WriteBinaryAnim(&chunk,anim);
-			}
-
-
-			// write all textures
-			for (unsigned int i = 0; i < scene->mNumTextures;++i) {
-				const aiTexture* mesh = scene->mTextures[i];
-				WriteBinaryTexture(&chunk,mesh);
-			}
-
-			// write lights
-			for (unsigned int i = 0; i < scene->mNumLights;++i) {
-				const aiLight* l = scene->mLights[i];
-				WriteBinaryLight(&chunk,l);
-			}
-
-			// write cameras
-			for (unsigned int i = 0; i < scene->mNumCameras;++i) {
-				const aiCamera* cam = scene->mCameras[i];
-				WriteBinaryCamera(&chunk,cam);
-			}
-
-		}
-
-	public:
-		AssbinExport()
-			: shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
-		{
-		}
-
-		// -----------------------------------------------------------------------------------
-		// Write a binary model dump
-		void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
-		{
-			IOStream * out = pIOSystem->Open( pFile, "wb" );
-			if (!out) return;
-
-			time_t tt = time(NULL);
-			tm* p     = gmtime(&tt);
-
-			// header
-			char s[64];
-			memset( s, 0, 64 );
+    // ----------------------------------------------------------------------------------
+    /** @class  AssbinChunkWriter
+     *  @brief  Chunk writer mechanism for the .assbin file structure
+     *
+     *  This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
+     *  the difference being that this takes another IOStream as a "container" in the
+     *  constructor, and when it is destroyed, it appends the magic number, the chunk size,
+     *  and the chunk contents to the container stream. This allows relatively easy chunk
+     *  chunk construction, even recursively.
+     */
+    class AssbinChunkWriter : public IOStream
+    {
+    private:
+
+        uint8_t* buffer;
+        uint32_t magic;
+        IOStream * container;
+        size_t cur_size, cursor, initial;
+
+    private:
+        // -------------------------------------------------------------------
+        void Grow(size_t need = 0)
+        {
+            size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
+
+            const uint8_t* const old = buffer;
+            buffer = new uint8_t[new_size];
+
+            if (old) {
+                memcpy(buffer,old,cur_size);
+                delete[] old;
+            }
+
+            cur_size = new_size;
+        }
+
+    public:
+
+        AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
+            : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
+        {
+        }
+
+        virtual ~AssbinChunkWriter()
+        {
+            if (container) {
+                container->Write( &magic, sizeof(uint32_t), 1 );
+                container->Write( &cursor, sizeof(uint32_t), 1 );
+                container->Write( buffer, 1, cursor );
+            }
+            if (buffer) delete[] buffer;
+        }
+
+        void * GetBufferPointer() { return buffer; }
+
+        // -------------------------------------------------------------------
+        virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; }
+        virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; }
+        virtual size_t Tell() const { return cursor; }
+        virtual void Flush() { }
+
+        virtual size_t FileSize() const
+        {
+            return cursor;
+        }
+
+        // -------------------------------------------------------------------
+        virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount)
+        {
+            pSize *= pCount;
+            if (cursor + pSize > cur_size) {
+                Grow(cursor + pSize);
+            }
+
+            memcpy(buffer+cursor, pvBuffer, pSize);
+            cursor += pSize;
+
+            return pCount;
+        }
+
+    };
+
+    // ----------------------------------------------------------------------------------
+    /** @class  AssbinExport
+     *  @brief  Assbin exporter class
+     *
+     *  This class performs the .assbin exporting, and is responsible for the file layout.
+     */
+    class AssbinExport
+    {
+    private:
+        bool shortened;
+        bool compressed;
+
+    protected:
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryNode( IOStream * container, const aiNode* node)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
+
+            Write<aiString>(&chunk,node->mName);
+            Write<aiMatrix4x4>(&chunk,node->mTransformation);
+            Write<unsigned int>(&chunk,node->mNumChildren);
+            Write<unsigned int>(&chunk,node->mNumMeshes);
+
+            for (unsigned int i = 0; i < node->mNumMeshes;++i) {
+                Write<unsigned int>(&chunk,node->mMeshes[i]);
+            }
+
+            for (unsigned int i = 0; i < node->mNumChildren;++i) {
+                WriteBinaryNode( &chunk, node->mChildren[i] );
+            }
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
+
+            Write<unsigned int>(&chunk,tex->mWidth);
+            Write<unsigned int>(&chunk,tex->mHeight);
+            chunk.Write( tex->achFormatHint, sizeof(char), 4 );
+
+            if(!shortened) {
+                if (!tex->mHeight) {
+                    chunk.Write(tex->pcData,1,tex->mWidth);
+                }
+                else {
+                    chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
+                }
+            }
+
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryBone(IOStream * container, const aiBone* b)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
+
+            Write<aiString>(&chunk,b->mName);
+            Write<unsigned int>(&chunk,b->mNumWeights);
+            Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
+
+            // for the moment we write dumb min/max values for the bones, too.
+            // maybe I'll add a better, hash-like solution later
+            if (shortened) {
+                WriteBounds(&chunk,b->mWeights,b->mNumWeights);
+            } // else write as usual
+            else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
+
+            Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
+            Write<unsigned int>(&chunk,mesh->mNumVertices);
+            Write<unsigned int>(&chunk,mesh->mNumFaces);
+            Write<unsigned int>(&chunk,mesh->mNumBones);
+            Write<unsigned int>(&chunk,mesh->mMaterialIndex);
+
+            // first of all, write bits for all existent vertex components
+            unsigned int c = 0;
+            if (mesh->mVertices) {
+                c |= ASSBIN_MESH_HAS_POSITIONS;
+            }
+            if (mesh->mNormals) {
+                c |= ASSBIN_MESH_HAS_NORMALS;
+            }
+            if (mesh->mTangents && mesh->mBitangents) {
+                c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
+            }
+            for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+                if (!mesh->mTextureCoords[n]) {
+                    break;
+                }
+                c |= ASSBIN_MESH_HAS_TEXCOORD(n);
+            }
+            for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+                if (!mesh->mColors[n]) {
+                    break;
+                }
+                c |= ASSBIN_MESH_HAS_COLOR(n);
+            }
+            Write<unsigned int>(&chunk,c);
+
+            aiVector3D minVec, maxVec;
+            if (mesh->mVertices) {
+                if (shortened) {
+                    WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
+                } // else write as usual
+                else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
+            }
+            if (mesh->mNormals) {
+                if (shortened) {
+                    WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
+                } // else write as usual
+                else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
+            }
+            if (mesh->mTangents && mesh->mBitangents) {
+                if (shortened) {
+                    WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
+                    WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
+                } // else write as usual
+                else {
+                    WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
+                    WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
+                }
+            }
+            for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+                if (!mesh->mColors[n])
+                    break;
+
+                if (shortened) {
+                    WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
+                } // else write as usual
+                else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
+            }
+            for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+                if (!mesh->mTextureCoords[n])
+                    break;
+
+                // write number of UV components
+                Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
+
+                if (shortened) {
+                    WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+                } // else write as usual
+                else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+            }
+
+            // write faces. There are no floating-point calculations involved
+            // in these, so we can write a simple hash over the face data
+            // to the dump file. We generate a single 32 Bit hash for 512 faces
+            // using Assimp's standard hashing function.
+            if (shortened) {
+                unsigned int processed = 0;
+                for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
+
+                    uint32_t hash = 0;
+                    for (unsigned int a = 0; a < job;++a) {
+
+                        const aiFace& f = mesh->mFaces[processed+a];
+                        uint32_t tmp = f.mNumIndices;
+                        hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
+                        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
+                            BOOST_STATIC_ASSERT(AI_MAX_VERTICES <= 0xffffffff);
+                            tmp = static_cast<uint32_t>( f.mIndices[i] );
+                            hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
+                        }
+                    }
+                    Write<unsigned int>(&chunk,hash);
+                }
+            }
+            else // else write as usual
+            {
+                // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
+                for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
+                    const aiFace& f = mesh->mFaces[i];
+
+                    BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff);
+                    Write<uint16_t>(&chunk,f.mNumIndices);
+
+                    for (unsigned int a = 0; a < f.mNumIndices;++a) {
+                        if (mesh->mNumVertices < (1u<<16)) {
+                            Write<uint16_t>(&chunk,f.mIndices[a]);
+                        }
+                        else Write<unsigned int>(&chunk,f.mIndices[a]);
+                    }
+                }
+            }
+
+            // write bones
+            if (mesh->mNumBones) {
+                for (unsigned int a = 0; a < mesh->mNumBones;++a) {
+                    const aiBone* b = mesh->mBones[a];
+                    WriteBinaryBone(&chunk,b);
+                }
+            }
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
+
+            Write<aiString>(&chunk,prop->mKey);
+            Write<unsigned int>(&chunk,prop->mSemantic);
+            Write<unsigned int>(&chunk,prop->mIndex);
+
+            Write<unsigned int>(&chunk,prop->mDataLength);
+            Write<unsigned int>(&chunk,(unsigned int)prop->mType);
+            chunk.Write(prop->mData,1,prop->mDataLength);
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
+
+            Write<unsigned int>(&chunk,mat->mNumProperties);
+            for (unsigned int i = 0; i < mat->mNumProperties;++i) {
+                WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
+
+            Write<aiString>(&chunk,nd->mNodeName);
+            Write<unsigned int>(&chunk,nd->mNumPositionKeys);
+            Write<unsigned int>(&chunk,nd->mNumRotationKeys);
+            Write<unsigned int>(&chunk,nd->mNumScalingKeys);
+            Write<unsigned int>(&chunk,nd->mPreState);
+            Write<unsigned int>(&chunk,nd->mPostState);
+
+            if (nd->mPositionKeys) {
+                if (shortened) {
+                    WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
+
+                } // else write as usual
+                else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
+            }
+            if (nd->mRotationKeys) {
+                if (shortened) {
+                    WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
+
+                } // else write as usual
+                else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
+            }
+            if (nd->mScalingKeys) {
+                if (shortened) {
+                    WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
+
+                } // else write as usual
+                else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
+            }
+        }
+
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
+
+            Write<aiString>(&chunk,anim->mName);
+            Write<double>(&chunk,anim->mDuration);
+            Write<double>(&chunk,anim->mTicksPerSecond);
+            Write<unsigned int>(&chunk,anim->mNumChannels);
+
+            for (unsigned int a = 0; a < anim->mNumChannels;++a) {
+                const aiNodeAnim* nd = anim->mChannels[a];
+                WriteBinaryNodeAnim(&chunk,nd);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryLight( IOStream * container, const aiLight* l )
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
+
+            Write<aiString>(&chunk,l->mName);
+            Write<unsigned int>(&chunk,l->mType);
+
+            if (l->mType != aiLightSource_DIRECTIONAL) {
+                Write<float>(&chunk,l->mAttenuationConstant);
+                Write<float>(&chunk,l->mAttenuationLinear);
+                Write<float>(&chunk,l->mAttenuationQuadratic);
+            }
+
+            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorDiffuse);
+            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorSpecular);
+            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorAmbient);
+
+            if (l->mType == aiLightSource_SPOT) {
+                Write<float>(&chunk,l->mAngleInnerCone);
+                Write<float>(&chunk,l->mAngleOuterCone);
+            }
+
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
+
+            Write<aiString>(&chunk,cam->mName);
+            Write<aiVector3D>(&chunk,cam->mPosition);
+            Write<aiVector3D>(&chunk,cam->mLookAt);
+            Write<aiVector3D>(&chunk,cam->mUp);
+            Write<float>(&chunk,cam->mHorizontalFOV);
+            Write<float>(&chunk,cam->mClipPlaneNear);
+            Write<float>(&chunk,cam->mClipPlaneFar);
+            Write<float>(&chunk,cam->mAspect);
+        }
+
+        // -----------------------------------------------------------------------------------
+        void WriteBinaryScene( IOStream * container, const aiScene* scene)
+        {
+            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
+
+            // basic scene information
+            Write<unsigned int>(&chunk,scene->mFlags);
+            Write<unsigned int>(&chunk,scene->mNumMeshes);
+            Write<unsigned int>(&chunk,scene->mNumMaterials);
+            Write<unsigned int>(&chunk,scene->mNumAnimations);
+            Write<unsigned int>(&chunk,scene->mNumTextures);
+            Write<unsigned int>(&chunk,scene->mNumLights);
+            Write<unsigned int>(&chunk,scene->mNumCameras);
+
+            // write node graph
+            WriteBinaryNode( &chunk, scene->mRootNode );
+
+            // write all meshes
+            for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
+                const aiMesh* mesh = scene->mMeshes[i];
+                WriteBinaryMesh( &chunk,mesh);
+            }
+
+            // write materials
+            for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
+                const aiMaterial* mat = scene->mMaterials[i];
+                WriteBinaryMaterial(&chunk,mat);
+            }
+
+            // write all animations
+            for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+                const aiAnimation* anim = scene->mAnimations[i];
+                WriteBinaryAnim(&chunk,anim);
+            }
+
+
+            // write all textures
+            for (unsigned int i = 0; i < scene->mNumTextures;++i) {
+                const aiTexture* mesh = scene->mTextures[i];
+                WriteBinaryTexture(&chunk,mesh);
+            }
+
+            // write lights
+            for (unsigned int i = 0; i < scene->mNumLights;++i) {
+                const aiLight* l = scene->mLights[i];
+                WriteBinaryLight(&chunk,l);
+            }
+
+            // write cameras
+            for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+                const aiCamera* cam = scene->mCameras[i];
+                WriteBinaryCamera(&chunk,cam);
+            }
+
+        }
+
+    public:
+        AssbinExport()
+            : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
+        {
+        }
+
+        // -----------------------------------------------------------------------------------
+        // Write a binary model dump
+        void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+        {
+            IOStream * out = pIOSystem->Open( pFile, "wb" );
+            if (!out) return;
+
+            time_t tt = time(NULL);
+            tm* p     = gmtime(&tt);
+
+            // header
+            char s[64];
+            memset( s, 0, 64 );
 #if _MSC_VER >= 1400
-			sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
+            sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
 #else
-			snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
+            snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
 #endif
-			out->Write( s, 44, 1 );
-			// == 44 bytes
-
-			Write<unsigned int>( out, ASSBIN_VERSION_MAJOR );
-			Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
-			Write<unsigned int>( out, aiGetVersionRevision() );
-			Write<unsigned int>( out, aiGetCompileFlags() );
-			Write<uint16_t>( out, shortened );
-			Write<uint16_t>( out, compressed );
-			// ==  20 bytes
-
-			char buff[256];
-			strncpy(buff,pFile,256);
-			out->Write(buff,sizeof(char),256);
-
-			char cmd[] = "\0";
-			strncpy(buff,cmd,128);
-			out->Write(buff,sizeof(char),128);
-
-			// leave 64 bytes free for future extensions
-			memset(buff,0xcd,64);
-			out->Write(buff,sizeof(char),64);
-			// == 435 bytes
-
-			// ==== total header size: 512 bytes
-			ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH );
-
-			// Up to here the data is uncompressed. For compressed files, the rest
-			// is compressed using standard DEFLATE from zlib.
-			if (compressed)
-			{
-				AssbinChunkWriter uncompressedStream( NULL, 0 );
-				WriteBinaryScene( &uncompressedStream, pScene );
-
-				uLongf uncompressedSize = uncompressedStream.Tell();
-				uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.);
-				uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
-
-				compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
-
-				out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
-				out->Write( compressedBuffer, sizeof(char), compressedSize );
-
-				delete[] compressedBuffer;
-			}
-			else
-			{
-				WriteBinaryScene( out, pScene );
-			}
-
-			pIOSystem->Close( out );
-		}
-	};
+            out->Write( s, 44, 1 );
+            // == 44 bytes
+
+            Write<unsigned int>( out, ASSBIN_VERSION_MAJOR );
+            Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
+            Write<unsigned int>( out, aiGetVersionRevision() );
+            Write<unsigned int>( out, aiGetCompileFlags() );
+            Write<uint16_t>( out, shortened );
+            Write<uint16_t>( out, compressed );
+            // ==  20 bytes
+
+            char buff[256];
+            strncpy(buff,pFile,256);
+            out->Write(buff,sizeof(char),256);
+
+            char cmd[] = "\0";
+            strncpy(buff,cmd,128);
+            out->Write(buff,sizeof(char),128);
+
+            // leave 64 bytes free for future extensions
+            memset(buff,0xcd,64);
+            out->Write(buff,sizeof(char),64);
+            // == 435 bytes
+
+            // ==== total header size: 512 bytes
+            ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH );
+
+            // Up to here the data is uncompressed. For compressed files, the rest
+            // is compressed using standard DEFLATE from zlib.
+            if (compressed)
+            {
+                AssbinChunkWriter uncompressedStream( NULL, 0 );
+                WriteBinaryScene( &uncompressedStream, pScene );
+
+                uLongf uncompressedSize = uncompressedStream.Tell();
+                uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.);
+                uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
+
+                compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
+
+                out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
+                out->Write( compressedBuffer, sizeof(char), compressedSize );
+
+                delete[] compressedBuffer;
+            }
+            else
+            {
+                WriteBinaryScene( out, pScene );
+            }
+
+            pIOSystem->Close( out );
+        }
+    };
 
 void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
-	AssbinExport exporter;
-	exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
+    AssbinExport exporter;
+    exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
 }
 } // end of namespace Assimp
 

+ 477 - 477
code/AssbinLoader.cpp

@@ -57,631 +57,631 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <boost/static_assert.hpp>
 
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#	include <zlib.h>
+#   include <zlib.h>
 #else
-#	include "../contrib/zlib/zlib.h"
+#   include "../contrib/zlib/zlib.h"
 #endif
 
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-	".assbin Importer",
-	"Gargaj / Conspiracy",
-	"",
-	"",
-	aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
-	0,
-	0,
-	0,
-	0,
-	"assbin"
+    ".assbin Importer",
+    "Gargaj / Conspiracy",
+    "",
+    "",
+    aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
+    0,
+    0,
+    0,
+    0,
+    "assbin"
 };
 
 const aiImporterDesc* AssbinImporter::GetInfo() const
 {
-	return &desc;
+    return &desc;
 }
 
 bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const
 {
-	IOStream * in = pIOHandler->Open(pFile);
-	if (!in)
-		return false;
+    IOStream * in = pIOHandler->Open(pFile);
+    if (!in)
+        return false;
 
-	char s[32];
-	in->Read( s, sizeof(char), 32 );
+    char s[32];
+    in->Read( s, sizeof(char), 32 );
 
-	pIOHandler->Close(in);
+    pIOHandler->Close(in);
 
-	return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
+    return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
 }
 
 template <typename T>
 T Read(IOStream * stream)
 {
-	T t;
-	stream->Read( &t, sizeof(T), 1 );
-	return t;
+    T t;
+    stream->Read( &t, sizeof(T), 1 );
+    return t;
 }
 
 template <>
 aiVector3D Read<aiVector3D>(IOStream * stream)
 {
-	aiVector3D v;
-	v.x = Read<float>(stream);
-	v.y = Read<float>(stream);
-	v.z = Read<float>(stream);
-	return v;
+    aiVector3D v;
+    v.x = Read<float>(stream);
+    v.y = Read<float>(stream);
+    v.z = Read<float>(stream);
+    return v;
 }
 
 template <>
 aiColor4D Read<aiColor4D>(IOStream * stream)
 {
-	aiColor4D c;
-	c.r = Read<float>(stream);
-	c.g = Read<float>(stream);
-	c.b = Read<float>(stream);
-	c.a = Read<float>(stream);
-	return c;
+    aiColor4D c;
+    c.r = Read<float>(stream);
+    c.g = Read<float>(stream);
+    c.b = Read<float>(stream);
+    c.a = Read<float>(stream);
+    return c;
 }
 
 template <>
 aiQuaternion Read<aiQuaternion>(IOStream * stream)
 {
-	aiQuaternion v;
-	v.w = Read<float>(stream);
-	v.x = Read<float>(stream);
-	v.y = Read<float>(stream);
-	v.z = Read<float>(stream);
-	return v;
+    aiQuaternion v;
+    v.w = Read<float>(stream);
+    v.x = Read<float>(stream);
+    v.y = Read<float>(stream);
+    v.z = Read<float>(stream);
+    return v;
 }
 
 template <>
 aiString Read<aiString>(IOStream * stream)
 {
-	aiString s;
-	stream->Read(&s.length,4,1);
-	stream->Read(s.data,s.length,1);
-	s.data[s.length] = 0;
-	return s;
+    aiString s;
+    stream->Read(&s.length,4,1);
+    stream->Read(s.data,s.length,1);
+    s.data[s.length] = 0;
+    return s;
 }
 
 template <>
 aiVertexWeight Read<aiVertexWeight>(IOStream * stream)
 {
-	aiVertexWeight w;
-	w.mVertexId = Read<unsigned int>(stream);
-	w.mWeight = Read<float>(stream);
-	return w;
+    aiVertexWeight w;
+    w.mVertexId = Read<unsigned int>(stream);
+    w.mWeight = Read<float>(stream);
+    return w;
 }
 
 template <>
 aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream)
 {
-	aiMatrix4x4 m;
-	for (unsigned int i = 0; i < 4;++i) {
-		for (unsigned int i2 = 0; i2 < 4;++i2) {
-			m[i][i2] = Read<float>(stream);
-		}
-	}
-	return m;
+    aiMatrix4x4 m;
+    for (unsigned int i = 0; i < 4;++i) {
+        for (unsigned int i2 = 0; i2 < 4;++i2) {
+            m[i][i2] = Read<float>(stream);
+        }
+    }
+    return m;
 }
 
 template <>
 aiVectorKey Read<aiVectorKey>(IOStream * stream)
 {
-	aiVectorKey v;
-	v.mTime = Read<double>(stream);
-	v.mValue = Read<aiVector3D>(stream);
-	return v;
+    aiVectorKey v;
+    v.mTime = Read<double>(stream);
+    v.mValue = Read<aiVector3D>(stream);
+    return v;
 }
 
 template <>
 aiQuatKey Read<aiQuatKey>(IOStream * stream)
 {
-	aiQuatKey v;
-	v.mTime = Read<double>(stream);
-	v.mValue = Read<aiQuaternion>(stream);
-	return v;
+    aiQuatKey v;
+    v.mTime = Read<double>(stream);
+    v.mValue = Read<aiQuaternion>(stream);
+    return v;
 }
 
 template <typename T>
 void ReadArray(IOStream * stream, T * out, unsigned int size)
 {
-	for (unsigned int i=0; i<size; i++) out[i] = Read<T>(stream);
+    for (unsigned int i=0; i<size; i++) out[i] = Read<T>(stream);
 }
 
 template <typename T> void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n )
 {
-	// not sure what to do here, the data isn't really useful.
-	stream->Seek( sizeof(T) * n, aiOrigin_CUR );
+    // not sure what to do here, the data isn't really useful.
+    stream->Seek( sizeof(T) * n, aiOrigin_CUR );
 }
 
 void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node )
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AINODE);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	*node = new aiNode();
-
-	(*node)->mName = Read<aiString>(stream);
-	(*node)->mTransformation = Read<aiMatrix4x4>(stream);
-	(*node)->mNumChildren = Read<unsigned int>(stream);
-	(*node)->mNumMeshes = Read<unsigned int>(stream);
-
-	if ((*node)->mNumMeshes)
-	{
-		(*node)->mMeshes = new unsigned int[(*node)->mNumMeshes];
-		for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) {
-			(*node)->mMeshes[i] = Read<unsigned int>(stream);
-		}
-	}
-
-	if ((*node)->mNumChildren)
-	{
-		(*node)->mChildren = new aiNode*[(*node)->mNumChildren];
-		for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) {
-			ReadBinaryNode( stream, &(*node)->mChildren[i] );
-		}
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AINODE);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    *node = new aiNode();
+
+    (*node)->mName = Read<aiString>(stream);
+    (*node)->mTransformation = Read<aiMatrix4x4>(stream);
+    (*node)->mNumChildren = Read<unsigned int>(stream);
+    (*node)->mNumMeshes = Read<unsigned int>(stream);
+
+    if ((*node)->mNumMeshes)
+    {
+        (*node)->mMeshes = new unsigned int[(*node)->mNumMeshes];
+        for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) {
+            (*node)->mMeshes[i] = Read<unsigned int>(stream);
+        }
+    }
+
+    if ((*node)->mNumChildren)
+    {
+        (*node)->mChildren = new aiNode*[(*node)->mNumChildren];
+        for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) {
+            ReadBinaryNode( stream, &(*node)->mChildren[i] );
+        }
+    }
 
 }
 
 // -----------------------------------------------------------------------------------
 void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AIBONE);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	b->mName = Read<aiString>(stream);
-	b->mNumWeights = Read<unsigned int>(stream);
-	b->mOffsetMatrix = Read<aiMatrix4x4>(stream);
-
-	// for the moment we write dumb min/max values for the bones, too.
-	// maybe I'll add a better, hash-like solution later
-	if (shortened)
-	{
-		ReadBounds(stream,b->mWeights,b->mNumWeights);
-	} // else write as usual
-	else
-	{
-		b->mWeights = new aiVertexWeight[b->mNumWeights];
-		ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AIBONE);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    b->mName = Read<aiString>(stream);
+    b->mNumWeights = Read<unsigned int>(stream);
+    b->mOffsetMatrix = Read<aiMatrix4x4>(stream);
+
+    // for the moment we write dumb min/max values for the bones, too.
+    // maybe I'll add a better, hash-like solution later
+    if (shortened)
+    {
+        ReadBounds(stream,b->mWeights,b->mNumWeights);
+    } // else write as usual
+    else
+    {
+        b->mWeights = new aiVertexWeight[b->mNumWeights];
+        ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
+    }
 }
 
 
 void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AIMESH);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	mesh->mPrimitiveTypes = Read<unsigned int>(stream);
-	mesh->mNumVertices = Read<unsigned int>(stream);
-	mesh->mNumFaces = Read<unsigned int>(stream);
-	mesh->mNumBones = Read<unsigned int>(stream);
-	mesh->mMaterialIndex = Read<unsigned int>(stream);
-
-	// first of all, write bits for all existent vertex components
-	unsigned int c = Read<unsigned int>(stream);
-
-	if (c & ASSBIN_MESH_HAS_POSITIONS)
-	{
-		if (shortened) {
-			ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
-		} // else write as usual
-		else
-		{
-			mesh->mVertices = new aiVector3D[mesh->mNumVertices];
-			ReadArray<aiVector3D>(stream,mesh->mVertices,mesh->mNumVertices);
-		}
-	}
-	if (c & ASSBIN_MESH_HAS_NORMALS)
-	{
-		if (shortened) {
-			ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
-		} // else write as usual
-		else
-		{
-			mesh->mNormals = new aiVector3D[mesh->mNumVertices];
-			ReadArray<aiVector3D>(stream,mesh->mNormals,mesh->mNumVertices);
-		}
-	}
-	if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS)
-	{
-		if (shortened) {
-			ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
-			ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
-		} // else write as usual
-		else
-		{
-			mesh->mTangents = new aiVector3D[mesh->mNumVertices];
-			ReadArray<aiVector3D>(stream,mesh->mTangents,mesh->mNumVertices);
-			mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
-			ReadArray<aiVector3D>(stream,mesh->mBitangents,mesh->mNumVertices);
-		}
-	}
-	for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n)
-	{
-		if (!(c & ASSBIN_MESH_HAS_COLOR(n)))
-			break;
-
-		if (shortened)
-		{
-			ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
-		} // else write as usual
-		else
-		{
-			mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
-			ReadArray<aiColor4D>(stream,mesh->mColors[n],mesh->mNumVertices);
-		}
-	}
-	for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
-	{
-		if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n)))
-			break;
-
-		// write number of UV components
-		mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
-
-		if (shortened) {
-			ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
-		} // else write as usual
-		else
-		{
-			mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
-			ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
-		}
-	}
-
-	// write faces. There are no floating-point calculations involved
-	// in these, so we can write a simple hash over the face data
-	// to the dump file. We generate a single 32 Bit hash for 512 faces
-	// using Assimp's standard hashing function.
-	if (shortened) {
-		Read<unsigned int>(stream);
-	}
-	else // else write as usual
-	{
-		// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
-		mesh->mFaces = new aiFace[mesh->mNumFaces];
-		for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
-			aiFace& f = mesh->mFaces[i];
-
-			BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff);
-			f.mNumIndices = Read<uint16_t>(stream);
-			f.mIndices = new unsigned int[f.mNumIndices];
-
-			for (unsigned int a = 0; a < f.mNumIndices;++a) {
-				if (mesh->mNumVertices < (1u<<16))
-				{
-					f.mIndices[a] = Read<uint16_t>(stream);
-				}
-				else
-				{
-					f.mIndices[a] = Read<unsigned int>(stream);
-				}
-			}
-		}
-	}
-
-	// write bones
-	if (mesh->mNumBones) {
-		mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones];
-		for (unsigned int a = 0; a < mesh->mNumBones;++a) {
-			mesh->mBones[a] = new aiBone();
-			ReadBinaryBone(stream,mesh->mBones[a]);
-		}
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AIMESH);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    mesh->mPrimitiveTypes = Read<unsigned int>(stream);
+    mesh->mNumVertices = Read<unsigned int>(stream);
+    mesh->mNumFaces = Read<unsigned int>(stream);
+    mesh->mNumBones = Read<unsigned int>(stream);
+    mesh->mMaterialIndex = Read<unsigned int>(stream);
+
+    // first of all, write bits for all existent vertex components
+    unsigned int c = Read<unsigned int>(stream);
+
+    if (c & ASSBIN_MESH_HAS_POSITIONS)
+    {
+        if (shortened) {
+            ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
+        } // else write as usual
+        else
+        {
+            mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+            ReadArray<aiVector3D>(stream,mesh->mVertices,mesh->mNumVertices);
+        }
+    }
+    if (c & ASSBIN_MESH_HAS_NORMALS)
+    {
+        if (shortened) {
+            ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
+        } // else write as usual
+        else
+        {
+            mesh->mNormals = new aiVector3D[mesh->mNumVertices];
+            ReadArray<aiVector3D>(stream,mesh->mNormals,mesh->mNumVertices);
+        }
+    }
+    if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS)
+    {
+        if (shortened) {
+            ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
+            ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
+        } // else write as usual
+        else
+        {
+            mesh->mTangents = new aiVector3D[mesh->mNumVertices];
+            ReadArray<aiVector3D>(stream,mesh->mTangents,mesh->mNumVertices);
+            mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
+            ReadArray<aiVector3D>(stream,mesh->mBitangents,mesh->mNumVertices);
+        }
+    }
+    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n)
+    {
+        if (!(c & ASSBIN_MESH_HAS_COLOR(n)))
+            break;
+
+        if (shortened)
+        {
+            ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
+        } // else write as usual
+        else
+        {
+            mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
+            ReadArray<aiColor4D>(stream,mesh->mColors[n],mesh->mNumVertices);
+        }
+    }
+    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
+    {
+        if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n)))
+            break;
+
+        // write number of UV components
+        mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
+
+        if (shortened) {
+            ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
+        } // else write as usual
+        else
+        {
+            mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
+            ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
+        }
+    }
+
+    // write faces. There are no floating-point calculations involved
+    // in these, so we can write a simple hash over the face data
+    // to the dump file. We generate a single 32 Bit hash for 512 faces
+    // using Assimp's standard hashing function.
+    if (shortened) {
+        Read<unsigned int>(stream);
+    }
+    else // else write as usual
+    {
+        // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
+        mesh->mFaces = new aiFace[mesh->mNumFaces];
+        for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
+            aiFace& f = mesh->mFaces[i];
+
+            BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff);
+            f.mNumIndices = Read<uint16_t>(stream);
+            f.mIndices = new unsigned int[f.mNumIndices];
+
+            for (unsigned int a = 0; a < f.mNumIndices;++a) {
+                if (mesh->mNumVertices < (1u<<16))
+                {
+                    f.mIndices[a] = Read<uint16_t>(stream);
+                }
+                else
+                {
+                    f.mIndices[a] = Read<unsigned int>(stream);
+                }
+            }
+        }
+    }
+
+    // write bones
+    if (mesh->mNumBones) {
+        mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones];
+        for (unsigned int a = 0; a < mesh->mNumBones;++a) {
+            mesh->mBones[a] = new aiBone();
+            ReadBinaryBone(stream,mesh->mBones[a]);
+        }
+    }
 }
 
 void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop)
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	prop->mKey = Read<aiString>(stream);
-	prop->mSemantic = Read<unsigned int>(stream);
-	prop->mIndex = Read<unsigned int>(stream);
-
-	prop->mDataLength = Read<unsigned int>(stream);
-	prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
-	prop->mData = new char [ prop->mDataLength ];
-	stream->Read(prop->mData,1,prop->mDataLength);
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    prop->mKey = Read<aiString>(stream);
+    prop->mSemantic = Read<unsigned int>(stream);
+    prop->mIndex = Read<unsigned int>(stream);
+
+    prop->mDataLength = Read<unsigned int>(stream);
+    prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
+    prop->mData = new char [ prop->mDataLength ];
+    stream->Read(prop->mData,1,prop->mDataLength);
 }
 
 // -----------------------------------------------------------------------------------
 void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
-	if (mat->mNumProperties)
-	{
-		if (mat->mProperties)
-		{
-			delete[] mat->mProperties;
-		}
-		mat->mProperties = new aiMaterialProperty*[mat->mNumProperties];
-		for (unsigned int i = 0; i < mat->mNumProperties;++i) {
-			mat->mProperties[i] = new aiMaterialProperty();
-			ReadBinaryMaterialProperty( stream, mat->mProperties[i]);
-		}
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
+    if (mat->mNumProperties)
+    {
+        if (mat->mProperties)
+        {
+            delete[] mat->mProperties;
+        }
+        mat->mProperties = new aiMaterialProperty*[mat->mNumProperties];
+        for (unsigned int i = 0; i < mat->mNumProperties;++i) {
+            mat->mProperties[i] = new aiMaterialProperty();
+            ReadBinaryMaterialProperty( stream, mat->mProperties[i]);
+        }
+    }
 }
 
 // -----------------------------------------------------------------------------------
 void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	nd->mNodeName = Read<aiString>(stream);
-	nd->mNumPositionKeys = Read<unsigned int>(stream);
-	nd->mNumRotationKeys = Read<unsigned int>(stream);
-	nd->mNumScalingKeys = Read<unsigned int>(stream);
-	nd->mPreState = (aiAnimBehaviour)Read<unsigned int>(stream);
-	nd->mPostState = (aiAnimBehaviour)Read<unsigned int>(stream);
-
-	if (nd->mNumPositionKeys) {
-		if (shortened) {
-			ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys);
-
-		} // else write as usual
-		else {
-			nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
-			ReadArray<aiVectorKey>(stream,nd->mPositionKeys,nd->mNumPositionKeys);
-		}
-	}
-	if (nd->mNumRotationKeys) {
-		if (shortened) {
-			ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
-
-		} // else write as usual
-		else
-		{
-			nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
-			ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
-		}
-	}
-	if (nd->mNumScalingKeys) {
-		if (shortened) {
-			ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
-
-		} // else write as usual
-		else
-		{
-			nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
-			ReadArray<aiVectorKey>(stream,nd->mScalingKeys,nd->mNumScalingKeys);
-		}
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    nd->mNodeName = Read<aiString>(stream);
+    nd->mNumPositionKeys = Read<unsigned int>(stream);
+    nd->mNumRotationKeys = Read<unsigned int>(stream);
+    nd->mNumScalingKeys = Read<unsigned int>(stream);
+    nd->mPreState = (aiAnimBehaviour)Read<unsigned int>(stream);
+    nd->mPostState = (aiAnimBehaviour)Read<unsigned int>(stream);
+
+    if (nd->mNumPositionKeys) {
+        if (shortened) {
+            ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys);
+
+        } // else write as usual
+        else {
+            nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
+            ReadArray<aiVectorKey>(stream,nd->mPositionKeys,nd->mNumPositionKeys);
+        }
+    }
+    if (nd->mNumRotationKeys) {
+        if (shortened) {
+            ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
+
+        } // else write as usual
+        else
+        {
+            nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
+            ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
+        }
+    }
+    if (nd->mNumScalingKeys) {
+        if (shortened) {
+            ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
+
+        } // else write as usual
+        else
+        {
+            nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
+            ReadArray<aiVectorKey>(stream,nd->mScalingKeys,nd->mNumScalingKeys);
+        }
+    }
 }
 
 
 // -----------------------------------------------------------------------------------
 void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	anim->mName = Read<aiString> (stream);
-	anim->mDuration = Read<double> (stream);
-	anim->mTicksPerSecond = Read<double> (stream);
-	anim->mNumChannels = Read<unsigned int>(stream);
-
-	if (anim->mNumChannels)
-	{
-		anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
-		for (unsigned int a = 0; a < anim->mNumChannels;++a) {
-			anim->mChannels[a] = new aiNodeAnim();
-			ReadBinaryNodeAnim(stream,anim->mChannels[a]);
-		}
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    anim->mName = Read<aiString> (stream);
+    anim->mDuration = Read<double> (stream);
+    anim->mTicksPerSecond = Read<double> (stream);
+    anim->mNumChannels = Read<unsigned int>(stream);
+
+    if (anim->mNumChannels)
+    {
+        anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
+        for (unsigned int a = 0; a < anim->mNumChannels;++a) {
+            anim->mChannels[a] = new aiNodeAnim();
+            ReadBinaryNodeAnim(stream,anim->mChannels[a]);
+        }
+    }
 }
 
 void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	tex->mWidth = Read<unsigned int>(stream);
-	tex->mHeight = Read<unsigned int>(stream);
-	stream->Read( tex->achFormatHint, sizeof(char), 4 );
-
-	if(!shortened) {
-		if (!tex->mHeight) {
-			tex->pcData = new aiTexel[ tex->mWidth ];
-			stream->Read(tex->pcData,1,tex->mWidth);
-		}
-		else {
-			tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
-			stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
-		}
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    tex->mWidth = Read<unsigned int>(stream);
+    tex->mHeight = Read<unsigned int>(stream);
+    stream->Read( tex->achFormatHint, sizeof(char), 4 );
+
+    if(!shortened) {
+        if (!tex->mHeight) {
+            tex->pcData = new aiTexel[ tex->mWidth ];
+            stream->Read(tex->pcData,1,tex->mWidth);
+        }
+        else {
+            tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
+            stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
+        }
+    }
 
 }
 
 // -----------------------------------------------------------------------------------
 void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
 
-	l->mName = Read<aiString>(stream);
-	l->mType = (aiLightSourceType)Read<unsigned int>(stream);
+    l->mName = Read<aiString>(stream);
+    l->mType = (aiLightSourceType)Read<unsigned int>(stream);
 
-	if (l->mType != aiLightSource_DIRECTIONAL) {
-		l->mAttenuationConstant = Read<float>(stream);
-		l->mAttenuationLinear = Read<float>(stream);
-		l->mAttenuationQuadratic = Read<float>(stream);
-	}
+    if (l->mType != aiLightSource_DIRECTIONAL) {
+        l->mAttenuationConstant = Read<float>(stream);
+        l->mAttenuationLinear = Read<float>(stream);
+        l->mAttenuationQuadratic = Read<float>(stream);
+    }
 
-	l->mColorDiffuse = Read<aiColor3D>(stream);
-	l->mColorSpecular = Read<aiColor3D>(stream);
-	l->mColorAmbient = Read<aiColor3D>(stream);
+    l->mColorDiffuse = Read<aiColor3D>(stream);
+    l->mColorSpecular = Read<aiColor3D>(stream);
+    l->mColorAmbient = Read<aiColor3D>(stream);
 
-	if (l->mType == aiLightSource_SPOT) {
-		l->mAngleInnerCone = Read<float>(stream);
-		l->mAngleOuterCone = Read<float>(stream);
-	}
+    if (l->mType == aiLightSource_SPOT) {
+        l->mAngleInnerCone = Read<float>(stream);
+        l->mAngleOuterCone = Read<float>(stream);
+    }
 
 }
 
 // -----------------------------------------------------------------------------------
 void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	cam->mName = Read<aiString>(stream);
-	cam->mPosition = Read<aiVector3D>(stream);
-	cam->mLookAt = Read<aiVector3D>(stream);
-	cam->mUp = Read<aiVector3D>(stream);
-	cam->mHorizontalFOV = Read<float>(stream);
-	cam->mClipPlaneNear = Read<float>(stream);
-	cam->mClipPlaneFar = Read<float>(stream);
-	cam->mAspect = Read<float>(stream);
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    cam->mName = Read<aiString>(stream);
+    cam->mPosition = Read<aiVector3D>(stream);
+    cam->mLookAt = Read<aiVector3D>(stream);
+    cam->mUp = Read<aiVector3D>(stream);
+    cam->mHorizontalFOV = Read<float>(stream);
+    cam->mClipPlaneNear = Read<float>(stream);
+    cam->mClipPlaneFar = Read<float>(stream);
+    cam->mAspect = Read<float>(stream);
 }
 
 void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
 {
-	uint32_t chunkID = Read<uint32_t>(stream);
-	ai_assert(chunkID == ASSBIN_CHUNK_AISCENE);
-	/*uint32_t size =*/ Read<uint32_t>(stream);
-
-	scene->mFlags         = Read<unsigned int>(stream);
-	scene->mNumMeshes     = Read<unsigned int>(stream);
-	scene->mNumMaterials  = Read<unsigned int>(stream);
-	scene->mNumAnimations = Read<unsigned int>(stream);
-	scene->mNumTextures   = Read<unsigned int>(stream);
-	scene->mNumLights     = Read<unsigned int>(stream);
-	scene->mNumCameras    = Read<unsigned int>(stream);
-
-	// Read node graph
-	scene->mRootNode = new aiNode[1];
-	ReadBinaryNode( stream, &scene->mRootNode );
-
-	// Read all meshes
-	if (scene->mNumMeshes)
-	{
-		scene->mMeshes = new aiMesh*[scene->mNumMeshes];
-		for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
-			scene->mMeshes[i] = new aiMesh();
-			ReadBinaryMesh( stream,scene->mMeshes[i]);
-		}
-	}
-
-	// Read materials
-	if (scene->mNumMaterials)
-	{
-		scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
-		for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
-			scene->mMaterials[i] = new aiMaterial();
-			ReadBinaryMaterial(stream,scene->mMaterials[i]);
-		}
-	}
-
-	// Read all animations
-	if (scene->mNumAnimations)
-	{
-		scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
-		for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
-			scene->mAnimations[i] = new aiAnimation();
-			ReadBinaryAnim(stream,scene->mAnimations[i]);
-		}
-	}
-
-	// Read all textures
-	if (scene->mNumTextures)
-	{
-		scene->mTextures = new aiTexture*[scene->mNumTextures];
-		for (unsigned int i = 0; i < scene->mNumTextures;++i) {
-			scene->mTextures[i] = new aiTexture();
-			ReadBinaryTexture(stream,scene->mTextures[i]);
-		}
-	}
-
-	// Read lights
-	if (scene->mNumLights)
-	{
-		scene->mLights = new aiLight*[scene->mNumLights];
-		for (unsigned int i = 0; i < scene->mNumLights;++i) {
-			scene->mLights[i] = new aiLight();
-			ReadBinaryLight(stream,scene->mLights[i]);
-		}
-	}
-
-	// Read cameras
-	if (scene->mNumCameras)
-	{
-		scene->mCameras = new aiCamera*[scene->mNumCameras];
-		for (unsigned int i = 0; i < scene->mNumCameras;++i) {
-			scene->mCameras[i] = new aiCamera();
-			ReadBinaryCamera(stream,scene->mCameras[i]);
-		}
-	}
+    uint32_t chunkID = Read<uint32_t>(stream);
+    ai_assert(chunkID == ASSBIN_CHUNK_AISCENE);
+    /*uint32_t size =*/ Read<uint32_t>(stream);
+
+    scene->mFlags         = Read<unsigned int>(stream);
+    scene->mNumMeshes     = Read<unsigned int>(stream);
+    scene->mNumMaterials  = Read<unsigned int>(stream);
+    scene->mNumAnimations = Read<unsigned int>(stream);
+    scene->mNumTextures   = Read<unsigned int>(stream);
+    scene->mNumLights     = Read<unsigned int>(stream);
+    scene->mNumCameras    = Read<unsigned int>(stream);
+
+    // Read node graph
+    scene->mRootNode = new aiNode[1];
+    ReadBinaryNode( stream, &scene->mRootNode );
+
+    // Read all meshes
+    if (scene->mNumMeshes)
+    {
+        scene->mMeshes = new aiMesh*[scene->mNumMeshes];
+        for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
+            scene->mMeshes[i] = new aiMesh();
+            ReadBinaryMesh( stream,scene->mMeshes[i]);
+        }
+    }
+
+    // Read materials
+    if (scene->mNumMaterials)
+    {
+        scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
+        for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
+            scene->mMaterials[i] = new aiMaterial();
+            ReadBinaryMaterial(stream,scene->mMaterials[i]);
+        }
+    }
+
+    // Read all animations
+    if (scene->mNumAnimations)
+    {
+        scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
+        for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+            scene->mAnimations[i] = new aiAnimation();
+            ReadBinaryAnim(stream,scene->mAnimations[i]);
+        }
+    }
+
+    // Read all textures
+    if (scene->mNumTextures)
+    {
+        scene->mTextures = new aiTexture*[scene->mNumTextures];
+        for (unsigned int i = 0; i < scene->mNumTextures;++i) {
+            scene->mTextures[i] = new aiTexture();
+            ReadBinaryTexture(stream,scene->mTextures[i]);
+        }
+    }
+
+    // Read lights
+    if (scene->mNumLights)
+    {
+        scene->mLights = new aiLight*[scene->mNumLights];
+        for (unsigned int i = 0; i < scene->mNumLights;++i) {
+            scene->mLights[i] = new aiLight();
+            ReadBinaryLight(stream,scene->mLights[i]);
+        }
+    }
+
+    // Read cameras
+    if (scene->mNumCameras)
+    {
+        scene->mCameras = new aiCamera*[scene->mNumCameras];
+        for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+            scene->mCameras[i] = new aiCamera();
+            ReadBinaryCamera(stream,scene->mCameras[i]);
+        }
+    }
 
 }
 
 void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler )
 {
-	IOStream * stream = pIOHandler->Open(pFile,"rb");
-	if (!stream)
-		return;
+    IOStream * stream = pIOHandler->Open(pFile,"rb");
+    if (!stream)
+        return;
 
-	stream->Seek( 44, aiOrigin_CUR ); // signature
+    stream->Seek( 44, aiOrigin_CUR ); // signature
 
-	/*unsigned int versionMajor =*/ Read<unsigned int>(stream);
-	/*unsigned int versionMinor =*/ Read<unsigned int>(stream);
-	/*unsigned int versionRevision =*/ Read<unsigned int>(stream);
-	/*unsigned int compileFlags =*/ Read<unsigned int>(stream);
+    /*unsigned int versionMajor =*/ Read<unsigned int>(stream);
+    /*unsigned int versionMinor =*/ Read<unsigned int>(stream);
+    /*unsigned int versionRevision =*/ Read<unsigned int>(stream);
+    /*unsigned int compileFlags =*/ Read<unsigned int>(stream);
 
-	shortened = Read<uint16_t>(stream) > 0;
-	compressed = Read<uint16_t>(stream) > 0;
+    shortened = Read<uint16_t>(stream) > 0;
+    compressed = Read<uint16_t>(stream) > 0;
 
-	if (shortened)
-		throw DeadlyImportError( "Shortened binaries are not supported!" );
+    if (shortened)
+        throw DeadlyImportError( "Shortened binaries are not supported!" );
 
-	stream->Seek( 256, aiOrigin_CUR ); // original filename
-	stream->Seek( 128, aiOrigin_CUR ); // options
-	stream->Seek( 64, aiOrigin_CUR ); // padding
+    stream->Seek( 256, aiOrigin_CUR ); // original filename
+    stream->Seek( 128, aiOrigin_CUR ); // options
+    stream->Seek( 64, aiOrigin_CUR ); // padding
 
-	if (compressed)
-	{
-		uLongf uncompressedSize = Read<uint32_t>(stream);
-		uLongf compressedSize = stream->FileSize() - stream->Tell();
+    if (compressed)
+    {
+        uLongf uncompressedSize = Read<uint32_t>(stream);
+        uLongf compressedSize = stream->FileSize() - stream->Tell();
 
-		unsigned char * compressedData = new unsigned char[ compressedSize ];
-		stream->Read( compressedData, 1, compressedSize );
+        unsigned char * compressedData = new unsigned char[ compressedSize ];
+        stream->Read( compressedData, 1, compressedSize );
 
-		unsigned char * uncompressedData = new unsigned char[ uncompressedSize ];
+        unsigned char * uncompressedData = new unsigned char[ uncompressedSize ];
 
-		uncompress( uncompressedData, &uncompressedSize, compressedData, compressedSize );
+        uncompress( uncompressedData, &uncompressedSize, compressedData, compressedSize );
 
-		MemoryIOStream io( uncompressedData, uncompressedSize );
+        MemoryIOStream io( uncompressedData, uncompressedSize );
 
-		ReadBinaryScene(&io,pScene);
+        ReadBinaryScene(&io,pScene);
 
-		delete[] uncompressedData;
-		delete[] compressedData;
-	}
-	else
-	{
-		ReadBinaryScene(stream,pScene);
-	}
+        delete[] uncompressedData;
+        delete[] compressedData;
+    }
+    else
+    {
+        ReadBinaryScene(stream,pScene);
+    }
 
-	pIOHandler->Close(stream);
+    pIOHandler->Close(stream);
 }
 
 #endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER

+ 1 - 1
code/AssbinLoader.h

@@ -61,7 +61,7 @@ struct aiCamera;
 
 #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
 
-namespace Assimp	{
+namespace Assimp    {
 
 // ---------------------------------------------------------------------------------
 /** Importer class for 3D Studio r3 and r4 3DS files

+ 306 - 306
code/Assimp.cpp

@@ -59,39 +59,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // ------------------------------------------------------------------------------------------------
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-#	include <boost/thread/thread.hpp>
-#	include <boost/thread/mutex.hpp>
+#   include <boost/thread/thread.hpp>
+#   include <boost/thread/mutex.hpp>
 #endif
 // ------------------------------------------------------------------------------------------------
 using namespace Assimp;
 
 namespace Assimp
 {
-	// underlying structure for aiPropertyStore
-	typedef BatchLoader::PropertyMap PropertyMap;
+    // underlying structure for aiPropertyStore
+    typedef BatchLoader::PropertyMap PropertyMap;
 
-	/** Stores the LogStream objects for all active C log streams */
-	struct mpred {
-		bool operator  () (const aiLogStream& s0, const aiLogStream& s1) const  {
-			return s0.callback<s1.callback&&s0.user<s1.user;
-		}
-	};
-	typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
+    /** Stores the LogStream objects for all active C log streams */
+    struct mpred {
+        bool operator  () (const aiLogStream& s0, const aiLogStream& s1) const  {
+            return s0.callback<s1.callback&&s0.user<s1.user;
+        }
+    };
+    typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
 
-	/** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
-	typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
+    /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
+    typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
 
-	/** Local storage of all active log streams */
-	static LogStreamMap gActiveLogStreams;
+    /** Local storage of all active log streams */
+    static LogStreamMap gActiveLogStreams;
 
-	/** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
-	static PredefLogStreamMap gPredefinedStreams;
+    /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
+    static PredefLogStreamMap gPredefinedStreams;
 
-	/** Error message of the last failed import process */
-	static std::string gLastErrorString;
+    /** Error message of the last failed import process */
+    static std::string gLastErrorString;
 
-	/** Verbose logging active or not? */
-	static aiBool gVerboseLogging = false;
+    /** Verbose logging active or not? */
+    static aiBool gVerboseLogging = false;
 
     /** will return all registered importers. */
     void GetImporterInstanceList(std::vector< BaseImporter* >& out);
@@ -110,331 +110,331 @@ static boost::mutex gLogStreamMutex;
 class LogToCallbackRedirector : public LogStream
 {
 public:
-	LogToCallbackRedirector(const aiLogStream& s)
-		: stream (s)	{
-			ai_assert(NULL != s.callback);
-	}
+    LogToCallbackRedirector(const aiLogStream& s)
+        : stream (s)    {
+            ai_assert(NULL != s.callback);
+    }
 
-	~LogToCallbackRedirector()	{
+    ~LogToCallbackRedirector()  {
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-		boost::mutex::scoped_lock lock(gLogStreamMutex);
+        boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
-		// (HACK) Check whether the 'stream.user' pointer points to a
-		// custom LogStream allocated by #aiGetPredefinedLogStream.
-		// In this case, we need to delete it, too. Of course, this
-		// might cause strange problems, but the chance is quite low.
+        // (HACK) Check whether the 'stream.user' pointer points to a
+        // custom LogStream allocated by #aiGetPredefinedLogStream.
+        // In this case, we need to delete it, too. Of course, this
+        // might cause strange problems, but the chance is quite low.
 
-		PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
-			gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
+        PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
+            gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
 
-		if (it != gPredefinedStreams.end()) {
-			delete *it;
-			gPredefinedStreams.erase(it);
-		}
-	}
+        if (it != gPredefinedStreams.end()) {
+            delete *it;
+            gPredefinedStreams.erase(it);
+        }
+    }
 
-	/** @copydoc LogStream::write */
-	void write(const char* message)	{
-		stream.callback(message,stream.user);
-	}
+    /** @copydoc LogStream::write */
+    void write(const char* message) {
+        stream.callback(message,stream.user);
+    }
 
 private:
-	aiLogStream stream;
+    aiLogStream stream;
 };
 
 // ------------------------------------------------------------------------------------------------
 void ReportSceneNotFoundError()
 {
-	DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
-		"The C-API does not accept scenes produced by the C++ API and vice versa");
+    DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
+        "The C-API does not accept scenes produced by the C++ API and vice versa");
 
-	assert(false);
+    assert(false);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the given file and returns its content.
 const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
 {
-	return aiImportFileEx(pFile,pFlags,NULL);
+    return aiImportFileEx(pFile,pFlags,NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
 const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,  aiFileIO* pFS)
 {
-	return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
+    return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
 const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
-	aiFileIO* pFS,
-	const aiPropertyStore* props)
-{
-	ai_assert(NULL != pFile);
-
-	const aiScene* scene = NULL;
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-
-	// create an Importer for this file
-	Assimp::Importer* imp = new Assimp::Importer();
-
-	// copy properties
-	if(props) {
-		const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
-		ImporterPimpl* pimpl = imp->Pimpl();
-		pimpl->mIntProperties = pp->ints;
-		pimpl->mFloatProperties = pp->floats;
-		pimpl->mStringProperties = pp->strings;
-		pimpl->mMatrixProperties = pp->matrices;
-	}
-	// setup a custom IO system if necessary
-	if (pFS)	{
-		imp->SetIOHandler( new CIOSystemWrapper (pFS) );
-	}
-
-	// and have it read the file
-	scene = imp->ReadFile( pFile, pFlags);
-
-	// if succeeded, store the importer in the scene and keep it alive
-	if( scene)	{
-		ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
-		priv->mOrigImporter = imp;
-	}
-	else	{
-		// if failed, extract error code and destroy the import
-		gLastErrorString = imp->GetErrorString();
-		delete imp;
-	}
-
-	// return imported data. If the import failed the pointer is NULL anyways
-	ASSIMP_END_EXCEPTION_REGION(const aiScene*);
-	return scene;
+    aiFileIO* pFS,
+    const aiPropertyStore* props)
+{
+    ai_assert(NULL != pFile);
+
+    const aiScene* scene = NULL;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // create an Importer for this file
+    Assimp::Importer* imp = new Assimp::Importer();
+
+    // copy properties
+    if(props) {
+        const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
+        ImporterPimpl* pimpl = imp->Pimpl();
+        pimpl->mIntProperties = pp->ints;
+        pimpl->mFloatProperties = pp->floats;
+        pimpl->mStringProperties = pp->strings;
+        pimpl->mMatrixProperties = pp->matrices;
+    }
+    // setup a custom IO system if necessary
+    if (pFS)    {
+        imp->SetIOHandler( new CIOSystemWrapper (pFS) );
+    }
+
+    // and have it read the file
+    scene = imp->ReadFile( pFile, pFlags);
+
+    // if succeeded, store the importer in the scene and keep it alive
+    if( scene)  {
+        ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
+        priv->mOrigImporter = imp;
+    }
+    else    {
+        // if failed, extract error code and destroy the import
+        gLastErrorString = imp->GetErrorString();
+        delete imp;
+    }
+
+    // return imported data. If the import failed the pointer is NULL anyways
+    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    return scene;
 }
 
 // ------------------------------------------------------------------------------------------------
 const aiScene* aiImportFileFromMemory(
-	const char* pBuffer,
-	unsigned int pLength,
-	unsigned int pFlags,
-	const char* pHint)
+    const char* pBuffer,
+    unsigned int pLength,
+    unsigned int pFlags,
+    const char* pHint)
 {
-	return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
+    return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
 const aiScene* aiImportFileFromMemoryWithProperties(
-	const char* pBuffer,
-	unsigned int pLength,
-	unsigned int pFlags,
-	const char* pHint,
-	const aiPropertyStore* props)
-{
-	ai_assert(NULL != pBuffer && 0 != pLength);
-
-	const aiScene* scene = NULL;
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-
-	// create an Importer for this file
-	Assimp::Importer* imp = new Assimp::Importer();
-
-	// copy properties
-	if(props) {
-		const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
-		ImporterPimpl* pimpl = imp->Pimpl();
-		pimpl->mIntProperties = pp->ints;
-		pimpl->mFloatProperties = pp->floats;
-		pimpl->mStringProperties = pp->strings;
-		pimpl->mMatrixProperties = pp->matrices;
-	}
-
-	// and have it read the file from the memory buffer
-	scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
-
-	// if succeeded, store the importer in the scene and keep it alive
-	if( scene)	{
-		 ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
-		 priv->mOrigImporter = imp;
-	}
-	else	{
-		// if failed, extract error code and destroy the import
-		gLastErrorString = imp->GetErrorString();
-		delete imp;
-	}
-	// return imported data. If the import failed the pointer is NULL anyways
-	ASSIMP_END_EXCEPTION_REGION(const aiScene*);
-	return scene;
+    const char* pBuffer,
+    unsigned int pLength,
+    unsigned int pFlags,
+    const char* pHint,
+    const aiPropertyStore* props)
+{
+    ai_assert(NULL != pBuffer && 0 != pLength);
+
+    const aiScene* scene = NULL;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // create an Importer for this file
+    Assimp::Importer* imp = new Assimp::Importer();
+
+    // copy properties
+    if(props) {
+        const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
+        ImporterPimpl* pimpl = imp->Pimpl();
+        pimpl->mIntProperties = pp->ints;
+        pimpl->mFloatProperties = pp->floats;
+        pimpl->mStringProperties = pp->strings;
+        pimpl->mMatrixProperties = pp->matrices;
+    }
+
+    // and have it read the file from the memory buffer
+    scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
+
+    // if succeeded, store the importer in the scene and keep it alive
+    if( scene)  {
+         ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
+         priv->mOrigImporter = imp;
+    }
+    else    {
+        // if failed, extract error code and destroy the import
+        gLastErrorString = imp->GetErrorString();
+        delete imp;
+    }
+    // return imported data. If the import failed the pointer is NULL anyways
+    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    return scene;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Releases all resources associated with the given import process.
 void aiReleaseImport( const aiScene* pScene)
 {
-	if (!pScene) {
-		return;
-	}
+    if (!pScene) {
+        return;
+    }
 
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 
-	// find the importer associated with this data
-	const ScenePrivateData* priv = ScenePriv(pScene);
-	if( !priv || !priv->mOrigImporter)	{
-		delete pScene;
-	}
-	else {
-		// deleting the Importer also deletes the scene
-		// Note: the reason that this is not written as 'delete priv->mOrigImporter'
-		// is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
-		Importer* importer = priv->mOrigImporter;
-		delete importer;
-	}
+    // find the importer associated with this data
+    const ScenePrivateData* priv = ScenePriv(pScene);
+    if( !priv || !priv->mOrigImporter)  {
+        delete pScene;
+    }
+    else {
+        // deleting the Importer also deletes the scene
+        // Note: the reason that this is not written as 'delete priv->mOrigImporter'
+        // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
+        Importer* importer = priv->mOrigImporter;
+        delete importer;
+    }
 
-	ASSIMP_END_EXCEPTION_REGION(void);
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
-	unsigned int pFlags)
+    unsigned int pFlags)
 {
-	const aiScene* sc = NULL;
+    const aiScene* sc = NULL;
 
 
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 
-	// find the importer associated with this data
-	const ScenePrivateData* priv = ScenePriv(pScene);
-	if( !priv || !priv->mOrigImporter)	{
-		ReportSceneNotFoundError();
-		return NULL;
-	}
+    // find the importer associated with this data
+    const ScenePrivateData* priv = ScenePriv(pScene);
+    if( !priv || !priv->mOrigImporter)  {
+        ReportSceneNotFoundError();
+        return NULL;
+    }
 
-	sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
+    sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
 
-	if (!sc) {
-		aiReleaseImport(pScene);
-		return NULL;
-	}
+    if (!sc) {
+        aiReleaseImport(pScene);
+        return NULL;
+    }
 
-	ASSIMP_END_EXCEPTION_REGION(const aiScene*);
-	return sc;
+    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    return sc;
 }
 
 // ------------------------------------------------------------------------------------------------
 void CallbackToLogRedirector (const char* msg, char* dt)
 {
-	ai_assert(NULL != msg && NULL != dt);
-	LogStream* s = (LogStream*)dt;
+    ai_assert(NULL != msg && NULL != dt);
+    LogStream* s = (LogStream*)dt;
 
-	s->write(msg);
+    s->write(msg);
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
 {
-	aiLogStream sout;
+    aiLogStream sout;
 
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-	LogStream* stream = LogStream::createDefaultStream(pStream,file);
-	if (!stream) {
-		sout.callback = NULL;
-		sout.user = NULL;
-	}
-	else {
-		sout.callback = &CallbackToLogRedirector;
-		sout.user = (char*)stream;
-	}
-	gPredefinedStreams.push_back(stream);
-	ASSIMP_END_EXCEPTION_REGION(aiLogStream);
-	return sout;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    LogStream* stream = LogStream::createDefaultStream(pStream,file);
+    if (!stream) {
+        sout.callback = NULL;
+        sout.user = NULL;
+    }
+    else {
+        sout.callback = &CallbackToLogRedirector;
+        sout.user = (char*)stream;
+    }
+    gPredefinedStreams.push_back(stream);
+    ASSIMP_END_EXCEPTION_REGION(aiLogStream);
+    return sout;
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
 {
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-	boost::mutex::scoped_lock lock(gLogStreamMutex);
+    boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 
-	LogStream* lg = new LogToCallbackRedirector(*stream);
-	gActiveLogStreams[*stream] = lg;
+    LogStream* lg = new LogToCallbackRedirector(*stream);
+    gActiveLogStreams[*stream] = lg;
 
-	if (DefaultLogger::isNullLogger()) {
-		DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
-	}
-	DefaultLogger::get()->attachStream(lg);
-	ASSIMP_END_EXCEPTION_REGION(void);
+    if (DefaultLogger::isNullLogger()) {
+        DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
+    }
+    DefaultLogger::get()->attachStream(lg);
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
 {
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-	boost::mutex::scoped_lock lock(gLogStreamMutex);
+    boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
-	// find the logstream associated with this data
-	LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
-	// it should be there... else the user is playing fools with us
-	if( it == gActiveLogStreams.end())	{
-		return AI_FAILURE;
-	}
-	DefaultLogger::get()->detatchStream( it->second );
-	delete it->second;
+    // find the logstream associated with this data
+    LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
+    // it should be there... else the user is playing fools with us
+    if( it == gActiveLogStreams.end())  {
+        return AI_FAILURE;
+    }
+    DefaultLogger::get()->detatchStream( it->second );
+    delete it->second;
 
-	gActiveLogStreams.erase( it);
+    gActiveLogStreams.erase( it);
 
-	if (gActiveLogStreams.empty()) {
-		DefaultLogger::kill();
-	}
-	ASSIMP_END_EXCEPTION_REGION(aiReturn);
-	return AI_SUCCESS;
+    if (gActiveLogStreams.empty()) {
+        DefaultLogger::kill();
+    }
+    ASSIMP_END_EXCEPTION_REGION(aiReturn);
+    return AI_SUCCESS;
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiDetachAllLogStreams(void)
 {
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-	boost::mutex::scoped_lock lock(gLogStreamMutex);
+    boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
-	for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
-		DefaultLogger::get()->detatchStream( it->second );
-		delete it->second;
-	}
-	gActiveLogStreams.clear();
-	DefaultLogger::kill();
-	ASSIMP_END_EXCEPTION_REGION(void);
+    for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
+        DefaultLogger::get()->detatchStream( it->second );
+        delete it->second;
+    }
+    gActiveLogStreams.clear();
+    DefaultLogger::kill();
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiEnableVerboseLogging(aiBool d)
 {
-	if (!DefaultLogger::isNullLogger()) {
-		DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
-	}
-	gVerboseLogging = d;
+    if (!DefaultLogger::isNullLogger()) {
+        DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
+    }
+    gVerboseLogging = d;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns the error text of the last failed import process.
 const char* aiGetErrorString()
 {
-	return gLastErrorString.c_str();
+    return gLastErrorString.c_str();
 }
 
 // -----------------------------------------------------------------------------------------------
 // Return the description of a importer given its index
 const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex)
 {
-	return Importer().GetImporterInfo(pIndex);
+    return Importer().GetImporterInfo(pIndex);
 }
 
 // -----------------------------------------------------------------------------------------------
 // Return the number of importers
 size_t aiGetImportFormatCount(void)
 {
-	return Importer().GetImporterCount();
+    return Importer().GetImporterCount();
 }
 
 
@@ -442,195 +442,195 @@ size_t aiGetImportFormatCount(void)
 // Returns the error text of the last failed import process.
 aiBool aiIsExtensionSupported(const char* szExtension)
 {
-	ai_assert(NULL != szExtension);
-	aiBool candoit=AI_FALSE;
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ai_assert(NULL != szExtension);
+    aiBool candoit=AI_FALSE;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 
-	// FIXME: no need to create a temporary Importer instance just for that ..
-	Assimp::Importer tmp;
-	candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
+    // FIXME: no need to create a temporary Importer instance just for that ..
+    Assimp::Importer tmp;
+    candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
 
-	ASSIMP_END_EXCEPTION_REGION(aiBool);
-	return candoit;
+    ASSIMP_END_EXCEPTION_REGION(aiBool);
+    return candoit;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get a list of all file extensions supported by ASSIMP
 void aiGetExtensionList(aiString* szOut)
 {
-	ai_assert(NULL != szOut);
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ai_assert(NULL != szOut);
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 
-	// FIXME: no need to create a temporary Importer instance just for that ..
-	Assimp::Importer tmp;
-	tmp.GetExtensionList(*szOut);
+    // FIXME: no need to create a temporary Importer instance just for that ..
+    Assimp::Importer tmp;
+    tmp.GetExtensionList(*szOut);
 
-	ASSIMP_END_EXCEPTION_REGION(void);
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get the memory requirements for a particular import.
 void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
-	C_STRUCT aiMemoryInfo* in)
+    C_STRUCT aiMemoryInfo* in)
 {
-	ASSIMP_BEGIN_EXCEPTION_REGION();
+    ASSIMP_BEGIN_EXCEPTION_REGION();
 
-	// find the importer associated with this data
-	const ScenePrivateData* priv = ScenePriv(pIn);
-	if( !priv || !priv->mOrigImporter)	{
-		ReportSceneNotFoundError();
-		return;
-	}
+    // find the importer associated with this data
+    const ScenePrivateData* priv = ScenePriv(pIn);
+    if( !priv || !priv->mOrigImporter)  {
+        ReportSceneNotFoundError();
+        return;
+    }
 
-	return priv->mOrigImporter->GetMemoryRequirements(*in);
-	ASSIMP_END_EXCEPTION_REGION(void);
+    return priv->mOrigImporter->GetMemoryRequirements(*in);
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
 {
-	return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
+    return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
 }
 
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
 {
-	delete reinterpret_cast<PropertyMap*>(p);
+    delete reinterpret_cast<PropertyMap*>(p);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Importer::SetPropertyInteger
 ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
 {
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-	PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
-	SetGenericProperty<int>(pp->ints,szName,value);
-	ASSIMP_END_EXCEPTION_REGION(void);
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<int>(pp->ints,szName,value);
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Importer::SetPropertyFloat
 ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value)
 {
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-	PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
-	SetGenericProperty<float>(pp->floats,szName,value);
-	ASSIMP_END_EXCEPTION_REGION(void);
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<float>(pp->floats,szName,value);
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Importer::SetPropertyString
 ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
-	const C_STRUCT aiString* st)
+    const C_STRUCT aiString* st)
 {
-	if (!st) {
-		return;
-	}
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-	PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
-	SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
-	ASSIMP_END_EXCEPTION_REGION(void);
+    if (!st) {
+        return;
+    }
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Importer::SetPropertyMatrix
 ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
-	const C_STRUCT aiMatrix4x4* mat)
+    const C_STRUCT aiMatrix4x4* mat)
 {
-	if (!mat) {
-		return;
-	}
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-	PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
-	SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
-	ASSIMP_END_EXCEPTION_REGION(void);
+    if (!mat) {
+        return;
+    }
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
+    ASSIMP_END_EXCEPTION_REGION(void);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Rotation matrix to quaternion
 ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
 {
-	ai_assert(NULL != quat && NULL != mat);
-	*quat = aiQuaternion(*mat);
+    ai_assert(NULL != quat && NULL != mat);
+    *quat = aiQuaternion(*mat);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Matrix decomposition
 ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
-	aiQuaternion* rotation,
-	aiVector3D* position)
+    aiQuaternion* rotation,
+    aiVector3D* position)
 {
-	ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat);
-	mat->Decompose(*scaling,*rotation,*position);
+    ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat);
+    mat->Decompose(*scaling,*rotation,*position);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Matrix transpose
 ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
 {
-	ai_assert(NULL != mat);
-	mat->Transpose();
+    ai_assert(NULL != mat);
+    mat->Transpose();
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
 {
-	ai_assert(NULL != mat);
-	mat->Transpose();
+    ai_assert(NULL != mat);
+    mat->Transpose();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Vector transformation
 ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
-	const aiMatrix3x3* mat)
+    const aiMatrix3x3* mat)
 {
-	ai_assert(NULL != mat && NULL != vec);
-	*vec *= (*mat);
+    ai_assert(NULL != mat && NULL != vec);
+    *vec *= (*mat);
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
-	const aiMatrix4x4* mat)
+    const aiMatrix4x4* mat)
 {
-	ai_assert(NULL != mat && NULL != vec);
-	*vec *= (*mat);
+    ai_assert(NULL != mat && NULL != vec);
+    *vec *= (*mat);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Matrix multiplication
 ASSIMP_API void aiMultiplyMatrix4(
-	aiMatrix4x4* dst,
-	const aiMatrix4x4* src)
+    aiMatrix4x4* dst,
+    const aiMatrix4x4* src)
 {
-	ai_assert(NULL != dst && NULL != src);
-	*dst = (*dst) * (*src);
+    ai_assert(NULL != dst && NULL != src);
+    *dst = (*dst) * (*src);
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiMultiplyMatrix3(
-	aiMatrix3x3* dst,
-	const aiMatrix3x3* src)
+    aiMatrix3x3* dst,
+    const aiMatrix3x3* src)
 {
-	ai_assert(NULL != dst && NULL != src);
-	*dst = (*dst) * (*src);
+    ai_assert(NULL != dst && NULL != src);
+    *dst = (*dst) * (*src);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Matrix identity
 ASSIMP_API void aiIdentityMatrix3(
-	aiMatrix3x3* mat)
+    aiMatrix3x3* mat)
 {
-	ai_assert(NULL != mat);
-	*mat = aiMatrix3x3();
+    ai_assert(NULL != mat);
+    *mat = aiMatrix3x3();
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiIdentityMatrix4(
-	aiMatrix4x4* mat)
+    aiMatrix4x4* mat)
 {
-	ai_assert(NULL != mat);
-	*mat = aiMatrix4x4();
+    ai_assert(NULL != mat);
+    *mat = aiMatrix4x4();
 }
 
 // ------------------------------------------------------------------------------------------------

+ 27 - 27
code/AssimpCExport.cpp

@@ -54,76 +54,76 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API size_t aiGetExportFormatCount(void)
 {
-	return Exporter().GetExportFormatCount();
+    return Exporter().GetExportFormatCount();
 }
 
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
 {
-	// Note: this is valid as the index always pertains to a builtin exporter,
-	// for which the returned structure is guaranteed to be of static storage duration.
-	return Exporter().GetExportFormatDescription(pIndex);
+    // Note: this is valid as the index always pertains to a builtin exporter,
+    // for which the returned structure is guaranteed to be of static storage duration.
+    return Exporter().GetExportFormatDescription(pIndex);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)
 {
-	if (!pOut || !pIn) {
-		return;
-	}
+    if (!pOut || !pIn) {
+        return;
+    }
 
-	SceneCombiner::CopyScene(pOut,pIn,true);
-	ScenePriv(*pOut)->mIsCopy = true;
+    SceneCombiner::CopyScene(pOut,pIn,true);
+    ScenePriv(*pOut)->mIsCopy = true;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn)
 {
-	// note: aiReleaseImport() is also able to delete scene copies, but in addition
-	// it also handles scenes with import metadata.
-	delete pIn;
+    // note: aiReleaseImport() is also able to delete scene copies, but in addition
+    // it also handles scenes with import metadata.
+    delete pIn;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing )
 {
-	return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing);
+    return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing )
 {
-	Exporter exp;
+    Exporter exp;
 
-	if (pIO) {
-		exp.SetIOHandler(new CIOSystemWrapper(pIO));
-	}
-	return exp.Export(pScene,pFormatId,pFileName,pPreprocessing);
+    if (pIO) {
+        exp.SetIOHandler(new CIOSystemWrapper(pIO));
+    }
+    return exp.Export(pScene,pFormatId,pFileName,pPreprocessing);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing  )
 {
-	Exporter exp;
-	if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) {
-		return NULL;
-	}
-	const aiExportDataBlob* blob = exp.GetOrphanedBlob();
-	ai_assert(blob);
-
-	return blob;
+    Exporter exp;
+    if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) {
+        return NULL;
+    }
+    const aiExportDataBlob* blob = exp.GetOrphanedBlob();
+    ai_assert(blob);
+
+    return blob;
 }
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData )
 {
-	delete pData;
+    delete pData;
 }
 
 #endif // !ASSIMP_BUILD_NO_EXPORT

+ 523 - 523
code/AssxmlExporter.cpp

@@ -48,9 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/Exporter.hpp"
 
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#	include <zlib.h>
+#   include <zlib.h>
 #else
-#	include "../contrib/zlib/zlib.h"
+#   include "../contrib/zlib/zlib.h"
 #endif
 
 #include <time.h>
@@ -61,94 +61,94 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 
-namespace Assimp	{
+namespace Assimp    {
 
-namespace AssxmlExport	{
+namespace AssxmlExport  {
 
 int ioprintf( IOStream * io, const char * format, ... )
 {
-	char sz[4096];
-	va_list va;
-	va_start( va, format );
-	int nSize = vsnprintf( sz, 4096, format, va );
+    char sz[4096];
+    va_list va;
+    va_start( va, format );
+    int nSize = vsnprintf( sz, 4096, format, va );
   ai_assert( nSize < 4096 );
-	va_end( va );
+    va_end( va );
 
-	io->Write( sz, sizeof(char), nSize );
+    io->Write( sz, sizeof(char), nSize );
 
-	return nSize;
+    return nSize;
 }
 
 // -----------------------------------------------------------------------------------
 // Convert a name to standard XML format
 void ConvertName(aiString& out, const aiString& in)
 {
-	out.length = 0;
-	for (unsigned int i = 0; i < in.length; ++i)  {
-		switch (in.data[i]) {
-			case '<':
-				out.Append("&lt;");break;
-			case '>':
-				out.Append("&gt;");break;
-			case '&':
-				out.Append("&amp;");break;
-			case '\"':
-				out.Append("&quot;");break;
-			case '\'':
-				out.Append("&apos;");break;
-			default:
-				out.data[out.length++] = in.data[i];
-		}
-	}
-	out.data[out.length] = 0;
+    out.length = 0;
+    for (unsigned int i = 0; i < in.length; ++i)  {
+        switch (in.data[i]) {
+            case '<':
+                out.Append("&lt;");break;
+            case '>':
+                out.Append("&gt;");break;
+            case '&':
+                out.Append("&amp;");break;
+            case '\"':
+                out.Append("&quot;");break;
+            case '\'':
+                out.Append("&apos;");break;
+            default:
+                out.data[out.length++] = in.data[i];
+        }
+    }
+    out.data[out.length] = 0;
 }
 
 // -----------------------------------------------------------------------------------
 // Write a single node as text dump
 void WriteNode(const aiNode* node, IOStream * io, unsigned int depth)
 {
-	char prefix[512];
-	for (unsigned int i = 0; i < depth;++i)
-		prefix[i] = '\t';
-	prefix[depth] = '\0';
-
-	const aiMatrix4x4& m = node->mTransformation;
-
-	aiString name;
-	ConvertName(name,node->mName);
-	ioprintf(io,"%s<Node name=\"%s\"> \n"
-		"%s\t<Matrix4> \n"
-		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
-		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
-		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
-		"%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
-		"%s\t</Matrix4> \n",
-		prefix,name.data,prefix,
-		prefix,m.a1,m.a2,m.a3,m.a4,
-		prefix,m.b1,m.b2,m.b3,m.b4,
-		prefix,m.c1,m.c2,m.c3,m.c4,
-		prefix,m.d1,m.d2,m.d3,m.d4,prefix);
-
-	if (node->mNumMeshes) {
-		ioprintf(io, "%s\t<MeshRefs num=\"%i\">\n%s\t",
-			prefix,node->mNumMeshes,prefix);
-
-		for (unsigned int i = 0; i < node->mNumMeshes;++i) {
-			ioprintf(io,"%i ",node->mMeshes[i]);
-		}
-		ioprintf(io,"\n%s\t</MeshRefs>\n",prefix);
-	}
-
-	if (node->mNumChildren) {
-		ioprintf(io,"%s\t<NodeList num=\"%i\">\n",
-			prefix,node->mNumChildren);
-
-		for (unsigned int i = 0; i < node->mNumChildren;++i) {
-			WriteNode(node->mChildren[i],io,depth+2);
-		}
-		ioprintf(io,"%s\t</NodeList>\n",prefix);
-	}
-	ioprintf(io,"%s</Node>\n",prefix);
+    char prefix[512];
+    for (unsigned int i = 0; i < depth;++i)
+        prefix[i] = '\t';
+    prefix[depth] = '\0';
+
+    const aiMatrix4x4& m = node->mTransformation;
+
+    aiString name;
+    ConvertName(name,node->mName);
+    ioprintf(io,"%s<Node name=\"%s\"> \n"
+        "%s\t<Matrix4> \n"
+        "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+        "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+        "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+        "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+        "%s\t</Matrix4> \n",
+        prefix,name.data,prefix,
+        prefix,m.a1,m.a2,m.a3,m.a4,
+        prefix,m.b1,m.b2,m.b3,m.b4,
+        prefix,m.c1,m.c2,m.c3,m.c4,
+        prefix,m.d1,m.d2,m.d3,m.d4,prefix);
+
+    if (node->mNumMeshes) {
+        ioprintf(io, "%s\t<MeshRefs num=\"%i\">\n%s\t",
+            prefix,node->mNumMeshes,prefix);
+
+        for (unsigned int i = 0; i < node->mNumMeshes;++i) {
+            ioprintf(io,"%i ",node->mMeshes[i]);
+        }
+        ioprintf(io,"\n%s\t</MeshRefs>\n",prefix);
+    }
+
+    if (node->mNumChildren) {
+        ioprintf(io,"%s\t<NodeList num=\"%i\">\n",
+            prefix,node->mNumChildren);
+
+        for (unsigned int i = 0; i < node->mNumChildren;++i) {
+            WriteNode(node->mChildren[i],io,depth+2);
+        }
+        ioprintf(io,"%s\t</NodeList>\n",prefix);
+    }
+    ioprintf(io,"%s</Node>\n",prefix);
 }
 
 
@@ -156,19 +156,19 @@ void WriteNode(const aiNode* node, IOStream * io, unsigned int depth)
 // Some chuncks of text will need to be encoded for XML
 // http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377
 static std::string encodeXML(const std::string& data) {
-		std::string buffer;
-		buffer.reserve(data.size());
-		for(size_t pos = 0; pos != data.size(); ++pos) {
-				switch(data[pos]) {
-						case '&':  buffer.append("&amp;");				break;
-						case '\"': buffer.append("&quot;");				break;
-						case '\'': buffer.append("&apos;");				break;
-						case '<':  buffer.append("&lt;");					break;
-						case '>':  buffer.append("&gt;");					break;
-						default:   buffer.append(&data[pos], 1);	break;
-				}
-		}
-		return buffer;
+        std::string buffer;
+        buffer.reserve(data.size());
+        for(size_t pos = 0; pos != data.size(); ++pos) {
+                switch(data[pos]) {
+                        case '&':  buffer.append("&amp;");              break;
+                        case '\"': buffer.append("&quot;");             break;
+                        case '\'': buffer.append("&apos;");             break;
+                        case '<':  buffer.append("&lt;");                   break;
+                        case '>':  buffer.append("&gt;");                   break;
+                        default:   buffer.append(&data[pos], 1);    break;
+                }
+        }
+        return buffer;
 }
 
 
@@ -177,462 +177,462 @@ static std::string encodeXML(const std::string& data) {
 // Write a text model dump
 void WriteDump(const aiScene* scene, IOStream* io, bool shortened)
 {
-	time_t tt = ::time(NULL);
-	tm* p     = ::gmtime(&tt);
+    time_t tt = ::time(NULL);
+    tm* p     = ::gmtime(&tt);
 
-	aiString name;
+    aiString name;
 
-	// write header
-	ioprintf(io,
-		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
-		"<ASSIMP format_id=\"1\">\n\n"
+    // write header
+    ioprintf(io,
+        "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+        "<ASSIMP format_id=\"1\">\n\n"
 
-		"<!-- XML Model dump produced by assimp dump\n"
-		"  Library version: %i.%i.%i\n"
-		"  %s\n"
-		"-->"
-		" \n\n"
-		"<Scene flags=\"%i\" postprocessing=\"%i\">\n",
+        "<!-- XML Model dump produced by assimp dump\n"
+        "  Library version: %i.%i.%i\n"
+        "  %s\n"
+        "-->"
+        " \n\n"
+        "<Scene flags=\"%i\" postprocessing=\"%i\">\n",
 
-		aiGetVersionMajor(),aiGetVersionMinor(),aiGetVersionRevision(),asctime(p),
-		scene->mFlags,
-		0 /*globalImporter->GetEffectivePostProcessing()*/);
+        aiGetVersionMajor(),aiGetVersionMinor(),aiGetVersionRevision(),asctime(p),
+        scene->mFlags,
+        0 /*globalImporter->GetEffectivePostProcessing()*/);
 
-	// write the node graph
-	WriteNode(scene->mRootNode, io, 0);
+    // write the node graph
+    WriteNode(scene->mRootNode, io, 0);
 
 #if 0
-		// write cameras
-	for (unsigned int i = 0; i < scene->mNumCameras;++i) {
-		aiCamera* cam  = scene->mCameras[i];
-		ConvertName(name,cam->mName);
-
-		// camera header
-		ioprintf(io,"\t<Camera parent=\"%s\">\n"
-			"\t\t<Vector3 name=\"up\"        > %0 8f %0 8f %0 8f </Vector3>\n"
-			"\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n"
-			"\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
-			"\t\t<Float   name=\"fov\"       > %f </Float>\n"
-			"\t\t<Float   name=\"aspect\"    > %f </Float>\n"
-			"\t\t<Float   name=\"near_clip\" > %f </Float>\n"
-			"\t\t<Float   name=\"far_clip\"  > %f </Float>\n"
-			"\t</Camera>\n",
-			name.data,
-			cam->mUp.x,cam->mUp.y,cam->mUp.z,
-			cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
-			cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
-			cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
-	}
-
-	// write lights
-	for (unsigned int i = 0; i < scene->mNumLights;++i) {
-		aiLight* l  = scene->mLights[i];
-		ConvertName(name,l->mName);
-
-		// light header
-		ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
-			"\t\t<Vector3 name=\"diffuse\"   > %0 8f %0 8f %0 8f </Vector3>\n"
-			"\t\t<Vector3 name=\"specular\"  > %0 8f %0 8f %0 8f </Vector3>\n"
-			"\t\t<Vector3 name=\"ambient\"   > %0 8f %0 8f %0 8f </Vector3>\n",
-			name.data,
-			(l->mType == aiLightSource_DIRECTIONAL ? "directional" :
-			(l->mType == aiLightSource_POINT ? "point" : "spot" )),
-			l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
-			l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
-			l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
-
-		if (l->mType != aiLightSource_DIRECTIONAL) {
-			ioprintf(io,
-				"\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
-				"\t\t<Float   name=\"atten_cst\" > %f </Float>\n"
-				"\t\t<Float   name=\"atten_lin\" > %f </Float>\n"
-				"\t\t<Float   name=\"atten_sqr\" > %f </Float>\n",
-				l->mPosition.x,l->mPosition.y,l->mPosition.z,
-				l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
-		}
-
-		if (l->mType != aiLightSource_POINT) {
-			ioprintf(io,
-				"\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n",
-				l->mDirection.x,l->mDirection.y,l->mDirection.z);
-		}
-
-		if (l->mType == aiLightSource_SPOT) {
-			ioprintf(io,
-				"\t\t<Float   name=\"cone_out\" > %f </Float>\n"
-				"\t\t<Float   name=\"cone_inn\" > %f </Float>\n",
-				l->mAngleOuterCone,l->mAngleInnerCone);
-		}
-		ioprintf(io,"\t</Light>\n");
-	}
+        // write cameras
+    for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+        aiCamera* cam  = scene->mCameras[i];
+        ConvertName(name,cam->mName);
+
+        // camera header
+        ioprintf(io,"\t<Camera parent=\"%s\">\n"
+            "\t\t<Vector3 name=\"up\"        > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Float   name=\"fov\"       > %f </Float>\n"
+            "\t\t<Float   name=\"aspect\"    > %f </Float>\n"
+            "\t\t<Float   name=\"near_clip\" > %f </Float>\n"
+            "\t\t<Float   name=\"far_clip\"  > %f </Float>\n"
+            "\t</Camera>\n",
+            name.data,
+            cam->mUp.x,cam->mUp.y,cam->mUp.z,
+            cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
+            cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
+            cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
+    }
+
+    // write lights
+    for (unsigned int i = 0; i < scene->mNumLights;++i) {
+        aiLight* l  = scene->mLights[i];
+        ConvertName(name,l->mName);
+
+        // light header
+        ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
+            "\t\t<Vector3 name=\"diffuse\"   > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"specular\"  > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"ambient\"   > %0 8f %0 8f %0 8f </Vector3>\n",
+            name.data,
+            (l->mType == aiLightSource_DIRECTIONAL ? "directional" :
+            (l->mType == aiLightSource_POINT ? "point" : "spot" )),
+            l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
+            l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
+            l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
+
+        if (l->mType != aiLightSource_DIRECTIONAL) {
+            ioprintf(io,
+                "\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
+                "\t\t<Float   name=\"atten_cst\" > %f </Float>\n"
+                "\t\t<Float   name=\"atten_lin\" > %f </Float>\n"
+                "\t\t<Float   name=\"atten_sqr\" > %f </Float>\n",
+                l->mPosition.x,l->mPosition.y,l->mPosition.z,
+                l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
+        }
+
+        if (l->mType != aiLightSource_POINT) {
+            ioprintf(io,
+                "\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n",
+                l->mDirection.x,l->mDirection.y,l->mDirection.z);
+        }
+
+        if (l->mType == aiLightSource_SPOT) {
+            ioprintf(io,
+                "\t\t<Float   name=\"cone_out\" > %f </Float>\n"
+                "\t\t<Float   name=\"cone_inn\" > %f </Float>\n",
+                l->mAngleOuterCone,l->mAngleInnerCone);
+        }
+        ioprintf(io,"\t</Light>\n");
+    }
 #endif
 
-	// write textures
-	if (scene->mNumTextures) {
-		ioprintf(io,"<TextureList num=\"%i\">\n",scene->mNumTextures);
-		for (unsigned int i = 0; i < scene->mNumTextures;++i) {
-			aiTexture* tex  = scene->mTextures[i];
-			bool compressed = (tex->mHeight == 0);
-
-			// mesh header
-			ioprintf(io,"\t<Texture width=\"%i\" height=\"%i\" compressed=\"%s\"> \n",
-				(compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight),
-				(compressed ? "true" : "false"));
-
-			if (compressed) {
-				ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth);
-
-				if (!shortened) {
-					for (unsigned int n = 0; n < tex->mWidth;++n) {
-						ioprintf(io,"\t\t\t%2x",reinterpret_cast<uint8_t*>(tex->pcData)[n]);
-						if (n && !(n % 50)) {
-							ioprintf(io,"\n");
-						}
-					}
-				}
-			}
-			else if (!shortened){
-				ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth*tex->mHeight*4);
-
-				// const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1;
-				for (unsigned int y = 0; y < tex->mHeight;++y) {
-					for (unsigned int x = 0; x < tex->mWidth;++x) {
-						aiTexel* tx = tex->pcData + y*tex->mWidth+x;
-						unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a;
-						ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a);
-
-						// group by four for readibility
-						if (0 == (x+y*tex->mWidth) % 4)
-							ioprintf(io,"\n");
-					}
-				}
-			}
-			ioprintf(io,"\t\t</Data>\n\t</Texture>\n");
-		}
-		ioprintf(io,"</TextureList>\n");
-	}
-
-	// write materials
-	if (scene->mNumMaterials) {
-		ioprintf(io,"<MaterialList num=\"%i\">\n",scene->mNumMaterials);
-		for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
-			const aiMaterial* mat = scene->mMaterials[i];
-
-			ioprintf(io,"\t<Material>\n");
-			ioprintf(io,"\t\t<MatPropertyList  num=\"%i\">\n",mat->mNumProperties);
-			for (unsigned int n = 0; n < mat->mNumProperties;++n) {
-
-				const aiMaterialProperty* prop = mat->mProperties[n];
-				const char* sz = "";
-				if (prop->mType == aiPTI_Float) {
-					sz = "float";
-				}
-				else if (prop->mType == aiPTI_Integer) {
-					sz = "integer";
-				}
-				else if (prop->mType == aiPTI_String) {
-					sz = "string";
-				}
-				else if (prop->mType == aiPTI_Buffer) {
-					sz = "binary_buffer";
-				}
-
-				ioprintf(io,"\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%i\"",
-					prop->mKey.data, sz,
-					::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex);
-
-				if (prop->mType == aiPTI_Float) {
-					ioprintf(io," size=\"%i\">\n\t\t\t\t",
-						static_cast<int>(prop->mDataLength/sizeof(float)));
-
-					for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) {
-						ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float))));
-					}
-				}
-				else if (prop->mType == aiPTI_Integer) {
-					ioprintf(io," size=\"%i\">\n\t\t\t\t",
-						static_cast<int>(prop->mDataLength/sizeof(int)));
-
-					for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) {
-						ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int))));
-					}
-				}
-				else if (prop->mType == aiPTI_Buffer) {
-					ioprintf(io," size=\"%i\">\n\t\t\t\t",
-						static_cast<int>(prop->mDataLength));
-
-					for (unsigned int p = 0; p < prop->mDataLength;++p) {
-						ioprintf(io,"%2x ",prop->mData[p]);
-						if (p && 0 == p%30) {
-							ioprintf(io,"\n\t\t\t\t");
-						}
-					}
-				}
-				else if (prop->mType == aiPTI_String) {
-					ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */);
-				}
-				ioprintf(io,"\n\t\t\t</MatProperty>\n");
-			}
-			ioprintf(io,"\t\t</MatPropertyList>\n");
-			ioprintf(io,"\t</Material>\n");
-		}
-		ioprintf(io,"</MaterialList>\n");
-	}
-
-	// write animations
-	if (scene->mNumAnimations) {
-		ioprintf(io,"<AnimationList num=\"%i\">\n",scene->mNumAnimations);
-		for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
-			aiAnimation* anim = scene->mAnimations[i];
-
-			// anim header
-			ConvertName(name,anim->mName);
-			ioprintf(io,"\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
-				name.data, anim->mDuration, anim->mTicksPerSecond);
-
-			// write bone animation channels
-			if (anim->mNumChannels) {
-				ioprintf(io,"\t\t<NodeAnimList num=\"%i\">\n",anim->mNumChannels);
-				for (unsigned int n = 0; n < anim->mNumChannels;++n) {
-					aiNodeAnim* nd = anim->mChannels[n];
-
-					// node anim header
-					ConvertName(name,nd->mNodeName);
-					ioprintf(io,"\t\t\t<NodeAnim node=\"%s\">\n",name.data);
-
-					if (!shortened) {
-						// write position keys
-						if (nd->mNumPositionKeys) {
-							ioprintf(io,"\t\t\t\t<PositionKeyList num=\"%i\">\n",nd->mNumPositionKeys);
-							for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) {
-								aiVectorKey* vc = nd->mPositionKeys+a;
-								ioprintf(io,"\t\t\t\t\t<PositionKey time=\"%e\">\n"
-									"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
-									vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
-							}
-							ioprintf(io,"\t\t\t\t</PositionKeyList>\n");
-						}
-
-						// write scaling keys
-						if (nd->mNumScalingKeys) {
-							ioprintf(io,"\t\t\t\t<ScalingKeyList num=\"%i\">\n",nd->mNumScalingKeys);
-							for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) {
-								aiVectorKey* vc = nd->mScalingKeys+a;
-								ioprintf(io,"\t\t\t\t\t<ScalingKey time=\"%e\">\n"
-									"\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
-									vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
-							}
-							ioprintf(io,"\t\t\t\t</ScalingKeyList>\n");
-						}
-
-						// write rotation keys
-						if (nd->mNumRotationKeys) {
-							ioprintf(io,"\t\t\t\t<RotationKeyList num=\"%i\">\n",nd->mNumRotationKeys);
-							for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) {
-								aiQuatKey* vc = nd->mRotationKeys+a;
-								ioprintf(io,"\t\t\t\t\t<RotationKey time=\"%e\">\n"
-									"\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
-									vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w);
-							}
-							ioprintf(io,"\t\t\t\t</RotationKeyList>\n");
-						}
-					}
-					ioprintf(io,"\t\t\t</NodeAnim>\n");
-				}
-				ioprintf(io,"\t\t</NodeAnimList>\n");
-			}
-			ioprintf(io,"\t</Animation>\n");
-		}
-		ioprintf(io,"</AnimationList>\n");
-	}
-
-	// write meshes
-	if (scene->mNumMeshes) {
-		ioprintf(io,"<MeshList num=\"%i\">\n",scene->mNumMeshes);
-		for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
-			aiMesh* mesh = scene->mMeshes[i];
-			// const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1;
-
-			// mesh header
-			ioprintf(io,"\t<Mesh types=\"%s %s %s %s\" material_index=\"%i\">\n",
-				(mesh->mPrimitiveTypes & aiPrimitiveType_POINT    ? "points"    : ""),
-				(mesh->mPrimitiveTypes & aiPrimitiveType_LINE     ? "lines"     : ""),
-				(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
-				(mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON  ? "polygons"  : ""),
-				mesh->mMaterialIndex);
-
-			// bones
-			if (mesh->mNumBones) {
-				ioprintf(io,"\t\t<BoneList num=\"%i\">\n",mesh->mNumBones);
-
-				for (unsigned int n = 0; n < mesh->mNumBones;++n) {
-					aiBone* bone = mesh->mBones[n];
-
-					ConvertName(name,bone->mName);
-					// bone header
-					ioprintf(io,"\t\t\t<Bone name=\"%s\">\n"
-						"\t\t\t\t<Matrix4> \n"
-						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
-						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
-						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
-						"\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
-						"\t\t\t\t</Matrix4> \n",
-						name.data,
-						bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4,
-						bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4,
-						bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4,
-						bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4);
-
-					if (!shortened && bone->mNumWeights) {
-						ioprintf(io,"\t\t\t\t<WeightList num=\"%i\">\n",bone->mNumWeights);
-
-						// bone weights
-						for (unsigned int a = 0; a < bone->mNumWeights;++a) {
-							aiVertexWeight* wght = bone->mWeights+a;
-
-							ioprintf(io,"\t\t\t\t\t<Weight index=\"%i\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
-								wght->mVertexId,wght->mWeight);
-						}
-						ioprintf(io,"\t\t\t\t</WeightList>\n");
-					}
-					ioprintf(io,"\t\t\t</Bone>\n");
-				}
-				ioprintf(io,"\t\t</BoneList>\n");
-			}
-
-			// faces
-			if (!shortened && mesh->mNumFaces) {
-				ioprintf(io,"\t\t<FaceList num=\"%i\">\n",mesh->mNumFaces);
-				for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
-					aiFace& f = mesh->mFaces[n];
-					ioprintf(io,"\t\t\t<Face num=\"%i\">\n"
-						"\t\t\t\t",f.mNumIndices);
-
-					for (unsigned int j = 0; j < f.mNumIndices;++j)
-						ioprintf(io,"%i ",f.mIndices[j]);
-
-					ioprintf(io,"\n\t\t\t</Face>\n");
-				}
-				ioprintf(io,"\t\t</FaceList>\n");
-			}
-
-			// vertex positions
-			if (mesh->HasPositions()) {
-				ioprintf(io,"\t\t<Positions num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
-				if (!shortened) {
-					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
-						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
-							mesh->mVertices[n].x,
-							mesh->mVertices[n].y,
-							mesh->mVertices[n].z);
-					}
-				}
-				ioprintf(io,"\t\t</Positions>\n");
-			}
-
-			// vertex normals
-			if (mesh->HasNormals()) {
-				ioprintf(io,"\t\t<Normals num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
-				if (!shortened) {
-					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
-						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
-							mesh->mNormals[n].x,
-							mesh->mNormals[n].y,
-							mesh->mNormals[n].z);
-					}
-				}
-				else {
-				}
-				ioprintf(io,"\t\t</Normals>\n");
-			}
-
-			// vertex tangents and bitangents
-			if (mesh->HasTangentsAndBitangents()) {
-				ioprintf(io,"\t\t<Tangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
-				if (!shortened) {
-					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
-						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
-							mesh->mTangents[n].x,
-							mesh->mTangents[n].y,
-							mesh->mTangents[n].z);
-					}
-				}
-				ioprintf(io,"\t\t</Tangents>\n");
-
-				ioprintf(io,"\t\t<Bitangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
-				if (!shortened) {
-					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
-						ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
-							mesh->mBitangents[n].x,
-							mesh->mBitangents[n].y,
-							mesh->mBitangents[n].z);
-					}
-				}
-				ioprintf(io,"\t\t</Bitangents>\n");
-			}
-
-			// texture coordinates
-			for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
-				if (!mesh->mTextureCoords[a])
-					break;
-
-				ioprintf(io,"\t\t<TextureCoords num=\"%i\" set=\"%i\" num_components=\"%i\"> \n",mesh->mNumVertices,
-					a,mesh->mNumUVComponents[a]);
-
-				if (!shortened) {
-					if (mesh->mNumUVComponents[a] == 3) {
-						for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
-							ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
-								mesh->mTextureCoords[a][n].x,
-								mesh->mTextureCoords[a][n].y,
-								mesh->mTextureCoords[a][n].z);
-						}
-					}
-					else {
-						for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
-							ioprintf(io,"\t\t%0 8f %0 8f\n",
-								mesh->mTextureCoords[a][n].x,
-								mesh->mTextureCoords[a][n].y);
-						}
-					}
-				}
-				ioprintf(io,"\t\t</TextureCoords>\n");
-			}
-
-			// vertex colors
-			for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
-				if (!mesh->mColors[a])
-					break;
-				ioprintf(io,"\t\t<Colors num=\"%i\" set=\"%i\" num_components=\"4\"> \n",mesh->mNumVertices,a);
-				if (!shortened) {
-					for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
-						ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n",
-							mesh->mColors[a][n].r,
-							mesh->mColors[a][n].g,
-							mesh->mColors[a][n].b,
-							mesh->mColors[a][n].a);
-					}
-				}
-				ioprintf(io,"\t\t</Colors>\n");
-			}
-			ioprintf(io,"\t</Mesh>\n");
-		}
-		ioprintf(io,"</MeshList>\n");
-	}
-	ioprintf(io,"</Scene>\n</ASSIMP>");
+    // write textures
+    if (scene->mNumTextures) {
+        ioprintf(io,"<TextureList num=\"%i\">\n",scene->mNumTextures);
+        for (unsigned int i = 0; i < scene->mNumTextures;++i) {
+            aiTexture* tex  = scene->mTextures[i];
+            bool compressed = (tex->mHeight == 0);
+
+            // mesh header
+            ioprintf(io,"\t<Texture width=\"%i\" height=\"%i\" compressed=\"%s\"> \n",
+                (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight),
+                (compressed ? "true" : "false"));
+
+            if (compressed) {
+                ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth);
+
+                if (!shortened) {
+                    for (unsigned int n = 0; n < tex->mWidth;++n) {
+                        ioprintf(io,"\t\t\t%2x",reinterpret_cast<uint8_t*>(tex->pcData)[n]);
+                        if (n && !(n % 50)) {
+                            ioprintf(io,"\n");
+                        }
+                    }
+                }
+            }
+            else if (!shortened){
+                ioprintf(io,"\t\t<Data length=\"%i\"> \n",tex->mWidth*tex->mHeight*4);
+
+                // const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1;
+                for (unsigned int y = 0; y < tex->mHeight;++y) {
+                    for (unsigned int x = 0; x < tex->mWidth;++x) {
+                        aiTexel* tx = tex->pcData + y*tex->mWidth+x;
+                        unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a;
+                        ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a);
+
+                        // group by four for readibility
+                        if (0 == (x+y*tex->mWidth) % 4)
+                            ioprintf(io,"\n");
+                    }
+                }
+            }
+            ioprintf(io,"\t\t</Data>\n\t</Texture>\n");
+        }
+        ioprintf(io,"</TextureList>\n");
+    }
+
+    // write materials
+    if (scene->mNumMaterials) {
+        ioprintf(io,"<MaterialList num=\"%i\">\n",scene->mNumMaterials);
+        for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
+            const aiMaterial* mat = scene->mMaterials[i];
+
+            ioprintf(io,"\t<Material>\n");
+            ioprintf(io,"\t\t<MatPropertyList  num=\"%i\">\n",mat->mNumProperties);
+            for (unsigned int n = 0; n < mat->mNumProperties;++n) {
+
+                const aiMaterialProperty* prop = mat->mProperties[n];
+                const char* sz = "";
+                if (prop->mType == aiPTI_Float) {
+                    sz = "float";
+                }
+                else if (prop->mType == aiPTI_Integer) {
+                    sz = "integer";
+                }
+                else if (prop->mType == aiPTI_String) {
+                    sz = "string";
+                }
+                else if (prop->mType == aiPTI_Buffer) {
+                    sz = "binary_buffer";
+                }
+
+                ioprintf(io,"\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%i\"",
+                    prop->mKey.data, sz,
+                    ::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex);
+
+                if (prop->mType == aiPTI_Float) {
+                    ioprintf(io," size=\"%i\">\n\t\t\t\t",
+                        static_cast<int>(prop->mDataLength/sizeof(float)));
+
+                    for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) {
+                        ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float))));
+                    }
+                }
+                else if (prop->mType == aiPTI_Integer) {
+                    ioprintf(io," size=\"%i\">\n\t\t\t\t",
+                        static_cast<int>(prop->mDataLength/sizeof(int)));
+
+                    for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) {
+                        ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int))));
+                    }
+                }
+                else if (prop->mType == aiPTI_Buffer) {
+                    ioprintf(io," size=\"%i\">\n\t\t\t\t",
+                        static_cast<int>(prop->mDataLength));
+
+                    for (unsigned int p = 0; p < prop->mDataLength;++p) {
+                        ioprintf(io,"%2x ",prop->mData[p]);
+                        if (p && 0 == p%30) {
+                            ioprintf(io,"\n\t\t\t\t");
+                        }
+                    }
+                }
+                else if (prop->mType == aiPTI_String) {
+                    ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */);
+                }
+                ioprintf(io,"\n\t\t\t</MatProperty>\n");
+            }
+            ioprintf(io,"\t\t</MatPropertyList>\n");
+            ioprintf(io,"\t</Material>\n");
+        }
+        ioprintf(io,"</MaterialList>\n");
+    }
+
+    // write animations
+    if (scene->mNumAnimations) {
+        ioprintf(io,"<AnimationList num=\"%i\">\n",scene->mNumAnimations);
+        for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+            aiAnimation* anim = scene->mAnimations[i];
+
+            // anim header
+            ConvertName(name,anim->mName);
+            ioprintf(io,"\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
+                name.data, anim->mDuration, anim->mTicksPerSecond);
+
+            // write bone animation channels
+            if (anim->mNumChannels) {
+                ioprintf(io,"\t\t<NodeAnimList num=\"%i\">\n",anim->mNumChannels);
+                for (unsigned int n = 0; n < anim->mNumChannels;++n) {
+                    aiNodeAnim* nd = anim->mChannels[n];
+
+                    // node anim header
+                    ConvertName(name,nd->mNodeName);
+                    ioprintf(io,"\t\t\t<NodeAnim node=\"%s\">\n",name.data);
+
+                    if (!shortened) {
+                        // write position keys
+                        if (nd->mNumPositionKeys) {
+                            ioprintf(io,"\t\t\t\t<PositionKeyList num=\"%i\">\n",nd->mNumPositionKeys);
+                            for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) {
+                                aiVectorKey* vc = nd->mPositionKeys+a;
+                                ioprintf(io,"\t\t\t\t\t<PositionKey time=\"%e\">\n"
+                                    "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
+                                    vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
+                            }
+                            ioprintf(io,"\t\t\t\t</PositionKeyList>\n");
+                        }
+
+                        // write scaling keys
+                        if (nd->mNumScalingKeys) {
+                            ioprintf(io,"\t\t\t\t<ScalingKeyList num=\"%i\">\n",nd->mNumScalingKeys);
+                            for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) {
+                                aiVectorKey* vc = nd->mScalingKeys+a;
+                                ioprintf(io,"\t\t\t\t\t<ScalingKey time=\"%e\">\n"
+                                    "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
+                                    vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z);
+                            }
+                            ioprintf(io,"\t\t\t\t</ScalingKeyList>\n");
+                        }
+
+                        // write rotation keys
+                        if (nd->mNumRotationKeys) {
+                            ioprintf(io,"\t\t\t\t<RotationKeyList num=\"%i\">\n",nd->mNumRotationKeys);
+                            for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) {
+                                aiQuatKey* vc = nd->mRotationKeys+a;
+                                ioprintf(io,"\t\t\t\t\t<RotationKey time=\"%e\">\n"
+                                    "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
+                                    vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w);
+                            }
+                            ioprintf(io,"\t\t\t\t</RotationKeyList>\n");
+                        }
+                    }
+                    ioprintf(io,"\t\t\t</NodeAnim>\n");
+                }
+                ioprintf(io,"\t\t</NodeAnimList>\n");
+            }
+            ioprintf(io,"\t</Animation>\n");
+        }
+        ioprintf(io,"</AnimationList>\n");
+    }
+
+    // write meshes
+    if (scene->mNumMeshes) {
+        ioprintf(io,"<MeshList num=\"%i\">\n",scene->mNumMeshes);
+        for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
+            aiMesh* mesh = scene->mMeshes[i];
+            // const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1;
+
+            // mesh header
+            ioprintf(io,"\t<Mesh types=\"%s %s %s %s\" material_index=\"%i\">\n",
+                (mesh->mPrimitiveTypes & aiPrimitiveType_POINT    ? "points"    : ""),
+                (mesh->mPrimitiveTypes & aiPrimitiveType_LINE     ? "lines"     : ""),
+                (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
+                (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON  ? "polygons"  : ""),
+                mesh->mMaterialIndex);
+
+            // bones
+            if (mesh->mNumBones) {
+                ioprintf(io,"\t\t<BoneList num=\"%i\">\n",mesh->mNumBones);
+
+                for (unsigned int n = 0; n < mesh->mNumBones;++n) {
+                    aiBone* bone = mesh->mBones[n];
+
+                    ConvertName(name,bone->mName);
+                    // bone header
+                    ioprintf(io,"\t\t\t<Bone name=\"%s\">\n"
+                        "\t\t\t\t<Matrix4> \n"
+                        "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                        "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                        "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                        "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                        "\t\t\t\t</Matrix4> \n",
+                        name.data,
+                        bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4,
+                        bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4,
+                        bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4,
+                        bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4);
+
+                    if (!shortened && bone->mNumWeights) {
+                        ioprintf(io,"\t\t\t\t<WeightList num=\"%i\">\n",bone->mNumWeights);
+
+                        // bone weights
+                        for (unsigned int a = 0; a < bone->mNumWeights;++a) {
+                            aiVertexWeight* wght = bone->mWeights+a;
+
+                            ioprintf(io,"\t\t\t\t\t<Weight index=\"%i\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
+                                wght->mVertexId,wght->mWeight);
+                        }
+                        ioprintf(io,"\t\t\t\t</WeightList>\n");
+                    }
+                    ioprintf(io,"\t\t\t</Bone>\n");
+                }
+                ioprintf(io,"\t\t</BoneList>\n");
+            }
+
+            // faces
+            if (!shortened && mesh->mNumFaces) {
+                ioprintf(io,"\t\t<FaceList num=\"%i\">\n",mesh->mNumFaces);
+                for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
+                    aiFace& f = mesh->mFaces[n];
+                    ioprintf(io,"\t\t\t<Face num=\"%i\">\n"
+                        "\t\t\t\t",f.mNumIndices);
+
+                    for (unsigned int j = 0; j < f.mNumIndices;++j)
+                        ioprintf(io,"%i ",f.mIndices[j]);
+
+                    ioprintf(io,"\n\t\t\t</Face>\n");
+                }
+                ioprintf(io,"\t\t</FaceList>\n");
+            }
+
+            // vertex positions
+            if (mesh->HasPositions()) {
+                ioprintf(io,"\t\t<Positions num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+                            mesh->mVertices[n].x,
+                            mesh->mVertices[n].y,
+                            mesh->mVertices[n].z);
+                    }
+                }
+                ioprintf(io,"\t\t</Positions>\n");
+            }
+
+            // vertex normals
+            if (mesh->HasNormals()) {
+                ioprintf(io,"\t\t<Normals num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+                            mesh->mNormals[n].x,
+                            mesh->mNormals[n].y,
+                            mesh->mNormals[n].z);
+                    }
+                }
+                else {
+                }
+                ioprintf(io,"\t\t</Normals>\n");
+            }
+
+            // vertex tangents and bitangents
+            if (mesh->HasTangentsAndBitangents()) {
+                ioprintf(io,"\t\t<Tangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+                            mesh->mTangents[n].x,
+                            mesh->mTangents[n].y,
+                            mesh->mTangents[n].z);
+                    }
+                }
+                ioprintf(io,"\t\t</Tangents>\n");
+
+                ioprintf(io,"\t\t<Bitangents num=\"%i\" set=\"0\" num_components=\"3\"> \n",mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+                            mesh->mBitangents[n].x,
+                            mesh->mBitangents[n].y,
+                            mesh->mBitangents[n].z);
+                    }
+                }
+                ioprintf(io,"\t\t</Bitangents>\n");
+            }
+
+            // texture coordinates
+            for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+                if (!mesh->mTextureCoords[a])
+                    break;
+
+                ioprintf(io,"\t\t<TextureCoords num=\"%i\" set=\"%i\" num_components=\"%i\"> \n",mesh->mNumVertices,
+                    a,mesh->mNumUVComponents[a]);
+
+                if (!shortened) {
+                    if (mesh->mNumUVComponents[a] == 3) {
+                        for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                            ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n",
+                                mesh->mTextureCoords[a][n].x,
+                                mesh->mTextureCoords[a][n].y,
+                                mesh->mTextureCoords[a][n].z);
+                        }
+                    }
+                    else {
+                        for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                            ioprintf(io,"\t\t%0 8f %0 8f\n",
+                                mesh->mTextureCoords[a][n].x,
+                                mesh->mTextureCoords[a][n].y);
+                        }
+                    }
+                }
+                ioprintf(io,"\t\t</TextureCoords>\n");
+            }
+
+            // vertex colors
+            for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
+                if (!mesh->mColors[a])
+                    break;
+                ioprintf(io,"\t\t<Colors num=\"%i\" set=\"%i\" num_components=\"4\"> \n",mesh->mNumVertices,a);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n",
+                            mesh->mColors[a][n].r,
+                            mesh->mColors[a][n].g,
+                            mesh->mColors[a][n].b,
+                            mesh->mColors[a][n].a);
+                    }
+                }
+                ioprintf(io,"\t\t</Colors>\n");
+            }
+            ioprintf(io,"\t</Mesh>\n");
+        }
+        ioprintf(io,"</MeshList>\n");
+    }
+    ioprintf(io,"</Scene>\n</ASSIMP>");
 }
 
 } // end of namespace AssxmlExport
 
 void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
-	IOStream * out = pIOSystem->Open( pFile, "wt" );
-	if (!out) return;
+    IOStream * out = pIOSystem->Open( pFile, "wt" );
+    if (!out) return;
 
-	bool shortened = false;
-	AssxmlExport::WriteDump( pScene, out, shortened );
+    bool shortened = false;
+    AssxmlExport::WriteDump( pScene, out, shortened );
 
-	pIOSystem->Close( out );
+    pIOSystem->Close( out );
 }
 
 } // end of namespace Assimp

+ 467 - 467
code/B3DImporter.cpp

@@ -61,21 +61,21 @@ using namespace Assimp;
 using namespace std;
 
 static const aiImporterDesc desc = {
-	"BlitzBasic 3D Importer",
-	"",
-	"",
-	"http://www.blitzbasic.com/",
-	aiImporterFlags_SupportBinaryFlavour,
-	0,
-	0,
-	0,
-	0,
-	"b3d"
+    "BlitzBasic 3D Importer",
+    "",
+    "",
+    "http://www.blitzbasic.com/",
+    aiImporterFlags_SupportBinaryFlavour,
+    0,
+    0,
+    0,
+    0,
+    "b3d"
 };
 
 // (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings
 #ifdef _MSC_VER
-#	pragma warning (disable: 4018)
+#   pragma warning (disable: 4018)
 #endif
 
 //#define DEBUG_B3D
@@ -83,157 +83,157 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
 
-	size_t pos=pFile.find_last_of( '.' );
-	if( pos==string::npos ) return false;
+    size_t pos=pFile.find_last_of( '.' );
+    if( pos==string::npos ) return false;
 
-	string ext=pFile.substr( pos+1 );
-	if( ext.size()!=3 ) return false;
+    string ext=pFile.substr( pos+1 );
+    if( ext.size()!=3 ) return false;
 
-	return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
+    return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
 }
 
 // ------------------------------------------------------------------------------------------------
 // Loader meta information
 const aiImporterDesc* B3DImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 #ifdef DEBUG_B3D
-	extern "C"{ void _stdcall AllocConsole(); }
+    extern "C"{ void _stdcall AllocConsole(); }
 #endif
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
 
 #ifdef DEBUG_B3D
-	AllocConsole();
-	freopen( "conin$","r",stdin );
-	freopen( "conout$","w",stdout );
-	freopen( "conout$","w",stderr );
-	cout<<"Hello world from the B3DImporter!"<<endl;
+    AllocConsole();
+    freopen( "conin$","r",stdin );
+    freopen( "conout$","w",stdout );
+    freopen( "conout$","w",stderr );
+    cout<<"Hello world from the B3DImporter!"<<endl;
 #endif
 
-	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
 
-	// Check whether we can read from the file
-	if( file.get() == NULL)
-		throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
+    // Check whether we can read from the file
+    if( file.get() == NULL)
+        throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
 
-	// check whether the .b3d file is large enough to contain
-	// at least one chunk.
-	size_t fileSize = file->FileSize();
-	if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small.");
+    // check whether the .b3d file is large enough to contain
+    // at least one chunk.
+    size_t fileSize = file->FileSize();
+    if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small.");
 
-	_pos=0;
-	_buf.resize( fileSize );
-	file->Read( &_buf[0],1,fileSize );
-	_stack.clear();
+    _pos=0;
+    _buf.resize( fileSize );
+    file->Read( &_buf[0],1,fileSize );
+    _stack.clear();
 
-	ReadBB3D( pScene );
+    ReadBB3D( pScene );
 }
 
 // ------------------------------------------------------------------------------------------------
 AI_WONT_RETURN void B3DImporter::Oops(){
-	throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" );
+    throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" );
 }
 
 // ------------------------------------------------------------------------------------------------
 AI_WONT_RETURN void B3DImporter::Fail( string str ){
 #ifdef DEBUG_B3D
-	cout<<"Error in B3D file data: "<<str<<endl;
+    cout<<"Error in B3D file data: "<<str<<endl;
 #endif
-	throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
+    throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
 }
 
 // ------------------------------------------------------------------------------------------------
 int B3DImporter::ReadByte(){
-	if( _pos<_buf.size() ) return _buf[_pos++];
-	Fail( "EOF" );
-	return 0;
+    if( _pos<_buf.size() ) return _buf[_pos++];
+    Fail( "EOF" );
+    return 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 int B3DImporter::ReadInt(){
-	if( _pos+4<=_buf.size() ){
-		int n=*(int*)&_buf[_pos];
-		_pos+=4;
-		return n;
-	}
-	Fail( "EOF" );
-	return 0;
+    if( _pos+4<=_buf.size() ){
+        int n=*(int*)&_buf[_pos];
+        _pos+=4;
+        return n;
+    }
+    Fail( "EOF" );
+    return 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 float B3DImporter::ReadFloat(){
-	if( _pos+4<=_buf.size() ){
-		float n=*(float*)&_buf[_pos];
-		_pos+=4;
-		return n;
-	}
-	Fail( "EOF" );
-	return 0.0f;
+    if( _pos+4<=_buf.size() ){
+        float n=*(float*)&_buf[_pos];
+        _pos+=4;
+        return n;
+    }
+    Fail( "EOF" );
+    return 0.0f;
 }
 
 // ------------------------------------------------------------------------------------------------
 aiVector2D B3DImporter::ReadVec2(){
-	float x=ReadFloat();
-	float y=ReadFloat();
-	return aiVector2D( x,y );
+    float x=ReadFloat();
+    float y=ReadFloat();
+    return aiVector2D( x,y );
 }
 
 // ------------------------------------------------------------------------------------------------
 aiVector3D B3DImporter::ReadVec3(){
-	float x=ReadFloat();
-	float y=ReadFloat();
-	float z=ReadFloat();
-	return aiVector3D( x,y,z );
+    float x=ReadFloat();
+    float y=ReadFloat();
+    float z=ReadFloat();
+    return aiVector3D( x,y,z );
 }
 
 // ------------------------------------------------------------------------------------------------
 aiQuaternion B3DImporter::ReadQuat(){
-	// (aramis_acg) Fix to adapt the loader to changed quat orientation
-	float w=-ReadFloat();
-	float x=ReadFloat();
-	float y=ReadFloat();
-	float z=ReadFloat();
-	return aiQuaternion( w,x,y,z );
+    // (aramis_acg) Fix to adapt the loader to changed quat orientation
+    float w=-ReadFloat();
+    float x=ReadFloat();
+    float y=ReadFloat();
+    float z=ReadFloat();
+    return aiQuaternion( w,x,y,z );
 }
 
 // ------------------------------------------------------------------------------------------------
 string B3DImporter::ReadString(){
-	string str;
-	while( _pos<_buf.size() ){
-		char c=(char)ReadByte();
-		if( !c ) return str;
-		str+=c;
-	}
-	Fail( "EOF" );
-	return string();
+    string str;
+    while( _pos<_buf.size() ){
+        char c=(char)ReadByte();
+        if( !c ) return str;
+        str+=c;
+    }
+    Fail( "EOF" );
+    return string();
 }
 
 // ------------------------------------------------------------------------------------------------
 string B3DImporter::ReadChunk(){
-	string tag;
-	for( int i=0;i<4;++i ){
-		tag+=char( ReadByte() );
-	}
+    string tag;
+    for( int i=0;i<4;++i ){
+        tag+=char( ReadByte() );
+    }
 #ifdef DEBUG_B3D
-//	cout<<"ReadChunk:"<<tag<<endl;
+//  cout<<"ReadChunk:"<<tag<<endl;
 #endif
-	unsigned sz=(unsigned)ReadInt();
-	_stack.push_back( _pos+sz );
-	return tag;
+    unsigned sz=(unsigned)ReadInt();
+    _stack.push_back( _pos+sz );
+    return tag;
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ExitChunk(){
-	_pos=_stack.back();
-	_stack.pop_back();
+    _pos=_stack.back();
+    _stack.pop_back();
 }
 
 // ------------------------------------------------------------------------------------------------
 unsigned B3DImporter::ChunkSize(){
-	return _stack.back()-_pos;
+    return _stack.back()-_pos;
 }
 // ------------------------------------------------------------------------------------------------
 
@@ -242,454 +242,454 @@ T *B3DImporter::to_array( const vector<T> &v ){
     if( v.empty() ) {
         return 0;
     }
-	T *p=new T[ v.size() ];
-	for( size_t i=0;i<v.size();++i ){
-		p[i]=v[i];
-	}
-	return p;
+    T *p=new T[ v.size() ];
+    for( size_t i=0;i<v.size();++i ){
+        p[i]=v[i];
+    }
+    return p;
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadTEXS(){
-	while( ChunkSize() ){
-		string name=ReadString();
-		/*int flags=*/ReadInt();
-		/*int blend=*/ReadInt();
-		/*aiVector2D pos=*/ReadVec2();
-		/*aiVector2D scale=*/ReadVec2();
-		/*float rot=*/ReadFloat();
-
-		_textures.push_back( name );
-	}
+    while( ChunkSize() ){
+        string name=ReadString();
+        /*int flags=*/ReadInt();
+        /*int blend=*/ReadInt();
+        /*aiVector2D pos=*/ReadVec2();
+        /*aiVector2D scale=*/ReadVec2();
+        /*float rot=*/ReadFloat();
+
+        _textures.push_back( name );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadBRUS(){
-	int n_texs=ReadInt();
-	if( n_texs<0 || n_texs>8 ){
-		Fail( "Bad texture count" );
-	}
-	while( ChunkSize() ){
-		string name=ReadString();
-		aiVector3D color=ReadVec3();
-		float alpha=ReadFloat();
-		float shiny=ReadFloat();
-		/*int blend=**/ReadInt();
-		int fx=ReadInt();
-
-		aiMaterial *mat=new aiMaterial;
-		_materials.push_back( mat );
-
-		// Name
-		aiString ainame( name );
-		mat->AddProperty( &ainame,AI_MATKEY_NAME );
-
-		// Diffuse color
-		mat->AddProperty( &color,1,AI_MATKEY_COLOR_DIFFUSE );
-
-		// Opacity
-		mat->AddProperty( &alpha,1,AI_MATKEY_OPACITY );
-
-		// Specular color
-		aiColor3D speccolor( shiny,shiny,shiny );
-		mat->AddProperty( &speccolor,1,AI_MATKEY_COLOR_SPECULAR );
-
-		// Specular power
-		float specpow=shiny*128;
-		mat->AddProperty( &specpow,1,AI_MATKEY_SHININESS );
-
-		// Double sided
-		if( fx & 0x10 ){
-			int i=1;
-			mat->AddProperty( &i,1,AI_MATKEY_TWOSIDED );
-		}
-
-		//Textures
-		for( int i=0;i<n_texs;++i ){
-			int texid=ReadInt();
-			if( texid<-1 || (texid>=0 && texid>=static_cast<int>(_textures.size())) ){
-				Fail( "Bad texture id" );
-			}
-			if( i==0 && texid>=0 ){
-				aiString texname( _textures[texid] );
-				mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) );
-			}
-		}
-	}
+    int n_texs=ReadInt();
+    if( n_texs<0 || n_texs>8 ){
+        Fail( "Bad texture count" );
+    }
+    while( ChunkSize() ){
+        string name=ReadString();
+        aiVector3D color=ReadVec3();
+        float alpha=ReadFloat();
+        float shiny=ReadFloat();
+        /*int blend=**/ReadInt();
+        int fx=ReadInt();
+
+        aiMaterial *mat=new aiMaterial;
+        _materials.push_back( mat );
+
+        // Name
+        aiString ainame( name );
+        mat->AddProperty( &ainame,AI_MATKEY_NAME );
+
+        // Diffuse color
+        mat->AddProperty( &color,1,AI_MATKEY_COLOR_DIFFUSE );
+
+        // Opacity
+        mat->AddProperty( &alpha,1,AI_MATKEY_OPACITY );
+
+        // Specular color
+        aiColor3D speccolor( shiny,shiny,shiny );
+        mat->AddProperty( &speccolor,1,AI_MATKEY_COLOR_SPECULAR );
+
+        // Specular power
+        float specpow=shiny*128;
+        mat->AddProperty( &specpow,1,AI_MATKEY_SHININESS );
+
+        // Double sided
+        if( fx & 0x10 ){
+            int i=1;
+            mat->AddProperty( &i,1,AI_MATKEY_TWOSIDED );
+        }
+
+        //Textures
+        for( int i=0;i<n_texs;++i ){
+            int texid=ReadInt();
+            if( texid<-1 || (texid>=0 && texid>=static_cast<int>(_textures.size())) ){
+                Fail( "Bad texture id" );
+            }
+            if( i==0 && texid>=0 ){
+                aiString texname( _textures[texid] );
+                mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) );
+            }
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadVRTS(){
-	_vflags=ReadInt();
-	_tcsets=ReadInt();
-	_tcsize=ReadInt();
-	if( _tcsets<0 || _tcsets>4 || _tcsize<0 || _tcsize>4 ){
-		Fail( "Bad texcoord data" );
-	}
+    _vflags=ReadInt();
+    _tcsets=ReadInt();
+    _tcsize=ReadInt();
+    if( _tcsets<0 || _tcsets>4 || _tcsize<0 || _tcsize>4 ){
+        Fail( "Bad texcoord data" );
+    }
 
-	int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4);
-	int n_verts=ChunkSize()/sz;
+    int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4);
+    int n_verts=ChunkSize()/sz;
 
-	int v0=_vertices.size();
-	_vertices.resize( v0+n_verts );
+    int v0=_vertices.size();
+    _vertices.resize( v0+n_verts );
 
-	for( int i=0;i<n_verts;++i ){
-		Vertex &v=_vertices[v0+i];
+    for( int i=0;i<n_verts;++i ){
+        Vertex &v=_vertices[v0+i];
 
-		memset( v.bones,0,sizeof(v.bones) );
-		memset( v.weights,0,sizeof(v.weights) );
+        memset( v.bones,0,sizeof(v.bones) );
+        memset( v.weights,0,sizeof(v.weights) );
 
-		v.vertex=ReadVec3();
+        v.vertex=ReadVec3();
 
-		if( _vflags & 1 ) v.normal=ReadVec3();
+        if( _vflags & 1 ) v.normal=ReadVec3();
 
-		if( _vflags & 2 ) ReadQuat();	//skip v 4bytes...
+        if( _vflags & 2 ) ReadQuat();   //skip v 4bytes...
 
-		for( int i=0;i<_tcsets;++i ){
-			float t[4]={0,0,0,0};
-			for( int j=0;j<_tcsize;++j ){
-				t[j]=ReadFloat();
-			}
-			t[1]=1-t[1];
-			if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] );
-		}
-	}
+        for( int i=0;i<_tcsets;++i ){
+            float t[4]={0,0,0,0};
+            for( int j=0;j<_tcsize;++j ){
+                t[j]=ReadFloat();
+            }
+            t[1]=1-t[1];
+            if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] );
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadTRIS( int v0 ){
-	int matid=ReadInt();
-	if( matid==-1 ){
-		matid=0;
-	}else if( matid<0 || matid>=(int)_materials.size() ){
+    int matid=ReadInt();
+    if( matid==-1 ){
+        matid=0;
+    }else if( matid<0 || matid>=(int)_materials.size() ){
 #ifdef DEBUG_B3D
-		cout<<"material id="<<matid<<endl;
+        cout<<"material id="<<matid<<endl;
 #endif
-		Fail( "Bad material id" );
-	}
+        Fail( "Bad material id" );
+    }
 
-	aiMesh *mesh=new aiMesh;
-	_meshes.push_back( mesh );
+    aiMesh *mesh=new aiMesh;
+    _meshes.push_back( mesh );
 
-	mesh->mMaterialIndex=matid;
-	mesh->mNumFaces=0;
-	mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE;
+    mesh->mMaterialIndex=matid;
+    mesh->mNumFaces=0;
+    mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE;
 
-	int n_tris=ChunkSize()/12;
-	aiFace *face=mesh->mFaces=new aiFace[n_tris];
+    int n_tris=ChunkSize()/12;
+    aiFace *face=mesh->mFaces=new aiFace[n_tris];
 
-	for( int i=0;i<n_tris;++i ){
-		int i0=ReadInt()+v0;
-		int i1=ReadInt()+v0;
-		int i2=ReadInt()+v0;
-		if( i0<0 || i0>=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){
+    for( int i=0;i<n_tris;++i ){
+        int i0=ReadInt()+v0;
+        int i1=ReadInt()+v0;
+        int i2=ReadInt()+v0;
+        if( i0<0 || i0>=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){
 #ifdef DEBUG_B3D
-			cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl;
+            cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl;
 #endif
-			Fail( "Bad triangle index" );
-			continue;
-		}
-		face->mNumIndices=3;
-		face->mIndices=new unsigned[3];
-		face->mIndices[0]=i0;
-		face->mIndices[1]=i1;
-		face->mIndices[2]=i2;
-		++mesh->mNumFaces;
-		++face;
-	}
+            Fail( "Bad triangle index" );
+            continue;
+        }
+        face->mNumIndices=3;
+        face->mIndices=new unsigned[3];
+        face->mIndices[0]=i0;
+        face->mIndices[1]=i1;
+        face->mIndices[2]=i2;
+        ++mesh->mNumFaces;
+        ++face;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadMESH(){
-	/*int matid=*/ReadInt();
-
-	int v0=_vertices.size();
-
-	while( ChunkSize() ){
-		string t=ReadChunk();
-		if( t=="VRTS" ){
-			ReadVRTS();
-		}else if( t=="TRIS" ){
-			ReadTRIS( v0 );
-		}
-		ExitChunk();
-	}
+    /*int matid=*/ReadInt();
+
+    int v0=_vertices.size();
+
+    while( ChunkSize() ){
+        string t=ReadChunk();
+        if( t=="VRTS" ){
+            ReadVRTS();
+        }else if( t=="TRIS" ){
+            ReadTRIS( v0 );
+        }
+        ExitChunk();
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadBONE( int id ){
-	while( ChunkSize() ){
-		int vertex=ReadInt();
-		float weight=ReadFloat();
-		if( vertex<0 || vertex>=(int)_vertices.size() ){
-			Fail( "Bad vertex index" );
-		}
-
-		Vertex &v=_vertices[vertex];
-		int i;
-		for( i=0;i<4;++i ){
-			if( !v.weights[i] ){
-				v.bones[i]=id;
-				v.weights[i]=weight;
-				break;
-			}
-		}
+    while( ChunkSize() ){
+        int vertex=ReadInt();
+        float weight=ReadFloat();
+        if( vertex<0 || vertex>=(int)_vertices.size() ){
+            Fail( "Bad vertex index" );
+        }
+
+        Vertex &v=_vertices[vertex];
+        int i;
+        for( i=0;i<4;++i ){
+            if( !v.weights[i] ){
+                v.bones[i]=id;
+                v.weights[i]=weight;
+                break;
+            }
+        }
 #ifdef DEBUG_B3D
-		if( i==4 ){
-			cout<<"Too many bone weights"<<endl;
-		}
+        if( i==4 ){
+            cout<<"Too many bone weights"<<endl;
+        }
 #endif
-	}
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadKEYS( aiNodeAnim *nodeAnim ){
-	vector<aiVectorKey> trans,scale;
-	vector<aiQuatKey> rot;
-	int flags=ReadInt();
-	while( ChunkSize() ){
-		int frame=ReadInt();
-		if( flags & 1 ){
-			trans.push_back( aiVectorKey( frame,ReadVec3() ) );
-		}
-		if( flags & 2 ){
-			scale.push_back( aiVectorKey( frame,ReadVec3() ) );
-		}
-		if( flags & 4 ){
-			rot.push_back( aiQuatKey( frame,ReadQuat() ) );
-		}
-	}
-
-	if( flags & 1 ){
-		nodeAnim->mNumPositionKeys=trans.size();
-		nodeAnim->mPositionKeys=to_array( trans );
-	}
-
-	if( flags & 2 ){
-		nodeAnim->mNumScalingKeys=scale.size();
-		nodeAnim->mScalingKeys=to_array( scale );
-	}
-
-	if( flags & 4 ){
-		nodeAnim->mNumRotationKeys=rot.size();
-		nodeAnim->mRotationKeys=to_array( rot );
-	}
+    vector<aiVectorKey> trans,scale;
+    vector<aiQuatKey> rot;
+    int flags=ReadInt();
+    while( ChunkSize() ){
+        int frame=ReadInt();
+        if( flags & 1 ){
+            trans.push_back( aiVectorKey( frame,ReadVec3() ) );
+        }
+        if( flags & 2 ){
+            scale.push_back( aiVectorKey( frame,ReadVec3() ) );
+        }
+        if( flags & 4 ){
+            rot.push_back( aiQuatKey( frame,ReadQuat() ) );
+        }
+    }
+
+    if( flags & 1 ){
+        nodeAnim->mNumPositionKeys=trans.size();
+        nodeAnim->mPositionKeys=to_array( trans );
+    }
+
+    if( flags & 2 ){
+        nodeAnim->mNumScalingKeys=scale.size();
+        nodeAnim->mScalingKeys=to_array( scale );
+    }
+
+    if( flags & 4 ){
+        nodeAnim->mNumRotationKeys=rot.size();
+        nodeAnim->mRotationKeys=to_array( rot );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadANIM(){
-	/*int flags=*/ReadInt();
-	int frames=ReadInt();
-	float fps=ReadFloat();
+    /*int flags=*/ReadInt();
+    int frames=ReadInt();
+    float fps=ReadFloat();
 
-	aiAnimation *anim=new aiAnimation;
-	_animations.push_back( anim );
+    aiAnimation *anim=new aiAnimation;
+    _animations.push_back( anim );
 
-	anim->mDuration=frames;
-	anim->mTicksPerSecond=fps;
+    anim->mDuration=frames;
+    anim->mTicksPerSecond=fps;
 }
 
 // ------------------------------------------------------------------------------------------------
 aiNode *B3DImporter::ReadNODE( aiNode *parent ){
 
-	string name=ReadString();
-	aiVector3D t=ReadVec3();
-	aiVector3D s=ReadVec3();
-	aiQuaternion r=ReadQuat();
-
-	aiMatrix4x4 trans,scale,rot;
-
-	aiMatrix4x4::Translation( t,trans );
-	aiMatrix4x4::Scaling( s,scale );
-	rot=aiMatrix4x4( r.GetMatrix() );
-
-	aiMatrix4x4 tform=trans * rot * scale;
-
-	int nodeid=_nodes.size();
-
-	aiNode *node=new aiNode( name );
-	_nodes.push_back( node );
-
-	node->mParent=parent;
-	node->mTransformation=tform;
-
-	aiNodeAnim *nodeAnim=0;
-	vector<unsigned> meshes;
-	vector<aiNode*> children;
-
-	while( ChunkSize() ){
-		string t=ReadChunk();
-		if( t=="MESH" ){
-			int n=_meshes.size();
-			ReadMESH();
-			for( int i=n;i<(int)_meshes.size();++i ){
-				meshes.push_back( i );
-			}
-		}else if( t=="BONE" ){
-			ReadBONE( nodeid );
-		}else if( t=="ANIM" ){
-			ReadANIM();
-		}else if( t=="KEYS" ){
-			if( !nodeAnim ){
-				nodeAnim=new aiNodeAnim;
-				_nodeAnims.push_back( nodeAnim );
-				nodeAnim->mNodeName=node->mName;
-			}
-			ReadKEYS( nodeAnim );
-		}else if( t=="NODE" ){
-			aiNode *child=ReadNODE( node );
-			children.push_back( child );
-		}
-		ExitChunk();
-	}
-
-	node->mNumMeshes=meshes.size();
-	node->mMeshes=to_array( meshes );
-
-	node->mNumChildren=children.size();
-	node->mChildren=to_array( children );
-
-	return node;
+    string name=ReadString();
+    aiVector3D t=ReadVec3();
+    aiVector3D s=ReadVec3();
+    aiQuaternion r=ReadQuat();
+
+    aiMatrix4x4 trans,scale,rot;
+
+    aiMatrix4x4::Translation( t,trans );
+    aiMatrix4x4::Scaling( s,scale );
+    rot=aiMatrix4x4( r.GetMatrix() );
+
+    aiMatrix4x4 tform=trans * rot * scale;
+
+    int nodeid=_nodes.size();
+
+    aiNode *node=new aiNode( name );
+    _nodes.push_back( node );
+
+    node->mParent=parent;
+    node->mTransformation=tform;
+
+    aiNodeAnim *nodeAnim=0;
+    vector<unsigned> meshes;
+    vector<aiNode*> children;
+
+    while( ChunkSize() ){
+        string t=ReadChunk();
+        if( t=="MESH" ){
+            int n=_meshes.size();
+            ReadMESH();
+            for( int i=n;i<(int)_meshes.size();++i ){
+                meshes.push_back( i );
+            }
+        }else if( t=="BONE" ){
+            ReadBONE( nodeid );
+        }else if( t=="ANIM" ){
+            ReadANIM();
+        }else if( t=="KEYS" ){
+            if( !nodeAnim ){
+                nodeAnim=new aiNodeAnim;
+                _nodeAnims.push_back( nodeAnim );
+                nodeAnim->mNodeName=node->mName;
+            }
+            ReadKEYS( nodeAnim );
+        }else if( t=="NODE" ){
+            aiNode *child=ReadNODE( node );
+            children.push_back( child );
+        }
+        ExitChunk();
+    }
+
+    node->mNumMeshes=meshes.size();
+    node->mMeshes=to_array( meshes );
+
+    node->mNumChildren=children.size();
+    node->mChildren=to_array( children );
+
+    return node;
 }
 
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadBB3D( aiScene *scene ){
 
-	_textures.clear();
-	_materials.clear();
-
-	_vertices.clear();
-	_meshes.clear();
+    _textures.clear();
+    _materials.clear();
+
+    _vertices.clear();
+    _meshes.clear();
+
+    _nodes.clear();
+    _nodeAnims.clear();
+    _animations.clear();
+
+    string t=ReadChunk();
+    if( t=="BB3D" ){
+        int version=ReadInt();
+
+        if (!DefaultLogger::isNullLogger()) {
+            char dmp[128];
+            sprintf(dmp,"B3D file format version: %i",version);
+            DefaultLogger::get()->info(dmp);
+        }
+
+        while( ChunkSize() ){
+            string t=ReadChunk();
+            if( t=="TEXS" ){
+                ReadTEXS();
+            }else if( t=="BRUS" ){
+                ReadBRUS();
+            }else if( t=="NODE" ){
+                ReadNODE( 0 );
+            }
+            ExitChunk();
+        }
+    }
+    ExitChunk();
+
+    if( !_nodes.size() ) Fail( "No nodes" );
+
+    if( !_meshes.size() ) Fail( "No meshes" );
+
+    //Fix nodes/meshes/bones
+    for(size_t i=0;i<_nodes.size();++i ){
+        aiNode *node=_nodes[i];
+
+        for( size_t j=0;j<node->mNumMeshes;++j ){
+            aiMesh *mesh=_meshes[node->mMeshes[j]];
+
+            int n_tris=mesh->mNumFaces;
+            int n_verts=mesh->mNumVertices=n_tris * 3;
+
+            aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
+            if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ];
+            if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
+
+            aiFace *face=mesh->mFaces;
+
+            vector< vector<aiVertexWeight> > vweights( _nodes.size() );
+
+            for( int i=0;i<n_verts;i+=3 ){
+                for( int j=0;j<3;++j ){
+                    Vertex &v=_vertices[face->mIndices[j]];
+
+                    *mv++=v.vertex;
+                    if( mn ) *mn++=v.normal;
+                    if( mc ) *mc++=v.texcoords;
+
+                    face->mIndices[j]=i+j;
 
-	_nodes.clear();
-	_nodeAnims.clear();
-	_animations.clear();
+                    for( int k=0;k<4;++k ){
+                        if( !v.weights[k] ) break;
 
-	string t=ReadChunk();
-	if( t=="BB3D" ){
-		int version=ReadInt();
+                        int bone=v.bones[k];
+                        float weight=v.weights[k];
 
-		if (!DefaultLogger::isNullLogger()) {
-			char dmp[128];
-			sprintf(dmp,"B3D file format version: %i",version);
-			DefaultLogger::get()->info(dmp);
-		}
-
-		while( ChunkSize() ){
-			string t=ReadChunk();
-			if( t=="TEXS" ){
-				ReadTEXS();
-			}else if( t=="BRUS" ){
-				ReadBRUS();
-			}else if( t=="NODE" ){
-				ReadNODE( 0 );
-			}
-			ExitChunk();
-		}
-	}
-	ExitChunk();
+                        vweights[bone].push_back( aiVertexWeight(i+j,weight) );
+                    }
+                }
+                ++face;
+            }
 
-	if( !_nodes.size() ) Fail( "No nodes" );
-
-	if( !_meshes.size() ) Fail( "No meshes" );
-
-	//Fix nodes/meshes/bones
-	for(size_t i=0;i<_nodes.size();++i ){
-		aiNode *node=_nodes[i];
-
-		for( size_t j=0;j<node->mNumMeshes;++j ){
-			aiMesh *mesh=_meshes[node->mMeshes[j]];
-
-			int n_tris=mesh->mNumFaces;
-			int n_verts=mesh->mNumVertices=n_tris * 3;
-
-			aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
-			if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ];
-			if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
-
-			aiFace *face=mesh->mFaces;
-
-			vector< vector<aiVertexWeight> > vweights( _nodes.size() );
-
-			for( int i=0;i<n_verts;i+=3 ){
-				for( int j=0;j<3;++j ){
-					Vertex &v=_vertices[face->mIndices[j]];
-
-					*mv++=v.vertex;
-					if( mn ) *mn++=v.normal;
-					if( mc ) *mc++=v.texcoords;
-
-					face->mIndices[j]=i+j;
-
-					for( int k=0;k<4;++k ){
-						if( !v.weights[k] ) break;
-
-						int bone=v.bones[k];
-						float weight=v.weights[k];
-
-						vweights[bone].push_back( aiVertexWeight(i+j,weight) );
-					}
-				}
-				++face;
-			}
-
-			vector<aiBone*> bones;
-			for(size_t i=0;i<vweights.size();++i ){
-				vector<aiVertexWeight> &weights=vweights[i];
-				if( !weights.size() ) continue;
-
-				aiBone *bone=new aiBone;
-				bones.push_back( bone );
-
-				aiNode *bnode=_nodes[i];
-
-				bone->mName=bnode->mName;
-				bone->mNumWeights=weights.size();
-				bone->mWeights=to_array( weights );
-
-				aiMatrix4x4 mat=bnode->mTransformation;
-				while( bnode->mParent ){
-					bnode=bnode->mParent;
-					mat=bnode->mTransformation * mat;
-				}
-				bone->mOffsetMatrix=mat.Inverse();
-			}
-			mesh->mNumBones=bones.size();
-			mesh->mBones=to_array( bones );
-		}
-	}
-
-	//nodes
-	scene->mRootNode=_nodes[0];
-
-	//material
-	if( !_materials.size() ){
-		_materials.push_back( new aiMaterial );
-	}
-	scene->mNumMaterials=_materials.size();
-	scene->mMaterials=to_array( _materials );
-
-	//meshes
-	scene->mNumMeshes=_meshes.size();
-	scene->mMeshes=to_array( _meshes );
-
-	//animations
-	if( _animations.size()==1 && _nodeAnims.size() ){
-
-		aiAnimation *anim=_animations.back();
-		anim->mNumChannels=_nodeAnims.size();
-		anim->mChannels=to_array( _nodeAnims );
+            vector<aiBone*> bones;
+            for(size_t i=0;i<vweights.size();++i ){
+                vector<aiVertexWeight> &weights=vweights[i];
+                if( !weights.size() ) continue;
 
-		scene->mNumAnimations=_animations.size();
-		scene->mAnimations=to_array( _animations );
-	}
+                aiBone *bone=new aiBone;
+                bones.push_back( bone );
+
+                aiNode *bnode=_nodes[i];
+
+                bone->mName=bnode->mName;
+                bone->mNumWeights=weights.size();
+                bone->mWeights=to_array( weights );
+
+                aiMatrix4x4 mat=bnode->mTransformation;
+                while( bnode->mParent ){
+                    bnode=bnode->mParent;
+                    mat=bnode->mTransformation * mat;
+                }
+                bone->mOffsetMatrix=mat.Inverse();
+            }
+            mesh->mNumBones=bones.size();
+            mesh->mBones=to_array( bones );
+        }
+    }
+
+    //nodes
+    scene->mRootNode=_nodes[0];
+
+    //material
+    if( !_materials.size() ){
+        _materials.push_back( new aiMaterial );
+    }
+    scene->mNumMaterials=_materials.size();
+    scene->mMaterials=to_array( _materials );
+
+    //meshes
+    scene->mNumMeshes=_meshes.size();
+    scene->mMeshes=to_array( _meshes );
+
+    //animations
+    if( _animations.size()==1 && _nodeAnims.size() ){
+
+        aiAnimation *anim=_animations.back();
+        anim->mNumChannels=_nodeAnims.size();
+        anim->mChannels=to_array( _nodeAnims );
+
+        scene->mNumAnimations=_animations.size();
+        scene->mAnimations=to_array( _animations );
+    }
 
-	// convert to RH
-	MakeLeftHandedProcess makeleft;
-	makeleft.Execute( scene );
+    // convert to RH
+    MakeLeftHandedProcess makeleft;
+    makeleft.Execute( scene );
 
-	FlipWindingOrderProcess flip;
-	flip.Execute( scene );
+    FlipWindingOrderProcess flip;
+    flip.Execute( scene );
 }
 
 #endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER

+ 57 - 57
code/B3DImporter.h

@@ -60,69 +60,69 @@ namespace Assimp{
 class B3DImporter : public BaseImporter{
 public:
 
-	virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
+    virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
 
 protected:
 
-	virtual const aiImporterDesc* GetInfo () const;
-	virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+    virtual const aiImporterDesc* GetInfo () const;
+    virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
 
 private:
 
-	int ReadByte();
-	int ReadInt();
-	float ReadFloat();
-	aiVector2D ReadVec2();
-	aiVector3D ReadVec3();
-	aiQuaternion ReadQuat();
-	std::string ReadString();
-	std::string ReadChunk();
-	void ExitChunk();
-	unsigned ChunkSize();
-
-	template<class T>
-	T *to_array( const std::vector<T> &v );
-
-	struct Vertex{
-		aiVector3D vertex;
-		aiVector3D normal;
-		aiVector3D texcoords;
-		unsigned char bones[4];
-		float weights[4];
-	};
-
-	AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
-	AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX;
-
-	void ReadTEXS();
-	void ReadBRUS();
-
-	void ReadVRTS();
-	void ReadTRIS( int v0 );
-	void ReadMESH();
-	void ReadBONE( int id );
-	void ReadKEYS( aiNodeAnim *nodeAnim );
-	void ReadANIM();
-
-	aiNode *ReadNODE( aiNode *parent );
-
-	void ReadBB3D( aiScene *scene );
-
-	unsigned _pos;
-//	unsigned _size;
-	std::vector<unsigned char> _buf;
-	std::vector<unsigned> _stack;
-
-	std::vector<std::string> _textures;
-	std::vector<aiMaterial*> _materials;
-
-	int _vflags,_tcsets,_tcsize;
-	std::vector<Vertex> _vertices;
-
-	std::vector<aiNode*> _nodes;
-	std::vector<aiMesh*> _meshes;
-	std::vector<aiNodeAnim*> _nodeAnims;
-	std::vector<aiAnimation*> _animations;
+    int ReadByte();
+    int ReadInt();
+    float ReadFloat();
+    aiVector2D ReadVec2();
+    aiVector3D ReadVec3();
+    aiQuaternion ReadQuat();
+    std::string ReadString();
+    std::string ReadChunk();
+    void ExitChunk();
+    unsigned ChunkSize();
+
+    template<class T>
+    T *to_array( const std::vector<T> &v );
+
+    struct Vertex{
+        aiVector3D vertex;
+        aiVector3D normal;
+        aiVector3D texcoords;
+        unsigned char bones[4];
+        float weights[4];
+    };
+
+    AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
+    AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX;
+
+    void ReadTEXS();
+    void ReadBRUS();
+
+    void ReadVRTS();
+    void ReadTRIS( int v0 );
+    void ReadMESH();
+    void ReadBONE( int id );
+    void ReadKEYS( aiNodeAnim *nodeAnim );
+    void ReadANIM();
+
+    aiNode *ReadNODE( aiNode *parent );
+
+    void ReadBB3D( aiScene *scene );
+
+    unsigned _pos;
+//  unsigned _size;
+    std::vector<unsigned char> _buf;
+    std::vector<unsigned> _stack;
+
+    std::vector<std::string> _textures;
+    std::vector<aiMaterial*> _materials;
+
+    int _vflags,_tcsets,_tcsize;
+    std::vector<Vertex> _vertices;
+
+    std::vector<aiNode*> _nodes;
+    std::vector<aiMesh*> _meshes;
+    std::vector<aiNodeAnim*> _nodeAnims;
+    std::vector<aiAnimation*> _animations;
 };
 
 }

+ 368 - 368
code/BVHLoader.cpp

@@ -55,16 +55,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-	"BVH Importer (MoCap)",
-	"",
-	"",
-	"",
-	aiImporterFlags_SupportTextFlavour,
-	0,
-	0,
-	0,
-	0,
-	"bvh"
+    "BVH Importer (MoCap)",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "bvh"
 };
 
 // ------------------------------------------------------------------------------------------------
@@ -82,458 +82,458 @@ BVHLoader::~BVHLoader()
 // Returns whether the class can handle the format of the given file.
 bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
 {
-	// check file extension
-	const std::string extension = GetExtension(pFile);
+    // check file extension
+    const std::string extension = GetExtension(pFile);
 
-	if( extension == "bvh")
-		return true;
+    if( extension == "bvh")
+        return true;
 
-	if ((!extension.length() || cs) && pIOHandler) {
-		const char* tokens[] = {"HIERARCHY"};
-		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-	}
-	return false;
+    if ((!extension.length() || cs) && pIOHandler) {
+        const char* tokens[] = {"HIERARCHY"};
+        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 void BVHLoader::SetupProperties(const Importer* pImp)
 {
-	noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
+    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Loader meta information
 const aiImporterDesc* BVHLoader::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
 {
-	mFileName = pFile;
+    mFileName = pFile;
 
-	// read file into memory
-	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
-	if( file.get() == NULL)
-		throw DeadlyImportError( "Failed to open file " + pFile + ".");
+    // read file into memory
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
+    if( file.get() == NULL)
+        throw DeadlyImportError( "Failed to open file " + pFile + ".");
 
-	size_t fileSize = file->FileSize();
-	if( fileSize == 0)
-		throw DeadlyImportError( "File is too small.");
+    size_t fileSize = file->FileSize();
+    if( fileSize == 0)
+        throw DeadlyImportError( "File is too small.");
 
-	mBuffer.resize( fileSize);
-	file->Read( &mBuffer.front(), 1, fileSize);
+    mBuffer.resize( fileSize);
+    file->Read( &mBuffer.front(), 1, fileSize);
 
-	// start reading
-	mReader = mBuffer.begin();
-	mLine = 1;
-	ReadStructure( pScene);
+    // start reading
+    mReader = mBuffer.begin();
+    mLine = 1;
+    ReadStructure( pScene);
 
-	if (!noSkeletonMesh) {
-		// build a dummy mesh for the skeleton so that we see something at least
-		SkeletonMeshBuilder meshBuilder( pScene);
-	}
+    if (!noSkeletonMesh) {
+        // build a dummy mesh for the skeleton so that we see something at least
+        SkeletonMeshBuilder meshBuilder( pScene);
+    }
 
-	// construct an animation from all the motion data we read
-	CreateAnimation( pScene);
+    // construct an animation from all the motion data we read
+    CreateAnimation( pScene);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the file
 void BVHLoader::ReadStructure( aiScene* pScene)
 {
-	// first comes hierarchy
-	std::string header = GetNextToken();
-	if( header != "HIERARCHY")
-		ThrowException( "Expected header string \"HIERARCHY\".");
-	ReadHierarchy( pScene);
-
-	// then comes the motion data
-	std::string motion = GetNextToken();
-	if( motion != "MOTION")
-		ThrowException( "Expected beginning of motion data \"MOTION\".");
-	ReadMotion( pScene);
+    // first comes hierarchy
+    std::string header = GetNextToken();
+    if( header != "HIERARCHY")
+        ThrowException( "Expected header string \"HIERARCHY\".");
+    ReadHierarchy( pScene);
+
+    // then comes the motion data
+    std::string motion = GetNextToken();
+    if( motion != "MOTION")
+        ThrowException( "Expected beginning of motion data \"MOTION\".");
+    ReadMotion( pScene);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the hierarchy
 void BVHLoader::ReadHierarchy( aiScene* pScene)
 {
-	std::string root = GetNextToken();
-	if( root != "ROOT")
-		ThrowException( "Expected root node \"ROOT\".");
+    std::string root = GetNextToken();
+    if( root != "ROOT")
+        ThrowException( "Expected root node \"ROOT\".");
 
-	// Go read the hierarchy from here
-	pScene->mRootNode = ReadNode();
+    // Go read the hierarchy from here
+    pScene->mRootNode = ReadNode();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads a node and recursively its childs and returns the created node;
 aiNode* BVHLoader::ReadNode()
 {
-	// first token is name
-	std::string nodeName = GetNextToken();
-	if( nodeName.empty() || nodeName == "{")
-		ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
-
-	// then an opening brace should follow
-	std::string openBrace = GetNextToken();
-	if( openBrace != "{")
-		ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
-
-	// Create a node
-	aiNode* node = new aiNode( nodeName);
-	std::vector<aiNode*> childNodes;
-
-	// and create an bone entry for it
-	mNodes.push_back( Node( node));
-	Node& internNode = mNodes.back();
-
-	// now read the node's contents
-	while( 1)
-	{
-		std::string token = GetNextToken();
-
-		// node offset to parent node
-		if( token == "OFFSET")
-			ReadNodeOffset( node);
-		else if( token == "CHANNELS")
-			ReadNodeChannels( internNode);
-		else if( token == "JOINT")
-		{
-			// child node follows
-			aiNode* child = ReadNode();
-			child->mParent = node;
-			childNodes.push_back( child);
-		}
-		else if( token == "End")
-		{
-			// The real symbol is "End Site". Second part comes in a separate token
-			std::string siteToken = GetNextToken();
-			if( siteToken != "Site")
-				ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken));
-
-			aiNode* child = ReadEndSite( nodeName);
-			child->mParent = node;
-			childNodes.push_back( child);
-		}
-		else if( token == "}")
-		{
-			// we're done with that part of the hierarchy
-			break;
-		} else
-		{
-			// everything else is a parse error
-			ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
-		}
-	}
-
-	// add the child nodes if there are any
-	if( childNodes.size() > 0)
-	{
-		node->mNumChildren = childNodes.size();
-		node->mChildren = new aiNode*[node->mNumChildren];
-		std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
-	}
-
-	// and return the sub-hierarchy we built here
-	return node;
+    // first token is name
+    std::string nodeName = GetNextToken();
+    if( nodeName.empty() || nodeName == "{")
+        ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
+
+    // then an opening brace should follow
+    std::string openBrace = GetNextToken();
+    if( openBrace != "{")
+        ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
+
+    // Create a node
+    aiNode* node = new aiNode( nodeName);
+    std::vector<aiNode*> childNodes;
+
+    // and create an bone entry for it
+    mNodes.push_back( Node( node));
+    Node& internNode = mNodes.back();
+
+    // now read the node's contents
+    while( 1)
+    {
+        std::string token = GetNextToken();
+
+        // node offset to parent node
+        if( token == "OFFSET")
+            ReadNodeOffset( node);
+        else if( token == "CHANNELS")
+            ReadNodeChannels( internNode);
+        else if( token == "JOINT")
+        {
+            // child node follows
+            aiNode* child = ReadNode();
+            child->mParent = node;
+            childNodes.push_back( child);
+        }
+        else if( token == "End")
+        {
+            // The real symbol is "End Site". Second part comes in a separate token
+            std::string siteToken = GetNextToken();
+            if( siteToken != "Site")
+                ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken));
+
+            aiNode* child = ReadEndSite( nodeName);
+            child->mParent = node;
+            childNodes.push_back( child);
+        }
+        else if( token == "}")
+        {
+            // we're done with that part of the hierarchy
+            break;
+        } else
+        {
+            // everything else is a parse error
+            ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
+        }
+    }
+
+    // add the child nodes if there are any
+    if( childNodes.size() > 0)
+    {
+        node->mNumChildren = childNodes.size();
+        node->mChildren = new aiNode*[node->mNumChildren];
+        std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
+    }
+
+    // and return the sub-hierarchy we built here
+    return node;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads an end node and returns the created node.
 aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
 {
-	// check opening brace
-	std::string openBrace = GetNextToken();
-	if( openBrace != "{")
-		ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
-
-	// Create a node
-	aiNode* node = new aiNode( "EndSite_" + pParentName);
-
-	// now read the node's contents. Only possible entry is "OFFSET"
-	while( 1)
-	{
-		std::string token = GetNextToken();
-
-		// end node's offset
-		if( token == "OFFSET")
-		{
-			ReadNodeOffset( node);
-		}
-		else if( token == "}")
-		{
-			// we're done with the end node
-			break;
-		} else
-		{
-			// everything else is a parse error
-			ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
-		}
-	}
-
-	// and return the sub-hierarchy we built here
-	return node;
+    // check opening brace
+    std::string openBrace = GetNextToken();
+    if( openBrace != "{")
+        ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
+
+    // Create a node
+    aiNode* node = new aiNode( "EndSite_" + pParentName);
+
+    // now read the node's contents. Only possible entry is "OFFSET"
+    while( 1)
+    {
+        std::string token = GetNextToken();
+
+        // end node's offset
+        if( token == "OFFSET")
+        {
+            ReadNodeOffset( node);
+        }
+        else if( token == "}")
+        {
+            // we're done with the end node
+            break;
+        } else
+        {
+            // everything else is a parse error
+            ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
+        }
+    }
+
+    // and return the sub-hierarchy we built here
+    return node;
 }
 // ------------------------------------------------------------------------------------------------
 // Reads a node offset for the given node
 void BVHLoader::ReadNodeOffset( aiNode* pNode)
 {
-	// Offset consists of three floats to read
-	aiVector3D offset;
-	offset.x = GetNextTokenAsFloat();
-	offset.y = GetNextTokenAsFloat();
-	offset.z = GetNextTokenAsFloat();
-
-	// build a transformation matrix from it
-	pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
-		0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
+    // Offset consists of three floats to read
+    aiVector3D offset;
+    offset.x = GetNextTokenAsFloat();
+    offset.y = GetNextTokenAsFloat();
+    offset.z = GetNextTokenAsFloat();
+
+    // build a transformation matrix from it
+    pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
+        0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the animation channels for the given node
 void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
 {
-	// number of channels. Use the float reader because we're lazy
-	float numChannelsFloat = GetNextTokenAsFloat();
-	unsigned int numChannels = (unsigned int) numChannelsFloat;
-
-	for( unsigned int a = 0; a < numChannels; a++)
-	{
-		std::string channelToken = GetNextToken();
-
-		if( channelToken == "Xposition")
-			pNode.mChannels.push_back( Channel_PositionX);
-		else if( channelToken == "Yposition")
-			pNode.mChannels.push_back( Channel_PositionY);
-		else if( channelToken == "Zposition")
-			pNode.mChannels.push_back( Channel_PositionZ);
-		else if( channelToken == "Xrotation")
-			pNode.mChannels.push_back( Channel_RotationX);
-		else if( channelToken == "Yrotation")
-			pNode.mChannels.push_back( Channel_RotationY);
-		else if( channelToken == "Zrotation")
-			pNode.mChannels.push_back( Channel_RotationZ);
-		else
-			ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken));
-	}
+    // number of channels. Use the float reader because we're lazy
+    float numChannelsFloat = GetNextTokenAsFloat();
+    unsigned int numChannels = (unsigned int) numChannelsFloat;
+
+    for( unsigned int a = 0; a < numChannels; a++)
+    {
+        std::string channelToken = GetNextToken();
+
+        if( channelToken == "Xposition")
+            pNode.mChannels.push_back( Channel_PositionX);
+        else if( channelToken == "Yposition")
+            pNode.mChannels.push_back( Channel_PositionY);
+        else if( channelToken == "Zposition")
+            pNode.mChannels.push_back( Channel_PositionZ);
+        else if( channelToken == "Xrotation")
+            pNode.mChannels.push_back( Channel_RotationX);
+        else if( channelToken == "Yrotation")
+            pNode.mChannels.push_back( Channel_RotationY);
+        else if( channelToken == "Zrotation")
+            pNode.mChannels.push_back( Channel_RotationZ);
+        else
+            ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken));
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the motion data
 void BVHLoader::ReadMotion( aiScene* /*pScene*/)
 {
-	// Read number of frames
-	std::string tokenFrames = GetNextToken();
-	if( tokenFrames != "Frames:")
-		ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
-
-	float numFramesFloat = GetNextTokenAsFloat();
-	mAnimNumFrames = (unsigned int) numFramesFloat;
-
-	// Read frame duration
-	std::string tokenDuration1 = GetNextToken();
-	std::string tokenDuration2 = GetNextToken();
-	if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
-		ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
-
-	mAnimTickDuration = GetNextTokenAsFloat();
-
-	// resize value vectors for each node
-	for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
-		it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
-
-	// now read all the data and store it in the corresponding node's value vector
-	for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
-	{
-		// on each line read the values for all nodes
-		for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
-		{
-			// get as many values as the node has channels
-			for( unsigned int c = 0; c < it->mChannels.size(); ++c)
-				it->mChannelValues.push_back( GetNextTokenAsFloat());
-		}
-
-		// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
-	}
+    // Read number of frames
+    std::string tokenFrames = GetNextToken();
+    if( tokenFrames != "Frames:")
+        ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
+
+    float numFramesFloat = GetNextTokenAsFloat();
+    mAnimNumFrames = (unsigned int) numFramesFloat;
+
+    // Read frame duration
+    std::string tokenDuration1 = GetNextToken();
+    std::string tokenDuration2 = GetNextToken();
+    if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
+        ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
+
+    mAnimTickDuration = GetNextTokenAsFloat();
+
+    // resize value vectors for each node
+    for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
+        it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
+
+    // now read all the data and store it in the corresponding node's value vector
+    for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
+    {
+        // on each line read the values for all nodes
+        for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
+        {
+            // get as many values as the node has channels
+            for( unsigned int c = 0; c < it->mChannels.size(); ++c)
+                it->mChannelValues.push_back( GetNextTokenAsFloat());
+        }
+
+        // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Retrieves the next token
 std::string BVHLoader::GetNextToken()
 {
-	// skip any preceeding whitespace
-	while( mReader != mBuffer.end())
-	{
-		if( !isspace( *mReader))
-			break;
-
-		// count lines
-		if( *mReader == '\n')
-			mLine++;
-
-		++mReader;
-	}
-
-	// collect all chars till the next whitespace. BVH is easy in respect to that.
-	std::string token;
-	while( mReader != mBuffer.end())
-	{
-		if( isspace( *mReader))
-			break;
-
-		token.push_back( *mReader);
-		++mReader;
-
-		// little extra logic to make sure braces are counted correctly
-		if( token == "{" || token == "}")
-			break;
-	}
-
-	// empty token means end of file, which is just fine
-	return token;
+    // skip any preceeding whitespace
+    while( mReader != mBuffer.end())
+    {
+        if( !isspace( *mReader))
+            break;
+
+        // count lines
+        if( *mReader == '\n')
+            mLine++;
+
+        ++mReader;
+    }
+
+    // collect all chars till the next whitespace. BVH is easy in respect to that.
+    std::string token;
+    while( mReader != mBuffer.end())
+    {
+        if( isspace( *mReader))
+            break;
+
+        token.push_back( *mReader);
+        ++mReader;
+
+        // little extra logic to make sure braces are counted correctly
+        if( token == "{" || token == "}")
+            break;
+    }
+
+    // empty token means end of file, which is just fine
+    return token;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the next token as a float
 float BVHLoader::GetNextTokenAsFloat()
 {
-	std::string token = GetNextToken();
-	if( token.empty())
-		ThrowException( "Unexpected end of file while trying to read a float");
+    std::string token = GetNextToken();
+    if( token.empty())
+        ThrowException( "Unexpected end of file while trying to read a float");
 
-	// check if the float is valid by testing if the atof() function consumed every char of the token
-	const char* ctoken = token.c_str();
-	float result = 0.0f;
-	ctoken = fast_atoreal_move<float>( ctoken, result);
+    // check if the float is valid by testing if the atof() function consumed every char of the token
+    const char* ctoken = token.c_str();
+    float result = 0.0f;
+    ctoken = fast_atoreal_move<float>( ctoken, result);
 
-	if( ctoken != token.c_str() + token.length())
-		ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token));
+    if( ctoken != token.c_str() + token.length())
+        ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token));
 
-	return result;
+    return result;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Aborts the file reading with an exception
 AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError)
 {
-	throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
+    throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
 }
 
 // ------------------------------------------------------------------------------------------------
 // Constructs an animation for the motion data and stores it in the given scene
 void BVHLoader::CreateAnimation( aiScene* pScene)
 {
-	// create the animation
-	pScene->mNumAnimations = 1;
-	pScene->mAnimations = new aiAnimation*[1];
-	aiAnimation* anim = new aiAnimation;
-	pScene->mAnimations[0] = anim;
-
-	// put down the basic parameters
-	anim->mName.Set( "Motion");
-	anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
-	anim->mDuration = double( mAnimNumFrames - 1);
-
-	// now generate the tracks for all nodes
-	anim->mNumChannels = mNodes.size();
-	anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
-
-	// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
-	for (unsigned int i = 0; i < anim->mNumChannels;++i)
-		anim->mChannels[i] = NULL;
-
-	for( unsigned int a = 0; a < anim->mNumChannels; a++)
-	{
-		const Node& node = mNodes[a];
-		const std::string nodeName = std::string( node.mNode->mName.data );
-		aiNodeAnim* nodeAnim = new aiNodeAnim;
-		anim->mChannels[a] = nodeAnim;
-		nodeAnim->mNodeName.Set( nodeName);
-
-		// translational part, if given
-		if( node.mChannels.size() == 6)
-		{
-			nodeAnim->mNumPositionKeys = mAnimNumFrames;
-			nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
-			aiVectorKey* poskey = nodeAnim->mPositionKeys;
-			for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
-			{
-				poskey->mTime = double( fr);
-
-				// Now compute all translations in the right order
-				for( unsigned int channel = 0; channel < 3; ++channel)
-				{
-					switch( node.mChannels[channel])
-					{
-					case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-					case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-					case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-					default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
-					}
-				}
-				++poskey;
-			}
-		} else
-		{
-			// if no translation part is given, put a default sequence
-			aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
-			nodeAnim->mNumPositionKeys = 1;
-			nodeAnim->mPositionKeys = new aiVectorKey[1];
-			nodeAnim->mPositionKeys[0].mTime = 0.0;
-			nodeAnim->mPositionKeys[0].mValue = nodePos;
-		}
-
-		// rotation part. Always present. First find value offsets
-		{
-			unsigned int rotOffset  = 0;
-			if( node.mChannels.size() == 6)
-			{
-				// Offset all further calculations
-				rotOffset = 3;
-			}
-
-			// Then create the number of rotation keys
-			nodeAnim->mNumRotationKeys = mAnimNumFrames;
-			nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
-			aiQuatKey* rotkey = nodeAnim->mRotationKeys;
-			for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
-			{
-				aiMatrix4x4 temp;
-				aiMatrix3x3 rotMatrix;
-
-				for( unsigned int channel = 0; channel < 3; ++channel)
-				{
-					// translate ZXY euler angels into a quaternion
-					const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
-
-					// Compute rotation transformations in the right order
-					switch (node.mChannels[rotOffset+channel])
-					{
-					case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
-					case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);	break;
-					case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
-					default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
-					}
-				}
-
-				rotkey->mTime = double( fr);
-				rotkey->mValue = aiQuaternion( rotMatrix);
-				++rotkey;
-			}
-		}
-
-		// scaling part. Always just a default track
-		{
-			nodeAnim->mNumScalingKeys = 1;
-			nodeAnim->mScalingKeys = new aiVectorKey[1];
-			nodeAnim->mScalingKeys[0].mTime = 0.0;
-			nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
-		}
-	}
+    // create the animation
+    pScene->mNumAnimations = 1;
+    pScene->mAnimations = new aiAnimation*[1];
+    aiAnimation* anim = new aiAnimation;
+    pScene->mAnimations[0] = anim;
+
+    // put down the basic parameters
+    anim->mName.Set( "Motion");
+    anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
+    anim->mDuration = double( mAnimNumFrames - 1);
+
+    // now generate the tracks for all nodes
+    anim->mNumChannels = mNodes.size();
+    anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
+
+    // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
+    for (unsigned int i = 0; i < anim->mNumChannels;++i)
+        anim->mChannels[i] = NULL;
+
+    for( unsigned int a = 0; a < anim->mNumChannels; a++)
+    {
+        const Node& node = mNodes[a];
+        const std::string nodeName = std::string( node.mNode->mName.data );
+        aiNodeAnim* nodeAnim = new aiNodeAnim;
+        anim->mChannels[a] = nodeAnim;
+        nodeAnim->mNodeName.Set( nodeName);
+
+        // translational part, if given
+        if( node.mChannels.size() == 6)
+        {
+            nodeAnim->mNumPositionKeys = mAnimNumFrames;
+            nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
+            aiVectorKey* poskey = nodeAnim->mPositionKeys;
+            for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
+            {
+                poskey->mTime = double( fr);
+
+                // Now compute all translations in the right order
+                for( unsigned int channel = 0; channel < 3; ++channel)
+                {
+                    switch( node.mChannels[channel])
+                    {
+                    case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
+                    case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
+                    case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
+                    default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
+                    }
+                }
+                ++poskey;
+            }
+        } else
+        {
+            // if no translation part is given, put a default sequence
+            aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
+            nodeAnim->mNumPositionKeys = 1;
+            nodeAnim->mPositionKeys = new aiVectorKey[1];
+            nodeAnim->mPositionKeys[0].mTime = 0.0;
+            nodeAnim->mPositionKeys[0].mValue = nodePos;
+        }
+
+        // rotation part. Always present. First find value offsets
+        {
+            unsigned int rotOffset  = 0;
+            if( node.mChannels.size() == 6)
+            {
+                // Offset all further calculations
+                rotOffset = 3;
+            }
+
+            // Then create the number of rotation keys
+            nodeAnim->mNumRotationKeys = mAnimNumFrames;
+            nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
+            aiQuatKey* rotkey = nodeAnim->mRotationKeys;
+            for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
+            {
+                aiMatrix4x4 temp;
+                aiMatrix3x3 rotMatrix;
+
+                for( unsigned int channel = 0; channel < 3; ++channel)
+                {
+                    // translate ZXY euler angels into a quaternion
+                    const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
+
+                    // Compute rotation transformations in the right order
+                    switch (node.mChannels[rotOffset+channel])
+                    {
+                    case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
+                    case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);  break;
+                    case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
+                    default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
+                    }
+                }
+
+                rotkey->mTime = double( fr);
+                rotkey->mValue = aiQuaternion( rotMatrix);
+                ++rotkey;
+            }
+        }
+
+        // scaling part. Always just a default track
+        {
+            nodeAnim->mNumScalingKeys = 1;
+            nodeAnim->mScalingKeys = new aiVectorKey[1];
+            nodeAnim->mScalingKeys[0].mTime = 0.0;
+            nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
+        }
+    }
 }
 
 #endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER

+ 70 - 70
code/BVHLoader.h

@@ -64,106 +64,106 @@ namespace Assimp
 class BVHLoader : public BaseImporter
 {
 
-	/** Possible animation channels for which the motion data holds the values */
-	enum ChannelType
-	{
-		Channel_PositionX,
-		Channel_PositionY,
-		Channel_PositionZ,
-		Channel_RotationX,
-		Channel_RotationY,
-		Channel_RotationZ
-	};
-
-	/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
-	struct Node
-	{
-		const aiNode* mNode;
-		std::vector<ChannelType> mChannels;
-		std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
-
-		Node() { }
-		Node( const aiNode* pNode) : mNode( pNode) { }
-	};
+    /** Possible animation channels for which the motion data holds the values */
+    enum ChannelType
+    {
+        Channel_PositionX,
+        Channel_PositionY,
+        Channel_PositionZ,
+        Channel_RotationX,
+        Channel_RotationY,
+        Channel_RotationZ
+    };
+
+    /** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
+    struct Node
+    {
+        const aiNode* mNode;
+        std::vector<ChannelType> mChannels;
+        std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
+
+        Node() { }
+        Node( const aiNode* pNode) : mNode( pNode) { }
+    };
 
 public:
 
-	BVHLoader();
-	~BVHLoader();
+    BVHLoader();
+    ~BVHLoader();
 
 public:
-	/** Returns whether the class can handle the format of the given file.
-	 * See BaseImporter::CanRead() for details.	*/
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
+    /** Returns whether the class can handle the format of the given file.
+     * See BaseImporter::CanRead() for details. */
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
 
-	void SetupProperties(const Importer* pImp);
-	const aiImporterDesc* GetInfo () const;
+    void SetupProperties(const Importer* pImp);
+    const aiImporterDesc* GetInfo () const;
 
 protected:
 
 
-	/** Imports the given file into the given scene structure.
-	 * See BaseImporter::InternReadFile() for details
-	 */
-	void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+    /** Imports the given file into the given scene structure.
+     * See BaseImporter::InternReadFile() for details
+     */
+    void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
 
 protected:
-	/** Reads the file */
-	void ReadStructure( aiScene* pScene);
+    /** Reads the file */
+    void ReadStructure( aiScene* pScene);
 
-	/** Reads the hierarchy */
-	void ReadHierarchy( aiScene* pScene);
+    /** Reads the hierarchy */
+    void ReadHierarchy( aiScene* pScene);
 
-	/** Reads a node and recursively its childs and returns the created node. */
-	aiNode* ReadNode();
+    /** Reads a node and recursively its childs and returns the created node. */
+    aiNode* ReadNode();
 
-	/** Reads an end node and returns the created node. */
-	aiNode* ReadEndSite( const std::string& pParentName);
+    /** Reads an end node and returns the created node. */
+    aiNode* ReadEndSite( const std::string& pParentName);
 
-	/** Reads a node offset for the given node */
-	void ReadNodeOffset( aiNode* pNode);
+    /** Reads a node offset for the given node */
+    void ReadNodeOffset( aiNode* pNode);
 
-	/** Reads the animation channels into the given node */
-	void ReadNodeChannels( BVHLoader::Node& pNode);
+    /** Reads the animation channels into the given node */
+    void ReadNodeChannels( BVHLoader::Node& pNode);
 
-	/** Reads the motion data */
-	void ReadMotion( aiScene* pScene);
+    /** Reads the motion data */
+    void ReadMotion( aiScene* pScene);
 
-	/** Retrieves the next token */
-	std::string GetNextToken();
+    /** Retrieves the next token */
+    std::string GetNextToken();
 
-	/** Reads the next token as a float */
-	float GetNextTokenAsFloat();
+    /** Reads the next token as a float */
+    float GetNextTokenAsFloat();
 
-	/** Aborts the file reading with an exception */
-	AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
+    /** Aborts the file reading with an exception */
+    AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
 
-	/** Constructs an animation for the motion data and stores it in the given scene */
-	void CreateAnimation( aiScene* pScene);
+    /** Constructs an animation for the motion data and stores it in the given scene */
+    void CreateAnimation( aiScene* pScene);
 
 protected:
-	/** Filename, for a verbose error message */
-	std::string mFileName;
+    /** Filename, for a verbose error message */
+    std::string mFileName;
 
-	/** Buffer to hold the loaded file */
-	std::vector<char> mBuffer;
+    /** Buffer to hold the loaded file */
+    std::vector<char> mBuffer;
 
-	/** Next char to read from the buffer */
-	std::vector<char>::const_iterator mReader;
+    /** Next char to read from the buffer */
+    std::vector<char>::const_iterator mReader;
 
-	/** Current line, for error messages */
-	unsigned int mLine;
+    /** Current line, for error messages */
+    unsigned int mLine;
 
-	/** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index.
-	* Also contain the motion data for the node's channels
-	*/
-	std::vector<Node> mNodes;
+    /** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index.
+    * Also contain the motion data for the node's channels
+    */
+    std::vector<Node> mNodes;
 
-	/** basic Animation parameters */
-	float mAnimTickDuration;
-	unsigned int mAnimNumFrames;
+    /** basic Animation parameters */
+    float mAnimTickDuration;
+    unsigned int mAnimNumFrames;
 
-	bool noSkeletonMesh;
+    bool noSkeletonMesh;
 };
 
 } // end of namespace Assimp

+ 388 - 392
code/BaseImporter.cpp

@@ -65,100 +65,100 @@ using namespace Assimp;
 BaseImporter::BaseImporter()
 : progress()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 BaseImporter::~BaseImporter()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file and returns the imported data.
 aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
 {
-	progress = pImp->GetProgressHandler();
-	ai_assert(progress);
+    progress = pImp->GetProgressHandler();
+    ai_assert(progress);
 
-	// Gather configuration properties for this run
-	SetupProperties( pImp );
+    // Gather configuration properties for this run
+    SetupProperties( pImp );
 
-	// Construct a file system filter to improve our success ratio at reading external files
-	FileSystemFilter filter(pFile,pIOHandler);
+    // Construct a file system filter to improve our success ratio at reading external files
+    FileSystemFilter filter(pFile,pIOHandler);
 
-	// create a scene object to hold the data
-	ScopeGuard<aiScene> sc(new aiScene());
+    // create a scene object to hold the data
+    ScopeGuard<aiScene> sc(new aiScene());
 
-	// dispatch importing
-	try
-	{
-		InternReadFile( pFile, sc, &filter);
+    // dispatch importing
+    try
+    {
+        InternReadFile( pFile, sc, &filter);
 
-	} catch( const std::exception& err )	{
-		// extract error description
-		mErrorText = err.what();
-		DefaultLogger::get()->error(mErrorText);
-		return NULL;
-	}
+    } catch( const std::exception& err )    {
+        // extract error description
+        mErrorText = err.what();
+        DefaultLogger::get()->error(mErrorText);
+        return NULL;
+    }
 
-	// return what we gathered from the import.
-	sc.dismiss();
-	return sc;
+    // return what we gathered from the import.
+    sc.dismiss();
+    return sc;
 }
 
 // ------------------------------------------------------------------------------------------------
 void BaseImporter::SetupProperties(const Importer* /*pImp*/)
 {
-	// the default implementation does nothing
+    // the default implementation does nothing
 }
 
 // ------------------------------------------------------------------------------------------------
 void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
 {
-	const aiImporterDesc* desc = GetInfo();
-	ai_assert(desc != NULL);
-
-	const char* ext = desc->mFileExtensions;
-	ai_assert(ext != NULL);
-
-	const char* last = ext;
-	do {
-		if (!*ext || *ext == ' ') {
-			extensions.insert(std::string(last,ext-last));
-			ai_assert(ext-last > 0);
-			last = ext;
-			while(*last == ' ') {
-				++last;
-			}
-		}
-	}
-	while(*ext++);
+    const aiImporterDesc* desc = GetInfo();
+    ai_assert(desc != NULL);
+
+    const char* ext = desc->mFileExtensions;
+    ai_assert(ext != NULL);
+
+    const char* last = ext;
+    do {
+        if (!*ext || *ext == ' ') {
+            extensions.insert(std::string(last,ext-last));
+            ai_assert(ext-last > 0);
+            last = ext;
+            while(*last == ' ') {
+                ++last;
+            }
+        }
+    }
+    while(*ext++);
 }
 
 // ------------------------------------------------------------------------------------------------
 /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler,
-	const std::string&	pFile,
-	const char**		tokens,
-	unsigned int		numTokens,
-	unsigned int		searchBytes /* = 200 */,
-	bool				tokensSol /* false */)
+    const std::string&  pFile,
+    const char**        tokens,
+    unsigned int        numTokens,
+    unsigned int        searchBytes /* = 200 */,
+    bool                tokensSol /* false */)
 {
-	ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes);
-	if (!pIOHandler)
-		return false;
-
-	boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
-	if (pStream.get() )	{
-		// read 200 characters from the file
-		boost::scoped_array<char> _buffer (new char[searchBytes+1 /* for the '\0' */]);
-		char* buffer = _buffer.get();
+    ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes);
+    if (!pIOHandler)
+        return false;
+
+    boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
+    if (pStream.get() ) {
+        // read 200 characters from the file
+        boost::scoped_array<char> _buffer (new char[searchBytes+1 /* for the '\0' */]);
+        char* buffer = _buffer.get();
         if( NULL == buffer ) {
             return false;
         }
 
-		const size_t read = pStream->Read(buffer,1,searchBytes);
+        const size_t read = pStream->Read(buffer,1,searchBytes);
         if( !read ) {
             return false;
         }
@@ -167,139 +167,139 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
             buffer[ i ] = ::tolower( buffer[ i ] );
         }
 
-		// It is not a proper handling of unicode files here ...
-		// ehm ... but it works in most cases.
-		char* cur = buffer,*cur2 = buffer,*end = &buffer[read];
-		while (cur != end)	{
+        // It is not a proper handling of unicode files here ...
+        // ehm ... but it works in most cases.
+        char* cur = buffer,*cur2 = buffer,*end = &buffer[read];
+        while (cur != end)  {
             if( *cur ) {
                 *cur2++ = *cur;
             }
-			++cur;
-		}
-		*cur2 = '\0';
+            ++cur;
+        }
+        *cur2 = '\0';
 
-		for (unsigned int i = 0; i < numTokens;++i)	{
-			ai_assert(NULL != tokens[i]);
+        for (unsigned int i = 0; i < numTokens;++i) {
+            ai_assert(NULL != tokens[i]);
 
 
-			const char* r = strstr(buffer,tokens[i]);
+            const char* r = strstr(buffer,tokens[i]);
             if( !r ) {
                 continue;
             }
-			// We got a match, either we don't care where it is, or it happens to
-			// be in the beginning of the file / line
-			if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
-				DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]);
-				return true;
-			}
-		}
-	}
-
-	return false;
+            // We got a match, either we don't care where it is, or it happens to
+            // be in the beginning of the file / line
+            if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
+                DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]);
+                return true;
+            }
+        }
+    }
+
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Simple check for file extension
 /*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile,
-	const char* ext0,
-	const char* ext1,
-	const char* ext2)
+    const char* ext0,
+    const char* ext1,
+    const char* ext2)
 {
-	std::string::size_type pos = pFile.find_last_of('.');
+    std::string::size_type pos = pFile.find_last_of('.');
 
-	// no file extension - can't read
-	if( pos == std::string::npos)
-		return false;
+    // no file extension - can't read
+    if( pos == std::string::npos)
+        return false;
 
-	const char* ext_real = & pFile[ pos+1 ];
-	if( !ASSIMP_stricmp(ext_real,ext0) )
-		return true;
+    const char* ext_real = & pFile[ pos+1 ];
+    if( !ASSIMP_stricmp(ext_real,ext0) )
+        return true;
 
-	// check for other, optional, file extensions
-	if (ext1 && !ASSIMP_stricmp(ext_real,ext1))
-		return true;
+    // check for other, optional, file extensions
+    if (ext1 && !ASSIMP_stricmp(ext_real,ext1))
+        return true;
 
-	if (ext2 && !ASSIMP_stricmp(ext_real,ext2))
-		return true;
+    if (ext2 && !ASSIMP_stricmp(ext_real,ext2))
+        return true;
 
-	return false;
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get file extension from path
 /*static*/ std::string BaseImporter::GetExtension (const std::string& pFile)
 {
-	std::string::size_type pos = pFile.find_last_of('.');
+    std::string::size_type pos = pFile.find_last_of('.');
 
-	// no file extension at all
-	if( pos == std::string::npos)
-		return "";
+    // no file extension at all
+    if( pos == std::string::npos)
+        return "";
 
-	std::string ret = pFile.substr(pos+1);
-	std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
-	return ret;
+    std::string ret = pFile.substr(pos+1);
+    std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
+    return ret;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Check for magic bytes at the beginning of the file.
 /* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
-	const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
+    const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
 {
-	ai_assert(size <= 16 && _magic);
-
-	if (!pIOHandler) {
-		return false;
-	}
-	union {
-		const char* magic;
-		const uint16_t* magic_u16;
-		const uint32_t* magic_u32;
-	};
-	magic = reinterpret_cast<const char*>(_magic);
-	boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
-	if (pStream.get() )	{
-
-		// skip to offset
-		pStream->Seek(offset,aiOrigin_SET);
-
-		// read 'size' characters from the file
-		union {
-			char data[16];
-			uint16_t data_u16[8];
-			uint32_t data_u32[4];
-		};
-		if(size != pStream->Read(data,1,size)) {
-			return false;
-		}
-
-		for (unsigned int i = 0; i < num; ++i) {
-			// also check against big endian versions of tokens with size 2,4
-			// that's just for convinience, the chance that we cause conflicts
-			// is quite low and it can save some lines and prevent nasty bugs
-			if (2 == size) {
-				uint16_t rev = *magic_u16;
-				ByteSwap::Swap(&rev);
-				if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
-					return true;
-				}
-			}
-			else if (4 == size) {
-				uint32_t rev = *magic_u32;
-				ByteSwap::Swap(&rev);
-				if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
-					return true;
-				}
-			}
-			else {
-				// any length ... just compare
-				if(!memcmp(magic,data,size)) {
-					return true;
-				}
-			}
-			magic += size;
-		}
-	}
-	return false;
+    ai_assert(size <= 16 && _magic);
+
+    if (!pIOHandler) {
+        return false;
+    }
+    union {
+        const char* magic;
+        const uint16_t* magic_u16;
+        const uint32_t* magic_u32;
+    };
+    magic = reinterpret_cast<const char*>(_magic);
+    boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
+    if (pStream.get() ) {
+
+        // skip to offset
+        pStream->Seek(offset,aiOrigin_SET);
+
+        // read 'size' characters from the file
+        union {
+            char data[16];
+            uint16_t data_u16[8];
+            uint32_t data_u32[4];
+        };
+        if(size != pStream->Read(data,1,size)) {
+            return false;
+        }
+
+        for (unsigned int i = 0; i < num; ++i) {
+            // also check against big endian versions of tokens with size 2,4
+            // that's just for convinience, the chance that we cause conflicts
+            // is quite low and it can save some lines and prevent nasty bugs
+            if (2 == size) {
+                uint16_t rev = *magic_u16;
+                ByteSwap::Swap(&rev);
+                if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
+                    return true;
+                }
+            }
+            else if (4 == size) {
+                uint32_t rev = *magic_u32;
+                ByteSwap::Swap(&rev);
+                if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
+                    return true;
+                }
+            }
+            else {
+                // any length ... just compare
+                if(!memcmp(magic,data,size)) {
+                    return true;
+                }
+            }
+            magic += size;
+        }
+    }
+    return false;
 }
 
 #include "../contrib/ConvertUTF/ConvertUTF.h"
@@ -307,311 +307,307 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
 // ------------------------------------------------------------------------------------------------
 void ReportResult(ConversionResult res)
 {
-	if(res == sourceExhausted) {
-		DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails");
-	}
-	else if(res == sourceIllegal) {
-		DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails");
-	}
+    if(res == sourceExhausted) {
+        DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails");
+    }
+    else if(res == sourceIllegal) {
+        DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert to UTF8 data
 void BaseImporter::ConvertToUTF8(std::vector<char>& data)
 {
-	ConversionResult result;
-	if(data.size() < 8) {
-		throw DeadlyImportError("File is too small");
-	}
-
-	// UTF 8 with BOM
-	if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
-		DefaultLogger::get()->debug("Found UTF-8 BOM ...");
-
-		std::copy(data.begin()+3,data.end(),data.begin());
-		data.resize(data.size()-3);
-		return;
-	}
-
-	// UTF 32 BE with BOM
-	if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
-
-		// swap the endianess ..
-		for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) {
-			AI_SWAP4P(p);
-		}
-	}
-
-	// UTF 32 LE with BOM
-	if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
-		DefaultLogger::get()->debug("Found UTF-32 BOM ...");
-
-		const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
-		char* dstart,*dend;
-		std::vector<char> output;
-		do {
-			output.resize(output.size()?output.size()*3/2:data.size()/2);
-			dstart = &output.front(),dend = &output.back()+1;
-
-			result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
-		} while(result == targetExhausted);
-
-		ReportResult(result);
-
-		// copy to output buffer.
-		const size_t outlen = (size_t)(dstart-&output.front());
-		data.assign(output.begin(),output.begin()+outlen);
-		return;
-	}
-
-	// UTF 16 BE with BOM
-	if(*((uint16_t*)&data.front()) == 0xFFFE) {
-
-		// swap the endianess ..
-		for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) {
-			ByteSwap::Swap2(p);
-		}
-	}
-
-	// UTF 16 LE with BOM
-	if(*((uint16_t*)&data.front()) == 0xFEFF) {
-		DefaultLogger::get()->debug("Found UTF-16 BOM ...");
-
-		const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
-		char* dstart,*dend;
-		std::vector<char> output;
-		do {
-			output.resize(output.size()?output.size()*3/2:data.size()*3/4);
-			dstart = &output.front(),dend = &output.back()+1;
-
-			result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
-		} while(result == targetExhausted);
-
-		ReportResult(result);
-
-		// copy to output buffer.
-		const size_t outlen = (size_t)(dstart-&output.front());
-		data.assign(output.begin(),output.begin()+outlen);
-		return;
-	}
+    ConversionResult result;
+    if(data.size() < 8) {
+        throw DeadlyImportError("File is too small");
+    }
+
+    // UTF 8 with BOM
+    if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
+        DefaultLogger::get()->debug("Found UTF-8 BOM ...");
+
+        std::copy(data.begin()+3,data.end(),data.begin());
+        data.resize(data.size()-3);
+        return;
+    }
+
+    // UTF 32 BE with BOM
+    if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
+
+        // swap the endianess ..
+        for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) {
+            AI_SWAP4P(p);
+        }
+    }
+
+    // UTF 32 LE with BOM
+    if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
+        DefaultLogger::get()->debug("Found UTF-32 BOM ...");
+
+        const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
+        char* dstart,*dend;
+        std::vector<char> output;
+        do {
+            output.resize(output.size()?output.size()*3/2:data.size()/2);
+            dstart = &output.front(),dend = &output.back()+1;
+
+            result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
+        } while(result == targetExhausted);
+
+        ReportResult(result);
+
+        // copy to output buffer.
+        const size_t outlen = (size_t)(dstart-&output.front());
+        data.assign(output.begin(),output.begin()+outlen);
+        return;
+    }
+
+    // UTF 16 BE with BOM
+    if(*((uint16_t*)&data.front()) == 0xFFFE) {
+
+        // swap the endianess ..
+        for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) {
+            ByteSwap::Swap2(p);
+        }
+    }
+
+    // UTF 16 LE with BOM
+    if(*((uint16_t*)&data.front()) == 0xFEFF) {
+        DefaultLogger::get()->debug("Found UTF-16 BOM ...");
+
+        const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
+        char* dstart,*dend;
+        std::vector<char> output;
+        do {
+            output.resize(output.size()?output.size()*3/2:data.size()*3/4);
+            dstart = &output.front(),dend = &output.back()+1;
+
+            result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
+        } while(result == targetExhausted);
+
+        ReportResult(result);
+
+        // copy to output buffer.
+        const size_t outlen = (size_t)(dstart-&output.front());
+        data.assign(output.begin(),output.begin()+outlen);
+        return;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert to UTF8 data to ISO-8859-1
 void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
 {
-	size_t size = data.size();
-	size_t i = 0, j = 0;
-
-	while(i < size) {
-		if ((unsigned char) data[i] < (size_t) 0x80) {
-			data[j] = data[i];
-		} else if(i < size - 1) {
-			if((unsigned char) data[i] == 0xC2) {
-				data[j] = data[++i];
-			} else if((unsigned char) data[i] == 0xC3) {
-				data[j] = ((unsigned char) data[++i] + 0x40);
-			} else {
-				std::stringstream stream;
-
-				stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
-
-				DefaultLogger::get()->error(stream.str());
-
-				data[j++] = data[i++];
-				data[j] = data[i];
-			}
-		} else {
-			DefaultLogger::get()->error("UTF8 code but only one character remaining");
+    size_t size = data.size();
+    size_t i = 0, j = 0;
+
+    while(i < size) {
+        if ((unsigned char) data[i] < (size_t) 0x80) {
+            data[j] = data[i];
+        } else if(i < size - 1) {
+            if((unsigned char) data[i] == 0xC2) {
+                data[j] = data[++i];
+            } else if((unsigned char) data[i] == 0xC3) {
+                data[j] = ((unsigned char) data[++i] + 0x40);
+            } else {
+                std::stringstream stream;
+
+                stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
+
+                DefaultLogger::get()->error(stream.str());
+
+                data[j++] = data[i++];
+                data[j] = data[i];
+            }
+        } else {
+            DefaultLogger::get()->error("UTF8 code but only one character remaining");
 
-			data[j] = data[i];
-		}
+            data[j] = data[i];
+        }
 
-		i++; j++;
-	}
+        i++; j++;
+    }
 
-	data.resize(j);
+    data.resize(j);
 }
 
 // ------------------------------------------------------------------------------------------------
 void BaseImporter::TextFileToBuffer(IOStream* stream,
-	std::vector<char>& data)
+    std::vector<char>& data)
 {
-	ai_assert(NULL != stream);
+    ai_assert(NULL != stream);
 
-	const size_t fileSize = stream->FileSize();
-	if(!fileSize) {
-		throw DeadlyImportError("File is empty");
-	}
+    const size_t fileSize = stream->FileSize();
+    if(!fileSize) {
+        throw DeadlyImportError("File is empty");
+    }
 
-	data.reserve(fileSize+1);
-	data.resize(fileSize);
-	if(fileSize != stream->Read( &data[0], 1, fileSize)) {
-		throw DeadlyImportError("File read error");
-	}
+    data.reserve(fileSize+1);
+    data.resize(fileSize);
+    if(fileSize != stream->Read( &data[0], 1, fileSize)) {
+        throw DeadlyImportError("File read error");
+    }
 
-	ConvertToUTF8(data);
+    ConvertToUTF8(data);
 
-	// append a binary zero to simplify string parsing
-	data.push_back(0);
+    // append a binary zero to simplify string parsing
+    data.push_back(0);
 }
 
 // ------------------------------------------------------------------------------------------------
 namespace Assimp
 {
-	// Represents an import request
-	struct LoadRequest
-	{
-		LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id)
-			: file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id)
-		{
-			if (_map)
-				map = *_map;
-		}
-
-		const std::string file;
-		unsigned int flags;
-		unsigned int refCnt;
-		aiScene* scene;
-		bool loaded;
-		BatchLoader::PropertyMap map;
-		unsigned int id;
-
-		bool operator== (const std::string& f) {
-			return file == f;
-		}
-	};
+    // Represents an import request
+    struct LoadRequest
+    {
+        LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id)
+            : file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id)
+        {
+            if (_map)
+                map = *_map;
+        }
+
+        const std::string file;
+        unsigned int flags;
+        unsigned int refCnt;
+        aiScene* scene;
+        bool loaded;
+        BatchLoader::PropertyMap map;
+        unsigned int id;
+
+        bool operator== (const std::string& f) {
+            return file == f;
+        }
+    };
 }
 
 // ------------------------------------------------------------------------------------------------
 // BatchLoader::pimpl data structure
 struct Assimp::BatchData
 {
-	BatchData()
+    BatchData()
         : pIOSystem()
         , pImporter()
         , next_id(0xffff)
-	{}
+    {}
 
-	// IO system to be used for all imports
-	IOSystem* pIOSystem;
+    // IO system to be used for all imports
+    IOSystem* pIOSystem;
 
-	// Importer used to load all meshes
-	Importer* pImporter;
+    // Importer used to load all meshes
+    Importer* pImporter;
 
-	// List of all imports
-	std::list<LoadRequest> requests;
+    // List of all imports
+    std::list<LoadRequest> requests;
 
-	// Base path
-	std::string pathBase;
+    // Base path
+    std::string pathBase;
 
-	// Id for next item
-	unsigned int next_id;
+    // Id for next item
+    unsigned int next_id;
 };
 
 // ------------------------------------------------------------------------------------------------
 BatchLoader::BatchLoader(IOSystem* pIO)
 {
-	ai_assert(NULL != pIO);
+    ai_assert(NULL != pIO);
 
-	data = new BatchData();
-	data->pIOSystem = pIO;
+    data = new BatchData();
+    data->pIOSystem = pIO;
 
-	data->pImporter = new Importer();
-	data->pImporter->SetIOHandler(data->pIOSystem);
+    data->pImporter = new Importer();
+    data->pImporter->SetIOHandler(data->pIOSystem);
 }
 
 // ------------------------------------------------------------------------------------------------
 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 (*it).scene;
-	}
-	data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */
-	delete data->pImporter;
-	delete data;
+    // 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 (*it).scene;
+    }
+    data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */
+    delete data->pImporter;
+    delete data;
 }
 
 
 // ------------------------------------------------------------------------------------------------
-unsigned int BatchLoader::AddLoadRequest	(const std::string& file,
-	unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
+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)	{
-
-		// Call IOSystem's path comparison function here
-		if (data->pIOSystem->ComparePaths((*it).file,file))	{
-
-			if (map) {
-				if (!((*it).map == *map))
-					continue;
-			}
-			else if (!(*it).map.empty())
-				continue;
-
-			(*it).refCnt++;
-			return (*it).id;
-		}
-	}
-
-	// 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++;
+    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)  {
+
+        // Call IOSystem's path comparison function here
+        if (data->pIOSystem->ComparePaths((*it).file,file)) {
+
+            if (map) {
+                if (!((*it).map == *map))
+                    continue;
+            }
+            else if (!(*it).map.empty())
+                continue;
+
+            (*it).refCnt++;
+            return (*it).id;
+        }
+    }
+
+    // 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++;
 }
 
 // ------------------------------------------------------------------------------------------------
-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)	{
-
-		if ((*it).id == which && (*it).loaded)	{
-
-			aiScene* sc = (*it).scene;
-			if (!(--(*it).refCnt))	{
-				data->requests.erase(it);
-			}
-			return sc;
-		}
-	}
-	return NULL;
+    for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
+
+        if ((*it).id == which && (*it).loaded)  {
+
+            aiScene* sc = (*it).scene;
+            if (!(--(*it).refCnt))  {
+                data->requests.erase(it);
+            }
+            return sc;
+        }
+    }
+    return NULL;
 }
 
 // ------------------------------------------------------------------------------------------------
 void BatchLoader::LoadAll()
 {
-	// no threaded implementation for the moment
-	for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it)	{
-		// force validation in debug builds
-		unsigned int pp = (*it).flags;
+    // no threaded implementation for the moment
+    for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
+        // force validation in debug builds
+        unsigned int pp = (*it).flags;
 #ifdef ASSIMP_BUILD_DEBUG
-		pp |= aiProcess_ValidateDataStructure;
+        pp |= aiProcess_ValidateDataStructure;
 #endif
-		// setup config properties if necessary
-		ImporterPimpl* pimpl = data->pImporter->Pimpl();
-		pimpl->mFloatProperties  = (*it).map.floats;
-		pimpl->mIntProperties    = (*it).map.ints;
-		pimpl->mStringProperties = (*it).map.strings;
-		pimpl->mMatrixProperties = (*it).map.matrices;
-
-		if (!DefaultLogger::isNullLogger())
-		{
-			DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
-			DefaultLogger::get()->info("File: " + (*it).file);
-		}
-		data->pImporter->ReadFile((*it).file,pp);
-		(*it).scene = data->pImporter->GetOrphanedScene();
-		(*it).loaded = true;
-
-		DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
-	}
-}
-
-
-
+        // setup config properties if necessary
+        ImporterPimpl* pimpl = data->pImporter->Pimpl();
+        pimpl->mFloatProperties  = (*it).map.floats;
+        pimpl->mIntProperties    = (*it).map.ints;
+        pimpl->mStringProperties = (*it).map.strings;
+        pimpl->mMatrixProperties = (*it).map.matrices;
+
+        if (!DefaultLogger::isNullLogger())
+        {
+            DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
+            DefaultLogger::get()->info("File: " + (*it).file);
+        }
+        data->pImporter->ReadFile((*it).file,pp);
+        (*it).scene = data->pImporter->GetOrphanedScene();
+        (*it).loaded = true;
 
+        DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
+    }
+}

+ 259 - 259
code/BaseImporter.h

@@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiScene;
 
-namespace Assimp	{
+namespace Assimp    {
 
 class Importer;
 class IOSystem;
@@ -64,32 +64,32 @@ class IOStream;
 
 // utility to do char4 to uint32 in a portable manner
 #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
-	(string[1] << 16) + (string[2] << 8) + string[3]))
+    (string[1] << 16) + (string[2] << 8) + string[3]))
 
 // ---------------------------------------------------------------------------
 template <typename T>
 struct ScopeGuard
 {
-	ScopeGuard(T* obj) : obj(obj), mdismiss() {}
-	~ScopeGuard () throw() {
-		if (!mdismiss) {
-			delete obj;
-		}
-		obj = NULL;
-	}
-
-	T* dismiss() {
-		mdismiss=true;
-		return obj;
-	}
-
-	operator T*() {
-		return obj;
-	}
-
-	T* operator -> () {
-		return obj;
-	}
+    ScopeGuard(T* obj) : obj(obj), mdismiss() {}
+    ~ScopeGuard () throw() {
+        if (!mdismiss) {
+            delete obj;
+        }
+        obj = NULL;
+    }
+
+    T* dismiss() {
+        mdismiss=true;
+        return obj;
+    }
+
+    operator T*() {
+        return obj;
+    }
+
+    T* operator -> () {
+        return obj;
+    }
 
 private:
     // no copying allowed.
@@ -97,8 +97,8 @@ private:
     ScopeGuard( const ScopeGuard & );
     ScopeGuard &operator = ( const ScopeGuard & );
 
-	T* obj;
-	bool mdismiss;
+    T* obj;
+    bool mdismiss;
 };
 
 
@@ -115,257 +115,257 @@ private:
  */
 class ASSIMP_API BaseImporter
 {
-	friend class Importer;
+    friend class Importer;
 
 public:
 
-	/** Constructor to be privately used by #Importer */
-	BaseImporter();
+    /** Constructor to be privately used by #Importer */
+    BaseImporter();
 
-	/** Destructor, private as well */
-	virtual ~BaseImporter();
+    /** Destructor, private as well */
+    virtual ~BaseImporter();
 
 public:
-	// -------------------------------------------------------------------
-	/** Returns whether the class can handle the format of the given file.
-	 *
-	 * The implementation should be as quick as possible. A check for
-	 * the file extension is enough. If no suitable loader is found with
-	 * this strategy, CanRead() is called again, the 'checkSig' parameter
-	 * set to true this time. Now the implementation is expected to
-	 * perform a full check of the file structure, possibly searching the
-	 * first bytes of the file for magic identifiers or keywords.
-	 *
-	 * @param pFile Path and file name of the file to be examined.
-	 * @param pIOHandler The IO handler to use for accessing any file.
-	 * @param checkSig Set to true if this method is called a second time.
-	 *   This time, the implementation may take more time to examine the
-	 *   contents of the file to be loaded for magic bytes, keywords, etc
-	 *   to be able to load files with unknown/not existent file extensions.
-	 * @return true if the class can read this file, false if not.
-	 */
-	virtual bool CanRead(
-		const std::string& pFile,
-		IOSystem* pIOHandler,
-		bool checkSig
-		) const = 0;
-
-	// -------------------------------------------------------------------
-	/** Imports the given file and returns the imported data.
-	 * If the import succeeds, ownership of the data is transferred to
-	 * the caller. If the import fails, NULL is returned. The function
-	 * takes care that any partially constructed data is destroyed
-	 * beforehand.
-	 *
-	 * @param pImp #Importer object hosting this loader.
-	 * @param pFile Path of the file to be imported.
-	 * @param pIOHandler IO-Handler used to open this and possible other files.
-	 * @return The imported data or NULL if failed. If it failed a
-	 * human-readable error description can be retrieved by calling
-	 * GetErrorText()
-	 *
-	 * @note This function is not intended to be overridden. Implement
-	 * InternReadFile() to do the import. If an exception is thrown somewhere
-	 * in InternReadFile(), this function will catch it and transform it into
-	 *  a suitable response to the caller.
-	 */
-	aiScene* ReadFile(
-		const Importer* pImp,
-		const std::string& pFile,
-		IOSystem* pIOHandler
-		);
-
-	// -------------------------------------------------------------------
-	/** Returns the error description of the last error that occured.
-	 * @return A description of the last error that occured. An empty
-	 * string if there was no error.
-	 */
-	const std::string& GetErrorText() const {
-		return mErrorText;
-	}
-
-	// -------------------------------------------------------------------
-	/** Called prior to ReadFile().
-	 * The function is a request to the importer to update its configuration
-	 * basing on the Importer's configuration property list.
-	 * @param pImp Importer instance
-	 */
-	virtual void SetupProperties(
-		const Importer* pImp
-		);
-
-
-	// -------------------------------------------------------------------
-	/** Called by #Importer::GetImporterInfo to get a description of
-	 *  some loader features. Importers must provide this information. */
-	virtual const aiImporterDesc* GetInfo() const = 0;
-
-
-
-	// -------------------------------------------------------------------
-	/** Called by #Importer::GetExtensionList for each loaded importer.
-	 *  Take the extension list contained in the structure returned by
-	 *  #GetInfo and insert all file extensions into the given set.
-	 *  @param extension set to collect file extensions in*/
-	void GetExtensionList(std::set<std::string>& extensions);
+    // -------------------------------------------------------------------
+    /** Returns whether the class can handle the format of the given file.
+     *
+     * The implementation should be as quick as possible. A check for
+     * the file extension is enough. If no suitable loader is found with
+     * this strategy, CanRead() is called again, the 'checkSig' parameter
+     * set to true this time. Now the implementation is expected to
+     * perform a full check of the file structure, possibly searching the
+     * first bytes of the file for magic identifiers or keywords.
+     *
+     * @param pFile Path and file name of the file to be examined.
+     * @param pIOHandler The IO handler to use for accessing any file.
+     * @param checkSig Set to true if this method is called a second time.
+     *   This time, the implementation may take more time to examine the
+     *   contents of the file to be loaded for magic bytes, keywords, etc
+     *   to be able to load files with unknown/not existent file extensions.
+     * @return true if the class can read this file, false if not.
+     */
+    virtual bool CanRead(
+        const std::string& pFile,
+        IOSystem* pIOHandler,
+        bool checkSig
+        ) const = 0;
+
+    // -------------------------------------------------------------------
+    /** Imports the given file and returns the imported data.
+     * If the import succeeds, ownership of the data is transferred to
+     * the caller. If the import fails, NULL is returned. The function
+     * takes care that any partially constructed data is destroyed
+     * beforehand.
+     *
+     * @param pImp #Importer object hosting this loader.
+     * @param pFile Path of the file to be imported.
+     * @param pIOHandler IO-Handler used to open this and possible other files.
+     * @return The imported data or NULL if failed. If it failed a
+     * human-readable error description can be retrieved by calling
+     * GetErrorText()
+     *
+     * @note This function is not intended to be overridden. Implement
+     * InternReadFile() to do the import. If an exception is thrown somewhere
+     * in InternReadFile(), this function will catch it and transform it into
+     *  a suitable response to the caller.
+     */
+    aiScene* ReadFile(
+        const Importer* pImp,
+        const std::string& pFile,
+        IOSystem* pIOHandler
+        );
+
+    // -------------------------------------------------------------------
+    /** Returns the error description of the last error that occured.
+     * @return A description of the last error that occured. An empty
+     * string if there was no error.
+     */
+    const std::string& GetErrorText() const {
+        return mErrorText;
+    }
+
+    // -------------------------------------------------------------------
+    /** Called prior to ReadFile().
+     * The function is a request to the importer to update its configuration
+     * basing on the Importer's configuration property list.
+     * @param pImp Importer instance
+     */
+    virtual void SetupProperties(
+        const Importer* pImp
+        );
+
+
+    // -------------------------------------------------------------------
+    /** Called by #Importer::GetImporterInfo to get a description of
+     *  some loader features. Importers must provide this information. */
+    virtual const aiImporterDesc* GetInfo() const = 0;
+
+
+
+    // -------------------------------------------------------------------
+    /** Called by #Importer::GetExtensionList for each loaded importer.
+     *  Take the extension list contained in the structure returned by
+     *  #GetInfo and insert all file extensions into the given set.
+     *  @param extension set to collect file extensions in*/
+    void GetExtensionList(std::set<std::string>& extensions);
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Imports the given file into the given scene structure. The
-	 * function is expected to throw an ImportErrorException if there is
-	 * an error. If it terminates normally, the data in aiScene is
-	 * expected to be correct. Override this function to implement the
-	 * actual importing.
-	 * <br>
-	 *  The output scene must meet the following requirements:<br>
-	 * <ul>
-	 * <li>At least a root node must be there, even if its only purpose
-	 *     is to reference one mesh.</li>
-	 * <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives
-	 *   in the mesh are determined automatically in this case.</li>
-	 * <li>the vertex data is stored in a pseudo-indexed "verbose" format.
-	 *   In fact this means that every vertex that is referenced by
-	 *   a face is unique. Or the other way round: a vertex index may
-	 *   not occur twice in a single aiMesh.</li>
-	 * <li>aiAnimation::mDuration may be -1. Assimp determines the length
-	 *   of the animation automatically in this case as the length of
-	 *   the longest animation channel.</li>
-	 * <li>aiMesh::mBitangents may be NULL if tangents and normals are
-	 *   given. In this case bitangents are computed as the cross product
-	 *   between normal and tangent.</li>
-	 * <li>There needn't be a material. If none is there a default material
-	 *   is generated. However, it is recommended practice for loaders
-	 *   to generate a default material for yourself that matches the
-	 *   default material setting for the file format better than Assimp's
-	 *   generic default material. Note that default materials *should*
-	 *   be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded
-	 *   or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy)
-	 *   texture. </li>
-	 * </ul>
-	 * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul>
-	 * <li> at least one mesh must be there</li>
-	 * <li> there may be no meshes with 0 vertices or faces</li>
-	 * </ul>
-	 * This won't be checked (except by the validation step): Assimp will
-	 * crash if one of the conditions is not met!
-	 *
-	 * @param pFile Path of the file to be imported.
-	 * @param pScene The scene object to hold the imported data.
-	 * NULL is not a valid parameter.
-	 * @param pIOHandler The IO handler to use for any file access.
-	 * NULL is not a valid parameter. */
-	virtual void InternReadFile(
-		const std::string& pFile,
-		aiScene* pScene,
-		IOSystem* pIOHandler
-		) = 0;
+    // -------------------------------------------------------------------
+    /** Imports the given file into the given scene structure. The
+     * function is expected to throw an ImportErrorException if there is
+     * an error. If it terminates normally, the data in aiScene is
+     * expected to be correct. Override this function to implement the
+     * actual importing.
+     * <br>
+     *  The output scene must meet the following requirements:<br>
+     * <ul>
+     * <li>At least a root node must be there, even if its only purpose
+     *     is to reference one mesh.</li>
+     * <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives
+     *   in the mesh are determined automatically in this case.</li>
+     * <li>the vertex data is stored in a pseudo-indexed "verbose" format.
+     *   In fact this means that every vertex that is referenced by
+     *   a face is unique. Or the other way round: a vertex index may
+     *   not occur twice in a single aiMesh.</li>
+     * <li>aiAnimation::mDuration may be -1. Assimp determines the length
+     *   of the animation automatically in this case as the length of
+     *   the longest animation channel.</li>
+     * <li>aiMesh::mBitangents may be NULL if tangents and normals are
+     *   given. In this case bitangents are computed as the cross product
+     *   between normal and tangent.</li>
+     * <li>There needn't be a material. If none is there a default material
+     *   is generated. However, it is recommended practice for loaders
+     *   to generate a default material for yourself that matches the
+     *   default material setting for the file format better than Assimp's
+     *   generic default material. Note that default materials *should*
+     *   be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded
+     *   or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy)
+     *   texture. </li>
+     * </ul>
+     * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul>
+     * <li> at least one mesh must be there</li>
+     * <li> there may be no meshes with 0 vertices or faces</li>
+     * </ul>
+     * This won't be checked (except by the validation step): Assimp will
+     * crash if one of the conditions is not met!
+     *
+     * @param pFile Path of the file to be imported.
+     * @param pScene The scene object to hold the imported data.
+     * NULL is not a valid parameter.
+     * @param pIOHandler The IO handler to use for any file access.
+     * NULL is not a valid parameter. */
+    virtual void InternReadFile(
+        const std::string& pFile,
+        aiScene* pScene,
+        IOSystem* pIOHandler
+        ) = 0;
 
 public: // static utilities
 
-	// -------------------------------------------------------------------
-	/** A utility for CanRead().
-	 *
-	 *  The function searches the header of a file for a specific token
-	 *  and returns true if this token is found. This works for text
-	 *  files only. There is a rudimentary handling of UNICODE files.
-	 *  The comparison is case independent.
-	 *
-	 *  @param pIOSystem IO System to work with
-	 *  @param file File name of the file
-	 *  @param tokens List of tokens to search for
-	 *  @param numTokens Size of the token array
-	 *  @param searchBytes Number of bytes to be searched for the tokens.
-	 */
-	static bool SearchFileHeaderForToken(
-		IOSystem* pIOSystem,
-		const std::string&	file,
-		const char** tokens,
-		unsigned int numTokens,
-		unsigned int searchBytes = 200,
-		bool tokensSol = false);
-
-	// -------------------------------------------------------------------
-	/** @brief Check whether a file has a specific file extension
-	 *  @param pFile Input file
-	 *  @param ext0 Extension to check for. Lowercase characters only, no dot!
-	 *  @param ext1 Optional second extension
-	 *  @param ext2 Optional third extension
-	 *  @note Case-insensitive
-	 */
-	static bool SimpleExtensionCheck (
-		const std::string& pFile,
-		const char* ext0,
-		const char* ext1 = NULL,
-		const char* ext2 = NULL);
-
-	// -------------------------------------------------------------------
-	/** @brief Extract file extension from a string
-	 *  @param pFile Input file
-	 *  @return Extension without trailing dot, all lowercase
-	 */
-	static std::string GetExtension (
-		const std::string& pFile);
-
-	// -------------------------------------------------------------------
-	/** @brief Check whether a file starts with one or more magic tokens
-	 *  @param pFile Input file
-	 *  @param pIOHandler IO system to be used
-	 *  @param magic n magic tokens
-	 *  @params num Size of magic
-	 *  @param offset Offset from file start where tokens are located
-	 *  @param Size of one token, in bytes. Maximally 16 bytes.
-	 *  @return true if one of the given tokens was found
-	 *
-	 *  @note For convinence, the check is also performed for the
-	 *  byte-swapped variant of all tokens (big endian). Only for
-	 *  tokens of size 2,4.
-	 */
-	static bool CheckMagicToken(
-		IOSystem* pIOHandler,
-		const std::string& pFile,
-		const void* magic,
-		unsigned int num,
-		unsigned int offset = 0,
-		unsigned int size   = 4);
-
-	// -------------------------------------------------------------------
-	/** An utility for all text file loaders. It converts a file to our
-	 *   UTF8 character set. Errors are reported, but ignored.
-	 *
-	 *  @param data File buffer to be converted to UTF8 data. The buffer
-	 *  is resized as appropriate. */
-	static void ConvertToUTF8(
-		std::vector<char>& data);
-
-	// -------------------------------------------------------------------
-	/** An utility for all text file loaders. It converts a file from our
-	 *   UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
-	 *
-	 *  @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
-	 *  is resized as appropriate. */
-	static void ConvertUTF8toISO8859_1(
-		std::string& data);
-
-	// -------------------------------------------------------------------
-	/** Utility for text file loaders which copies the contents of the
-	 *  file into a memory buffer and converts it to our UTF8
-	 *  representation.
-	 *  @param stream Stream to read from.
-	 *  @param data Output buffer to be resized and filled with the
-	 *   converted text file data. The buffer is terminated with
-	 *   a binary 0. */
-	static void TextFileToBuffer(
-		IOStream* stream,
-		std::vector<char>& data);
+    // -------------------------------------------------------------------
+    /** A utility for CanRead().
+     *
+     *  The function searches the header of a file for a specific token
+     *  and returns true if this token is found. This works for text
+     *  files only. There is a rudimentary handling of UNICODE files.
+     *  The comparison is case independent.
+     *
+     *  @param pIOSystem IO System to work with
+     *  @param file File name of the file
+     *  @param tokens List of tokens to search for
+     *  @param numTokens Size of the token array
+     *  @param searchBytes Number of bytes to be searched for the tokens.
+     */
+    static bool SearchFileHeaderForToken(
+        IOSystem* pIOSystem,
+        const std::string&  file,
+        const char** tokens,
+        unsigned int numTokens,
+        unsigned int searchBytes = 200,
+        bool tokensSol = false);
+
+    // -------------------------------------------------------------------
+    /** @brief Check whether a file has a specific file extension
+     *  @param pFile Input file
+     *  @param ext0 Extension to check for. Lowercase characters only, no dot!
+     *  @param ext1 Optional second extension
+     *  @param ext2 Optional third extension
+     *  @note Case-insensitive
+     */
+    static bool SimpleExtensionCheck (
+        const std::string& pFile,
+        const char* ext0,
+        const char* ext1 = NULL,
+        const char* ext2 = NULL);
+
+    // -------------------------------------------------------------------
+    /** @brief Extract file extension from a string
+     *  @param pFile Input file
+     *  @return Extension without trailing dot, all lowercase
+     */
+    static std::string GetExtension (
+        const std::string& pFile);
+
+    // -------------------------------------------------------------------
+    /** @brief Check whether a file starts with one or more magic tokens
+     *  @param pFile Input file
+     *  @param pIOHandler IO system to be used
+     *  @param magic n magic tokens
+     *  @params num Size of magic
+     *  @param offset Offset from file start where tokens are located
+     *  @param Size of one token, in bytes. Maximally 16 bytes.
+     *  @return true if one of the given tokens was found
+     *
+     *  @note For convinence, the check is also performed for the
+     *  byte-swapped variant of all tokens (big endian). Only for
+     *  tokens of size 2,4.
+     */
+    static bool CheckMagicToken(
+        IOSystem* pIOHandler,
+        const std::string& pFile,
+        const void* magic,
+        unsigned int num,
+        unsigned int offset = 0,
+        unsigned int size   = 4);
+
+    // -------------------------------------------------------------------
+    /** An utility for all text file loaders. It converts a file to our
+     *   UTF8 character set. Errors are reported, but ignored.
+     *
+     *  @param data File buffer to be converted to UTF8 data. The buffer
+     *  is resized as appropriate. */
+    static void ConvertToUTF8(
+        std::vector<char>& data);
+
+    // -------------------------------------------------------------------
+    /** An utility for all text file loaders. It converts a file from our
+     *   UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
+     *
+     *  @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
+     *  is resized as appropriate. */
+    static void ConvertUTF8toISO8859_1(
+        std::string& data);
+
+    // -------------------------------------------------------------------
+    /** Utility for text file loaders which copies the contents of the
+     *  file into a memory buffer and converts it to our UTF8
+     *  representation.
+     *  @param stream Stream to read from.
+     *  @param data Output buffer to be resized and filled with the
+     *   converted text file data. The buffer is terminated with
+     *   a binary 0. */
+    static void TextFileToBuffer(
+        IOStream* stream,
+        std::vector<char>& data);
 
 protected:
 
-	/** Error description in case there was one. */
-	std::string mErrorText;
+    /** Error description in case there was one. */
+    std::string mErrorText;
 
-	/** Currently set progress handler */
-	ProgressHandler* progress;
+    /** Currently set progress handler */
+    ProgressHandler* progress;
 };
 
 

+ 19 - 19
code/BaseProcess.cpp

@@ -61,45 +61,45 @@ BaseProcess::BaseProcess()
 // Destructor, private as well
 BaseProcess::~BaseProcess()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 void BaseProcess::ExecuteOnScene( Importer* pImp)
 {
-	ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene);
+    ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene);
 
-	progress = pImp->GetProgressHandler();
-	ai_assert(progress);
+    progress = pImp->GetProgressHandler();
+    ai_assert(progress);
 
-	SetupProperties( pImp );
+    SetupProperties( pImp );
 
-	// catch exceptions thrown inside the PostProcess-Step
-	try
-	{
-		Execute(pImp->Pimpl()->mScene);
+    // catch exceptions thrown inside the PostProcess-Step
+    try
+    {
+        Execute(pImp->Pimpl()->mScene);
 
-	} catch( const std::exception& err )	{
+    } catch( const std::exception& err )    {
 
-		// extract error description
-		pImp->Pimpl()->mErrorString = err.what();
-		DefaultLogger::get()->error(pImp->Pimpl()->mErrorString);
+        // extract error description
+        pImp->Pimpl()->mErrorString = err.what();
+        DefaultLogger::get()->error(pImp->Pimpl()->mErrorString);
 
-		// and kill the partially imported data
-		delete pImp->Pimpl()->mScene;
-		pImp->Pimpl()->mScene = NULL;
-	}
+        // and kill the partially imported data
+        delete pImp->Pimpl()->mScene;
+        pImp->Pimpl()->mScene = NULL;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BaseProcess::SetupProperties(const Importer* /*pImp*/)
 {
-	// the default implementation does nothing
+    // the default implementation does nothing
 }
 
 // ------------------------------------------------------------------------------------------------
 bool BaseProcess::RequireVerboseFormat() const
 {
-	return true;
+    return true;
 }
 

+ 172 - 172
code/BaseProcess.h

@@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiScene;
 
-namespace Assimp	{
+namespace Assimp    {
 
 class Importer;
 
@@ -64,121 +64,121 @@ class SharedPostProcessInfo
 {
 public:
 
-	struct Base
-	{
-		virtual ~Base()
-		{}
-	};
-
-	//! Represents data that is allocated on the heap, thus needs to be deleted
-	template <typename T>
-	struct THeapData : public Base
-	{
-		THeapData(T* in)
-			: data (in)
-		{}
-
-		~THeapData()
-		{
-			delete data;
-		}
-		T* data;
-	};
-
-	//! Represents static, by-value data not allocated on the heap
-	template <typename T>
-	struct TStaticData : public Base
-	{
-		TStaticData(T in)
-			: data (in)
-		{}
-
-		~TStaticData()
-		{}
-
-		T data;
-	};
-
-	// some typedefs for cleaner code
-	typedef unsigned int KeyType;
-	typedef std::map<KeyType, Base*>  PropertyMap;
+    struct Base
+    {
+        virtual ~Base()
+        {}
+    };
+
+    //! Represents data that is allocated on the heap, thus needs to be deleted
+    template <typename T>
+    struct THeapData : public Base
+    {
+        THeapData(T* in)
+            : data (in)
+        {}
+
+        ~THeapData()
+        {
+            delete data;
+        }
+        T* data;
+    };
+
+    //! Represents static, by-value data not allocated on the heap
+    template <typename T>
+    struct TStaticData : public Base
+    {
+        TStaticData(T in)
+            : data (in)
+        {}
+
+        ~TStaticData()
+        {}
+
+        T data;
+    };
+
+    // some typedefs for cleaner code
+    typedef unsigned int KeyType;
+    typedef std::map<KeyType, Base*>  PropertyMap;
 
 public:
 
-	//! Destructor
-	~SharedPostProcessInfo()
-	{
-		Clean();
-	}
-
-	//! Remove all stored properties from the table
-	void Clean()
-	{
-		// invoke the virtual destructor for all stored properties
-		for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
-			 it != end; ++it)
-		{
-			delete (*it).second;
-		}
-		pmap.clear();
-	}
-
-	//! Add a heap property to the list
-	template <typename T>
-	void AddProperty( const char* name, T* in ){
-		AddProperty(name,(Base*)new THeapData<T>(in));
-	}
-
-	//! Add a static by-value property to the list
-	template <typename T>
-	void AddProperty( const char* name, T in ){
-		AddProperty(name,(Base*)new TStaticData<T>(in));
-	}
-
-
-	//! Get a heap property
-	template <typename T>
-	bool GetProperty( const char* name, T*& out ) const
-	{
-		THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
-		if(!t)
-		{
-			out = NULL;
-			return false;
-		}
-		out = t->data;
-		return true;
-	}
-
-	//! Get a static, by-value property
-	template <typename T>
-	bool GetProperty( const char* name, T& out ) const
-	{
-		TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
-		if(!t)return false;
-		out = t->data;
-		return true;
-	}
-
-	//! Remove a property of a specific type
-	void RemoveProperty( const char* name)	{
-		SetGenericPropertyPtr<Base>(pmap,name,NULL);
-	}
+    //! Destructor
+    ~SharedPostProcessInfo()
+    {
+        Clean();
+    }
+
+    //! Remove all stored properties from the table
+    void Clean()
+    {
+        // invoke the virtual destructor for all stored properties
+        for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
+             it != end; ++it)
+        {
+            delete (*it).second;
+        }
+        pmap.clear();
+    }
+
+    //! Add a heap property to the list
+    template <typename T>
+    void AddProperty( const char* name, T* in ){
+        AddProperty(name,(Base*)new THeapData<T>(in));
+    }
+
+    //! Add a static by-value property to the list
+    template <typename T>
+    void AddProperty( const char* name, T in ){
+        AddProperty(name,(Base*)new TStaticData<T>(in));
+    }
+
+
+    //! Get a heap property
+    template <typename T>
+    bool GetProperty( const char* name, T*& out ) const
+    {
+        THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
+        if(!t)
+        {
+            out = NULL;
+            return false;
+        }
+        out = t->data;
+        return true;
+    }
+
+    //! Get a static, by-value property
+    template <typename T>
+    bool GetProperty( const char* name, T& out ) const
+    {
+        TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
+        if(!t)return false;
+        out = t->data;
+        return true;
+    }
+
+    //! Remove a property of a specific type
+    void RemoveProperty( const char* name)  {
+        SetGenericPropertyPtr<Base>(pmap,name,NULL);
+    }
 
 private:
 
-	void AddProperty( const char* name, Base* data)	{
-		SetGenericPropertyPtr<Base>(pmap,name,data);
-	}
+    void AddProperty( const char* name, Base* data) {
+        SetGenericPropertyPtr<Base>(pmap,name,data);
+    }
 
-	Base* GetPropertyInternal( const char* name) const	{
-		return GetGenericProperty<Base*>(pmap,name,NULL);
-	}
+    Base* GetPropertyInternal( const char* name) const  {
+        return GetGenericProperty<Base*>(pmap,name,NULL);
+    }
 
 private:
 
-	//! Map of all stored properties
-	PropertyMap pmap;
+    //! Map of all stored properties
+    PropertyMap pmap;
 };
 
 #if 0
@@ -190,10 +190,10 @@ private:
  */
  struct PPDependencyTable
  {
-	 unsigned int execute_me_before_these;
-	 unsigned int execute_me_after_these;
-	 unsigned int only_if_these_are_not_specified;
-	 unsigned int mutually_exclusive_with;
+     unsigned int execute_me_before_these;
+     unsigned int execute_me_after_these;
+     unsigned int only_if_these_are_not_specified;
+     unsigned int mutually_exclusive_with;
  };
 
 #endif
@@ -213,79 +213,79 @@ private:
  */
 class ASSIMP_API_WINONLY BaseProcess
 {
-	friend class Importer;
+    friend class Importer;
 
 public:
 
-	/** Constructor to be privately used by Importer */
-	BaseProcess();
+    /** Constructor to be privately used by Importer */
+    BaseProcess();
 
-	/** Destructor, private as well */
-	virtual ~BaseProcess();
+    /** Destructor, private as well */
+    virtual ~BaseProcess();
 
 public:
 
-	// -------------------------------------------------------------------
-	/** Returns whether the processing step is present in the given flag.
-	 * @param pFlags The processing flags the importer was called with. A
-	 *   bitwise combination of #aiPostProcessSteps.
-	 * @return true if the process is present in this flag fields,
-	 *   false if not.
-	*/
-	virtual bool IsActive( unsigned int pFlags) const = 0;
-
-	// -------------------------------------------------------------------
-	/** Check whether this step expects its input vertex data to be
-	 *  in verbose format. */
-	virtual bool RequireVerboseFormat() const;
-
-	// -------------------------------------------------------------------
-	/** Executes the post processing step on the given imported data.
-	* The function deletes the scene if the postprocess step fails (
-	* the object pointer will be set to NULL).
-	* @param pImp Importer instance (pImp->mScene must be valid)
-	*/
-	void ExecuteOnScene( Importer* pImp);
-
-	// -------------------------------------------------------------------
-	/** Called prior to ExecuteOnScene().
-	* The function is a request to the process to update its configuration
-	* basing on the Importer's configuration property list.
-	*/
-	virtual void SetupProperties(const Importer* pImp);
-
-	// -------------------------------------------------------------------
-	/** Executes the post processing step on the given imported data.
-	* A process should throw an ImportErrorException* if it fails.
-	* This method must be implemented by deriving classes.
-	* @param pScene The imported data to work at.
-	*/
-	virtual void Execute( aiScene* pScene) = 0;
-
-
-	// -------------------------------------------------------------------
-	/** Assign a new SharedPostProcessInfo to the step. This object
-	 *  allows multiple postprocess steps to share data.
-	 * @param sh May be NULL
-	*/
-	inline void SetSharedData(SharedPostProcessInfo* sh)	{
-		shared = sh;
-	}
-
-	// -------------------------------------------------------------------
-	/** Get the shared data that is assigned to the step.
-	*/
-	inline SharedPostProcessInfo* GetSharedData()	{
-		return shared;
-	}
+    // -------------------------------------------------------------------
+    /** Returns whether the processing step is present in the given flag.
+     * @param pFlags The processing flags the importer was called with. A
+     *   bitwise combination of #aiPostProcessSteps.
+     * @return true if the process is present in this flag fields,
+     *   false if not.
+    */
+    virtual bool IsActive( unsigned int pFlags) const = 0;
+
+    // -------------------------------------------------------------------
+    /** Check whether this step expects its input vertex data to be
+     *  in verbose format. */
+    virtual bool RequireVerboseFormat() const;
+
+    // -------------------------------------------------------------------
+    /** Executes the post processing step on the given imported data.
+    * The function deletes the scene if the postprocess step fails (
+    * the object pointer will be set to NULL).
+    * @param pImp Importer instance (pImp->mScene must be valid)
+    */
+    void ExecuteOnScene( Importer* pImp);
+
+    // -------------------------------------------------------------------
+    /** Called prior to ExecuteOnScene().
+    * The function is a request to the process to update its configuration
+    * basing on the Importer's configuration property list.
+    */
+    virtual void SetupProperties(const Importer* pImp);
+
+    // -------------------------------------------------------------------
+    /** Executes the post processing step on the given imported data.
+    * A process should throw an ImportErrorException* if it fails.
+    * This method must be implemented by deriving classes.
+    * @param pScene The imported data to work at.
+    */
+    virtual void Execute( aiScene* pScene) = 0;
+
+
+    // -------------------------------------------------------------------
+    /** Assign a new SharedPostProcessInfo to the step. This object
+     *  allows multiple postprocess steps to share data.
+     * @param sh May be NULL
+    */
+    inline void SetSharedData(SharedPostProcessInfo* sh)    {
+        shared = sh;
+    }
+
+    // -------------------------------------------------------------------
+    /** Get the shared data that is assigned to the step.
+    */
+    inline SharedPostProcessInfo* GetSharedData()   {
+        return shared;
+    }
 
 protected:
 
-	/** See the doc of #SharedPostProcessInfo for more details */
-	SharedPostProcessInfo* shared;
+    /** See the doc of #SharedPostProcessInfo for more details */
+    SharedPostProcessInfo* shared;
 
-	/** Currently active progress handler */
-	ProgressHandler* progress;
+    /** Currently active progress handler */
+    ProgressHandler* progress;
 };
 
 

+ 90 - 90
code/Bitmap.cpp

@@ -53,95 +53,95 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 
-	void Bitmap::Save(aiTexture* texture, IOStream* file) {
-		if(file != NULL) {
-			Header header;
-			DIB dib;
-
-			dib.size = DIB::dib_size;
-			dib.width = texture->mWidth;
-			dib.height = texture->mHeight;
-			dib.planes = 1;
-			dib.bits_per_pixel = 8 * mBytesPerPixel;
-			dib.compression = 0;
-			dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
-			dib.x_resolution = 0;
-			dib.y_resolution = 0;
-			dib.nb_colors = 0;
-			dib.nb_important_colors = 0;
-
-			header.type = 0x4D42; // 'BM'
-			header.offset = Header::header_size + DIB::dib_size;
-			header.size = header.offset + dib.image_size;
-			header.reserved1 = 0;
-			header.reserved2 = 0;
-
-			WriteHeader(header, file);
-			WriteDIB(dib, file);
-			WriteData(texture, file);
-		}
-	}
-
-	template<typename T>
-	inline std::size_t Copy(uint8_t* data, T& field) {
-		std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
-	}
-
-	void Bitmap::WriteHeader(Header& header, IOStream* file) {
-		uint8_t data[Header::header_size];
-
-		std::size_t offset = 0;
-
-		offset += Copy(&data[offset], header.type);
-		offset += Copy(&data[offset], header.size);
-		offset += Copy(&data[offset], header.reserved1);
-		offset += Copy(&data[offset], header.reserved2);
-		offset += Copy(&data[offset], header.offset);
-
-		file->Write(data, Header::header_size, 1);
-	}
-
-	void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
-		uint8_t data[DIB::dib_size];
-
-		std::size_t offset = 0;
-
-		offset += Copy(&data[offset], dib.size);
-		offset += Copy(&data[offset], dib.width);
-		offset += Copy(&data[offset], dib.height);
-		offset += Copy(&data[offset], dib.planes);
-		offset += Copy(&data[offset], dib.bits_per_pixel);
-		offset += Copy(&data[offset], dib.compression);
-		offset += Copy(&data[offset], dib.image_size);
-		offset += Copy(&data[offset], dib.x_resolution);
-		offset += Copy(&data[offset], dib.y_resolution);
-		offset += Copy(&data[offset], dib.nb_colors);
-		offset += Copy(&data[offset], dib.nb_important_colors);
-
-		file->Write(data, DIB::dib_size, 1);
-	}
-
-	void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
-		static const std::size_t padding_offset = 4;
-		static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
-
-		unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
-		uint8_t pixel[mBytesPerPixel];
-
-		for(std::size_t i = 0; i < texture->mHeight; ++i) {
-			for(std::size_t j = 0; j < texture->mWidth; ++j) {
-				const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
-
-				pixel[0] = texel.r;
-				pixel[1] = texel.g;
-				pixel[2] = texel.b;
-				pixel[3] = texel.a;
-
-				file->Write(pixel, mBytesPerPixel, 1);
-			}
-
-			file->Write(padding_data, padding, 1);
-		}
-	}
+    void Bitmap::Save(aiTexture* texture, IOStream* file) {
+        if(file != NULL) {
+            Header header;
+            DIB dib;
+
+            dib.size = DIB::dib_size;
+            dib.width = texture->mWidth;
+            dib.height = texture->mHeight;
+            dib.planes = 1;
+            dib.bits_per_pixel = 8 * mBytesPerPixel;
+            dib.compression = 0;
+            dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
+            dib.x_resolution = 0;
+            dib.y_resolution = 0;
+            dib.nb_colors = 0;
+            dib.nb_important_colors = 0;
+
+            header.type = 0x4D42; // 'BM'
+            header.offset = Header::header_size + DIB::dib_size;
+            header.size = header.offset + dib.image_size;
+            header.reserved1 = 0;
+            header.reserved2 = 0;
+
+            WriteHeader(header, file);
+            WriteDIB(dib, file);
+            WriteData(texture, file);
+        }
+    }
+
+    template<typename T>
+    inline std::size_t Copy(uint8_t* data, T& field) {
+        std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
+    }
+
+    void Bitmap::WriteHeader(Header& header, IOStream* file) {
+        uint8_t data[Header::header_size];
+
+        std::size_t offset = 0;
+
+        offset += Copy(&data[offset], header.type);
+        offset += Copy(&data[offset], header.size);
+        offset += Copy(&data[offset], header.reserved1);
+        offset += Copy(&data[offset], header.reserved2);
+        offset += Copy(&data[offset], header.offset);
+
+        file->Write(data, Header::header_size, 1);
+    }
+
+    void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
+        uint8_t data[DIB::dib_size];
+
+        std::size_t offset = 0;
+
+        offset += Copy(&data[offset], dib.size);
+        offset += Copy(&data[offset], dib.width);
+        offset += Copy(&data[offset], dib.height);
+        offset += Copy(&data[offset], dib.planes);
+        offset += Copy(&data[offset], dib.bits_per_pixel);
+        offset += Copy(&data[offset], dib.compression);
+        offset += Copy(&data[offset], dib.image_size);
+        offset += Copy(&data[offset], dib.x_resolution);
+        offset += Copy(&data[offset], dib.y_resolution);
+        offset += Copy(&data[offset], dib.nb_colors);
+        offset += Copy(&data[offset], dib.nb_important_colors);
+
+        file->Write(data, DIB::dib_size, 1);
+    }
+
+    void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
+        static const std::size_t padding_offset = 4;
+        static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
+
+        unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
+        uint8_t pixel[mBytesPerPixel];
+
+        for(std::size_t i = 0; i < texture->mHeight; ++i) {
+            for(std::size_t j = 0; j < texture->mWidth; ++j) {
+                const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
+
+                pixel[0] = texel.r;
+                pixel[1] = texel.g;
+                pixel[2] = texel.b;
+                pixel[3] = texel.a;
+
+                file->Write(pixel, mBytesPerPixel, 1);
+            }
+
+            file->Write(padding_data, padding, 1);
+        }
+    }
 
 }

+ 50 - 50
code/Bitmap.h

@@ -57,85 +57,85 @@ namespace Assimp {
 class IOStream;
 class Bitmap {
 
-	protected:
+    protected:
 
-		struct Header {
+        struct Header {
 
-			uint16_t type;
+            uint16_t type;
 
-			uint32_t size;
+            uint32_t size;
 
-			uint16_t reserved1;
+            uint16_t reserved1;
 
-			uint16_t reserved2;
+            uint16_t reserved2;
 
-			uint32_t offset;
+            uint32_t offset;
 
-			// We define the struct size because sizeof(Header) might return a wrong result because of structure padding.
-			// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
-			static const std::size_t header_size =
-				sizeof(uint16_t) + // type
-				sizeof(uint32_t) + // size
-				sizeof(uint16_t) + // reserved1
-				sizeof(uint16_t) + // reserved2
-				sizeof(uint32_t);  // offset
+            // We define the struct size because sizeof(Header) might return a wrong result because of structure padding.
+            // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
+            static const std::size_t header_size =
+                sizeof(uint16_t) + // type
+                sizeof(uint32_t) + // size
+                sizeof(uint16_t) + // reserved1
+                sizeof(uint16_t) + // reserved2
+                sizeof(uint32_t);  // offset
 
-		};
+        };
 
-		struct DIB {
+        struct DIB {
 
-			uint32_t size;
+            uint32_t size;
 
-			int32_t width;
+            int32_t width;
 
-			int32_t height;
+            int32_t height;
 
-			uint16_t planes;
+            uint16_t planes;
 
-			uint16_t bits_per_pixel;
+            uint16_t bits_per_pixel;
 
-			uint32_t compression;
+            uint32_t compression;
 
-			uint32_t image_size;
+            uint32_t image_size;
 
-			int32_t x_resolution;
+            int32_t x_resolution;
 
-			int32_t y_resolution;
+            int32_t y_resolution;
 
-			uint32_t nb_colors;
+            uint32_t nb_colors;
 
-			uint32_t nb_important_colors;
+            uint32_t nb_important_colors;
 
-			// We define the struct size because sizeof(DIB) might return a wrong result because of structure padding.
-			// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
-			static const std::size_t dib_size =
-				sizeof(uint32_t) + // size
-				sizeof(int32_t) +  // width
-				sizeof(int32_t) +  // height
-				sizeof(uint16_t) + // planes
-				sizeof(uint16_t) + // bits_per_pixel
-				sizeof(uint32_t) + // compression
-				sizeof(uint32_t) + // image_size
-				sizeof(int32_t) +  // x_resolution
-				sizeof(int32_t) +  // y_resolution
-				sizeof(uint32_t) + // nb_colors
-				sizeof(uint32_t);  // nb_important_colors
+            // We define the struct size because sizeof(DIB) might return a wrong result because of structure padding.
+            // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
+            static const std::size_t dib_size =
+                sizeof(uint32_t) + // size
+                sizeof(int32_t) +  // width
+                sizeof(int32_t) +  // height
+                sizeof(uint16_t) + // planes
+                sizeof(uint16_t) + // bits_per_pixel
+                sizeof(uint32_t) + // compression
+                sizeof(uint32_t) + // image_size
+                sizeof(int32_t) +  // x_resolution
+                sizeof(int32_t) +  // y_resolution
+                sizeof(uint32_t) + // nb_colors
+                sizeof(uint32_t);  // nb_important_colors
 
-		};
+        };
 
-		static const std::size_t mBytesPerPixel = 4;
+        static const std::size_t mBytesPerPixel = 4;
 
-	public:
+    public:
 
-		static void Save(aiTexture* texture, IOStream* file);
+        static void Save(aiTexture* texture, IOStream* file);
 
-	protected:
+    protected:
 
-		static void WriteHeader(Header& header, IOStream* file);
+        static void WriteHeader(Header& header, IOStream* file);
 
-		static void WriteDIB(DIB& dib, IOStream* file);
+        static void WriteDIB(DIB& dib, IOStream* file);
 
-		static void WriteData(aiTexture* texture, IOStream* file);
+        static void WriteData(aiTexture* texture, IOStream* file);
 
 };
 

+ 79 - 79
code/BlenderBMesh.cpp

@@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp
 {
-	template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: ";
+    template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: ";
 }
 
 using namespace Assimp;
@@ -61,142 +61,142 @@ using namespace Assimp::Formatter;
 
 // ------------------------------------------------------------------------------------------------
 BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
-	BMesh( mesh ),
-	triMesh( NULL )
+    BMesh( mesh ),
+    triMesh( NULL )
 {
 }
 
 // ------------------------------------------------------------------------------------------------
 BlenderBMeshConverter::~BlenderBMeshConverter( )
 {
-	DestroyTriMesh( );
+    DestroyTriMesh( );
 }
 
 // ------------------------------------------------------------------------------------------------
 bool BlenderBMeshConverter::ContainsBMesh( ) const
 {
-	// TODO - Should probably do some additional verification here
-	return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
+    // TODO - Should probably do some additional verification here
+    return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
 }
 
 // ------------------------------------------------------------------------------------------------
 const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
 {
-	AssertValidMesh( );
-	AssertValidSizes( );
-	PrepareTriMesh( );
+    AssertValidMesh( );
+    AssertValidSizes( );
+    PrepareTriMesh( );
 
-	for ( int i = 0; i < BMesh->totpoly; ++i )
-	{
-		const MPoly& poly = BMesh->mpoly[ i ];
-		ConvertPolyToFaces( poly );
-	}
+    for ( int i = 0; i < BMesh->totpoly; ++i )
+    {
+        const MPoly& poly = BMesh->mpoly[ i ];
+        ConvertPolyToFaces( poly );
+    }
 
-	return triMesh;
+    return triMesh;
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::AssertValidMesh( )
 {
-	if ( !ContainsBMesh( ) )
-	{
-		ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
-	}
+    if ( !ContainsBMesh( ) )
+    {
+        ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::AssertValidSizes( )
 {
-	if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
-	{
-		ThrowException( "BMesh poly array has incorrect size" );
-	}
-	if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
-	{
-		ThrowException( "BMesh loop array has incorrect size" );
-	}
+    if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
+    {
+        ThrowException( "BMesh poly array has incorrect size" );
+    }
+    if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
+    {
+        ThrowException( "BMesh loop array has incorrect size" );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::PrepareTriMesh( )
 {
-	if ( triMesh )
-	{
-		DestroyTriMesh( );
-	}
-
-	triMesh = new Mesh( *BMesh );
-	triMesh->totface = 0;
-	triMesh->mface.clear( );
+    if ( triMesh )
+    {
+        DestroyTriMesh( );
+    }
+
+    triMesh = new Mesh( *BMesh );
+    triMesh->totface = 0;
+    triMesh->mface.clear( );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::DestroyTriMesh( )
 {
-	delete triMesh;
-	triMesh = NULL;
+    delete triMesh;
+    triMesh = NULL;
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
 {
-	const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
-
-	if ( poly.totloop == 3 || poly.totloop == 4 )
-	{
-		AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
-
-		// UVs are optional, so only convert when present.
-		if ( BMesh->mloopuv.size() )
-		{
-			if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
-			{
-				ThrowException( "BMesh uv loop array has incorrect size" );
-			}
-			const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
-			AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
-		}
-	}
-	else if ( poly.totloop > 4 )
-	{
+    const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
+
+    if ( poly.totloop == 3 || poly.totloop == 4 )
+    {
+        AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
+
+        // UVs are optional, so only convert when present.
+        if ( BMesh->mloopuv.size() )
+        {
+            if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
+            {
+                ThrowException( "BMesh uv loop array has incorrect size" );
+            }
+            const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
+            AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
+        }
+    }
+    else if ( poly.totloop > 4 )
+    {
 #if ASSIMP_BLEND_WITH_GLU_TESSELLATE
-		BlenderTessellatorGL tessGL( *this );
-		tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
+        BlenderTessellatorGL tessGL( *this );
+        tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
 #elif ASSIMP_BLEND_WITH_POLY_2_TRI
-		BlenderTessellatorP2T tessP2T( *this );
-		tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
+        BlenderTessellatorP2T tessP2T( *this );
+        tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
 #endif
-	}
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
 {
-	MFace face;
-	face.v1 = v1;
-	face.v2 = v2;
-	face.v3 = v3;
-	face.v4 = v4;
-	// TODO - Work out how materials work
-	face.mat_nr = 0;
-	triMesh->mface.push_back( face );
-	triMesh->totface = triMesh->mface.size( );
+    MFace face;
+    face.v1 = v1;
+    face.v2 = v2;
+    face.v3 = v3;
+    face.v4 = v4;
+    // TODO - Work out how materials work
+    face.mat_nr = 0;
+    triMesh->mface.push_back( face );
+    triMesh->totface = triMesh->mface.size( );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
 {
-	MTFace mtface;
-	memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
-	memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
-	memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
+    MTFace mtface;
+    memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
+    memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
+    memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
 
-	if ( uv4 )
-	{
-		memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
-	}
+    if ( uv4 )
+    {
+        memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
+    }
 
-	triMesh->mtface.push_back( mtface );
+    triMesh->mtface.push_back( mtface );
 }
 
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 40 - 40
code/BlenderBMesh.h

@@ -48,46 +48,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp
 {
-	// TinyFormatter.h
-	namespace Formatter
-	{
-		template < typename T,typename TR, typename A > class basic_formatter;
-		typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
-	}
-
-	// BlenderScene.h
-	namespace Blender
-	{
-		struct Mesh;
-		struct MPoly;
-		struct MLoop;
-	}
-
-	class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter >
-	{
-	public:
-		BlenderBMeshConverter( const Blender::Mesh* mesh );
-		~BlenderBMeshConverter( );
-
-		bool ContainsBMesh( ) const;
-
-		const Blender::Mesh* TriangulateBMesh( );
-
-	private:
-		void AssertValidMesh( );
-		void AssertValidSizes( );
-		void PrepareTriMesh( );
-		void DestroyTriMesh( );
-		void ConvertPolyToFaces( const Blender::MPoly& poly );
-		void AddFace( int v1, int v2, int v3, int v4 = 0 );
-		void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 );
-
-		const Blender::Mesh* BMesh;
-		Blender::Mesh* triMesh;
-
-		friend class BlenderTessellatorGL;
-		friend class BlenderTessellatorP2T;
-	};
+    // TinyFormatter.h
+    namespace Formatter
+    {
+        template < typename T,typename TR, typename A > class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
+    }
+
+    // BlenderScene.h
+    namespace Blender
+    {
+        struct Mesh;
+        struct MPoly;
+        struct MLoop;
+    }
+
+    class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter >
+    {
+    public:
+        BlenderBMeshConverter( const Blender::Mesh* mesh );
+        ~BlenderBMeshConverter( );
+
+        bool ContainsBMesh( ) const;
+
+        const Blender::Mesh* TriangulateBMesh( );
+
+    private:
+        void AssertValidMesh( );
+        void AssertValidSizes( );
+        void PrepareTriMesh( );
+        void DestroyTriMesh( );
+        void ConvertPolyToFaces( const Blender::MPoly& poly );
+        void AddFace( int v1, int v2, int v3, int v4 = 0 );
+        void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 );
+
+        const Blender::Mesh* BMesh;
+        Blender::Mesh* triMesh;
+
+        friend class BlenderTessellatorGL;
+        friend class BlenderTessellatorP2T;
+    };
 
 } // end of namespace Assimp
 

+ 241 - 241
code/BlenderDNA.cpp

@@ -56,168 +56,168 @@ using namespace Assimp::Formatter;
 
 #define for_each BOOST_FOREACH
 bool match4(StreamReaderAny& stream, const char* string) {
-	char tmp[] = {
-		(stream).GetI1(),
-		(stream).GetI1(),
-		(stream).GetI1(),
-		(stream).GetI1()
-	};
-	return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
+    char tmp[] = {
+        (stream).GetI1(),
+        (stream).GetI1(),
+        (stream).GetI1(),
+        (stream).GetI1()
+    };
+    return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
 }
 
 struct Type {
-	size_t size;
-	std::string name;
+    size_t size;
+    std::string name;
 };
 
 // ------------------------------------------------------------------------------------------------
 void DNAParser :: Parse ()
 {
-	StreamReaderAny& stream = *db.reader.get();
-	DNA& dna = db.dna;
-
-	if(!match4(stream,"SDNA")) {
-		throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
-	}
-
-	// name dictionary
-	if(!match4(stream,"NAME")) {
-		throw DeadlyImportError("BlenderDNA: Expected NAME field");
-	}
-
-	std::vector<std::string> names (stream.GetI4());
-	for_each(std::string& s, names) {
-		while (char c = stream.GetI1()) {
-			s += c;
-		}
-	}
-
-	// type dictionary
-	for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
-	if(!match4(stream,"TYPE")) {
-		throw DeadlyImportError("BlenderDNA: Expected TYPE field");
-	}
-
-	std::vector<Type> types (stream.GetI4());
-	for_each(Type& s, types) {
-		while (char c = stream.GetI1()) {
-			s.name += c;
-		}
-	}
-
-	// type length dictionary
-	for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
-	if(!match4(stream,"TLEN")) {
-		throw DeadlyImportError("BlenderDNA: Expected TLEN field");
-	}
-
-	for_each(Type& s, types) {
-		s.size = stream.GetI2();
-	}
-
-	// structures dictionary
-	for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
-	if(!match4(stream,"STRC")) {
-		throw DeadlyImportError("BlenderDNA: Expected STRC field");
-	}
-
-	size_t end = stream.GetI4(), fields = 0;
-
-	dna.structures.reserve(end);
-	for(size_t i = 0; i != end; ++i) {
-
-		uint16_t n = stream.GetI2();
-		if (n >= types.size()) {
-			throw DeadlyImportError((format(),
-				"BlenderDNA: Invalid type index in structure name" ,n,
-				" (there are only ", types.size(), " entries)"
-			));
-		}
-
-		// maintain separate indexes
-		dna.indices[types[n].name] = dna.structures.size();
-
-		dna.structures.push_back(Structure());
-		Structure& s = dna.structures.back();
-		s.name  = types[n].name;
-		//s.index = dna.structures.size()-1;
-
-		n = stream.GetI2();
-		s.fields.reserve(n);
-
-		size_t offset = 0;
-		for (size_t m = 0; m < n; ++m, ++fields) {
-
-			uint16_t j = stream.GetI2();
-			if (j >= types.size()) {
-				throw DeadlyImportError((format(),
-					"BlenderDNA: Invalid type index in structure field ", j,
-					" (there are only ", types.size(), " entries)"
-				));
-			}
-			s.fields.push_back(Field());
-			Field& f = s.fields.back();
-			f.offset = offset;
-
-			f.type = types[j].name;
-			f.size = types[j].size;
-
-			j = stream.GetI2();
-			if (j >= names.size()) {
-				throw DeadlyImportError((format(),
-					"BlenderDNA: Invalid name index in structure field ", j,
-					" (there are only ", names.size(), " entries)"
-				));
-			}
-
-			f.name = names[j];
-			f.flags = 0u;
-
-			// pointers always specify the size of the pointee instead of their own.
-			// The pointer asterisk remains a property of the lookup name.
-			if (f.name[0] == '*') {
-				f.size = db.i64bit ? 8 : 4;
-				f.flags |= FieldFlag_Pointer;
-			}
-
-			// arrays, however, specify the size of a single element so we
-			// need to parse the (possibly multi-dimensional) array declaration
-			// in order to obtain the actual size of the array in the file.
-			// Also we need to alter the lookup name to include no array
-			// brackets anymore or size fixup won't work (if our size does
-			// not match the size read from the DNA).
-			if (*f.name.rbegin() == ']') {
-				const std::string::size_type rb = f.name.find('[');
-				if (rb == std::string::npos) {
-					throw DeadlyImportError((format(),
-						"BlenderDNA: Encountered invalid array declaration ",
-						f.name
-					));
-				}
-
-				f.flags |= FieldFlag_Array;
-				DNA::ExtractArraySize(f.name,f.array_sizes);
-				f.name = f.name.substr(0,rb);
-
-				f.size *= f.array_sizes[0] * f.array_sizes[1];
-			}
-
-			// maintain separate indexes
-			s.indices[f.name] = s.fields.size()-1;
-			offset += f.size;
-		}
-		s.size = offset;
-	}
-
-	DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
-		" structures with totally ",fields," fields"));
+    StreamReaderAny& stream = *db.reader.get();
+    DNA& dna = db.dna;
+
+    if(!match4(stream,"SDNA")) {
+        throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
+    }
+
+    // name dictionary
+    if(!match4(stream,"NAME")) {
+        throw DeadlyImportError("BlenderDNA: Expected NAME field");
+    }
+
+    std::vector<std::string> names (stream.GetI4());
+    for_each(std::string& s, names) {
+        while (char c = stream.GetI1()) {
+            s += c;
+        }
+    }
+
+    // type dictionary
+    for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
+    if(!match4(stream,"TYPE")) {
+        throw DeadlyImportError("BlenderDNA: Expected TYPE field");
+    }
+
+    std::vector<Type> types (stream.GetI4());
+    for_each(Type& s, types) {
+        while (char c = stream.GetI1()) {
+            s.name += c;
+        }
+    }
+
+    // type length dictionary
+    for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
+    if(!match4(stream,"TLEN")) {
+        throw DeadlyImportError("BlenderDNA: Expected TLEN field");
+    }
+
+    for_each(Type& s, types) {
+        s.size = stream.GetI2();
+    }
+
+    // structures dictionary
+    for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
+    if(!match4(stream,"STRC")) {
+        throw DeadlyImportError("BlenderDNA: Expected STRC field");
+    }
+
+    size_t end = stream.GetI4(), fields = 0;
+
+    dna.structures.reserve(end);
+    for(size_t i = 0; i != end; ++i) {
+
+        uint16_t n = stream.GetI2();
+        if (n >= types.size()) {
+            throw DeadlyImportError((format(),
+                "BlenderDNA: Invalid type index in structure name" ,n,
+                " (there are only ", types.size(), " entries)"
+            ));
+        }
+
+        // maintain separate indexes
+        dna.indices[types[n].name] = dna.structures.size();
+
+        dna.structures.push_back(Structure());
+        Structure& s = dna.structures.back();
+        s.name  = types[n].name;
+        //s.index = dna.structures.size()-1;
+
+        n = stream.GetI2();
+        s.fields.reserve(n);
+
+        size_t offset = 0;
+        for (size_t m = 0; m < n; ++m, ++fields) {
+
+            uint16_t j = stream.GetI2();
+            if (j >= types.size()) {
+                throw DeadlyImportError((format(),
+                    "BlenderDNA: Invalid type index in structure field ", j,
+                    " (there are only ", types.size(), " entries)"
+                ));
+            }
+            s.fields.push_back(Field());
+            Field& f = s.fields.back();
+            f.offset = offset;
+
+            f.type = types[j].name;
+            f.size = types[j].size;
+
+            j = stream.GetI2();
+            if (j >= names.size()) {
+                throw DeadlyImportError((format(),
+                    "BlenderDNA: Invalid name index in structure field ", j,
+                    " (there are only ", names.size(), " entries)"
+                ));
+            }
+
+            f.name = names[j];
+            f.flags = 0u;
+
+            // pointers always specify the size of the pointee instead of their own.
+            // The pointer asterisk remains a property of the lookup name.
+            if (f.name[0] == '*') {
+                f.size = db.i64bit ? 8 : 4;
+                f.flags |= FieldFlag_Pointer;
+            }
+
+            // arrays, however, specify the size of a single element so we
+            // need to parse the (possibly multi-dimensional) array declaration
+            // in order to obtain the actual size of the array in the file.
+            // Also we need to alter the lookup name to include no array
+            // brackets anymore or size fixup won't work (if our size does
+            // not match the size read from the DNA).
+            if (*f.name.rbegin() == ']') {
+                const std::string::size_type rb = f.name.find('[');
+                if (rb == std::string::npos) {
+                    throw DeadlyImportError((format(),
+                        "BlenderDNA: Encountered invalid array declaration ",
+                        f.name
+                    ));
+                }
+
+                f.flags |= FieldFlag_Array;
+                DNA::ExtractArraySize(f.name,f.array_sizes);
+                f.name = f.name.substr(0,rb);
+
+                f.size *= f.array_sizes[0] * f.array_sizes[1];
+            }
+
+            // maintain separate indexes
+            s.indices[f.name] = s.fields.size()-1;
+            offset += f.size;
+        }
+        s.size = offset;
+    }
+
+    DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
+        " structures with totally ",fields," fields"));
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
-	dna.DumpToFile();
+    dna.DumpToFile();
 #endif
 
-	dna.AddPrimitiveStructures();
-	dna.RegisterConverters();
+    dna.AddPrimitiveStructures();
+    dna.RegisterConverters();
 }
 
 
@@ -227,144 +227,144 @@ void DNAParser :: Parse ()
 // ------------------------------------------------------------------------------------------------
 void DNA :: DumpToFile()
 {
-	// we dont't bother using the VFS here for this is only for debugging.
-	// (and all your bases are belong to us).
-
-	std::ofstream f("dna.txt");
-	if (f.fail()) {
-		DefaultLogger::get()->error("Could not dump dna to dna.txt");
-		return;
-	}
-	f << "Field format: type name offset size" << "\n";
-	f << "Structure format: name size" << "\n";
-
-	for_each(const Structure& s, structures) {
-		f << s.name << " " << s.size << "\n\n";
-		for_each(const Field& ff, s.fields) {
-			f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
-		}
-		f << std::endl;
-	}
-	DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
+    // we dont't bother using the VFS here for this is only for debugging.
+    // (and all your bases are belong to us).
+
+    std::ofstream f("dna.txt");
+    if (f.fail()) {
+        DefaultLogger::get()->error("Could not dump dna to dna.txt");
+        return;
+    }
+    f << "Field format: type name offset size" << "\n";
+    f << "Structure format: name size" << "\n";
+
+    for_each(const Structure& s, structures) {
+        f << s.name << " " << s.size << "\n\n";
+        for_each(const Field& ff, s.fields) {
+            f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
+        }
+        f << std::endl;
+    }
+    DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
 }
 #endif
 
 // ------------------------------------------------------------------------------------------------
 /*static*/ void  DNA :: ExtractArraySize(
-	const std::string& out,
-	size_t array_sizes[2]
+    const std::string& out,
+    size_t array_sizes[2]
 )
 {
-	array_sizes[0] = array_sizes[1] = 1;
-	std::string::size_type pos = out.find('[');
-	if (pos++ == std::string::npos) {
-		return;
-	}
-	array_sizes[0] = strtoul10(&out[pos]);
-
-	pos = out.find('[',pos);
-	if (pos++ == std::string::npos) {
-		return;
-	}
-	array_sizes[1] = strtoul10(&out[pos]);
+    array_sizes[0] = array_sizes[1] = 1;
+    std::string::size_type pos = out.find('[');
+    if (pos++ == std::string::npos) {
+        return;
+    }
+    array_sizes[0] = strtoul10(&out[pos]);
+
+    pos = out.find('[',pos);
+    if (pos++ == std::string::npos) {
+        return;
+    }
+    array_sizes[1] = strtoul10(&out[pos]);
 }
 
 // ------------------------------------------------------------------------------------------------
 boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
-	const Structure& structure,
-	const FileDatabase& db
+    const Structure& structure,
+    const FileDatabase& db
 ) const
 {
-	std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
-	if (it == converters.end()) {
-		return boost::shared_ptr< ElemBase >();
-	}
+    std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
+    if (it == converters.end()) {
+        return boost::shared_ptr< ElemBase >();
+    }
 
-	boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
-	(structure.*((*it).second.second))(ret,db);
+    boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
+    (structure.*((*it).second.second))(ret,db);
 
-	return ret;
+    return ret;
 }
 
 // ------------------------------------------------------------------------------------------------
 DNA::FactoryPair DNA :: GetBlobToStructureConverter(
-	const Structure& structure,
-	const FileDatabase& /*db*/
+    const Structure& structure,
+    const FileDatabase& /*db*/
 ) const
 {
-	std::map<std::string,  FactoryPair>::const_iterator it = converters.find(structure.name);
-	return it == converters.end() ? FactoryPair() : (*it).second;
+    std::map<std::string,  FactoryPair>::const_iterator it = converters.find(structure.name);
+    return it == converters.end() ? FactoryPair() : (*it).second;
 }
 
 // basing on http://www.blender.org/development/architecture/notes-on-sdna/
 // ------------------------------------------------------------------------------------------------
 void DNA :: AddPrimitiveStructures()
 {
-	// NOTE: these are just dummies. Their presence enforces
-	// Structure::Convert<target_type> to be called on these
-	// empty structures. These converters are special
-	// overloads which scan the name of the structure and
-	// perform the required data type conversion if one
-	// of these special names is found in the structure
-	// in question.
+    // NOTE: these are just dummies. Their presence enforces
+    // Structure::Convert<target_type> to be called on these
+    // empty structures. These converters are special
+    // overloads which scan the name of the structure and
+    // perform the required data type conversion if one
+    // of these special names is found in the structure
+    // in question.
 
-	indices["int"] = structures.size();
-	structures.push_back( Structure() );
-	structures.back().name = "int";
-	structures.back().size = 4;
+    indices["int"] = structures.size();
+    structures.push_back( Structure() );
+    structures.back().name = "int";
+    structures.back().size = 4;
 
-	indices["short"] = structures.size();
-	structures.push_back( Structure() );
-	structures.back().name = "short";
-	structures.back().size = 2;
+    indices["short"] = structures.size();
+    structures.push_back( Structure() );
+    structures.back().name = "short";
+    structures.back().size = 2;
 
 
-	indices["char"] = structures.size();
-	structures.push_back( Structure() );
-	structures.back().name = "char";
-	structures.back().size = 1;
+    indices["char"] = structures.size();
+    structures.push_back( Structure() );
+    structures.back().name = "char";
+    structures.back().size = 1;
 
 
-	indices["float"] = structures.size();
-	structures.push_back( Structure() );
-	structures.back().name = "float";
-	structures.back().size = 4;
+    indices["float"] = structures.size();
+    structures.push_back( Structure() );
+    structures.back().name = "float";
+    structures.back().size = 4;
 
 
-	indices["double"] = structures.size();
-	structures.push_back( Structure() );
-	structures.back().name = "double";
-	structures.back().size = 8;
+    indices["double"] = structures.size();
+    structures.push_back( Structure() );
+    structures.back().name = "double";
+    structures.back().size = 8;
 
-	// no long, seemingly.
+    // no long, seemingly.
 }
 
 // ------------------------------------------------------------------------------------------------
 void SectionParser :: Next()
 {
-	stream.SetCurrentPos(current.start + current.size);
+    stream.SetCurrentPos(current.start + current.size);
 
-	const char tmp[] = {
-		stream.GetI1(),
-		stream.GetI1(),
-		stream.GetI1(),
-		stream.GetI1()
-	};
-	current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
+    const char tmp[] = {
+        stream.GetI1(),
+        stream.GetI1(),
+        stream.GetI1(),
+        stream.GetI1()
+    };
+    current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
 
-	current.size = stream.GetI4();
-	current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
+    current.size = stream.GetI4();
+    current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
 
-	current.dna_index = stream.GetI4();
-	current.num = stream.GetI4();
+    current.dna_index = stream.GetI4();
+    current.num = stream.GetI4();
 
-	current.start = stream.GetCurrentPos();
-	if (stream.GetRemainingSizeToLimit() < current.size) {
-		throw DeadlyImportError("BLEND: invalid size of file block");
-	}
+    current.start = stream.GetCurrentPos();
+    if (stream.GetRemainingSizeToLimit() < current.size) {
+        throw DeadlyImportError("BLEND: invalid size of file block");
+    }
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
-	DefaultLogger::get()->debug(current.id);
+    DefaultLogger::get()->debug(current.id);
 #endif
 }
 

File diff suppressed because it is too large
+ 415 - 415
code/BlenderDNA.h


+ 126 - 126
code/BlenderIntermediate.h

@@ -60,142 +60,142 @@ struct aiTexture;
 namespace Assimp {
 namespace Blender {
 
-	// --------------------------------------------------------------------
-	/** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */
-	// --------------------------------------------------------------------
-	template <template <typename,typename> class TCLASS, typename T>
-	struct TempArray	{
-		typedef TCLASS< T*,std::allocator<T*> > mywrap;
-
-		TempArray() {
-		}
-
-		~TempArray () {
-			for_each(T* elem, arr) {
-				delete elem;
-			}
-		}
-
-		void dismiss() {
-			arr.clear();
-		}
-
-		mywrap* operator -> () {
-			return &arr;
-		}
-
-		operator mywrap& () {
-			return arr;
-		}
-
-		operator const mywrap& () const {
-			return arr;
-		}
-
-		mywrap& get () {
-			return arr;
-		}
-
-		const mywrap& get () const {
-			return arr;
-		}
-
-		T* operator[] (size_t idx) const {
-			return arr[idx];
-		}
-
-		T*& operator[] (size_t idx) {
-			return arr[idx];
-		}
-
-	private:
-		// no copy semantics
-		void operator= (const TempArray&)  {
-		}
-
-		TempArray(const TempArray& arr) {
-		}
-
-	private:
-		mywrap arr;
-	};
+    // --------------------------------------------------------------------
+    /** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */
+    // --------------------------------------------------------------------
+    template <template <typename,typename> class TCLASS, typename T>
+    struct TempArray    {
+        typedef TCLASS< T*,std::allocator<T*> > mywrap;
+
+        TempArray() {
+        }
+
+        ~TempArray () {
+            for_each(T* elem, arr) {
+                delete elem;
+            }
+        }
+
+        void dismiss() {
+            arr.clear();
+        }
+
+        mywrap* operator -> () {
+            return &arr;
+        }
+
+        operator mywrap& () {
+            return arr;
+        }
+
+        operator const mywrap& () const {
+            return arr;
+        }
+
+        mywrap& get () {
+            return arr;
+        }
+
+        const mywrap& get () const {
+            return arr;
+        }
+
+        T* operator[] (size_t idx) const {
+            return arr[idx];
+        }
+
+        T*& operator[] (size_t idx) {
+            return arr[idx];
+        }
+
+    private:
+        // no copy semantics
+        void operator= (const TempArray&)  {
+        }
+
+        TempArray(const TempArray& arr) {
+        }
+
+    private:
+        mywrap arr;
+    };
 
 #ifdef _MSC_VER
-#	pragma warning(disable:4351)
+#   pragma warning(disable:4351)
 #endif
 
-	struct ObjectCompare {
-		bool operator() (const Object* left, const Object* right) const {
-			return strcmp(left->id.name, right->id.name) == -1;
-		}
-	};
-
-	// When keeping objects in sets, sort them by their name.
-	typedef std::set<const Object*, ObjectCompare> ObjectSet;
-
-	// --------------------------------------------------------------------
-	/** ConversionData acts as intermediate storage location for
-	 *  the various ConvertXXX routines in BlenderImporter.*/
-	// --------------------------------------------------------------------
-	struct ConversionData
-	{
-		ConversionData(const FileDatabase& db)
-			: sentinel_cnt()
-			, next_texture()
-			, db(db)
-		{}
-
-		struct ObjectCompare {
-			bool operator() (const Object* left, const Object* right) const {
-				return strcmp(left->id.name, right->id.name) == -1;
-			}
-		};
-
-		ObjectSet objects;
-
-		TempArray <std::vector, aiMesh> meshes;
-		TempArray <std::vector, aiCamera> cameras;
-		TempArray <std::vector, aiLight> lights;
-		TempArray <std::vector, aiMaterial> materials;
-		TempArray <std::vector, aiTexture> textures;
-
-		// set of all materials referenced by at least one mesh in the scene
-		std::deque< boost::shared_ptr< Material > > materials_raw;
-
-		// counter to name sentinel textures inserted as substitutes for procedural textures.
-		unsigned int sentinel_cnt;
-
-		// next texture ID for each texture type, respectively
-		unsigned int next_texture[aiTextureType_UNKNOWN+1];
-
-		// original file data
-		const FileDatabase& db;
-	};
+    struct ObjectCompare {
+        bool operator() (const Object* left, const Object* right) const {
+            return strcmp(left->id.name, right->id.name) == -1;
+        }
+    };
+
+    // When keeping objects in sets, sort them by their name.
+    typedef std::set<const Object*, ObjectCompare> ObjectSet;
+
+    // --------------------------------------------------------------------
+    /** ConversionData acts as intermediate storage location for
+     *  the various ConvertXXX routines in BlenderImporter.*/
+    // --------------------------------------------------------------------
+    struct ConversionData
+    {
+        ConversionData(const FileDatabase& db)
+            : sentinel_cnt()
+            , next_texture()
+            , db(db)
+        {}
+
+        struct ObjectCompare {
+            bool operator() (const Object* left, const Object* right) const {
+                return strcmp(left->id.name, right->id.name) == -1;
+            }
+        };
+
+        ObjectSet objects;
+
+        TempArray <std::vector, aiMesh> meshes;
+        TempArray <std::vector, aiCamera> cameras;
+        TempArray <std::vector, aiLight> lights;
+        TempArray <std::vector, aiMaterial> materials;
+        TempArray <std::vector, aiTexture> textures;
+
+        // set of all materials referenced by at least one mesh in the scene
+        std::deque< boost::shared_ptr< Material > > materials_raw;
+
+        // counter to name sentinel textures inserted as substitutes for procedural textures.
+        unsigned int sentinel_cnt;
+
+        // next texture ID for each texture type, respectively
+        unsigned int next_texture[aiTextureType_UNKNOWN+1];
+
+        // original file data
+        const FileDatabase& db;
+    };
 #ifdef _MSC_VER
-#	pragma warning(default:4351)
+#   pragma warning(default:4351)
 #endif
 
 // ------------------------------------------------------------------------------------------------
 inline const char* GetTextureTypeDisplayString(Tex::Type t)
 {
-	switch (t)	{
-	case Tex::Type_CLOUDS		:  return  "Clouds";
-	case Tex::Type_WOOD			:  return  "Wood";
-	case Tex::Type_MARBLE		:  return  "Marble";
-	case Tex::Type_MAGIC		:  return  "Magic";
-	case Tex::Type_BLEND		:  return  "Blend";
-	case Tex::Type_STUCCI		:  return  "Stucci";
-	case Tex::Type_NOISE		:  return  "Noise";
-	case Tex::Type_PLUGIN		:  return  "Plugin";
-	case Tex::Type_MUSGRAVE		:  return  "Musgrave";
-	case Tex::Type_VORONOI		:  return  "Voronoi";
-	case Tex::Type_DISTNOISE	:  return  "DistortedNoise";
-	case Tex::Type_ENVMAP		:  return  "EnvMap";
-	case Tex::Type_IMAGE		:  return  "Image";
-	default:
-		break;
-	}
-	return "<Unknown>";
+    switch (t)  {
+    case Tex::Type_CLOUDS       :  return  "Clouds";
+    case Tex::Type_WOOD         :  return  "Wood";
+    case Tex::Type_MARBLE       :  return  "Marble";
+    case Tex::Type_MAGIC        :  return  "Magic";
+    case Tex::Type_BLEND        :  return  "Blend";
+    case Tex::Type_STUCCI       :  return  "Stucci";
+    case Tex::Type_NOISE        :  return  "Noise";
+    case Tex::Type_PLUGIN       :  return  "Plugin";
+    case Tex::Type_MUSGRAVE     :  return  "Musgrave";
+    case Tex::Type_VORONOI      :  return  "Voronoi";
+    case Tex::Type_DISTNOISE    :  return  "DistortedNoise";
+    case Tex::Type_ENVMAP       :  return  "EnvMap";
+    case Tex::Type_IMAGE        :  return  "Image";
+    default:
+        break;
+    }
+    return "<Unknown>";
 }
 
 } // ! Blender

+ 935 - 935
code/BlenderLoader.cpp

@@ -62,15 +62,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // zlib is needed for compressed blend files
 #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
-#	ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#		include <zlib.h>
-#	else
-#		include "../contrib/zlib/zlib.h"
-#	endif
+#   ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#       include <zlib.h>
+#   else
+#       include "../contrib/zlib/zlib.h"
+#   endif
 #endif
 
 namespace Assimp {
-	template<> const std::string LogFunctions<BlenderImporter>::log_prefix = "BLEND: ";
+    template<> const std::string LogFunctions<BlenderImporter>::log_prefix = "BLEND: ";
 }
 
 using namespace Assimp;
@@ -78,16 +78,16 @@ using namespace Assimp::Blender;
 using namespace Assimp::Formatter;
 
 static const aiImporterDesc blenderDesc = {
-	"Blender 3D Importer \nhttp://www.blender3d.org",
-	"",
-	"",
-	"No animation support yet",
-	aiImporterFlags_SupportBinaryFlavour,
-	0,
-	0,
-	2,
-	50,
-	"blend"
+    "Blender 3D Importer \nhttp://www.blender3d.org",
+    "",
+    "",
+    "No animation support yet",
+    aiImporterFlags_SupportBinaryFlavour,
+    0,
+    0,
+    2,
+    50,
+    "blend"
 };
 
 
@@ -101,1059 +101,1059 @@ BlenderImporter::BlenderImporter()
 // Destructor, private as well
 BlenderImporter::~BlenderImporter()
 {
-	delete modifier_cache;
+    delete modifier_cache;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-	const std::string& extension = GetExtension(pFile);
-	if (extension == "blend") {
-		return true;
-	}
-
-	else if ((!extension.length() || checkSig) && pIOHandler)	{
-		// note: this won't catch compressed files
-		const char* tokens[] = {"BLENDER"};
-		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-	}
-	return false;
+    const std::string& extension = GetExtension(pFile);
+    if (extension == "blend") {
+        return true;
+    }
+
+    else if ((!extension.length() || checkSig) && pIOHandler)   {
+        // note: this won't catch compressed files
+        const char* tokens[] = {"BLENDER"};
+        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // List all extensions handled by this loader
 void BlenderImporter::GetExtensionList(std::set<std::string>& app)
 {
-	app.insert("blend");
+    app.insert("blend");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Loader registry entry
 const aiImporterDesc* BlenderImporter::GetInfo () const
 {
-	return &blenderDesc;
+    return &blenderDesc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup configuration properties for the loader
 void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
 {
-	// nothing to be done for the moment
+    // nothing to be done for the moment
 }
 
 struct free_it
 {
-	free_it(void* free) : free(free) {}
-	~free_it() {
-		::free(this->free);
-	}
+    free_it(void* free) : free(free) {}
+    ~free_it() {
+        ::free(this->free);
+    }
 
-	void* free;
+    void* free;
 };
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void BlenderImporter::InternReadFile( const std::string& pFile,
-	aiScene* pScene, IOSystem* pIOHandler)
+    aiScene* pScene, IOSystem* pIOHandler)
 {
 #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
-	Bytef* dest = NULL;
-	free_it free_it_really(dest);
+    Bytef* dest = NULL;
+    free_it free_it_really(dest);
 #endif
 
-	FileDatabase file;
-	boost::shared_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
-	if (!stream) {
-		ThrowException("Could not open file for reading");
-	}
-
-	char magic[8] = {0};
-	stream->Read(magic,7,1);
-	if (strcmp(magic,"BLENDER")) {
-		// Check for presence of the gzip header. If yes, assume it is a
-		// compressed blend file and try uncompressing it, else fail. This is to
-		// avoid uncompressing random files which our loader might end up with.
+    FileDatabase file;
+    boost::shared_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
+    if (!stream) {
+        ThrowException("Could not open file for reading");
+    }
+
+    char magic[8] = {0};
+    stream->Read(magic,7,1);
+    if (strcmp(magic,"BLENDER")) {
+        // Check for presence of the gzip header. If yes, assume it is a
+        // compressed blend file and try uncompressing it, else fail. This is to
+        // avoid uncompressing random files which our loader might end up with.
 #ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
-		ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
+        ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
 #else
 
-		if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
-			ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
-		}
+        if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
+            ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
+        }
 
-		LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
-		if (magic[2] != 8) {
-			ThrowException("Unsupported GZIP compression method");
-		}
+        LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
+        if (magic[2] != 8) {
+            ThrowException("Unsupported GZIP compression method");
+        }
 
-		// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
-		stream->Seek(0L,aiOrigin_SET);
-		boost::shared_ptr<StreamReaderLE> reader = boost::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
+        // http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
+        stream->Seek(0L,aiOrigin_SET);
+        boost::shared_ptr<StreamReaderLE> reader = boost::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
 
-		// build a zlib stream
-		z_stream zstream;
-		zstream.opaque = Z_NULL;
-		zstream.zalloc = Z_NULL;
-		zstream.zfree  = Z_NULL;
-		zstream.data_type = Z_BINARY;
+        // build a zlib stream
+        z_stream zstream;
+        zstream.opaque = Z_NULL;
+        zstream.zalloc = Z_NULL;
+        zstream.zfree  = Z_NULL;
+        zstream.data_type = Z_BINARY;
 
-		// http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
-		inflateInit2(&zstream, 16+MAX_WBITS);
+        // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
+        inflateInit2(&zstream, 16+MAX_WBITS);
 
-		zstream.next_in   = reinterpret_cast<Bytef*>( reader->GetPtr() );
-		zstream.avail_in  = reader->GetRemainingSize();
+        zstream.next_in   = reinterpret_cast<Bytef*>( reader->GetPtr() );
+        zstream.avail_in  = reader->GetRemainingSize();
 
-		size_t total = 0l;
+        size_t total = 0l;
 
-		// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
+        // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
 #define MYBLOCK 1024
-		Bytef block[MYBLOCK];
-		int ret;
-		do {
-			zstream.avail_out = MYBLOCK;
-			zstream.next_out = block;
-			ret = inflate(&zstream, Z_NO_FLUSH);
-
-			if (ret != Z_STREAM_END && ret != Z_OK) {
-				ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .BLEND file");
-			}
-			const size_t have = MYBLOCK - zstream.avail_out;
-			total += have;
-			dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
-			memcpy(dest + total - have,block,have);
-		}
-		while (ret != Z_STREAM_END);
-
-		// terminate zlib
-		inflateEnd(&zstream);
-
-		// replace the input stream with a memory stream
-		stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total));
-
-		// .. and retry
-		stream->Read(magic,7,1);
-		if (strcmp(magic,"BLENDER")) {
-			ThrowException("Found no BLENDER magic word in decompressed GZIP file");
-		}
+        Bytef block[MYBLOCK];
+        int ret;
+        do {
+            zstream.avail_out = MYBLOCK;
+            zstream.next_out = block;
+            ret = inflate(&zstream, Z_NO_FLUSH);
+
+            if (ret != Z_STREAM_END && ret != Z_OK) {
+                ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .BLEND file");
+            }
+            const size_t have = MYBLOCK - zstream.avail_out;
+            total += have;
+            dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
+            memcpy(dest + total - have,block,have);
+        }
+        while (ret != Z_STREAM_END);
+
+        // terminate zlib
+        inflateEnd(&zstream);
+
+        // replace the input stream with a memory stream
+        stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total));
+
+        // .. and retry
+        stream->Read(magic,7,1);
+        if (strcmp(magic,"BLENDER")) {
+            ThrowException("Found no BLENDER magic word in decompressed GZIP file");
+        }
 #endif
-	}
+    }
 
-	file.i64bit = (stream->Read(magic,1,1),magic[0]=='-');
-	file.little = (stream->Read(magic,1,1),magic[0]=='v');
+    file.i64bit = (stream->Read(magic,1,1),magic[0]=='-');
+    file.little = (stream->Read(magic,1,1),magic[0]=='v');
 
-	stream->Read(magic,3,1);
-	magic[3] = '\0';
+    stream->Read(magic,3,1);
+    magic[3] = '\0';
 
-	LogInfo((format(),"Blender version is ",magic[0],".",magic+1,
-		" (64bit: ",file.i64bit?"true":"false",
-		", little endian: ",file.little?"true":"false",")"
-	));
+    LogInfo((format(),"Blender version is ",magic[0],".",magic+1,
+        " (64bit: ",file.i64bit?"true":"false",
+        ", little endian: ",file.little?"true":"false",")"
+    ));
 
-	ParseBlendFile(file,stream);
+    ParseBlendFile(file,stream);
 
-	Scene scene;
-	ExtractScene(scene,file);
+    Scene scene;
+    ExtractScene(scene,file);
 
-	ConvertBlendFile(pScene,scene,file);
+    ConvertBlendFile(pScene,scene,file);
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::ParseBlendFile(FileDatabase& out, boost::shared_ptr<IOStream> stream)
 {
-	out.reader = boost::shared_ptr<StreamReaderAny>(new StreamReaderAny(stream,out.little));
-
-	DNAParser dna_reader(out);
-	const DNA* dna = NULL;
-
-	out.entries.reserve(128); { // even small BLEND files tend to consist of many file blocks
-		SectionParser parser(*out.reader.get(),out.i64bit);
-
-		// first parse the file in search for the DNA and insert all other sections into the database
-		while ((parser.Next(),1)) {
-			const FileBlockHead& head = parser.GetCurrent();
-
-			if (head.id == "ENDB") {
-				break; // only valid end of the file
-			}
-			else if (head.id == "DNA1") {
-				dna_reader.Parse();
-				dna = &dna_reader.GetDNA();
-				continue;
-			}
-
-			out.entries.push_back(head);
-		}
-	}
-	if (!dna) {
-		ThrowException("SDNA not found");
-	}
-
-	std::sort(out.entries.begin(),out.entries.end());
+    out.reader = boost::shared_ptr<StreamReaderAny>(new StreamReaderAny(stream,out.little));
+
+    DNAParser dna_reader(out);
+    const DNA* dna = NULL;
+
+    out.entries.reserve(128); { // even small BLEND files tend to consist of many file blocks
+        SectionParser parser(*out.reader.get(),out.i64bit);
+
+        // first parse the file in search for the DNA and insert all other sections into the database
+        while ((parser.Next(),1)) {
+            const FileBlockHead& head = parser.GetCurrent();
+
+            if (head.id == "ENDB") {
+                break; // only valid end of the file
+            }
+            else if (head.id == "DNA1") {
+                dna_reader.Parse();
+                dna = &dna_reader.GetDNA();
+                continue;
+            }
+
+            out.entries.push_back(head);
+        }
+    }
+    if (!dna) {
+        ThrowException("SDNA not found");
+    }
+
+    std::sort(out.entries.begin(),out.entries.end());
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
 {
-	const FileBlockHead* block = NULL;
-	std::map<std::string,size_t>::const_iterator it = file.dna.indices.find("Scene");
-	if (it == file.dna.indices.end()) {
-		ThrowException("There is no `Scene` structure record");
-	}
+    const FileBlockHead* block = NULL;
+    std::map<std::string,size_t>::const_iterator it = file.dna.indices.find("Scene");
+    if (it == file.dna.indices.end()) {
+        ThrowException("There is no `Scene` structure record");
+    }
 
-	const Structure& ss = file.dna.structures[(*it).second];
+    const Structure& ss = file.dna.structures[(*it).second];
 
-	// we need a scene somewhere to start with.
-	for_each(const FileBlockHead& bl,file.entries) {
+    // we need a scene somewhere to start with.
+    for_each(const FileBlockHead& bl,file.entries) {
 
-		// Fix: using the DNA index is more reliable to locate scenes
-		//if (bl.id == "SC") {
+        // Fix: using the DNA index is more reliable to locate scenes
+        //if (bl.id == "SC") {
 
-		if (bl.dna_index == (*it).second) {
-			block = &bl;
-			break;
-		}
-	}
+        if (bl.dna_index == (*it).second) {
+            block = &bl;
+            break;
+        }
+    }
 
-	if (!block) {
-		ThrowException("There is not a single `Scene` record to load");
-	}
+    if (!block) {
+        ThrowException("There is not a single `Scene` record to load");
+    }
 
-	file.reader->SetCurrentPos(block->start);
-	ss.Convert(out,file);
+    file.reader->SetCurrentPos(block->start);
+    ss.Convert(out,file);
 
 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
-	DefaultLogger::get()->info((format(),
-		"(Stats) Fields read: "	,file.stats().fields_read,
-		", pointers resolved: "	,file.stats().pointers_resolved,
-		", cache hits: "        ,file.stats().cache_hits,
-		", cached objects: "	,file.stats().cached_objects
-	));
+    DefaultLogger::get()->info((format(),
+        "(Stats) Fields read: " ,file.stats().fields_read,
+        ", pointers resolved: " ,file.stats().pointers_resolved,
+        ", cache hits: "        ,file.stats().cache_hits,
+        ", cached objects: "    ,file.stats().cached_objects
+    ));
 #endif
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileDatabase& file)
 {
-	ConversionData conv(file);
-
-	// FIXME it must be possible to take the hierarchy directly from
-	// the file. This is terrible. Here, we're first looking for
-	// all objects which don't have parent objects at all -
-	std::deque<const Object*> no_parents;
-	for (boost::shared_ptr<Base> cur = boost::static_pointer_cast<Base> ( in.base.first ); cur; cur = cur->next) {
-		if (cur->object) {
-			if(!cur->object->parent) {
-				no_parents.push_back(cur->object.get());
-			}
-			else conv.objects.insert(cur->object.get());
-		}
-	}
-	for (boost::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
-		if (cur->object) {
-			if(cur->object->parent) {
-				conv.objects.insert(cur->object.get());
-			}
-		}
-	}
-
-	if (no_parents.empty()) {
-		ThrowException("Expected at least one object with no parent");
-	}
-
-	aiNode* root = out->mRootNode = new aiNode("<BlenderRoot>");
-
-	root->mNumChildren = static_cast<unsigned int>(no_parents.size());
-	root->mChildren = new aiNode*[root->mNumChildren]();
-	for (unsigned int i = 0; i < root->mNumChildren; ++i) {
-		root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
-		root->mChildren[i]->mParent = root;
-	}
-
-	BuildMaterials(conv);
-
-	if (conv.meshes->size()) {
-		out->mMeshes = new aiMesh*[out->mNumMeshes = static_cast<unsigned int>( conv.meshes->size() )];
-		std::copy(conv.meshes->begin(),conv.meshes->end(),out->mMeshes);
-		conv.meshes.dismiss();
-	}
-
-	if (conv.lights->size()) {
-		out->mLights = new aiLight*[out->mNumLights = static_cast<unsigned int>( conv.lights->size() )];
-		std::copy(conv.lights->begin(),conv.lights->end(),out->mLights);
-		conv.lights.dismiss();
-	}
-
-	if (conv.cameras->size()) {
-		out->mCameras = new aiCamera*[out->mNumCameras = static_cast<unsigned int>( conv.cameras->size() )];
-		std::copy(conv.cameras->begin(),conv.cameras->end(),out->mCameras);
-		conv.cameras.dismiss();
-	}
-
-	if (conv.materials->size()) {
-		out->mMaterials = new aiMaterial*[out->mNumMaterials = static_cast<unsigned int>( conv.materials->size() )];
-		std::copy(conv.materials->begin(),conv.materials->end(),out->mMaterials);
-		conv.materials.dismiss();
-	}
-
-	if (conv.textures->size()) {
-		out->mTextures = new aiTexture*[out->mNumTextures = static_cast<unsigned int>( conv.textures->size() )];
-		std::copy(conv.textures->begin(),conv.textures->end(),out->mTextures);
-		conv.textures.dismiss();
-	}
-
-	// acknowledge that the scene might come out incomplete
-	// by Assimps definition of `complete`: blender scenes
-	// can consist of thousands of cameras or lights with
-	// not a single mesh between them.
-	if (!out->mNumMeshes) {
-		out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
-	}
+    ConversionData conv(file);
+
+    // FIXME it must be possible to take the hierarchy directly from
+    // the file. This is terrible. Here, we're first looking for
+    // all objects which don't have parent objects at all -
+    std::deque<const Object*> no_parents;
+    for (boost::shared_ptr<Base> cur = boost::static_pointer_cast<Base> ( in.base.first ); cur; cur = cur->next) {
+        if (cur->object) {
+            if(!cur->object->parent) {
+                no_parents.push_back(cur->object.get());
+            }
+            else conv.objects.insert(cur->object.get());
+        }
+    }
+    for (boost::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
+        if (cur->object) {
+            if(cur->object->parent) {
+                conv.objects.insert(cur->object.get());
+            }
+        }
+    }
+
+    if (no_parents.empty()) {
+        ThrowException("Expected at least one object with no parent");
+    }
+
+    aiNode* root = out->mRootNode = new aiNode("<BlenderRoot>");
+
+    root->mNumChildren = static_cast<unsigned int>(no_parents.size());
+    root->mChildren = new aiNode*[root->mNumChildren]();
+    for (unsigned int i = 0; i < root->mNumChildren; ++i) {
+        root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
+        root->mChildren[i]->mParent = root;
+    }
+
+    BuildMaterials(conv);
+
+    if (conv.meshes->size()) {
+        out->mMeshes = new aiMesh*[out->mNumMeshes = static_cast<unsigned int>( conv.meshes->size() )];
+        std::copy(conv.meshes->begin(),conv.meshes->end(),out->mMeshes);
+        conv.meshes.dismiss();
+    }
+
+    if (conv.lights->size()) {
+        out->mLights = new aiLight*[out->mNumLights = static_cast<unsigned int>( conv.lights->size() )];
+        std::copy(conv.lights->begin(),conv.lights->end(),out->mLights);
+        conv.lights.dismiss();
+    }
+
+    if (conv.cameras->size()) {
+        out->mCameras = new aiCamera*[out->mNumCameras = static_cast<unsigned int>( conv.cameras->size() )];
+        std::copy(conv.cameras->begin(),conv.cameras->end(),out->mCameras);
+        conv.cameras.dismiss();
+    }
+
+    if (conv.materials->size()) {
+        out->mMaterials = new aiMaterial*[out->mNumMaterials = static_cast<unsigned int>( conv.materials->size() )];
+        std::copy(conv.materials->begin(),conv.materials->end(),out->mMaterials);
+        conv.materials.dismiss();
+    }
+
+    if (conv.textures->size()) {
+        out->mTextures = new aiTexture*[out->mNumTextures = static_cast<unsigned int>( conv.textures->size() )];
+        std::copy(conv.textures->begin(),conv.textures->end(),out->mTextures);
+        conv.textures.dismiss();
+    }
+
+    // acknowledge that the scene might come out incomplete
+    // by Assimps definition of `complete`: blender scenes
+    // can consist of thousands of cameras or lights with
+    // not a single mesh between them.
+    if (!out->mNumMeshes) {
+        out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const MTex* tex, const Image* img, ConversionData& conv_data)
 {
-	(void)mat; (void)tex; (void)conv_data;
-	aiString name;
-
-	// check if the file contents are bundled with the BLEND file
-	if (img->packedfile) {
-		name.data[0] = '*';
-		name.length = 1+ ASSIMP_itoa10(name.data+1,MAXLEN-1,conv_data.textures->size());
-
-		conv_data.textures->push_back(new aiTexture());
-		aiTexture* tex = conv_data.textures->back();
-
-		// usually 'img->name' will be the original file name of the embedded textures,
-		// so we can extract the file extension from it.
-		const size_t nlen = strlen( img->name );
-		const char* s = img->name+nlen, *e = s;
-
-		while (s >= img->name && *s != '.')--s;
-
-		tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] );
-		tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] );
-		tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] );
-		tex->achFormatHint[3] = '\0';
-
-		// tex->mHeight = 0;
-		tex->mWidth = img->packedfile->size;
-		uint8_t* ch = new uint8_t[tex->mWidth];
-
-		conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val));
-		conv_data.db.reader->CopyAndAdvance(ch,tex->mWidth);
-
-		tex->pcData = reinterpret_cast<aiTexel*>(ch);
-
-		LogInfo("Reading embedded texture, original file was "+std::string(img->name));
-	}
-	else {
-		name = aiString( img->name );
-	}
-
-	aiTextureType texture_type = aiTextureType_UNKNOWN;
-	MTex::MapType map_type = tex->mapto;
-
-	if (map_type & MTex::MapType_COL)
-	    texture_type = aiTextureType_DIFFUSE;
-	else if (map_type & MTex::MapType_NORM) {
-	    if (tex->tex->imaflag & Tex::ImageFlags_NORMALMAP) {
-	        texture_type = aiTextureType_NORMALS;
-	    }
-	    else {
-	        texture_type = aiTextureType_HEIGHT;
-	    }
-	    out->AddProperty(&tex->norfac,1,AI_MATKEY_BUMPSCALING);
-	}
-	else if (map_type & MTex::MapType_COLSPEC)
-		texture_type = aiTextureType_SPECULAR;
-	else if (map_type & MTex::MapType_COLMIR)
-		texture_type = aiTextureType_REFLECTION;
-	//else if (map_type & MTex::MapType_REF)
-	else if (map_type & MTex::MapType_SPEC)
-		texture_type = aiTextureType_SHININESS;
-	else if (map_type & MTex::MapType_EMIT)
-		texture_type = aiTextureType_EMISSIVE;
-	//else if (map_type & MTex::MapType_ALPHA)
-	//else if (map_type & MTex::MapType_HAR)
-	//else if (map_type & MTex::MapType_RAYMIRR)
-	//else if (map_type & MTex::MapType_TRANSLU)
-	else if (map_type & MTex::MapType_AMB)
-		texture_type = aiTextureType_AMBIENT;
-	else if (map_type & MTex::MapType_DISPLACE)
-		texture_type = aiTextureType_DISPLACEMENT;
-	//else if (map_type & MTex::MapType_WARP)
-
-	out->AddProperty(&name,AI_MATKEY_TEXTURE(texture_type,
-	    conv_data.next_texture[texture_type]++));
+    (void)mat; (void)tex; (void)conv_data;
+    aiString name;
+
+    // check if the file contents are bundled with the BLEND file
+    if (img->packedfile) {
+        name.data[0] = '*';
+        name.length = 1+ ASSIMP_itoa10(name.data+1,MAXLEN-1,conv_data.textures->size());
+
+        conv_data.textures->push_back(new aiTexture());
+        aiTexture* tex = conv_data.textures->back();
+
+        // usually 'img->name' will be the original file name of the embedded textures,
+        // so we can extract the file extension from it.
+        const size_t nlen = strlen( img->name );
+        const char* s = img->name+nlen, *e = s;
+
+        while (s >= img->name && *s != '.')--s;
+
+        tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] );
+        tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] );
+        tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] );
+        tex->achFormatHint[3] = '\0';
+
+        // tex->mHeight = 0;
+        tex->mWidth = img->packedfile->size;
+        uint8_t* ch = new uint8_t[tex->mWidth];
+
+        conv_data.db.reader->SetCurrentPos(static_cast<size_t>( img->packedfile->data->val));
+        conv_data.db.reader->CopyAndAdvance(ch,tex->mWidth);
+
+        tex->pcData = reinterpret_cast<aiTexel*>(ch);
+
+        LogInfo("Reading embedded texture, original file was "+std::string(img->name));
+    }
+    else {
+        name = aiString( img->name );
+    }
+
+    aiTextureType texture_type = aiTextureType_UNKNOWN;
+    MTex::MapType map_type = tex->mapto;
+
+    if (map_type & MTex::MapType_COL)
+        texture_type = aiTextureType_DIFFUSE;
+    else if (map_type & MTex::MapType_NORM) {
+        if (tex->tex->imaflag & Tex::ImageFlags_NORMALMAP) {
+            texture_type = aiTextureType_NORMALS;
+        }
+        else {
+            texture_type = aiTextureType_HEIGHT;
+        }
+        out->AddProperty(&tex->norfac,1,AI_MATKEY_BUMPSCALING);
+    }
+    else if (map_type & MTex::MapType_COLSPEC)
+        texture_type = aiTextureType_SPECULAR;
+    else if (map_type & MTex::MapType_COLMIR)
+        texture_type = aiTextureType_REFLECTION;
+    //else if (map_type & MTex::MapType_REF)
+    else if (map_type & MTex::MapType_SPEC)
+        texture_type = aiTextureType_SHININESS;
+    else if (map_type & MTex::MapType_EMIT)
+        texture_type = aiTextureType_EMISSIVE;
+    //else if (map_type & MTex::MapType_ALPHA)
+    //else if (map_type & MTex::MapType_HAR)
+    //else if (map_type & MTex::MapType_RAYMIRR)
+    //else if (map_type & MTex::MapType_TRANSLU)
+    else if (map_type & MTex::MapType_AMB)
+        texture_type = aiTextureType_AMBIENT;
+    else if (map_type & MTex::MapType_DISPLACE)
+        texture_type = aiTextureType_DISPLACEMENT;
+    //else if (map_type & MTex::MapType_WARP)
+
+    out->AddProperty(&name,AI_MATKEY_TEXTURE(texture_type,
+        conv_data.next_texture[texture_type]++));
 
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::AddSentinelTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
 {
-	(void)mat; (void)tex; (void)conv_data;
-
-	aiString name;
-	name.length = sprintf(name.data, "Procedural,num=%i,type=%s",conv_data.sentinel_cnt++,
-		GetTextureTypeDisplayString(tex->tex->type)
-	);
-	out->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(
-		conv_data.next_texture[aiTextureType_DIFFUSE]++)
-	);
+    (void)mat; (void)tex; (void)conv_data;
+
+    aiString name;
+    name.length = sprintf(name.data, "Procedural,num=%i,type=%s",conv_data.sentinel_cnt++,
+        GetTextureTypeDisplayString(tex->tex->type)
+    );
+    out->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(
+        conv_data.next_texture[aiTextureType_DIFFUSE]++)
+    );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::ResolveTexture(aiMaterial* out, const Material* mat, const MTex* tex, ConversionData& conv_data)
 {
-	const Tex* rtex = tex->tex.get();
-	if(!rtex || !rtex->type) {
-		return;
-	}
-
-	// We can't support most of the texture types because they're mostly procedural.
-	// These are substituted by a dummy texture.
-	const char* dispnam = "";
-	switch( rtex->type )
-	{
-			// these are listed in blender's UI
-		case Tex::Type_CLOUDS		:
-		case Tex::Type_WOOD			:
-		case Tex::Type_MARBLE		:
-		case Tex::Type_MAGIC		:
-		case Tex::Type_BLEND		:
-		case Tex::Type_STUCCI		:
-		case Tex::Type_NOISE		:
-		case Tex::Type_PLUGIN		:
-		case Tex::Type_MUSGRAVE		:
-		case Tex::Type_VORONOI		:
-		case Tex::Type_DISTNOISE	:
-		case Tex::Type_ENVMAP		:
-
-			// these do no appear in the UI, why?
-		case Tex::Type_POINTDENSITY	:
-		case Tex::Type_VOXELDATA	:
-
-			LogWarn(std::string("Encountered a texture with an unsupported type: ")+dispnam);
-			AddSentinelTexture(out, mat, tex, conv_data);
-			break;
-
-		case Tex::Type_IMAGE		:
-			if (!rtex->ima) {
-				LogError("A texture claims to be an Image, but no image reference is given");
-				break;
-			}
-			ResolveImage(out, mat, tex, rtex->ima.get(),conv_data);
-			break;
-
-		default:
-			ai_assert(false);
-	};
+    const Tex* rtex = tex->tex.get();
+    if(!rtex || !rtex->type) {
+        return;
+    }
+
+    // We can't support most of the texture types because they're mostly procedural.
+    // These are substituted by a dummy texture.
+    const char* dispnam = "";
+    switch( rtex->type )
+    {
+            // these are listed in blender's UI
+        case Tex::Type_CLOUDS       :
+        case Tex::Type_WOOD         :
+        case Tex::Type_MARBLE       :
+        case Tex::Type_MAGIC        :
+        case Tex::Type_BLEND        :
+        case Tex::Type_STUCCI       :
+        case Tex::Type_NOISE        :
+        case Tex::Type_PLUGIN       :
+        case Tex::Type_MUSGRAVE     :
+        case Tex::Type_VORONOI      :
+        case Tex::Type_DISTNOISE    :
+        case Tex::Type_ENVMAP       :
+
+            // these do no appear in the UI, why?
+        case Tex::Type_POINTDENSITY :
+        case Tex::Type_VOXELDATA    :
+
+            LogWarn(std::string("Encountered a texture with an unsupported type: ")+dispnam);
+            AddSentinelTexture(out, mat, tex, conv_data);
+            break;
+
+        case Tex::Type_IMAGE        :
+            if (!rtex->ima) {
+                LogError("A texture claims to be an Image, but no image reference is given");
+                break;
+            }
+            ResolveImage(out, mat, tex, rtex->ima.get(),conv_data);
+            break;
+
+        default:
+            ai_assert(false);
+    };
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::BuildMaterials(ConversionData& conv_data)
 {
-	conv_data.materials->reserve(conv_data.materials_raw.size());
-
-	// add a default material if necessary
-	unsigned int index = static_cast<unsigned int>( -1 );
-	for_each( aiMesh* mesh, conv_data.meshes.get() ) {
-		if (mesh->mMaterialIndex == static_cast<unsigned int>( -1 )) {
-
-			if (index == static_cast<unsigned int>( -1 )) {
-				// Setup a default material.
-				boost::shared_ptr<Material> p(new Material());
-				ai_assert(::strlen(AI_DEFAULT_MATERIAL_NAME) < sizeof(p->id.name)-2);
-				strcpy( p->id.name+2, AI_DEFAULT_MATERIAL_NAME );
-
-				// Note: MSVC11 does not zero-initialize Material here, although it should.
-				// Thus all relevant fields should be explicitly initialized. We cannot add
-				// a default constructor to Material since the DNA codegen does not support
-				// parsing it.
-				p->r = p->g = p->b = 0.6f;
-				p->specr = p->specg = p->specb = 0.6f;
-				p->ambr = p->ambg = p->ambb = 0.0f;
-				p->mirr = p->mirg = p->mirb = 0.0f;
-				p->emit = 0.f;
-				p->alpha = 0.f;
-				p->har = 0;
-
-				index = static_cast<unsigned int>( conv_data.materials_raw.size() );
-				conv_data.materials_raw.push_back(p);
-				LogInfo("Adding default material");
-			}
-			mesh->mMaterialIndex = index;
-		}
-	}
-
-	for_each(boost::shared_ptr<Material> mat, conv_data.materials_raw) {
-
-		// reset per material global counters
-		for (size_t i = 0; i < sizeof(conv_data.next_texture)/sizeof(conv_data.next_texture[0]);++i) {
-			conv_data.next_texture[i] = 0 ;
-		}
-
-		aiMaterial* mout = new aiMaterial();
-		conv_data.materials->push_back(mout);
-		// For any new material field handled here, the default material above must be updated with an appropriate default value.
-
-		// set material name
-		aiString name = aiString(mat->id.name+2); // skip over the name prefix 'MA'
-		mout->AddProperty(&name,AI_MATKEY_NAME);
-
-
-		// basic material colors
-		aiColor3D col(mat->r,mat->g,mat->b);
-		if (mat->r || mat->g || mat->b ) {
-
-			// Usually, zero diffuse color means no diffuse color at all in the equation.
-			// So we omit this member to express this intent.
-			mout->AddProperty(&col,1,AI_MATKEY_COLOR_DIFFUSE);
-
-			if (mat->emit) {
-				aiColor3D emit_col(mat->emit * mat->r, mat->emit * mat->g, mat->emit * mat->b) ;
-				mout->AddProperty(&emit_col, 1, AI_MATKEY_COLOR_EMISSIVE) ;
-			}
-		}
-
-		col = aiColor3D(mat->specr,mat->specg,mat->specb);
-		mout->AddProperty(&col,1,AI_MATKEY_COLOR_SPECULAR);
-
-		// is hardness/shininess set?
-		if( mat->har ) {
-			const float har = mat->har;
-			mout->AddProperty(&har,1,AI_MATKEY_SHININESS);
-		}
-
-		col = aiColor3D(mat->ambr,mat->ambg,mat->ambb);
-		mout->AddProperty(&col,1,AI_MATKEY_COLOR_AMBIENT);
-
-		col = aiColor3D(mat->mirr,mat->mirg,mat->mirb);
-		mout->AddProperty(&col,1,AI_MATKEY_COLOR_REFLECTIVE);
-
-		for(size_t i = 0; i < sizeof(mat->mtex) / sizeof(mat->mtex[0]); ++i) {
-			if (!mat->mtex[i]) {
-				continue;
-			}
-
-			ResolveTexture(mout,mat.get(),mat->mtex[i].get(),conv_data);
-		}
-	}
+    conv_data.materials->reserve(conv_data.materials_raw.size());
+
+    // add a default material if necessary
+    unsigned int index = static_cast<unsigned int>( -1 );
+    for_each( aiMesh* mesh, conv_data.meshes.get() ) {
+        if (mesh->mMaterialIndex == static_cast<unsigned int>( -1 )) {
+
+            if (index == static_cast<unsigned int>( -1 )) {
+                // Setup a default material.
+                boost::shared_ptr<Material> p(new Material());
+                ai_assert(::strlen(AI_DEFAULT_MATERIAL_NAME) < sizeof(p->id.name)-2);
+                strcpy( p->id.name+2, AI_DEFAULT_MATERIAL_NAME );
+
+                // Note: MSVC11 does not zero-initialize Material here, although it should.
+                // Thus all relevant fields should be explicitly initialized. We cannot add
+                // a default constructor to Material since the DNA codegen does not support
+                // parsing it.
+                p->r = p->g = p->b = 0.6f;
+                p->specr = p->specg = p->specb = 0.6f;
+                p->ambr = p->ambg = p->ambb = 0.0f;
+                p->mirr = p->mirg = p->mirb = 0.0f;
+                p->emit = 0.f;
+                p->alpha = 0.f;
+                p->har = 0;
+
+                index = static_cast<unsigned int>( conv_data.materials_raw.size() );
+                conv_data.materials_raw.push_back(p);
+                LogInfo("Adding default material");
+            }
+            mesh->mMaterialIndex = index;
+        }
+    }
+
+    for_each(boost::shared_ptr<Material> mat, conv_data.materials_raw) {
+
+        // reset per material global counters
+        for (size_t i = 0; i < sizeof(conv_data.next_texture)/sizeof(conv_data.next_texture[0]);++i) {
+            conv_data.next_texture[i] = 0 ;
+        }
+
+        aiMaterial* mout = new aiMaterial();
+        conv_data.materials->push_back(mout);
+        // For any new material field handled here, the default material above must be updated with an appropriate default value.
+
+        // set material name
+        aiString name = aiString(mat->id.name+2); // skip over the name prefix 'MA'
+        mout->AddProperty(&name,AI_MATKEY_NAME);
+
+
+        // basic material colors
+        aiColor3D col(mat->r,mat->g,mat->b);
+        if (mat->r || mat->g || mat->b ) {
+
+            // Usually, zero diffuse color means no diffuse color at all in the equation.
+            // So we omit this member to express this intent.
+            mout->AddProperty(&col,1,AI_MATKEY_COLOR_DIFFUSE);
+
+            if (mat->emit) {
+                aiColor3D emit_col(mat->emit * mat->r, mat->emit * mat->g, mat->emit * mat->b) ;
+                mout->AddProperty(&emit_col, 1, AI_MATKEY_COLOR_EMISSIVE) ;
+            }
+        }
+
+        col = aiColor3D(mat->specr,mat->specg,mat->specb);
+        mout->AddProperty(&col,1,AI_MATKEY_COLOR_SPECULAR);
+
+        // is hardness/shininess set?
+        if( mat->har ) {
+            const float har = mat->har;
+            mout->AddProperty(&har,1,AI_MATKEY_SHININESS);
+        }
+
+        col = aiColor3D(mat->ambr,mat->ambg,mat->ambb);
+        mout->AddProperty(&col,1,AI_MATKEY_COLOR_AMBIENT);
+
+        col = aiColor3D(mat->mirr,mat->mirg,mat->mirb);
+        mout->AddProperty(&col,1,AI_MATKEY_COLOR_REFLECTIVE);
+
+        for(size_t i = 0; i < sizeof(mat->mtex) / sizeof(mat->mtex[0]); ++i) {
+            if (!mat->mtex[i]) {
+                continue;
+            }
+
+            ResolveTexture(mout,mat.get(),mat->mtex[i].get(),conv_data);
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::CheckActualType(const ElemBase* dt, const char* check)
 {
-	ai_assert(dt);
-	if (strcmp(dt->dna_type,check)) {
-		ThrowException((format(),
-			"Expected object at ",std::hex,dt," to be of type `",check,
-			"`, but it claims to be a `",dt->dna_type,"`instead"
-		));
-	}
+    ai_assert(dt);
+    if (strcmp(dt->dna_type,check)) {
+        ThrowException((format(),
+            "Expected object at ",std::hex,dt," to be of type `",check,
+            "`, but it claims to be a `",dt->dna_type,"`instead"
+        ));
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::NotSupportedObjectType(const Object* obj, const char* type)
 {
-	LogWarn((format(), "Object `",obj->id.name,"` - type is unsupported: `",type, "`, skipping" ));
+    LogWarn((format(), "Object `",obj->id.name,"` - type is unsupported: `",type, "`, skipping" ));
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, const Mesh* mesh,
-	ConversionData& conv_data, TempArray<std::vector,aiMesh>&  temp
-	)
+    ConversionData& conv_data, TempArray<std::vector,aiMesh>&  temp
+    )
 {
-	// TODO: Resolve various problems with BMesh triangluation before re-enabling.
-	//       See issues #400, #373, #318  #315 and #132.
+    // TODO: Resolve various problems with BMesh triangluation before re-enabling.
+    //       See issues #400, #373, #318  #315 and #132.
 #if defined(TODO_FIX_BMESH_CONVERSION)
-	BlenderBMeshConverter BMeshConverter( mesh );
-	if ( BMeshConverter.ContainsBMesh( ) )
-	{
-		mesh = BMeshConverter.TriangulateBMesh( );
-	}
+    BlenderBMeshConverter BMeshConverter( mesh );
+    if ( BMeshConverter.ContainsBMesh( ) )
+    {
+        mesh = BMeshConverter.TriangulateBMesh( );
+    }
 #endif
 
-	typedef std::pair<const int,size_t> MyPair;
-	if ((!mesh->totface && !mesh->totloop) || !mesh->totvert) {
-		return;
-	}
-
-	// some sanity checks
-	if (static_cast<size_t> ( mesh->totface ) > mesh->mface.size() ){
-		ThrowException("Number of faces is larger than the corresponding array");
-	}
-
-	if (static_cast<size_t> ( mesh->totvert ) > mesh->mvert.size()) {
-		ThrowException("Number of vertices is larger than the corresponding array");
-	}
-
-	if (static_cast<size_t> ( mesh->totloop ) > mesh->mloop.size()) {
-		ThrowException("Number of vertices is larger than the corresponding array");
-	}
-
-	// collect per-submesh numbers
-	std::map<int,size_t> per_mat;
-	std::map<int,size_t> per_mat_verts;
-	for (int i = 0; i < mesh->totface; ++i) {
-
-		const MFace& mf = mesh->mface[i];
-		per_mat[ mf.mat_nr ]++;
-		per_mat_verts[ mf.mat_nr ] += mf.v4?4:3;
-	}
-
-	for (int i = 0; i < mesh->totpoly; ++i) {
-		const MPoly& mp = mesh->mpoly[i];
-		per_mat[ mp.mat_nr ]++;
-		per_mat_verts[ mp.mat_nr ] += mp.totloop;
-	}
-
-	// ... and allocate the corresponding meshes
-	const size_t old = temp->size();
-	temp->reserve(temp->size() + per_mat.size());
-
-	std::map<size_t,size_t> mat_num_to_mesh_idx;
-	for_each(MyPair& it, per_mat) {
-
-		mat_num_to_mesh_idx[it.first] = temp->size();
-		temp->push_back(new aiMesh());
-
-		aiMesh* out = temp->back();
-		out->mVertices = new aiVector3D[per_mat_verts[it.first]];
-		out->mNormals  = new aiVector3D[per_mat_verts[it.first]];
-
-		//out->mNumFaces = 0
-		//out->mNumVertices = 0
-		out->mFaces = new aiFace[it.second]();
-
-		// all submeshes created from this mesh are named equally. this allows
-		// curious users to recover the original adjacency.
-		out->mName = aiString(mesh->id.name+2);
-			// skip over the name prefix 'ME'
-
-		// resolve the material reference and add this material to the set of
-		// output materials. The (temporary) material index is the index
-		// of the material entry within the list of resolved materials.
-		if (mesh->mat) {
-
-			if (static_cast<size_t> ( it.first ) >= mesh->mat.size() ) {
-				ThrowException("Material index is out of range");
-			}
-
-			boost::shared_ptr<Material> mat = mesh->mat[it.first];
-			const std::deque< boost::shared_ptr<Material> >::iterator has = std::find(
-					conv_data.materials_raw.begin(),
-					conv_data.materials_raw.end(),mat
-			);
-
-			if (has != conv_data.materials_raw.end()) {
-				out->mMaterialIndex = static_cast<unsigned int>( std::distance(conv_data.materials_raw.begin(),has));
-			}
-			else {
-				out->mMaterialIndex = static_cast<unsigned int>( conv_data.materials_raw.size() );
-				conv_data.materials_raw.push_back(mat);
-			}
-		}
-		else out->mMaterialIndex = static_cast<unsigned int>( -1 );
-	}
-
-	for (int i = 0; i < mesh->totface; ++i) {
-
-		const MFace& mf = mesh->mface[i];
-
-		aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ];
-		aiFace& f = out->mFaces[out->mNumFaces++];
-
-		f.mIndices = new unsigned int[ f.mNumIndices = mf.v4?4:3 ];
-		aiVector3D* vo = out->mVertices + out->mNumVertices;
-		aiVector3D* vn = out->mNormals + out->mNumVertices;
-
-		// XXX we can't fold this easily, because we are restricted
-		// to the member names from the BLEND file (v1,v2,v3,v4)
-		// which are assigned by the genblenddna.py script and
-		// cannot be changed without breaking the entire
-		// import process.
-
-		if (mf.v1 >= mesh->totvert) {
-			ThrowException("Vertex index v1 out of range");
-		}
-		const MVert* v = &mesh->mvert[mf.v1];
-		vo->x = v->co[0];
-		vo->y = v->co[1];
-		vo->z = v->co[2];
-		vn->x = v->no[0];
-		vn->y = v->no[1];
-		vn->z = v->no[2];
-		f.mIndices[0] = out->mNumVertices++;
-		++vo;
-		++vn;
-
-		//	if (f.mNumIndices >= 2) {
-		if (mf.v2 >= mesh->totvert) {
-			ThrowException("Vertex index v2 out of range");
-		}
-		v = &mesh->mvert[mf.v2];
-		vo->x = v->co[0];
-		vo->y = v->co[1];
-		vo->z = v->co[2];
-		vn->x = v->no[0];
-		vn->y = v->no[1];
-		vn->z = v->no[2];
-		f.mIndices[1] = out->mNumVertices++;
-		++vo;
-		++vn;
-
-		if (mf.v3 >= mesh->totvert) {
-			ThrowException("Vertex index v3 out of range");
-		}
-		//	if (f.mNumIndices >= 3) {
-		v = &mesh->mvert[mf.v3];
-		vo->x = v->co[0];
-		vo->y = v->co[1];
-		vo->z = v->co[2];
-		vn->x = v->no[0];
-		vn->y = v->no[1];
-		vn->z = v->no[2];
-		f.mIndices[2] = out->mNumVertices++;
-		++vo;
-		++vn;
-
-		if (mf.v4 >= mesh->totvert) {
-			ThrowException("Vertex index v4 out of range");
-		}
-		//	if (f.mNumIndices >= 4) {
-		if (mf.v4) {
-			v = &mesh->mvert[mf.v4];
-			vo->x = v->co[0];
-			vo->y = v->co[1];
-			vo->z = v->co[2];
-			vn->x = v->no[0];
-			vn->y = v->no[1];
-			vn->z = v->no[2];
-			f.mIndices[3] = out->mNumVertices++;
-			++vo;
-			++vn;
-
-			out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
-		}
-		else out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
-
-		//	}
-		//	}
-		//	}
-	}
-
-	for (int i = 0; i < mesh->totpoly; ++i) {
-
-		const MPoly& mf = mesh->mpoly[i];
-
-		aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ];
-		aiFace& f = out->mFaces[out->mNumFaces++];
-
-		f.mIndices = new unsigned int[ f.mNumIndices = mf.totloop ];
-		aiVector3D* vo = out->mVertices + out->mNumVertices;
-		aiVector3D* vn = out->mNormals + out->mNumVertices;
-
-		// XXX we can't fold this easily, because we are restricted
-		// to the member names from the BLEND file (v1,v2,v3,v4)
-		// which are assigned by the genblenddna.py script and
-		// cannot be changed without breaking the entire
-		// import process.
-		for (int j = 0;j < mf.totloop; ++j)
-		{
-			const MLoop& loop = mesh->mloop[mf.loopstart + j];
-
-			if (loop.v >= mesh->totvert) {
-				ThrowException("Vertex index out of range");
-			}
-
-			const MVert& v = mesh->mvert[loop.v];
-
-			vo->x = v.co[0];
-			vo->y = v.co[1];
-			vo->z = v.co[2];
-			vn->x = v.no[0];
-			vn->y = v.no[1];
-			vn->z = v.no[2];
-			f.mIndices[j] = out->mNumVertices++;
-
-			++vo;
-			++vn;
-
-		}
-		if (mf.totloop == 3)
-		{
-			out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
-		}
-		else
-		{
-			out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
-		}
-	}
-
-	// collect texture coordinates, they're stored in a separate per-face buffer
-	if (mesh->mtface || mesh->mloopuv) {
-		if (mesh->totface > static_cast<int> ( mesh->mtface.size())) {
-			ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)");
-		}
-		for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
-			ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
-
-			(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
-			(*it)->mNumFaces = (*it)->mNumVertices = 0;
-		}
-
-		for (int i = 0; i < mesh->totface; ++i) {
-			const MTFace* v = &mesh->mtface[i];
-
-			aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
-			const aiFace& f = out->mFaces[out->mNumFaces++];
-
-			aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
-			for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
-				vo->x = v->uv[i][0];
-				vo->y = v->uv[i][1];
-			}
-		}
-
-		for (int i = 0; i < mesh->totpoly; ++i) {
-			const MPoly& v = mesh->mpoly[i];
-			aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
-			const aiFace& f = out->mFaces[out->mNumFaces++];
-
-			aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
-			for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
-				const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
-				vo->x = uv.uv[0];
-				vo->y = uv.uv[1];
-			}
-
-		}
-	}
-
-	// collect texture coordinates, old-style (marked as deprecated in current blender sources)
-	if (mesh->tface) {
-		if (mesh->totface > static_cast<int> ( mesh->tface.size())) {
-			ThrowException("Number of faces is larger than the corresponding UV face array (#2)");
-		}
-		for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
-			ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
-
-			(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
-			(*it)->mNumFaces = (*it)->mNumVertices = 0;
-		}
-
-		for (int i = 0; i < mesh->totface; ++i) {
-			const TFace* v = &mesh->tface[i];
-
-			aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
-			const aiFace& f = out->mFaces[out->mNumFaces++];
-
-			aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
-			for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
-				vo->x = v->uv[i][0];
-				vo->y = v->uv[i][1];
-			}
-		}
-	}
-
-	// collect vertex colors, stored separately as well
-	if (mesh->mcol || mesh->mloopcol) {
-		if (mesh->totface > static_cast<int> ( (mesh->mcol.size()/4)) ) {
-			ThrowException("Number of faces is larger than the corresponding color face array");
-		}
-		for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
-			ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
-
-			(*it)->mColors[0] = new aiColor4D[(*it)->mNumVertices];
-			(*it)->mNumFaces = (*it)->mNumVertices = 0;
-		}
-
-		for (int i = 0; i < mesh->totface; ++i) {
-
-			aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
-			const aiFace& f = out->mFaces[out->mNumFaces++];
-
-			aiColor4D* vo = &out->mColors[0][out->mNumVertices];
-			for (unsigned int n = 0; n < f.mNumIndices; ++n, ++vo,++out->mNumVertices) {
-				const MCol* col = &mesh->mcol[(i<<2)+n];
-
-				vo->r = col->r;
-				vo->g = col->g;
-				vo->b = col->b;
-				vo->a = col->a;
-			}
-			for (unsigned int n = f.mNumIndices; n < 4; ++n);
-		}
-
-		for (int i = 0; i < mesh->totpoly; ++i) {
-			const MPoly& v = mesh->mpoly[i];
-			aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
-			const aiFace& f = out->mFaces[out->mNumFaces++];
-
-			aiColor4D* vo = &out->mColors[0][out->mNumVertices];
-			for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
-				const MLoopCol& col = mesh->mloopcol[v.loopstart + j];
-				vo->r = col.r;
-				vo->g = col.g;
-				vo->b = col.b;
-				vo->a = col.a;
-			}
-
-		}
-
-	}
-
-	return;
+    typedef std::pair<const int,size_t> MyPair;
+    if ((!mesh->totface && !mesh->totloop) || !mesh->totvert) {
+        return;
+    }
+
+    // some sanity checks
+    if (static_cast<size_t> ( mesh->totface ) > mesh->mface.size() ){
+        ThrowException("Number of faces is larger than the corresponding array");
+    }
+
+    if (static_cast<size_t> ( mesh->totvert ) > mesh->mvert.size()) {
+        ThrowException("Number of vertices is larger than the corresponding array");
+    }
+
+    if (static_cast<size_t> ( mesh->totloop ) > mesh->mloop.size()) {
+        ThrowException("Number of vertices is larger than the corresponding array");
+    }
+
+    // collect per-submesh numbers
+    std::map<int,size_t> per_mat;
+    std::map<int,size_t> per_mat_verts;
+    for (int i = 0; i < mesh->totface; ++i) {
+
+        const MFace& mf = mesh->mface[i];
+        per_mat[ mf.mat_nr ]++;
+        per_mat_verts[ mf.mat_nr ] += mf.v4?4:3;
+    }
+
+    for (int i = 0; i < mesh->totpoly; ++i) {
+        const MPoly& mp = mesh->mpoly[i];
+        per_mat[ mp.mat_nr ]++;
+        per_mat_verts[ mp.mat_nr ] += mp.totloop;
+    }
+
+    // ... and allocate the corresponding meshes
+    const size_t old = temp->size();
+    temp->reserve(temp->size() + per_mat.size());
+
+    std::map<size_t,size_t> mat_num_to_mesh_idx;
+    for_each(MyPair& it, per_mat) {
+
+        mat_num_to_mesh_idx[it.first] = temp->size();
+        temp->push_back(new aiMesh());
+
+        aiMesh* out = temp->back();
+        out->mVertices = new aiVector3D[per_mat_verts[it.first]];
+        out->mNormals  = new aiVector3D[per_mat_verts[it.first]];
+
+        //out->mNumFaces = 0
+        //out->mNumVertices = 0
+        out->mFaces = new aiFace[it.second]();
+
+        // all submeshes created from this mesh are named equally. this allows
+        // curious users to recover the original adjacency.
+        out->mName = aiString(mesh->id.name+2);
+            // skip over the name prefix 'ME'
+
+        // resolve the material reference and add this material to the set of
+        // output materials. The (temporary) material index is the index
+        // of the material entry within the list of resolved materials.
+        if (mesh->mat) {
+
+            if (static_cast<size_t> ( it.first ) >= mesh->mat.size() ) {
+                ThrowException("Material index is out of range");
+            }
+
+            boost::shared_ptr<Material> mat = mesh->mat[it.first];
+            const std::deque< boost::shared_ptr<Material> >::iterator has = std::find(
+                    conv_data.materials_raw.begin(),
+                    conv_data.materials_raw.end(),mat
+            );
+
+            if (has != conv_data.materials_raw.end()) {
+                out->mMaterialIndex = static_cast<unsigned int>( std::distance(conv_data.materials_raw.begin(),has));
+            }
+            else {
+                out->mMaterialIndex = static_cast<unsigned int>( conv_data.materials_raw.size() );
+                conv_data.materials_raw.push_back(mat);
+            }
+        }
+        else out->mMaterialIndex = static_cast<unsigned int>( -1 );
+    }
+
+    for (int i = 0; i < mesh->totface; ++i) {
+
+        const MFace& mf = mesh->mface[i];
+
+        aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ];
+        aiFace& f = out->mFaces[out->mNumFaces++];
+
+        f.mIndices = new unsigned int[ f.mNumIndices = mf.v4?4:3 ];
+        aiVector3D* vo = out->mVertices + out->mNumVertices;
+        aiVector3D* vn = out->mNormals + out->mNumVertices;
+
+        // XXX we can't fold this easily, because we are restricted
+        // to the member names from the BLEND file (v1,v2,v3,v4)
+        // which are assigned by the genblenddna.py script and
+        // cannot be changed without breaking the entire
+        // import process.
+
+        if (mf.v1 >= mesh->totvert) {
+            ThrowException("Vertex index v1 out of range");
+        }
+        const MVert* v = &mesh->mvert[mf.v1];
+        vo->x = v->co[0];
+        vo->y = v->co[1];
+        vo->z = v->co[2];
+        vn->x = v->no[0];
+        vn->y = v->no[1];
+        vn->z = v->no[2];
+        f.mIndices[0] = out->mNumVertices++;
+        ++vo;
+        ++vn;
+
+        //  if (f.mNumIndices >= 2) {
+        if (mf.v2 >= mesh->totvert) {
+            ThrowException("Vertex index v2 out of range");
+        }
+        v = &mesh->mvert[mf.v2];
+        vo->x = v->co[0];
+        vo->y = v->co[1];
+        vo->z = v->co[2];
+        vn->x = v->no[0];
+        vn->y = v->no[1];
+        vn->z = v->no[2];
+        f.mIndices[1] = out->mNumVertices++;
+        ++vo;
+        ++vn;
+
+        if (mf.v3 >= mesh->totvert) {
+            ThrowException("Vertex index v3 out of range");
+        }
+        //  if (f.mNumIndices >= 3) {
+        v = &mesh->mvert[mf.v3];
+        vo->x = v->co[0];
+        vo->y = v->co[1];
+        vo->z = v->co[2];
+        vn->x = v->no[0];
+        vn->y = v->no[1];
+        vn->z = v->no[2];
+        f.mIndices[2] = out->mNumVertices++;
+        ++vo;
+        ++vn;
+
+        if (mf.v4 >= mesh->totvert) {
+            ThrowException("Vertex index v4 out of range");
+        }
+        //  if (f.mNumIndices >= 4) {
+        if (mf.v4) {
+            v = &mesh->mvert[mf.v4];
+            vo->x = v->co[0];
+            vo->y = v->co[1];
+            vo->z = v->co[2];
+            vn->x = v->no[0];
+            vn->y = v->no[1];
+            vn->z = v->no[2];
+            f.mIndices[3] = out->mNumVertices++;
+            ++vo;
+            ++vn;
+
+            out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+        }
+        else out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+
+        //  }
+        //  }
+        //  }
+    }
+
+    for (int i = 0; i < mesh->totpoly; ++i) {
+
+        const MPoly& mf = mesh->mpoly[i];
+
+        aiMesh* const out = temp[ mat_num_to_mesh_idx[ mf.mat_nr ] ];
+        aiFace& f = out->mFaces[out->mNumFaces++];
+
+        f.mIndices = new unsigned int[ f.mNumIndices = mf.totloop ];
+        aiVector3D* vo = out->mVertices + out->mNumVertices;
+        aiVector3D* vn = out->mNormals + out->mNumVertices;
+
+        // XXX we can't fold this easily, because we are restricted
+        // to the member names from the BLEND file (v1,v2,v3,v4)
+        // which are assigned by the genblenddna.py script and
+        // cannot be changed without breaking the entire
+        // import process.
+        for (int j = 0;j < mf.totloop; ++j)
+        {
+            const MLoop& loop = mesh->mloop[mf.loopstart + j];
+
+            if (loop.v >= mesh->totvert) {
+                ThrowException("Vertex index out of range");
+            }
+
+            const MVert& v = mesh->mvert[loop.v];
+
+            vo->x = v.co[0];
+            vo->y = v.co[1];
+            vo->z = v.co[2];
+            vn->x = v.no[0];
+            vn->y = v.no[1];
+            vn->z = v.no[2];
+            f.mIndices[j] = out->mNumVertices++;
+
+            ++vo;
+            ++vn;
+
+        }
+        if (mf.totloop == 3)
+        {
+            out->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+        }
+        else
+        {
+            out->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+        }
+    }
+
+    // collect texture coordinates, they're stored in a separate per-face buffer
+    if (mesh->mtface || mesh->mloopuv) {
+        if (mesh->totface > static_cast<int> ( mesh->mtface.size())) {
+            ThrowException("Number of UV faces is larger than the corresponding UV face array (#1)");
+        }
+        for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
+            ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
+
+            (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
+            (*it)->mNumFaces = (*it)->mNumVertices = 0;
+        }
+
+        for (int i = 0; i < mesh->totface; ++i) {
+            const MTFace* v = &mesh->mtface[i];
+
+            aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
+            const aiFace& f = out->mFaces[out->mNumFaces++];
+
+            aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
+            for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
+                vo->x = v->uv[i][0];
+                vo->y = v->uv[i][1];
+            }
+        }
+
+        for (int i = 0; i < mesh->totpoly; ++i) {
+            const MPoly& v = mesh->mpoly[i];
+            aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
+            const aiFace& f = out->mFaces[out->mNumFaces++];
+
+            aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
+            for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
+                const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
+                vo->x = uv.uv[0];
+                vo->y = uv.uv[1];
+            }
+
+        }
+    }
+
+    // collect texture coordinates, old-style (marked as deprecated in current blender sources)
+    if (mesh->tface) {
+        if (mesh->totface > static_cast<int> ( mesh->tface.size())) {
+            ThrowException("Number of faces is larger than the corresponding UV face array (#2)");
+        }
+        for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
+            ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
+
+            (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
+            (*it)->mNumFaces = (*it)->mNumVertices = 0;
+        }
+
+        for (int i = 0; i < mesh->totface; ++i) {
+            const TFace* v = &mesh->tface[i];
+
+            aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
+            const aiFace& f = out->mFaces[out->mNumFaces++];
+
+            aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
+            for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) {
+                vo->x = v->uv[i][0];
+                vo->y = v->uv[i][1];
+            }
+        }
+    }
+
+    // collect vertex colors, stored separately as well
+    if (mesh->mcol || mesh->mloopcol) {
+        if (mesh->totface > static_cast<int> ( (mesh->mcol.size()/4)) ) {
+            ThrowException("Number of faces is larger than the corresponding color face array");
+        }
+        for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
+            ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
+
+            (*it)->mColors[0] = new aiColor4D[(*it)->mNumVertices];
+            (*it)->mNumFaces = (*it)->mNumVertices = 0;
+        }
+
+        for (int i = 0; i < mesh->totface; ++i) {
+
+            aiMesh* const out = temp[ mat_num_to_mesh_idx[ mesh->mface[i].mat_nr ] ];
+            const aiFace& f = out->mFaces[out->mNumFaces++];
+
+            aiColor4D* vo = &out->mColors[0][out->mNumVertices];
+            for (unsigned int n = 0; n < f.mNumIndices; ++n, ++vo,++out->mNumVertices) {
+                const MCol* col = &mesh->mcol[(i<<2)+n];
+
+                vo->r = col->r;
+                vo->g = col->g;
+                vo->b = col->b;
+                vo->a = col->a;
+            }
+            for (unsigned int n = f.mNumIndices; n < 4; ++n);
+        }
+
+        for (int i = 0; i < mesh->totpoly; ++i) {
+            const MPoly& v = mesh->mpoly[i];
+            aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
+            const aiFace& f = out->mFaces[out->mNumFaces++];
+
+            aiColor4D* vo = &out->mColors[0][out->mNumVertices];
+            for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
+                const MLoopCol& col = mesh->mloopcol[v.loopstart + j];
+                vo->r = col.r;
+                vo->g = col.g;
+                vo->b = col.b;
+                vo->a = col.a;
+            }
+
+        }
+
+    }
+
+    return;
 }
 
 // ------------------------------------------------------------------------------------------------
 aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* /*camera*/, ConversionData& /*conv_data*/)
 {
-	ScopeGuard<aiCamera> out(new aiCamera());
-	out->mName = obj->id.name+2;
-	out->mPosition = aiVector3D(0.f, 0.f, 0.f);
-	out->mUp = aiVector3D(0.f, 1.f, 0.f);
-	out->mLookAt = aiVector3D(0.f, 0.f, -1.f);
-	return out.dismiss();
+    ScopeGuard<aiCamera> out(new aiCamera());
+    out->mName = obj->id.name+2;
+    out->mPosition = aiVector3D(0.f, 0.f, 0.f);
+    out->mUp = aiVector3D(0.f, 1.f, 0.f);
+    out->mLookAt = aiVector3D(0.f, 0.f, -1.f);
+    return out.dismiss();
 }
 
 // ------------------------------------------------------------------------------------------------
 aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, const Lamp* lamp, ConversionData& /*conv_data*/)
 {
-	ScopeGuard<aiLight> out(new aiLight());
-	out->mName = obj->id.name+2;
-
-	switch (lamp->type)
-	{
-	    case Lamp::Type_Local:
-	        out->mType = aiLightSource_POINT;
-	        break;
-	    case Lamp::Type_Sun:
-	        out->mType = aiLightSource_DIRECTIONAL;
-
-	        // blender orients directional lights as facing toward -z
-	        out->mDirection = aiVector3D(0.f, 0.f, -1.f);
-	        break;
-	    default:
-	        break;
-	}
-
-	out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
-	out->mColorSpecular = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
-	out->mColorDiffuse = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
-	return out.dismiss();
+    ScopeGuard<aiLight> out(new aiLight());
+    out->mName = obj->id.name+2;
+
+    switch (lamp->type)
+    {
+        case Lamp::Type_Local:
+            out->mType = aiLightSource_POINT;
+            break;
+        case Lamp::Type_Sun:
+            out->mType = aiLightSource_DIRECTIONAL;
+
+            // blender orients directional lights as facing toward -z
+            out->mDirection = aiVector3D(0.f, 0.f, -1.f);
+            break;
+        default:
+            break;
+    }
+
+    out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
+    out->mColorSpecular = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
+    out->mColorDiffuse = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
+    return out.dismiss();
 }
 
 // ------------------------------------------------------------------------------------------------
 aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, ConversionData& conv_data, const aiMatrix4x4& parentTransform)
 {
-	std::deque<const Object*> children;
-	for(ObjectSet::iterator it = conv_data.objects.begin(); it != conv_data.objects.end() ;) {
-		const Object* object = *it;
-		if (object->parent == obj) {
-			children.push_back(object);
-
-			conv_data.objects.erase(it++);
-			continue;
-		}
-		++it;
-	}
-
-	ScopeGuard<aiNode> node(new aiNode(obj->id.name+2)); // skip over the name prefix 'OB'
-	if (obj->data) {
-		switch (obj->type)
-		{
-		case Object :: Type_EMPTY:
-			break; // do nothing
-
-
-			// supported object types
-		case Object :: Type_MESH: {
-			const size_t old = conv_data.meshes->size();
-
-			CheckActualType(obj->data.get(),"Mesh");
-			ConvertMesh(in,obj,static_cast<const Mesh*>(obj->data.get()),conv_data,conv_data.meshes);
-
-			if (conv_data.meshes->size() > old) {
-				node->mMeshes = new unsigned int[node->mNumMeshes = static_cast<unsigned int>(conv_data.meshes->size()-old)];
-				for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
-					node->mMeshes[i] = i + old;
-				}
-			}}
-			break;
-		case Object :: Type_LAMP: {
-			CheckActualType(obj->data.get(),"Lamp");
-			aiLight* mesh = ConvertLight(in,obj,static_cast<const Lamp*>(
-				obj->data.get()),conv_data);
-
-			if (mesh) {
-				conv_data.lights->push_back(mesh);
-			}}
-			break;
-		case Object :: Type_CAMERA: {
-			CheckActualType(obj->data.get(),"Camera");
-			aiCamera* mesh = ConvertCamera(in,obj,static_cast<const Camera*>(
-				obj->data.get()),conv_data);
-
-			if (mesh) {
-				conv_data.cameras->push_back(mesh);
-			}}
-			break;
-
-
-			// unsupported object types / log, but do not break
-		case Object :: Type_CURVE:
-			NotSupportedObjectType(obj,"Curve");
-			break;
-		case Object :: Type_SURF:
-			NotSupportedObjectType(obj,"Surface");
-			break;
-		case Object :: Type_FONT:
-			NotSupportedObjectType(obj,"Font");
-			break;
-		case Object :: Type_MBALL:
-			NotSupportedObjectType(obj,"MetaBall");
-			break;
-		case Object :: Type_WAVE:
-			NotSupportedObjectType(obj,"Wave");
-			break;
-		case Object :: Type_LATTICE:
-			NotSupportedObjectType(obj,"Lattice");
-			break;
-
-			// invalid or unknown type
-		default:
-			break;
-		}
-	}
-
-	for(unsigned int x = 0; x < 4; ++x) {
-		for(unsigned int y = 0; y < 4; ++y) {
-			node->mTransformation[y][x] = obj->obmat[x][y];
-		}
-	}
-
-	aiMatrix4x4 m = parentTransform;
-	m = m.Inverse();
-
-	node->mTransformation = m*node->mTransformation;
-
-	if (children.size()) {
-		node->mNumChildren = static_cast<unsigned int>(children.size());
-		aiNode** nd = node->mChildren = new aiNode*[node->mNumChildren]();
-		for_each (const Object* nobj,children) {
-			*nd = ConvertNode(in,nobj,conv_data,node->mTransformation * parentTransform);
-			(*nd++)->mParent = node;
-		}
-	}
-
-	// apply modifiers
-	modifier_cache->ApplyModifiers(*node,conv_data,in,*obj);
-
-	return node.dismiss();
+    std::deque<const Object*> children;
+    for(ObjectSet::iterator it = conv_data.objects.begin(); it != conv_data.objects.end() ;) {
+        const Object* object = *it;
+        if (object->parent == obj) {
+            children.push_back(object);
+
+            conv_data.objects.erase(it++);
+            continue;
+        }
+        ++it;
+    }
+
+    ScopeGuard<aiNode> node(new aiNode(obj->id.name+2)); // skip over the name prefix 'OB'
+    if (obj->data) {
+        switch (obj->type)
+        {
+        case Object :: Type_EMPTY:
+            break; // do nothing
+
+
+            // supported object types
+        case Object :: Type_MESH: {
+            const size_t old = conv_data.meshes->size();
+
+            CheckActualType(obj->data.get(),"Mesh");
+            ConvertMesh(in,obj,static_cast<const Mesh*>(obj->data.get()),conv_data,conv_data.meshes);
+
+            if (conv_data.meshes->size() > old) {
+                node->mMeshes = new unsigned int[node->mNumMeshes = static_cast<unsigned int>(conv_data.meshes->size()-old)];
+                for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
+                    node->mMeshes[i] = i + old;
+                }
+            }}
+            break;
+        case Object :: Type_LAMP: {
+            CheckActualType(obj->data.get(),"Lamp");
+            aiLight* mesh = ConvertLight(in,obj,static_cast<const Lamp*>(
+                obj->data.get()),conv_data);
+
+            if (mesh) {
+                conv_data.lights->push_back(mesh);
+            }}
+            break;
+        case Object :: Type_CAMERA: {
+            CheckActualType(obj->data.get(),"Camera");
+            aiCamera* mesh = ConvertCamera(in,obj,static_cast<const Camera*>(
+                obj->data.get()),conv_data);
+
+            if (mesh) {
+                conv_data.cameras->push_back(mesh);
+            }}
+            break;
+
+
+            // unsupported object types / log, but do not break
+        case Object :: Type_CURVE:
+            NotSupportedObjectType(obj,"Curve");
+            break;
+        case Object :: Type_SURF:
+            NotSupportedObjectType(obj,"Surface");
+            break;
+        case Object :: Type_FONT:
+            NotSupportedObjectType(obj,"Font");
+            break;
+        case Object :: Type_MBALL:
+            NotSupportedObjectType(obj,"MetaBall");
+            break;
+        case Object :: Type_WAVE:
+            NotSupportedObjectType(obj,"Wave");
+            break;
+        case Object :: Type_LATTICE:
+            NotSupportedObjectType(obj,"Lattice");
+            break;
+
+            // invalid or unknown type
+        default:
+            break;
+        }
+    }
+
+    for(unsigned int x = 0; x < 4; ++x) {
+        for(unsigned int y = 0; y < 4; ++y) {
+            node->mTransformation[y][x] = obj->obmat[x][y];
+        }
+    }
+
+    aiMatrix4x4 m = parentTransform;
+    m = m.Inverse();
+
+    node->mTransformation = m*node->mTransformation;
+
+    if (children.size()) {
+        node->mNumChildren = static_cast<unsigned int>(children.size());
+        aiNode** nd = node->mChildren = new aiNode*[node->mNumChildren]();
+        for_each (const Object* nobj,children) {
+            *nd = ConvertNode(in,nobj,conv_data,node->mTransformation * parentTransform);
+            (*nd++)->mParent = node;
+        }
+    }
+
+    // apply modifiers
+    modifier_cache->ApplyModifiers(*node,conv_data,in,*obj);
+
+    return node.dismiss();
 }
 
 

+ 134 - 134
code/BlenderLoader.h

@@ -54,43 +54,43 @@ struct aiLight;
 struct aiCamera;
 struct aiMaterial;
 
-namespace Assimp	{
-
-	// TinyFormatter.h
-	namespace Formatter {
-		template <typename T,typename TR, typename A> class basic_formatter;
-		typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
-	}
-
-	// BlenderDNA.h
-	namespace Blender {
-		class  FileDatabase;
-		struct ElemBase;
-	}
-
-	// BlenderScene.h
-	namespace Blender {
-		struct Scene;
-		struct Object;
-		struct Mesh;
-		struct Camera;
-		struct Lamp;
-		struct MTex;
-		struct Image;
-		struct Material;
-	}
-
-	// BlenderIntermediate.h
-	namespace Blender {
-		struct ConversionData;
-		template <template <typename,typename> class TCLASS, typename T> struct TempArray;
-	}
-
-	// BlenderModifier.h
-	namespace Blender {
-		class BlenderModifierShowcase;
-		class BlenderModifier;
-	}
+namespace Assimp    {
+
+    // TinyFormatter.h
+    namespace Formatter {
+        template <typename T,typename TR, typename A> class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
+    }
+
+    // BlenderDNA.h
+    namespace Blender {
+        class  FileDatabase;
+        struct ElemBase;
+    }
+
+    // BlenderScene.h
+    namespace Blender {
+        struct Scene;
+        struct Object;
+        struct Mesh;
+        struct Camera;
+        struct Lamp;
+        struct MTex;
+        struct Image;
+        struct Material;
+    }
+
+    // BlenderIntermediate.h
+    namespace Blender {
+        struct ConversionData;
+        template <template <typename,typename> class TCLASS, typename T> struct TempArray;
+    }
+
+    // BlenderModifier.h
+    namespace Blender {
+        class BlenderModifierShowcase;
+        class BlenderModifier;
+    }
 
 
 
@@ -102,127 +102,127 @@ namespace Assimp	{
 class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter>
 {
 public:
-	BlenderImporter();
-	~BlenderImporter();
+    BlenderImporter();
+    ~BlenderImporter();
 
 
 public:
 
-	// --------------------
-	bool CanRead( const std::string& pFile,
-		IOSystem* pIOHandler,
-		bool checkSig
-	) const;
+    // --------------------
+    bool CanRead( const std::string& pFile,
+        IOSystem* pIOHandler,
+        bool checkSig
+    ) const;
 
 protected:
 
-	// --------------------
-	const aiImporterDesc* GetInfo () const;
+    // --------------------
+    const aiImporterDesc* GetInfo () const;
 
-	// --------------------
-	void GetExtensionList(std::set<std::string>& app);
+    // --------------------
+    void GetExtensionList(std::set<std::string>& app);
 
-	// --------------------
-	void SetupProperties(const Importer* pImp);
+    // --------------------
+    void SetupProperties(const Importer* pImp);
 
-	// --------------------
-	void InternReadFile( const std::string& pFile,
-		aiScene* pScene,
-		IOSystem* pIOHandler
-	);
+    // --------------------
+    void InternReadFile( const std::string& pFile,
+        aiScene* pScene,
+        IOSystem* pIOHandler
+    );
 
-	// --------------------
-	void ParseBlendFile(Blender::FileDatabase& out,
-		boost::shared_ptr<IOStream> stream
-	);
+    // --------------------
+    void ParseBlendFile(Blender::FileDatabase& out,
+        boost::shared_ptr<IOStream> stream
+    );
 
-	// --------------------
-	void ExtractScene(Blender::Scene& out,
-		const Blender::FileDatabase& file
-	);
+    // --------------------
+    void ExtractScene(Blender::Scene& out,
+        const Blender::FileDatabase& file
+    );
 
-	// --------------------
-	void ConvertBlendFile(aiScene* out,
-		const Blender::Scene& in,
-		const Blender::FileDatabase& file
-	);
+    // --------------------
+    void ConvertBlendFile(aiScene* out,
+        const Blender::Scene& in,
+        const Blender::FileDatabase& file
+    );
 
 private:
 
-	// --------------------
-	aiNode* ConvertNode(const Blender::Scene& in,
-		const Blender::Object* obj,
-		Blender::ConversionData& conv_info,
-		const aiMatrix4x4& parentTransform
-	);
-
-	// --------------------
-	void ConvertMesh(const Blender::Scene& in,
-		const Blender::Object* obj,
-		const Blender::Mesh* mesh,
-		Blender::ConversionData& conv_data,
-		Blender::TempArray<std::vector,aiMesh>& temp
-	);
-
-	// --------------------
-	aiLight* ConvertLight(const Blender::Scene& in,
-		const Blender::Object* obj,
-		const Blender::Lamp* mesh,
-		Blender::ConversionData& conv_data
-	);
-
-	// --------------------
-	aiCamera* ConvertCamera(const Blender::Scene& in,
-		const Blender::Object* obj,
-		const Blender::Camera* mesh,
-		Blender::ConversionData& conv_data
-	);
-
-	// --------------------
-	void BuildMaterials(
-		Blender::ConversionData& conv_data
-	) ;
-
-	// --------------------
-	void ResolveTexture(
-		aiMaterial* out,
-		const Blender::Material* mat,
-		const Blender::MTex* tex,
-		Blender::ConversionData& conv_data
-	);
-
-	// --------------------
-	void ResolveImage(
-		aiMaterial* out,
-		const Blender::Material* mat,
-		const Blender::MTex* tex,
-		const Blender::Image* img,
-		Blender::ConversionData& conv_data
-	);
-
-	void AddSentinelTexture(
-		aiMaterial* out,
-		const Blender::Material* mat,
-		const Blender::MTex* tex,
-		Blender::ConversionData& conv_data
-	);
+    // --------------------
+    aiNode* ConvertNode(const Blender::Scene& in,
+        const Blender::Object* obj,
+        Blender::ConversionData& conv_info,
+        const aiMatrix4x4& parentTransform
+    );
+
+    // --------------------
+    void ConvertMesh(const Blender::Scene& in,
+        const Blender::Object* obj,
+        const Blender::Mesh* mesh,
+        Blender::ConversionData& conv_data,
+        Blender::TempArray<std::vector,aiMesh>& temp
+    );
+
+    // --------------------
+    aiLight* ConvertLight(const Blender::Scene& in,
+        const Blender::Object* obj,
+        const Blender::Lamp* mesh,
+        Blender::ConversionData& conv_data
+    );
+
+    // --------------------
+    aiCamera* ConvertCamera(const Blender::Scene& in,
+        const Blender::Object* obj,
+        const Blender::Camera* mesh,
+        Blender::ConversionData& conv_data
+    );
+
+    // --------------------
+    void BuildMaterials(
+        Blender::ConversionData& conv_data
+    ) ;
+
+    // --------------------
+    void ResolveTexture(
+        aiMaterial* out,
+        const Blender::Material* mat,
+        const Blender::MTex* tex,
+        Blender::ConversionData& conv_data
+    );
+
+    // --------------------
+    void ResolveImage(
+        aiMaterial* out,
+        const Blender::Material* mat,
+        const Blender::MTex* tex,
+        const Blender::Image* img,
+        Blender::ConversionData& conv_data
+    );
+
+    void AddSentinelTexture(
+        aiMaterial* out,
+        const Blender::Material* mat,
+        const Blender::MTex* tex,
+        Blender::ConversionData& conv_data
+    );
 
 private: // static stuff, mostly logging and error reporting.
 
-	// --------------------
-	static void CheckActualType(const Blender::ElemBase* dt,
-		const char* check
-	);
+    // --------------------
+    static void CheckActualType(const Blender::ElemBase* dt,
+        const char* check
+    );
 
-	// --------------------
-	static void NotSupportedObjectType(const Blender::Object* obj,
-		const char* type
-	);
+    // --------------------
+    static void NotSupportedObjectType(const Blender::Object* obj,
+        const char* type
+    );
 
 
 private:
 
-	Blender::BlenderModifierShowcase* modifier_cache;
+    Blender::BlenderModifierShowcase* modifier_cache;
 
 }; // !class BlenderImporter
 

+ 204 - 204
code/BlenderModifier.cpp

@@ -58,120 +58,120 @@ using namespace Assimp;
 using namespace Assimp::Blender;
 
 template <typename T> BlenderModifier* god() {
-	return new T();
+    return new T();
 }
 
 // add all available modifiers here
 typedef BlenderModifier* (*fpCreateModifier)();
 static const fpCreateModifier creators[] = {
-		&god<BlenderModifier_Mirror>,
-		&god<BlenderModifier_Subdivision>,
+        &god<BlenderModifier_Mirror>,
+        &god<BlenderModifier_Subdivision>,
 
-		NULL // sentinel
+        NULL // sentinel
 };
 
 // ------------------------------------------------------------------------------------------------
 // just testing out some new macros to simplify logging
 #define ASSIMP_LOG_WARN_F(string,...)\
-	DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
+    DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
 
 #define ASSIMP_LOG_ERROR_F(string,...)\
-	DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
+    DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
 
 #define ASSIMP_LOG_DEBUG_F(string,...)\
-	DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
+    DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
 
 #define ASSIMP_LOG_INFO_F(string,...)\
-	DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
+    DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
 
 
 #define ASSIMP_LOG_WARN(string)\
-	DefaultLogger::get()->warn(string)
+    DefaultLogger::get()->warn(string)
 
 #define ASSIMP_LOG_ERROR(string)\
-	DefaultLogger::get()->error(string)
+    DefaultLogger::get()->error(string)
 
 #define ASSIMP_LOG_DEBUG(string)\
-	DefaultLogger::get()->debug(string)
+    DefaultLogger::get()->debug(string)
 
 #define ASSIMP_LOG_INFO(string)\
-	DefaultLogger::get()->info(string)
+    DefaultLogger::get()->info(string)
 
 
 // ------------------------------------------------------------------------------------------------
 struct SharedModifierData : ElemBase
 {
-	ModifierData modifier;
+    ModifierData modifier;
 };
 
 // ------------------------------------------------------------------------------------------------
 void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
 {
-	size_t cnt = 0u, ful = 0u;
-
-	// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
-	// we're allowed to dereference the pointers without risking to crash. We might still be
-	// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
-	// structures is at offset sizeof(vftable) with no padding.
-	const SharedModifierData* cur = boost::static_pointer_cast<const SharedModifierData> ( orig_object.modifiers.first.get() );
-	for (; cur; cur =  boost::static_pointer_cast<const SharedModifierData> ( cur->modifier.next.get() ), ++ful) {
-		ai_assert(cur->dna_type);
-
-		const Structure* s = conv_data.db.dna.Get( cur->dna_type );
-		if (!s) {
-			ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
-			continue;
-		}
-
-		// this is a common trait of all XXXMirrorData structures in BlenderDNA
-		const Field* f = s->Get("modifier");
-		if (!f || f->offset != 0) {
-			ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
-			continue;
-		}
-
-		s = conv_data.db.dna.Get( f->type );
-		if (!s || s->name != "ModifierData") {
-			ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
-			continue;
-		}
-
-		// now, we can be sure that we should be fine to dereference *cur* as
-		// ModifierData (with the above note).
-		const ModifierData& dat = cur->modifier;
-
-		const fpCreateModifier* curgod = creators;
-		std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
-
-		for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
-			if (curmod == endmod) {
-				cached_modifiers->push_back((*curgod)());
-
-				endmod = cached_modifiers->end();
-				curmod = endmod-1;
-			}
-
-			BlenderModifier* const modifier = *curmod;
-			if(modifier->IsActive(dat)) {
-				modifier->DoIt(out,conv_data,*boost::static_pointer_cast<const ElemBase>(cur),in,orig_object);
-				cnt++;
-
-				curgod = NULL;
-				break;
-			}
-		}
-		if (curgod) {
-			ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
-		}
-	}
-
-	// Even though we managed to resolve some or all of the modifiers on this
-	// object, we still can't say whether our modifier implementations were
-	// able to fully do their job.
-	if (ful) {
-		ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
-			"`, check log messages above for errors");
-	}
+    size_t cnt = 0u, ful = 0u;
+
+    // NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
+    // we're allowed to dereference the pointers without risking to crash. We might still be
+    // invoking UB btw - we're assuming that the ModifierData member of the respective modifier
+    // structures is at offset sizeof(vftable) with no padding.
+    const SharedModifierData* cur = boost::static_pointer_cast<const SharedModifierData> ( orig_object.modifiers.first.get() );
+    for (; cur; cur =  boost::static_pointer_cast<const SharedModifierData> ( cur->modifier.next.get() ), ++ful) {
+        ai_assert(cur->dna_type);
+
+        const Structure* s = conv_data.db.dna.Get( cur->dna_type );
+        if (!s) {
+            ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
+            continue;
+        }
+
+        // this is a common trait of all XXXMirrorData structures in BlenderDNA
+        const Field* f = s->Get("modifier");
+        if (!f || f->offset != 0) {
+            ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
+            continue;
+        }
+
+        s = conv_data.db.dna.Get( f->type );
+        if (!s || s->name != "ModifierData") {
+            ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
+            continue;
+        }
+
+        // now, we can be sure that we should be fine to dereference *cur* as
+        // ModifierData (with the above note).
+        const ModifierData& dat = cur->modifier;
+
+        const fpCreateModifier* curgod = creators;
+        std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
+
+        for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
+            if (curmod == endmod) {
+                cached_modifiers->push_back((*curgod)());
+
+                endmod = cached_modifiers->end();
+                curmod = endmod-1;
+            }
+
+            BlenderModifier* const modifier = *curmod;
+            if(modifier->IsActive(dat)) {
+                modifier->DoIt(out,conv_data,*boost::static_pointer_cast<const ElemBase>(cur),in,orig_object);
+                cnt++;
+
+                curgod = NULL;
+                break;
+            }
+        }
+        if (curgod) {
+            ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
+        }
+    }
+
+    // Even though we managed to resolve some or all of the modifiers on this
+    // object, we still can't say whether our modifier implementations were
+    // able to fully do their job.
+    if (ful) {
+        ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
+            "`, check log messages above for errors");
+    }
 }
 
 
@@ -179,102 +179,102 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
 // ------------------------------------------------------------------------------------------------
 bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
 {
-	return modin.type == ModifierData::eModifierType_Mirror;
+    return modin.type == ModifierData::eModifierType_Mirror;
 }
 
 // ------------------------------------------------------------------------------------------------
 void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier,
-	const Scene& /*in*/,
-	const Object& orig_object )
+    const Scene& /*in*/,
+    const Object& orig_object )
 {
-	// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
-	const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
-	ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
-
-	conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
-
-	// XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
-
-	// take all input meshes and clone them
-	for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
-		aiMesh* mesh;
-		SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
-
-		const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
-		const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
-		const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
-
-		if (mir.mirror_ob) {
-			const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				aiVector3D& v = mesh->mVertices[i];
-
-				v.x = center.x + xs*(center.x - v.x);
-				v.y = center.y + ys*(center.y - v.y);
-				v.z = center.z + zs*(center.z - v.z);
-			}
-		}
-		else {
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				aiVector3D& v = mesh->mVertices[i];
-				v.x *= xs;v.y *= ys;v.z *= zs;
-			}
-		}
-
-		if (mesh->mNormals) {
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				aiVector3D& v = mesh->mNormals[i];
-				v.x *= xs;v.y *= ys;v.z *= zs;
-			}
-		}
-
-		if (mesh->mTangents) {
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				aiVector3D& v = mesh->mTangents[i];
-				v.x *= xs;v.y *= ys;v.z *= zs;
-			}
-		}
-
-		if (mesh->mBitangents) {
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				aiVector3D& v = mesh->mBitangents[i];
-				v.x *= xs;v.y *= ys;v.z *= zs;
-			}
-		}
-
-		const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
-		const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
-
-		for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				aiVector3D& v = mesh->mTextureCoords[n][i];
-				v.x *= us;v.y *= vs;
-			}
-		}
-
-		// Only reverse the winding order if an odd number of axes were mirrored.
-		if (xs * ys * zs < 0) {
-			for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
-				aiFace& face = mesh->mFaces[i];
-				for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
-					std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
-			}
-		}
-
-		conv_data.meshes->push_back(mesh);
-	}
-	unsigned int* nind = new unsigned int[out.mNumMeshes*2];
-
-	std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
-	std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
-		std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
-
-	delete[] out.mMeshes;
-	out.mMeshes = nind;
-	out.mNumMeshes *= 2;
-
-	ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
-		orig_object.id.name,"`");
+    // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
+    const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
+    ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
+
+    conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
+
+    // XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
+
+    // take all input meshes and clone them
+    for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
+        aiMesh* mesh;
+        SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
+
+        const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
+        const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
+        const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
+
+        if (mir.mirror_ob) {
+            const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
+            for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                aiVector3D& v = mesh->mVertices[i];
+
+                v.x = center.x + xs*(center.x - v.x);
+                v.y = center.y + ys*(center.y - v.y);
+                v.z = center.z + zs*(center.z - v.z);
+            }
+        }
+        else {
+            for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                aiVector3D& v = mesh->mVertices[i];
+                v.x *= xs;v.y *= ys;v.z *= zs;
+            }
+        }
+
+        if (mesh->mNormals) {
+            for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                aiVector3D& v = mesh->mNormals[i];
+                v.x *= xs;v.y *= ys;v.z *= zs;
+            }
+        }
+
+        if (mesh->mTangents) {
+            for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                aiVector3D& v = mesh->mTangents[i];
+                v.x *= xs;v.y *= ys;v.z *= zs;
+            }
+        }
+
+        if (mesh->mBitangents) {
+            for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                aiVector3D& v = mesh->mBitangents[i];
+                v.x *= xs;v.y *= ys;v.z *= zs;
+            }
+        }
+
+        const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
+        const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
+
+        for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
+            for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                aiVector3D& v = mesh->mTextureCoords[n][i];
+                v.x *= us;v.y *= vs;
+            }
+        }
+
+        // Only reverse the winding order if an odd number of axes were mirrored.
+        if (xs * ys * zs < 0) {
+            for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
+                aiFace& face = mesh->mFaces[i];
+                for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
+                    std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
+            }
+        }
+
+        conv_data.meshes->push_back(mesh);
+    }
+    unsigned int* nind = new unsigned int[out.mNumMeshes*2];
+
+    std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
+    std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
+        std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
+
+    delete[] out.mMeshes;
+    out.mMeshes = nind;
+    out.mNumMeshes *= 2;
+
+    ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
+        orig_object.id.name,"`");
 }
 
 
@@ -283,46 +283,46 @@ void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  co
 // ------------------------------------------------------------------------------------------------
 bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
 {
-	return modin.type == ModifierData::eModifierType_Subsurf;
+    return modin.type == ModifierData::eModifierType_Subsurf;
 }
 
 // ------------------------------------------------------------------------------------------------
 void  BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data,  const ElemBase& orig_modifier,
-	const Scene& /*in*/,
-	const Object& orig_object )
+    const Scene& /*in*/,
+    const Object& orig_object )
 {
-	// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
-	const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
-	ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
-
-	Subdivider::Algorithm algo;
-	switch (mir.subdivType)
-	{
-	case SubsurfModifierData::TYPE_CatmullClarke:
-		algo = Subdivider::CATMULL_CLARKE;
-		break;
-
-	case SubsurfModifierData::TYPE_Simple:
-		ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
-		algo = Subdivider::CATMULL_CLARKE;
-		break;
-
-	default:
-		ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
-		return;
-	};
-
-	boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo));
-	ai_assert(subd);
-
-	aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
-	boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]());
-
-	subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
-	std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
-
-	ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
-		orig_object.id.name,"`");
+    // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
+    const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
+    ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
+
+    Subdivider::Algorithm algo;
+    switch (mir.subdivType)
+    {
+    case SubsurfModifierData::TYPE_CatmullClarke:
+        algo = Subdivider::CATMULL_CLARKE;
+        break;
+
+    case SubsurfModifierData::TYPE_Simple:
+        ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
+        algo = Subdivider::CATMULL_CLARKE;
+        break;
+
+    default:
+        ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
+        return;
+    };
+
+    boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo));
+    ai_assert(subd);
+
+    aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
+    boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]());
+
+    subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
+    std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
+
+    ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
+        orig_object.id.name,"`");
 }
 
 #endif

+ 48 - 48
code/BlenderModifier.h

@@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BlenderIntermediate.h"
 #include "TinyFormatter.h"
 namespace Assimp {
-	namespace Blender {
+    namespace Blender {
 
 // -------------------------------------------------------------------------------------------
 /** Dummy base class for all blender modifiers. Modifiers are reused between imports, so
@@ -57,30 +57,30 @@ class BlenderModifier
 {
 public:
 
-	virtual ~BlenderModifier() {
-	}
+    virtual ~BlenderModifier() {
+    }
 
 public:
 
-	// --------------------
-	/** Check if *this* modifier is active, given a ModifierData& block.*/
-	virtual bool IsActive( const ModifierData& /*modin*/) {
-		return false;
-	}
-
-	// --------------------
-	/** Apply the modifier to a given output node. The original data used
-	 *  to construct the node is given as well. Not called unless IsActive()
-	 *  was called and gave positive response. */
-	virtual void DoIt(aiNode& /*out*/,
-		ConversionData& /*conv_data*/,
-		const ElemBase& orig_modifier,
-		const Scene& /*in*/,
-		const Object& /*orig_object*/
-	) {
-		DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type));
-		return;
-	}
+    // --------------------
+    /** Check if *this* modifier is active, given a ModifierData& block.*/
+    virtual bool IsActive( const ModifierData& /*modin*/) {
+        return false;
+    }
+
+    // --------------------
+    /** Apply the modifier to a given output node. The original data used
+     *  to construct the node is given as well. Not called unless IsActive()
+     *  was called and gave positive response. */
+    virtual void DoIt(aiNode& /*out*/,
+        ConversionData& /*conv_data*/,
+        const ElemBase& orig_modifier,
+        const Scene& /*in*/,
+        const Object& /*orig_object*/
+    ) {
+        DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type));
+        return;
+    }
 };
 
 
@@ -91,17 +91,17 @@ class BlenderModifierShowcase
 {
 public:
 
-	// --------------------
-	/** Apply all requested modifiers provided we support them. */
-	void ApplyModifiers(aiNode& out,
-		ConversionData& conv_data,
-		const Scene& in,
-		const Object& orig_object
-	);
+    // --------------------
+    /** Apply all requested modifiers provided we support them. */
+    void ApplyModifiers(aiNode& out,
+        ConversionData& conv_data,
+        const Scene& in,
+        const Object& orig_object
+    );
 
 private:
 
-	TempArray< std::vector,BlenderModifier > cached_modifiers;
+    TempArray< std::vector,BlenderModifier > cached_modifiers;
 };
 
 
@@ -119,16 +119,16 @@ class BlenderModifier_Mirror : public BlenderModifier
 {
 public:
 
-	// --------------------
-	virtual bool IsActive( const ModifierData& modin);
+    // --------------------
+    virtual bool IsActive( const ModifierData& modin);
 
-	// --------------------
-	virtual void DoIt(aiNode& out,
-		ConversionData& conv_data,
-		const ElemBase& orig_modifier,
-		const Scene& in,
-		const Object& orig_object
-	) ;
+    // --------------------
+    virtual void DoIt(aiNode& out,
+        ConversionData& conv_data,
+        const ElemBase& orig_modifier,
+        const Scene& in,
+        const Object& orig_object
+    ) ;
 };
 
 // -------------------------------------------------------------------------------------------
@@ -138,16 +138,16 @@ class BlenderModifier_Subdivision : public BlenderModifier
 {
 public:
 
-	// --------------------
-	virtual bool IsActive( const ModifierData& modin);
+    // --------------------
+    virtual bool IsActive( const ModifierData& modin);
 
-	// --------------------
-	virtual void DoIt(aiNode& out,
-		ConversionData& conv_data,
-		const ElemBase& orig_modifier,
-		const Scene& in,
-		const Object& orig_object
-	) ;
+    // --------------------
+    virtual void DoIt(aiNode& out,
+        ConversionData& conv_data,
+        const ElemBase& orig_modifier,
+        const Scene& in,
+        const Object& orig_object
+    ) ;
 };
 
 

+ 55 - 55
code/BlenderScene.cpp

@@ -76,7 +76,7 @@ template <> void Structure :: Convert<Object> (
     ReadFieldPtr<ErrorPolicy_Fail>(dest.data,"*data",db);
     ReadField<ErrorPolicy_Igno>(dest.modifiers,"modifiers",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -90,7 +90,7 @@ template <> void Structure :: Convert<Group> (
     ReadField<ErrorPolicy_Igno>(dest.layer,"layer",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.gobject,"*gobject",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -129,7 +129,7 @@ template <> void Structure :: Convert<MTex> (
     ReadField<ErrorPolicy_Igno>(dest.hardfac,"hardfac",db);
     ReadField<ErrorPolicy_Igno>(dest.norfac,"norfac",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -146,7 +146,7 @@ template <> void Structure :: Convert<TFace> (
     ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
     ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -162,7 +162,7 @@ template <> void Structure :: Convert<SubsurfModifierData> (
     ReadField<ErrorPolicy_Igno>(dest.renderLevels,"renderLevels",db);
     ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -179,7 +179,7 @@ template <> void Structure :: Convert<MFace> (
     ReadField<ErrorPolicy_Fail>(dest.mat_nr,"mat_nr",db);
     ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -207,7 +207,7 @@ template <> void Structure :: Convert<Lamp> (
     ReadField<ErrorPolicy_Igno>((int&)dest.falloff_type,"falloff_type",db);
     ReadField<ErrorPolicy_Igno>(dest.sun_brightness,"sun_brightness",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -220,7 +220,7 @@ template <> void Structure :: Convert<MDeformWeight> (
     ReadField<ErrorPolicy_Fail>(dest.def_nr,"def_nr",db);
     ReadField<ErrorPolicy_Fail>(dest.weight,"weight",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -234,7 +234,7 @@ template <> void Structure :: Convert<PackedFile> (
     ReadField<ErrorPolicy_Warn>(dest.seek,"seek",db);
     ReadFieldPtr<ErrorPolicy_Warn>(dest.data,"*data",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -243,36 +243,36 @@ template <> void Structure :: Convert<Base> (
     const FileDatabase& db
     ) const
 {
-	// note: as per https://github.com/assimp/assimp/issues/128,
-	// reading the Object linked list recursively is prone to stack overflow.
-	// This structure converter is therefore an hand-written exception that
-	// does it iteratively.
+    // note: as per https://github.com/assimp/assimp/issues/128,
+    // reading the Object linked list recursively is prone to stack overflow.
+    // This structure converter is therefore an hand-written exception that
+    // does it iteratively.
 
-	const int initial_pos = db.reader->GetCurrentPos();
+    const int initial_pos = db.reader->GetCurrentPos();
 
-	std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
-	for ( ;; ) {
+    std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
+    for ( ;; ) {
 
-		Base& cur_dest = *todo.first;
-		db.reader->SetCurrentPos(todo.second);
+        Base& cur_dest = *todo.first;
+        db.reader->SetCurrentPos(todo.second);
 
-		// we know that this is a double-linked, circular list which we never
-		// traverse backwards, so don't bother resolving the back links.
-		cur_dest.prev = NULL;
+        // we know that this is a double-linked, circular list which we never
+        // traverse backwards, so don't bother resolving the back links.
+        cur_dest.prev = NULL;
 
-		ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
+        ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
 
-		// the return value of ReadFieldPtr indicates whether the object
-		// was already cached. In this case, we don't need to resolve
-		// it again.
-		if(!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next,"*next",db, true) && cur_dest.next) {
-			todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
-			continue;
-		}
-		break;
-	}
+        // the return value of ReadFieldPtr indicates whether the object
+        // was already cached. In this case, we don't need to resolve
+        // it again.
+        if(!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next,"*next",db, true) && cur_dest.next) {
+            todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
+            continue;
+        }
+        break;
+    }
 
-	db.reader->SetCurrentPos(initial_pos + size);
+    db.reader->SetCurrentPos(initial_pos + size);
 }
 
 //--------------------------------------------------------------------------------
@@ -288,7 +288,7 @@ template <> void Structure :: Convert<MTFace> (
     ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
     ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -324,7 +324,7 @@ template <> void Structure :: Convert<Material> (
     ReadField<ErrorPolicy_Warn>(dest.spec_shader,"spec_shader",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex,"*mtex",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -345,7 +345,7 @@ template <> void Structure :: Convert<MTexPoly> (
     ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
     ReadField<ErrorPolicy_Igno>(dest.pad,"pad",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -379,7 +379,7 @@ template <> void Structure :: Convert<Mesh> (
     ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db);
     ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -392,7 +392,7 @@ template <> void Structure :: Convert<MDeformVert> (
     ReadFieldPtr<ErrorPolicy_Warn>(dest.dw,"*dw",db);
     ReadField<ErrorPolicy_Igno>(dest.totweight,"totweight",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -404,7 +404,7 @@ template <> void Structure :: Convert<World> (
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -419,7 +419,7 @@ template <> void Structure :: Convert<MLoopCol> (
     ReadField<ErrorPolicy_Igno>(dest.b,"b",db);
     ReadField<ErrorPolicy_Igno>(dest.a,"a",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -435,7 +435,7 @@ template <> void Structure :: Convert<MVert> (
     ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
     ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -451,7 +451,7 @@ template <> void Structure :: Convert<MEdge> (
     ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db);
     ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -464,7 +464,7 @@ template <> void Structure :: Convert<MLoopUV> (
     ReadFieldArray<ErrorPolicy_Igno>(dest.uv,"uv",db);
     ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -478,7 +478,7 @@ template <> void Structure :: Convert<GroupObject> (
     ReadFieldPtr<ErrorPolicy_Fail>(dest.next,"*next",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.ob,"*ob",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -491,7 +491,7 @@ template <> void Structure :: Convert<ListBase> (
     ReadFieldPtr<ErrorPolicy_Igno>(dest.first,"*first",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.last,"*last",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -504,7 +504,7 @@ template <> void Structure :: Convert<MLoop> (
     ReadField<ErrorPolicy_Igno>(dest.v,"v",db);
     ReadField<ErrorPolicy_Igno>(dest.e,"e",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -520,7 +520,7 @@ template <> void Structure :: Convert<ModifierData> (
     ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.name,"name",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -533,7 +533,7 @@ template <> void Structure :: Convert<ID> (
     ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db);
     ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -548,7 +548,7 @@ template <> void Structure :: Convert<MCol> (
     ReadField<ErrorPolicy_Fail>(dest.b,"b",db);
     ReadField<ErrorPolicy_Fail>(dest.a,"a",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -563,7 +563,7 @@ template <> void Structure :: Convert<MPoly> (
     ReadField<ErrorPolicy_Igno>(dest.mat_nr,"mat_nr",db);
     ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -579,7 +579,7 @@ template <> void Structure :: Convert<Scene> (
     ReadFieldPtr<ErrorPolicy_Warn>(dest.basact,"*basact",db);
     ReadField<ErrorPolicy_Igno>(dest.base,"base",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -594,7 +594,7 @@ template <> void Structure :: Convert<Library> (
     ReadFieldArray<ErrorPolicy_Fail>(dest.filename,"filename",db);
     ReadFieldPtr<ErrorPolicy_Warn>(dest.parent,"*parent",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -607,7 +607,7 @@ template <> void Structure :: Convert<Tex> (
     ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
     ReadFieldPtr<ErrorPolicy_Warn>(dest.ima,"*ima",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -622,7 +622,7 @@ template <> void Structure :: Convert<Camera> (
     ReadField<ErrorPolicy_Warn>((int&)dest.flag,"flag",db);
     ReadField<ErrorPolicy_Warn>(dest.angle,"angle",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -638,7 +638,7 @@ template <> void Structure :: Convert<MirrorModifierData> (
     ReadField<ErrorPolicy_Igno>(dest.tolerance,"tolerance",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob,"*mirror_ob",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------
@@ -671,7 +671,7 @@ template <> void Structure :: Convert<Image> (
     ReadField<ErrorPolicy_Igno>(dest.gen_y,"gen_y",db);
     ReadField<ErrorPolicy_Igno>(dest.gen_type,"gen_type",db);
 
-	db.reader->IncPtr(size);
+    db.reader->IncPtr(size);
 }
 
 //--------------------------------------------------------------------------------

+ 400 - 400
code/BlenderScene.h

@@ -46,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "BlenderDNA.h"
 
-namespace Assimp	{
-	namespace Blender {
+namespace Assimp    {
+    namespace Blender {
 
 // Minor parts of this file are extracts from blender data structures,
 // declared in the ./source/blender/makesdna directory.
@@ -65,7 +65,7 @@ namespace Assimp	{
 //
 // * Structures may include the primitive types char, int, short,
 //   float, double. Signedness specifiers are not allowed on
-//	 integers. Enum types are allowed, but they must have been
+//   integers. Enum types are allowed, but they must have been
 //   defined in this header.
 //
 // * Structures may aggregate other structures, unless not defined
@@ -103,15 +103,15 @@ struct Image;
 // -------------------------------------------------------------------------------
 struct ID : ElemBase {
 
-	char name[24] WARN;
-	short flag;
+    char name[24] WARN;
+    short flag;
 };
 
 // -------------------------------------------------------------------------------
 struct ListBase : ElemBase {
 
-	boost::shared_ptr<ElemBase> first;
-	boost::shared_ptr<ElemBase> last;
+    boost::shared_ptr<ElemBase> first;
+    boost::shared_ptr<ElemBase> last;
 };
 
 
@@ -119,37 +119,37 @@ struct ListBase : ElemBase {
 struct PackedFile : ElemBase {
      int size WARN;
      int seek WARN;
-	 boost::shared_ptr< FileOffset > data WARN;
+     boost::shared_ptr< FileOffset > data WARN;
 };
 
 // -------------------------------------------------------------------------------
 struct GroupObject : ElemBase {
 
-	boost::shared_ptr<GroupObject> prev,next FAIL;
-	boost::shared_ptr<Object> ob;
+    boost::shared_ptr<GroupObject> prev,next FAIL;
+    boost::shared_ptr<Object> ob;
 };
 
 // -------------------------------------------------------------------------------
 struct Group : ElemBase {
-	ID id FAIL;
-	int layer;
+    ID id FAIL;
+    int layer;
 
-	boost::shared_ptr<GroupObject> gobject;
+    boost::shared_ptr<GroupObject> gobject;
 };
 
 // -------------------------------------------------------------------------------
 struct World : ElemBase {
-	ID id FAIL;
+    ID id FAIL;
 
 };
 
 // -------------------------------------------------------------------------------
 struct MVert : ElemBase {
-	float co[3] FAIL;
-	float no[3] FAIL;
-	char flag;
-	int mat_nr WARN;
-	int bweight;
+    float co[3] FAIL;
+    float no[3] FAIL;
+    char flag;
+    int mat_nr WARN;
+    int bweight;
 };
 
 // -------------------------------------------------------------------------------
@@ -161,68 +161,68 @@ struct MEdge : ElemBase {
 
 // -------------------------------------------------------------------------------
 struct MLoop : ElemBase {
-	int v, e;
+    int v, e;
 };
 
 // -------------------------------------------------------------------------------
 struct MLoopUV : ElemBase {
-	float uv[2];
-	int flag;
+    float uv[2];
+    int flag;
 };
 
 // -------------------------------------------------------------------------------
 // Note that red and blue are not swapped, as with MCol
 struct MLoopCol : ElemBase {
-	char r, g, b, a;
+    char r, g, b, a;
 };
 
 // -------------------------------------------------------------------------------
 struct MPoly : ElemBase {
-	int loopstart;
-	int totloop;
-	short mat_nr;
-	char flag;
+    int loopstart;
+    int totloop;
+    short mat_nr;
+    char flag;
 };
 
 // -------------------------------------------------------------------------------
 struct MTexPoly : ElemBase {
-	Image* tpage;
-	char flag, transp;
-	short mode, tile, pad;
+    Image* tpage;
+    char flag, transp;
+    short mode, tile, pad;
 };
 
 // -------------------------------------------------------------------------------
 struct MCol : ElemBase {
-	char r,g,b,a FAIL;
+    char r,g,b,a FAIL;
 };
 
 // -------------------------------------------------------------------------------
 struct MFace : ElemBase {
-	int v1,v2,v3,v4 FAIL;
-	int mat_nr FAIL;
-	char flag;
+    int v1,v2,v3,v4 FAIL;
+    int mat_nr FAIL;
+    char flag;
 };
 
 // -------------------------------------------------------------------------------
 struct TFace : ElemBase {
-	float uv[4][2] FAIL;
-	int col[4] FAIL;
-	char flag;
-	short mode;
-	short tile;
-	short unwrap;
+    float uv[4][2] FAIL;
+    int col[4] FAIL;
+    char flag;
+    short mode;
+    short tile;
+    short unwrap;
 };
 
 // -------------------------------------------------------------------------------
 struct MTFace : ElemBase {
 
-	float uv[4][2] FAIL;
-	char flag;
-	short mode;
-	short tile;
-	short unwrap;
+    float uv[4][2] FAIL;
+    char flag;
+    short mode;
+    short tile;
+    short unwrap;
 
-	// boost::shared_ptr<Image> tpage;
+    // boost::shared_ptr<Image> tpage;
 };
 
 // -------------------------------------------------------------------------------
@@ -234,124 +234,124 @@ struct MDeformWeight : ElemBase  {
 // -------------------------------------------------------------------------------
 struct MDeformVert : ElemBase  {
 
-	vector<MDeformWeight> dw WARN;
-	int totweight;
+    vector<MDeformWeight> dw WARN;
+    int totweight;
 };
 
 // -------------------------------------------------------------------------------
 struct Material : ElemBase {
-	ID id FAIL;
+    ID id FAIL;
 
-	float r,g,b WARN;
-	float specr,specg,specb WARN;
-	short har;
-	float ambr,ambg,ambb WARN;
-	float mirr,mirg,mirb;
-	float emit WARN;
-	float alpha WARN;
-	float ref;
-	float translucency;
-	float roughness;
-	float darkness;
-	float refrac;
+    float r,g,b WARN;
+    float specr,specg,specb WARN;
+    short har;
+    float ambr,ambg,ambb WARN;
+    float mirr,mirg,mirb;
+    float emit WARN;
+    float alpha WARN;
+    float ref;
+    float translucency;
+    float roughness;
+    float darkness;
+    float refrac;
 
-	boost::shared_ptr<Group> group;
+    boost::shared_ptr<Group> group;
 
-	short diff_shader WARN;
-	short spec_shader WARN;
+    short diff_shader WARN;
+    short spec_shader WARN;
 
-	boost::shared_ptr<MTex> mtex[18];
+    boost::shared_ptr<MTex> mtex[18];
 };
 
 // -------------------------------------------------------------------------------
 struct Mesh : ElemBase {
-	ID id FAIL;
+    ID id FAIL;
 
-	int totface FAIL;
-	int totedge FAIL;
-	int totvert FAIL;
-	int totloop;
-	int totpoly;
+    int totface FAIL;
+    int totedge FAIL;
+    int totvert FAIL;
+    int totloop;
+    int totpoly;
 
-	short subdiv;
-	short subdivr;
-	short subsurftype;
-	short smoothresh;
+    short subdiv;
+    short subdivr;
+    short subsurftype;
+    short smoothresh;
 
-	vector<MFace> mface FAIL;
-	vector<MTFace> mtface;
-	vector<TFace> tface;
-	vector<MVert> mvert FAIL;
-	vector<MEdge> medge WARN;
-	vector<MLoop> mloop;
-	vector<MLoopUV> mloopuv;
-	vector<MLoopCol> mloopcol;
-	vector<MPoly> mpoly;
-	vector<MTexPoly> mtpoly;
-	vector<MDeformVert> dvert;
-	vector<MCol> mcol;
+    vector<MFace> mface FAIL;
+    vector<MTFace> mtface;
+    vector<TFace> tface;
+    vector<MVert> mvert FAIL;
+    vector<MEdge> medge WARN;
+    vector<MLoop> mloop;
+    vector<MLoopUV> mloopuv;
+    vector<MLoopCol> mloopcol;
+    vector<MPoly> mpoly;
+    vector<MTexPoly> mtpoly;
+    vector<MDeformVert> dvert;
+    vector<MCol> mcol;
 
-	vector< boost::shared_ptr<Material> > mat FAIL;
+    vector< boost::shared_ptr<Material> > mat FAIL;
 };
 
 // -------------------------------------------------------------------------------
 struct Library : ElemBase {
-	ID id FAIL;
+    ID id FAIL;
 
-	char name[240] WARN;
-	char filename[240] FAIL;
-	boost::shared_ptr<Library> parent WARN;
+    char name[240] WARN;
+    char filename[240] FAIL;
+    boost::shared_ptr<Library> parent WARN;
 };
 
 // -------------------------------------------------------------------------------
 struct Camera : ElemBase {
-	enum Type {
-		  Type_PERSP	=	0
-		 ,Type_ORTHO	=	1
-	};
+    enum Type {
+          Type_PERSP    =   0
+         ,Type_ORTHO    =   1
+    };
 
-	ID id FAIL;
+    ID id FAIL;
 
-	// struct AnimData *adt;
+    // struct AnimData *adt;
 
-	Type type,flag WARN;
-	float angle WARN;
-	//float passepartalpha, angle;
-	//float clipsta, clipend;
-	//float lens, ortho_scale, drawsize;
-	//float shiftx, shifty;
+    Type type,flag WARN;
+    float angle WARN;
+    //float passepartalpha, angle;
+    //float clipsta, clipend;
+    //float lens, ortho_scale, drawsize;
+    //float shiftx, shifty;
 
-	//float YF_dofdist, YF_aperture;
-	//short YF_bkhtype, YF_bkhbias;
-	//float YF_bkhrot;
+    //float YF_dofdist, YF_aperture;
+    //short YF_bkhtype, YF_bkhbias;
+    //float YF_bkhrot;
 };
 
 
 // -------------------------------------------------------------------------------
 struct Lamp : ElemBase {
 
-	enum FalloffType {
-		 FalloffType_Constant	= 0x0
-		,FalloffType_InvLinear	= 0x1
-		,FalloffType_InvSquare	= 0x2
-		//,FalloffType_Curve	= 0x3
-		//,FalloffType_Sliders	= 0x4
-	};
-
-	enum Type {
-		 Type_Local			= 0x0
-		,Type_Sun			= 0x1
-		,Type_Spot			= 0x2
-		,Type_Hemi			= 0x3
-		,Type_Area			= 0x4
-		//,Type_YFPhoton	= 0x5
-	};
+    enum FalloffType {
+         FalloffType_Constant   = 0x0
+        ,FalloffType_InvLinear  = 0x1
+        ,FalloffType_InvSquare  = 0x2
+        //,FalloffType_Curve    = 0x3
+        //,FalloffType_Sliders  = 0x4
+    };
+
+    enum Type {
+         Type_Local         = 0x0
+        ,Type_Sun           = 0x1
+        ,Type_Spot          = 0x2
+        ,Type_Hemi          = 0x3
+        ,Type_Area          = 0x4
+        //,Type_YFPhoton    = 0x5
+    };
 
       ID id FAIL;
       //AnimData *adt;
 
       Type type FAIL;
-	  short flags;
+      short flags;
 
       //int mode;
 
@@ -374,33 +374,33 @@ struct Lamp : ElemBase {
       //short ray_samp, ray_sampy, ray_sampz;
       //short ray_samp_type;
       //short area_shape;
-	  //float area_size, area_sizey, area_sizez;
-	  //float adapt_thresh;
-	  //short ray_samp_method;
-
-	  //short texact, shadhalostep;
-
-	  //short sun_effect_type;
-	  //short skyblendtype;
-	  //float horizon_brightness;
-	  //float spread;
-	  float sun_brightness;
-	  //float sun_size;
-	  //float backscattered_light;
-	  //float sun_intensity;
-	  //float atm_turbidity;
-	  //float atm_inscattering_factor;
-	  //float atm_extinction_factor;
-	  //float atm_distance_factor;
-	  //float skyblendfac;
-	  //float sky_exposure;
-	  //short sky_colorspace;
-
-	  // int YF_numphotons, YF_numsearch;
-	  // short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
-	  // float YF_causticblur, YF_ltradius;
-
-	  // float YF_glowint, YF_glowofs;
+      //float area_size, area_sizey, area_sizez;
+      //float adapt_thresh;
+      //short ray_samp_method;
+
+      //short texact, shadhalostep;
+
+      //short sun_effect_type;
+      //short skyblendtype;
+      //float horizon_brightness;
+      //float spread;
+      float sun_brightness;
+      //float sun_size;
+      //float backscattered_light;
+      //float sun_intensity;
+      //float atm_turbidity;
+      //float atm_inscattering_factor;
+      //float atm_extinction_factor;
+      //float atm_distance_factor;
+      //float skyblendfac;
+      //float sky_exposure;
+      //short sky_colorspace;
+
+      // int YF_numphotons, YF_numsearch;
+      // short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
+      // float YF_causticblur, YF_ltradius;
+
+      // float YF_glowint, YF_glowofs;
       // short YF_glowtype, YF_pad2;
 
       //struct Ipo *ipo;
@@ -412,7 +412,7 @@ struct Lamp : ElemBase {
 
 // -------------------------------------------------------------------------------
 struct ModifierData : ElemBase  {
-	enum ModifierType {
+    enum ModifierType {
       eModifierType_None = 0,
       eModifierType_Subsurf,
       eModifierType_Lattice,
@@ -446,314 +446,314 @@ struct ModifierData : ElemBase  {
       eModifierType_Surface,
       eModifierType_Smoke,
       eModifierType_ShapeKey
-	};
+    };
 
-	boost::shared_ptr<ElemBase> next WARN;
-	boost::shared_ptr<ElemBase> prev WARN;
+    boost::shared_ptr<ElemBase> next WARN;
+    boost::shared_ptr<ElemBase> prev WARN;
 
-	int type, mode;
-	char name[32];
+    int type, mode;
+    char name[32];
 };
 
 // -------------------------------------------------------------------------------
 struct SubsurfModifierData : ElemBase  {
 
-	enum Type {
+    enum Type {
 
-		TYPE_CatmullClarke = 0x0,
-		TYPE_Simple = 0x1
-	};
+        TYPE_CatmullClarke = 0x0,
+        TYPE_Simple = 0x1
+    };
 
-	enum Flags {
-		// some omitted
-		FLAGS_SubsurfUV		=1<<3
-	};
+    enum Flags {
+        // some omitted
+        FLAGS_SubsurfUV     =1<<3
+    };
 
-	ModifierData modifier FAIL;
-	short subdivType WARN;
-	short levels FAIL;
-	short renderLevels ;
-	short flags;
+    ModifierData modifier FAIL;
+    short subdivType WARN;
+    short levels FAIL;
+    short renderLevels ;
+    short flags;
 };
 
 // -------------------------------------------------------------------------------
 struct MirrorModifierData : ElemBase {
 
-	enum Flags {
-		Flags_CLIPPING      =1<<0,
-		Flags_MIRROR_U      =1<<1,
-		Flags_MIRROR_V      =1<<2,
-		Flags_AXIS_X        =1<<3,
-		Flags_AXIS_Y        =1<<4,
-		Flags_AXIS_Z        =1<<5,
-		Flags_VGROUP        =1<<6
-	};
+    enum Flags {
+        Flags_CLIPPING      =1<<0,
+        Flags_MIRROR_U      =1<<1,
+        Flags_MIRROR_V      =1<<2,
+        Flags_AXIS_X        =1<<3,
+        Flags_AXIS_Y        =1<<4,
+        Flags_AXIS_Z        =1<<5,
+        Flags_VGROUP        =1<<6
+    };
 
-	ModifierData modifier FAIL;
+    ModifierData modifier FAIL;
 
-	short axis, flag;
-	float tolerance;
-	boost::shared_ptr<Object> mirror_ob;
+    short axis, flag;
+    float tolerance;
+    boost::shared_ptr<Object> mirror_ob;
 };
 
 // -------------------------------------------------------------------------------
 struct Object : ElemBase  {
-	ID id FAIL;
+    ID id FAIL;
 
-	enum Type {
-		 Type_EMPTY		=	0
-		,Type_MESH		=	1
-		,Type_CURVE		=	2
-		,Type_SURF		=   3
-		,Type_FONT		=   4
-		,Type_MBALL		=	5
+    enum Type {
+         Type_EMPTY     =   0
+        ,Type_MESH      =   1
+        ,Type_CURVE     =   2
+        ,Type_SURF      =   3
+        ,Type_FONT      =   4
+        ,Type_MBALL     =   5
 
-		,Type_LAMP		=	10
-		,Type_CAMERA	=   11
+        ,Type_LAMP      =   10
+        ,Type_CAMERA    =   11
 
-		,Type_WAVE		=   21
-		,Type_LATTICE	=   22
-	};
+        ,Type_WAVE      =   21
+        ,Type_LATTICE   =   22
+    };
 
-	Type type FAIL;
-	float obmat[4][4] WARN;
-	float parentinv[4][4] WARN;
-	char parsubstr[32] WARN;
+    Type type FAIL;
+    float obmat[4][4] WARN;
+    float parentinv[4][4] WARN;
+    char parsubstr[32] WARN;
 
-	Object* parent WARN;
-	boost::shared_ptr<Object> track WARN;
+    Object* parent WARN;
+    boost::shared_ptr<Object> track WARN;
 
-	boost::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
-	boost::shared_ptr<Group> dup_group WARN;
-	boost::shared_ptr<ElemBase> data FAIL;
+    boost::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
+    boost::shared_ptr<Group> dup_group WARN;
+    boost::shared_ptr<ElemBase> data FAIL;
 
-	ListBase modifiers;
+    ListBase modifiers;
 };
 
 
 // -------------------------------------------------------------------------------
 struct Base : ElemBase {
-	Base* prev WARN;
-	boost::shared_ptr<Base> next WARN;
-	boost::shared_ptr<Object> object WARN;
+    Base* prev WARN;
+    boost::shared_ptr<Base> next WARN;
+    boost::shared_ptr<Object> object WARN;
 };
 
 // -------------------------------------------------------------------------------
 struct Scene : ElemBase {
-	ID id FAIL;
+    ID id FAIL;
 
-	boost::shared_ptr<Object> camera WARN;
-	boost::shared_ptr<World> world WARN;
-	boost::shared_ptr<Base> basact WARN;
+    boost::shared_ptr<Object> camera WARN;
+    boost::shared_ptr<World> world WARN;
+    boost::shared_ptr<Base> basact WARN;
 
-	ListBase base;
+    ListBase base;
 };
 
 
 // -------------------------------------------------------------------------------
 struct Image : ElemBase {
-	ID id FAIL;
+    ID id FAIL;
 
-	char name[240] WARN;
+    char name[240] WARN;
 
-	//struct anim *anim;
+    //struct anim *anim;
 
-	short ok, flag;
-	short source, type, pad, pad1;
-	int lastframe;
+    short ok, flag;
+    short source, type, pad, pad1;
+    int lastframe;
 
-	short tpageflag, totbind;
-	short xrep, yrep;
-	short twsta, twend;
-	//unsigned int bindcode;
-	//unsigned int *repbind;
+    short tpageflag, totbind;
+    short xrep, yrep;
+    short twsta, twend;
+    //unsigned int bindcode;
+    //unsigned int *repbind;
 
-	boost::shared_ptr<PackedFile> packedfile;
-	//struct PreviewImage * preview;
+    boost::shared_ptr<PackedFile> packedfile;
+    //struct PreviewImage * preview;
 
-	float lastupdate;
-	int lastused;
-	short animspeed;
+    float lastupdate;
+    int lastused;
+    short animspeed;
 
-	short gen_x, gen_y, gen_type;
+    short gen_x, gen_y, gen_type;
 };
 
 // -------------------------------------------------------------------------------
 struct Tex : ElemBase {
 
-	// actually, the only texture type we support is Type_IMAGE
-	enum Type {
-		 Type_CLOUDS		= 1
-		,Type_WOOD			= 2
-		,Type_MARBLE		= 3
-		,Type_MAGIC			= 4
-		,Type_BLEND			= 5
-		,Type_STUCCI		= 6
-		,Type_NOISE			= 7
-		,Type_IMAGE			= 8
-		,Type_PLUGIN		= 9
-		,Type_ENVMAP		= 10
-		,Type_MUSGRAVE		= 11
-		,Type_VORONOI		= 12
-		,Type_DISTNOISE		= 13
-		,Type_POINTDENSITY	= 14
-		,Type_VOXELDATA		= 15
-	};
-
-	enum ImageFlags {
-	     ImageFlags_INTERPOL    	 = 1
-	    ,ImageFlags_USEALPHA    	 = 2
-	    ,ImageFlags_MIPMAP      	 = 4
-	    ,ImageFlags_IMAROT      	 = 16
-	    ,ImageFlags_CALCALPHA   	 = 32
-	    ,ImageFlags_NORMALMAP   	 = 2048
-	    ,ImageFlags_GAUSS_MIP   	 = 4096
-	    ,ImageFlags_FILTER_MIN  	 = 8192
-	    ,ImageFlags_DERIVATIVEMAP   = 16384
-	};
-
-	ID id FAIL;
-	// AnimData *adt;
-
-	//float noisesize, turbul;
-	//float bright, contrast, rfac, gfac, bfac;
-	//float filtersize;
-
-	//float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain;
-	//float dist_amount, ns_outscale;
-
-	//float vn_w1;
-	//float vn_w2;
-	//float vn_w3;
-	//float vn_w4;
-	//float vn_mexp;
-	//short vn_distm, vn_coltype;
-
-	//short noisedepth, noisetype;
-	//short noisebasis, noisebasis2;
-
-	//short flag;
-	ImageFlags imaflag;
-	Type type FAIL;
-	//short stype;
-
-	//float cropxmin, cropymin, cropxmax, cropymax;
-	//int texfilter;
-	//int afmax;
-	//short xrepeat, yrepeat;
-	//short extend;
-
-	//short fie_ima;
-	//int len;
-	//int frames, offset, sfra;
-
-	//float checkerdist, nabla;
-	//float norfac;
-
-	//ImageUser iuser;
-
-	//bNodeTree *nodetree;
-	//Ipo *ipo;
-	boost::shared_ptr<Image> ima WARN;
-	//PluginTex *plugin;
-	//ColorBand *coba;
-	//EnvMap *env;
-	//PreviewImage * preview;
-	//PointDensity *pd;
-	//VoxelData *vd;
-
-	//char use_nodes;
+    // actually, the only texture type we support is Type_IMAGE
+    enum Type {
+         Type_CLOUDS        = 1
+        ,Type_WOOD          = 2
+        ,Type_MARBLE        = 3
+        ,Type_MAGIC         = 4
+        ,Type_BLEND         = 5
+        ,Type_STUCCI        = 6
+        ,Type_NOISE         = 7
+        ,Type_IMAGE         = 8
+        ,Type_PLUGIN        = 9
+        ,Type_ENVMAP        = 10
+        ,Type_MUSGRAVE      = 11
+        ,Type_VORONOI       = 12
+        ,Type_DISTNOISE     = 13
+        ,Type_POINTDENSITY  = 14
+        ,Type_VOXELDATA     = 15
+    };
+
+    enum ImageFlags {
+         ImageFlags_INTERPOL         = 1
+        ,ImageFlags_USEALPHA         = 2
+        ,ImageFlags_MIPMAP           = 4
+        ,ImageFlags_IMAROT           = 16
+        ,ImageFlags_CALCALPHA        = 32
+        ,ImageFlags_NORMALMAP        = 2048
+        ,ImageFlags_GAUSS_MIP        = 4096
+        ,ImageFlags_FILTER_MIN       = 8192
+        ,ImageFlags_DERIVATIVEMAP   = 16384
+    };
+
+    ID id FAIL;
+    // AnimData *adt;
+
+    //float noisesize, turbul;
+    //float bright, contrast, rfac, gfac, bfac;
+    //float filtersize;
+
+    //float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain;
+    //float dist_amount, ns_outscale;
+
+    //float vn_w1;
+    //float vn_w2;
+    //float vn_w3;
+    //float vn_w4;
+    //float vn_mexp;
+    //short vn_distm, vn_coltype;
+
+    //short noisedepth, noisetype;
+    //short noisebasis, noisebasis2;
+
+    //short flag;
+    ImageFlags imaflag;
+    Type type FAIL;
+    //short stype;
+
+    //float cropxmin, cropymin, cropxmax, cropymax;
+    //int texfilter;
+    //int afmax;
+    //short xrepeat, yrepeat;
+    //short extend;
+
+    //short fie_ima;
+    //int len;
+    //int frames, offset, sfra;
+
+    //float checkerdist, nabla;
+    //float norfac;
+
+    //ImageUser iuser;
+
+    //bNodeTree *nodetree;
+    //Ipo *ipo;
+    boost::shared_ptr<Image> ima WARN;
+    //PluginTex *plugin;
+    //ColorBand *coba;
+    //EnvMap *env;
+    //PreviewImage * preview;
+    //PointDensity *pd;
+    //VoxelData *vd;
+
+    //char use_nodes;
 };
 
 // -------------------------------------------------------------------------------
 struct MTex : ElemBase {
 
-	enum Projection {
-		 Proj_N = 0
-		,Proj_X = 1
-		,Proj_Y = 2
-		,Proj_Z = 3
-	};
-
-	enum Flag {
-		 Flag_RGBTOINT		= 0x1
-		,Flag_STENCIL		= 0x2
-		,Flag_NEGATIVE		= 0x4
-		,Flag_ALPHAMIX		= 0x8
-		,Flag_VIEWSPACE		= 0x10
-	};
-
-	enum BlendType {
-		 BlendType_BLEND			= 0
-		,BlendType_MUL				= 1
-		,BlendType_ADD				= 2
-		,BlendType_SUB				= 3
-		,BlendType_DIV				= 4
-		,BlendType_DARK				= 5
-		,BlendType_DIFF				= 6
-		,BlendType_LIGHT			= 7
-		,BlendType_SCREEN			= 8
-		,BlendType_OVERLAY			= 9
-		,BlendType_BLEND_HUE		= 10
-		,BlendType_BLEND_SAT		= 11
-		,BlendType_BLEND_VAL		= 12
-		,BlendType_BLEND_COLOR		= 13
-	};
-
-	enum MapType {
-	     MapType_COL         = 1
-	    ,MapType_NORM        = 2
-	    ,MapType_COLSPEC     = 4
-	    ,MapType_COLMIR      = 8
-	    ,MapType_REF         = 16
-	    ,MapType_SPEC        = 32
-	    ,MapType_EMIT        = 64
-	    ,MapType_ALPHA       = 128
-	    ,MapType_HAR         = 256
-	    ,MapType_RAYMIRR     = 512
-	    ,MapType_TRANSLU     = 1024
-	    ,MapType_AMB         = 2048
-	    ,MapType_DISPLACE    = 4096
-	    ,MapType_WARP        = 8192
-	};
-
-	// short texco, maptoneg;
-	MapType mapto;
-
-	BlendType blendtype;
-	boost::shared_ptr<Object> object;
-	boost::shared_ptr<Tex> tex;
-	char uvname[32];
-
-	Projection projx,projy,projz;
-	char mapping;
-	float ofs[3], size[3], rot;
-
-	int texflag;
-	short colormodel, pmapto, pmaptoneg;
-	//short normapspace, which_output;
-	//char brush_map_mode;
-	float r,g,b,k WARN;
-	//float def_var, rt;
-
-	//float colfac, varfac;
-
-	float norfac;
-	//float dispfac, warpfac;
-	float colspecfac, mirrfac, alphafac;
-	float difffac, specfac, emitfac, hardfac;
-	//float raymirrfac, translfac, ambfac;
-	//float colemitfac, colreflfac, coltransfac;
-	//float densfac, scatterfac, reflfac;
-
-	//float timefac, lengthfac, clumpfac;
-	//float kinkfac, roughfac, padensfac;
-	//float lifefac, sizefac, ivelfac, pvelfac;
-	//float shadowfac;
-	//float zenupfac, zendownfac, blendfac;
-};
-
-
-	}
+    enum Projection {
+         Proj_N = 0
+        ,Proj_X = 1
+        ,Proj_Y = 2
+        ,Proj_Z = 3
+    };
+
+    enum Flag {
+         Flag_RGBTOINT      = 0x1
+        ,Flag_STENCIL       = 0x2
+        ,Flag_NEGATIVE      = 0x4
+        ,Flag_ALPHAMIX      = 0x8
+        ,Flag_VIEWSPACE     = 0x10
+    };
+
+    enum BlendType {
+         BlendType_BLEND            = 0
+        ,BlendType_MUL              = 1
+        ,BlendType_ADD              = 2
+        ,BlendType_SUB              = 3
+        ,BlendType_DIV              = 4
+        ,BlendType_DARK             = 5
+        ,BlendType_DIFF             = 6
+        ,BlendType_LIGHT            = 7
+        ,BlendType_SCREEN           = 8
+        ,BlendType_OVERLAY          = 9
+        ,BlendType_BLEND_HUE        = 10
+        ,BlendType_BLEND_SAT        = 11
+        ,BlendType_BLEND_VAL        = 12
+        ,BlendType_BLEND_COLOR      = 13
+    };
+
+    enum MapType {
+         MapType_COL         = 1
+        ,MapType_NORM        = 2
+        ,MapType_COLSPEC     = 4
+        ,MapType_COLMIR      = 8
+        ,MapType_REF         = 16
+        ,MapType_SPEC        = 32
+        ,MapType_EMIT        = 64
+        ,MapType_ALPHA       = 128
+        ,MapType_HAR         = 256
+        ,MapType_RAYMIRR     = 512
+        ,MapType_TRANSLU     = 1024
+        ,MapType_AMB         = 2048
+        ,MapType_DISPLACE    = 4096
+        ,MapType_WARP        = 8192
+    };
+
+    // short texco, maptoneg;
+    MapType mapto;
+
+    BlendType blendtype;
+    boost::shared_ptr<Object> object;
+    boost::shared_ptr<Tex> tex;
+    char uvname[32];
+
+    Projection projx,projy,projz;
+    char mapping;
+    float ofs[3], size[3], rot;
+
+    int texflag;
+    short colormodel, pmapto, pmaptoneg;
+    //short normapspace, which_output;
+    //char brush_map_mode;
+    float r,g,b,k WARN;
+    //float def_var, rt;
+
+    //float colfac, varfac;
+
+    float norfac;
+    //float dispfac, warpfac;
+    float colspecfac, mirrfac, alphafac;
+    float difffac, specfac, emitfac, hardfac;
+    //float raymirrfac, translfac, ambfac;
+    //float colemitfac, colreflfac, coltransfac;
+    //float densfac, scatterfac, reflfac;
+
+    //float timefac, lengthfac, clumpfac;
+    //float kinkfac, roughfac, padensfac;
+    //float lifefac, sizefac, ivelfac, pvelfac;
+    //float shadowfac;
+    //float zenupfac, zendownfac, blendfac;
+};
+
+
+    }
 }
 #endif

+ 3 - 3
code/BlenderSceneGen.h

@@ -47,8 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BlenderDNA.h"
 #include "BlenderScene.h"
 
-namespace Assimp	{
-	namespace Blender {
+namespace Assimp    {
+    namespace Blender {
 
 
 template <> void Structure :: Convert<Object> (
@@ -250,7 +250,7 @@ template <> void Structure :: Convert<Image> (
 ;
 
 
-	}
+    }
 }
 
 #endif

+ 252 - 252
code/BlenderTessellator.cpp

@@ -56,7 +56,7 @@ static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3;
 
 namspace Assimp
 {
-	template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
+    template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
 }
 
 using namespace Assimp;
@@ -68,7 +68,7 @@ using namespace Assimp::Blender;
 
 // ------------------------------------------------------------------------------------------------
 BlenderTessellatorGL::BlenderTessellatorGL( BlenderBMeshConverter& converter ):
-	converter( &converter )
+    converter( &converter )
 {
 }
 
@@ -80,167 +80,167 @@ BlenderTessellatorGL::~BlenderTessellatorGL( )
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
 {
-	AssertVertexCount( vertexCount );
+    AssertVertexCount( vertexCount );
 
-	std::vector< VertexGL > polyLoopGL;
-	GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices );
+    std::vector< VertexGL > polyLoopGL;
+    GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices );
 
-	TessDataGL tessData;
-	Tesssellate( polyLoopGL, tessData );
+    TessDataGL tessData;
+    Tesssellate( polyLoopGL, tessData );
 
-	TriangulateDrawCalls( tessData );
+    TriangulateDrawCalls( tessData );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::AssertVertexCount( int vertexCount )
 {
-	if ( vertexCount <= 4 )
-	{
-		ThrowException( "Expected more than 4 vertices for tessellation" );
-	}
+    if ( vertexCount <= 4 )
+    {
+        ThrowException( "Expected more than 4 vertices for tessellation" );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::GenerateLoopVerts( std::vector< VertexGL >& polyLoopGL, const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
 {
-	for ( int i = 0; i < vertexCount; ++i )
-	{
-		const MLoop& loopItem = polyLoop[ i ];
-		const MVert& vertex = vertices[ loopItem.v ];
-		polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) );
-	}
+    for ( int i = 0; i < vertexCount; ++i )
+    {
+        const MLoop& loopItem = polyLoop[ i ];
+        const MVert& vertex = vertices[ loopItem.v ];
+        polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::Tesssellate( std::vector< VertexGL >& polyLoopGL, TessDataGL& tessData )
 {
-	GLUtesselator* tessellator = gluNewTess( );
-	gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) );
-	gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) );
-	gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) );
-	gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) );
-	gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) );
-	gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) );
-	gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO );
+    GLUtesselator* tessellator = gluNewTess( );
+    gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) );
+    gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) );
+    gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) );
+    gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) );
+    gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) );
+    gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) );
+    gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO );
 
-	gluTessBeginPolygon( tessellator, &tessData );
-	gluTessBeginContour( tessellator );
+    gluTessBeginPolygon( tessellator, &tessData );
+    gluTessBeginContour( tessellator );
 
-	for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i )
-	{
-		gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] );
-	}
+    for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i )
+    {
+        gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] );
+    }
 
-	gluTessEndContour( tessellator );
-	gluTessEndPolygon( tessellator );
+    gluTessEndContour( tessellator );
+    gluTessEndPolygon( tessellator );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::TriangulateDrawCalls( const TessDataGL& tessData )
 {
-	// NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically
-	//        need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case
-	//        GLU tessellate changes or tristrips and fans are wanted.
-	//        See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml
-	for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i )
-	{
-		const DrawCallGL& drawCallGL = tessData.drawCalls[ i ];
-		const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ];
-		if ( drawCallGL.drawMode == GL_TRIANGLES )
-		{
-			MakeFacesFromTris( vertices, drawCallGL.vertexCount );
-		}
-		else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP )
-		{
-			MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount );
-		}
-		else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN )
-		{
-			MakeFacesFromTriFan( vertices, drawCallGL.vertexCount );
-		}
-	}
+    // NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically
+    //        need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case
+    //        GLU tessellate changes or tristrips and fans are wanted.
+    //        See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml
+    for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i )
+    {
+        const DrawCallGL& drawCallGL = tessData.drawCalls[ i ];
+        const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ];
+        if ( drawCallGL.drawMode == GL_TRIANGLES )
+        {
+            MakeFacesFromTris( vertices, drawCallGL.vertexCount );
+        }
+        else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP )
+        {
+            MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount );
+        }
+        else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN )
+        {
+            MakeFacesFromTriFan( vertices, drawCallGL.vertexCount );
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::MakeFacesFromTris( const VertexGL* vertices, int vertexCount )
 {
-	int triangleCount = vertexCount / 3;
-	for ( int i = 0; i < triangleCount; ++i )
-	{
-		int vertexBase = i * 3;
-		converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
-	}
+    int triangleCount = vertexCount / 3;
+    for ( int i = 0; i < triangleCount; ++i )
+    {
+        int vertexBase = i * 3;
+        converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::MakeFacesFromTriStrip( const VertexGL* vertices, int vertexCount )
 {
-	int triangleCount = vertexCount - 2;
-	for ( int i = 0; i < triangleCount; ++i )
-	{
-		int vertexBase = i;
-		converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
-	}
+    int triangleCount = vertexCount - 2;
+    for ( int i = 0; i < triangleCount; ++i )
+    {
+        int vertexBase = i;
+        converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::MakeFacesFromTriFan( const VertexGL* vertices, int vertexCount )
 {
-	int triangleCount = vertexCount - 2;
-	for ( int i = 0; i < triangleCount; ++i )
-	{
-		int vertexBase = i;
-		converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
-	}
+    int triangleCount = vertexCount - 2;
+    for ( int i = 0; i < triangleCount; ++i )
+    {
+        int vertexBase = i;
+        converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::TessellateBegin( GLenum drawModeGL, void* userData )
 {
-	TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
-	tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) );
+    TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
+    tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::TessellateEnd( void* )
 {
-	// Do nothing
+    // Do nothing
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::TessellateVertex( const void* vtxData, void* userData )
 {
-	TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
+    TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
 
-	const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData );
-	if ( vertex.magic != BLEND_TESS_MAGIC )
-	{
-		ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" );
-	}
-	tessData.vertices.push_back( vertex );
-	if ( tessData.drawCalls.size( ) == 0 )
-	{
-		ThrowException( "\"Vertex\" callback received before \"Begin\"" );
-	}
-	++( tessData.drawCalls.back( ).vertexCount );
+    const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData );
+    if ( vertex.magic != BLEND_TESS_MAGIC )
+    {
+        ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" );
+    }
+    tessData.vertices.push_back( vertex );
+    if ( tessData.drawCalls.size( ) == 0 )
+    {
+        ThrowException( "\"Vertex\" callback received before \"Begin\"" );
+    }
+    ++( tessData.drawCalls.back( ).vertexCount );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData )
 {
-	ThrowException( "Intersected polygon loops are not yet supported" );
+    ThrowException( "Intersected polygon loops are not yet supported" );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::TessellateEdgeFlag( GLboolean, void* )
 {
-	// Do nothing
+    // Do nothing
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
 {
-	ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) );
+    ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) );
 }
 
 #endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
@@ -249,7 +249,7 @@ void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
 
 namespace Assimp
 {
-	template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
+    template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
 }
 
 using namespace Assimp;
@@ -257,7 +257,7 @@ using namespace Assimp::Blender;
 
 // ------------------------------------------------------------------------------------------------
 BlenderTessellatorP2T::BlenderTessellatorP2T( BlenderBMeshConverter& converter ):
-	converter( &converter )
+    converter( &converter )
 {
 }
 
@@ -269,178 +269,178 @@ BlenderTessellatorP2T::~BlenderTessellatorP2T( )
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorP2T::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
 {
-	AssertVertexCount( vertexCount );
+    AssertVertexCount( vertexCount );
 
-	// NOTE - We have to hope that points in a Blender polygon are roughly on the same plane.
-	//        There may be some triangulation artifacts if they are wildly different.
+    // NOTE - We have to hope that points in a Blender polygon are roughly on the same plane.
+    //        There may be some triangulation artifacts if they are wildly different.
 
-	std::vector< PointP2T > points;
-	Copy3DVertices( polyLoop, vertexCount, vertices, points );
+    std::vector< PointP2T > points;
+    Copy3DVertices( polyLoop, vertexCount, vertices, points );
 
-	PlaneP2T plane = FindLLSQPlane( points );
+    PlaneP2T plane = FindLLSQPlane( points );
 
-	aiMatrix4x4 transform = GeneratePointTransformMatrix( plane );
+    aiMatrix4x4 transform = GeneratePointTransformMatrix( plane );
 
-	TransformAndFlattenVectices( transform, points );
+    TransformAndFlattenVectices( transform, points );
 
-	std::vector< p2t::Point* > pointRefs;
-	ReferencePoints( points, pointRefs );
+    std::vector< p2t::Point* > pointRefs;
+    ReferencePoints( points, pointRefs );
 
-	p2t::CDT cdt( pointRefs );
+    p2t::CDT cdt( pointRefs );
 
-	cdt.Triangulate( );
-	std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( );
+    cdt.Triangulate( );
+    std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( );
 
-	MakeFacesFromTriangles( triangles );
+    MakeFacesFromTriangles( triangles );
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorP2T::AssertVertexCount( int vertexCount )
 {
-	if ( vertexCount <= 4 )
-	{
-		ThrowException( "Expected more than 4 vertices for tessellation" );
-	}
+    if ( vertexCount <= 4 )
+    {
+        ThrowException( "Expected more than 4 vertices for tessellation" );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorP2T::Copy3DVertices( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices, std::vector< PointP2T >& points ) const
 {
-	points.resize( vertexCount );
-	for ( int i = 0; i < vertexCount; ++i )
-	{
-		const MLoop& loop = polyLoop[ i ];
-		const MVert& vert = vertices[ loop.v ];
+    points.resize( vertexCount );
+    for ( int i = 0; i < vertexCount; ++i )
+    {
+        const MLoop& loop = polyLoop[ i ];
+        const MVert& vert = vertices[ loop.v ];
 
-		PointP2T& point = points[ i ];
-		point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] );
-		point.index = loop.v;
-		point.magic = BLEND_TESS_MAGIC;
-	}
+        PointP2T& point = points[ i ];
+        point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] );
+        point.index = loop.v;
+        point.magic = BLEND_TESS_MAGIC;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const
 {
-	aiVector3D sideA( 1.0f, 0.0f, 0.0f );
-	if ( std::fabs( plane.normal * sideA ) > 0.999f )
-	{
-		sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
-	}
-
-	aiVector3D sideB( plane.normal ^ sideA );
-	sideB.Normalize( );
-	sideA = sideB ^ plane.normal;
-
-	aiMatrix4x4 result;
-	result.a1 = sideA.x;
-	result.a2 = sideA.y;
-	result.a3 = sideA.z;
-	result.b1 = sideB.x;
-	result.b2 = sideB.y;
-	result.b3 = sideB.z;
-	result.c1 = plane.normal.x;
-	result.c2 = plane.normal.y;
-	result.c3 = plane.normal.z;
-	result.a4 = plane.centre.x;
-	result.b4 = plane.centre.y;
-	result.c4 = plane.centre.z;
-	result.Inverse( );
-
-	return result;
+    aiVector3D sideA( 1.0f, 0.0f, 0.0f );
+    if ( std::fabs( plane.normal * sideA ) > 0.999f )
+    {
+        sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
+    }
+
+    aiVector3D sideB( plane.normal ^ sideA );
+    sideB.Normalize( );
+    sideA = sideB ^ plane.normal;
+
+    aiMatrix4x4 result;
+    result.a1 = sideA.x;
+    result.a2 = sideA.y;
+    result.a3 = sideA.z;
+    result.b1 = sideB.x;
+    result.b2 = sideB.y;
+    result.b3 = sideB.z;
+    result.c1 = plane.normal.x;
+    result.c2 = plane.normal.y;
+    result.c3 = plane.normal.z;
+    result.a4 = plane.centre.x;
+    result.b4 = plane.centre.y;
+    result.c4 = plane.centre.z;
+    result.Inverse( );
+
+    return result;
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorP2T::TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const
 {
-	for ( unsigned int i = 0; i < vertices.size( ); ++i )
-	{
-		PointP2T& point = vertices[ i ];
-		point.point3D = transform * point.point3D;
-		point.point2D.set( point.point3D.y, point.point3D.z );
-	}
+    for ( unsigned int i = 0; i < vertices.size( ); ++i )
+    {
+        PointP2T& point = vertices[ i ];
+        point.point3D = transform * point.point3D;
+        point.point2D.set( point.point3D.y, point.point3D.z );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const
 {
-	pointRefs.resize( points.size( ) );
-	for ( unsigned int i = 0; i < points.size( ); ++i )
-	{
-		pointRefs[ i ] = &points[ i ].point2D;
-	}
+    pointRefs.resize( points.size( ) );
+    for ( unsigned int i = 0; i < points.size( ); ++i )
+    {
+        pointRefs[ i ] = &points[ i ].point2D;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Yes this is filthy... but we have no choice
 #define OffsetOf( Class, Member ) ( static_cast< unsigned int >( \
-	reinterpret_cast<uint8_t*>(&( reinterpret_cast< Class* >( NULL )->*( &Class::Member ) )) - \
-	static_cast<uint8_t*>(NULL) ) )
+    reinterpret_cast<uint8_t*>(&( reinterpret_cast< Class* >( NULL )->*( &Class::Member ) )) - \
+    static_cast<uint8_t*>(NULL) ) )
 
 inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
 {
-	unsigned int pointOffset = OffsetOf( PointP2T, point2D );
-	PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
-	if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
-	{
-		ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
-	}
-	return pointStruct;
+    unsigned int pointOffset = OffsetOf( PointP2T, point2D );
+    PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
+    if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
+    {
+        ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
+    }
+    return pointStruct;
 }
 
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
 {
-	for ( unsigned int i = 0; i < triangles.size( ); ++i )
-	{
-		p2t::Triangle& Triangle = *triangles[ i ];
+    for ( unsigned int i = 0; i < triangles.size( ); ++i )
+    {
+        p2t::Triangle& Triangle = *triangles[ i ];
 
-		PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) );
-		PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) );
-		PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) );
+        PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) );
+        PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) );
+        PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) );
 
-		converter->AddFace( pointA.index, pointB.index, pointC.index );
-	}
+        converter->AddFace( pointA.index, pointB.index, pointC.index );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 inline float p2tMax( float a, float b )
 {
-	return a > b ? a : b;
+    return a > b ? a : b;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
 float BlenderTessellatorP2T::FindLargestMatrixElem( const aiMatrix3x3& mtx ) const
 {
-	float result = 0.0f;
+    float result = 0.0f;
 
-	for ( int x = 0; x < 3; ++x )
-	{
-		for ( int y = 0; y < 3; ++y )
-		{
-			result = p2tMax( std::fabs( mtx[ x ][ y ] ), result );
-		}
-	}
+    for ( int x = 0; x < 3; ++x )
+    {
+        for ( int y = 0; y < 3; ++y )
+        {
+            result = p2tMax( std::fabs( mtx[ x ][ y ] ), result );
+        }
+    }
 
-	return result;
+    return result;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Aparently Assimp doesn't have matrix scaling
 aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const
 {
-	aiMatrix3x3 result;
+    aiMatrix3x3 result;
 
-	for ( int x = 0; x < 3; ++x )
-	{
-		for ( int y = 0; y < 3; ++y )
-		{
-			result[ x ][ y ] = mtx[ x ][ y ] * scale;
-		}
-	}
+    for ( int x = 0; x < 3; ++x )
+    {
+        for ( int y = 0; y < 3; ++y )
+        {
+            result[ x ][ y ] = mtx[ x ][ y ] * scale;
+        }
+    }
 
-	return result;
+    return result;
 }
 
 
@@ -448,70 +448,70 @@ aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float sc
 // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
 aiVector3D BlenderTessellatorP2T::GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const
 {
-	float scale = FindLargestMatrixElem( mtx );
-	aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale );
-	mc = mc * mc * mc;
-
-	aiVector3D v( 1.0f );
-	aiVector3D lastV = v;
-	for ( int i = 0; i < 100; ++i )
-	{
-		v = mc * v;
-		v.Normalize( );
-		if ( ( v - lastV ).SquareLength( ) < 1e-16f )
-		{
-			break;
-		}
-		lastV = v;
-	}
-	return v;
+    float scale = FindLargestMatrixElem( mtx );
+    aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale );
+    mc = mc * mc * mc;
+
+    aiVector3D v( 1.0f );
+    aiVector3D lastV = v;
+    for ( int i = 0; i < 100; ++i )
+    {
+        v = mc * v;
+        v.Normalize( );
+        if ( ( v - lastV ).SquareLength( ) < 1e-16f )
+        {
+            break;
+        }
+        lastV = v;
+    }
+    return v;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
 PlaneP2T BlenderTessellatorP2T::FindLLSQPlane( const std::vector< PointP2T >& points ) const
 {
-	PlaneP2T result;
-
-	aiVector3D sum( 0.0f );
-	for ( unsigned int i = 0; i < points.size( ); ++i )
-	{
-		sum += points[ i ].point3D;
-	}
-	result.centre = sum * ( 1.0f / points.size( ) );
-
-	float sumXX = 0.0f;
-	float sumXY = 0.0f;
-	float sumXZ = 0.0f;
-	float sumYY = 0.0f;
-	float sumYZ = 0.0f;
-	float sumZZ = 0.0f;
-	for ( unsigned int i = 0; i < points.size( ); ++i )
-	{
-		aiVector3D offset = points[ i ].point3D - result.centre;
-		sumXX += offset.x * offset.x;
-		sumXY += offset.x * offset.y;
-		sumXZ += offset.x * offset.z;
-		sumYY += offset.y * offset.y;
-		sumYZ += offset.y * offset.z;
-		sumZZ += offset.z * offset.z;
-	}
-
-	aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ );
-
-	float det = mtx.Determinant( );
-	if ( det == 0.0f )
-	{
-		result.normal = aiVector3D( 0.0f );
-	}
-	else
-	{
-		aiMatrix3x3 invMtx = mtx;
-		invMtx.Inverse( );
-		result.normal = GetEigenVectorFromLargestEigenValue( invMtx );
-	}
-
-	return result;
+    PlaneP2T result;
+
+    aiVector3D sum( 0.0f );
+    for ( unsigned int i = 0; i < points.size( ); ++i )
+    {
+        sum += points[ i ].point3D;
+    }
+    result.centre = sum * ( 1.0f / points.size( ) );
+
+    float sumXX = 0.0f;
+    float sumXY = 0.0f;
+    float sumXZ = 0.0f;
+    float sumYY = 0.0f;
+    float sumYZ = 0.0f;
+    float sumZZ = 0.0f;
+    for ( unsigned int i = 0; i < points.size( ); ++i )
+    {
+        aiVector3D offset = points[ i ].point3D - result.centre;
+        sumXX += offset.x * offset.x;
+        sumXY += offset.x * offset.y;
+        sumXZ += offset.x * offset.z;
+        sumYY += offset.y * offset.y;
+        sumYZ += offset.y * offset.z;
+        sumZZ += offset.z * offset.z;
+    }
+
+    aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ );
+
+    float det = mtx.Determinant( );
+    if ( det == 0.0f )
+    {
+        result.normal = aiVector3D( 0.0f );
+    }
+    else
+    {
+        aiMatrix3x3 invMtx = mtx;
+        invMtx.Inverse( );
+        result.normal = GetEigenVectorFromLargestEigenValue( invMtx );
+    }
+
+    return result;
 }
 
 #endif // ASSIMP_BLEND_WITH_POLY_2_TRI

+ 125 - 125
code/BlenderTessellator.h

@@ -50,11 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // made configurable in CMake and potentially not wanted by most users
 // as it requires a Gl environment.
 #ifndef ASSIMP_BLEND_WITH_GLU_TESSELLATE
-#	define ASSIMP_BLEND_WITH_GLU_TESSELLATE 0
+#   define ASSIMP_BLEND_WITH_GLU_TESSELLATE 0
 #endif
 
 #ifndef ASSIMP_BLEND_WITH_POLY_2_TRI
-#	define ASSIMP_BLEND_WITH_POLY_2_TRI 1
+#   define ASSIMP_BLEND_WITH_POLY_2_TRI 1
 #endif
 
 #include "LogAux.h"
@@ -68,74 +68,74 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp
 {
-	class BlenderBMeshConverter;
-
-	// TinyFormatter.h
-	namespace Formatter
-	{
-		template < typename T,typename TR, typename A > class basic_formatter;
-		typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
-	}
-
-	// BlenderScene.h
-	namespace Blender
-	{
-		struct MLoop;
-		struct MVert;
-
-		struct VertexGL
-		{
-			GLdouble X;
-			GLdouble Y;
-			GLdouble Z;
-			int index;
-			int magic;
-
-			VertexGL( GLdouble X, GLdouble Y, GLdouble Z, int index, int magic ): X( X ), Y( Y ), Z( Z ), index( index ), magic( magic ) { }
-		};
-
-		struct DrawCallGL
-		{
-			GLenum drawMode;
-			int baseVertex;
-			int vertexCount;
-
-			DrawCallGL( GLenum drawMode, int baseVertex ): drawMode( drawMode ), baseVertex( baseVertex ), vertexCount( 0 ) { }
-		};
-
-		struct TessDataGL
-		{
-			std::vector< DrawCallGL > drawCalls;
-			std::vector< VertexGL > vertices;
-		};
-	}
-
-	class BlenderTessellatorGL: public LogFunctions< BlenderTessellatorGL >
-	{
-	public:
-		BlenderTessellatorGL( BlenderBMeshConverter& converter );
-		~BlenderTessellatorGL( );
-
-		void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
-
-	private:
-		void AssertVertexCount( int vertexCount );
-		void GenerateLoopVerts( std::vector< Blender::VertexGL >& polyLoopGL, const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
-		void Tesssellate( std::vector< Blender::VertexGL >& polyLoopGL, Blender::TessDataGL& tessData );
-		void TriangulateDrawCalls( const Blender::TessDataGL& tessData );
-		void MakeFacesFromTris( const Blender::VertexGL* vertices, int vertexCount );
-		void MakeFacesFromTriStrip( const Blender::VertexGL* vertices, int vertexCount );
-		void MakeFacesFromTriFan( const Blender::VertexGL* vertices, int vertexCount );
-
-		static void TessellateBegin( GLenum drawModeGL, void* userData );
-		static void TessellateEnd( void* userData );
-		static void TessellateVertex( const void* vtxData, void* userData );
-		static void TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData );
-		static void TessellateEdgeFlag( GLboolean edgeFlag, void* userData );
-		static void TessellateError( GLenum errorCode, void* userData );
-
-		BlenderBMeshConverter* converter;
-	};
+    class BlenderBMeshConverter;
+
+    // TinyFormatter.h
+    namespace Formatter
+    {
+        template < typename T,typename TR, typename A > class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
+    }
+
+    // BlenderScene.h
+    namespace Blender
+    {
+        struct MLoop;
+        struct MVert;
+
+        struct VertexGL
+        {
+            GLdouble X;
+            GLdouble Y;
+            GLdouble Z;
+            int index;
+            int magic;
+
+            VertexGL( GLdouble X, GLdouble Y, GLdouble Z, int index, int magic ): X( X ), Y( Y ), Z( Z ), index( index ), magic( magic ) { }
+        };
+
+        struct DrawCallGL
+        {
+            GLenum drawMode;
+            int baseVertex;
+            int vertexCount;
+
+            DrawCallGL( GLenum drawMode, int baseVertex ): drawMode( drawMode ), baseVertex( baseVertex ), vertexCount( 0 ) { }
+        };
+
+        struct TessDataGL
+        {
+            std::vector< DrawCallGL > drawCalls;
+            std::vector< VertexGL > vertices;
+        };
+    }
+
+    class BlenderTessellatorGL: public LogFunctions< BlenderTessellatorGL >
+    {
+    public:
+        BlenderTessellatorGL( BlenderBMeshConverter& converter );
+        ~BlenderTessellatorGL( );
+
+        void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
+
+    private:
+        void AssertVertexCount( int vertexCount );
+        void GenerateLoopVerts( std::vector< Blender::VertexGL >& polyLoopGL, const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
+        void Tesssellate( std::vector< Blender::VertexGL >& polyLoopGL, Blender::TessDataGL& tessData );
+        void TriangulateDrawCalls( const Blender::TessDataGL& tessData );
+        void MakeFacesFromTris( const Blender::VertexGL* vertices, int vertexCount );
+        void MakeFacesFromTriStrip( const Blender::VertexGL* vertices, int vertexCount );
+        void MakeFacesFromTriFan( const Blender::VertexGL* vertices, int vertexCount );
+
+        static void TessellateBegin( GLenum drawModeGL, void* userData );
+        static void TessellateEnd( void* userData );
+        static void TessellateVertex( const void* vtxData, void* userData );
+        static void TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData );
+        static void TessellateEdgeFlag( GLboolean edgeFlag, void* userData );
+        static void TessellateError( GLenum errorCode, void* userData );
+
+        BlenderBMeshConverter* converter;
+    };
 } // end of namespace Assimp
 
 #endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
@@ -146,61 +146,61 @@ namespace Assimp
 
 namespace Assimp
 {
-	class BlenderBMeshConverter;
-
-	// TinyFormatter.h
-	namespace Formatter
-	{
-		template < typename T,typename TR, typename A > class basic_formatter;
-		typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
-	}
-
-	// BlenderScene.h
-	namespace Blender
-	{
-		struct MLoop;
-		struct MVert;
-
-		struct PointP2T
-		{
-			aiVector3D point3D;
-			p2t::Point point2D;
-			int magic;
-			int index;
-		};
-
-		struct PlaneP2T
-		{
-			aiVector3D centre;
-			aiVector3D normal;
-		};
-	}
-
-	class BlenderTessellatorP2T: public LogFunctions< BlenderTessellatorP2T >
-	{
-	public:
-		BlenderTessellatorP2T( BlenderBMeshConverter& converter );
-		~BlenderTessellatorP2T( );
-
-		void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
-
-	private:
-		void AssertVertexCount( int vertexCount );
-		void Copy3DVertices( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices, std::vector< Blender::PointP2T >& targetVertices ) const;
-		aiMatrix4x4 GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const;
-		void TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const;
-		void ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const;
-		inline Blender::PointP2T& GetActualPointStructure( p2t::Point& point ) const;
-		void MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const;
-
-		// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
-		float FindLargestMatrixElem( const aiMatrix3x3& mtx ) const;
-		aiMatrix3x3 ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const;
-		aiVector3D GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const;
-		Blender::PlaneP2T FindLLSQPlane( const std::vector< Blender::PointP2T >& points ) const;
-
-		BlenderBMeshConverter* converter;
-	};
+    class BlenderBMeshConverter;
+
+    // TinyFormatter.h
+    namespace Formatter
+    {
+        template < typename T,typename TR, typename A > class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
+    }
+
+    // BlenderScene.h
+    namespace Blender
+    {
+        struct MLoop;
+        struct MVert;
+
+        struct PointP2T
+        {
+            aiVector3D point3D;
+            p2t::Point point2D;
+            int magic;
+            int index;
+        };
+
+        struct PlaneP2T
+        {
+            aiVector3D centre;
+            aiVector3D normal;
+        };
+    }
+
+    class BlenderTessellatorP2T: public LogFunctions< BlenderTessellatorP2T >
+    {
+    public:
+        BlenderTessellatorP2T( BlenderBMeshConverter& converter );
+        ~BlenderTessellatorP2T( );
+
+        void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
+
+    private:
+        void AssertVertexCount( int vertexCount );
+        void Copy3DVertices( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices, std::vector< Blender::PointP2T >& targetVertices ) const;
+        aiMatrix4x4 GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const;
+        void TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const;
+        void ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const;
+        inline Blender::PointP2T& GetActualPointStructure( p2t::Point& point ) const;
+        void MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const;
+
+        // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
+        float FindLargestMatrixElem( const aiMatrix3x3& mtx ) const;
+        aiMatrix3x3 ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const;
+        aiVector3D GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const;
+        Blender::PlaneP2T FindLLSQPlane( const std::vector< Blender::PointP2T >& points ) const;
+
+        BlenderBMeshConverter* converter;
+    };
 } // end of namespace Assimp
 
 #endif // ASSIMP_BLEND_WITH_POLY_2_TRI

+ 199 - 199
code/BlobIOSystem.h

@@ -54,8 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <set>
 #include <vector>
 
-namespace Assimp	{
-	class BlobIOSystem;
+namespace Assimp    {
+    class BlobIOSystem;
 
 // --------------------------------------------------------------------------------------------
 /** Redirect IOStream to a blob */
@@ -64,144 +64,144 @@ class BlobIOStream : public IOStream
 {
 public:
 
-	BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096)
-		: buffer()
-		, cur_size()
-		, file_size()
-		, cursor()
-		, initial(initial)
-		, file(file)
-		, creator(creator)
-	{
-	}
+    BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096)
+        : buffer()
+        , cur_size()
+        , file_size()
+        , cursor()
+        , initial(initial)
+        , file(file)
+        , creator(creator)
+    {
+    }
 
 
-	virtual ~BlobIOStream();
+    virtual ~BlobIOStream();
 
 public:
 
-	// -------------------------------------------------------------------
-	aiExportDataBlob* GetBlob()
-	{
-		aiExportDataBlob* blob = new aiExportDataBlob();
-		blob->size = file_size;
-		blob->data = buffer;
+    // -------------------------------------------------------------------
+    aiExportDataBlob* GetBlob()
+    {
+        aiExportDataBlob* blob = new aiExportDataBlob();
+        blob->size = file_size;
+        blob->data = buffer;
 
-		buffer = NULL;
+        buffer = NULL;
 
-		return blob;
-	}
+        return blob;
+    }
 
 
 public:
 
 
-	// -------------------------------------------------------------------
+    // -------------------------------------------------------------------
     virtual size_t Read( void *,
-		size_t,
-		size_t )
-	{
-		return 0;
-	}
+        size_t,
+        size_t )
+    {
+        return 0;
+    }
 
-	// -------------------------------------------------------------------
+    // -------------------------------------------------------------------
     virtual size_t Write(const void* pvBuffer,
-		size_t pSize,
-		size_t pCount)
-	{
-		pSize *= pCount;
-		if (cursor + pSize > cur_size) {
-			Grow(cursor + pSize);
-		}
-
-		memcpy(buffer+cursor, pvBuffer, pSize);
-		cursor += pSize;
-
-		file_size = std::max(file_size,cursor);
-		return pCount;
-	}
-
-	// -------------------------------------------------------------------
-	virtual aiReturn Seek(size_t pOffset,
-		aiOrigin pOrigin)
-	{
-		switch(pOrigin)
-		{
-		case aiOrigin_CUR:
-			cursor += pOffset;
-			break;
-
-		case aiOrigin_END:
-			cursor = file_size - pOffset;
-			break;
-
-		case aiOrigin_SET:
-			cursor = pOffset;
-			break;
-
-		default:
-			return AI_FAILURE;
-		}
-
-		if (cursor > file_size) {
-			Grow(cursor);
-		}
-
-		file_size = std::max(cursor,file_size);
-		return AI_SUCCESS;
-	}
-
-	// -------------------------------------------------------------------
+        size_t pSize,
+        size_t pCount)
+    {
+        pSize *= pCount;
+        if (cursor + pSize > cur_size) {
+            Grow(cursor + pSize);
+        }
+
+        memcpy(buffer+cursor, pvBuffer, pSize);
+        cursor += pSize;
+
+        file_size = std::max(file_size,cursor);
+        return pCount;
+    }
+
+    // -------------------------------------------------------------------
+    virtual aiReturn Seek(size_t pOffset,
+        aiOrigin pOrigin)
+    {
+        switch(pOrigin)
+        {
+        case aiOrigin_CUR:
+            cursor += pOffset;
+            break;
+
+        case aiOrigin_END:
+            cursor = file_size - pOffset;
+            break;
+
+        case aiOrigin_SET:
+            cursor = pOffset;
+            break;
+
+        default:
+            return AI_FAILURE;
+        }
+
+        if (cursor > file_size) {
+            Grow(cursor);
+        }
+
+        file_size = std::max(cursor,file_size);
+        return AI_SUCCESS;
+    }
+
+    // -------------------------------------------------------------------
     virtual size_t Tell() const
-	{
-		return cursor;
-	}
+    {
+        return cursor;
+    }
 
-	// -------------------------------------------------------------------
-	virtual size_t FileSize() const
-	{
-		return file_size;
-	}
+    // -------------------------------------------------------------------
+    virtual size_t FileSize() const
+    {
+        return file_size;
+    }
 
-	// -------------------------------------------------------------------
-	virtual void Flush()
-	{
-		// ignore
-	}
+    // -------------------------------------------------------------------
+    virtual void Flush()
+    {
+        // ignore
+    }
 
 
 
 private:
 
-	// -------------------------------------------------------------------
-	void Grow(size_t need = 0)
-	{
-		// 1.5 and phi are very heap-friendly growth factors (the first
-		// allows for frequent re-use of heap blocks, the second
-		// forms a fibonacci sequence with similar characteristics -
-		// since this heavily depends on the heap implementation
-		// and other factors as well, i'll just go with 1.5 since
-		// it is quicker to compute).
-		size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
+    // -------------------------------------------------------------------
+    void Grow(size_t need = 0)
+    {
+        // 1.5 and phi are very heap-friendly growth factors (the first
+        // allows for frequent re-use of heap blocks, the second
+        // forms a fibonacci sequence with similar characteristics -
+        // since this heavily depends on the heap implementation
+        // and other factors as well, i'll just go with 1.5 since
+        // it is quicker to compute).
+        size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
 
-		const uint8_t* const old = buffer;
-		buffer = new uint8_t[new_size];
+        const uint8_t* const old = buffer;
+        buffer = new uint8_t[new_size];
 
-		if (old) {
-			memcpy(buffer,old,cur_size);
-			delete[] old;
-		}
+        if (old) {
+            memcpy(buffer,old,cur_size);
+            delete[] old;
+        }
 
-		cur_size = new_size;
-	}
+        cur_size = new_size;
+    }
 
 private:
 
-	uint8_t* buffer;
-	size_t cur_size,file_size, cursor, initial;
+    uint8_t* buffer;
+    size_t cur_size,file_size, cursor, initial;
 
-	const std::string file;
-	BlobIOSystem* const creator;
+    const std::string file;
+    BlobIOSystem* const creator;
 };
 
 
@@ -213,122 +213,122 @@ private:
 class BlobIOSystem : public IOSystem
 {
 
-	friend class BlobIOStream;
-	typedef std::pair<std::string, aiExportDataBlob*> BlobEntry;
+    friend class BlobIOStream;
+    typedef std::pair<std::string, aiExportDataBlob*> BlobEntry;
 
 public:
 
-	BlobIOSystem()
-	{
-	}
+    BlobIOSystem()
+    {
+    }
 
-	virtual ~BlobIOSystem()
-	{
-		BOOST_FOREACH(BlobEntry& blobby, blobs) {
-			delete blobby.second;
-		}
-	}
+    virtual ~BlobIOSystem()
+    {
+        BOOST_FOREACH(BlobEntry& blobby, blobs) {
+            delete blobby.second;
+        }
+    }
 
 public:
 
-	// -------------------------------------------------------------------
-	const char* GetMagicFileName() const
-	{
-		return AI_BLOBIO_MAGIC;
-	}
-
-
-	// -------------------------------------------------------------------
-	aiExportDataBlob* GetBlobChain()
-	{
-		// one must be the master
-		aiExportDataBlob* master = NULL, *cur;
-		BOOST_FOREACH(const BlobEntry& blobby, blobs) {
-			if (blobby.first == AI_BLOBIO_MAGIC) {
-				master = blobby.second;
-				break;
-			}
-		}
-		if (!master) {
-			DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly.");
-			return NULL;
-		}
-
-		master->name.Set("");
-
-		cur = master;
-		BOOST_FOREACH(const BlobEntry& blobby, blobs) {
-			if (blobby.second == master) {
-				continue;
-			}
-
-			cur->next = blobby.second;
-			cur = cur->next;
-
-			// extract the file extension from the file written
-			const std::string::size_type s = blobby.first.find_first_of('.');
-			cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1));
-		}
-
-		// give up blob ownership
-		blobs.clear();
-		return master;
-	}
+    // -------------------------------------------------------------------
+    const char* GetMagicFileName() const
+    {
+        return AI_BLOBIO_MAGIC;
+    }
+
+
+    // -------------------------------------------------------------------
+    aiExportDataBlob* GetBlobChain()
+    {
+        // one must be the master
+        aiExportDataBlob* master = NULL, *cur;
+        BOOST_FOREACH(const BlobEntry& blobby, blobs) {
+            if (blobby.first == AI_BLOBIO_MAGIC) {
+                master = blobby.second;
+                break;
+            }
+        }
+        if (!master) {
+            DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly.");
+            return NULL;
+        }
+
+        master->name.Set("");
+
+        cur = master;
+        BOOST_FOREACH(const BlobEntry& blobby, blobs) {
+            if (blobby.second == master) {
+                continue;
+            }
+
+            cur->next = blobby.second;
+            cur = cur->next;
+
+            // extract the file extension from the file written
+            const std::string::size_type s = blobby.first.find_first_of('.');
+            cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1));
+        }
+
+        // give up blob ownership
+        blobs.clear();
+        return master;
+    }
 
 public:
 
-	// -------------------------------------------------------------------
-	virtual bool Exists( const char* pFile) const {
-		return created.find(std::string(pFile)) != created.end();
-	}
+    // -------------------------------------------------------------------
+    virtual bool Exists( const char* pFile) const {
+        return created.find(std::string(pFile)) != created.end();
+    }
 
 
-	// -------------------------------------------------------------------
-	virtual char getOsSeparator() const {
-		return '/';
-	}
+    // -------------------------------------------------------------------
+    virtual char getOsSeparator() const {
+        return '/';
+    }
 
 
-	// -------------------------------------------------------------------
-	virtual IOStream* Open(const char* pFile,
-		const char* pMode)
-	{
-		if (pMode[0] != 'w') {
-			return NULL;
-		}
+    // -------------------------------------------------------------------
+    virtual IOStream* Open(const char* pFile,
+        const char* pMode)
+    {
+        if (pMode[0] != 'w') {
+            return NULL;
+        }
 
-		created.insert(std::string(pFile));
-		return new BlobIOStream(this,std::string(pFile));
-	}
+        created.insert(std::string(pFile));
+        return new BlobIOStream(this,std::string(pFile));
+    }
 
-	// -------------------------------------------------------------------
-	virtual void Close( IOStream* pFile)
-	{
-		delete pFile;
-	}
+    // -------------------------------------------------------------------
+    virtual void Close( IOStream* pFile)
+    {
+        delete pFile;
+    }
 
 private:
 
-	// -------------------------------------------------------------------
-	void OnDestruct(const std::string& filename, BlobIOStream* child)
-	{
-		// we don't know in which the files are closed, so we
-		// can't reliably say that the first must be the master
-		// file ...
-		blobs.push_back( BlobEntry(filename,child->GetBlob()) );
-	}
+    // -------------------------------------------------------------------
+    void OnDestruct(const std::string& filename, BlobIOStream* child)
+    {
+        // we don't know in which the files are closed, so we
+        // can't reliably say that the first must be the master
+        // file ...
+        blobs.push_back( BlobEntry(filename,child->GetBlob()) );
+    }
 
 private:
-	std::set<std::string> created;
-	std::vector< BlobEntry > blobs;
+    std::set<std::string> created;
+    std::vector< BlobEntry > blobs;
 };
 
 
 // --------------------------------------------------------------------------------------------
 BlobIOStream :: ~BlobIOStream()
 {
-	creator->OnDestruct(file,this);
-	delete[] buffer;
+    creator->OnDestruct(file,this);
+    delete[] buffer;
 }
 
 

+ 160 - 160
code/ByteSwapper.h

@@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <stdlib.h>
 #endif
 
-namespace Assimp	{
+namespace Assimp    {
 // --------------------------------------------------------------------------------------
 /** Defines some useful byte order swap routines.
  *
@@ -60,143 +60,143 @@ namespace Assimp	{
 // --------------------------------------------------------------------------------------
 class ByteSwap
 {
-	ByteSwap() {}
+    ByteSwap() {}
 
 public:
 
-	// ----------------------------------------------------------------------
-	/** Swap two bytes of data
-	 *  @param[inout] _szOut A void* to save the reintcasts for the caller. */
-	static inline void Swap2(void* _szOut)
-	{
-		ai_assert(_szOut);
+    // ----------------------------------------------------------------------
+    /** Swap two bytes of data
+     *  @param[inout] _szOut A void* to save the reintcasts for the caller. */
+    static inline void Swap2(void* _szOut)
+    {
+        ai_assert(_szOut);
 
 #if _MSC_VER >= 1400
-		uint16_t* const szOut = reinterpret_cast<uint16_t*>(_szOut);
-		*szOut = _byteswap_ushort(*szOut);
+        uint16_t* const szOut = reinterpret_cast<uint16_t*>(_szOut);
+        *szOut = _byteswap_ushort(*szOut);
 #else
-		uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
-		std::swap(szOut[0],szOut[1]);
+        uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
+        std::swap(szOut[0],szOut[1]);
 #endif
-	}
+    }
 
-	// ----------------------------------------------------------------------
-	/** Swap four bytes of data
-	 *  @param[inout] _szOut A void* to save the reintcasts for the caller. */
-	static inline void Swap4(void* _szOut)
-	{
-		ai_assert(_szOut);
+    // ----------------------------------------------------------------------
+    /** Swap four bytes of data
+     *  @param[inout] _szOut A void* to save the reintcasts for the caller. */
+    static inline void Swap4(void* _szOut)
+    {
+        ai_assert(_szOut);
 
 #if _MSC_VER >= 1400
-		uint32_t* const szOut = reinterpret_cast<uint32_t*>(_szOut);
-		*szOut = _byteswap_ulong(*szOut);
+        uint32_t* const szOut = reinterpret_cast<uint32_t*>(_szOut);
+        *szOut = _byteswap_ulong(*szOut);
 #else
-		uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
-		std::swap(szOut[0],szOut[3]);
-		std::swap(szOut[1],szOut[2]);
+        uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
+        std::swap(szOut[0],szOut[3]);
+        std::swap(szOut[1],szOut[2]);
 #endif
-	}
+    }
 
-	// ----------------------------------------------------------------------
-	/** Swap eight bytes of data
-	 *  @param[inout] _szOut A void* to save the reintcasts for the caller. */
-	static inline void Swap8(void* _szOut)
-	{
-	ai_assert(_szOut);
+    // ----------------------------------------------------------------------
+    /** Swap eight bytes of data
+     *  @param[inout] _szOut A void* to save the reintcasts for the caller. */
+    static inline void Swap8(void* _szOut)
+    {
+    ai_assert(_szOut);
 
 #if _MSC_VER >= 1400
-		uint64_t* const szOut = reinterpret_cast<uint64_t*>(_szOut);
-		*szOut = _byteswap_uint64(*szOut);
+        uint64_t* const szOut = reinterpret_cast<uint64_t*>(_szOut);
+        *szOut = _byteswap_uint64(*szOut);
 #else
-		uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
-		std::swap(szOut[0],szOut[7]);
-		std::swap(szOut[1],szOut[6]);
-		std::swap(szOut[2],szOut[5]);
-		std::swap(szOut[3],szOut[4]);
+        uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
+        std::swap(szOut[0],szOut[7]);
+        std::swap(szOut[1],szOut[6]);
+        std::swap(szOut[2],szOut[5]);
+        std::swap(szOut[3],szOut[4]);
 #endif
-	}
-
-	// ----------------------------------------------------------------------
-	/** ByteSwap a float. Not a joke.
-	 *  @param[inout] fOut ehm. .. */
-	static inline void Swap(float* fOut) {
-		Swap4(fOut);
-	}
-
-	// ----------------------------------------------------------------------
-	/** ByteSwap a double. Not a joke.
-	 *  @param[inout] fOut ehm. .. */
-	static inline void Swap(double* fOut) {
-		Swap8(fOut);
-	}
-
-
-	// ----------------------------------------------------------------------
-	/** ByteSwap an int16t. Not a joke.
-	 *  @param[inout] fOut ehm. .. */
-	static inline void Swap(int16_t* fOut) {
-		Swap2(fOut);
-	}
-
-	static inline void Swap(uint16_t* fOut) {
-		Swap2(fOut);
-	}
-
-	// ----------------------------------------------------------------------
-	/** ByteSwap an int32t. Not a joke.
-	 *  @param[inout] fOut ehm. .. */
-	static inline void Swap(int32_t* fOut){
-		Swap4(fOut);
-	}
-
-	static inline void Swap(uint32_t* fOut){
-		Swap4(fOut);
-	}
-
-	// ----------------------------------------------------------------------
-	/** ByteSwap an int64t. Not a joke.
-	 *  @param[inout] fOut ehm. .. */
-	static inline void Swap(int64_t* fOut) {
-		Swap8(fOut);
-	}
-
-	static inline void Swap(uint64_t* fOut) {
-		Swap8(fOut);
-	}
-
-	// ----------------------------------------------------------------------
-	//! Templatized ByteSwap
-	//! \returns param tOut as swapped
-	template<typename Type>
-	static inline Type Swapped(Type tOut)
-	{
-		return _swapper<Type,sizeof(Type)>()(tOut);
-	}
+    }
+
+    // ----------------------------------------------------------------------
+    /** ByteSwap a float. Not a joke.
+     *  @param[inout] fOut ehm. .. */
+    static inline void Swap(float* fOut) {
+        Swap4(fOut);
+    }
+
+    // ----------------------------------------------------------------------
+    /** ByteSwap a double. Not a joke.
+     *  @param[inout] fOut ehm. .. */
+    static inline void Swap(double* fOut) {
+        Swap8(fOut);
+    }
+
+
+    // ----------------------------------------------------------------------
+    /** ByteSwap an int16t. Not a joke.
+     *  @param[inout] fOut ehm. .. */
+    static inline void Swap(int16_t* fOut) {
+        Swap2(fOut);
+    }
+
+    static inline void Swap(uint16_t* fOut) {
+        Swap2(fOut);
+    }
+
+    // ----------------------------------------------------------------------
+    /** ByteSwap an int32t. Not a joke.
+     *  @param[inout] fOut ehm. .. */
+    static inline void Swap(int32_t* fOut){
+        Swap4(fOut);
+    }
+
+    static inline void Swap(uint32_t* fOut){
+        Swap4(fOut);
+    }
+
+    // ----------------------------------------------------------------------
+    /** ByteSwap an int64t. Not a joke.
+     *  @param[inout] fOut ehm. .. */
+    static inline void Swap(int64_t* fOut) {
+        Swap8(fOut);
+    }
+
+    static inline void Swap(uint64_t* fOut) {
+        Swap8(fOut);
+    }
+
+    // ----------------------------------------------------------------------
+    //! Templatized ByteSwap
+    //! \returns param tOut as swapped
+    template<typename Type>
+    static inline Type Swapped(Type tOut)
+    {
+        return _swapper<Type,sizeof(Type)>()(tOut);
+    }
 
 private:
 
-	template <typename T, size_t size> struct _swapper;
+    template <typename T, size_t size> struct _swapper;
 };
 
 template <typename T> struct ByteSwap::_swapper<T,2> {
-	T operator() (T tOut) {
-		Swap2(&tOut);
-		return tOut;
-	}
+    T operator() (T tOut) {
+        Swap2(&tOut);
+        return tOut;
+    }
 };
 
 template <typename T> struct ByteSwap::_swapper<T,4> {
-	T operator() (T tOut) {
-		Swap4(&tOut);
-		return tOut;
-	}
+    T operator() (T tOut) {
+        Swap4(&tOut);
+        return tOut;
+    }
 };
 
 template <typename T> struct ByteSwap::_swapper<T,8> {
-	T operator() (T tOut) {
-		Swap8(&tOut);
-		return tOut;
-	}
+    T operator() (T tOut) {
+        Swap8(&tOut);
+        return tOut;
+    }
 };
 
 
@@ -204,39 +204,39 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
 // ByteSwap macros for BigEndian/LittleEndian support
 // --------------------------------------------------------------------------------------
 #if (defined AI_BUILD_BIG_ENDIAN)
-#	define AI_LE(t)	(t)
-#	define AI_BE(t) ByteSwap::Swapped(t)
-#	define AI_LSWAP2(p)
-#	define AI_LSWAP4(p)
-#	define AI_LSWAP8(p)
-#	define AI_LSWAP2P(p)
-#	define AI_LSWAP4P(p)
-#	define AI_LSWAP8P(p)
-#	define LE_NCONST const
-#	define AI_SWAP2(p) ByteSwap::Swap2(&(p))
-#	define AI_SWAP4(p) ByteSwap::Swap4(&(p))
-#	define AI_SWAP8(p) ByteSwap::Swap8(&(p))
-#	define AI_SWAP2P(p) ByteSwap::Swap2((p))
-#	define AI_SWAP4P(p) ByteSwap::Swap4((p))
-#	define AI_SWAP8P(p) ByteSwap::Swap8((p))
-#	define BE_NCONST
+#   define AI_LE(t) (t)
+#   define AI_BE(t) ByteSwap::Swapped(t)
+#   define AI_LSWAP2(p)
+#   define AI_LSWAP4(p)
+#   define AI_LSWAP8(p)
+#   define AI_LSWAP2P(p)
+#   define AI_LSWAP4P(p)
+#   define AI_LSWAP8P(p)
+#   define LE_NCONST const
+#   define AI_SWAP2(p) ByteSwap::Swap2(&(p))
+#   define AI_SWAP4(p) ByteSwap::Swap4(&(p))
+#   define AI_SWAP8(p) ByteSwap::Swap8(&(p))
+#   define AI_SWAP2P(p) ByteSwap::Swap2((p))
+#   define AI_SWAP4P(p) ByteSwap::Swap4((p))
+#   define AI_SWAP8P(p) ByteSwap::Swap8((p))
+#   define BE_NCONST
 #else
-#	define AI_BE(t)	(t)
-#	define AI_LE(t) ByteSwap::Swapped(t)
-#	define AI_SWAP2(p)
-#	define AI_SWAP4(p)
-#	define AI_SWAP8(p)
-#	define AI_SWAP2P(p)
-#	define AI_SWAP4P(p)
-#	define AI_SWAP8P(p)
-#	define BE_NCONST const
-#	define AI_LSWAP2(p)		ByteSwap::Swap2(&(p))
-#	define AI_LSWAP4(p)		ByteSwap::Swap4(&(p))
-#	define AI_LSWAP8(p)		ByteSwap::Swap8(&(p))
-#	define AI_LSWAP2P(p)	ByteSwap::Swap2((p))
-#	define AI_LSWAP4P(p)	ByteSwap::Swap4((p))
-#	define AI_LSWAP8P(p)	ByteSwap::Swap8((p))
-#	define LE_NCONST
+#   define AI_BE(t) (t)
+#   define AI_LE(t) ByteSwap::Swapped(t)
+#   define AI_SWAP2(p)
+#   define AI_SWAP4(p)
+#   define AI_SWAP8(p)
+#   define AI_SWAP2P(p)
+#   define AI_SWAP4P(p)
+#   define AI_SWAP8P(p)
+#   define BE_NCONST const
+#   define AI_LSWAP2(p)     ByteSwap::Swap2(&(p))
+#   define AI_LSWAP4(p)     ByteSwap::Swap4(&(p))
+#   define AI_LSWAP8(p)     ByteSwap::Swap8(&(p))
+#   define AI_LSWAP2P(p)    ByteSwap::Swap2((p))
+#   define AI_LSWAP4P(p)    ByteSwap::Swap4((p))
+#   define AI_LSWAP8P(p)    ByteSwap::Swap8((p))
+#   define LE_NCONST
 #endif
 
 
@@ -244,41 +244,41 @@ namespace Intern {
 
 // --------------------------------------------------------------------------------------------
 template <typename T, bool doit>
-struct ByteSwapper	{
-	void operator() (T* inout) {
-		ByteSwap::Swap(inout);
-	}
+struct ByteSwapper  {
+    void operator() (T* inout) {
+        ByteSwap::Swap(inout);
+    }
 };
 
 template <typename T>
-struct ByteSwapper<T,false>	{
-	void operator() (T*) {
-	}
+struct ByteSwapper<T,false> {
+    void operator() (T*) {
+    }
 };
 
 // --------------------------------------------------------------------------------------------
 template <bool SwapEndianess, typename T, bool RuntimeSwitch>
 struct Getter {
-	void operator() (T* inout, bool le) {
+    void operator() (T* inout, bool le) {
 #ifdef AI_BUILD_BIG_ENDIAN
-		le =  le;
+        le =  le;
 #else
-		le =  !le;
+        le =  !le;
 #endif
-		if (le) {
-			ByteSwapper<T,(sizeof(T)>1?true:false)> () (inout);
-		}
-		else ByteSwapper<T,false> () (inout);
-	}
+        if (le) {
+            ByteSwapper<T,(sizeof(T)>1?true:false)> () (inout);
+        }
+        else ByteSwapper<T,false> () (inout);
+    }
 };
 
 template <bool SwapEndianess, typename T>
 struct Getter<SwapEndianess,T,false> {
 
-	void operator() (T* inout, bool /*le*/) {
-		// static branch
-		ByteSwapper<T,(SwapEndianess && sizeof(T)>1)> () (inout);
-	}
+    void operator() (T* inout, bool /*le*/) {
+        // static branch
+        ByteSwapper<T,(SwapEndianess && sizeof(T)>1)> () (inout);
+    }
 };
 } // end Intern
 } // end Assimp

+ 499 - 499
code/C4DImporter.cpp

@@ -47,14 +47,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // where it is turned on in the CMake settings.
 
 #ifndef _MSC_VER
-#	error C4D support is currently MSVC only
+#   error C4D support is currently MSVC only
 #endif
 
 #include "C4DImporter.h"
 #include "TinyFormatter.h"
 
 #if defined(_M_X64) || defined(__amd64__)
-#	define __C4D_64BIT
+#   define __C4D_64BIT
 #endif
 
 #define __PC
@@ -66,28 +66,28 @@ using namespace _melange_;
 // overload this function and fill in your own unique data
 void GetWriterInfo(LONG &id, String &appname)
 {
-	id = 2424226;
-	appname = "Open Asset Import Library";
+    id = 2424226;
+    appname = "Open Asset Import Library";
 }
 
 using namespace Assimp;
 using namespace Assimp::Formatter;
 
 namespace Assimp {
-	template<> const std::string LogFunctions<C4DImporter>::log_prefix = "C4D: ";
+    template<> const std::string LogFunctions<C4DImporter>::log_prefix = "C4D: ";
 }
 
 static const aiImporterDesc desc = {
-	"Cinema4D Importer",
-	"",
-	"",
-	"",
-	aiImporterFlags_SupportBinaryFlavour,
-	0,
-	0,
-	0,
-	0,
-	"c4d"
+    "Cinema4D Importer",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportBinaryFlavour,
+    0,
+    0,
+    0,
+    0,
+    "c4d"
 };
 
 
@@ -102,542 +102,542 @@ C4DImporter::~C4DImporter()
 // ------------------------------------------------------------------------------------------------
 bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-	const std::string& extension = GetExtension(pFile);
-	if (extension == "c4d") {
-		return true;
-	}
-
-	else if ((!extension.length() || checkSig) && pIOHandler)	{
-		// TODO
-	}
-	return false;
+    const std::string& extension = GetExtension(pFile);
+    if (extension == "c4d") {
+        return true;
+    }
+
+    else if ((!extension.length() || checkSig) && pIOHandler)   {
+        // TODO
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 const aiImporterDesc* C4DImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 void C4DImporter::SetupProperties(const Importer* /*pImp*/)
 {
-	// nothing to be done for the moment
+    // nothing to be done for the moment
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void C4DImporter::InternReadFile( const std::string& pFile,
-	aiScene* pScene, IOSystem* pIOHandler)
+    aiScene* pScene, IOSystem* pIOHandler)
 {
-	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
-
-	if( file.get() == NULL) {
-		ThrowException("failed to open file " + pFile);
-	}
-
-	const size_t file_size = file->FileSize();
-
-	std::vector<uint8_t> mBuffer(file_size);
-	file->Read(&mBuffer[0], 1, file_size);
-
-	Filename f;
-	f.SetMemoryReadMode(&mBuffer[0], file_size);
-
-	// open document first
-	BaseDocument* doc = LoadDocument(f, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS);
-	if(doc == NULL) {
-		ThrowException("failed to read document " + pFile);
-	}
-
-	pScene->mRootNode = new aiNode("<C4DRoot>");
-
-	// first convert all materials
-	ReadMaterials(doc->GetFirstMaterial());
-
-	// process C4D scenegraph recursively
-	try {
-		RecurseHierarchy(doc->GetFirstObject(), pScene->mRootNode);
-	}
-	catch(...) {
-		BOOST_FOREACH(aiMesh* mesh, meshes) {
-			delete mesh;
-		}
-		BaseDocument::Free(doc);
-		throw;
-	}
-	BaseDocument::Free(doc);
-
-	// copy meshes over
-	pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
-	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
-	std::copy(meshes.begin(), meshes.end(), pScene->mMeshes);
-
-	// copy materials over, adding a default material if necessary
-	unsigned int mat_count = static_cast<unsigned int>(materials.size());
-	BOOST_FOREACH(aiMesh* mesh, meshes) {
-		ai_assert(mesh->mMaterialIndex <= mat_count);
-		if(mesh->mMaterialIndex >= mat_count) {
-			++mat_count;
-
-			ScopeGuard<aiMaterial> def_material(new aiMaterial());
-			const aiString name(AI_DEFAULT_MATERIAL_NAME);
-			def_material->AddProperty(&name, AI_MATKEY_NAME);
-
-			materials.push_back(def_material.dismiss());
-			break;
-		}
-	}
-
-	pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
-	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]();
-	std::copy(materials.begin(), materials.end(), pScene->mMaterials);
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
+
+    if( file.get() == NULL) {
+        ThrowException("failed to open file " + pFile);
+    }
+
+    const size_t file_size = file->FileSize();
+
+    std::vector<uint8_t> mBuffer(file_size);
+    file->Read(&mBuffer[0], 1, file_size);
+
+    Filename f;
+    f.SetMemoryReadMode(&mBuffer[0], file_size);
+
+    // open document first
+    BaseDocument* doc = LoadDocument(f, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS);
+    if(doc == NULL) {
+        ThrowException("failed to read document " + pFile);
+    }
+
+    pScene->mRootNode = new aiNode("<C4DRoot>");
+
+    // first convert all materials
+    ReadMaterials(doc->GetFirstMaterial());
+
+    // process C4D scenegraph recursively
+    try {
+        RecurseHierarchy(doc->GetFirstObject(), pScene->mRootNode);
+    }
+    catch(...) {
+        BOOST_FOREACH(aiMesh* mesh, meshes) {
+            delete mesh;
+        }
+        BaseDocument::Free(doc);
+        throw;
+    }
+    BaseDocument::Free(doc);
+
+    // copy meshes over
+    pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
+    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
+    std::copy(meshes.begin(), meshes.end(), pScene->mMeshes);
+
+    // copy materials over, adding a default material if necessary
+    unsigned int mat_count = static_cast<unsigned int>(materials.size());
+    BOOST_FOREACH(aiMesh* mesh, meshes) {
+        ai_assert(mesh->mMaterialIndex <= mat_count);
+        if(mesh->mMaterialIndex >= mat_count) {
+            ++mat_count;
+
+            ScopeGuard<aiMaterial> def_material(new aiMaterial());
+            const aiString name(AI_DEFAULT_MATERIAL_NAME);
+            def_material->AddProperty(&name, AI_MATKEY_NAME);
+
+            materials.push_back(def_material.dismiss());
+            break;
+        }
+    }
+
+    pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
+    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]();
+    std::copy(materials.begin(), materials.end(), pScene->mMaterials);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 bool C4DImporter::ReadShader(aiMaterial* out, _melange_::BaseShader* shader)
 {
-	// based on Melange sample code (C4DImportExport.cpp)
-	while(shader) {
-		if(shader->GetType() == Xlayer) {
-			BaseContainer* container = shader->GetDataInstance();
-			GeData blend = container->GetData(SLA_LAYER_BLEND);
-			iBlendDataType* blend_list = reinterpret_cast<iBlendDataType*>(blend.GetCustomDataType(CUSTOMDATA_BLEND_LIST));
-			if (!blend_list)
-			{
-				LogWarn("ignoring XLayer shader: no blend list given");
-				continue;
-			}
-
-			LayerShaderLayer *lsl = dynamic_cast<LayerShaderLayer*>(blend_list->m_BlendLayers.GetObject(0));
-
-			// Ignore the actual layer blending - models for real-time rendering should not
-			// use them in a non-trivial way. Just try to find textures that we can apply
-			// to the model.
-			while (lsl)
-			{
-				if (lsl->GetType() == TypeFolder)
-				{
-					BlendFolder* const folder = dynamic_cast<BlendFolder*>(lsl);
-					LayerShaderLayer *subLsl = dynamic_cast<LayerShaderLayer*>(folder->m_Children.GetObject(0));
-
-					while (subLsl)
-					{
-						if (subLsl->GetType() == TypeShader) {
-							BlendShader* const shader = dynamic_cast<BlendShader*>(subLsl);
-							if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
-								return true;
-							}
-						}
-
-						subLsl = subLsl->GetNext();
-					}
-				}
-				else if (lsl->GetType() == TypeShader) {
-					BlendShader* const shader = dynamic_cast<BlendShader*>(lsl);
-					if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
-						return true;
-					}
-				}
-
-				lsl = lsl->GetNext();
-			}
-		}
-		else if ( shader->GetType() == Xbitmap )
-		{
-			aiString path;
-			shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1);
-			path.length = ::strlen(path.data);
-			out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
-			return true;
-		}
-		else {
-			LogWarn("ignoring shader type: " + std::string(GetObjectTypeName(shader->GetType())));
-		}
-		shader = shader->GetNext();
-	}
-	return false;
+    // based on Melange sample code (C4DImportExport.cpp)
+    while(shader) {
+        if(shader->GetType() == Xlayer) {
+            BaseContainer* container = shader->GetDataInstance();
+            GeData blend = container->GetData(SLA_LAYER_BLEND);
+            iBlendDataType* blend_list = reinterpret_cast<iBlendDataType*>(blend.GetCustomDataType(CUSTOMDATA_BLEND_LIST));
+            if (!blend_list)
+            {
+                LogWarn("ignoring XLayer shader: no blend list given");
+                continue;
+            }
+
+            LayerShaderLayer *lsl = dynamic_cast<LayerShaderLayer*>(blend_list->m_BlendLayers.GetObject(0));
+
+            // Ignore the actual layer blending - models for real-time rendering should not
+            // use them in a non-trivial way. Just try to find textures that we can apply
+            // to the model.
+            while (lsl)
+            {
+                if (lsl->GetType() == TypeFolder)
+                {
+                    BlendFolder* const folder = dynamic_cast<BlendFolder*>(lsl);
+                    LayerShaderLayer *subLsl = dynamic_cast<LayerShaderLayer*>(folder->m_Children.GetObject(0));
+
+                    while (subLsl)
+                    {
+                        if (subLsl->GetType() == TypeShader) {
+                            BlendShader* const shader = dynamic_cast<BlendShader*>(subLsl);
+                            if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
+                                return true;
+                            }
+                        }
+
+                        subLsl = subLsl->GetNext();
+                    }
+                }
+                else if (lsl->GetType() == TypeShader) {
+                    BlendShader* const shader = dynamic_cast<BlendShader*>(lsl);
+                    if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
+                        return true;
+                    }
+                }
+
+                lsl = lsl->GetNext();
+            }
+        }
+        else if ( shader->GetType() == Xbitmap )
+        {
+            aiString path;
+            shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1);
+            path.length = ::strlen(path.data);
+            out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
+            return true;
+        }
+        else {
+            LogWarn("ignoring shader type: " + std::string(GetObjectTypeName(shader->GetType())));
+        }
+        shader = shader->GetNext();
+    }
+    return false;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void C4DImporter::ReadMaterials(_melange_::BaseMaterial* mat)
 {
-	// based on Melange sample code
-	while (mat)
-	{
-		const String& name = mat->GetName();
-		if (mat->GetType() == Mmaterial)
-		{
-			aiMaterial* out = new aiMaterial();
-			material_mapping[mat] = static_cast<unsigned int>(materials.size());
-			materials.push_back(out);
-
-			aiString ai_name;
-			name.GetCString(ai_name.data, MAXLEN-1);
-			ai_name.length = ::strlen(ai_name.data);
-			out->AddProperty(&ai_name, AI_MATKEY_NAME);
-
-			Material& m = dynamic_cast<Material&>(*mat);
-
-			if (m.GetChannelState(CHANNEL_COLOR))
-			{
-				GeData data;
-				mat->GetParameter(MATERIAL_COLOR_COLOR, data);
-				Vector color = data.GetVector();
-				mat->GetParameter(MATERIAL_COLOR_BRIGHTNESS, data);
-				const Real brightness = data.GetReal();
-
-				color *= brightness;
-
-				aiVector3D v;
-				v.x = color.x;
-				v.y = color.y;
-				v.z = color.z;
-				out->AddProperty(&v, 1, AI_MATKEY_COLOR_DIFFUSE);
-			}
-
-			BaseShader* const shader = m.GetShader(MATERIAL_COLOR_SHADER);
-			if(shader) {
-				ReadShader(out, shader);
-			}
-		}
-		else
-		{
-			LogWarn("ignoring plugin material: " + std::string(GetObjectTypeName(mat->GetType())));
-		}
-		mat = mat->GetNext();
-	}
+    // based on Melange sample code
+    while (mat)
+    {
+        const String& name = mat->GetName();
+        if (mat->GetType() == Mmaterial)
+        {
+            aiMaterial* out = new aiMaterial();
+            material_mapping[mat] = static_cast<unsigned int>(materials.size());
+            materials.push_back(out);
+
+            aiString ai_name;
+            name.GetCString(ai_name.data, MAXLEN-1);
+            ai_name.length = ::strlen(ai_name.data);
+            out->AddProperty(&ai_name, AI_MATKEY_NAME);
+
+            Material& m = dynamic_cast<Material&>(*mat);
+
+            if (m.GetChannelState(CHANNEL_COLOR))
+            {
+                GeData data;
+                mat->GetParameter(MATERIAL_COLOR_COLOR, data);
+                Vector color = data.GetVector();
+                mat->GetParameter(MATERIAL_COLOR_BRIGHTNESS, data);
+                const Real brightness = data.GetReal();
+
+                color *= brightness;
+
+                aiVector3D v;
+                v.x = color.x;
+                v.y = color.y;
+                v.z = color.z;
+                out->AddProperty(&v, 1, AI_MATKEY_COLOR_DIFFUSE);
+            }
+
+            BaseShader* const shader = m.GetShader(MATERIAL_COLOR_SHADER);
+            if(shader) {
+                ReadShader(out, shader);
+            }
+        }
+        else
+        {
+            LogWarn("ignoring plugin material: " + std::string(GetObjectTypeName(mat->GetType())));
+        }
+        mat = mat->GetNext();
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent)
 {
-	ai_assert(parent != NULL);
-	std::vector<aiNode*> nodes;
-
-	// based on Melange sample code
-	while (object)
-	{
-		const String& name = object->GetName();
-		const LONG type = object->GetType();
-		const Matrix& ml = object->GetMl();
-
-		aiString string;
-		name.GetCString(string.data, MAXLEN-1);
-		string.length = ::strlen(string.data);
-		aiNode* const nd = new aiNode();
-
-		nd->mParent = parent;
-		nd->mName = string;
-
-		nd->mTransformation.a1 = ml.v1.x;
-		nd->mTransformation.b1 = ml.v1.y;
-		nd->mTransformation.c1 = ml.v1.z;
-
-		nd->mTransformation.a2 = ml.v2.x;
-		nd->mTransformation.b2 = ml.v2.y;
-		nd->mTransformation.c2 = ml.v2.z;
-
-		nd->mTransformation.a3 = ml.v3.x;
-		nd->mTransformation.b3 = ml.v3.y;
-		nd->mTransformation.c3 = ml.v3.z;
-
-		nd->mTransformation.a4 = ml.off.x;
-		nd->mTransformation.b4 = ml.off.y;
-		nd->mTransformation.c4 = ml.off.z;
-
-		nodes.push_back(nd);
-
-		GeData data;
-		if (type == Ocamera)
-		{
-			object->GetParameter(CAMERAOBJECT_FOV, data);
-			// TODO: read camera
-		}
-		else if (type == Olight)
-		{
-			// TODO: read light
-		}
-		else if (type == Opolygon)
-		{
-			aiMesh* const mesh = ReadMesh(object);
-			if(mesh != NULL) {
-				nd->mNumMeshes = 1;
-				nd->mMeshes = new unsigned int[1];
-				nd->mMeshes[0] = static_cast<unsigned int>(meshes.size());
-				meshes.push_back(mesh);
-			}
-		}
-		else {
-			LogWarn("ignoring object: " + std::string(GetObjectTypeName(type)));
-		}
-
-		RecurseHierarchy(object->GetDown(), nd);
-		object = object->GetNext();
-	}
-
-	// copy nodes over to parent
-	parent->mNumChildren = static_cast<unsigned int>(nodes.size());
-	parent->mChildren = new aiNode*[parent->mNumChildren]();
-	std::copy(nodes.begin(), nodes.end(), parent->mChildren);
+    ai_assert(parent != NULL);
+    std::vector<aiNode*> nodes;
+
+    // based on Melange sample code
+    while (object)
+    {
+        const String& name = object->GetName();
+        const LONG type = object->GetType();
+        const Matrix& ml = object->GetMl();
+
+        aiString string;
+        name.GetCString(string.data, MAXLEN-1);
+        string.length = ::strlen(string.data);
+        aiNode* const nd = new aiNode();
+
+        nd->mParent = parent;
+        nd->mName = string;
+
+        nd->mTransformation.a1 = ml.v1.x;
+        nd->mTransformation.b1 = ml.v1.y;
+        nd->mTransformation.c1 = ml.v1.z;
+
+        nd->mTransformation.a2 = ml.v2.x;
+        nd->mTransformation.b2 = ml.v2.y;
+        nd->mTransformation.c2 = ml.v2.z;
+
+        nd->mTransformation.a3 = ml.v3.x;
+        nd->mTransformation.b3 = ml.v3.y;
+        nd->mTransformation.c3 = ml.v3.z;
+
+        nd->mTransformation.a4 = ml.off.x;
+        nd->mTransformation.b4 = ml.off.y;
+        nd->mTransformation.c4 = ml.off.z;
+
+        nodes.push_back(nd);
+
+        GeData data;
+        if (type == Ocamera)
+        {
+            object->GetParameter(CAMERAOBJECT_FOV, data);
+            // TODO: read camera
+        }
+        else if (type == Olight)
+        {
+            // TODO: read light
+        }
+        else if (type == Opolygon)
+        {
+            aiMesh* const mesh = ReadMesh(object);
+            if(mesh != NULL) {
+                nd->mNumMeshes = 1;
+                nd->mMeshes = new unsigned int[1];
+                nd->mMeshes[0] = static_cast<unsigned int>(meshes.size());
+                meshes.push_back(mesh);
+            }
+        }
+        else {
+            LogWarn("ignoring object: " + std::string(GetObjectTypeName(type)));
+        }
+
+        RecurseHierarchy(object->GetDown(), nd);
+        object = object->GetNext();
+    }
+
+    // copy nodes over to parent
+    parent->mNumChildren = static_cast<unsigned int>(nodes.size());
+    parent->mChildren = new aiNode*[parent->mNumChildren]();
+    std::copy(nodes.begin(), nodes.end(), parent->mChildren);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 aiMesh* C4DImporter::ReadMesh(BaseObject* object)
 {
-	assert(object != NULL && object->GetType() == Opolygon);
-
-	// based on Melange sample code
-	PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
-	ai_assert(polyObject != NULL);
-
-	const LONG pointCount = polyObject->GetPointCount();
-	const LONG polyCount = polyObject->GetPolygonCount();
-	if(!polyObject || !pointCount) {
-		LogWarn("ignoring mesh with zero vertices or faces");
-		return NULL;
-	}
-
-	const Vector* points = polyObject->GetPointR();
-	ai_assert(points != NULL);
-
-	const CPolygon* polys = polyObject->GetPolygonR();
-	ai_assert(polys != NULL);
-
-	ScopeGuard<aiMesh> mesh(new aiMesh());
-	mesh->mNumFaces = static_cast<unsigned int>(polyCount);
-	aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
-
-	mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
-	mesh->mMaterialIndex = 0;
-
-	unsigned int vcount = 0;
-
-	// first count vertices
-	for (LONG i = 0; i < polyCount; i++)
-	{
-		vcount += 3;
-
-		// TODO: do we also need to handle lines or points with similar checks?
-		if (polys[i].c != polys[i].d)
-		{
-			mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
-			++vcount;
-		}
-	}
-
-	ai_assert(vcount > 0);
-
-	mesh->mNumVertices = vcount;
-	aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
-	aiVector3D* normals, *uvs, *tangents, *bitangents;
-	unsigned int n = 0;
-
-	// check if there are normals, tangents or UVW coordinates
-	BaseTag* tag = object->GetTag(Tnormal);
-	NormalTag* normals_src = NULL;
-	if(tag) {
-		normals_src = dynamic_cast<NormalTag*>(tag);
-		normals = mesh->mNormals = new aiVector3D[mesh->mNumVertices]();
-	}
-
-	tag = object->GetTag(Ttangent);
-	TangentTag* tangents_src = NULL;
-	if(tag) {
-		tangents_src = dynamic_cast<TangentTag*>(tag);
-		tangents = mesh->mTangents = new aiVector3D[mesh->mNumVertices]();
-		bitangents = mesh->mBitangents = new aiVector3D[mesh->mNumVertices]();
-	}
-
-	tag = object->GetTag(Tuvw);
-	UVWTag* uvs_src = NULL;
-	if(tag) {
-		uvs_src = dynamic_cast<UVWTag*>(tag);
-		uvs = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]();
-	}
-
-	// copy vertices and extra channels over and populate faces
-	for (LONG i = 0; i < polyCount; ++i, ++face)
-	{
-		ai_assert(polys[i].a < pointCount && polys[i].a >= 0);
-		const Vector& pointA = points[polys[i].a];
-		verts->x = pointA.x;
-		verts->y = pointA.y;
-		verts->z = pointA.z;
-		++verts;
-
-		ai_assert(polys[i].b < pointCount && polys[i].b >= 0);
-		const Vector& pointB = points[polys[i].b];
-		verts->x = pointB.x;
-		verts->y = pointB.y;
-		verts->z = pointB.z;
-		++verts;
-
-		ai_assert(polys[i].c < pointCount && polys[i].c >= 0);
-		const Vector& pointC = points[polys[i].c];
-		verts->x = pointC.x;
-		verts->y = pointC.y;
-		verts->z = pointC.z;
-		++verts;
-
-		// TODO: do we also need to handle lines or points with similar checks?
-		if (polys[i].c != polys[i].d)
-		{
-			ai_assert(polys[i].d < pointCount && polys[i].d >= 0);
-
-			face->mNumIndices = 4;
-			mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
-			const Vector& pointD = points[polys[i].d];
-			verts->x = pointD.x;
-			verts->y = pointD.y;
-			verts->z = pointD.z;
-			++verts;
-		}
-		else {
-			face->mNumIndices = 3;
-		}
-		face->mIndices = new unsigned int[face->mNumIndices];
-		for(unsigned int j = 0; j < face->mNumIndices; ++j) {
-			face->mIndices[j] = n++;
-		}
-
-		// copy normals
-		if (normals_src) {
-			if(i >= normals_src->GetNormalCount()) {
-				LogError("unexpected number of normals, ignoring");
-			}
-			else {
-				const NormalStruct& nor = normals_src->GetNormals(i);
-				normals->x = nor.a.x;
-				normals->y = nor.a.y;
-				normals->z = nor.a.z;
-				++normals;
-
-				normals->x = nor.b.x;
-				normals->y = nor.b.y;
-				normals->z = nor.b.z;
-				++normals;
-
-				normals->x = nor.c.x;
-				normals->y = nor.c.y;
-				normals->z = nor.c.z;
-				++normals;
-
-				if(face->mNumIndices == 4) {
-					normals->x = nor.d.x;
-					normals->y = nor.d.y;
-					normals->z = nor.d.z;
-					++normals;
-				}
-			}
-		}
-
-		// copy tangents and bitangents
-		if (tangents_src) {
-
-			for(unsigned int k = 0; k < face->mNumIndices; ++k) {
-				LONG l;
-				switch(k) {
-				case 0:
-					l = polys[i].a;
-					break;
-				case 1:
-					l = polys[i].b;
-					break;
-				case 2:
-					l = polys[i].c;
-					break;
-				case 3:
-					l = polys[i].d;
-					break;
-				default:
-					ai_assert(false);
-				}
-				if(l >= tangents_src->GetDataCount()) {
-					LogError("unexpected number of tangents, ignoring");
-					break;
-				}
-
-				Tangent tan = tangents_src->GetDataR()[l];
-				tangents->x = tan.vl.x;
-				tangents->y = tan.vl.y;
-				tangents->z = tan.vl.z;
-				++tangents;
-
-				bitangents->x = tan.vr.x;
-				bitangents->y = tan.vr.y;
-				bitangents->z = tan.vr.z;
-				++bitangents;
-			}
-		}
-
-		// copy UVs
-		if (uvs_src) {
-			if(i >= uvs_src->GetDataCount()) {
-				LogError("unexpected number of UV coordinates, ignoring");
-			}
-			else {
-				UVWStruct uvw;
-				uvs_src->Get(uvs_src->GetDataAddressR(),i,uvw);
-
-				uvs->x = uvw.a.x;
-				uvs->y = 1.0f-uvw.a.y;
-				uvs->z = uvw.a.z;
-				++uvs;
-
-				uvs->x = uvw.b.x;
-				uvs->y = 1.0f-uvw.b.y;
-				uvs->z = uvw.b.z;
-				++uvs;
-
-				uvs->x = uvw.c.x;
-				uvs->y = 1.0f-uvw.c.y;
-				uvs->z = uvw.c.z;
-				++uvs;
-
-				if(face->mNumIndices == 4) {
-					uvs->x = uvw.d.x;
-					uvs->y = 1.0f-uvw.d.y;
-					uvs->z = uvw.d.z;
-					++uvs;
-				}
-			}
-		}
-	}
-
-	mesh->mMaterialIndex = ResolveMaterial(polyObject);
-	return mesh.dismiss();
+    assert(object != NULL && object->GetType() == Opolygon);
+
+    // based on Melange sample code
+    PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
+    ai_assert(polyObject != NULL);
+
+    const LONG pointCount = polyObject->GetPointCount();
+    const LONG polyCount = polyObject->GetPolygonCount();
+    if(!polyObject || !pointCount) {
+        LogWarn("ignoring mesh with zero vertices or faces");
+        return NULL;
+    }
+
+    const Vector* points = polyObject->GetPointR();
+    ai_assert(points != NULL);
+
+    const CPolygon* polys = polyObject->GetPolygonR();
+    ai_assert(polys != NULL);
+
+    ScopeGuard<aiMesh> mesh(new aiMesh());
+    mesh->mNumFaces = static_cast<unsigned int>(polyCount);
+    aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
+
+    mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+    mesh->mMaterialIndex = 0;
+
+    unsigned int vcount = 0;
+
+    // first count vertices
+    for (LONG i = 0; i < polyCount; i++)
+    {
+        vcount += 3;
+
+        // TODO: do we also need to handle lines or points with similar checks?
+        if (polys[i].c != polys[i].d)
+        {
+            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+            ++vcount;
+        }
+    }
+
+    ai_assert(vcount > 0);
+
+    mesh->mNumVertices = vcount;
+    aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+    aiVector3D* normals, *uvs, *tangents, *bitangents;
+    unsigned int n = 0;
+
+    // check if there are normals, tangents or UVW coordinates
+    BaseTag* tag = object->GetTag(Tnormal);
+    NormalTag* normals_src = NULL;
+    if(tag) {
+        normals_src = dynamic_cast<NormalTag*>(tag);
+        normals = mesh->mNormals = new aiVector3D[mesh->mNumVertices]();
+    }
+
+    tag = object->GetTag(Ttangent);
+    TangentTag* tangents_src = NULL;
+    if(tag) {
+        tangents_src = dynamic_cast<TangentTag*>(tag);
+        tangents = mesh->mTangents = new aiVector3D[mesh->mNumVertices]();
+        bitangents = mesh->mBitangents = new aiVector3D[mesh->mNumVertices]();
+    }
+
+    tag = object->GetTag(Tuvw);
+    UVWTag* uvs_src = NULL;
+    if(tag) {
+        uvs_src = dynamic_cast<UVWTag*>(tag);
+        uvs = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]();
+    }
+
+    // copy vertices and extra channels over and populate faces
+    for (LONG i = 0; i < polyCount; ++i, ++face)
+    {
+        ai_assert(polys[i].a < pointCount && polys[i].a >= 0);
+        const Vector& pointA = points[polys[i].a];
+        verts->x = pointA.x;
+        verts->y = pointA.y;
+        verts->z = pointA.z;
+        ++verts;
+
+        ai_assert(polys[i].b < pointCount && polys[i].b >= 0);
+        const Vector& pointB = points[polys[i].b];
+        verts->x = pointB.x;
+        verts->y = pointB.y;
+        verts->z = pointB.z;
+        ++verts;
+
+        ai_assert(polys[i].c < pointCount && polys[i].c >= 0);
+        const Vector& pointC = points[polys[i].c];
+        verts->x = pointC.x;
+        verts->y = pointC.y;
+        verts->z = pointC.z;
+        ++verts;
+
+        // TODO: do we also need to handle lines or points with similar checks?
+        if (polys[i].c != polys[i].d)
+        {
+            ai_assert(polys[i].d < pointCount && polys[i].d >= 0);
+
+            face->mNumIndices = 4;
+            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+            const Vector& pointD = points[polys[i].d];
+            verts->x = pointD.x;
+            verts->y = pointD.y;
+            verts->z = pointD.z;
+            ++verts;
+        }
+        else {
+            face->mNumIndices = 3;
+        }
+        face->mIndices = new unsigned int[face->mNumIndices];
+        for(unsigned int j = 0; j < face->mNumIndices; ++j) {
+            face->mIndices[j] = n++;
+        }
+
+        // copy normals
+        if (normals_src) {
+            if(i >= normals_src->GetNormalCount()) {
+                LogError("unexpected number of normals, ignoring");
+            }
+            else {
+                const NormalStruct& nor = normals_src->GetNormals(i);
+                normals->x = nor.a.x;
+                normals->y = nor.a.y;
+                normals->z = nor.a.z;
+                ++normals;
+
+                normals->x = nor.b.x;
+                normals->y = nor.b.y;
+                normals->z = nor.b.z;
+                ++normals;
+
+                normals->x = nor.c.x;
+                normals->y = nor.c.y;
+                normals->z = nor.c.z;
+                ++normals;
+
+                if(face->mNumIndices == 4) {
+                    normals->x = nor.d.x;
+                    normals->y = nor.d.y;
+                    normals->z = nor.d.z;
+                    ++normals;
+                }
+            }
+        }
+
+        // copy tangents and bitangents
+        if (tangents_src) {
+
+            for(unsigned int k = 0; k < face->mNumIndices; ++k) {
+                LONG l;
+                switch(k) {
+                case 0:
+                    l = polys[i].a;
+                    break;
+                case 1:
+                    l = polys[i].b;
+                    break;
+                case 2:
+                    l = polys[i].c;
+                    break;
+                case 3:
+                    l = polys[i].d;
+                    break;
+                default:
+                    ai_assert(false);
+                }
+                if(l >= tangents_src->GetDataCount()) {
+                    LogError("unexpected number of tangents, ignoring");
+                    break;
+                }
+
+                Tangent tan = tangents_src->GetDataR()[l];
+                tangents->x = tan.vl.x;
+                tangents->y = tan.vl.y;
+                tangents->z = tan.vl.z;
+                ++tangents;
+
+                bitangents->x = tan.vr.x;
+                bitangents->y = tan.vr.y;
+                bitangents->z = tan.vr.z;
+                ++bitangents;
+            }
+        }
+
+        // copy UVs
+        if (uvs_src) {
+            if(i >= uvs_src->GetDataCount()) {
+                LogError("unexpected number of UV coordinates, ignoring");
+            }
+            else {
+                UVWStruct uvw;
+                uvs_src->Get(uvs_src->GetDataAddressR(),i,uvw);
+
+                uvs->x = uvw.a.x;
+                uvs->y = 1.0f-uvw.a.y;
+                uvs->z = uvw.a.z;
+                ++uvs;
+
+                uvs->x = uvw.b.x;
+                uvs->y = 1.0f-uvw.b.y;
+                uvs->z = uvw.b.z;
+                ++uvs;
+
+                uvs->x = uvw.c.x;
+                uvs->y = 1.0f-uvw.c.y;
+                uvs->z = uvw.c.z;
+                ++uvs;
+
+                if(face->mNumIndices == 4) {
+                    uvs->x = uvw.d.x;
+                    uvs->y = 1.0f-uvw.d.y;
+                    uvs->z = uvw.d.z;
+                    ++uvs;
+                }
+            }
+        }
+    }
+
+    mesh->mMaterialIndex = ResolveMaterial(polyObject);
+    return mesh.dismiss();
 }
 
 
 // ------------------------------------------------------------------------------------------------
 unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj)
 {
-	ai_assert(obj != NULL);
+    ai_assert(obj != NULL);
 
-	const unsigned int mat_count = static_cast<unsigned int>(materials.size());
+    const unsigned int mat_count = static_cast<unsigned int>(materials.size());
 
-	BaseTag* tag = obj->GetTag(Ttexture);
-	if(tag == NULL) {
-		return mat_count;
-	}
+    BaseTag* tag = obj->GetTag(Ttexture);
+    if(tag == NULL) {
+        return mat_count;
+    }
 
-	TextureTag& ttag = dynamic_cast<TextureTag&>(*tag);
+    TextureTag& ttag = dynamic_cast<TextureTag&>(*tag);
 
-	BaseMaterial* const mat = ttag.GetMaterial();
-	assert(mat != NULL);
+    BaseMaterial* const mat = ttag.GetMaterial();
+    assert(mat != NULL);
 
-	const MaterialMap::const_iterator it = material_mapping.find(mat);
-	if(it == material_mapping.end()) {
-		return mat_count;
-	}
+    const MaterialMap::const_iterator it = material_mapping.find(mat);
+    if(it == material_mapping.end()) {
+        return mat_count;
+    }
 
-	ai_assert((*it).second < mat_count);
-	return (*it).second;
+    ai_assert((*it).second < mat_count);
+    return (*it).second;
 }
 
 #endif // ASSIMP_BUILD_NO_C4D_IMPORTER

+ 31 - 31
code/C4DImporter.h

@@ -55,19 +55,19 @@ struct aiMaterial;
 struct aiImporterDesc;
 
 namespace _melange_ {
-	class BaseObject; // c4d_file.h
-	class PolygonObject;
-	class BaseMaterial;
-	class BaseShader;
+    class BaseObject; // c4d_file.h
+    class PolygonObject;
+    class BaseMaterial;
+    class BaseShader;
 }
 
-namespace Assimp	{
+namespace Assimp    {
 
-	// TinyFormatter.h
-	namespace Formatter {
-		template <typename T,typename TR, typename A> class basic_formatter;
-		typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
-	}
+    // TinyFormatter.h
+    namespace Formatter {
+        template <typename T,typename TR, typename A> class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
+    }
 
 // -------------------------------------------------------------------------------------------
 /** Importer class to load Cinema4D files using the Melange library to be obtained from
@@ -79,42 +79,42 @@ class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter>
 {
 public:
 
-	C4DImporter();
-	~C4DImporter();
+    C4DImporter();
+    ~C4DImporter();
 
 
 public:
 
-	// --------------------
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-		bool checkSig) const;
+    // --------------------
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
 
 protected:
 
-	// --------------------
-	const aiImporterDesc* GetInfo () const;
+    // --------------------
+    const aiImporterDesc* GetInfo () const;
 
-	// --------------------
-	void SetupProperties(const Importer* pImp);
+    // --------------------
+    void SetupProperties(const Importer* pImp);
 
-	// --------------------
-	void InternReadFile( const std::string& pFile, aiScene* pScene,
-		IOSystem* pIOHandler);
+    // --------------------
+    void InternReadFile( const std::string& pFile, aiScene* pScene,
+        IOSystem* pIOHandler);
 
 private:
 
-	void ReadMaterials(_melange_::BaseMaterial* mat);
-	void RecurseHierarchy(_melange_::BaseObject* object, aiNode* parent);
-	aiMesh* ReadMesh(_melange_::BaseObject* object);
-	unsigned int ResolveMaterial(_melange_::PolygonObject* obj);
+    void ReadMaterials(_melange_::BaseMaterial* mat);
+    void RecurseHierarchy(_melange_::BaseObject* object, aiNode* parent);
+    aiMesh* ReadMesh(_melange_::BaseObject* object);
+    unsigned int ResolveMaterial(_melange_::PolygonObject* obj);
 
-	bool ReadShader(aiMaterial* out, _melange_::BaseShader* shader);
+    bool ReadShader(aiMaterial* out, _melange_::BaseShader* shader);
 
-	std::vector<aiMesh*> meshes;
-	std::vector<aiMaterial*> materials;
+    std::vector<aiMesh*> meshes;
+    std::vector<aiMaterial*> materials;
 
-	typedef std::map<_melange_::BaseMaterial*, unsigned int> MaterialMap;
-	MaterialMap material_mapping;
+    typedef std::map<_melange_::BaseMaterial*, unsigned int> MaterialMap;
+    MaterialMap material_mapping;
 
 }; // !class C4DImporter
 

+ 84 - 84
code/CInterfaceIOWrapper.h

@@ -48,61 +48,61 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/IOStream.hpp"
 #include "../include/assimp/IOSystem.hpp"
 
-namespace Assimp	{
+namespace Assimp    {
 
 // ------------------------------------------------------------------------------------------------
 // Custom IOStream implementation for the C-API
 class CIOStreamWrapper : public IOStream
 {
-	friend class CIOSystemWrapper;
+    friend class CIOSystemWrapper;
 public:
 
-	CIOStreamWrapper(aiFile* pFile)
-		: mFile(pFile)
-	{}
-
-	// ...................................................................
-	size_t Read(void* pvBuffer,
-		size_t pSize,
-		size_t pCount
-	){
-		// need to typecast here as C has no void*
-		return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
-	}
-
-	// ...................................................................
-	size_t Write(const void* pvBuffer,
-		size_t pSize,
-		size_t pCount
-	){
-		// need to typecast here as C has no void*
-		return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
-	}
-
-	// ...................................................................
-	aiReturn Seek(size_t pOffset,
-		aiOrigin pOrigin
-	){
-		return mFile->SeekProc(mFile,pOffset,pOrigin);
-	}
-
-	// ...................................................................
-	size_t Tell(void) const {
-		return mFile->TellProc(mFile);
-	}
-
-	// ...................................................................
-	size_t	FileSize() const {
-		return mFile->FileSizeProc(mFile);
-	}
-
-	// ...................................................................
-	void Flush () {
-		return mFile->FlushProc(mFile);
-	}
+    CIOStreamWrapper(aiFile* pFile)
+        : mFile(pFile)
+    {}
+
+    // ...................................................................
+    size_t Read(void* pvBuffer,
+        size_t pSize,
+        size_t pCount
+    ){
+        // need to typecast here as C has no void*
+        return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
+    }
+
+    // ...................................................................
+    size_t Write(const void* pvBuffer,
+        size_t pSize,
+        size_t pCount
+    ){
+        // need to typecast here as C has no void*
+        return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
+    }
+
+    // ...................................................................
+    aiReturn Seek(size_t pOffset,
+        aiOrigin pOrigin
+    ){
+        return mFile->SeekProc(mFile,pOffset,pOrigin);
+    }
+
+    // ...................................................................
+    size_t Tell(void) const {
+        return mFile->TellProc(mFile);
+    }
+
+    // ...................................................................
+    size_t  FileSize() const {
+        return mFile->FileSizeProc(mFile);
+    }
+
+    // ...................................................................
+    void Flush () {
+        return mFile->FlushProc(mFile);
+    }
 
 private:
-	aiFile* mFile;
+    aiFile* mFile;
 };
 
 // ------------------------------------------------------------------------------------------------
@@ -110,48 +110,48 @@ private:
 class CIOSystemWrapper : public IOSystem
 {
 public:
-	CIOSystemWrapper(aiFileIO* pFile)
-		: mFileSystem(pFile)
-	{}
-
-	// ...................................................................
-	bool Exists( const char* pFile) const {
-		aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb");
-		if (p){
-			mFileSystem->CloseProc(mFileSystem,p);
-			return true;
-		}
-		return false;
-	}
-
-	// ...................................................................
-	char getOsSeparator() const {
+    CIOSystemWrapper(aiFileIO* pFile)
+        : mFileSystem(pFile)
+    {}
+
+    // ...................................................................
+    bool Exists( const char* pFile) const {
+        aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb");
+        if (p){
+            mFileSystem->CloseProc(mFileSystem,p);
+            return true;
+        }
+        return false;
+    }
+
+    // ...................................................................
+    char getOsSeparator() const {
 #ifndef _WIN32
-		return '/';
+        return '/';
 #else
-		return '\\';
+        return '\\';
 #endif
-	}
-
-	// ...................................................................
-	IOStream* Open(const char* pFile,const char* pMode = "rb") {
-		aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode);
-		if (!p) {
-			return NULL;
-		}
-		return new CIOStreamWrapper(p);
-	}
-
-	// ...................................................................
-	void Close( IOStream* pFile) {
-		if (!pFile) {
-			return;
-		}
-		mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
-		delete pFile;
-	}
+    }
+
+    // ...................................................................
+    IOStream* Open(const char* pFile,const char* pMode = "rb") {
+        aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode);
+        if (!p) {
+            return NULL;
+        }
+        return new CIOStreamWrapper(p);
+    }
+
+    // ...................................................................
+    void Close( IOStream* pFile) {
+        if (!pFile) {
+            return;
+        }
+        mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
+        delete pFile;
+    }
 private:
-	aiFileIO* mFileSystem;
+    aiFileIO* mFileSystem;
 };
 
 }

File diff suppressed because it is too large
+ 692 - 692
code/COBLoader.cpp


+ 76 - 76
code/COBLoader.h

@@ -49,21 +49,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiNode;
 
-namespace Assimp	{
-	class LineSplitter;
-
-	// TinyFormatter.h
-	namespace Formatter {
-		template <typename T,typename TR, typename A> class basic_formatter;
-		typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
-	}
-
-	// COBScene.h
-	namespace COB {
-		struct ChunkInfo;
-		struct Node;
-		struct Scene;
-	}
+namespace Assimp    {
+    class LineSplitter;
+
+    // TinyFormatter.h
+    namespace Formatter {
+        template <typename T,typename TR, typename A> class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
+    }
+
+    // COBScene.h
+    namespace COB {
+        struct ChunkInfo;
+        struct Node;
+        struct Scene;
+    }
 
 // -------------------------------------------------------------------------------------------
 /** Importer class to load TrueSpace files (cob,scn) up to v6.
@@ -73,99 +73,99 @@ namespace Assimp	{
 class COBImporter : public BaseImporter
 {
 public:
-	COBImporter();
-	~COBImporter();
+    COBImporter();
+    ~COBImporter();
 
 
 public:
 
-	// --------------------
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-		bool checkSig) const;
+    // --------------------
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
 
 protected:
 
-	// --------------------
-	const aiImporterDesc* GetInfo () const;
+    // --------------------
+    const aiImporterDesc* GetInfo () const;
 
-	// --------------------
-	void SetupProperties(const Importer* pImp);
+    // --------------------
+    void SetupProperties(const Importer* pImp);
 
-	// --------------------
-	void InternReadFile( const std::string& pFile, aiScene* pScene,
-		IOSystem* pIOHandler);
+    // --------------------
+    void InternReadFile( const std::string& pFile, aiScene* pScene,
+        IOSystem* pIOHandler);
 
 private:
 
-	// -------------------------------------------------------------------
-	/** Prepend 'COB: ' and throw msg.*/
-	AI_WONT_RETURN static void ThrowException(const std::string& msg) AI_WONT_RETURN_SUFFIX;
+    // -------------------------------------------------------------------
+    /** Prepend 'COB: ' and throw msg.*/
+    AI_WONT_RETURN static void ThrowException(const std::string& msg) AI_WONT_RETURN_SUFFIX;
 
-	// -------------------------------------------------------------------
-	/** @brief Read from an ascii scene/object file
-	 *  @param out Receives output data.
-	 *  @param stream Stream to read from. */
-	void ReadAsciiFile(COB::Scene& out, StreamReaderLE* stream);
+    // -------------------------------------------------------------------
+    /** @brief Read from an ascii scene/object file
+     *  @param out Receives output data.
+     *  @param stream Stream to read from. */
+    void ReadAsciiFile(COB::Scene& out, StreamReaderLE* stream);
 
-	// -------------------------------------------------------------------
-	/** @brief Read from a binary scene/object file
-	 *  @param out Receives output data.
-	 *  @param stream Stream to read from.  */
-	void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream);
+    // -------------------------------------------------------------------
+    /** @brief Read from a binary scene/object file
+     *  @param out Receives output data.
+     *  @param stream Stream to read from.  */
+    void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream);
 
 
 private:
 
-	// Conversion to Assimp output format
+    // Conversion to Assimp output format
 
-	aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill);
+    aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill);
 
 private:
 
-	// ASCII file support
+    // ASCII file support
 
-	void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name);
-	void ReadChunkInfo_Ascii(COB::ChunkInfo& out, const LineSplitter& splitter);
-	void ReadBasicNodeInfo_Ascii(COB::Node& msh, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	template <typename T> void ReadFloat3Tuple_Ascii(T& fill, const char** in);
+    void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name);
+    void ReadChunkInfo_Ascii(COB::ChunkInfo& out, const LineSplitter& splitter);
+    void ReadBasicNodeInfo_Ascii(COB::Node& msh, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    template <typename T> void ReadFloat3Tuple_Ascii(T& fill, const char** in);
 
-	void ReadPolH_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadBitM_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadMat1_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadGrou_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadBone_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadCame_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadLght_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadUnit_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
-	void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadPolH_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadBitM_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadMat1_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadGrou_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadBone_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadCame_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadLght_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadUnit_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
+    void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
 
 
-	// ASCII file logging stuff to add proper line numbers to messages
+    // ASCII file logging stuff to add proper line numbers to messages
 
-	static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message);
-	static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message);
-	static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message);
-	static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message);
+    static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message);
+    static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message);
+    static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message);
+    static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message);
 
-	static void LogWarn_Ascii  (const Formatter::format& message);
-	static void LogError_Ascii (const Formatter::format& message);
-	static void LogInfo_Ascii  (const Formatter::format& message);
-	static void LogDebug_Ascii (const Formatter::format& message);
+    static void LogWarn_Ascii  (const Formatter::format& message);
+    static void LogError_Ascii (const Formatter::format& message);
+    static void LogInfo_Ascii  (const Formatter::format& message);
+    static void LogDebug_Ascii (const Formatter::format& message);
 
 
-	// Binary file support
+    // Binary file support
 
-	void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name);
-	void ReadString_Binary(std::string& out, StreamReaderLE& reader);
-	void ReadBasicNodeInfo_Binary(COB::Node& msh, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name);
+    void ReadString_Binary(std::string& out, StreamReaderLE& reader);
+    void ReadBasicNodeInfo_Binary(COB::Node& msh, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
 
-	void ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
-	void ReadBitM_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
-	void ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
-	void ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
-	void ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
-	void ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
-	void ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void ReadBitM_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
+    void ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
 
 
 }; // !class COBImporter

+ 115 - 115
code/COBScene.h

@@ -50,208 +50,208 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BaseImporter.h"
 #include "./../include/assimp/material.h"
 
-namespace Assimp	{
-	namespace COB {
+namespace Assimp    {
+    namespace COB {
 
 // ------------------
 /** Represents a single vertex index in a face */
 struct VertexIndex
 {
-	// intentionally uninitialized
-	unsigned int pos_idx,uv_idx;
+    // intentionally uninitialized
+    unsigned int pos_idx,uv_idx;
 };
 
 // ------------------
 /** COB Face data structure */
 struct Face
 {
-	// intentionally uninitialized
-	unsigned int material, flags;
-	std::vector<VertexIndex> indices;
+    // intentionally uninitialized
+    unsigned int material, flags;
+    std::vector<VertexIndex> indices;
 };
 
 // ------------------
 /** COB chunk header information */
 struct ChunkInfo
 {
-	enum {NO_SIZE=UINT_MAX};
+    enum {NO_SIZE=UINT_MAX};
 
-	ChunkInfo ()
-		:	id        (0)
-		,	parent_id (0)
-		,	version	  (0)
-		,	size	  (NO_SIZE)
-	{}
+    ChunkInfo ()
+        :   id        (0)
+        ,   parent_id (0)
+        ,   version   (0)
+        ,   size      (NO_SIZE)
+    {}
 
-	// Id of this chunk, unique within file
-	unsigned int id;
+    // Id of this chunk, unique within file
+    unsigned int id;
 
-	// and the corresponding parent
-	unsigned int parent_id;
+    // and the corresponding parent
+    unsigned int parent_id;
 
-	// version. v1.23 becomes 123
-	unsigned int version;
+    // version. v1.23 becomes 123
+    unsigned int version;
 
-	// chunk size in bytes, only relevant for binary files
-	// NO_SIZE is also valid.
-	unsigned int size;
+    // chunk size in bytes, only relevant for binary files
+    // NO_SIZE is also valid.
+    unsigned int size;
 };
 
 // ------------------
 /** A node in the scenegraph */
 struct Node : public ChunkInfo
 {
-	enum Type {
-		TYPE_MESH,TYPE_GROUP,TYPE_LIGHT,TYPE_CAMERA,TYPE_BONE
-	};
+    enum Type {
+        TYPE_MESH,TYPE_GROUP,TYPE_LIGHT,TYPE_CAMERA,TYPE_BONE
+    };
 
-	virtual ~Node() {}
-	Node(Type type) : type(type), unit_scale(1.f){}
+    virtual ~Node() {}
+    Node(Type type) : type(type), unit_scale(1.f){}
 
-	Type type;
+    Type type;
 
-	// used during resolving
-	typedef std::deque<const Node*> ChildList;
-	mutable ChildList temp_children;
+    // used during resolving
+    typedef std::deque<const Node*> ChildList;
+    mutable ChildList temp_children;
 
-	// unique name
-	std::string name;
+    // unique name
+    std::string name;
 
-	// local mesh transformation
-	aiMatrix4x4 transform;
+    // local mesh transformation
+    aiMatrix4x4 transform;
 
-	// scaling for this node to get to the metric system
-	float unit_scale;
+    // scaling for this node to get to the metric system
+    float unit_scale;
 };
 
 // ------------------
 /** COB Mesh data structure */
 struct Mesh : public Node
 {
-	using ChunkInfo::operator=;
-	enum DrawFlags {
-		SOLID = 0x1,
-		TRANS = 0x2,
-		WIRED = 0x4,
-		BBOX  = 0x8,
-		HIDE  = 0x10
-	};
-
-	Mesh()
-		: Node(TYPE_MESH)
-		, draw_flags(SOLID)
-	{}
-
-	// vertex elements
-	std::vector<aiVector2D> texture_coords;
-	std::vector<aiVector3D> vertex_positions;
-
-	// face data
-	std::vector<Face> faces;
-
-	// misc. drawing flags
-	unsigned int draw_flags;
-
-	// used during resolving
-	typedef std::deque<Face*> FaceRefList;
-	typedef std::map< unsigned int,FaceRefList > TempMap;
-	TempMap temp_map;
+    using ChunkInfo::operator=;
+    enum DrawFlags {
+        SOLID = 0x1,
+        TRANS = 0x2,
+        WIRED = 0x4,
+        BBOX  = 0x8,
+        HIDE  = 0x10
+    };
+
+    Mesh()
+        : Node(TYPE_MESH)
+        , draw_flags(SOLID)
+    {}
+
+    // vertex elements
+    std::vector<aiVector2D> texture_coords;
+    std::vector<aiVector3D> vertex_positions;
+
+    // face data
+    std::vector<Face> faces;
+
+    // misc. drawing flags
+    unsigned int draw_flags;
+
+    // used during resolving
+    typedef std::deque<Face*> FaceRefList;
+    typedef std::map< unsigned int,FaceRefList > TempMap;
+    TempMap temp_map;
 };
 
 // ------------------
 /** COB Group data structure */
 struct Group : public Node
 {
-	using ChunkInfo::operator=;
-	Group() : Node(TYPE_GROUP) {}
+    using ChunkInfo::operator=;
+    Group() : Node(TYPE_GROUP) {}
 };
 
 // ------------------
 /** COB Bone data structure */
 struct Bone : public Node
 {
-	using ChunkInfo::operator=;
-	Bone() : Node(TYPE_BONE) {}
+    using ChunkInfo::operator=;
+    Bone() : Node(TYPE_BONE) {}
 };
 
 // ------------------
 /** COB Light data structure */
 struct Light : public Node
 {
-	enum LightType {
-		SPOT,LOCAL,INFINITE
-	};
+    enum LightType {
+        SPOT,LOCAL,INFINITE
+    };
 
-	using ChunkInfo::operator=;
-	Light() : Node(TYPE_LIGHT),angle(),inner_angle(),ltype(SPOT) {}
+    using ChunkInfo::operator=;
+    Light() : Node(TYPE_LIGHT),angle(),inner_angle(),ltype(SPOT) {}
 
-	aiColor3D color;
-	float angle,inner_angle;
+    aiColor3D color;
+    float angle,inner_angle;
 
-	LightType ltype;
+    LightType ltype;
 };
 
 // ------------------
 /** COB Camera data structure */
 struct Camera : public Node
 {
-	using ChunkInfo::operator=;
-	Camera() : Node(TYPE_CAMERA) {}
+    using ChunkInfo::operator=;
+    Camera() : Node(TYPE_CAMERA) {}
 };
 
 // ------------------
 /** COB Texture data structure */
 struct Texture
 {
-	std::string path;
-	aiUVTransform transform;
+    std::string path;
+    aiUVTransform transform;
 };
 
 // ------------------
 /** COB Material data structure */
 struct Material : ChunkInfo
 {
-	using ChunkInfo::operator=;
-	enum Shader {
-		FLAT,PHONG,METAL
-	};
+    using ChunkInfo::operator=;
+    enum Shader {
+        FLAT,PHONG,METAL
+    };
 
-	enum AutoFacet {
-		FACETED,AUTOFACETED,SMOOTH
-	};
+    enum AutoFacet {
+        FACETED,AUTOFACETED,SMOOTH
+    };
 
-	Material() : alpha(),exp(),ior(),ka(),ks(1.f),
-		matnum(UINT_MAX),
-		shader(FLAT),autofacet(FACETED),
-		autofacet_angle()
-	{}
+    Material() : alpha(),exp(),ior(),ka(),ks(1.f),
+        matnum(UINT_MAX),
+        shader(FLAT),autofacet(FACETED),
+        autofacet_angle()
+    {}
 
-	std::string type;
+    std::string type;
 
-	aiColor3D rgb;
-	float alpha, exp, ior,ka,ks;
+    aiColor3D rgb;
+    float alpha, exp, ior,ka,ks;
 
-	unsigned int matnum;
-	Shader shader;
+    unsigned int matnum;
+    Shader shader;
 
-	AutoFacet autofacet;
-	float autofacet_angle;
+    AutoFacet autofacet;
+    float autofacet_angle;
 
-	boost::shared_ptr<Texture> tex_env,tex_bump,tex_color;
+    boost::shared_ptr<Texture> tex_env,tex_bump,tex_color;
 };
 
 // ------------------
 /** Embedded bitmap, for instance for the thumbnail image */
 struct Bitmap : ChunkInfo
 {
-	Bitmap() : orig_size() {}
-	struct BitmapHeader
-	{
-	};
-
-	BitmapHeader head;
-	size_t orig_size;
-	std::vector<char> buff_zipped;
+    Bitmap() : orig_size() {}
+    struct BitmapHeader
+    {
+    };
+
+    BitmapHeader head;
+    size_t orig_size;
+    std::vector<char> buff_zipped;
 };
 
 typedef std::deque< boost::shared_ptr<Node> > NodeList;
@@ -261,14 +261,14 @@ typedef std::vector< Material > MaterialList;
 /** Represents a master COB scene, even if we loaded just a single COB file */
 struct Scene
 {
-	NodeList nodes;
-	MaterialList materials;
+    NodeList nodes;
+    MaterialList materials;
 
-	// becomes *0 later
-	Bitmap thumbnail;
+    // becomes *0 later
+    Bitmap thumbnail;
 };
 
-	} // end COB
+    } // end COB
 } // end Assimp
 
 #endif

+ 201 - 201
code/CSMLoader.cpp

@@ -62,16 +62,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-	"CharacterStudio Motion Importer (MoCap)",
-	"",
-	"",
-	"",
-	aiImporterFlags_SupportTextFlavour,
-	0,
-	0,
-	0,
-	0,
-	"csm"
+    "CharacterStudio Motion Importer (MoCap)",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "csm"
 };
 
 
@@ -90,217 +90,217 @@ CSMImporter::~CSMImporter()
 // Returns whether the class can handle the format of the given file.
 bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-	// check file extension
-	const std::string extension = GetExtension(pFile);
+    // check file extension
+    const std::string extension = GetExtension(pFile);
 
-	if( extension == "csm")
-		return true;
+    if( extension == "csm")
+        return true;
 
-	if ((checkSig || !extension.length()) && pIOHandler) {
-		const char* tokens[] = {"$Filename"};
-		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-	}
-	return false;
+    if ((checkSig || !extension.length()) && pIOHandler) {
+        const char* tokens[] = {"$Filename"};
+        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Build a string of all file extensions supported
 const aiImporterDesc* CSMImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup configuration properties for the loader
 void CSMImporter::SetupProperties(const Importer* pImp)
 {
-	noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
+    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void CSMImporter::InternReadFile( const std::string& pFile,
-	aiScene* pScene, IOSystem* pIOHandler)
+    aiScene* pScene, IOSystem* pIOHandler)
 {
-	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
-
-	// Check whether we can read from the file
-	if( file.get() == NULL) {
-		throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
-	}
-
-	// allocate storage and copy the contents of the file to a memory buffer
-	std::vector<char> mBuffer2;
-	TextFileToBuffer(file.get(),mBuffer2);
-	const char* buffer = &mBuffer2[0];
-
-	aiAnimation* anim = new aiAnimation();
-	int first = 0, last = 0x00ffffff;
-
-	// now process the file and look out for '$' sections
-	while (1)	{
-		SkipSpaces(&buffer);
-		if ('\0' == *buffer)
-			break;
-
-		if ('$'  == *buffer)	{
-			++buffer;
-			if (TokenMatchI(buffer,"firstframe",10))	{
-				SkipSpaces(&buffer);
-				first = strtol10(buffer,&buffer);
-			}
-			else if (TokenMatchI(buffer,"lastframe",9))		{
-				SkipSpaces(&buffer);
-				last = strtol10(buffer,&buffer);
-			}
-			else if (TokenMatchI(buffer,"rate",4))	{
-				SkipSpaces(&buffer);
-				float d;
-				buffer = fast_atoreal_move<float>(buffer,d);
-				anim->mTicksPerSecond = d;
-			}
-			else if (TokenMatchI(buffer,"order",5))	{
-				std::vector< aiNodeAnim* > anims_temp;
-				anims_temp.reserve(30);
-				while (1)	{
-					SkipSpaces(&buffer);
-					if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
-						break; // next section
-
-					// Construct a new node animation channel and setup its name
-					anims_temp.push_back(new aiNodeAnim());
-					aiNodeAnim* nda = anims_temp.back();
-
-					char* ot = nda->mNodeName.data;
-					while (!IsSpaceOrNewLine(*buffer))
-						*ot++ = *buffer++;
-
-					*ot = '\0';
-					nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
-				}
-
-				anim->mNumChannels = anims_temp.size();
-				if (!anim->mNumChannels)
-					throw DeadlyImportError("CSM: Empty $order section");
-
-				// copy over to the output animation
-				anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
-				::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
-			}
-			else if (TokenMatchI(buffer,"points",6))	{
-				if (!anim->mNumChannels)
-					throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
-
-				// If we know how many frames we'll read, we can preallocate some storage
-				unsigned int alloc = 100;
-				if (last != 0x00ffffff)
-				{
-					alloc = last-first;
-					alloc += alloc>>2u; // + 25%
-					for (unsigned int i = 0; i < anim->mNumChannels;++i)
-						anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
-				}
-
-				unsigned int filled = 0;
-
-				// Now read all point data.
-				while (1)	{
-					SkipSpaces(&buffer);
-					if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$'))	{
-						break; // next section
-					}
-
-					// read frame
-					const int frame = ::strtoul10(buffer,&buffer);
-					last  = std::max(frame,last);
-					first = std::min(frame,last);
-					for (unsigned int i = 0; i < anim->mNumChannels;++i)	{
-
-						aiNodeAnim* s = anim->mChannels[i];
-						if (s->mNumPositionKeys == alloc)	{ /* need to reallocate? */
-
-							aiVectorKey* old = s->mPositionKeys;
-							s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
-							::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
-							delete[] old;
-						}
-
-						// read x,y,z
-						if(!SkipSpacesAndLineEnd(&buffer))
-							throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord");
-
-						if (TokenMatchI(buffer, "DROPOUT", 7))	{
-							// seems this is invalid marker data; at least the doc says it's possible
-							DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)");
-						}
-						else	{
-							aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
-							sub->mTime = (double)frame;
-							buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
-
-							if(!SkipSpacesAndLineEnd(&buffer))
-								throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord");
-							buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
-
-							if(!SkipSpacesAndLineEnd(&buffer))
-								throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord");
-							buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
-
-							++s->mNumPositionKeys;
-						}
-					}
-
-					// update allocation granularity
-					if (filled == alloc)
-						alloc *= 2;
-
-					++filled;
-				}
-				// all channels must be complete in order to continue safely.
-				for (unsigned int i = 0; i < anim->mNumChannels;++i)	{
-
-					if (!anim->mChannels[i]->mNumPositionKeys)
-						throw DeadlyImportError("CSM: Invalid marker track");
-				}
-			}
-		}
-		else	{
-			// advance to the next line
-			SkipLine(&buffer);
-		}
-	}
-
-	// Setup a proper animation duration
-	anim->mDuration = last - std::min( first, 0 );
-
-	// build a dummy root node with the tiny markers as children
-	pScene->mRootNode = new aiNode();
-	pScene->mRootNode->mName.Set("$CSM_DummyRoot");
-
-	pScene->mRootNode->mNumChildren = anim->mNumChannels;
-	pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels];
-
-	for (unsigned int i = 0; i < anim->mNumChannels;++i)	{
-		aiNodeAnim* na = anim->mChannels[i];
-
-		aiNode* nd  = pScene->mRootNode->mChildren[i] = new aiNode();
-		nd->mName   = anim->mChannels[i]->mNodeName;
-		nd->mParent = pScene->mRootNode;
-
-		aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation);
-	}
-
-	// Store the one and only animation in the scene
-	pScene->mAnimations    = new aiAnimation*[pScene->mNumAnimations=1];
-	pScene->mAnimations[0] = anim;
-	anim->mName.Set("$CSM_MasterAnim");
-
-	// mark the scene as incomplete and run SkeletonMeshBuilder on it
-	pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
-
-	if (!noSkeletonMesh) {
-		SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true);
-	}
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
+
+    // Check whether we can read from the file
+    if( file.get() == NULL) {
+        throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
+    }
+
+    // allocate storage and copy the contents of the file to a memory buffer
+    std::vector<char> mBuffer2;
+    TextFileToBuffer(file.get(),mBuffer2);
+    const char* buffer = &mBuffer2[0];
+
+    aiAnimation* anim = new aiAnimation();
+    int first = 0, last = 0x00ffffff;
+
+    // now process the file and look out for '$' sections
+    while (1)   {
+        SkipSpaces(&buffer);
+        if ('\0' == *buffer)
+            break;
+
+        if ('$'  == *buffer)    {
+            ++buffer;
+            if (TokenMatchI(buffer,"firstframe",10))    {
+                SkipSpaces(&buffer);
+                first = strtol10(buffer,&buffer);
+            }
+            else if (TokenMatchI(buffer,"lastframe",9))     {
+                SkipSpaces(&buffer);
+                last = strtol10(buffer,&buffer);
+            }
+            else if (TokenMatchI(buffer,"rate",4))  {
+                SkipSpaces(&buffer);
+                float d;
+                buffer = fast_atoreal_move<float>(buffer,d);
+                anim->mTicksPerSecond = d;
+            }
+            else if (TokenMatchI(buffer,"order",5)) {
+                std::vector< aiNodeAnim* > anims_temp;
+                anims_temp.reserve(30);
+                while (1)   {
+                    SkipSpaces(&buffer);
+                    if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
+                        break; // next section
+
+                    // Construct a new node animation channel and setup its name
+                    anims_temp.push_back(new aiNodeAnim());
+                    aiNodeAnim* nda = anims_temp.back();
+
+                    char* ot = nda->mNodeName.data;
+                    while (!IsSpaceOrNewLine(*buffer))
+                        *ot++ = *buffer++;
+
+                    *ot = '\0';
+                    nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
+                }
+
+                anim->mNumChannels = anims_temp.size();
+                if (!anim->mNumChannels)
+                    throw DeadlyImportError("CSM: Empty $order section");
+
+                // copy over to the output animation
+                anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
+                ::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
+            }
+            else if (TokenMatchI(buffer,"points",6))    {
+                if (!anim->mNumChannels)
+                    throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
+
+                // If we know how many frames we'll read, we can preallocate some storage
+                unsigned int alloc = 100;
+                if (last != 0x00ffffff)
+                {
+                    alloc = last-first;
+                    alloc += alloc>>2u; // + 25%
+                    for (unsigned int i = 0; i < anim->mNumChannels;++i)
+                        anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
+                }
+
+                unsigned int filled = 0;
+
+                // Now read all point data.
+                while (1)   {
+                    SkipSpaces(&buffer);
+                    if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$'))   {
+                        break; // next section
+                    }
+
+                    // read frame
+                    const int frame = ::strtoul10(buffer,&buffer);
+                    last  = std::max(frame,last);
+                    first = std::min(frame,last);
+                    for (unsigned int i = 0; i < anim->mNumChannels;++i)    {
+
+                        aiNodeAnim* s = anim->mChannels[i];
+                        if (s->mNumPositionKeys == alloc)   { /* need to reallocate? */
+
+                            aiVectorKey* old = s->mPositionKeys;
+                            s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
+                            ::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
+                            delete[] old;
+                        }
+
+                        // read x,y,z
+                        if(!SkipSpacesAndLineEnd(&buffer))
+                            throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord");
+
+                        if (TokenMatchI(buffer, "DROPOUT", 7))  {
+                            // seems this is invalid marker data; at least the doc says it's possible
+                            DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)");
+                        }
+                        else    {
+                            aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
+                            sub->mTime = (double)frame;
+                            buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
+
+                            if(!SkipSpacesAndLineEnd(&buffer))
+                                throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord");
+                            buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
+
+                            if(!SkipSpacesAndLineEnd(&buffer))
+                                throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord");
+                            buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
+
+                            ++s->mNumPositionKeys;
+                        }
+                    }
+
+                    // update allocation granularity
+                    if (filled == alloc)
+                        alloc *= 2;
+
+                    ++filled;
+                }
+                // all channels must be complete in order to continue safely.
+                for (unsigned int i = 0; i < anim->mNumChannels;++i)    {
+
+                    if (!anim->mChannels[i]->mNumPositionKeys)
+                        throw DeadlyImportError("CSM: Invalid marker track");
+                }
+            }
+        }
+        else    {
+            // advance to the next line
+            SkipLine(&buffer);
+        }
+    }
+
+    // Setup a proper animation duration
+    anim->mDuration = last - std::min( first, 0 );
+
+    // build a dummy root node with the tiny markers as children
+    pScene->mRootNode = new aiNode();
+    pScene->mRootNode->mName.Set("$CSM_DummyRoot");
+
+    pScene->mRootNode->mNumChildren = anim->mNumChannels;
+    pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels];
+
+    for (unsigned int i = 0; i < anim->mNumChannels;++i)    {
+        aiNodeAnim* na = anim->mChannels[i];
+
+        aiNode* nd  = pScene->mRootNode->mChildren[i] = new aiNode();
+        nd->mName   = anim->mChannels[i]->mNodeName;
+        nd->mParent = pScene->mRootNode;
+
+        aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation);
+    }
+
+    // Store the one and only animation in the scene
+    pScene->mAnimations    = new aiAnimation*[pScene->mNumAnimations=1];
+    pScene->mAnimations[0] = anim;
+    anim->mName.Set("$CSM_MasterAnim");
+
+    // mark the scene as incomplete and run SkeletonMeshBuilder on it
+    pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
+
+    if (!noSkeletonMesh) {
+        SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true);
+    }
 }
 
 #endif // !! ASSIMP_BUILD_NO_CSM_IMPORTER

+ 14 - 14
code/CSMLoader.h

@@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "BaseImporter.h"
 
-namespace Assimp	{
+namespace Assimp    {
 
 // ---------------------------------------------------------------------------
 /** Importer class to load MOCAPs in CharacterStudio Motion format.
@@ -60,30 +60,30 @@ namespace Assimp	{
 class CSMImporter : public BaseImporter
 {
 public:
-	CSMImporter();
-	~CSMImporter();
+    CSMImporter();
+    ~CSMImporter();
 
 
 public:
-	// -------------------------------------------------------------------
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-		bool checkSig) const;
+    // -------------------------------------------------------------------
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
 
 protected:
 
-	// -------------------------------------------------------------------
-	const aiImporterDesc* GetInfo () const;
+    // -------------------------------------------------------------------
+    const aiImporterDesc* GetInfo () const;
 
-	// -------------------------------------------------------------------
-	void SetupProperties(const Importer* pImp);
+    // -------------------------------------------------------------------
+    void SetupProperties(const Importer* pImp);
 
-	// -------------------------------------------------------------------
-	void InternReadFile( const std::string& pFile, aiScene* pScene,
-		IOSystem* pIOHandler);
+    // -------------------------------------------------------------------
+    void InternReadFile( const std::string& pFile, aiScene* pScene,
+        IOSystem* pIOHandler);
 
 private:
 
-	bool noSkeletonMesh;
+    bool noSkeletonMesh;
 
 }; // end of class CSMImporter
 } // end of namespace Assimp

+ 181 - 181
code/CalcTangentsProcess.cpp

@@ -56,21 +56,21 @@ using namespace Assimp;
 CalcTangentsProcess::CalcTangentsProcess()
 : configMaxAngle( AI_DEG_TO_RAD(45.f) )
 , configSourceUV( 0 ) {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 CalcTangentsProcess::~CalcTangentsProcess()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
 {
-	return (pFlags & aiProcess_CalcTangentSpace) != 0;
+    return (pFlags & aiProcess_CalcTangentSpace) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -79,12 +79,12 @@ void CalcTangentsProcess::SetupProperties(const Importer* pImp)
 {
     ai_assert( NULL != pImp );
 
-	// get the current value of the property
-	configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
-	configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
-	configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
+    // get the current value of the property
+    configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
+    configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
+    configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
 
-	configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0);
+    configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -95,12 +95,12 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
 
     DefaultLogger::get()->debug("CalcTangentsProcess begin");
 
-	bool bHas = false;
-	for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
-		if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
+    bool bHas = false;
+    for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
+        if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
     }
 
-	if ( bHas ) {
+    if ( bHas ) {
         DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated");
     } else {
         DefaultLogger::get()->debug("CalcTangentsProcess finished");
@@ -111,106 +111,106 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
 // Calculates tangents and bitangents for the given mesh
 bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
 {
-	// we assume that the mesh is still in the verbose vertex format where each face has its own set
-	// of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
-	// assert() it here.
+    // we assume that the mesh is still in the verbose vertex format where each face has its own set
+    // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
+    // assert() it here.
     // assert( must be verbose, dammit);
 
-	if (pMesh->mTangents) // this implies that mBitangents is also there
-		return false;
-
-	// If the mesh consists of lines and/or points but not of
-	// triangles or higher-order polygons the normal vectors
-	// are undefined.
-	if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
-	{
-		DefaultLogger::get()->info("Tangents are undefined for line and point meshes");
-		return false;
-	}
-
-	// what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
-	if( pMesh->mNormals == NULL)
-	{
-		DefaultLogger::get()->error("Failed to compute tangents; need normals");
-		return false;
-	}
-	if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
-	{
-		DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
-		return false;
-	}
-
-	const float angleEpsilon = 0.9999f;
-
-	std::vector<bool> vertexDone( pMesh->mNumVertices, false);
-	const float qnan = get_qnan();
-
-	// create space for the tangents and bitangents
-	pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
-	pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
-
-	const aiVector3D* meshPos = pMesh->mVertices;
-	const aiVector3D* meshNorm = pMesh->mNormals;
-	const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV];
-	aiVector3D* meshTang = pMesh->mTangents;
-	aiVector3D* meshBitang = pMesh->mBitangents;
-
-	// calculate the tangent and bitangent for every face
-	for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
-	{
-		const aiFace& face = pMesh->mFaces[a];
-		if (face.mNumIndices < 3)
-		{
-			// There are less than three indices, thus the tangent vector
-			// is not defined. We are finished with these vertices now,
-			// their tangent vectors are set to qnan.
-			for (unsigned int i = 0; i < face.mNumIndices;++i)
-			{
-				unsigned int idx = face.mIndices[i];
-				vertexDone  [idx] = true;
-				meshTang    [idx] = aiVector3D(qnan);
-				meshBitang  [idx] = aiVector3D(qnan);
-			}
-
-			continue;
-		}
-
-		// triangle or polygon... we always use only the first three indices. A polygon
-		// is supposed to be planar anyways....
-		// FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
-		const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
-
-		// position differences p1->p2 and p1->p3
-		aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
-
-		// texture offset p1->p2 and p1->p3
-		float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
+    if (pMesh->mTangents) // this implies that mBitangents is also there
+        return false;
+
+    // If the mesh consists of lines and/or points but not of
+    // triangles or higher-order polygons the normal vectors
+    // are undefined.
+    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
+    {
+        DefaultLogger::get()->info("Tangents are undefined for line and point meshes");
+        return false;
+    }
+
+    // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
+    if( pMesh->mNormals == NULL)
+    {
+        DefaultLogger::get()->error("Failed to compute tangents; need normals");
+        return false;
+    }
+    if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
+    {
+        DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
+        return false;
+    }
+
+    const float angleEpsilon = 0.9999f;
+
+    std::vector<bool> vertexDone( pMesh->mNumVertices, false);
+    const float qnan = get_qnan();
+
+    // create space for the tangents and bitangents
+    pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
+    pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
+
+    const aiVector3D* meshPos = pMesh->mVertices;
+    const aiVector3D* meshNorm = pMesh->mNormals;
+    const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV];
+    aiVector3D* meshTang = pMesh->mTangents;
+    aiVector3D* meshBitang = pMesh->mBitangents;
+
+    // calculate the tangent and bitangent for every face
+    for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
+    {
+        const aiFace& face = pMesh->mFaces[a];
+        if (face.mNumIndices < 3)
+        {
+            // There are less than three indices, thus the tangent vector
+            // is not defined. We are finished with these vertices now,
+            // their tangent vectors are set to qnan.
+            for (unsigned int i = 0; i < face.mNumIndices;++i)
+            {
+                unsigned int idx = face.mIndices[i];
+                vertexDone  [idx] = true;
+                meshTang    [idx] = aiVector3D(qnan);
+                meshBitang  [idx] = aiVector3D(qnan);
+            }
+
+            continue;
+        }
+
+        // triangle or polygon... we always use only the first three indices. A polygon
+        // is supposed to be planar anyways....
+        // FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
+        const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
+
+        // position differences p1->p2 and p1->p3
+        aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
+
+        // texture offset p1->p2 and p1->p3
+        float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
         float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
-		float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
+        float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
         // when t1, t2, t3 in same position in UV space, just use default UV direction.
         if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) {
             sx = 0.0; sy = 1.0;
             tx = 1.0; ty = 0.0;
         }
 
-		// tangent points in the direction where to positive X axis of the texture coord's would point in model space
-		// bitangent's points along the positive Y axis of the texture coord's, respectively
-		aiVector3D tangent, bitangent;
-		tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
+        // tangent points in the direction where to positive X axis of the texture coord's would point in model space
+        // bitangent's points along the positive Y axis of the texture coord's, respectively
+        aiVector3D tangent, bitangent;
+        tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
         tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
         tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
         bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
         bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
         bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
 
-		// store for every vertex of that face
-		for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
-			unsigned int p = face.mIndices[b];
+        // store for every vertex of that face
+        for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
+            unsigned int p = face.mIndices[b];
 
-			// project tangent and bitangent into the plane formed by the vertex' normal
-			aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
-			aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
-			localTangent.Normalize(); localBitangent.Normalize();
+            // project tangent and bitangent into the plane formed by the vertex' normal
+            aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
+            aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
+            localTangent.Normalize(); localBitangent.Normalize();
 
             // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
             bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
@@ -226,92 +226,92 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
             }
 
             // and write it into the mesh.
-			meshTang[ p ]   = localTangent;
-			meshBitang[ p ] = localBitangent;
-		}
+            meshTang[ p ]   = localTangent;
+            meshBitang[ p ] = localBitangent;
+        }
     }
 
 
-	// create a helper to quickly find locally close vertices among the vertex array
-	// FIX: check whether we can reuse the SpatialSort of a previous step
-	SpatialSort* vertexFinder = NULL;
-	SpatialSort  _vertexFinder;
-	float posEpsilon;
-	if (shared)
-	{
-		std::vector<std::pair<SpatialSort,float> >* avf;
-		shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
-		if (avf)
-		{
-			std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
-			vertexFinder = &blubb.first;
-			posEpsilon = blubb.second;;
-		}
-	}
-	if (!vertexFinder)
-	{
-		_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
-		vertexFinder = &_vertexFinder;
-		posEpsilon = ComputePositionEpsilon(pMesh);
-	}
-	std::vector<unsigned int> verticesFound;
-
-	const float fLimit = cosf(configMaxAngle);
-	std::vector<unsigned int> closeVertices;
-
-	// in the second pass we now smooth out all tangents and bitangents at the same local position
-	// if they are not too far off.
-	for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
-	{
-		if( vertexDone[a])
-			continue;
-
-		const aiVector3D& origPos = pMesh->mVertices[a];
-		const aiVector3D& origNorm = pMesh->mNormals[a];
-		const aiVector3D& origTang = pMesh->mTangents[a];
-		const aiVector3D& origBitang = pMesh->mBitangents[a];
-		closeVertices.resize( 0 );
-
-		// find all vertices close to that position
-		vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
-
-		closeVertices.reserve (verticesFound.size()+5);
-		closeVertices.push_back( a);
-
-		// look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
-		for( unsigned int b = 0; b < verticesFound.size(); b++)
-		{
-			unsigned int idx = verticesFound[b];
-			if( vertexDone[idx])
-				continue;
-			if( meshNorm[idx] * origNorm < angleEpsilon)
-				continue;
-			if(  meshTang[idx] * origTang < fLimit)
-				continue;
-			if( meshBitang[idx] * origBitang < fLimit)
-				continue;
-
-			// it's similar enough -> add it to the smoothing group
-			closeVertices.push_back( idx);
-			vertexDone[idx] = true;
-		}
-
-		// smooth the tangents and bitangents of all vertices that were found to be close enough
-		aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
-		for( unsigned int b = 0; b < closeVertices.size(); ++b)
-		{
-			smoothTangent += meshTang[ closeVertices[b] ];
-			smoothBitangent += meshBitang[ closeVertices[b] ];
-		}
-		smoothTangent.Normalize();
-		smoothBitangent.Normalize();
-
-		// and write it back into all affected tangents
-		for( unsigned int b = 0; b < closeVertices.size(); ++b)
-		{
-			meshTang[ closeVertices[b] ] = smoothTangent;
-			meshBitang[ closeVertices[b] ] = smoothBitangent;
-		}
-	}
-	return true;
+    // create a helper to quickly find locally close vertices among the vertex array
+    // FIX: check whether we can reuse the SpatialSort of a previous step
+    SpatialSort* vertexFinder = NULL;
+    SpatialSort  _vertexFinder;
+    float posEpsilon;
+    if (shared)
+    {
+        std::vector<std::pair<SpatialSort,float> >* avf;
+        shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
+        if (avf)
+        {
+            std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
+            vertexFinder = &blubb.first;
+            posEpsilon = blubb.second;;
+        }
+    }
+    if (!vertexFinder)
+    {
+        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
+        vertexFinder = &_vertexFinder;
+        posEpsilon = ComputePositionEpsilon(pMesh);
+    }
+    std::vector<unsigned int> verticesFound;
+
+    const float fLimit = cosf(configMaxAngle);
+    std::vector<unsigned int> closeVertices;
+
+    // in the second pass we now smooth out all tangents and bitangents at the same local position
+    // if they are not too far off.
+    for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
+    {
+        if( vertexDone[a])
+            continue;
+
+        const aiVector3D& origPos = pMesh->mVertices[a];
+        const aiVector3D& origNorm = pMesh->mNormals[a];
+        const aiVector3D& origTang = pMesh->mTangents[a];
+        const aiVector3D& origBitang = pMesh->mBitangents[a];
+        closeVertices.resize( 0 );
+
+        // find all vertices close to that position
+        vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
+
+        closeVertices.reserve (verticesFound.size()+5);
+        closeVertices.push_back( a);
+
+        // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
+        for( unsigned int b = 0; b < verticesFound.size(); b++)
+        {
+            unsigned int idx = verticesFound[b];
+            if( vertexDone[idx])
+                continue;
+            if( meshNorm[idx] * origNorm < angleEpsilon)
+                continue;
+            if(  meshTang[idx] * origTang < fLimit)
+                continue;
+            if( meshBitang[idx] * origBitang < fLimit)
+                continue;
+
+            // it's similar enough -> add it to the smoothing group
+            closeVertices.push_back( idx);
+            vertexDone[idx] = true;
+        }
+
+        // smooth the tangents and bitangents of all vertices that were found to be close enough
+        aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
+        for( unsigned int b = 0; b < closeVertices.size(); ++b)
+        {
+            smoothTangent += meshTang[ closeVertices[b] ];
+            smoothBitangent += meshBitang[ closeVertices[b] ];
+        }
+        smoothTangent.Normalize();
+        smoothBitangent.Normalize();
+
+        // and write it back into all affected tangents
+        for( unsigned int b = 0; b < closeVertices.size(); ++b)
+        {
+            meshTang[ closeVertices[b] ] = smoothTangent;
+            meshBitang[ closeVertices[b] ] = smoothBitangent;
+        }
+    }
+    return true;
 }

+ 38 - 38
code/CalcTangentsProcess.h

@@ -61,53 +61,53 @@ class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess
 {
 public:
 
-	CalcTangentsProcess();
-	~CalcTangentsProcess();
+    CalcTangentsProcess();
+    ~CalcTangentsProcess();
 
 public:
-	// -------------------------------------------------------------------
-	/** Returns whether the processing step is present in the given flag.
-	* @param pFlags The processing flags the importer was called with.
-	*   A bitwise combination of #aiPostProcessSteps.
-	* @return true if the process is present in this flag fields,
-	*   false if not.
-	*/
-	bool IsActive( unsigned int pFlags) const;
-
-	// -------------------------------------------------------------------
-	/** Called prior to ExecuteOnScene().
-	* The function is a request to the process to update its configuration
-	* basing on the Importer's configuration property list.
-	*/
-	void SetupProperties(const Importer* pImp);
-
-
-	// setter for configMaxAngle
-	inline void SetMaxSmoothAngle(float f)
-	{
-		configMaxAngle =f;
-	}
+    // -------------------------------------------------------------------
+    /** Returns whether the processing step is present in the given flag.
+    * @param pFlags The processing flags the importer was called with.
+    *   A bitwise combination of #aiPostProcessSteps.
+    * @return true if the process is present in this flag fields,
+    *   false if not.
+    */
+    bool IsActive( unsigned int pFlags) const;
+
+    // -------------------------------------------------------------------
+    /** Called prior to ExecuteOnScene().
+    * The function is a request to the process to update its configuration
+    * basing on the Importer's configuration property list.
+    */
+    void SetupProperties(const Importer* pImp);
+
+
+    // setter for configMaxAngle
+    inline void SetMaxSmoothAngle(float f)
+    {
+        configMaxAngle =f;
+    }
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Calculates tangents and bitangents for a specific mesh.
-	* @param pMesh The mesh to process.
-	* @param meshIndex Index of the mesh
-	*/
-	bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
+    // -------------------------------------------------------------------
+    /** Calculates tangents and bitangents for a specific mesh.
+    * @param pMesh The mesh to process.
+    * @param meshIndex Index of the mesh
+    */
+    bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
 
-	// -------------------------------------------------------------------
-	/** Executes the post processing step on the given imported data.
-	* @param pScene The imported data to work at.
-	*/
-	void Execute( aiScene* pScene);
+    // -------------------------------------------------------------------
+    /** Executes the post processing step on the given imported data.
+    * @param pScene The imported data to work at.
+    */
+    void Execute( aiScene* pScene);
 
 private:
 
-	/** Configuration option: maximum smoothing angle, in radians*/
-	float configMaxAngle;
-	unsigned int configSourceUV;
+    /** Configuration option: maximum smoothing angle, in radians*/
+    float configMaxAngle;
+    unsigned int configSourceUV;
 };
 
 } // end of namespace Assimp

+ 662 - 663
code/ColladaExporter.cpp

@@ -68,20 +68,20 @@ namespace Assimp
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
-	std::string path = DefaultIOSystem::absolutePath(std::string(pFile));
-	std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
+    std::string path = DefaultIOSystem::absolutePath(std::string(pFile));
+    std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
 
-	// invoke the exporter
-	ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file);
+    // invoke the exporter
+    ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file);
 
-	// we're still here - export successfully completed. Write result to the given IOSYstem
-	boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
-	if(outfile == NULL) {
-		throw DeadlyExportError("could not open output .dae file: " + std::string(pFile));
-	}
+    // we're still here - export successfully completed. Write result to the given IOSYstem
+    boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
+    if(outfile == NULL) {
+        throw DeadlyExportError("could not open output .dae file: " + std::string(pFile));
+    }
 
-	// XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
-	outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1);
+    // XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
+    outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1);
 }
 
 } // end of namespace Assimp
@@ -92,252 +92,252 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p
 // Constructor for a specific scene to export
 ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file)
 {
-	// make sure that all formatting happens using the standard, C locale and not the user's current locale
-	mOutput.imbue( std::locale("C") );
+    // make sure that all formatting happens using the standard, C locale and not the user's current locale
+    mOutput.imbue( std::locale("C") );
 
-	mScene = pScene;
-	mSceneOwned = false;
+    mScene = pScene;
+    mSceneOwned = false;
 
-	// set up strings
-	endstr = "\n";
+    // set up strings
+    endstr = "\n";
 
-	// start writing
-	WriteFile();
+    // start writing
+    WriteFile();
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor
 ColladaExporter::~ColladaExporter()
 {
-	if(mSceneOwned) {
-		delete mScene;
-	}
+    if(mSceneOwned) {
+        delete mScene;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Starts writing the contents
 void ColladaExporter::WriteFile()
 {
-	// write the DTD
-	mOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>" << endstr;
-	// COLLADA element start
-	mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
-	PushTag();
-
-	WriteTextures();
-	WriteHeader();
-
-	WriteCamerasLibrary();
-	WriteLightsLibrary();
-	WriteMaterials();
-	WriteGeometryLibrary();
-
-	WriteSceneLibrary();
-
-	// useless Collada fu at the end, just in case we haven't had enough indirections, yet.
-	mOutput << startstr << "<scene>" << endstr;
-	PushTag();
-	mOutput << startstr << "<instance_visual_scene url=\"#" + XMLEscape(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
-	PopTag();
-	mOutput << startstr << "</scene>" << endstr;
-	PopTag();
-	mOutput << "</COLLADA>" << endstr;
+    // write the DTD
+    mOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>" << endstr;
+    // COLLADA element start
+    mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
+    PushTag();
+
+    WriteTextures();
+    WriteHeader();
+
+    WriteCamerasLibrary();
+    WriteLightsLibrary();
+    WriteMaterials();
+    WriteGeometryLibrary();
+
+    WriteSceneLibrary();
+
+    // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
+    mOutput << startstr << "<scene>" << endstr;
+    PushTag();
+    mOutput << startstr << "<instance_visual_scene url=\"#" + XMLEscape(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
+    PopTag();
+    mOutput << startstr << "</scene>" << endstr;
+    PopTag();
+    mOutput << "</COLLADA>" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Writes the asset header
 void ColladaExporter::WriteHeader()
 {
-	static const float epsilon = 0.00001f;
-	static const aiQuaternion x_rot(aiMatrix3x3(
-		0, -1,  0,
-		1,  0,  0,
-		0,  0,  1));
-	static const aiQuaternion y_rot(aiMatrix3x3(
-		1,  0,  0,
-		0,  1,  0,
-		0,  0,  1));
-	static const aiQuaternion z_rot(aiMatrix3x3(
-		1,  0,  0,
-		0,  0,  1,
-		0, -1,  0));
-
-	static const unsigned int date_nb_chars = 20;
-	char date_str[date_nb_chars];
-	std::time_t date = std::time(NULL);
-	std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date));
-
-	aiVector3D scaling;
-	aiQuaternion rotation;
-	aiVector3D position;
-	mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position);
-	rotation.Normalize();
-
-	bool add_root_node = false;
-
-	float scale = 1.0;
-	if(std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) {
-		scale = (float) ((((double) scaling.x) + ((double) scaling.y) + ((double) scaling.z)) / 3.0);
-	} else {
-		add_root_node = true;
-	}
-
-	std::string up_axis = "Y_UP";
-	if(rotation.Equal(x_rot, epsilon)) {
-		up_axis = "X_UP";
-	} else if(rotation.Equal(y_rot, epsilon)) {
-		up_axis = "Y_UP";
-	} else if(rotation.Equal(z_rot, epsilon)) {
-		up_axis = "Z_UP";
-	} else {
-		add_root_node = true;
-	}
-
-	if(! position.Equal(aiVector3D(0, 0, 0))) {
-		add_root_node = true;
-	}
-
-	if(mScene->mRootNode->mNumChildren == 0) {
-		add_root_node = true;
-	}
-
-	if(add_root_node) {
-		aiScene* scene;
-		SceneCombiner::CopyScene(&scene, mScene);
-
-		aiNode* root = new aiNode("Scene");
-
-		root->mNumChildren = 1;
-		root->mChildren = new aiNode*[root->mNumChildren];
-
-		root->mChildren[0] = scene->mRootNode;
-		scene->mRootNode->mParent = root;
-		scene->mRootNode = root;
-
-		mScene = scene;
-		mSceneOwned = true;
-
-		up_axis = "Y_UP";
-		scale = 1.0;
-	}
-
-	mOutput << startstr << "<asset>" << endstr;
-	PushTag();
-	mOutput << startstr << "<contributor>" << endstr;
-	PushTag();
-
-	aiMetadata* meta = mScene->mRootNode->mMetaData;
-	aiString value;
-	if (!meta || !meta->Get("Author", value))
-		mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
-	else
-		mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
-
-	if (!meta || !meta->Get("AuthoringTool", value))
-		mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
-	else
-		mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
-
-	//mOutput << startstr << "<author>" << mScene->author.C_Str() << "</author>" << endstr;
-	//mOutput << startstr << "<authoring_tool>" << mScene->authoringTool.C_Str() << "</authoring_tool>" << endstr;
-
-	PopTag();
-	mOutput << startstr << "</contributor>" << endstr;
-	mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
-	mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
-	mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
-	mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
-	PopTag();
-	mOutput << startstr << "</asset>" << endstr;
+    static const float epsilon = 0.00001f;
+    static const aiQuaternion x_rot(aiMatrix3x3(
+        0, -1,  0,
+        1,  0,  0,
+        0,  0,  1));
+    static const aiQuaternion y_rot(aiMatrix3x3(
+        1,  0,  0,
+        0,  1,  0,
+        0,  0,  1));
+    static const aiQuaternion z_rot(aiMatrix3x3(
+        1,  0,  0,
+        0,  0,  1,
+        0, -1,  0));
+
+    static const unsigned int date_nb_chars = 20;
+    char date_str[date_nb_chars];
+    std::time_t date = std::time(NULL);
+    std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date));
+
+    aiVector3D scaling;
+    aiQuaternion rotation;
+    aiVector3D position;
+    mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position);
+    rotation.Normalize();
+
+    bool add_root_node = false;
+
+    float scale = 1.0;
+    if(std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) {
+        scale = (float) ((((double) scaling.x) + ((double) scaling.y) + ((double) scaling.z)) / 3.0);
+    } else {
+        add_root_node = true;
+    }
+
+    std::string up_axis = "Y_UP";
+    if(rotation.Equal(x_rot, epsilon)) {
+        up_axis = "X_UP";
+    } else if(rotation.Equal(y_rot, epsilon)) {
+        up_axis = "Y_UP";
+    } else if(rotation.Equal(z_rot, epsilon)) {
+        up_axis = "Z_UP";
+    } else {
+        add_root_node = true;
+    }
+
+    if(! position.Equal(aiVector3D(0, 0, 0))) {
+        add_root_node = true;
+    }
+
+    if(mScene->mRootNode->mNumChildren == 0) {
+        add_root_node = true;
+    }
+
+    if(add_root_node) {
+        aiScene* scene;
+        SceneCombiner::CopyScene(&scene, mScene);
+
+        aiNode* root = new aiNode("Scene");
+
+        root->mNumChildren = 1;
+        root->mChildren = new aiNode*[root->mNumChildren];
+
+        root->mChildren[0] = scene->mRootNode;
+        scene->mRootNode->mParent = root;
+        scene->mRootNode = root;
+
+        mScene = scene;
+        mSceneOwned = true;
+
+        up_axis = "Y_UP";
+        scale = 1.0;
+    }
+
+    mOutput << startstr << "<asset>" << endstr;
+    PushTag();
+    mOutput << startstr << "<contributor>" << endstr;
+    PushTag();
+
+    aiMetadata* meta = mScene->mRootNode->mMetaData;
+    aiString value;
+    if (!meta || !meta->Get("Author", value))
+        mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
+    else
+        mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
+
+    if (!meta || !meta->Get("AuthoringTool", value))
+        mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
+    else
+        mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
+
+    //mOutput << startstr << "<author>" << mScene->author.C_Str() << "</author>" << endstr;
+    //mOutput << startstr << "<authoring_tool>" << mScene->authoringTool.C_Str() << "</authoring_tool>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</contributor>" << endstr;
+    mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+    mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
+    mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
+    mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
+    PopTag();
+    mOutput << startstr << "</asset>" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Write the embedded textures
 void ColladaExporter::WriteTextures() {
-	static const unsigned int buffer_size = 1024;
-	char str[buffer_size];
+    static const unsigned int buffer_size = 1024;
+    char str[buffer_size];
 
-	if(mScene->HasTextures()) {
-		for(unsigned int i = 0; i < mScene->mNumTextures; i++) {
-			// It would be great to be able to create a directory in portable standard C++, but it's not the case,
-			// so we just write the textures in the current directory.
+    if(mScene->HasTextures()) {
+        for(unsigned int i = 0; i < mScene->mNumTextures; i++) {
+            // It would be great to be able to create a directory in portable standard C++, but it's not the case,
+            // so we just write the textures in the current directory.
 
-			aiTexture* texture = mScene->mTextures[i];
+            aiTexture* texture = mScene->mTextures[i];
 
-			ASSIMP_itoa10(str, buffer_size, i + 1);
+            ASSIMP_itoa10(str, buffer_size, i + 1);
 
-			std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint);
+            std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint);
 
-			boost::scoped_ptr<IOStream> outfile(mIOSystem->Open(mPath + name, "wb"));
-			if(outfile == NULL) {
-				throw DeadlyExportError("could not open output texture file: " + mPath + name);
-			}
+            boost::scoped_ptr<IOStream> outfile(mIOSystem->Open(mPath + name, "wb"));
+            if(outfile == NULL) {
+                throw DeadlyExportError("could not open output texture file: " + mPath + name);
+            }
 
-			if(texture->mHeight == 0) {
-				outfile->Write((void*) texture->pcData, texture->mWidth, 1);
-			} else {
-				Bitmap::Save(texture, outfile.get());
-			}
+            if(texture->mHeight == 0) {
+                outfile->Write((void*) texture->pcData, texture->mWidth, 1);
+            } else {
+                Bitmap::Save(texture, outfile.get());
+            }
 
-			outfile->Flush();
+            outfile->Flush();
 
-			textures.insert(std::make_pair(i, name));
-		}
-	}
+            textures.insert(std::make_pair(i, name));
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Write the embedded textures
 void ColladaExporter::WriteCamerasLibrary() {
-	if(mScene->HasCameras()) {
+    if(mScene->HasCameras()) {
 
-		mOutput << startstr << "<library_cameras>" << endstr;
-		PushTag();
+        mOutput << startstr << "<library_cameras>" << endstr;
+        PushTag();
 
-		for( size_t a = 0; a < mScene->mNumCameras; ++a)
-			WriteCamera( a);
+        for( size_t a = 0; a < mScene->mNumCameras; ++a)
+            WriteCamera( a);
 
-		PopTag();
-		mOutput << startstr << "</library_cameras>" << endstr;
+        PopTag();
+        mOutput << startstr << "</library_cameras>" << endstr;
 
-	}
+    }
 }
 
 void ColladaExporter::WriteCamera(size_t pIndex){
 
-	const aiCamera *cam = mScene->mCameras[pIndex];
-	const std::string idstrEscaped = XMLEscape(cam->mName.C_Str());
-
-	mOutput << startstr << "<camera id=\"" << idstrEscaped << "-camera\" name=\"" << idstrEscaped << "_name\" >" << endstr;
-	PushTag();
-	mOutput << startstr << "<optics>" << endstr;
-	PushTag();
-	mOutput << startstr << "<technique_common>" << endstr;
-	PushTag();
-	//assimp doesn't support the import of orthographic cameras! se we write
-	//always perspective
-	mOutput << startstr << "<perspective>" << endstr;
-	PushTag();
-	mOutput << startstr << "<xfov sid=\"xfov\">"<<
-								AI_RAD_TO_DEG(cam->mHorizontalFOV)
-						<<"</xfov>" << endstr;
-	mOutput << startstr << "<aspect_ratio>"
-						<<		cam->mAspect
-						<< "</aspect_ratio>" << endstr;
-	mOutput << startstr << "<znear sid=\"znear\">"
-						<<		cam->mClipPlaneNear
-						<<	"</znear>" << endstr;
-	mOutput << startstr << "<zfar sid=\"zfar\">"
-						<<		cam->mClipPlaneFar
-						<< "</zfar>" << endstr;
-	PopTag();
-	mOutput << startstr << "</perspective>" << endstr;
-	PopTag();
-	mOutput << startstr << "</technique_common>" << endstr;
-	PopTag();
-	mOutput << startstr << "</optics>" << endstr;
-	PopTag();
-	mOutput << startstr << "</camera>" << endstr;
+    const aiCamera *cam = mScene->mCameras[pIndex];
+    const std::string idstrEscaped = XMLEscape(cam->mName.C_Str());
+
+    mOutput << startstr << "<camera id=\"" << idstrEscaped << "-camera\" name=\"" << idstrEscaped << "_name\" >" << endstr;
+    PushTag();
+    mOutput << startstr << "<optics>" << endstr;
+    PushTag();
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    //assimp doesn't support the import of orthographic cameras! se we write
+    //always perspective
+    mOutput << startstr << "<perspective>" << endstr;
+    PushTag();
+    mOutput << startstr << "<xfov sid=\"xfov\">"<<
+                                AI_RAD_TO_DEG(cam->mHorizontalFOV)
+                        <<"</xfov>" << endstr;
+    mOutput << startstr << "<aspect_ratio>"
+                        <<      cam->mAspect
+                        << "</aspect_ratio>" << endstr;
+    mOutput << startstr << "<znear sid=\"znear\">"
+                        <<      cam->mClipPlaneNear
+                        <<  "</znear>" << endstr;
+    mOutput << startstr << "<zfar sid=\"zfar\">"
+                        <<      cam->mClipPlaneFar
+                        << "</zfar>" << endstr;
+    PopTag();
+    mOutput << startstr << "</perspective>" << endstr;
+    PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+    PopTag();
+    mOutput << startstr << "</optics>" << endstr;
+    PopTag();
+    mOutput << startstr << "</camera>" << endstr;
 
 }
 
@@ -345,140 +345,140 @@ void ColladaExporter::WriteCamera(size_t pIndex){
 // ------------------------------------------------------------------------------------------------
 // Write the embedded textures
 void ColladaExporter::WriteLightsLibrary() {
-	if(mScene->HasLights()) {
+    if(mScene->HasLights()) {
 
-		mOutput << startstr << "<library_lights>" << endstr;
-		PushTag();
+        mOutput << startstr << "<library_lights>" << endstr;
+        PushTag();
 
-		for( size_t a = 0; a < mScene->mNumLights; ++a)
-			WriteLight( a);
+        for( size_t a = 0; a < mScene->mNumLights; ++a)
+            WriteLight( a);
 
-		PopTag();
-		mOutput << startstr << "</library_lights>" << endstr;
+        PopTag();
+        mOutput << startstr << "</library_lights>" << endstr;
 
-	}
+    }
 }
 
 void ColladaExporter::WriteLight(size_t pIndex){
 
-	const aiLight *light = mScene->mLights[pIndex];
-	const std::string idstrEscaped = XMLEscape(light->mName.C_Str());
-
-	mOutput << startstr << "<light id=\"" << idstrEscaped << "-light\" name=\""
-			<< idstrEscaped << "_name\" >" << endstr;
-	PushTag();
-	mOutput << startstr << "<technique_common>" << endstr;
-	PushTag();
-	switch(light->mType){
-		case aiLightSource_AMBIENT:
-			WriteAmbienttLight(light);
-			break;
-		case aiLightSource_DIRECTIONAL:
-			WriteDirectionalLight(light);
-			break;
-		case aiLightSource_POINT:
-			WritePointLight(light);
-			break;
-		case aiLightSource_SPOT:
-			WriteSpotLight(light);
-			break;
-		case aiLightSource_UNDEFINED:
-		case _aiLightSource_Force32Bit:
-			break;
-	}
-	PopTag();
-	mOutput << startstr << "</technique_common>" << endstr;
-
-	PopTag();
-	mOutput << startstr << "</light>" << endstr;
+    const aiLight *light = mScene->mLights[pIndex];
+    const std::string idstrEscaped = XMLEscape(light->mName.C_Str());
+
+    mOutput << startstr << "<light id=\"" << idstrEscaped << "-light\" name=\""
+            << idstrEscaped << "_name\" >" << endstr;
+    PushTag();
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    switch(light->mType){
+        case aiLightSource_AMBIENT:
+            WriteAmbienttLight(light);
+            break;
+        case aiLightSource_DIRECTIONAL:
+            WriteDirectionalLight(light);
+            break;
+        case aiLightSource_POINT:
+            WritePointLight(light);
+            break;
+        case aiLightSource_SPOT:
+            WriteSpotLight(light);
+            break;
+        case aiLightSource_UNDEFINED:
+        case _aiLightSource_Force32Bit:
+            break;
+    }
+    PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</light>" << endstr;
 
 }
 
 void ColladaExporter::WritePointLight(const aiLight *const light){
-	const aiColor3D &color=  light->mColorDiffuse;
-	mOutput << startstr << "<point>" << endstr;
-	PushTag();
-	mOutput << startstr << "<color sid=\"color\">"
-							<< color.r<<" "<<color.g<<" "<<color.b
-						<<"</color>" << endstr;
-	mOutput << startstr << "<constant_attenuation>"
-							<< light->mAttenuationConstant
-						<<"</constant_attenuation>" << endstr;
-	mOutput << startstr << "<linear_attenuation>"
-							<< light->mAttenuationLinear
-						<<"</linear_attenuation>" << endstr;
-	mOutput << startstr << "<quadratic_attenuation>"
-							<< light->mAttenuationQuadratic
-						<<"</quadratic_attenuation>" << endstr;
-
-	PopTag();
-	mOutput << startstr << "</point>" << endstr;
+    const aiColor3D &color=  light->mColorDiffuse;
+    mOutput << startstr << "<point>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+                            << color.r<<" "<<color.g<<" "<<color.b
+                        <<"</color>" << endstr;
+    mOutput << startstr << "<constant_attenuation>"
+                            << light->mAttenuationConstant
+                        <<"</constant_attenuation>" << endstr;
+    mOutput << startstr << "<linear_attenuation>"
+                            << light->mAttenuationLinear
+                        <<"</linear_attenuation>" << endstr;
+    mOutput << startstr << "<quadratic_attenuation>"
+                            << light->mAttenuationQuadratic
+                        <<"</quadratic_attenuation>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</point>" << endstr;
 
 }
 void ColladaExporter::WriteDirectionalLight(const aiLight *const light){
-	const aiColor3D &color=  light->mColorDiffuse;
-	mOutput << startstr << "<directional>" << endstr;
-	PushTag();
-	mOutput << startstr << "<color sid=\"color\">"
-							<< color.r<<" "<<color.g<<" "<<color.b
-						<<"</color>" << endstr;
+    const aiColor3D &color=  light->mColorDiffuse;
+    mOutput << startstr << "<directional>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+                            << color.r<<" "<<color.g<<" "<<color.b
+                        <<"</color>" << endstr;
 
-	PopTag();
-	mOutput << startstr << "</directional>" << endstr;
+    PopTag();
+    mOutput << startstr << "</directional>" << endstr;
 
 }
 void ColladaExporter::WriteSpotLight(const aiLight *const light){
 
-	const aiColor3D &color=  light->mColorDiffuse;
-	mOutput << startstr << "<spot>" << endstr;
-	PushTag();
-	mOutput << startstr << "<color sid=\"color\">"
-							<< color.r<<" "<<color.g<<" "<<color.b
-						<<"</color>" << endstr;
-	mOutput << startstr << "<constant_attenuation>"
-								<< light->mAttenuationConstant
-							<<"</constant_attenuation>" << endstr;
-	mOutput << startstr << "<linear_attenuation>"
-							<< light->mAttenuationLinear
-						<<"</linear_attenuation>" << endstr;
-	mOutput << startstr << "<quadratic_attenuation>"
-							<< light->mAttenuationQuadratic
-						<<"</quadratic_attenuation>" << endstr;
-	/*
-	out->mAngleOuterCone = AI_DEG_TO_RAD (std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+
-							srcLight->mFalloffAngle);
-	*/
-
-	const float fallOffAngle = AI_RAD_TO_DEG(light->mAngleInnerCone);
-	mOutput << startstr <<"<falloff_angle sid=\"fall_off_angle\">"
-								<< fallOffAngle
-						<<"</falloff_angle>" << endstr;
-	double temp = light->mAngleOuterCone-light->mAngleInnerCone;
-
-	temp = std::cos(temp);
-	temp = std::log(temp)/std::log(0.1);
-	temp = 1/temp;
-	mOutput << startstr << "<falloff_exponent sid=\"fall_off_exponent\">"
-							<< temp
-						<<"</falloff_exponent>" << endstr;
-
-
-	PopTag();
-	mOutput << startstr << "</spot>" << endstr;
+    const aiColor3D &color=  light->mColorDiffuse;
+    mOutput << startstr << "<spot>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+                            << color.r<<" "<<color.g<<" "<<color.b
+                        <<"</color>" << endstr;
+    mOutput << startstr << "<constant_attenuation>"
+                                << light->mAttenuationConstant
+                            <<"</constant_attenuation>" << endstr;
+    mOutput << startstr << "<linear_attenuation>"
+                            << light->mAttenuationLinear
+                        <<"</linear_attenuation>" << endstr;
+    mOutput << startstr << "<quadratic_attenuation>"
+                            << light->mAttenuationQuadratic
+                        <<"</quadratic_attenuation>" << endstr;
+    /*
+    out->mAngleOuterCone = AI_DEG_TO_RAD (std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+
+                            srcLight->mFalloffAngle);
+    */
+
+    const float fallOffAngle = AI_RAD_TO_DEG(light->mAngleInnerCone);
+    mOutput << startstr <<"<falloff_angle sid=\"fall_off_angle\">"
+                                << fallOffAngle
+                        <<"</falloff_angle>" << endstr;
+    double temp = light->mAngleOuterCone-light->mAngleInnerCone;
+
+    temp = std::cos(temp);
+    temp = std::log(temp)/std::log(0.1);
+    temp = 1/temp;
+    mOutput << startstr << "<falloff_exponent sid=\"fall_off_exponent\">"
+                            << temp
+                        <<"</falloff_exponent>" << endstr;
+
+
+    PopTag();
+    mOutput << startstr << "</spot>" << endstr;
 
 }
 
 void ColladaExporter::WriteAmbienttLight(const aiLight *const light){
 
-	const aiColor3D &color=  light->mColorAmbient;
-	mOutput << startstr << "<ambient>" << endstr;
-	PushTag();
-	mOutput << startstr << "<color sid=\"color\">"
-							<< color.r<<" "<<color.g<<" "<<color.b
-						<<"</color>" << endstr;
+    const aiColor3D &color=  light->mColorAmbient;
+    mOutput << startstr << "<ambient>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+                            << color.r<<" "<<color.g<<" "<<color.b
+                        <<"</color>" << endstr;
 
-	PopTag();
-	mOutput << startstr << "</ambient>" << endstr;
+    PopTag();
+    mOutput << startstr << "</ambient>" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -495,30 +495,30 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial*
 
     if(index_str.size() != 0 && index_str[0] == '*')
     {
-		unsigned int index;
+        unsigned int index;
 
-    	index_str = index_str.substr(1, std::string::npos);
+        index_str = index_str.substr(1, std::string::npos);
 
-    	try {
-    		index = (unsigned int) strtoul10_64(index_str.c_str());
-    	} catch(std::exception& error) {
-    		throw DeadlyExportError(error.what());
-    	}
+        try {
+            index = (unsigned int) strtoul10_64(index_str.c_str());
+        } catch(std::exception& error) {
+            throw DeadlyExportError(error.what());
+        }
 
-    	std::map<unsigned int, std::string>::const_iterator name = textures.find(index);
+        std::map<unsigned int, std::string>::const_iterator name = textures.find(index);
 
-    	if(name != textures.end()) {
-    		poSurface.texture = name->second;
-    	} else {
-    		throw DeadlyExportError("could not find embedded texture at index " + index_str);
-    	}
+        if(name != textures.end()) {
+            poSurface.texture = name->second;
+        } else {
+            throw DeadlyExportError("could not find embedded texture at index " + index_str);
+        }
     } else
     {
-		poSurface.texture = texfile.C_Str();
+        poSurface.texture = texfile.C_Str();
     }
 
     poSurface.channel = uvChannel;
-	poSurface.exist = true;
+    poSurface.exist = true;
   } else
   {
     if( pKey )
@@ -536,8 +536,8 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin
     PushTag();
     mOutput << startstr << "<init_from>";
 
-	// URL encode image file name first, then XML encode on top
-	std::stringstream imageUrlEncoded;
+    // URL encode image file name first, then XML encode on top
+    std::stringstream imageUrlEncoded;
     for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it )
     {
       if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' )
@@ -545,7 +545,7 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin
       else
         imageUrlEncoded << '%' << std::hex << size_t( (unsigned char) *it) << std::dec;
     }
-	mOutput << XMLEscape(imageUrlEncoded.str());
+    mOutput << XMLEscape(imageUrlEncoded.str());
     mOutput << "</init_from>" << endstr;
     PopTag();
     mOutput << startstr << "</image>" << endstr;
@@ -563,7 +563,7 @@ void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std
     {
       mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
     }
-	else
+    else
     {
       mOutput << startstr << "<texture texture=\"" << XMLEscape(pImageName) << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
     }
@@ -605,13 +605,13 @@ void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std
 // Writes a scalar property
 void ColladaExporter::WriteFloatEntry( const Property& pProperty, const std::string& pTypeName)
 {
-	if(pProperty.exist) {
-		mOutput << startstr << "<" << pTypeName << ">" << endstr;
-		PushTag();
-		mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr;
-		PopTag();
-		mOutput << startstr << "</" << pTypeName << ">" << endstr;
-	}
+    if(pProperty.exist) {
+        mOutput << startstr << "<" << pTypeName << ">" << endstr;
+        PushTag();
+        mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr;
+        PopTag();
+        mOutput << startstr << "</" << pTypeName << ">" << endstr;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -631,26 +631,26 @@ void ColladaExporter::WriteMaterials()
       name = "mat";
     materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
     for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
-		// isalnum on MSVC asserts for code points outside [0,255]. Thus prevent unwanted promotion
-		// of char to signed int and take the unsigned char value.
+        // isalnum on MSVC asserts for code points outside [0,255]. Thus prevent unwanted promotion
+        // of char to signed int and take the unsigned char value.
       if( !isalnum( static_cast<uint8_t>(*it) ) ) {
         *it = '_';
-	  }
-	}
-
-	aiShadingMode shading = aiShadingMode_Flat;
-	materials[a].shading_model = "phong";
-	if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) {
-		if(shading == aiShadingMode_Phong) {
-			materials[a].shading_model = "phong";
-		} else if(shading == aiShadingMode_Blinn) {
-			materials[a].shading_model = "blinn";
-		} else if(shading == aiShadingMode_NoShading) {
-			materials[a].shading_model = "constant";
-		} else if(shading == aiShadingMode_Gouraud) {
-			materials[a].shading_model = "lambert";
-		}
-	}
+      }
+    }
+
+    aiShadingMode shading = aiShadingMode_Flat;
+    materials[a].shading_model = "phong";
+    if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) {
+        if(shading == aiShadingMode_Phong) {
+            materials[a].shading_model = "phong";
+        } else if(shading == aiShadingMode_Blinn) {
+            materials[a].shading_model = "blinn";
+        } else if(shading == aiShadingMode_NoShading) {
+            materials[a].shading_model = "constant";
+        } else if(shading == aiShadingMode_Gouraud) {
+            materials[a].shading_model = "lambert";
+        }
+    }
 
     ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
     if( !materials[a].ambient.texture.empty() ) numTextures++;
@@ -662,15 +662,15 @@ void ColladaExporter::WriteMaterials()
     if( !materials[a].emissive.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
     if( !materials[a].reflective.texture.empty() ) numTextures++;
-	ReadMaterialSurface( materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT);
+    ReadMaterialSurface( materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT);
     if( !materials[a].transparent.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0);
     if( !materials[a].normal.texture.empty() ) numTextures++;
 
-	materials[a].shininess.exist = mat->Get( AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS;
-	materials[a].transparency.exist = mat->Get( AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS;
-	materials[a].transparency.value = 1 - materials[a].transparency.value;
-	materials[a].index_refraction.exist = mat->Get( AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS;
+    materials[a].shininess.exist = mat->Get( AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS;
+    materials[a].transparency.exist = mat->Get( AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS;
+    materials[a].transparency.value = 1 - materials[a].transparency.value;
+    materials[a].index_refraction.exist = mat->Get( AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS;
   }
 
   // output textures if present
@@ -686,7 +686,7 @@ void ColladaExporter::WriteMaterials()
       WriteImageEntry( mat.specular, mat.name + "-specular-image");
       WriteImageEntry( mat.emissive, mat.name + "-emission-image");
       WriteImageEntry( mat.reflective, mat.name + "-reflective-image");
-	  WriteImageEntry( mat.transparent, mat.name + "-transparent-image");
+      WriteImageEntry( mat.transparent, mat.name + "-transparent-image");
       WriteImageEntry( mat.normal, mat.name + "-normal-image");
     }
     PopTag();
@@ -713,27 +713,27 @@ void ColladaExporter::WriteMaterials()
       WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
       WriteTextureParamEntry( mat.specular, "specular", mat.name);
       WriteTextureParamEntry( mat.reflective, "reflective", mat.name);
-	  WriteTextureParamEntry( mat.transparent, "transparent", mat.name);
-	  WriteTextureParamEntry( mat.normal, "normal", mat.name);
+      WriteTextureParamEntry( mat.transparent, "transparent", mat.name);
+      WriteTextureParamEntry( mat.normal, "normal", mat.name);
 
       mOutput << startstr << "<technique sid=\"standard\">" << endstr;
       PushTag();
-	  mOutput << startstr << "<" << mat.shading_model << ">" << endstr;
+      mOutput << startstr << "<" << mat.shading_model << ">" << endstr;
       PushTag();
 
       WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emission-sampler");
       WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler");
       WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
       WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler");
-	  WriteFloatEntry(mat.shininess, "shininess");
+      WriteFloatEntry(mat.shininess, "shininess");
       WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler");
-	  WriteTextureColorEntry( mat.transparent, "transparent", mat.name + "-transparent-sampler");
-	  WriteFloatEntry(mat.transparency, "transparency");
-	  WriteFloatEntry(mat.index_refraction, "index_of_refraction");
+      WriteTextureColorEntry( mat.transparent, "transparent", mat.name + "-transparent-sampler");
+      WriteFloatEntry(mat.transparency, "transparency");
+      WriteFloatEntry(mat.index_refraction, "index_of_refraction");
 
-	  if(! mat.normal.texture.empty()) {
-		WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");
-	  }
+      if(! mat.normal.texture.empty()) {
+        WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");
+      }
 
       PopTag();
       mOutput << startstr << "</" << mat.shading_model << ">" << endstr;
@@ -768,325 +768,324 @@ void ColladaExporter::WriteMaterials()
 // Writes the geometry library
 void ColladaExporter::WriteGeometryLibrary()
 {
-	mOutput << startstr << "<library_geometries>" << endstr;
-	PushTag();
+    mOutput << startstr << "<library_geometries>" << endstr;
+    PushTag();
 
-	for( size_t a = 0; a < mScene->mNumMeshes; ++a)
-		WriteGeometry( a);
+    for( size_t a = 0; a < mScene->mNumMeshes; ++a)
+        WriteGeometry( a);
 
-	PopTag();
-	mOutput << startstr << "</library_geometries>" << endstr;
+    PopTag();
+    mOutput << startstr << "</library_geometries>" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Writes the given mesh
 void ColladaExporter::WriteGeometry( size_t pIndex)
 {
-	const aiMesh* mesh = mScene->mMeshes[pIndex];
-	const std::string idstr = GetMeshId( pIndex);
-	const std::string idstrEscaped = XMLEscape(idstr);
+    const aiMesh* mesh = mScene->mMeshes[pIndex];
+    const std::string idstr = GetMeshId( pIndex);
+    const std::string idstrEscaped = XMLEscape(idstr);
 
   if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
     return;
 
-	// opening tag
-	mOutput << startstr << "<geometry id=\"" << idstrEscaped << "\" name=\"" << idstrEscaped << "_name\" >" << endstr;
-	PushTag();
-
-	mOutput << startstr << "<mesh>" << endstr;
-	PushTag();
-
-	// Positions
-	WriteFloatArray( idstr + "-positions", FloatType_Vector, (float*) mesh->mVertices, mesh->mNumVertices);
-	// Normals, if any
-	if( mesh->HasNormals() )
-		WriteFloatArray( idstr + "-normals", FloatType_Vector, (float*) mesh->mNormals, mesh->mNumVertices);
-
-	// texture coords
-	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
-	{
-		if( mesh->HasTextureCoords( a) )
-		{
-			WriteFloatArray( idstr + "-tex" + boost::lexical_cast<std::string> (a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2,
-				(float*) mesh->mTextureCoords[a], mesh->mNumVertices);
-		}
-	}
-
-	// vertex colors
-	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
-	{
-		if( mesh->HasVertexColors( a) )
-			WriteFloatArray( idstr + "-color" + boost::lexical_cast<std::string> (a), FloatType_Color, (float*) mesh->mColors[a], mesh->mNumVertices);
-	}
-
-	// assemble vertex structure
-	mOutput << startstr << "<vertices id=\"" << idstrEscaped << "-vertices" << "\">" << endstr;
-	PushTag();
-	mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstrEscaped << "-positions\" />" << endstr;
-	if( mesh->HasNormals() )
-		mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstrEscaped << "-normals\" />" << endstr;
-	for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
-	{
-		if( mesh->HasTextureCoords( a) )
-			mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstrEscaped << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr;
-	}
-	for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
-	{
-		if( mesh->HasVertexColors( a) )
-			mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstrEscaped << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr;
-	}
-
-	PopTag();
-	mOutput << startstr << "</vertices>" << endstr;
-
-	// count the number of lines, triangles and polygon meshes
-	int countLines = 0;
-	int countPoly = 0;
-	for( size_t a = 0; a < mesh->mNumFaces; ++a )
-	{
-		if (mesh->mFaces[a].mNumIndices == 2) countLines++;
-		else if (mesh->mFaces[a].mNumIndices >= 3) countPoly++;
-	}
-
-	// lines
-	if (countLines)
-	{
-		mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
-		PushTag();
-		mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr;
-		mOutput << startstr << "<p>";
-		for( size_t a = 0; a < mesh->mNumFaces; ++a )
-		{
-			const aiFace& face = mesh->mFaces[a];
-			if (face.mNumIndices != 2) continue;
-			for( size_t b = 0; b < face.mNumIndices; ++b )
-				mOutput << face.mIndices[b] << " ";
-		}
-		mOutput << "</p>" << endstr;
-		PopTag();
-		mOutput << startstr << "</lines>" << endstr;
-	}
-
-	// triangle - dont use it, because compatibility problems
-
-	// polygons
-	if (countPoly)
-	{
-		mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
-		PushTag();
-		mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr;
-
-		mOutput << startstr << "<vcount>";
-		for( size_t a = 0; a < mesh->mNumFaces; ++a )
-		{
-			if (mesh->mFaces[a].mNumIndices < 3) continue;
-			mOutput << mesh->mFaces[a].mNumIndices << " ";
-		}
-		mOutput << "</vcount>" << endstr;
-
-		mOutput << startstr << "<p>";
-		for( size_t a = 0; a < mesh->mNumFaces; ++a )
-		{
-			const aiFace& face = mesh->mFaces[a];
-			if (face.mNumIndices < 3) continue;
-			for( size_t b = 0; b < face.mNumIndices; ++b )
-				mOutput << face.mIndices[b] << " ";
-		}
-		mOutput << "</p>" << endstr;
-		PopTag();
-		mOutput << startstr << "</polylist>" << endstr;
-	}
-
-	// closing tags
-	PopTag();
-	mOutput << startstr << "</mesh>" << endstr;
-	PopTag();
-	mOutput << startstr << "</geometry>" << endstr;
+    // opening tag
+    mOutput << startstr << "<geometry id=\"" << idstrEscaped << "\" name=\"" << idstrEscaped << "_name\" >" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<mesh>" << endstr;
+    PushTag();
+
+    // Positions
+    WriteFloatArray( idstr + "-positions", FloatType_Vector, (float*) mesh->mVertices, mesh->mNumVertices);
+    // Normals, if any
+    if( mesh->HasNormals() )
+        WriteFloatArray( idstr + "-normals", FloatType_Vector, (float*) mesh->mNormals, mesh->mNumVertices);
+
+    // texture coords
+    for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
+    {
+        if( mesh->HasTextureCoords( a) )
+        {
+            WriteFloatArray( idstr + "-tex" + boost::lexical_cast<std::string> (a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2,
+                (float*) mesh->mTextureCoords[a], mesh->mNumVertices);
+        }
+    }
+
+    // vertex colors
+    for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
+    {
+        if( mesh->HasVertexColors( a) )
+            WriteFloatArray( idstr + "-color" + boost::lexical_cast<std::string> (a), FloatType_Color, (float*) mesh->mColors[a], mesh->mNumVertices);
+    }
+
+    // assemble vertex structure
+    mOutput << startstr << "<vertices id=\"" << idstrEscaped << "-vertices" << "\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstrEscaped << "-positions\" />" << endstr;
+    if( mesh->HasNormals() )
+        mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstrEscaped << "-normals\" />" << endstr;
+    for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
+    {
+        if( mesh->HasTextureCoords( a) )
+            mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstrEscaped << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr;
+    }
+    for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
+    {
+        if( mesh->HasVertexColors( a) )
+            mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstrEscaped << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr;
+    }
+
+    PopTag();
+    mOutput << startstr << "</vertices>" << endstr;
+
+    // count the number of lines, triangles and polygon meshes
+    int countLines = 0;
+    int countPoly = 0;
+    for( size_t a = 0; a < mesh->mNumFaces; ++a )
+    {
+        if (mesh->mFaces[a].mNumIndices == 2) countLines++;
+        else if (mesh->mFaces[a].mNumIndices >= 3) countPoly++;
+    }
+
+    // lines
+    if (countLines)
+    {
+        mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr;
+        mOutput << startstr << "<p>";
+        for( size_t a = 0; a < mesh->mNumFaces; ++a )
+        {
+            const aiFace& face = mesh->mFaces[a];
+            if (face.mNumIndices != 2) continue;
+            for( size_t b = 0; b < face.mNumIndices; ++b )
+                mOutput << face.mIndices[b] << " ";
+        }
+        mOutput << "</p>" << endstr;
+        PopTag();
+        mOutput << startstr << "</lines>" << endstr;
+    }
+
+    // triangle - dont use it, because compatibility problems
+
+    // polygons
+    if (countPoly)
+    {
+        mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr;
+
+        mOutput << startstr << "<vcount>";
+        for( size_t a = 0; a < mesh->mNumFaces; ++a )
+        {
+            if (mesh->mFaces[a].mNumIndices < 3) continue;
+            mOutput << mesh->mFaces[a].mNumIndices << " ";
+        }
+        mOutput << "</vcount>" << endstr;
+
+        mOutput << startstr << "<p>";
+        for( size_t a = 0; a < mesh->mNumFaces; ++a )
+        {
+            const aiFace& face = mesh->mFaces[a];
+            if (face.mNumIndices < 3) continue;
+            for( size_t b = 0; b < face.mNumIndices; ++b )
+                mOutput << face.mIndices[b] << " ";
+        }
+        mOutput << "</p>" << endstr;
+        PopTag();
+        mOutput << startstr << "</polylist>" << endstr;
+    }
+
+    // closing tags
+    PopTag();
+    mOutput << startstr << "</mesh>" << endstr;
+    PopTag();
+    mOutput << startstr << "</geometry>" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Writes a float array of the given type
 void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount)
 {
-	size_t floatsPerElement = 0;
-	switch( pType )
-	{
-		case FloatType_Vector: floatsPerElement = 3; break;
-		case FloatType_TexCoord2: floatsPerElement = 2; break;
-		case FloatType_TexCoord3: floatsPerElement = 3; break;
-		case FloatType_Color: floatsPerElement = 3; break;
-		default:
-			return;
-	}
-
-	std::string arrayId = pIdString + "-array";
-
-	mOutput << startstr << "<source id=\"" << XMLEscape(pIdString) << "\" name=\"" << XMLEscape(pIdString) << "\">" << endstr;
-	PushTag();
-
-	// source array
-	mOutput << startstr << "<float_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
-	PushTag();
-
-	if( pType == FloatType_TexCoord2 )
-	{
-		for( size_t a = 0; a < pElementCount; ++a )
-		{
-			mOutput << pData[a*3+0] << " ";
-			mOutput << pData[a*3+1] << " ";
-		}
-	}
-	else if( pType == FloatType_Color )
-	{
-		for( size_t a = 0; a < pElementCount; ++a )
-		{
-			mOutput << pData[a*4+0] << " ";
-			mOutput << pData[a*4+1] << " ";
-			mOutput << pData[a*4+2] << " ";
-		}
-	}
-	else
-	{
-		for( size_t a = 0; a < pElementCount * floatsPerElement; ++a )
-			mOutput << pData[a] << " ";
-	}
-	mOutput << "</float_array>" << endstr;
-	PopTag();
-
-	// the usual Collada fun. Let's bloat it even more!
-	mOutput << startstr << "<technique_common>" << endstr;
-	PushTag();
-	mOutput << startstr << "<accessor count=\"" << pElementCount << "\" offset=\"0\" source=\"#" << arrayId << "\" stride=\"" << floatsPerElement << "\">" << endstr;
-	PushTag();
-
-	switch( pType )
-	{
-		case FloatType_Vector:
-			mOutput << startstr << "<param name=\"X\" type=\"float\" />" << endstr;
-			mOutput << startstr << "<param name=\"Y\" type=\"float\" />" << endstr;
-			mOutput << startstr << "<param name=\"Z\" type=\"float\" />" << endstr;
-			break;
-
-		case FloatType_TexCoord2:
-			mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
-			mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
-			break;
-
-		case FloatType_TexCoord3:
-			mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
-			mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
-			mOutput << startstr << "<param name=\"P\" type=\"float\" />" << endstr;
-			break;
-
-		case FloatType_Color:
-			mOutput << startstr << "<param name=\"R\" type=\"float\" />" << endstr;
-			mOutput << startstr << "<param name=\"G\" type=\"float\" />" << endstr;
-			mOutput << startstr << "<param name=\"B\" type=\"float\" />" << endstr;
-			break;
-	}
-
-	PopTag();
-	mOutput << startstr << "</accessor>" << endstr;
-	PopTag();
-	mOutput << startstr << "</technique_common>" << endstr;
-	PopTag();
-	mOutput << startstr << "</source>" << endstr;
+    size_t floatsPerElement = 0;
+    switch( pType )
+    {
+        case FloatType_Vector: floatsPerElement = 3; break;
+        case FloatType_TexCoord2: floatsPerElement = 2; break;
+        case FloatType_TexCoord3: floatsPerElement = 3; break;
+        case FloatType_Color: floatsPerElement = 3; break;
+        default:
+            return;
+    }
+
+    std::string arrayId = pIdString + "-array";
+
+    mOutput << startstr << "<source id=\"" << XMLEscape(pIdString) << "\" name=\"" << XMLEscape(pIdString) << "\">" << endstr;
+    PushTag();
+
+    // source array
+    mOutput << startstr << "<float_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
+    PushTag();
+
+    if( pType == FloatType_TexCoord2 )
+    {
+        for( size_t a = 0; a < pElementCount; ++a )
+        {
+            mOutput << pData[a*3+0] << " ";
+            mOutput << pData[a*3+1] << " ";
+        }
+    }
+    else if( pType == FloatType_Color )
+    {
+        for( size_t a = 0; a < pElementCount; ++a )
+        {
+            mOutput << pData[a*4+0] << " ";
+            mOutput << pData[a*4+1] << " ";
+            mOutput << pData[a*4+2] << " ";
+        }
+    }
+    else
+    {
+        for( size_t a = 0; a < pElementCount * floatsPerElement; ++a )
+            mOutput << pData[a] << " ";
+    }
+    mOutput << "</float_array>" << endstr;
+    PopTag();
+
+    // the usual Collada fun. Let's bloat it even more!
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    mOutput << startstr << "<accessor count=\"" << pElementCount << "\" offset=\"0\" source=\"#" << arrayId << "\" stride=\"" << floatsPerElement << "\">" << endstr;
+    PushTag();
+
+    switch( pType )
+    {
+        case FloatType_Vector:
+            mOutput << startstr << "<param name=\"X\" type=\"float\" />" << endstr;
+            mOutput << startstr << "<param name=\"Y\" type=\"float\" />" << endstr;
+            mOutput << startstr << "<param name=\"Z\" type=\"float\" />" << endstr;
+            break;
+
+        case FloatType_TexCoord2:
+            mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
+            mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
+            break;
+
+        case FloatType_TexCoord3:
+            mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
+            mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
+            mOutput << startstr << "<param name=\"P\" type=\"float\" />" << endstr;
+            break;
+
+        case FloatType_Color:
+            mOutput << startstr << "<param name=\"R\" type=\"float\" />" << endstr;
+            mOutput << startstr << "<param name=\"G\" type=\"float\" />" << endstr;
+            mOutput << startstr << "<param name=\"B\" type=\"float\" />" << endstr;
+            break;
+    }
+
+    PopTag();
+    mOutput << startstr << "</accessor>" << endstr;
+    PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+    PopTag();
+    mOutput << startstr << "</source>" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Writes the scene library
 void ColladaExporter::WriteSceneLibrary()
 {
-	const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str());
+    const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str());
 
-	mOutput << startstr << "<library_visual_scenes>" << endstr;
-	PushTag();
-	mOutput << startstr << "<visual_scene id=\"" + scene_name_escaped + "\" name=\"" + scene_name_escaped + "\">" << endstr;
-	PushTag();
+    mOutput << startstr << "<library_visual_scenes>" << endstr;
+    PushTag();
+    mOutput << startstr << "<visual_scene id=\"" + scene_name_escaped + "\" name=\"" + scene_name_escaped + "\">" << endstr;
+    PushTag();
 
-	// start recursive write at the root node
-	for( size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a )
-		WriteNode( mScene->mRootNode->mChildren[a]);
+    // start recursive write at the root node
+    for( size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a )
+        WriteNode( mScene->mRootNode->mChildren[a]);
 
-	PopTag();
-	mOutput << startstr << "</visual_scene>" << endstr;
-	PopTag();
-	mOutput << startstr << "</library_visual_scenes>" << endstr;
+    PopTag();
+    mOutput << startstr << "</visual_scene>" << endstr;
+    PopTag();
+    mOutput << startstr << "</library_visual_scenes>" << endstr;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Recursively writes the given node
 void ColladaExporter::WriteNode(aiNode* pNode)
 {
-	// the must have a name
-	if (pNode->mName.length == 0)
-	{
-		std::stringstream ss;
-		ss << "Node_" << pNode;
-		pNode->mName.Set(ss.str());
-	}
-
-	const std::string node_name_escaped = XMLEscape(pNode->mName.data);
-	mOutput << startstr << "<node id=\"" << node_name_escaped << "\" name=\"" << node_name_escaped << "\">" << endstr;
-	PushTag();
-
-	// write transformation - we can directly put the matrix there
-	// TODO: (thom) decompose into scale - rot - quad to allow adressing it by animations afterwards
-	const aiMatrix4x4& mat = pNode->mTransformation;
-	mOutput << startstr << "<matrix>";
-	mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
-	mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
-	mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
-	mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4;
-	mOutput << "</matrix>" << endstr;
-
-	if(pNode->mNumMeshes==0){
-		//check if it is a camera node
-		for(size_t i=0; i<mScene->mNumCameras; i++){
-			if(mScene->mCameras[i]->mName == pNode->mName){
-				mOutput << startstr <<"<instance_camera url=\"#" << node_name_escaped << "-camera\"/>" << endstr;
-				break;
-			}
-		}
-		//check if it is a light node
-		for(size_t i=0; i<mScene->mNumLights; i++){
-			if(mScene->mLights[i]->mName == pNode->mName){
-				mOutput << startstr <<"<instance_light url=\"#" << node_name_escaped << "-light\"/>" << endstr;
-				break;
-			}
-		}
-
-	}else
-	// instance every geometry
-	for( size_t a = 0; a < pNode->mNumMeshes; ++a )
-	{
-		const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
-	// do not instanciate mesh if empty. I wonder how this could happen
-	if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
-		continue;
-	mOutput << startstr << "<instance_geometry url=\"#" << XMLEscape(GetMeshId( pNode->mMeshes[a])) << "\">" << endstr;
-	PushTag();
-	mOutput << startstr << "<bind_material>" << endstr;
-	PushTag();
-	mOutput << startstr << "<technique_common>" << endstr;
-	PushTag();
-	mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << XMLEscape(materials[mesh->mMaterialIndex].name) << "\" />" << endstr;
-		PopTag();
-	mOutput << startstr << "</technique_common>" << endstr;
-	PopTag();
-	mOutput << startstr << "</bind_material>" << endstr;
-	PopTag();
-		mOutput << startstr << "</instance_geometry>" << endstr;
-	}
-
-	// recurse into subnodes
-	for( size_t a = 0; a < pNode->mNumChildren; ++a )
-		WriteNode( pNode->mChildren[a]);
-
-	PopTag();
-	mOutput << startstr << "</node>" << endstr;
+    // the must have a name
+    if (pNode->mName.length == 0)
+    {
+        std::stringstream ss;
+        ss << "Node_" << pNode;
+        pNode->mName.Set(ss.str());
+    }
+
+    const std::string node_name_escaped = XMLEscape(pNode->mName.data);
+    mOutput << startstr << "<node id=\"" << node_name_escaped << "\" name=\"" << node_name_escaped << "\">" << endstr;
+    PushTag();
+
+    // write transformation - we can directly put the matrix there
+    // TODO: (thom) decompose into scale - rot - quad to allow adressing it by animations afterwards
+    const aiMatrix4x4& mat = pNode->mTransformation;
+    mOutput << startstr << "<matrix>";
+    mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
+    mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
+    mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
+    mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4;
+    mOutput << "</matrix>" << endstr;
+
+    if(pNode->mNumMeshes==0){
+        //check if it is a camera node
+        for(size_t i=0; i<mScene->mNumCameras; i++){
+            if(mScene->mCameras[i]->mName == pNode->mName){
+                mOutput << startstr <<"<instance_camera url=\"#" << node_name_escaped << "-camera\"/>" << endstr;
+                break;
+            }
+        }
+        //check if it is a light node
+        for(size_t i=0; i<mScene->mNumLights; i++){
+            if(mScene->mLights[i]->mName == pNode->mName){
+                mOutput << startstr <<"<instance_light url=\"#" << node_name_escaped << "-light\"/>" << endstr;
+                break;
+            }
+        }
+
+    }else
+    // instance every geometry
+    for( size_t a = 0; a < pNode->mNumMeshes; ++a )
+    {
+        const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
+    // do not instanciate mesh if empty. I wonder how this could happen
+    if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
+        continue;
+    mOutput << startstr << "<instance_geometry url=\"#" << XMLEscape(GetMeshId( pNode->mMeshes[a])) << "\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<bind_material>" << endstr;
+    PushTag();
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << XMLEscape(materials[mesh->mMaterialIndex].name) << "\" />" << endstr;
+        PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+    PopTag();
+    mOutput << startstr << "</bind_material>" << endstr;
+    PopTag();
+        mOutput << startstr << "</instance_geometry>" << endstr;
+    }
+
+    // recurse into subnodes
+    for( size_t a = 0; a < pNode->mNumChildren; ++a )
+        WriteNode( pNode->mChildren[a]);
+
+    PopTag();
+    mOutput << startstr << "</node>" << endstr;
 }
 
 #endif
 #endif
-

+ 59 - 59
code/ColladaExporter.h

@@ -65,88 +65,88 @@ namespace Assimp
 class ColladaExporter
 {
 public:
-	/// Constructor for a specific scene to export
-	ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
+    /// Constructor for a specific scene to export
+    ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
 
-	/// Destructor
-	virtual ~ColladaExporter();
+    /// Destructor
+    virtual ~ColladaExporter();
 
 protected:
-	/// Starts writing the contents
-	void WriteFile();
+    /// Starts writing the contents
+    void WriteFile();
 
-	/// Writes the asset header
-	void WriteHeader();
+    /// Writes the asset header
+    void WriteHeader();
 
-	/// Writes the embedded textures
-	void WriteTextures();
+    /// Writes the embedded textures
+    void WriteTextures();
 
-	/// Writes the material setup
-	void WriteMaterials();
+    /// Writes the material setup
+    void WriteMaterials();
 
-	/// Writes the cameras library
-	void WriteCamerasLibrary();
+    /// Writes the cameras library
+    void WriteCamerasLibrary();
 
-	// Write a camera entry
-	void WriteCamera(size_t pIndex);
+    // Write a camera entry
+    void WriteCamera(size_t pIndex);
 
-	/// Writes the cameras library
-	void WriteLightsLibrary();
+    /// Writes the cameras library
+    void WriteLightsLibrary();
 
-	// Write a camera entry
-	void WriteLight(size_t pIndex);
-	void WritePointLight(const aiLight *const light);
-	void WriteDirectionalLight(const aiLight *const light);
-	void WriteSpotLight(const aiLight *const light);
-	void WriteAmbienttLight(const aiLight *const light);
+    // Write a camera entry
+    void WriteLight(size_t pIndex);
+    void WritePointLight(const aiLight *const light);
+    void WriteDirectionalLight(const aiLight *const light);
+    void WriteSpotLight(const aiLight *const light);
+    void WriteAmbienttLight(const aiLight *const light);
 
-	/// Writes the geometry library
-	void WriteGeometryLibrary();
+    /// Writes the geometry library
+    void WriteGeometryLibrary();
 
-	/// Writes the given mesh
-	void WriteGeometry( size_t pIndex);
+    /// Writes the given mesh
+    void WriteGeometry( size_t pIndex);
 
-	enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color };
+    enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color };
 
-	/// Writes a float array of the given type
-	void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount);
+    /// Writes a float array of the given type
+    void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount);
 
-	/// Writes the scene library
-	void WriteSceneLibrary();
+    /// Writes the scene library
+    void WriteSceneLibrary();
 
-	/// Recursively writes the given node
-	void WriteNode( aiNode* pNode);
+    /// Recursively writes the given node
+    void WriteNode( aiNode* pNode);
 
-	/// Enters a new xml element, which increases the indentation
-	void PushTag() { startstr.append( "  "); }
-	/// Leaves an element, decreasing the indentation
-	void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); }
+    /// Enters a new xml element, which increases the indentation
+    void PushTag() { startstr.append( "  "); }
+    /// Leaves an element, decreasing the indentation
+    void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); }
 
-	/// Creates a mesh ID for the given mesh
-	std::string GetMeshId( size_t pIndex) const { return std::string( "meshId" ) + boost::lexical_cast<std::string> (pIndex); }
+    /// Creates a mesh ID for the given mesh
+    std::string GetMeshId( size_t pIndex) const { return std::string( "meshId" ) + boost::lexical_cast<std::string> (pIndex); }
 
 public:
-	/// Stringstream to write all output into
-	std::stringstream mOutput;
+    /// Stringstream to write all output into
+    std::stringstream mOutput;
 
 protected:
-	/// The IOSystem for output
-	IOSystem* mIOSystem;
+    /// The IOSystem for output
+    IOSystem* mIOSystem;
 
-	/// Path of the directory where the scene will be exported
-	const std::string mPath;
+    /// Path of the directory where the scene will be exported
+    const std::string mPath;
 
-	/// Name of the file (without extension) where the scene will be exported
-	const std::string mFile;
+    /// Name of the file (without extension) where the scene will be exported
+    const std::string mFile;
 
-	/// The scene to be written
-	const aiScene* mScene;
-	bool mSceneOwned;
+    /// The scene to be written
+    const aiScene* mScene;
+    bool mSceneOwned;
 
-	/// current line start string, contains the current indentation for simple stream insertion
-	std::string startstr;
-	/// current line end string for simple stream insertion
-	std::string endstr;
+    /// current line start string, contains the current indentation for simple stream insertion
+    std::string startstr;
+    /// current line end string for simple stream insertion
+    std::string endstr;
 
   // pair of color and texture - texture precedences color
   struct Surface
@@ -161,8 +161,8 @@ protected:
   struct Property
   {
     bool exist;
-	 float value;
-	 Property()
+     float value;
+     Property()
          : exist(false)
          , value(0.0f)
      {}
@@ -174,7 +174,7 @@ protected:
     std::string name;
     std::string shading_model;
     Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
-   	Property shininess, transparency, index_refraction;
+    Property shininess, transparency, index_refraction;
 
     Material() {}
   };

+ 356 - 356
code/ColladaHelper.h

@@ -53,79 +53,79 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiMaterial;
 
-namespace Assimp	{
-namespace Collada		{
+namespace Assimp    {
+namespace Collada       {
 
 /** Collada file versions which evolved during the years ... */
 enum FormatVersion
 {
-	FV_1_5_n,
-	FV_1_4_n,
-	FV_1_3_n
+    FV_1_5_n,
+    FV_1_4_n,
+    FV_1_3_n
 };
 
 
 /** Transformation types that can be applied to a node */
 enum TransformType
 {
-	TF_LOOKAT,
-	TF_ROTATE,
-	TF_TRANSLATE,
-	TF_SCALE,
-	TF_SKEW,
-	TF_MATRIX
+    TF_LOOKAT,
+    TF_ROTATE,
+    TF_TRANSLATE,
+    TF_SCALE,
+    TF_SKEW,
+    TF_MATRIX
 };
 
 /** Different types of input data to a vertex or face */
 enum InputType
 {
-	IT_Invalid,
-	IT_Vertex,  // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
-	IT_Position,
-	IT_Normal,
-	IT_Texcoord,
-	IT_Color,
-	IT_Tangent,
-	IT_Bitangent
+    IT_Invalid,
+    IT_Vertex,  // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
+    IT_Position,
+    IT_Normal,
+    IT_Texcoord,
+    IT_Color,
+    IT_Tangent,
+    IT_Bitangent
 };
 
 /** Contains all data for one of the different transformation types */
 struct Transform
 {
-	std::string mID;  ///< SID of the transform step, by which anim channels address their target node
-	TransformType mType;
-	float f[16]; ///< Interpretation of data depends on the type of the transformation
+    std::string mID;  ///< SID of the transform step, by which anim channels address their target node
+    TransformType mType;
+    float f[16]; ///< Interpretation of data depends on the type of the transformation
 };
 
 /** A collada camera. */
 struct Camera
 {
-	Camera()
-		:	mOrtho  (false)
-		,	mHorFov (10e10f)
-		,	mVerFov (10e10f)
-		,	mAspect (10e10f)
-		,	mZNear  (0.1f)
-		,	mZFar   (1000.f)
-	{}
-
-	// Name of camera
-	std::string mName;
+    Camera()
+        :   mOrtho  (false)
+        ,   mHorFov (10e10f)
+        ,   mVerFov (10e10f)
+        ,   mAspect (10e10f)
+        ,   mZNear  (0.1f)
+        ,   mZFar   (1000.f)
+    {}
+
+    // Name of camera
+    std::string mName;
 
-	// True if it is an orthografic camera
-	bool mOrtho;
+    // True if it is an orthografic camera
+    bool mOrtho;
 
-	//! Horizontal field of view in degrees
-	float mHorFov;
+    //! Horizontal field of view in degrees
+    float mHorFov;
 
-	//! Vertical field of view in degrees
-	float mVerFov;
+    //! Vertical field of view in degrees
+    float mVerFov;
 
-	//! Screen aspect
-	float mAspect;
+    //! Screen aspect
+    float mAspect;
 
-	//! Near& far z
-	float mZNear, mZFar;
+    //! Near& far z
+    float mZNear, mZFar;
 };
 
 #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
@@ -133,70 +133,70 @@ struct Camera
 /** A collada light source. */
 struct Light
 {
-	Light()
-		:	mType            (aiLightSource_UNDEFINED)
-		,	mAttConstant     (1.f)
-		,	mAttLinear       (0.f)
-		,	mAttQuadratic    (0.f)
-		,	mFalloffAngle    (180.f)
-		,	mFalloffExponent (0.f)
-		,	mPenumbraAngle	 (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
-		,	mOuterAngle		 (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
-		,	mIntensity		 (1.f)
-	{}
-
-	//! Type of the light source aiLightSourceType + ambient
-	unsigned int mType;
-
-	//! Color of the light
-	aiColor3D mColor;
-
-	//! Light attenuation
-	float mAttConstant,mAttLinear,mAttQuadratic;
-
-	//! Spot light falloff
-	float mFalloffAngle;
-	float mFalloffExponent;
-
-	// -----------------------------------------------------
-	// FCOLLADA extension from here
-
-	//! ... related stuff from maja and max extensions
-	float mPenumbraAngle;
-	float mOuterAngle;
-
-	//! Common light intensity
-	float mIntensity;
+    Light()
+        :   mType            (aiLightSource_UNDEFINED)
+        ,   mAttConstant     (1.f)
+        ,   mAttLinear       (0.f)
+        ,   mAttQuadratic    (0.f)
+        ,   mFalloffAngle    (180.f)
+        ,   mFalloffExponent (0.f)
+        ,   mPenumbraAngle   (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
+        ,   mOuterAngle      (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
+        ,   mIntensity       (1.f)
+    {}
+
+    //! Type of the light source aiLightSourceType + ambient
+    unsigned int mType;
+
+    //! Color of the light
+    aiColor3D mColor;
+
+    //! Light attenuation
+    float mAttConstant,mAttLinear,mAttQuadratic;
+
+    //! Spot light falloff
+    float mFalloffAngle;
+    float mFalloffExponent;
+
+    // -----------------------------------------------------
+    // FCOLLADA extension from here
+
+    //! ... related stuff from maja and max extensions
+    float mPenumbraAngle;
+    float mOuterAngle;
+
+    //! Common light intensity
+    float mIntensity;
 };
 
 /** Short vertex index description */
 struct InputSemanticMapEntry
 {
-	InputSemanticMapEntry()
-		:	mSet(0)
-		,	mType(IT_Invalid)
-	{}
+    InputSemanticMapEntry()
+        :   mSet(0)
+        ,   mType(IT_Invalid)
+    {}
 
-	//! Index of set, optional
-	unsigned int mSet;
+    //! Index of set, optional
+    unsigned int mSet;
 
-	//! Type of referenced vertex input
-	InputType mType;
+    //! Type of referenced vertex input
+    InputType mType;
 };
 
 /** Table to map from effect to vertex input semantics */
 struct SemanticMappingTable
 {
-	//! Name of material
-	std::string mMatName;
+    //! Name of material
+    std::string mMatName;
 
-	//! List of semantic map commands, grouped by effect semantic name
-	std::map<std::string, InputSemanticMapEntry> mMap;
+    //! List of semantic map commands, grouped by effect semantic name
+    std::map<std::string, InputSemanticMapEntry> mMap;
 
-	//! For std::find
-	bool operator == (const std::string& s) const {
-		return s == mMatName;
-	}
+    //! For std::find
+    bool operator == (const std::string& s) const {
+        return s == mMatName;
+    }
 };
 
 /** A reference to a mesh inside a node, including materials assigned to the various subgroups.
@@ -204,414 +204,414 @@ struct SemanticMappingTable
  */
 struct MeshInstance
 {
-	///< ID of the mesh or controller to be instanced
-	std::string mMeshOrController;
+    ///< ID of the mesh or controller to be instanced
+    std::string mMeshOrController;
 
-	///< Map of materials by the subgroup ID they're applied to
-	std::map<std::string, SemanticMappingTable> mMaterials;
+    ///< Map of materials by the subgroup ID they're applied to
+    std::map<std::string, SemanticMappingTable> mMaterials;
 };
 
 /** A reference to a camera inside a node*/
 struct CameraInstance
 {
-	 ///< ID of the camera
-	std::string mCamera;
+     ///< ID of the camera
+    std::string mCamera;
 };
 
 /** A reference to a light inside a node*/
 struct LightInstance
 {
-	 ///< ID of the camera
-	std::string mLight;
+     ///< ID of the camera
+    std::string mLight;
 };
 
 /** A reference to a node inside a node*/
 struct NodeInstance
 {
-	 ///< ID of the node
-	std::string mNode;
+     ///< ID of the node
+    std::string mNode;
 };
 
 /** A node in a scene hierarchy */
 struct Node
 {
-	std::string mName;
-	std::string mID;
+    std::string mName;
+    std::string mID;
     std::string mSID;
-	Node* mParent;
-	std::vector<Node*> mChildren;
+    Node* mParent;
+    std::vector<Node*> mChildren;
 
-	/** Operations in order to calculate the resulting transformation to parent. */
-	std::vector<Transform> mTransforms;
+    /** Operations in order to calculate the resulting transformation to parent. */
+    std::vector<Transform> mTransforms;
 
-	/** Meshes at this node */
-	std::vector<MeshInstance> mMeshes;
+    /** Meshes at this node */
+    std::vector<MeshInstance> mMeshes;
 
-	/** Lights at this node */
-	std::vector<LightInstance> mLights;
+    /** Lights at this node */
+    std::vector<LightInstance> mLights;
 
-	/** Cameras at this node */
-	std::vector<CameraInstance> mCameras;
+    /** Cameras at this node */
+    std::vector<CameraInstance> mCameras;
 
-	/** Node instances at this node */
-	std::vector<NodeInstance> mNodeInstances;
+    /** Node instances at this node */
+    std::vector<NodeInstance> mNodeInstances;
 
-	/** Rootnodes: Name of primary camera, if any */
-	std::string mPrimaryCamera;
+    /** Rootnodes: Name of primary camera, if any */
+    std::string mPrimaryCamera;
 
-	//! Constructor. Begin with a zero parent
-	Node() {
-		mParent = NULL;
-	}
+    //! Constructor. Begin with a zero parent
+    Node() {
+        mParent = NULL;
+    }
 
-	//! Destructor: delete all children subsequently
-	~Node() {
-		for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
-			delete *it;
-	}
+    //! Destructor: delete all children subsequently
+    ~Node() {
+        for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
+            delete *it;
+    }
 };
 
 /** Data source array: either floats or strings */
 struct Data
 {
-	bool mIsStringArray;
-	std::vector<float> mValues;
-	std::vector<std::string> mStrings;
+    bool mIsStringArray;
+    std::vector<float> mValues;
+    std::vector<std::string> mStrings;
 };
 
 /** Accessor to a data array */
 struct Accessor
 {
-	size_t mCount;   // in number of objects
-	size_t mSize;    // size of an object, in elements (floats or strings, mostly 1)
-	size_t mOffset;  // in number of values
-	size_t mStride;  // Stride in number of values
-	std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
-	size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
-						  // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
-	std::string mSource;   // URL of the source array
-	mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
-
-	Accessor()
-	{
-		mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
-		mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
-	}
+    size_t mCount;   // in number of objects
+    size_t mSize;    // size of an object, in elements (floats or strings, mostly 1)
+    size_t mOffset;  // in number of values
+    size_t mStride;  // Stride in number of values
+    std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
+    size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
+                          // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
+    std::string mSource;   // URL of the source array
+    mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
+
+    Accessor()
+    {
+        mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
+        mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
+    }
 };
 
 /** A single face in a mesh */
 struct Face
 {
-	std::vector<size_t> mIndices;
+    std::vector<size_t> mIndices;
 };
 
 /** An input channel for mesh data, referring to a single accessor */
 struct InputChannel
 {
-	InputType mType;      // Type of the data
-	size_t mIndex;		  // Optional index, if multiple sets of the same data type are given
-	size_t mOffset;       // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
-	std::string mAccessor; // ID of the accessor where to read the actual values from.
-	mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
+    InputType mType;      // Type of the data
+    size_t mIndex;        // Optional index, if multiple sets of the same data type are given
+    size_t mOffset;       // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
+    std::string mAccessor; // ID of the accessor where to read the actual values from.
+    mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
 
-	InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
+    InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
 };
 
 /** Subset of a mesh with a certain material */
 struct SubMesh
 {
-	std::string mMaterial; ///< subgroup identifier
-	size_t mNumFaces; ///< number of faces in this submesh
+    std::string mMaterial; ///< subgroup identifier
+    size_t mNumFaces; ///< number of faces in this submesh
 };
 
 /** Contains data for a single mesh */
 struct Mesh
 {
-	Mesh()
-	{
-		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
-			mNumUVComponents[i] = 2;
-	}
+    Mesh()
+    {
+        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
+            mNumUVComponents[i] = 2;
+    }
 
     std::string mName;
 
-	// just to check if there's some sophisticated addressing involved...
-	// which we don't support, and therefore should warn about.
-	std::string mVertexID;
+    // just to check if there's some sophisticated addressing involved...
+    // which we don't support, and therefore should warn about.
+    std::string mVertexID;
 
-	// Vertex data addressed by vertex indices
-	std::vector<InputChannel> mPerVertexData;
+    // Vertex data addressed by vertex indices
+    std::vector<InputChannel> mPerVertexData;
 
-	// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
-	std::vector<aiVector3D> mPositions;
-	std::vector<aiVector3D> mNormals;
-	std::vector<aiVector3D> mTangents;
-	std::vector<aiVector3D> mBitangents;
-	std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
-	std::vector<aiColor4D>  mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
+    // actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
+    std::vector<aiVector3D> mPositions;
+    std::vector<aiVector3D> mNormals;
+    std::vector<aiVector3D> mTangents;
+    std::vector<aiVector3D> mBitangents;
+    std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+    std::vector<aiColor4D>  mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
 
-	unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+    unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 
-	// Faces. Stored are only the number of vertices for each face.
-	// 1 == point, 2 == line, 3 == triangle, 4+ == poly
-	std::vector<size_t> mFaceSize;
+    // Faces. Stored are only the number of vertices for each face.
+    // 1 == point, 2 == line, 3 == triangle, 4+ == poly
+    std::vector<size_t> mFaceSize;
 
-	// Position indices for all faces in the sequence given in mFaceSize -
-	// necessary for bone weight assignment
-	std::vector<size_t> mFacePosIndices;
+    // Position indices for all faces in the sequence given in mFaceSize -
+    // necessary for bone weight assignment
+    std::vector<size_t> mFacePosIndices;
 
-	// Submeshes in this mesh, each with a given material
-	std::vector<SubMesh> mSubMeshes;
+    // Submeshes in this mesh, each with a given material
+    std::vector<SubMesh> mSubMeshes;
 };
 
 /** Which type of primitives the ReadPrimitives() function is going to read */
 enum PrimitiveType
 {
-	Prim_Invalid,
-	Prim_Lines,
-	Prim_LineStrip,
-	Prim_Triangles,
-	Prim_TriStrips,
-	Prim_TriFans,
-	Prim_Polylist,
-	Prim_Polygon
+    Prim_Invalid,
+    Prim_Lines,
+    Prim_LineStrip,
+    Prim_Triangles,
+    Prim_TriStrips,
+    Prim_TriFans,
+    Prim_Polylist,
+    Prim_Polygon
 };
 
 /** A skeleton controller to deform a mesh with the use of joints */
 struct Controller
 {
-	// the URL of the mesh deformed by the controller.
-	std::string mMeshId;
+    // the URL of the mesh deformed by the controller.
+    std::string mMeshId;
 
-	// accessor URL of the joint names
-	std::string mJointNameSource;
+    // accessor URL of the joint names
+    std::string mJointNameSource;
 
     ///< The bind shape matrix, as array of floats. I'm not sure what this matrix actually describes, but it can't be ignored in all cases
     float mBindShapeMatrix[16];
 
-	// accessor URL of the joint inverse bind matrices
-	std::string mJointOffsetMatrixSource;
+    // accessor URL of the joint inverse bind matrices
+    std::string mJointOffsetMatrixSource;
 
-	// input channel: joint names.
-	InputChannel mWeightInputJoints;
-	// input channel: joint weights
-	InputChannel mWeightInputWeights;
+    // input channel: joint names.
+    InputChannel mWeightInputJoints;
+    // input channel: joint weights
+    InputChannel mWeightInputWeights;
 
-	// Number of weights per vertex.
-	std::vector<size_t> mWeightCounts;
+    // Number of weights per vertex.
+    std::vector<size_t> mWeightCounts;
 
-	// JointIndex-WeightIndex pairs for all vertices
-	std::vector< std::pair<size_t, size_t> > mWeights;
+    // JointIndex-WeightIndex pairs for all vertices
+    std::vector< std::pair<size_t, size_t> > mWeights;
 };
 
 /** A collada material. Pretty much the only member is a reference to an effect. */
 struct Material
 {
-	std::string mName;
-	std::string mEffect;
+    std::string mName;
+    std::string mEffect;
 };
 
 /** Type of the effect param */
 enum ParamType
 {
-	Param_Sampler,
-	Param_Surface
+    Param_Sampler,
+    Param_Surface
 };
 
 /** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
 struct EffectParam
 {
-	ParamType mType;
-	std::string mReference; // to which other thing the param is referring to.
+    ParamType mType;
+    std::string mReference; // to which other thing the param is referring to.
 };
 
 /** Shading type supported by the standard effect spec of Collada */
 enum ShadeType
 {
-	Shade_Invalid,
-	Shade_Constant,
-	Shade_Lambert,
-	Shade_Phong,
-	Shade_Blinn
+    Shade_Invalid,
+    Shade_Constant,
+    Shade_Lambert,
+    Shade_Phong,
+    Shade_Blinn
 };
 
 /** Represents a texture sampler in collada */
 struct Sampler
 {
-	Sampler()
-		:	mWrapU		(true)
-		,	mWrapV		(true)
-		,	mMirrorU	()
-		,	mMirrorV	()
-		,	mOp			(aiTextureOp_Multiply)
-		,	mUVId		(UINT_MAX)
-		,	mWeighting  (1.f)
-		,	mMixWithPrevious (1.f)
-	{}
-
-	/** Name of image reference
-	 */
-	std::string mName;
-
-	/** Wrap U?
-	 */
-	bool mWrapU;
-
-	/** Wrap V?
-	 */
-	bool mWrapV;
-
-	/** Mirror U?
-	 */
-	bool mMirrorU;
-
-	/** Mirror V?
-	 */
-	bool mMirrorV;
-
-	/** Blend mode
-	 */
-	aiTextureOp mOp;
-
-	/** UV transformation
-	 */
-	aiUVTransform mTransform;
-
-	/** Name of source UV channel
-	 */
-	std::string mUVChannel;
-
-	/** Resolved UV channel index or UINT_MAX if not known
-	 */
-	unsigned int mUVId;
-
-	// OKINO/MAX3D extensions from here
-	// -------------------------------------------------------
-
-	/** Weighting factor
-	 */
-	float mWeighting;
-
-	/** Mixing factor from OKINO
-	 */
-	float mMixWithPrevious;
+    Sampler()
+        :   mWrapU      (true)
+        ,   mWrapV      (true)
+        ,   mMirrorU    ()
+        ,   mMirrorV    ()
+        ,   mOp         (aiTextureOp_Multiply)
+        ,   mUVId       (UINT_MAX)
+        ,   mWeighting  (1.f)
+        ,   mMixWithPrevious (1.f)
+    {}
+
+    /** Name of image reference
+     */
+    std::string mName;
+
+    /** Wrap U?
+     */
+    bool mWrapU;
+
+    /** Wrap V?
+     */
+    bool mWrapV;
+
+    /** Mirror U?
+     */
+    bool mMirrorU;
+
+    /** Mirror V?
+     */
+    bool mMirrorV;
+
+    /** Blend mode
+     */
+    aiTextureOp mOp;
+
+    /** UV transformation
+     */
+    aiUVTransform mTransform;
+
+    /** Name of source UV channel
+     */
+    std::string mUVChannel;
+
+    /** Resolved UV channel index or UINT_MAX if not known
+     */
+    unsigned int mUVId;
+
+    // OKINO/MAX3D extensions from here
+    // -------------------------------------------------------
+
+    /** Weighting factor
+     */
+    float mWeighting;
+
+    /** Mixing factor from OKINO
+     */
+    float mMixWithPrevious;
 };
 
 /** A collada effect. Can contain about anything according to the Collada spec,
     but we limit our version to a reasonable subset. */
 struct Effect
 {
-	// Shading mode
-	ShadeType mShadeType;
-
-	// Colors
-	aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
-		mTransparent, mReflective;
-
-	// Textures
-	Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
-		mTexTransparent, mTexBump, mTexReflective;
-
-	// Scalar factory
-	float mShininess, mRefractIndex, mReflectivity;
-	float mTransparency;
-	bool mHasTransparency;
-	bool mRGBTransparency;
-
-	// local params referring to each other by their SID
-	typedef std::map<std::string, Collada::EffectParam> ParamLibrary;
-	ParamLibrary mParams;
-
-	// MAX3D extensions
-	// ---------------------------------------------------------
-	// Double-sided?
-	bool mDoubleSided, mWireframe, mFaceted;
-
-	Effect()
-		: mShadeType    (Shade_Phong)
-		, mEmissive		( 0, 0, 0, 1)
-		, mAmbient		( 0.1f, 0.1f, 0.1f, 1)
-		, mDiffuse		( 0.6f, 0.6f, 0.6f, 1)
-		, mSpecular		( 0.4f, 0.4f, 0.4f, 1)
-		, mTransparent	( 0, 0, 0, 1)
-		, mShininess    (10.0f)
-		, mRefractIndex (1.f)
-		, mReflectivity (1.f)
-		, mTransparency (1.f)
-		, mHasTransparency (false)
-		, mRGBTransparency(false)
-		, mDoubleSided	(false)
-		, mWireframe    (false)
-		, mFaceted      (false)
-	{
-	}
+    // Shading mode
+    ShadeType mShadeType;
+
+    // Colors
+    aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
+        mTransparent, mReflective;
+
+    // Textures
+    Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
+        mTexTransparent, mTexBump, mTexReflective;
+
+    // Scalar factory
+    float mShininess, mRefractIndex, mReflectivity;
+    float mTransparency;
+    bool mHasTransparency;
+    bool mRGBTransparency;
+
+    // local params referring to each other by their SID
+    typedef std::map<std::string, Collada::EffectParam> ParamLibrary;
+    ParamLibrary mParams;
+
+    // MAX3D extensions
+    // ---------------------------------------------------------
+    // Double-sided?
+    bool mDoubleSided, mWireframe, mFaceted;
+
+    Effect()
+        : mShadeType    (Shade_Phong)
+        , mEmissive     ( 0, 0, 0, 1)
+        , mAmbient      ( 0.1f, 0.1f, 0.1f, 1)
+        , mDiffuse      ( 0.6f, 0.6f, 0.6f, 1)
+        , mSpecular     ( 0.4f, 0.4f, 0.4f, 1)
+        , mTransparent  ( 0, 0, 0, 1)
+        , mShininess    (10.0f)
+        , mRefractIndex (1.f)
+        , mReflectivity (1.f)
+        , mTransparency (1.f)
+        , mHasTransparency (false)
+        , mRGBTransparency(false)
+        , mDoubleSided  (false)
+        , mWireframe    (false)
+        , mFaceted      (false)
+    {
+    }
 };
 
 /** An image, meaning texture */
 struct Image
 {
-	std::string mFileName;
+    std::string mFileName;
 
-	/** If image file name is zero, embedded image data
-	 */
-	std::vector<uint8_t> mImageData;
+    /** If image file name is zero, embedded image data
+     */
+    std::vector<uint8_t> mImageData;
 
-	/** If image file name is zero, file format of
-	 *  embedded image data.
-	 */
-	std::string mEmbeddedFormat;
+    /** If image file name is zero, file format of
+     *  embedded image data.
+     */
+    std::string mEmbeddedFormat;
 
 };
 
 /** An animation channel. */
 struct AnimationChannel
 {
-	/** URL of the data to animate. Could be about anything, but we support only the
-	 * "NodeID/TransformID.SubElement" notation
-	 */
-	std::string mTarget;
-
-	/** Source URL of the time values. Collada calls them "input". Meh. */
-	std::string mSourceTimes;
-	/** Source URL of the value values. Collada calls them "output". */
-	std::string mSourceValues;
+    /** URL of the data to animate. Could be about anything, but we support only the
+     * "NodeID/TransformID.SubElement" notation
+     */
+    std::string mTarget;
+
+    /** Source URL of the time values. Collada calls them "input". Meh. */
+    std::string mSourceTimes;
+    /** Source URL of the value values. Collada calls them "output". */
+    std::string mSourceValues;
 };
 
 /** An animation. Container for 0-x animation channels or 0-x animations */
 struct Animation
 {
-	/** Anim name */
-	std::string mName;
+    /** Anim name */
+    std::string mName;
 
-	/** the animation channels, if any */
-	std::vector<AnimationChannel> mChannels;
+    /** the animation channels, if any */
+    std::vector<AnimationChannel> mChannels;
 
-	/** the sub-animations, if any */
-	std::vector<Animation*> mSubAnims;
+    /** the sub-animations, if any */
+    std::vector<Animation*> mSubAnims;
 
-	/** Destructor */
-	~Animation()
-	{
-		for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
-			delete *it;
-	}
+    /** Destructor */
+    ~Animation()
+    {
+        for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
+            delete *it;
+    }
 };
 
 /** Description of a collada animation channel which has been determined to affect the current node */
 struct ChannelEntry
 {
-	const Collada::AnimationChannel* mChannel; ///> the source channel
-	std::string mTransformId;   // the ID of the transformation step of the node which is influenced
-	size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
-	size_t mSubElement; // starting index inside the transform data
-
-	// resolved data references
-	const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
-	const Collada::Data* mTimeData; ///> Source data array for the time values
-	const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
-	const Collada::Data* mValueData; ///> Source datat array for the key value values
-
-	ChannelEntry()
+    const Collada::AnimationChannel* mChannel; ///> the source channel
+    std::string mTransformId;   // the ID of the transformation step of the node which is influenced
+    size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
+    size_t mSubElement; // starting index inside the transform data
+
+    // resolved data references
+    const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
+    const Collada::Data* mTimeData; ///> Source data array for the time values
+    const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
+    const Collada::Data* mValueData; ///> Source datat array for the key value values
+
+    ChannelEntry()
       : mChannel()
       , mTransformIndex()
       , mSubElement()

File diff suppressed because it is too large
+ 1225 - 1225
code/ColladaLoader.cpp


+ 162 - 162
code/ColladaLoader.h

@@ -57,26 +57,26 @@ namespace Assimp
 
 struct ColladaMeshIndex
 {
-	std::string mMeshID;
-	size_t mSubMesh;
-	std::string mMaterial;
-	ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial)
-		: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
-	{   }
-
-	bool operator < (const ColladaMeshIndex& p) const
-	{
-		if( mMeshID == p.mMeshID)
-		{
-			if( mSubMesh == p.mSubMesh)
-				return mMaterial < p.mMaterial;
-			else
-				return mSubMesh < p.mSubMesh;
-		} else
-		{
-			return mMeshID < p.mMeshID;
-		}
-	}
+    std::string mMeshID;
+    size_t mSubMesh;
+    std::string mMaterial;
+    ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial)
+        : mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
+    {   }
+
+    bool operator < (const ColladaMeshIndex& p) const
+    {
+        if( mMeshID == p.mMeshID)
+        {
+            if( mSubMesh == p.mSubMesh)
+                return mMaterial < p.mMaterial;
+            else
+                return mSubMesh < p.mSubMesh;
+        } else
+        {
+            return mMeshID < p.mMeshID;
+        }
+    }
 };
 
 /** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
@@ -85,166 +85,166 @@ struct ColladaMeshIndex
 class ColladaLoader : public BaseImporter
 {
 public:
-	ColladaLoader();
-	~ColladaLoader();
+    ColladaLoader();
+    ~ColladaLoader();
 
 
 public:
-	/** Returns whether the class can handle the format of the given file.
-	 * See BaseImporter::CanRead() for details.	*/
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
+    /** Returns whether the class can handle the format of the given file.
+     * See BaseImporter::CanRead() for details. */
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
 
 protected:
-	/** Return importer meta information.
-	 * See #BaseImporter::GetInfo for the details
-	 */
-	const aiImporterDesc* GetInfo () const;
-
-	void SetupProperties(const Importer* pImp);
-
-	/** Imports the given file into the given scene structure.
-	 * See BaseImporter::InternReadFile() for details
-	 */
-	void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
-
-	/** Recursively constructs a scene node for the given parser node and returns it. */
-	aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
-
-	/** Resolve node instances */
-	void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
-		std::vector<const Collada::Node*>& resolved);
-
-	/** Builds meshes for the given node and references them */
-	void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
-		aiNode* pTarget);
-
-	/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
-	aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
-		const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
-
-	/** Builds cameras for the given node and references them */
-	void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode,
-		aiNode* pTarget);
-
-	/** Builds lights for the given node and references them */
-	void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode,
-		aiNode* pTarget);
-
-	/** Stores all meshes in the given scene */
-	void StoreSceneMeshes( aiScene* pScene);
-
-	/** Stores all materials in the given scene */
-	void StoreSceneMaterials( aiScene* pScene);
-
-	/** Stores all lights in the given scene */
-	void StoreSceneLights( aiScene* pScene);
-
-	/** Stores all cameras in the given scene */
-	void StoreSceneCameras( aiScene* pScene);
-
-	/** Stores all textures in the given scene */
-	void StoreSceneTextures( aiScene* pScene);
-
-	/** Stores all animations
-	 * @param pScene target scene to store the anims
-	 */
-	void StoreAnimations( aiScene* pScene, const ColladaParser& pParser);
-
-	/** Stores all animations for the given source anim and its nested child animations
-	 * @param pScene target scene to store the anims
-	 * @param pSrcAnim the source animation to process
-	 * @param pPrefix Prefix to the name in case of nested animations
-	 */
-	void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pPrefix);
-
-	/** Constructs the animation for the given source anim */
-	void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName);
-
-	/** Constructs materials from the collada material definitions */
-	void BuildMaterials( ColladaParser& pParser, aiScene* pScene);
-
-	/** Fill materials from the collada material definitions */
-	void FillMaterials( const ColladaParser& pParser, aiScene* pScene);
-
-	/** Resolve UV channel mappings*/
-	void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
-		const Collada::SemanticMappingTable& table);
-
-	/** Add a texture and all of its sampling properties to a material*/
-	void AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
-		const Collada::Effect& effect,
-		const Collada::Sampler& sampler,
-		aiTextureType type, unsigned int idx = 0);
-
-	/** Resolves the texture name for the given effect texture entry */
-	aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
-		const Collada::Effect& pEffect, const std::string& pName);
-
-	/** Converts a path read from a collada file to the usual representation */
-	void ConvertPath( aiString& ss);
-
-	/** Reads a float value from an accessor and its data array.
-	 * @param pAccessor The accessor to use for reading
-	 * @param pData The data array to read from
-	 * @param pIndex The index of the element to retrieve
-	 * @param pOffset Offset into the element, for multipart elements such as vectors or matrices
-	 * @return the specified value
-	 */
-	float ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const;
-
-	/** Reads a string value from an accessor and its data array.
-	 * @param pAccessor The accessor to use for reading
-	 * @param pData The data array to read from
-	 * @param pIndex The index of the element to retrieve
-	 * @return the specified value
-	 */
-	const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const;
+    /** Return importer meta information.
+     * See #BaseImporter::GetInfo for the details
+     */
+    const aiImporterDesc* GetInfo () const;
+
+    void SetupProperties(const Importer* pImp);
+
+    /** Imports the given file into the given scene structure.
+     * See BaseImporter::InternReadFile() for details
+     */
+    void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+
+    /** Recursively constructs a scene node for the given parser node and returns it. */
+    aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
+
+    /** Resolve node instances */
+    void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
+        std::vector<const Collada::Node*>& resolved);
+
+    /** Builds meshes for the given node and references them */
+    void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
+        aiNode* pTarget);
+
+    /** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
+    aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
+        const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
+
+    /** Builds cameras for the given node and references them */
+    void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode,
+        aiNode* pTarget);
+
+    /** Builds lights for the given node and references them */
+    void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode,
+        aiNode* pTarget);
+
+    /** Stores all meshes in the given scene */
+    void StoreSceneMeshes( aiScene* pScene);
+
+    /** Stores all materials in the given scene */
+    void StoreSceneMaterials( aiScene* pScene);
+
+    /** Stores all lights in the given scene */
+    void StoreSceneLights( aiScene* pScene);
+
+    /** Stores all cameras in the given scene */
+    void StoreSceneCameras( aiScene* pScene);
+
+    /** Stores all textures in the given scene */
+    void StoreSceneTextures( aiScene* pScene);
+
+    /** Stores all animations
+     * @param pScene target scene to store the anims
+     */
+    void StoreAnimations( aiScene* pScene, const ColladaParser& pParser);
+
+    /** Stores all animations for the given source anim and its nested child animations
+     * @param pScene target scene to store the anims
+     * @param pSrcAnim the source animation to process
+     * @param pPrefix Prefix to the name in case of nested animations
+     */
+    void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pPrefix);
+
+    /** Constructs the animation for the given source anim */
+    void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName);
+
+    /** Constructs materials from the collada material definitions */
+    void BuildMaterials( ColladaParser& pParser, aiScene* pScene);
+
+    /** Fill materials from the collada material definitions */
+    void FillMaterials( const ColladaParser& pParser, aiScene* pScene);
+
+    /** Resolve UV channel mappings*/
+    void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
+        const Collada::SemanticMappingTable& table);
+
+    /** Add a texture and all of its sampling properties to a material*/
+    void AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
+        const Collada::Effect& effect,
+        const Collada::Sampler& sampler,
+        aiTextureType type, unsigned int idx = 0);
+
+    /** Resolves the texture name for the given effect texture entry */
+    aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
+        const Collada::Effect& pEffect, const std::string& pName);
+
+    /** Converts a path read from a collada file to the usual representation */
+    void ConvertPath( aiString& ss);
+
+    /** Reads a float value from an accessor and its data array.
+     * @param pAccessor The accessor to use for reading
+     * @param pData The data array to read from
+     * @param pIndex The index of the element to retrieve
+     * @param pOffset Offset into the element, for multipart elements such as vectors or matrices
+     * @return the specified value
+     */
+    float ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const;
+
+    /** Reads a string value from an accessor and its data array.
+     * @param pAccessor The accessor to use for reading
+     * @param pData The data array to read from
+     * @param pIndex The index of the element to retrieve
+     * @return the specified value
+     */
+    const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const;
 
-	/** Recursively collects all nodes into the given array */
-	void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const;
-
-	/** Finds a node in the collada scene by the given name */
-	const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const;
-	/** Finds a node in the collada scene by the given SID */
-	const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
-
-	/** Finds a proper name for a node derived from the collada-node's properties */
-	std::string FindNameForNode( const Collada::Node* pNode);
+    /** Recursively collects all nodes into the given array */
+    void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const;
+
+    /** Finds a node in the collada scene by the given name */
+    const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const;
+    /** Finds a node in the collada scene by the given SID */
+    const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
+
+    /** Finds a proper name for a node derived from the collada-node's properties */
+    std::string FindNameForNode( const Collada::Node* pNode);
 
 protected:
-	/** Filename, for a verbose error message */
-	std::string mFileName;
+    /** Filename, for a verbose error message */
+    std::string mFileName;
 
-	/** Which mesh-material compound was stored under which mesh ID */
-	std::map<ColladaMeshIndex, size_t> mMeshIndexByID;
+    /** Which mesh-material compound was stored under which mesh ID */
+    std::map<ColladaMeshIndex, size_t> mMeshIndexByID;
 
-	/** Which material was stored under which index in the scene */
-	std::map<std::string, size_t> mMaterialIndexByName;
+    /** Which material was stored under which index in the scene */
+    std::map<std::string, size_t> mMaterialIndexByName;
 
-	/** Accumulated meshes for the target scene */
-	std::vector<aiMesh*> mMeshes;
+    /** Accumulated meshes for the target scene */
+    std::vector<aiMesh*> mMeshes;
 
-	/** Temporary material list */
-	std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
+    /** Temporary material list */
+    std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
 
-	/** Temporary camera list */
-	std::vector<aiCamera*> mCameras;
+    /** Temporary camera list */
+    std::vector<aiCamera*> mCameras;
 
-	/** Temporary light list */
-	std::vector<aiLight*> mLights;
+    /** Temporary light list */
+    std::vector<aiLight*> mLights;
 
-	/** Temporary texture list */
-	std::vector<aiTexture*> mTextures;
+    /** Temporary texture list */
+    std::vector<aiTexture*> mTextures;
 
-	/** Accumulated animations for the target scene */
-	std::vector<aiAnimation*> mAnims;
+    /** Accumulated animations for the target scene */
+    std::vector<aiAnimation*> mAnims;
 
-	bool noSkeletonMesh;
-	bool ignoreUpDirection;
-	bool invertTransparency;
+    bool noSkeletonMesh;
+    bool ignoreUpDirection;
+    bool invertTransparency;
 
-	/** Used by FindNameForNode() to generate unique node names */
-	unsigned int mNodeNameCounter;
+    /** Used by FindNameForNode() to generate unique node names */
+    unsigned int mNodeNameCounter;
 };
 
 } // end of namespace Assimp

File diff suppressed because it is too large
+ 1289 - 1289
code/ColladaParser.cpp


+ 190 - 190
code/ColladaParser.h

@@ -61,279 +61,279 @@ namespace Assimp
 */
 class ColladaParser
 {
-	friend class ColladaLoader;
+    friend class ColladaLoader;
 
 protected:
-	/** Constructor from XML file */
-	ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
+    /** Constructor from XML file */
+    ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
 
-	/** Destructor */
-	~ColladaParser();
+    /** Destructor */
+    ~ColladaParser();
 
-	/** Reads the contents of the file */
-	void ReadContents();
+    /** Reads the contents of the file */
+    void ReadContents();
 
-	/** Reads the structure of the file */
-	void ReadStructure();
+    /** Reads the structure of the file */
+    void ReadStructure();
 
-	/** Reads asset informations such as coordinate system informations and legal blah */
-	void ReadAssetInfo();
+    /** Reads asset informations such as coordinate system informations and legal blah */
+    void ReadAssetInfo();
 
-	/** Reads the animation library */
-	void ReadAnimationLibrary();
+    /** Reads the animation library */
+    void ReadAnimationLibrary();
 
-	/** Reads an animation into the given parent structure */
-	void ReadAnimation( Collada::Animation* pParent);
+    /** Reads an animation into the given parent structure */
+    void ReadAnimation( Collada::Animation* pParent);
 
-	/** Reads an animation sampler into the given anim channel */
-	void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
+    /** Reads an animation sampler into the given anim channel */
+    void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
 
-	/** Reads the skeleton controller library */
-	void ReadControllerLibrary();
+    /** Reads the skeleton controller library */
+    void ReadControllerLibrary();
 
-	/** Reads a controller into the given mesh structure */
-	void ReadController( Collada::Controller& pController);
+    /** Reads a controller into the given mesh structure */
+    void ReadController( Collada::Controller& pController);
 
-	/** Reads the joint definitions for the given controller */
-	void ReadControllerJoints( Collada::Controller& pController);
+    /** Reads the joint definitions for the given controller */
+    void ReadControllerJoints( Collada::Controller& pController);
 
-	/** Reads the joint weights for the given controller */
-	void ReadControllerWeights( Collada::Controller& pController);
+    /** Reads the joint weights for the given controller */
+    void ReadControllerWeights( Collada::Controller& pController);
 
-	/** Reads the image library contents */
-	void ReadImageLibrary();
+    /** Reads the image library contents */
+    void ReadImageLibrary();
 
-	/** Reads an image entry into the given image */
-	void ReadImage( Collada::Image& pImage);
+    /** Reads an image entry into the given image */
+    void ReadImage( Collada::Image& pImage);
 
-	/** Reads the material library */
-	void ReadMaterialLibrary();
+    /** Reads the material library */
+    void ReadMaterialLibrary();
 
-	/** Reads a material entry into the given material */
-	void ReadMaterial( Collada::Material& pMaterial);
+    /** Reads a material entry into the given material */
+    void ReadMaterial( Collada::Material& pMaterial);
 
-	/** Reads the camera library */
-	void ReadCameraLibrary();
+    /** Reads the camera library */
+    void ReadCameraLibrary();
 
-	/** Reads a camera entry into the given camera */
-	void ReadCamera( Collada::Camera& pCamera);
+    /** Reads a camera entry into the given camera */
+    void ReadCamera( Collada::Camera& pCamera);
 
-	/** Reads the light library */
-	void ReadLightLibrary();
+    /** Reads the light library */
+    void ReadLightLibrary();
 
-	/** Reads a light entry into the given light */
-	void ReadLight( Collada::Light& pLight);
+    /** Reads a light entry into the given light */
+    void ReadLight( Collada::Light& pLight);
 
-	/** Reads the effect library */
-	void ReadEffectLibrary();
+    /** Reads the effect library */
+    void ReadEffectLibrary();
 
-	/** Reads an effect entry into the given effect*/
-	void ReadEffect( Collada::Effect& pEffect);
+    /** Reads an effect entry into the given effect*/
+    void ReadEffect( Collada::Effect& pEffect);
 
-	/** Reads an COMMON effect profile */
-	void ReadEffectProfileCommon( Collada::Effect& pEffect);
+    /** Reads an COMMON effect profile */
+    void ReadEffectProfileCommon( Collada::Effect& pEffect);
 
-	/** Read sampler properties */
-	void ReadSamplerProperties( Collada::Sampler& pSampler);
+    /** Read sampler properties */
+    void ReadSamplerProperties( Collada::Sampler& pSampler);
 
-	/** Reads an effect entry containing a color or a texture defining that color */
-	void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
+    /** Reads an effect entry containing a color or a texture defining that color */
+    void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
 
-	/** Reads an effect entry containing a float */
-	void ReadEffectFloat( float& pFloat);
+    /** Reads an effect entry containing a float */
+    void ReadEffectFloat( float& pFloat);
 
-	/** Reads an effect parameter specification of any kind */
-	void ReadEffectParam( Collada::EffectParam& pParam);
+    /** Reads an effect parameter specification of any kind */
+    void ReadEffectParam( Collada::EffectParam& pParam);
 
-	/** Reads the geometry library contents */
-	void ReadGeometryLibrary();
+    /** Reads the geometry library contents */
+    void ReadGeometryLibrary();
 
-	/** Reads a geometry from the geometry library. */
-	void ReadGeometry( Collada::Mesh* pMesh);
+    /** Reads a geometry from the geometry library. */
+    void ReadGeometry( Collada::Mesh* pMesh);
 
-	/** Reads a mesh from the geometry library */
-	void ReadMesh( Collada::Mesh* pMesh);
+    /** Reads a mesh from the geometry library */
+    void ReadMesh( Collada::Mesh* pMesh);
 
-	/** Reads a source element - a combination of raw data and an accessor defining
-	 * things that should not be redefinable. Yes, that's another rant.
-	 */
-	void ReadSource();
+    /** Reads a source element - a combination of raw data and an accessor defining
+     * things that should not be redefinable. Yes, that's another rant.
+     */
+    void ReadSource();
 
-	/** Reads a data array holding a number of elements, and stores it in the global library.
-	 * Currently supported are array of floats and arrays of strings.
-	 */
-	void ReadDataArray();
+    /** Reads a data array holding a number of elements, and stores it in the global library.
+     * Currently supported are array of floats and arrays of strings.
+     */
+    void ReadDataArray();
 
-	/** Reads an accessor and stores it in the global library under the given ID -
-	 * accessors use the ID of the parent <source> element
-	 */
-	void ReadAccessor( const std::string& pID);
+    /** Reads an accessor and stores it in the global library under the given ID -
+     * accessors use the ID of the parent <source> element
+     */
+    void ReadAccessor( const std::string& pID);
 
-	/** Reads input declarations of per-vertex mesh data into the given mesh */
-	void ReadVertexData( Collada::Mesh* pMesh);
+    /** Reads input declarations of per-vertex mesh data into the given mesh */
+    void ReadVertexData( Collada::Mesh* pMesh);
 
-	/** Reads input declarations of per-index mesh data into the given mesh */
-	void ReadIndexData( Collada::Mesh* pMesh);
+    /** Reads input declarations of per-index mesh data into the given mesh */
+    void ReadIndexData( Collada::Mesh* pMesh);
 
-	/** Reads a single input channel element and stores it in the given array, if valid */
-	void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
+    /** Reads a single input channel element and stores it in the given array, if valid */
+    void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
 
-	/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
-	size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
-		size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
+    /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
+    size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
+        size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
 
-	/** Copies the data for a single primitive into the mesh, based on the InputChannels */
-	void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
-		Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
-		size_t currentPrimitive, const std::vector<size_t>& indices);
+    /** Copies the data for a single primitive into the mesh, based on the InputChannels */
+    void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
+        Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
+        size_t currentPrimitive, const std::vector<size_t>& indices);
 
-	/** Reads one triangle of a tristrip into the mesh */
-	void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh,
-		std::vector<Collada::InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices);
+    /** Reads one triangle of a tristrip into the mesh */
+    void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh,
+        std::vector<Collada::InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices);
 
-	/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
-	void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
+    /** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
+    void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
 
-	/** Reads the library of node hierarchies and scene parts */
-	void ReadSceneLibrary();
+    /** Reads the library of node hierarchies and scene parts */
+    void ReadSceneLibrary();
 
-	/** Reads a scene node's contents including children and stores it in the given node */
-	void ReadSceneNode( Collada::Node* pNode);
+    /** Reads a scene node's contents including children and stores it in the given node */
+    void ReadSceneNode( Collada::Node* pNode);
 
-	/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
-	void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
+    /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
+    void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
 
-	/** Reads a mesh reference in a node and adds it to the node's mesh list */
-	void ReadNodeGeometry( Collada::Node* pNode);
+    /** Reads a mesh reference in a node and adds it to the node's mesh list */
+    void ReadNodeGeometry( Collada::Node* pNode);
 
-	/** Reads the collada scene */
-	void ReadScene();
+    /** Reads the collada scene */
+    void ReadScene();
 
-	// Processes bind_vertex_input and bind elements
-	void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
+    // Processes bind_vertex_input and bind elements
+    void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
 
 protected:
-	/** Aborts the file reading with an exception */
-	AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
+    /** Aborts the file reading with an exception */
+    AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
 
-	/** Skips all data until the end node of the current element */
-	void SkipElement();
+    /** Skips all data until the end node of the current element */
+    void SkipElement();
 
-	/** Skips all data until the end node of the given element */
-	void SkipElement( const char* pElement);
+    /** Skips all data until the end node of the given element */
+    void SkipElement( const char* pElement);
 
-	/** Compares the current xml element name to the given string and returns true if equal */
-	bool IsElement( const char* pName) const;
+    /** Compares the current xml element name to the given string and returns true if equal */
+    bool IsElement( const char* pName) const;
 
-	/** Tests for the opening tag of the given element, throws an exception if not found */
-	void TestOpening( const char* pName);
+    /** Tests for the opening tag of the given element, throws an exception if not found */
+    void TestOpening( const char* pName);
 
-	/** Tests for the closing tag of the given element, throws an exception if not found */
-	void TestClosing( const char* pName);
+    /** Tests for the closing tag of the given element, throws an exception if not found */
+    void TestClosing( const char* pName);
 
-	/** Checks the present element for the presence of the attribute, returns its index
-	    or throws an exception if not found */
-	int GetAttribute( const char* pAttr) const;
+    /** Checks the present element for the presence of the attribute, returns its index
+        or throws an exception if not found */
+    int GetAttribute( const char* pAttr) const;
 
-	/** Returns the index of the named attribute or -1 if not found. Does not throw,
-	    therefore useful for optional attributes */
-	int TestAttribute( const char* pAttr) const;
+    /** Returns the index of the named attribute or -1 if not found. Does not throw,
+        therefore useful for optional attributes */
+    int TestAttribute( const char* pAttr) const;
 
-	/** Reads the text contents of an element, throws an exception if not given.
-	    Skips leading whitespace. */
-	const char* GetTextContent();
+    /** Reads the text contents of an element, throws an exception if not given.
+        Skips leading whitespace. */
+    const char* GetTextContent();
 
-	/** Reads the text contents of an element, returns NULL if not given.
-	    Skips leading whitespace. */
-	const char* TestTextContent();
+    /** Reads the text contents of an element, returns NULL if not given.
+        Skips leading whitespace. */
+    const char* TestTextContent();
 
-	/** Reads a single bool from current text content */
-	bool ReadBoolFromTextContent();
+    /** Reads a single bool from current text content */
+    bool ReadBoolFromTextContent();
 
-	/** Reads a single float from current text content */
-	float ReadFloatFromTextContent();
+    /** Reads a single float from current text content */
+    float ReadFloatFromTextContent();
 
-	/** Calculates the resulting transformation from all the given transform steps */
-	aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
+    /** Calculates the resulting transformation from all the given transform steps */
+    aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
 
-	/** Determines the input data type for the given semantic string */
-	Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
+    /** Determines the input data type for the given semantic string */
+    Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
 
-	/** Finds the item in the given library by its reference, throws if not found */
-	template <typename Type> const Type& ResolveLibraryReference(
-		const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
+    /** Finds the item in the given library by its reference, throws if not found */
+    template <typename Type> const Type& ResolveLibraryReference(
+        const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
 
 protected:
-	/** Filename, for a verbose error message */
-	std::string mFileName;
+    /** Filename, for a verbose error message */
+    std::string mFileName;
 
-	/** XML reader, member for everyday use */
-	irr::io::IrrXMLReader* mReader;
+    /** XML reader, member for everyday use */
+    irr::io::IrrXMLReader* mReader;
 
-	/** All data arrays found in the file by ID. Might be referred to by actually
-	    everyone. Collada, you are a steaming pile of indirection. */
-	typedef std::map<std::string, Collada::Data> DataLibrary;
-	DataLibrary mDataLibrary;
+    /** All data arrays found in the file by ID. Might be referred to by actually
+        everyone. Collada, you are a steaming pile of indirection. */
+    typedef std::map<std::string, Collada::Data> DataLibrary;
+    DataLibrary mDataLibrary;
 
-	/** Same for accessors which define how the data in a data array is accessed. */
-	typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
-	AccessorLibrary mAccessorLibrary;
+    /** Same for accessors which define how the data in a data array is accessed. */
+    typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
+    AccessorLibrary mAccessorLibrary;
 
-	/** Mesh library: mesh by ID */
-	typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
-	MeshLibrary mMeshLibrary;
+    /** Mesh library: mesh by ID */
+    typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
+    MeshLibrary mMeshLibrary;
 
-	/** node library: root node of the hierarchy part by ID */
-	typedef std::map<std::string, Collada::Node*> NodeLibrary;
-	NodeLibrary mNodeLibrary;
+    /** node library: root node of the hierarchy part by ID */
+    typedef std::map<std::string, Collada::Node*> NodeLibrary;
+    NodeLibrary mNodeLibrary;
 
-	/** Image library: stores texture properties by ID */
-	typedef std::map<std::string, Collada::Image> ImageLibrary;
-	ImageLibrary mImageLibrary;
+    /** Image library: stores texture properties by ID */
+    typedef std::map<std::string, Collada::Image> ImageLibrary;
+    ImageLibrary mImageLibrary;
 
-	/** Effect library: surface attributes by ID */
-	typedef std::map<std::string, Collada::Effect> EffectLibrary;
-	EffectLibrary mEffectLibrary;
+    /** Effect library: surface attributes by ID */
+    typedef std::map<std::string, Collada::Effect> EffectLibrary;
+    EffectLibrary mEffectLibrary;
 
-	/** Material library: surface material by ID */
-	typedef std::map<std::string, Collada::Material> MaterialLibrary;
-	MaterialLibrary mMaterialLibrary;
+    /** Material library: surface material by ID */
+    typedef std::map<std::string, Collada::Material> MaterialLibrary;
+    MaterialLibrary mMaterialLibrary;
 
-	/** Light library: surface light by ID */
-	typedef std::map<std::string, Collada::Light> LightLibrary;
-	LightLibrary mLightLibrary;
+    /** Light library: surface light by ID */
+    typedef std::map<std::string, Collada::Light> LightLibrary;
+    LightLibrary mLightLibrary;
 
-	/** Camera library: surface material by ID */
-	typedef std::map<std::string, Collada::Camera> CameraLibrary;
-	CameraLibrary mCameraLibrary;
+    /** Camera library: surface material by ID */
+    typedef std::map<std::string, Collada::Camera> CameraLibrary;
+    CameraLibrary mCameraLibrary;
 
-	/** Controller library: joint controllers by ID */
-	typedef std::map<std::string, Collada::Controller> ControllerLibrary;
-	ControllerLibrary mControllerLibrary;
+    /** Controller library: joint controllers by ID */
+    typedef std::map<std::string, Collada::Controller> ControllerLibrary;
+    ControllerLibrary mControllerLibrary;
 
-	/** Pointer to the root node. Don't delete, it just points to one of
-	    the nodes in the node library. */
-	Collada::Node* mRootNode;
+    /** Pointer to the root node. Don't delete, it just points to one of
+        the nodes in the node library. */
+    Collada::Node* mRootNode;
 
-	/** Root animation container */
-	Collada::Animation mAnims;
+    /** Root animation container */
+    Collada::Animation mAnims;
 
-	/** Size unit: how large compared to a meter */
-	float mUnitSize;
+    /** Size unit: how large compared to a meter */
+    float mUnitSize;
 
-	/** Which is the up vector */
-	enum { UP_X, UP_Y, UP_Z } mUpDirection;
+    /** Which is the up vector */
+    enum { UP_X, UP_Y, UP_Z } mUpDirection;
 
-	/** Collada file format version */
-	Collada::FormatVersion mFormat;
+    /** Collada file format version */
+    Collada::FormatVersion mFormat;
 };
 
 // ------------------------------------------------------------------------------------------------
 // Check for element match
 inline bool ColladaParser::IsElement( const char* pName) const
 {
-	ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
-	return ::strcmp( mReader->getNodeName(), pName) == 0;
+    ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
+    return ::strcmp( mReader->getNodeName(), pName) == 0;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -341,10 +341,10 @@ inline bool ColladaParser::IsElement( const char* pName) const
 template <typename Type>
 const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
 {
-	typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
-	if( it == pLibrary.end())
-		ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
-	return it->second;
+    typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
+    if( it == pLibrary.end())
+        ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
+    return it->second;
 }
 
 } // end of namespace Assimp

+ 386 - 386
code/ComputeUVMappingProcess.cpp

@@ -49,42 +49,42 @@ using namespace Assimp;
 
 namespace {
 
-	const static aiVector3D base_axis_y(0.f,1.f,0.f);
-	const static aiVector3D base_axis_x(1.f,0.f,0.f);
-	const static aiVector3D base_axis_z(0.f,0.f,1.f);
-	const static float angle_epsilon = 0.95f;
+    const static aiVector3D base_axis_y(0.f,1.f,0.f);
+    const static aiVector3D base_axis_x(1.f,0.f,0.f);
+    const static aiVector3D base_axis_z(0.f,0.f,1.f);
+    const static float angle_epsilon = 0.95f;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 ComputeUVMappingProcess::ComputeUVMappingProcess()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 ComputeUVMappingProcess::~ComputeUVMappingProcess()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const
 {
-	return	(pFlags & aiProcess_GenUVCoords) != 0;
+    return  (pFlags & aiProcess_GenUVCoords) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Check whether a ray intersects a plane and find the intersection point
 inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
-	const aiVector3D& planeNormal, aiVector3D& pos)
+    const aiVector3D& planeNormal, aiVector3D& pos)
 {
-	const float b = planeNormal * (planePos - ray.pos);
-	float h = ray.dir * planeNormal;
+    const float b = planeNormal * (planePos - ray.pos);
+    float h = ray.dir * planeNormal;
     if ((h < 10e-5f && h > -10e-5f) || (h = b/h) < 0)
-		return false;
+        return false;
 
     pos = ray.pos + (ray.dir * h);
     return true;
@@ -94,411 +94,411 @@ inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
 // Find the first empty UV channel in a mesh
 inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
 {
-	for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
-		if (!mesh->mTextureCoords[m])return m;
+    for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
+        if (!mesh->mTextureCoords[m])return m;
 
-	DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found");
-	return UINT_MAX;
+    DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found");
+    return UINT_MAX;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Try to remove UV seams
 void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
 {
-	// TODO: just a very rough algorithm. I think it could be done
-	// much easier, but I don't know how and am currently too tired to
-	// to think about a better solution.
-
-	const static float LOWER_LIMIT = 0.1f;
-	const static float UPPER_LIMIT = 0.9f;
-
-	const static float LOWER_EPSILON = 10e-3f;
-	const static float UPPER_EPSILON = 1.f-10e-3f;
-
-	for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
-	{
-		const aiFace& face = mesh->mFaces[fidx];
-		if (face.mNumIndices < 3) continue; // triangles and polygons only, please
-
-		unsigned int small = face.mNumIndices, large = small;
-		bool zero = false, one = false, round_to_zero = false;
-
-		// Check whether this face lies on a UV seam. We can just guess,
-		// but the assumption that a face with at least one very small
-		// on the one side and one very large U coord on the other side
-		// lies on a UV seam should work for most cases.
-		for (unsigned int n = 0; n < face.mNumIndices;++n)
-		{
-			if (out[face.mIndices[n]].x < LOWER_LIMIT)
-			{
-				small = n;
-
-				// If we have a U value very close to 0 we can't
-				// round the others to 0, too.
-				if (out[face.mIndices[n]].x <= LOWER_EPSILON)
-					zero = true;
-				else round_to_zero = true;
-			}
-			if (out[face.mIndices[n]].x > UPPER_LIMIT)
-			{
-				large = n;
-
-				// If we have a U value very close to 1 we can't
-				// round the others to 1, too.
-				if (out[face.mIndices[n]].x >= UPPER_EPSILON)
-					one = true;
-			}
-		}
-		if (small != face.mNumIndices && large != face.mNumIndices)
-		{
-			for (unsigned int n = 0; n < face.mNumIndices;++n)
-			{
-				// If the u value is over the upper limit and no other u
-				// value of that face is 0, round it to 0
-				if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
-					out[face.mIndices[n]].x = 0.f;
-
-				// If the u value is below the lower limit and no other u
-				// value of that face is 1, round it to 1
-				else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one)
-					out[face.mIndices[n]].x = 1.f;
-
-				// The face contains both 0 and 1 as UV coords. This can occur
-				// for faces which have an edge that lies directly on the seam.
-				// Due to numerical inaccuracies one U coord becomes 0, the
-				// other 1. But we do still have a third UV coord to determine
-				// to which side we must round to.
-				else if (one && zero)
-				{
-					if (round_to_zero && out[face.mIndices[n]].x >=  UPPER_EPSILON)
-						out[face.mIndices[n]].x = 0.f;
-					else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
-						out[face.mIndices[n]].x = 1.f;
-				}
-			}
-		}
-	}
+    // TODO: just a very rough algorithm. I think it could be done
+    // much easier, but I don't know how and am currently too tired to
+    // to think about a better solution.
+
+    const static float LOWER_LIMIT = 0.1f;
+    const static float UPPER_LIMIT = 0.9f;
+
+    const static float LOWER_EPSILON = 10e-3f;
+    const static float UPPER_EPSILON = 1.f-10e-3f;
+
+    for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
+    {
+        const aiFace& face = mesh->mFaces[fidx];
+        if (face.mNumIndices < 3) continue; // triangles and polygons only, please
+
+        unsigned int small = face.mNumIndices, large = small;
+        bool zero = false, one = false, round_to_zero = false;
+
+        // Check whether this face lies on a UV seam. We can just guess,
+        // but the assumption that a face with at least one very small
+        // on the one side and one very large U coord on the other side
+        // lies on a UV seam should work for most cases.
+        for (unsigned int n = 0; n < face.mNumIndices;++n)
+        {
+            if (out[face.mIndices[n]].x < LOWER_LIMIT)
+            {
+                small = n;
+
+                // If we have a U value very close to 0 we can't
+                // round the others to 0, too.
+                if (out[face.mIndices[n]].x <= LOWER_EPSILON)
+                    zero = true;
+                else round_to_zero = true;
+            }
+            if (out[face.mIndices[n]].x > UPPER_LIMIT)
+            {
+                large = n;
+
+                // If we have a U value very close to 1 we can't
+                // round the others to 1, too.
+                if (out[face.mIndices[n]].x >= UPPER_EPSILON)
+                    one = true;
+            }
+        }
+        if (small != face.mNumIndices && large != face.mNumIndices)
+        {
+            for (unsigned int n = 0; n < face.mNumIndices;++n)
+            {
+                // If the u value is over the upper limit and no other u
+                // value of that face is 0, round it to 0
+                if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
+                    out[face.mIndices[n]].x = 0.f;
+
+                // If the u value is below the lower limit and no other u
+                // value of that face is 1, round it to 1
+                else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one)
+                    out[face.mIndices[n]].x = 1.f;
+
+                // The face contains both 0 and 1 as UV coords. This can occur
+                // for faces which have an edge that lies directly on the seam.
+                // Due to numerical inaccuracies one U coord becomes 0, the
+                // other 1. But we do still have a third UV coord to determine
+                // to which side we must round to.
+                else if (one && zero)
+                {
+                    if (round_to_zero && out[face.mIndices[n]].x >=  UPPER_EPSILON)
+                        out[face.mIndices[n]].x = 0.f;
+                    else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
+                        out[face.mIndices[n]].x = 1.f;
+                }
+            }
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
 {
-	aiVector3D center, min, max;
-	FindMeshCenter(mesh, center, min, max);
-
-	// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
-	// currently the mapping axis will always be one of x,y,z, except if the
-	// PretransformVertices step is used (it transforms the meshes into worldspace,
-	// thus changing the mapping axis)
-	if (axis * base_axis_x >= angle_epsilon)	{
-
-		// For each point get a normalized projection vector in the sphere,
-		// get its longitude and latitude and map them to their respective
-		// UV axes. Problems occur around the poles ... unsolvable.
-		//
-		// The spherical coordinate system looks like this:
-		// x = cos(lon)*cos(lat)
-		// y = sin(lon)*cos(lat)
-		// z = sin(lat)
-		//
-		// Thus we can derive:
-		// lat  = arcsin (z)
-		// lon  = arctan (y/x)
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
-			out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-				(std::asin  (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
-		}
-	}
-	else if (axis * base_axis_y >= angle_epsilon)	{
-		// ... just the same again
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
-			out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-				(std::asin  (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
-		}
-	}
-	else if (axis * base_axis_z >= angle_epsilon)	{
-		// ... just the same again
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
-			out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-				(std::asin  (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
-		}
-	}
-	// slower code path in case the mapping axis is not one of the coordinate system axes
-	else	{
-		aiMatrix4x4 mTrafo;
-		aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
-
-		// again the same, except we're applying a transformation now
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
-			out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
-				(asin  (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
-		}
-	}
-
-
-	// Now find and remove UV seams. A seam occurs if a face has a tcoord
-	// close to zero on the one side, and a tcoord close to one on the
-	// other side.
-	RemoveUVSeams(mesh,out);
+    aiVector3D center, min, max;
+    FindMeshCenter(mesh, center, min, max);
+
+    // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
+    // currently the mapping axis will always be one of x,y,z, except if the
+    // PretransformVertices step is used (it transforms the meshes into worldspace,
+    // thus changing the mapping axis)
+    if (axis * base_axis_x >= angle_epsilon)    {
+
+        // For each point get a normalized projection vector in the sphere,
+        // get its longitude and latitude and map them to their respective
+        // UV axes. Problems occur around the poles ... unsolvable.
+        //
+        // The spherical coordinate system looks like this:
+        // x = cos(lon)*cos(lat)
+        // y = sin(lon)*cos(lat)
+        // z = sin(lat)
+        //
+        // Thus we can derive:
+        // lat  = arcsin (z)
+        // lon  = arctan (y/x)
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
+            out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
+                (std::asin  (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
+        }
+    }
+    else if (axis * base_axis_y >= angle_epsilon)   {
+        // ... just the same again
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
+            out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
+                (std::asin  (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
+        }
+    }
+    else if (axis * base_axis_z >= angle_epsilon)   {
+        // ... just the same again
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
+            out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
+                (std::asin  (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
+        }
+    }
+    // slower code path in case the mapping axis is not one of the coordinate system axes
+    else    {
+        aiMatrix4x4 mTrafo;
+        aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
+
+        // again the same, except we're applying a transformation now
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
+            out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
+                (asin  (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
+        }
+    }
+
+
+    // Now find and remove UV seams. A seam occurs if a face has a tcoord
+    // close to zero on the one side, and a tcoord close to one on the
+    // other side.
+    RemoveUVSeams(mesh,out);
 }
 
 // ------------------------------------------------------------------------------------------------
 void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
 {
-	aiVector3D center, min, max;
-
-	// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
-	// currently the mapping axis will always be one of x,y,z, except if the
-	// PretransformVertices step is used (it transforms the meshes into worldspace,
-	// thus changing the mapping axis)
-	if (axis * base_axis_x >= angle_epsilon)	{
-		FindMeshCenter(mesh, center, min, max);
-		const float diff = max.x - min.x;
-
-		// If the main axis is 'z', the z coordinate of a point 'p' is mapped
-		// directly to the texture V axis. The other axis is derived from
-		// the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
-		// 'c' is the center point of the mesh.
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D& pos = mesh->mVertices[pnt];
-			aiVector3D& uv  = out[pnt];
-
-			uv.y = (pos.x - min.x) / diff;
-			uv.x = (atan2 ( pos.z - center.z, pos.y - center.y) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
-		}
-	}
-	else if (axis * base_axis_y >= angle_epsilon)	{
-		FindMeshCenter(mesh, center, min, max);
-		const float diff = max.y - min.y;
-
-		// just the same ...
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D& pos = mesh->mVertices[pnt];
-			aiVector3D& uv  = out[pnt];
-
-			uv.y = (pos.y - min.y) / diff;
-			uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
-		}
-	}
-	else if (axis * base_axis_z >= angle_epsilon)	{
-		FindMeshCenter(mesh, center, min, max);
-		const float diff = max.z - min.z;
-
-		// just the same ...
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D& pos = mesh->mVertices[pnt];
-			aiVector3D& uv  = out[pnt];
-
-			uv.y = (pos.z - min.z) / diff;
-			uv.x = (atan2 ( pos.y - center.y, pos.x - center.x) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
-		}
-	}
-	// slower code path in case the mapping axis is not one of the coordinate system axes
-	else {
-		aiMatrix4x4 mTrafo;
-		aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
-		FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
-		const float diff = max.y - min.y;
-
-		// again the same, except we're applying a transformation now
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
-			const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
-			aiVector3D& uv  = out[pnt];
-
-			uv.y = (pos.y - min.y) / diff;
-			uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
-		}
-	}
-
-	// Now find and remove UV seams. A seam occurs if a face has a tcoord
-	// close to zero on the one side, and a tcoord close to one on the
-	// other side.
-	RemoveUVSeams(mesh,out);
+    aiVector3D center, min, max;
+
+    // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
+    // currently the mapping axis will always be one of x,y,z, except if the
+    // PretransformVertices step is used (it transforms the meshes into worldspace,
+    // thus changing the mapping axis)
+    if (axis * base_axis_x >= angle_epsilon)    {
+        FindMeshCenter(mesh, center, min, max);
+        const float diff = max.x - min.x;
+
+        // If the main axis is 'z', the z coordinate of a point 'p' is mapped
+        // directly to the texture V axis. The other axis is derived from
+        // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
+        // 'c' is the center point of the mesh.
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D& pos = mesh->mVertices[pnt];
+            aiVector3D& uv  = out[pnt];
+
+            uv.y = (pos.x - min.x) / diff;
+            uv.x = (atan2 ( pos.z - center.z, pos.y - center.y) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
+        }
+    }
+    else if (axis * base_axis_y >= angle_epsilon)   {
+        FindMeshCenter(mesh, center, min, max);
+        const float diff = max.y - min.y;
+
+        // just the same ...
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D& pos = mesh->mVertices[pnt];
+            aiVector3D& uv  = out[pnt];
+
+            uv.y = (pos.y - min.y) / diff;
+            uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
+        }
+    }
+    else if (axis * base_axis_z >= angle_epsilon)   {
+        FindMeshCenter(mesh, center, min, max);
+        const float diff = max.z - min.z;
+
+        // just the same ...
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D& pos = mesh->mVertices[pnt];
+            aiVector3D& uv  = out[pnt];
+
+            uv.y = (pos.z - min.z) / diff;
+            uv.x = (atan2 ( pos.y - center.y, pos.x - center.x) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
+        }
+    }
+    // slower code path in case the mapping axis is not one of the coordinate system axes
+    else {
+        aiMatrix4x4 mTrafo;
+        aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
+        FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
+        const float diff = max.y - min.y;
+
+        // again the same, except we're applying a transformation now
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
+            const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
+            aiVector3D& uv  = out[pnt];
+
+            uv.y = (pos.y - min.y) / diff;
+            uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
+        }
+    }
+
+    // Now find and remove UV seams. A seam occurs if a face has a tcoord
+    // close to zero on the one side, and a tcoord close to one on the
+    // other side.
+    RemoveUVSeams(mesh,out);
 }
 
 // ------------------------------------------------------------------------------------------------
 void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
 {
-	float diffu,diffv;
-	aiVector3D center, min, max;
-
-	// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
-	// currently the mapping axis will always be one of x,y,z, except if the
-	// PretransformVertices step is used (it transforms the meshes into worldspace,
-	// thus changing the mapping axis)
-	if (axis * base_axis_x >= angle_epsilon)	{
-		FindMeshCenter(mesh, center, min, max);
-		diffu = max.z - min.z;
-		diffv = max.y - min.y;
-
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D& pos = mesh->mVertices[pnt];
-			out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.f);
-		}
-	}
-	else if (axis * base_axis_y >= angle_epsilon)	{
-		FindMeshCenter(mesh, center, min, max);
-		diffu = max.x - min.x;
-		diffv = max.z - min.z;
-
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D& pos = mesh->mVertices[pnt];
-			out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
-		}
-	}
-	else if (axis * base_axis_z >= angle_epsilon)	{
-		FindMeshCenter(mesh, center, min, max);
-		diffu = max.y - min.y;
-		diffv = max.z - min.z;
-
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D& pos = mesh->mVertices[pnt];
-			out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.f);
-		}
-	}
-	// slower code path in case the mapping axis is not one of the coordinate system axes
-	else
-	{
-		aiMatrix4x4 mTrafo;
-		aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
-		FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
-		diffu = max.x - min.x;
-		diffv = max.z - min.z;
-
-		// again the same, except we're applying a transformation now
-		for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)	{
-			const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
-			out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
-		}
-	}
-
-	// shouldn't be necessary to remove UV seams ...
+    float diffu,diffv;
+    aiVector3D center, min, max;
+
+    // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
+    // currently the mapping axis will always be one of x,y,z, except if the
+    // PretransformVertices step is used (it transforms the meshes into worldspace,
+    // thus changing the mapping axis)
+    if (axis * base_axis_x >= angle_epsilon)    {
+        FindMeshCenter(mesh, center, min, max);
+        diffu = max.z - min.z;
+        diffv = max.y - min.y;
+
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D& pos = mesh->mVertices[pnt];
+            out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.f);
+        }
+    }
+    else if (axis * base_axis_y >= angle_epsilon)   {
+        FindMeshCenter(mesh, center, min, max);
+        diffu = max.x - min.x;
+        diffv = max.z - min.z;
+
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D& pos = mesh->mVertices[pnt];
+            out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
+        }
+    }
+    else if (axis * base_axis_z >= angle_epsilon)   {
+        FindMeshCenter(mesh, center, min, max);
+        diffu = max.y - min.y;
+        diffv = max.z - min.z;
+
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D& pos = mesh->mVertices[pnt];
+            out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.f);
+        }
+    }
+    // slower code path in case the mapping axis is not one of the coordinate system axes
+    else
+    {
+        aiMatrix4x4 mTrafo;
+        aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
+        FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
+        diffu = max.x - min.x;
+        diffv = max.z - min.z;
+
+        // again the same, except we're applying a transformation now
+        for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)  {
+            const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
+            out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
+        }
+    }
+
+    // shouldn't be necessary to remove UV seams ...
 }
 
 // ------------------------------------------------------------------------------------------------
 void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
 {
-	DefaultLogger::get()->error("Mapping type currently not implemented");
+    DefaultLogger::get()->error("Mapping type currently not implemented");
 }
 
 // ------------------------------------------------------------------------------------------------
 void ComputeUVMappingProcess::Execute( aiScene* pScene)
 {
-	DefaultLogger::get()->debug("GenUVCoordsProcess begin");
-	char buffer[1024];
-
-	if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
-		throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
-
-	std::list<MappingInfo> mappingStack;
-
-	/*  Iterate through all materials and search for non-UV mapped textures
-	 */
-	for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
-	{
-		mappingStack.clear();
-		aiMaterial* mat = pScene->mMaterials[i];
-		for (unsigned int a = 0; a < mat->mNumProperties;++a)
-		{
-			aiMaterialProperty* prop = mat->mProperties[a];
-			if (!::strcmp( prop->mKey.data, "$tex.mapping"))
-			{
-				aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
-				if (aiTextureMapping_UV != mapping)
-				{
-					if (!DefaultLogger::isNullLogger())
-					{
-						sprintf(buffer, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
-							TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
-							MappingTypeToString(mapping));
-
-						DefaultLogger::get()->info(buffer);
-					}
-
-					if (aiTextureMapping_OTHER == mapping)
-						continue;
-
-					MappingInfo info (mapping);
-
-					// Get further properties - currently only the major axis
-					for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
-					{
-						aiMaterialProperty* prop2 = mat->mProperties[a2];
-						if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
-							continue;
-
-						if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis"))	{
-							info.axis = *((aiVector3D*)prop2->mData);
-							break;
-						}
-					}
-
-					unsigned int idx;
-
-					// Check whether we have this mapping mode already
-					std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
-					if (mappingStack.end() != it)
-					{
-						idx = (*it).uv;
-					}
-					else
-					{
-						/*  We have found a non-UV mapped texture. Now
-						*   we need to find all meshes using this material
-						*   that we can compute UV channels for them.
-						*/
-						for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
-						{
-							aiMesh* mesh = pScene->mMeshes[m];
-							unsigned int outIdx = 0;
-							if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
-								!mesh->mNumVertices)
-							{
-								continue;
-							}
-
-							// Allocate output storage
-							aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
-
-							switch (mapping)
-							{
-							case aiTextureMapping_SPHERE:
-								ComputeSphereMapping(mesh,info.axis,p);
-								break;
-							case aiTextureMapping_CYLINDER:
-								ComputeCylinderMapping(mesh,info.axis,p);
-								break;
-							case aiTextureMapping_PLANE:
-								ComputePlaneMapping(mesh,info.axis,p);
-								break;
-							case aiTextureMapping_BOX:
-								ComputeBoxMapping(mesh,p);
-								break;
-							default:
-								ai_assert(false);
-							}
-							if (m && idx != outIdx)
-							{
-								DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to "
-									"this material have equal numbers of UV channels. The UV index stored in  "
-									"the material structure does therefore not apply for all meshes. ");
-							}
-							idx = outIdx;
-						}
-						info.uv = idx;
-						mappingStack.push_back(info);
-					}
-
-					// Update the material property list
-					mapping = aiTextureMapping_UV;
-					((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
-				}
-			}
-		}
-	}
-	DefaultLogger::get()->debug("GenUVCoordsProcess finished");
+    DefaultLogger::get()->debug("GenUVCoordsProcess begin");
+    char buffer[1024];
+
+    if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
+        throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
+
+    std::list<MappingInfo> mappingStack;
+
+    /*  Iterate through all materials and search for non-UV mapped textures
+     */
+    for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
+    {
+        mappingStack.clear();
+        aiMaterial* mat = pScene->mMaterials[i];
+        for (unsigned int a = 0; a < mat->mNumProperties;++a)
+        {
+            aiMaterialProperty* prop = mat->mProperties[a];
+            if (!::strcmp( prop->mKey.data, "$tex.mapping"))
+            {
+                aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
+                if (aiTextureMapping_UV != mapping)
+                {
+                    if (!DefaultLogger::isNullLogger())
+                    {
+                        sprintf(buffer, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
+                            TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
+                            MappingTypeToString(mapping));
+
+                        DefaultLogger::get()->info(buffer);
+                    }
+
+                    if (aiTextureMapping_OTHER == mapping)
+                        continue;
+
+                    MappingInfo info (mapping);
+
+                    // Get further properties - currently only the major axis
+                    for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
+                    {
+                        aiMaterialProperty* prop2 = mat->mProperties[a2];
+                        if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
+                            continue;
+
+                        if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis"))  {
+                            info.axis = *((aiVector3D*)prop2->mData);
+                            break;
+                        }
+                    }
+
+                    unsigned int idx;
+
+                    // Check whether we have this mapping mode already
+                    std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
+                    if (mappingStack.end() != it)
+                    {
+                        idx = (*it).uv;
+                    }
+                    else
+                    {
+                        /*  We have found a non-UV mapped texture. Now
+                        *   we need to find all meshes using this material
+                        *   that we can compute UV channels for them.
+                        */
+                        for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
+                        {
+                            aiMesh* mesh = pScene->mMeshes[m];
+                            unsigned int outIdx = 0;
+                            if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
+                                !mesh->mNumVertices)
+                            {
+                                continue;
+                            }
+
+                            // Allocate output storage
+                            aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
+
+                            switch (mapping)
+                            {
+                            case aiTextureMapping_SPHERE:
+                                ComputeSphereMapping(mesh,info.axis,p);
+                                break;
+                            case aiTextureMapping_CYLINDER:
+                                ComputeCylinderMapping(mesh,info.axis,p);
+                                break;
+                            case aiTextureMapping_PLANE:
+                                ComputePlaneMapping(mesh,info.axis,p);
+                                break;
+                            case aiTextureMapping_BOX:
+                                ComputeBoxMapping(mesh,p);
+                                break;
+                            default:
+                                ai_assert(false);
+                            }
+                            if (m && idx != outIdx)
+                            {
+                                DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to "
+                                    "this material have equal numbers of UV channels. The UV index stored in  "
+                                    "the material structure does therefore not apply for all meshes. ");
+                            }
+                            idx = outIdx;
+                        }
+                        info.uv = idx;
+                        mappingStack.push_back(info);
+                    }
+
+                    // Update the material property list
+                    mapping = aiTextureMapping_UV;
+                    ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
+                }
+            }
+        }
+    }
+    DefaultLogger::get()->debug("GenUVCoordsProcess finished");
 }

+ 72 - 72
code/ComputeUVMappingProcess.h

@@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 class ComputeUVMappingTest;
 
 namespace Assimp
-	{
+    {
 
 // ---------------------------------------------------------------------------
 /** ComputeUVMappingProcess - converts special mappings, such as spherical,
@@ -60,86 +60,86 @@ namespace Assimp
 class ComputeUVMappingProcess : public BaseProcess
 {
 public:
-	ComputeUVMappingProcess();
-	~ComputeUVMappingProcess();
+    ComputeUVMappingProcess();
+    ~ComputeUVMappingProcess();
 
 public:
 
-	// -------------------------------------------------------------------
-	/** Returns whether the processing step is present in the given flag field.
-	* @param pFlags The processing flags the importer was called with. A bitwise
-	*   combination of #aiPostProcessSteps.
-	* @return true if the process is present in this flag fields, false if not.
-	*/
-	bool IsActive( unsigned int pFlags) const;
-
-	// -------------------------------------------------------------------
-	/** Executes the post processing step on the given imported data.
-	* At the moment a process is not supposed to fail.
-	* @param pScene The imported data to work at.
-	*/
-	void Execute( aiScene* pScene);
+    // -------------------------------------------------------------------
+    /** Returns whether the processing step is present in the given flag field.
+    * @param pFlags The processing flags the importer was called with. A bitwise
+    *   combination of #aiPostProcessSteps.
+    * @return true if the process is present in this flag fields, false if not.
+    */
+    bool IsActive( unsigned int pFlags) const;
+
+    // -------------------------------------------------------------------
+    /** Executes the post processing step on the given imported data.
+    * At the moment a process is not supposed to fail.
+    * @param pScene The imported data to work at.
+    */
+    void Execute( aiScene* pScene);
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Computes spherical UV coordinates for a mesh
-	 *
-	 *  @param mesh Mesh to be processed
-	 *  @param axis Main axis
-	 *  @param out Receives output UV coordinates
-	*/
-	void ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis,
-		aiVector3D* out);
-
-	// -------------------------------------------------------------------
-	/** Computes cylindrical UV coordinates for a mesh
-	 *
-	 *  @param mesh Mesh to be processed
-	 *  @param axis Main axis
-	 *  @param out Receives output UV coordinates
-	*/
-	void ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis,
-		aiVector3D* out);
-
-	// -------------------------------------------------------------------
-	/** Computes planar UV coordinates for a mesh
-	 *
-	 *  @param mesh Mesh to be processed
-	 *  @param axis Main axis
-	 *  @param out Receives output UV coordinates
-	*/
-	void ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis,
-		aiVector3D* out);
-
-	// -------------------------------------------------------------------
-	/** Computes cubic UV coordinates for a mesh
-	 *
-	 *  @param mesh Mesh to be processed
-	 *  @param out Receives output UV coordinates
-	*/
-	void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out);
+    // -------------------------------------------------------------------
+    /** Computes spherical UV coordinates for a mesh
+     *
+     *  @param mesh Mesh to be processed
+     *  @param axis Main axis
+     *  @param out Receives output UV coordinates
+    */
+    void ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis,
+        aiVector3D* out);
+
+    // -------------------------------------------------------------------
+    /** Computes cylindrical UV coordinates for a mesh
+     *
+     *  @param mesh Mesh to be processed
+     *  @param axis Main axis
+     *  @param out Receives output UV coordinates
+    */
+    void ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis,
+        aiVector3D* out);
+
+    // -------------------------------------------------------------------
+    /** Computes planar UV coordinates for a mesh
+     *
+     *  @param mesh Mesh to be processed
+     *  @param axis Main axis
+     *  @param out Receives output UV coordinates
+    */
+    void ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis,
+        aiVector3D* out);
+
+    // -------------------------------------------------------------------
+    /** Computes cubic UV coordinates for a mesh
+     *
+     *  @param mesh Mesh to be processed
+     *  @param out Receives output UV coordinates
+    */
+    void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out);
 
 private:
 
-	// temporary structure to describe a mapping
-	struct MappingInfo
-	{
-		MappingInfo(aiTextureMapping _type)
-			: type	(_type)
-			, axis	(0.f,1.f,0.f)
-			, uv	(0u)
-		{}
-
-		aiTextureMapping type;
-		aiVector3D axis;
-		unsigned int uv;
-
-		bool operator== (const MappingInfo& other)
-		{
-			return type == other.type && axis == other.axis;
-		}
-	};
+    // temporary structure to describe a mapping
+    struct MappingInfo
+    {
+        MappingInfo(aiTextureMapping _type)
+            : type  (_type)
+            , axis  (0.f,1.f,0.f)
+            , uv    (0u)
+        {}
+
+        aiTextureMapping type;
+        aiVector3D axis;
+        unsigned int uv;
+
+        bool operator== (const MappingInfo& other)
+        {
+            return type == other.type && axis == other.axis;
+        }
+    };
 };
 
 } // end of namespace Assimp

+ 135 - 135
code/ConvertToLHProcess.cpp

@@ -74,59 +74,59 @@ MakeLeftHandedProcess::~MakeLeftHandedProcess() {
 // Returns whether the processing step is present in the given flag field.
 bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const
 {
-	return 0 != (pFlags & aiProcess_MakeLeftHanded);
+    return 0 != (pFlags & aiProcess_MakeLeftHanded);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 void MakeLeftHandedProcess::Execute( aiScene* pScene)
 {
-	// Check for an existent root node to proceed
-	ai_assert(pScene->mRootNode != NULL);
-	DefaultLogger::get()->debug("MakeLeftHandedProcess begin");
-
-	// recursively convert all the nodes
-	ProcessNode( pScene->mRootNode, aiMatrix4x4());
-
-	// process the meshes accordingly
-	for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
-		ProcessMesh( pScene->mMeshes[a]);
-
-	// process the materials accordingly
-	for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
-		ProcessMaterial( pScene->mMaterials[a]);
-
-	// transform all animation channels as well
-	for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
-	{
-		aiAnimation* anim = pScene->mAnimations[a];
-		for( unsigned int b = 0; b < anim->mNumChannels; b++)
-		{
-			aiNodeAnim* nodeAnim = anim->mChannels[b];
-			ProcessAnimation( nodeAnim);
-		}
-	}
-	DefaultLogger::get()->debug("MakeLeftHandedProcess finished");
+    // Check for an existent root node to proceed
+    ai_assert(pScene->mRootNode != NULL);
+    DefaultLogger::get()->debug("MakeLeftHandedProcess begin");
+
+    // recursively convert all the nodes
+    ProcessNode( pScene->mRootNode, aiMatrix4x4());
+
+    // process the meshes accordingly
+    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
+        ProcessMesh( pScene->mMeshes[a]);
+
+    // process the materials accordingly
+    for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
+        ProcessMaterial( pScene->mMaterials[a]);
+
+    // transform all animation channels as well
+    for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
+    {
+        aiAnimation* anim = pScene->mAnimations[a];
+        for( unsigned int b = 0; b < anim->mNumChannels; b++)
+        {
+            aiNodeAnim* nodeAnim = anim->mChannels[b];
+            ProcessAnimation( nodeAnim);
+        }
+    }
+    DefaultLogger::get()->debug("MakeLeftHandedProcess finished");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Recursively converts a node, all of its children and all of its meshes
 void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation)
 {
-	// mirror all base vectors at the local Z axis
-	pNode->mTransformation.c1 = -pNode->mTransformation.c1;
-	pNode->mTransformation.c2 = -pNode->mTransformation.c2;
-	pNode->mTransformation.c3 = -pNode->mTransformation.c3;
-	pNode->mTransformation.c4 = -pNode->mTransformation.c4;
-
-	// now invert the Z axis again to keep the matrix determinant positive.
-	// The local meshes will be inverted accordingly so that the result should look just fine again.
-	pNode->mTransformation.a3 = -pNode->mTransformation.a3;
-	pNode->mTransformation.b3 = -pNode->mTransformation.b3;
-	pNode->mTransformation.c3 = -pNode->mTransformation.c3;
-	pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
-
-	// continue for all children
+    // mirror all base vectors at the local Z axis
+    pNode->mTransformation.c1 = -pNode->mTransformation.c1;
+    pNode->mTransformation.c2 = -pNode->mTransformation.c2;
+    pNode->mTransformation.c3 = -pNode->mTransformation.c3;
+    pNode->mTransformation.c4 = -pNode->mTransformation.c4;
+
+    // now invert the Z axis again to keep the matrix determinant positive.
+    // The local meshes will be inverted accordingly so that the result should look just fine again.
+    pNode->mTransformation.a3 = -pNode->mTransformation.a3;
+    pNode->mTransformation.b3 = -pNode->mTransformation.b3;
+    pNode->mTransformation.c3 = -pNode->mTransformation.c3;
+    pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
+
+    // continue for all children
     for( size_t a = 0; a < pNode->mNumChildren; ++a ) {
         ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation );
     }
@@ -136,78 +136,78 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
 // Converts a single mesh to left handed coordinates.
 void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
 {
-	// mirror positions, normals and stuff along the Z axis
-	for( size_t a = 0; a < pMesh->mNumVertices; ++a)
-	{
-		pMesh->mVertices[a].z *= -1.0f;
-		if( pMesh->HasNormals())
-			pMesh->mNormals[a].z *= -1.0f;
-		if( pMesh->HasTangentsAndBitangents())
-		{
-			pMesh->mTangents[a].z *= -1.0f;
-			pMesh->mBitangents[a].z *= -1.0f;
-		}
-	}
-
-	// mirror offset matrices of all bones
-	for( size_t a = 0; a < pMesh->mNumBones; ++a)
-	{
-		aiBone* bone = pMesh->mBones[a];
-		bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
-		bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
-		bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
-		bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
-		bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
-		bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
-	}
-
-	// mirror bitangents as well as they're derived from the texture coords
-	if( pMesh->HasTangentsAndBitangents())
-	{
-		for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
-			pMesh->mBitangents[a] *= -1.0f;
-	}
+    // mirror positions, normals and stuff along the Z axis
+    for( size_t a = 0; a < pMesh->mNumVertices; ++a)
+    {
+        pMesh->mVertices[a].z *= -1.0f;
+        if( pMesh->HasNormals())
+            pMesh->mNormals[a].z *= -1.0f;
+        if( pMesh->HasTangentsAndBitangents())
+        {
+            pMesh->mTangents[a].z *= -1.0f;
+            pMesh->mBitangents[a].z *= -1.0f;
+        }
+    }
+
+    // mirror offset matrices of all bones
+    for( size_t a = 0; a < pMesh->mNumBones; ++a)
+    {
+        aiBone* bone = pMesh->mBones[a];
+        bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
+        bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
+        bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
+        bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
+        bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
+        bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
+    }
+
+    // mirror bitangents as well as they're derived from the texture coords
+    if( pMesh->HasTangentsAndBitangents())
+    {
+        for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
+            pMesh->mBitangents[a] *= -1.0f;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single material to left handed coordinates.
 void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
 {
-	aiMaterial* mat = (aiMaterial*)_mat;
-	for (unsigned int a = 0; a < mat->mNumProperties;++a)	{
-		aiMaterialProperty* prop = mat->mProperties[a];
-
-		// Mapping axis for UV mappings?
-		if (!::strcmp( prop->mKey.data, "$tex.mapaxis"))	{
-			ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
-			aiVector3D* pff = (aiVector3D*)prop->mData;
-
-			pff->z *= -1.f;
-		}
-	}
+    aiMaterial* mat = (aiMaterial*)_mat;
+    for (unsigned int a = 0; a < mat->mNumProperties;++a)   {
+        aiMaterialProperty* prop = mat->mProperties[a];
+
+        // Mapping axis for UV mappings?
+        if (!::strcmp( prop->mKey.data, "$tex.mapaxis"))    {
+            ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
+            aiVector3D* pff = (aiVector3D*)prop->mData;
+
+            pff->z *= -1.f;
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Converts the given animation to LH coordinates.
 void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim)
 {
-	// position keys
-	for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
-		pAnim->mPositionKeys[a].mValue.z *= -1.0f;
-
-	// rotation keys
-	for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
-	{
-		/* That's the safe version, but the float errors add up. So we try the short version instead
-		aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
-		rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
-		rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
-		aiQuaternion rotquat( rotmat);
-		pAnim->mRotationKeys[a].mValue = rotquat;
-		*/
-		pAnim->mRotationKeys[a].mValue.x *= -1.0f;
-		pAnim->mRotationKeys[a].mValue.y *= -1.0f;
-	}
+    // position keys
+    for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
+        pAnim->mPositionKeys[a].mValue.z *= -1.0f;
+
+    // rotation keys
+    for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
+    {
+        /* That's the safe version, but the float errors add up. So we try the short version instead
+        aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
+        rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
+        rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
+        aiQuaternion rotquat( rotmat);
+        pAnim->mRotationKeys[a].mValue = rotquat;
+        */
+        pAnim->mRotationKeys[a].mValue.x *= -1.0f;
+        pAnim->mRotationKeys[a].mValue.y *= -1.0f;
+    }
 }
 
 #endif // !!  ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
@@ -228,52 +228,52 @@ FlipUVsProcess::~FlipUVsProcess()
 // Returns whether the processing step is present in the given flag field.
 bool FlipUVsProcess::IsActive( unsigned int pFlags) const
 {
-	return 0 != (pFlags & aiProcess_FlipUVs);
+    return 0 != (pFlags & aiProcess_FlipUVs);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 void FlipUVsProcess::Execute( aiScene* pScene)
 {
-	DefaultLogger::get()->debug("FlipUVsProcess begin");
-	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
-		ProcessMesh(pScene->mMeshes[i]);
+    DefaultLogger::get()->debug("FlipUVsProcess begin");
+    for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
+        ProcessMesh(pScene->mMeshes[i]);
 
-	for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
-		ProcessMaterial(pScene->mMaterials[i]);
-	DefaultLogger::get()->debug("FlipUVsProcess finished");
+    for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
+        ProcessMaterial(pScene->mMaterials[i]);
+    DefaultLogger::get()->debug("FlipUVsProcess finished");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single material
 void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
 {
-	aiMaterial* mat = (aiMaterial*)_mat;
-	for (unsigned int a = 0; a < mat->mNumProperties;++a)	{
-		aiMaterialProperty* prop = mat->mProperties[a];
+    aiMaterial* mat = (aiMaterial*)_mat;
+    for (unsigned int a = 0; a < mat->mNumProperties;++a)   {
+        aiMaterialProperty* prop = mat->mProperties[a];
         if( !prop ) {
             DefaultLogger::get()->debug( "Property is null" );
             continue;
         }
 
-		// UV transformation key?
-		if (!::strcmp( prop->mKey.data, "$tex.uvtrafo"))	{
-			ai_assert( prop->mDataLength >= sizeof(aiUVTransform));  /* something is wrong with the validation if we end up here */
-			aiUVTransform* uv = (aiUVTransform*)prop->mData;
+        // UV transformation key?
+        if (!::strcmp( prop->mKey.data, "$tex.uvtrafo"))    {
+            ai_assert( prop->mDataLength >= sizeof(aiUVTransform));  /* something is wrong with the validation if we end up here */
+            aiUVTransform* uv = (aiUVTransform*)prop->mData;
 
-			// just flip it, that's everything
-			uv->mTranslation.y *= -1.f;
-			uv->mRotation *= -1.f;
-		}
-	}
+            // just flip it, that's everything
+            uv->mTranslation.y *= -1.f;
+            uv->mRotation *= -1.f;
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single mesh
 void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
 {
-	// mirror texture y coordinate
-	for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)	{
+    // mirror texture y coordinate
+    for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)   {
         if( !pMesh->HasTextureCoords( a ) ) {
             break;
         }
@@ -281,7 +281,7 @@ void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
         for( unsigned int b = 0; b < pMesh->mNumVertices; b++ ) {
             pMesh->mTextureCoords[ a ][ b ].y = 1.0f - pMesh->mTextureCoords[ a ][ b ].y;
         }
-	}
+    }
 }
 
 #endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS
@@ -302,30 +302,30 @@ FlipWindingOrderProcess::~FlipWindingOrderProcess()
 // Returns whether the processing step is present in the given flag field.
 bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
 {
-	return 0 != (pFlags & aiProcess_FlipWindingOrder);
+    return 0 != (pFlags & aiProcess_FlipWindingOrder);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 void FlipWindingOrderProcess::Execute( aiScene* pScene)
 {
-	DefaultLogger::get()->debug("FlipWindingOrderProcess begin");
-	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
-		ProcessMesh(pScene->mMeshes[i]);
-	DefaultLogger::get()->debug("FlipWindingOrderProcess finished");
+    DefaultLogger::get()->debug("FlipWindingOrderProcess begin");
+    for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
+        ProcessMesh(pScene->mMeshes[i]);
+    DefaultLogger::get()->debug("FlipWindingOrderProcess finished");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single mesh
 void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
 {
-	// invert the order of all faces in this mesh
-	for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
-	{
-		aiFace& face = pMesh->mFaces[a];
-		for( unsigned int b = 0; b < face.mNumIndices / 2; b++)
-			std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]);
-	}
+    // invert the order of all faces in this mesh
+    for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
+    {
+        aiFace& face = pMesh->mFaces[a];
+        for( unsigned int b = 0; b < face.mNumIndices / 2; b++)
+            std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]);
+    }
 }
 
 #endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS

+ 54 - 54
code/ConvertToLHProcess.h

@@ -57,7 +57,7 @@ struct aiNodeAnim;
 struct aiNode;
 struct aiMaterial;
 
-namespace Assimp	{
+namespace Assimp    {
 
 // -----------------------------------------------------------------------------------
 /** @brief The MakeLeftHandedProcess converts all imported data to a left-handed
@@ -74,43 +74,43 @@ class MakeLeftHandedProcess : public BaseProcess
 
 
 public:
-	MakeLeftHandedProcess();
-	~MakeLeftHandedProcess();
+    MakeLeftHandedProcess();
+    ~MakeLeftHandedProcess();
 
-	// -------------------------------------------------------------------
-	bool IsActive( unsigned int pFlags) const;
+    // -------------------------------------------------------------------
+    bool IsActive( unsigned int pFlags) const;
 
-	// -------------------------------------------------------------------
-	void Execute( aiScene* pScene);
+    // -------------------------------------------------------------------
+    void Execute( aiScene* pScene);
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Recursively converts a node and all of its children
-	 */
-	void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation);
-
-	// -------------------------------------------------------------------
-	/** Converts a single mesh to left handed coordinates.
-	 * This means that positions, normals and tangents are mirrored at
-	 * the local Z axis and the order of all faces are inverted.
-	 * @param pMesh The mesh to convert.
-	 */
-	void ProcessMesh( aiMesh* pMesh);
-
-	// -------------------------------------------------------------------
-	/** Converts a single material to left-handed coordinates
-	 * @param pMat Material to convert
-	 */
-	void ProcessMaterial( aiMaterial* pMat);
-
-	// -------------------------------------------------------------------
-	/** Converts the given animation to LH coordinates.
-	 * The rotation and translation keys are transformed, the scale keys
-	 * work in local space and can therefore be left untouched.
-	 * @param pAnim The bone animation to transform
-	 */
-	void ProcessAnimation( aiNodeAnim* pAnim);
+    // -------------------------------------------------------------------
+    /** Recursively converts a node and all of its children
+     */
+    void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation);
+
+    // -------------------------------------------------------------------
+    /** Converts a single mesh to left handed coordinates.
+     * This means that positions, normals and tangents are mirrored at
+     * the local Z axis and the order of all faces are inverted.
+     * @param pMesh The mesh to convert.
+     */
+    void ProcessMesh( aiMesh* pMesh);
+
+    // -------------------------------------------------------------------
+    /** Converts a single material to left-handed coordinates
+     * @param pMat Material to convert
+     */
+    void ProcessMaterial( aiMaterial* pMat);
+
+    // -------------------------------------------------------------------
+    /** Converts the given animation to LH coordinates.
+     * The rotation and translation keys are transformed, the scale keys
+     * work in local space and can therefore be left untouched.
+     * @param pAnim The bone animation to transform
+     */
+    void ProcessAnimation( aiNodeAnim* pAnim);
 };
 
 
@@ -119,23 +119,23 @@ protected:
  */
 class FlipWindingOrderProcess : public BaseProcess
 {
-	friend class Importer;
+    friend class Importer;
 
 public:
-	/** Constructor to be privately used by Importer */
-	FlipWindingOrderProcess();
+    /** Constructor to be privately used by Importer */
+    FlipWindingOrderProcess();
 
-	/** Destructor, private as well */
-	~FlipWindingOrderProcess();
+    /** Destructor, private as well */
+    ~FlipWindingOrderProcess();
 
-	// -------------------------------------------------------------------
-	bool IsActive( unsigned int pFlags) const;
+    // -------------------------------------------------------------------
+    bool IsActive( unsigned int pFlags) const;
 
-	// -------------------------------------------------------------------
-	void Execute( aiScene* pScene);
+    // -------------------------------------------------------------------
+    void Execute( aiScene* pScene);
 
 protected:
-	void ProcessMesh( aiMesh* pMesh);
+    void ProcessMesh( aiMesh* pMesh);
 };
 
 // ---------------------------------------------------------------------------
@@ -143,24 +143,24 @@ protected:
  */
 class FlipUVsProcess : public BaseProcess
 {
-	friend class Importer;
+    friend class Importer;
 
 public:
-	/** Constructor to be privately used by Importer */
-	FlipUVsProcess();
+    /** Constructor to be privately used by Importer */
+    FlipUVsProcess();
 
-	/** Destructor, private as well */
-	~FlipUVsProcess();
+    /** Destructor, private as well */
+    ~FlipUVsProcess();
 
-	// -------------------------------------------------------------------
-	bool IsActive( unsigned int pFlags) const;
+    // -------------------------------------------------------------------
+    bool IsActive( unsigned int pFlags) const;
 
-	// -------------------------------------------------------------------
-	void Execute( aiScene* pScene);
+    // -------------------------------------------------------------------
+    void Execute( aiScene* pScene);
 
 protected:
-	void ProcessMesh( aiMesh* pMesh);
-	void ProcessMaterial( aiMaterial* mat);
+    void ProcessMesh( aiMesh* pMesh);
+    void ProcessMaterial( aiMaterial* mat);
 };
 
 } // end of namespace Assimp

+ 115 - 115
code/DXFHelper.h

@@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/DefaultLogger.hpp"
 
 namespace Assimp {
-	namespace DXF {
+    namespace DXF {
 
 
 // read pairs of lines, parse group code and value and provide utilities
@@ -63,113 +63,113 @@ class LineReader
 
 public:
 
-	LineReader(StreamReaderLE& reader)
-		 // do NOT skip empty lines. In DXF files, they count as valid data.
-		: splitter(reader,false,true)
-		, end()
-	{
-	}
+    LineReader(StreamReaderLE& reader)
+         // do NOT skip empty lines. In DXF files, they count as valid data.
+        : splitter(reader,false,true)
+        , end()
+    {
+    }
 
 public:
 
 
-	// -----------------------------------------
-	bool Is(int gc, const char* what) const {
-		return groupcode == gc && !strcmp(what,value.c_str());
-	}
+    // -----------------------------------------
+    bool Is(int gc, const char* what) const {
+        return groupcode == gc && !strcmp(what,value.c_str());
+    }
 
-	// -----------------------------------------
-	bool Is(int gc) const {
-		return groupcode == gc;
-	}
+    // -----------------------------------------
+    bool Is(int gc) const {
+        return groupcode == gc;
+    }
 
-	// -----------------------------------------
-	int GroupCode() const {
-		return groupcode;
-	}
+    // -----------------------------------------
+    int GroupCode() const {
+        return groupcode;
+    }
 
-	// -----------------------------------------
-	const std::string& Value() const {
-		return value;
-	}
+    // -----------------------------------------
+    const std::string& Value() const {
+        return value;
+    }
 
-	// -----------------------------------------
-	bool End() const {
-		return !((bool)*this);
-	}
+    // -----------------------------------------
+    bool End() const {
+        return !((bool)*this);
+    }
 
 public:
 
-	// -----------------------------------------
-	unsigned int ValueAsUnsignedInt() const {
-		return strtoul10(value.c_str());
-	}
+    // -----------------------------------------
+    unsigned int ValueAsUnsignedInt() const {
+        return strtoul10(value.c_str());
+    }
 
-	// -----------------------------------------
-	int ValueAsSignedInt() const {
-		return strtol10(value.c_str());
-	}
+    // -----------------------------------------
+    int ValueAsSignedInt() const {
+        return strtol10(value.c_str());
+    }
 
-	// -----------------------------------------
-	float ValueAsFloat() const {
-		return fast_atof(value.c_str());
-	}
+    // -----------------------------------------
+    float ValueAsFloat() const {
+        return fast_atof(value.c_str());
+    }
 
 public:
 
-	// -----------------------------------------
-	/** pseudo-iterator increment to advance to the next (groupcode/value) pair */
-	LineReader& operator++() {
-		if (end) {
-			if (end == 1) {
-				++end;
-			}
-			return *this;
-		}
-
-		try {
-			groupcode = strtol10(splitter->c_str());
-			splitter++;
-
-			value = *splitter;
-			splitter++;
-
-			// automatically skip over {} meta blocks (these are for application use
-			// and currently not relevant for Assimp).
-			if (value.length() && value[0] == '{') {
-
-				size_t cnt = 0;
-				for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
-
-				splitter++;
-				DefaultLogger::get()->debug((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
-			}
-		} catch(std::logic_error&) {
-			ai_assert(!splitter);
-		}
-		if (!splitter) {
-			end = 1;
-		}
-		return *this;
-	}
-
-	// -----------------------------------------
-	LineReader& operator++(int) {
-		return ++(*this);
-	}
-
-
-	// -----------------------------------------
-	operator bool() const {
-		return end <= 1;
-	}
+    // -----------------------------------------
+    /** pseudo-iterator increment to advance to the next (groupcode/value) pair */
+    LineReader& operator++() {
+        if (end) {
+            if (end == 1) {
+                ++end;
+            }
+            return *this;
+        }
+
+        try {
+            groupcode = strtol10(splitter->c_str());
+            splitter++;
+
+            value = *splitter;
+            splitter++;
+
+            // automatically skip over {} meta blocks (these are for application use
+            // and currently not relevant for Assimp).
+            if (value.length() && value[0] == '{') {
+
+                size_t cnt = 0;
+                for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
+
+                splitter++;
+                DefaultLogger::get()->debug((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
+            }
+        } catch(std::logic_error&) {
+            ai_assert(!splitter);
+        }
+        if (!splitter) {
+            end = 1;
+        }
+        return *this;
+    }
+
+    // -----------------------------------------
+    LineReader& operator++(int) {
+        return ++(*this);
+    }
+
+
+    // -----------------------------------------
+    operator bool() const {
+        return end <= 1;
+    }
 
 private:
 
-	LineSplitter splitter;
-	int groupcode;
-	std::string value;
-	int end;
+    LineSplitter splitter;
+    int groupcode;
+    std::string value;
+    int end;
 };
 
 
@@ -177,52 +177,52 @@ private:
 // represents a POLYLINE or a LWPOLYLINE. or even a 3DFACE The data is converted as needed.
 struct PolyLine
 {
-	PolyLine()
-		: flags()
-	{}
-
-	std::vector<aiVector3D> positions;
-	std::vector<aiColor4D>  colors;
-	std::vector<unsigned int> indices;
-	std::vector<unsigned int> counts;
-	unsigned int flags;
-
-	std::string layer;
-	std::string desc;
+    PolyLine()
+        : flags()
+    {}
+
+    std::vector<aiVector3D> positions;
+    std::vector<aiColor4D>  colors;
+    std::vector<unsigned int> indices;
+    std::vector<unsigned int> counts;
+    unsigned int flags;
+
+    std::string layer;
+    std::string desc;
 };
 
 
 // reference to a BLOCK. Specifies its own coordinate system.
 struct InsertBlock
 {
-	InsertBlock()
-		: scale(1.f,1.f,1.f)
-		, angle()
-	{}
+    InsertBlock()
+        : scale(1.f,1.f,1.f)
+        , angle()
+    {}
 
-	aiVector3D pos;
-	aiVector3D scale;
-	float angle;
+    aiVector3D pos;
+    aiVector3D scale;
+    float angle;
 
-	std::string name;
+    std::string name;
 };
 
 
 // keeps track of all geometry in a single BLOCK.
 struct Block
 {
-	std::vector< boost::shared_ptr<PolyLine> > lines;
-	std::vector<InsertBlock> insertions;
+    std::vector< boost::shared_ptr<PolyLine> > lines;
+    std::vector<InsertBlock> insertions;
 
-	std::string name;
-	aiVector3D base;
+    std::string name;
+    aiVector3D base;
 };
 
 
 struct FileData
 {
-	// note: the LAST block always contains the stuff from ENTITIES.
-	std::vector<Block> blocks;
+    // note: the LAST block always contains the stuff from ENTITIES.
+    std::vector<Block> blocks;
 };
 
 

File diff suppressed because it is too large
+ 543 - 543
code/DXFLoader.cpp


+ 64 - 64
code/DXFLoader.h

@@ -46,17 +46,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "BaseImporter.h"
 
-namespace Assimp	{
-	namespace DXF {
+namespace Assimp    {
+    namespace DXF {
 
-		class LineReader;
-		struct FileData;
-		struct PolyLine;
-		struct Block;
-		struct InsertBlock;
+        class LineReader;
+        struct FileData;
+        struct PolyLine;
+        struct Block;
+        struct InsertBlock;
 
-		typedef std::map<std::string, const DXF::Block*> BlockMap;
-	}
+        typedef std::map<std::string, const DXF::Block*> BlockMap;
+    }
 
 
 // ---------------------------------------------------------------------------
@@ -66,85 +66,85 @@ namespace Assimp	{
 class DXFImporter : public BaseImporter
 {
 public:
-	DXFImporter();
-	~DXFImporter();
+    DXFImporter();
+    ~DXFImporter();
 
 
 
 public:
 
-	// -------------------------------------------------------------------
-	/** Returns whether the class can handle the format of the given file.
-	* See BaseImporter::CanRead() for details.	*/
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-		bool checkSig) const;
+    // -------------------------------------------------------------------
+    /** Returns whether the class can handle the format of the given file.
+    * See BaseImporter::CanRead() for details.  */
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+        bool checkSig) const;
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Return importer meta information.
-	 * See #BaseImporter::GetInfo for the details*/
-	const aiImporterDesc* GetInfo () const;
+    // -------------------------------------------------------------------
+    /** Return importer meta information.
+     * See #BaseImporter::GetInfo for the details*/
+    const aiImporterDesc* GetInfo () const;
 
-	// -------------------------------------------------------------------
-	/** Imports the given file into the given scene structure.
-	 * See BaseImporter::InternReadFile() for details */
-	void InternReadFile( const std::string& pFile,
-		aiScene* pScene,
-		IOSystem* pIOHandler);
+    // -------------------------------------------------------------------
+    /** Imports the given file into the given scene structure.
+     * See BaseImporter::InternReadFile() for details */
+    void InternReadFile( const std::string& pFile,
+        aiScene* pScene,
+        IOSystem* pIOHandler);
 
 private:
 
-	// -----------------------------------------------------
-	void SkipSection(DXF::LineReader& reader);
+    // -----------------------------------------------------
+    void SkipSection(DXF::LineReader& reader);
 
-	// -----------------------------------------------------
-	void ParseHeader(DXF::LineReader& reader,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void ParseHeader(DXF::LineReader& reader,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ParseEntities(DXF::LineReader& reader,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void ParseEntities(DXF::LineReader& reader,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ParseBlocks(DXF::LineReader& reader,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void ParseBlocks(DXF::LineReader& reader,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ParseBlock(DXF::LineReader& reader,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void ParseBlock(DXF::LineReader& reader,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ParseInsertion(DXF::LineReader& reader,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void ParseInsertion(DXF::LineReader& reader,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ParsePolyLine(DXF::LineReader& reader,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void ParsePolyLine(DXF::LineReader& reader,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ParsePolyLineVertex(DXF::LineReader& reader,
-		DXF::PolyLine& line);
+    // -----------------------------------------------------
+    void ParsePolyLineVertex(DXF::LineReader& reader,
+        DXF::PolyLine& line);
 
-	// -----------------------------------------------------
-	void Parse3DFace(DXF::LineReader& reader,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void Parse3DFace(DXF::LineReader& reader,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ConvertMeshes(aiScene* pScene,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void ConvertMeshes(aiScene* pScene,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void GenerateHierarchy(aiScene* pScene,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void GenerateHierarchy(aiScene* pScene,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void GenerateMaterials(aiScene* pScene,
-		DXF::FileData& output);
+    // -----------------------------------------------------
+    void GenerateMaterials(aiScene* pScene,
+        DXF::FileData& output);
 
-	// -----------------------------------------------------
-	void ExpandBlockReferences(DXF::Block& bl,
-		const DXF::BlockMap& blocks_by_name);
+    // -----------------------------------------------------
+    void ExpandBlockReferences(DXF::Block& bl,
+        const DXF::BlockMap& blocks_by_name);
 };
 
 } // end of namespace Assimp

+ 345 - 345
code/DeboneProcess.cpp

@@ -1,4 +1,4 @@
-									 /*
+/*
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
@@ -55,411 +55,411 @@ using namespace Assimp;
 // Constructor to be privately used by Importer
 DeboneProcess::DeboneProcess()
 {
-	mNumBones = 0;
-	mNumBonesCanDoWithout = 0;
+    mNumBones = 0;
+    mNumBonesCanDoWithout = 0;
 
-	mThreshold = AI_DEBONE_THRESHOLD;
-	mAllOrNone = false;
+    mThreshold = AI_DEBONE_THRESHOLD;
+    mAllOrNone = false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 DeboneProcess::~DeboneProcess()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool DeboneProcess::IsActive( unsigned int pFlags) const
 {
-	return (pFlags & aiProcess_Debone) != 0;
+    return (pFlags & aiProcess_Debone) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 void DeboneProcess::SetupProperties(const Importer* pImp)
 {
-	// get the current value of the property
-	mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
-	mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
+    // get the current value of the property
+    mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
+    mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 void DeboneProcess::Execute( aiScene* pScene)
 {
-	DefaultLogger::get()->debug("DeboneProcess begin");
-
-	if(!pScene->mNumMeshes) {
-		return;
-	}
-
-	std::vector<bool> splitList(pScene->mNumMeshes);
-	for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
-		splitList[a] = ConsiderMesh( pScene->mMeshes[a] );
-	}
-
-	int numSplits = 0;
-
-	if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones))	{
-		for(unsigned int a = 0; a < pScene->mNumMeshes; a++)	{
-			if(splitList[a]) {
-				numSplits++;
-			}
-		}
-	}
-
-	if(numSplits)	{
-		// we need to do something. Let's go.
-		//mSubMeshIndices.clear();                  // really needed?
-		mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway
-
-		// build a new array of meshes for the scene
-		std::vector<aiMesh*> meshes;
-
-		for(unsigned int a=0;a<pScene->mNumMeshes;a++)
-		{
-			aiMesh* srcMesh = pScene->mMeshes[a];
-
-			std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
-
-			if(splitList[a]) {
-				SplitMesh(srcMesh,newMeshes);
-			}
-
-			// mesh was split
-			if(!newMeshes.empty())	{
-				unsigned int out = 0, in = srcMesh->mNumBones;
-
-				// store new meshes and indices of the new meshes
-				for(unsigned int b=0;b<newMeshes.size();b++)	{
-					const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0;
-
-					aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0;
-					std::pair<unsigned int,aiNode*> push_pair(meshes.size(),theNode);
-
-					mSubMeshIndices[a].push_back(push_pair);
-					meshes.push_back(newMeshes[b].first);
-
-					out+=newMeshes[b].first->mNumBones;
-				}
-
-				if(!DefaultLogger::isNullLogger()) {
-					char buffer[1024];
-					::sprintf(buffer,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out);
-					DefaultLogger::get()->info(buffer);
-				}
-
-				// and destroy the source mesh. It should be completely contained inside the new submeshes
-				delete srcMesh;
-			}
-			else	{
-				// Mesh is kept unchanged - store it's new place in the mesh array
-				mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(meshes.size(),(aiNode*)0));
-				meshes.push_back(srcMesh);
-			}
-		}
-
-		// rebuild the scene's mesh array
-		pScene->mNumMeshes = meshes.size();
-		delete [] pScene->mMeshes;
-		pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-		std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
-
-		// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
-		UpdateNode( pScene->mRootNode);
-	}
-
-	DefaultLogger::get()->debug("DeboneProcess end");
+    DefaultLogger::get()->debug("DeboneProcess begin");
+
+    if(!pScene->mNumMeshes) {
+        return;
+    }
+
+    std::vector<bool> splitList(pScene->mNumMeshes);
+    for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
+        splitList[a] = ConsiderMesh( pScene->mMeshes[a] );
+    }
+
+    int numSplits = 0;
+
+    if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones))  {
+        for(unsigned int a = 0; a < pScene->mNumMeshes; a++)    {
+            if(splitList[a]) {
+                numSplits++;
+            }
+        }
+    }
+
+    if(numSplits)   {
+        // we need to do something. Let's go.
+        //mSubMeshIndices.clear();                  // really needed?
+        mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway
+
+        // build a new array of meshes for the scene
+        std::vector<aiMesh*> meshes;
+
+        for(unsigned int a=0;a<pScene->mNumMeshes;a++)
+        {
+            aiMesh* srcMesh = pScene->mMeshes[a];
+
+            std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
+
+            if(splitList[a]) {
+                SplitMesh(srcMesh,newMeshes);
+            }
+
+            // mesh was split
+            if(!newMeshes.empty())  {
+                unsigned int out = 0, in = srcMesh->mNumBones;
+
+                // store new meshes and indices of the new meshes
+                for(unsigned int b=0;b<newMeshes.size();b++)    {
+                    const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0;
+
+                    aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0;
+                    std::pair<unsigned int,aiNode*> push_pair(meshes.size(),theNode);
+
+                    mSubMeshIndices[a].push_back(push_pair);
+                    meshes.push_back(newMeshes[b].first);
+
+                    out+=newMeshes[b].first->mNumBones;
+                }
+
+                if(!DefaultLogger::isNullLogger()) {
+                    char buffer[1024];
+                    ::sprintf(buffer,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out);
+                    DefaultLogger::get()->info(buffer);
+                }
+
+                // and destroy the source mesh. It should be completely contained inside the new submeshes
+                delete srcMesh;
+            }
+            else    {
+                // Mesh is kept unchanged - store it's new place in the mesh array
+                mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(meshes.size(),(aiNode*)0));
+                meshes.push_back(srcMesh);
+            }
+        }
+
+        // rebuild the scene's mesh array
+        pScene->mNumMeshes = meshes.size();
+        delete [] pScene->mMeshes;
+        pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+        std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
+
+        // recurse through all nodes and translate the node's mesh indices to fit the new mesh array
+        UpdateNode( pScene->mRootNode);
+    }
+
+    DefaultLogger::get()->debug("DeboneProcess end");
 }
 
 // ------------------------------------------------------------------------------------------------
 // Counts bones total/removable in a given mesh.
 bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
 {
-	if(!pMesh->HasBones()) {
-		return false;
-	}
-
-	bool split = false;
-
-	//interstitial faces not permitted
-	bool isInterstitialRequired = false;
-
-	std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
-	std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
-
-	const unsigned int cUnowned = UINT_MAX;
-	const unsigned int cCoowned = UINT_MAX-1;
-
-	for(unsigned int i=0;i<pMesh->mNumBones;i++)	{
-		for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++)	{
-			float w = pMesh->mBones[i]->mWeights[j].mWeight;
-
-			if(w==0.0f) {
-				continue;
-			}
-
-			unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
-			if(w>=mThreshold)	{
-
-				if(vertexBones[vid]!=cUnowned)	{
-					if(vertexBones[vid]==i) //double entry
-					{
-						DefaultLogger::get()->warn("Encountered double entry in bone weights");
-					}
-					else //TODO: track attraction in order to break tie
-					{
-						vertexBones[vid] = cCoowned;
-					}
-				}
-				else vertexBones[vid] = i;
-			}
-
-			if(!isBoneNecessary[i]) {
-				isBoneNecessary[i] = w<mThreshold;
-			}
-		}
-
-		if(!isBoneNecessary[i])  {
-			isInterstitialRequired = true;
-		}
-	}
-
-	if(isInterstitialRequired) {
-		for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
-			unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
-
-			for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
-				unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
-
-				if(v!=w)	{
-					if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
-					if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
-				}
-			}
-		}
-	}
-
-	for(unsigned int i=0;i<pMesh->mNumBones;i++)	{
-		if(!isBoneNecessary[i])	{
-			mNumBonesCanDoWithout++;
-			split = true;
-		}
-
-		mNumBones++;
-	}
-	return split;
+    if(!pMesh->HasBones()) {
+        return false;
+    }
+
+    bool split = false;
+
+    //interstitial faces not permitted
+    bool isInterstitialRequired = false;
+
+    std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
+    std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
+
+    const unsigned int cUnowned = UINT_MAX;
+    const unsigned int cCoowned = UINT_MAX-1;
+
+    for(unsigned int i=0;i<pMesh->mNumBones;i++)    {
+        for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++)   {
+            float w = pMesh->mBones[i]->mWeights[j].mWeight;
+
+            if(w==0.0f) {
+                continue;
+            }
+
+            unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
+            if(w>=mThreshold)   {
+
+                if(vertexBones[vid]!=cUnowned)  {
+                    if(vertexBones[vid]==i) //double entry
+                    {
+                        DefaultLogger::get()->warn("Encountered double entry in bone weights");
+                    }
+                    else //TODO: track attraction in order to break tie
+                    {
+                        vertexBones[vid] = cCoowned;
+                    }
+                }
+                else vertexBones[vid] = i;
+            }
+
+            if(!isBoneNecessary[i]) {
+                isBoneNecessary[i] = w<mThreshold;
+            }
+        }
+
+        if(!isBoneNecessary[i])  {
+            isInterstitialRequired = true;
+        }
+    }
+
+    if(isInterstitialRequired) {
+        for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
+            unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
+
+            for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
+                unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
+
+                if(v!=w)    {
+                    if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
+                    if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
+                }
+            }
+        }
+    }
+
+    for(unsigned int i=0;i<pMesh->mNumBones;i++)    {
+        if(!isBoneNecessary[i]) {
+            mNumBonesCanDoWithout++;
+            split = true;
+        }
+
+        mNumBones++;
+    }
+    return split;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Splits the given mesh by bone count.
 void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const
 {
-	// same deal here as ConsiderMesh basically
-
-	std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
-	std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
-
-	const unsigned int cUnowned = UINT_MAX;
-	const unsigned int cCoowned = UINT_MAX-1;
-
-	for(unsigned int i=0;i<pMesh->mNumBones;i++)	{
-		for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++)	{
-			float w = pMesh->mBones[i]->mWeights[j].mWeight;
-
-			if(w==0.0f) {
-				continue;
-			}
-
-			unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
-
-			if(w>=mThreshold) {
-				if(vertexBones[vid]!=cUnowned)  {
-					if(vertexBones[vid]==i) //double entry
-					{
-						//DefaultLogger::get()->warn("Encountered double entry in bone weights");
-					}
-					else //TODO: track attraction in order to break tie
-					{
-						vertexBones[vid] = cCoowned;
-					}
-				}
-				else vertexBones[vid] = i;
-			}
-
-			if(!isBoneNecessary[i]) {
-				isBoneNecessary[i] = w<mThreshold;
-			}
-		}
-	}
-
-	unsigned int nFacesUnowned = 0;
-
-	std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX);
-	std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0);
-
-	for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
-		unsigned int nInterstitial = 1;
-
-		unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
-
-		for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
-			unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
-
-			if(v!=w)	{
-				if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
-				if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
-			}
-			else nInterstitial++;
-		}
-
-		if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices)	{
-			faceBones[i] = v; //primitive belongs to bone #v
-			facesPerBone[v]++;
-		}
-		else nFacesUnowned++;
-	}
-
-	// invalidate any "cojoined" faces
-	for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
-		if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]])
-		{
-			ai_assert(facesPerBone[faceBones[i]]>0);
-			facesPerBone[faceBones[i]]--;
-
-			nFacesUnowned++;
-			faceBones[i] = cUnowned;
-		}
-	}
-
-	if(nFacesUnowned) {
-		std::vector<unsigned int> subFaces;
-
-		for(unsigned int i=0;i<pMesh->mNumFaces;i++)	{
-			if(faceBones[i]==cUnowned) {
-				subFaces.push_back(i);
-			}
-		}
-
-		aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0);
-		std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0);
-
-		poNewMeshes.push_back(push_pair);
-	}
-
-	for(unsigned int i=0;i<pMesh->mNumBones;i++) {
-
-		if(!isBoneNecessary[i]&&facesPerBone[i]>0)	{
-			std::vector<unsigned int> subFaces;
-
-			for(unsigned int j=0;j<pMesh->mNumFaces;j++)	{
-				if(faceBones[j]==i) {
-					subFaces.push_back(j);
-				}
-			}
-
-			unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES;
-			aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f);
-
-			//Lifted from PretransformVertices.cpp
-			ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix);
-			std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]);
-
-			poNewMeshes.push_back(push_pair);
-		}
-	}
+    // same deal here as ConsiderMesh basically
+
+    std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
+    std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
+
+    const unsigned int cUnowned = UINT_MAX;
+    const unsigned int cCoowned = UINT_MAX-1;
+
+    for(unsigned int i=0;i<pMesh->mNumBones;i++)    {
+        for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++)   {
+            float w = pMesh->mBones[i]->mWeights[j].mWeight;
+
+            if(w==0.0f) {
+                continue;
+            }
+
+            unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
+
+            if(w>=mThreshold) {
+                if(vertexBones[vid]!=cUnowned)  {
+                    if(vertexBones[vid]==i) //double entry
+                    {
+                        //DefaultLogger::get()->warn("Encountered double entry in bone weights");
+                    }
+                    else //TODO: track attraction in order to break tie
+                    {
+                        vertexBones[vid] = cCoowned;
+                    }
+                }
+                else vertexBones[vid] = i;
+            }
+
+            if(!isBoneNecessary[i]) {
+                isBoneNecessary[i] = w<mThreshold;
+            }
+        }
+    }
+
+    unsigned int nFacesUnowned = 0;
+
+    std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX);
+    std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0);
+
+    for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
+        unsigned int nInterstitial = 1;
+
+        unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
+
+        for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
+            unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
+
+            if(v!=w)    {
+                if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
+                if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
+            }
+            else nInterstitial++;
+        }
+
+        if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices)    {
+            faceBones[i] = v; //primitive belongs to bone #v
+            facesPerBone[v]++;
+        }
+        else nFacesUnowned++;
+    }
+
+    // invalidate any "cojoined" faces
+    for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
+        if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]])
+        {
+            ai_assert(facesPerBone[faceBones[i]]>0);
+            facesPerBone[faceBones[i]]--;
+
+            nFacesUnowned++;
+            faceBones[i] = cUnowned;
+        }
+    }
+
+    if(nFacesUnowned) {
+        std::vector<unsigned int> subFaces;
+
+        for(unsigned int i=0;i<pMesh->mNumFaces;i++)    {
+            if(faceBones[i]==cUnowned) {
+                subFaces.push_back(i);
+            }
+        }
+
+        aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0);
+        std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0);
+
+        poNewMeshes.push_back(push_pair);
+    }
+
+    for(unsigned int i=0;i<pMesh->mNumBones;i++) {
+
+        if(!isBoneNecessary[i]&&facesPerBone[i]>0)  {
+            std::vector<unsigned int> subFaces;
+
+            for(unsigned int j=0;j<pMesh->mNumFaces;j++)    {
+                if(faceBones[j]==i) {
+                    subFaces.push_back(j);
+                }
+            }
+
+            unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES;
+            aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f);
+
+            //Lifted from PretransformVertices.cpp
+            ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix);
+            std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]);
+
+            poNewMeshes.push_back(push_pair);
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Recursively updates the node's mesh list to account for the changed mesh list
 void DeboneProcess::UpdateNode(aiNode* pNode) const
 {
-	// rebuild the node's mesh index list
+    // rebuild the node's mesh index list
 
-	std::vector<unsigned int> newMeshList;
+    std::vector<unsigned int> newMeshList;
 
-	// this will require two passes
+    // this will require two passes
 
-	unsigned int m = pNode->mNumMeshes, n = mSubMeshIndices.size();
+    unsigned int m = pNode->mNumMeshes, n = mSubMeshIndices.size();
 
-	// first pass, look for meshes which have not moved
+    // first pass, look for meshes which have not moved
 
-	for(unsigned int a=0;a<m;a++)	{
+    for(unsigned int a=0;a<m;a++)   {
 
-		unsigned int srcIndex = pNode->mMeshes[a];
-		const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
-		unsigned int nSubmeshes = subMeshes.size();
+        unsigned int srcIndex = pNode->mMeshes[a];
+        const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
+        unsigned int nSubmeshes = subMeshes.size();
 
-		for(unsigned int b=0;b<nSubmeshes;b++) {
-			if(!subMeshes[b].second) {
-				newMeshList.push_back(subMeshes[b].first);
-			}
-		}
-	}
+        for(unsigned int b=0;b<nSubmeshes;b++) {
+            if(!subMeshes[b].second) {
+                newMeshList.push_back(subMeshes[b].first);
+            }
+        }
+    }
 
-	// second pass, collect deboned meshes
+    // second pass, collect deboned meshes
 
-	for(unsigned int a=0;a<n;a++)
-	{
-		const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
-		unsigned int nSubmeshes = subMeshes.size();
+    for(unsigned int a=0;a<n;a++)
+    {
+        const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
+        unsigned int nSubmeshes = subMeshes.size();
 
-		for(unsigned int b=0;b<nSubmeshes;b++) {
-			if(subMeshes[b].second == pNode)	{
-				newMeshList.push_back(subMeshes[b].first);
-			}
-		}
-	}
+        for(unsigned int b=0;b<nSubmeshes;b++) {
+            if(subMeshes[b].second == pNode)    {
+                newMeshList.push_back(subMeshes[b].first);
+            }
+        }
+    }
 
-	if( pNode->mNumMeshes > 0 )	{
-		delete [] pNode->mMeshes; pNode->mMeshes = NULL;
-	}
+    if( pNode->mNumMeshes > 0 ) {
+        delete [] pNode->mMeshes; pNode->mMeshes = NULL;
+    }
 
-	pNode->mNumMeshes = newMeshList.size();
+    pNode->mNumMeshes = newMeshList.size();
 
-	if(pNode->mNumMeshes)	{
-		pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
-		std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
-	}
+    if(pNode->mNumMeshes)   {
+        pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
+        std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
+    }
 
-	// do that also recursively for all children
-	for( unsigned int a = 0; a < pNode->mNumChildren; ++a )	{
-		UpdateNode( pNode->mChildren[a]);
-	}
+    // do that also recursively for all children
+    for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) {
+        UpdateNode( pNode->mChildren[a]);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Apply the node transformation to a mesh
 void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const
 {
-	// Check whether we need to transform the coordinates at all
-	if (!mat.IsIdentity()) {
-
-		if (mesh->HasPositions()) {
-			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-				mesh->mVertices[i] = mat * mesh->mVertices[i];
-			}
-		}
-		if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
-			aiMatrix4x4 mWorldIT = mat;
-			mWorldIT.Inverse().Transpose();
-
-			// TODO: implement Inverse() for aiMatrix3x3
-			aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
-
-			if (mesh->HasNormals()) {
-				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-					mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
-				}
-			}
-			if (mesh->HasTangentsAndBitangents()) {
-				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
-					mesh->mTangents[i]   = (m * mesh->mTangents[i]).Normalize();
-					mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
-				}
-			}
-		}
-	}
+    // Check whether we need to transform the coordinates at all
+    if (!mat.IsIdentity()) {
+
+        if (mesh->HasPositions()) {
+            for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                mesh->mVertices[i] = mat * mesh->mVertices[i];
+            }
+        }
+        if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
+            aiMatrix4x4 mWorldIT = mat;
+            mWorldIT.Inverse().Transpose();
+
+            // TODO: implement Inverse() for aiMatrix3x3
+            aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
+
+            if (mesh->HasNormals()) {
+                for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                    mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
+                }
+            }
+            if (mesh->HasTangentsAndBitangents()) {
+                for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                    mesh->mTangents[i]   = (m * mesh->mTangents[i]).Normalize();
+                    mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
+                }
+            }
+        }
+    }
 }

+ 46 - 46
code/DeboneProcess.h

@@ -1,4 +1,4 @@
-				   /*
+                   /*
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
@@ -55,7 +55,7 @@ namespace Assimp
 {
 
 #if (!defined AI_DEBONE_THRESHOLD)
-#	define AI_DEBONE_THRESHOLD	1.0f
+#   define AI_DEBONE_THRESHOLD  1.0f
 #endif // !! AI_DEBONE_THRESHOLD
 
 // ---------------------------------------------------------------------------
@@ -68,63 +68,63 @@ class DeboneProcess : public BaseProcess
 {
 public:
 
-	DeboneProcess();
-	~DeboneProcess();
+    DeboneProcess();
+    ~DeboneProcess();
 
 public:
-	// -------------------------------------------------------------------
-	/** Returns whether the processing step is present in the given flag.
-	* @param pFlags The processing flags the importer was called with.
-	*   A bitwise combination of #aiPostProcessSteps.
-	* @return true if the process is present in this flag fields,
-	*   false if not.
-	*/
-	bool IsActive( unsigned int pFlags) const;
-
-	// -------------------------------------------------------------------
-	/** Called prior to ExecuteOnScene().
-	* The function is a request to the process to update its configuration
-	* basing on the Importer's configuration property list.
-	*/
-	void SetupProperties(const Importer* pImp);
+    // -------------------------------------------------------------------
+    /** Returns whether the processing step is present in the given flag.
+    * @param pFlags The processing flags the importer was called with.
+    *   A bitwise combination of #aiPostProcessSteps.
+    * @return true if the process is present in this flag fields,
+    *   false if not.
+    */
+    bool IsActive( unsigned int pFlags) const;
+
+    // -------------------------------------------------------------------
+    /** Called prior to ExecuteOnScene().
+    * The function is a request to the process to update its configuration
+    * basing on the Importer's configuration property list.
+    */
+    void SetupProperties(const Importer* pImp);
 
 protected:
 
-	// -------------------------------------------------------------------
-	/** Executes the post processing step on the given imported data.
-	* At the moment a process is not supposed to fail.
-	* @param pScene The imported data to work at.
-	*/
-	void Execute( aiScene* pScene);
+    // -------------------------------------------------------------------
+    /** Executes the post processing step on the given imported data.
+    * At the moment a process is not supposed to fail.
+    * @param pScene The imported data to work at.
+    */
+    void Execute( aiScene* pScene);
 
-	// -------------------------------------------------------------------
-	/** Counts bones total/removable in a given mesh.
-	* @param pMesh The mesh to process.
-	*/
-	bool ConsiderMesh( const aiMesh* pMesh);
+    // -------------------------------------------------------------------
+    /** Counts bones total/removable in a given mesh.
+    * @param pMesh The mesh to process.
+    */
+    bool ConsiderMesh( const aiMesh* pMesh);
 
-	/// Splits the given mesh by bone count.
-	/// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
-	/// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
-	void SplitMesh(const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const;
+    /// Splits the given mesh by bone count.
+    /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
+    /// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
+    void SplitMesh(const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const;
 
-	/// Recursively updates the node's mesh list to account for the changed mesh list
-	void UpdateNode(aiNode* pNode) const;
+    /// Recursively updates the node's mesh list to account for the changed mesh list
+    void UpdateNode(aiNode* pNode) const;
 
-	// -------------------------------------------------------------------
-	// Apply transformation to a mesh
-	void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const;
+    // -------------------------------------------------------------------
+    // Apply transformation to a mesh
+    void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const;
 
 public:
-	/** Number of bones present in the scene. */
-	unsigned int mNumBones;
-	unsigned int mNumBonesCanDoWithout;
+    /** Number of bones present in the scene. */
+    unsigned int mNumBones;
+    unsigned int mNumBonesCanDoWithout;
 
-	float mThreshold;
-	bool mAllOrNone;
+    float mThreshold;
+    bool mAllOrNone;
 
-	/// Per mesh index: Array of indices of the new submeshes.
-	std::vector< std::vector< std::pair< unsigned int,aiNode* > > > mSubMeshIndices;
+    /// Per mesh index: Array of indices of the new submeshes.
+    std::vector< std::vector< std::pair< unsigned int,aiNode* > > > mSubMeshIndices;
 };
 
 } // end of namespace Assimp

+ 43 - 43
code/DefaultIOStream.cpp

@@ -54,62 +54,62 @@ using namespace Assimp;
 // ----------------------------------------------------------------------------------
 DefaultIOStream::~DefaultIOStream()
 {
-	if (mFile) {
-		::fclose(mFile);
-	}
+    if (mFile) {
+        ::fclose(mFile);
+    }
 }
 
 // ----------------------------------------------------------------------------------
 size_t DefaultIOStream::Read(void* pvBuffer,
-	size_t pSize,
-	size_t pCount)
+    size_t pSize,
+    size_t pCount)
 {
-	ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
-	return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0);
+    ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
+    return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0);
 }
 
 // ----------------------------------------------------------------------------------
 size_t DefaultIOStream::Write(const void* pvBuffer,
-	size_t pSize,
-	size_t pCount)
+    size_t pSize,
+    size_t pCount)
 {
-	ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
-	return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0);
+    ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
+    return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0);
 }
 
 // ----------------------------------------------------------------------------------
 aiReturn DefaultIOStream::Seek(size_t pOffset,
-	 aiOrigin pOrigin)
+     aiOrigin pOrigin)
 {
-	if (!mFile) {
-		return AI_FAILURE;
-	}
+    if (!mFile) {
+        return AI_FAILURE;
+    }
 
-	// Just to check whether our enum maps one to one with the CRT constants
-	BOOST_STATIC_ASSERT(aiOrigin_CUR == SEEK_CUR &&
-		aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET);
+    // Just to check whether our enum maps one to one with the CRT constants
+    BOOST_STATIC_ASSERT(aiOrigin_CUR == SEEK_CUR &&
+        aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET);
 
-	// do the seek
-	return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE);
+    // do the seek
+    return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE);
 }
 
 // ----------------------------------------------------------------------------------
 size_t DefaultIOStream::Tell() const
 {
-	if (!mFile) {
-		return 0;
-	}
-	return ::ftell(mFile);
+    if (!mFile) {
+        return 0;
+    }
+    return ::ftell(mFile);
 }
 
 // ----------------------------------------------------------------------------------
 size_t DefaultIOStream::FileSize() const
 {
-	if (! mFile || mFilename.empty()) {
-		return 0;
-	}
+    if (! mFile || mFilename.empty()) {
+        return 0;
+    }
 
-	if (SIZE_MAX == cachedSize) {
+    if (SIZE_MAX == cachedSize) {
 
         // Although fseek/ftell would allow us to reuse the exising file handle here,
         // it is generally unsafe because:
@@ -120,28 +120,28 @@ size_t DefaultIOStream::FileSize() const
         // See here for details:
         // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
 #if defined _WIN32 && !defined __GNUC__
-		struct __stat64 fileStat;
-		int err = _stat64(  mFilename.c_str(), &fileStat );
-		if (0 != err)
-			return 0;
-		cachedSize = (size_t) (fileStat.st_size);
+        struct __stat64 fileStat;
+        int err = _stat64(  mFilename.c_str(), &fileStat );
+        if (0 != err)
+            return 0;
+        cachedSize = (size_t) (fileStat.st_size);
 #else
-		struct stat fileStat;
-		int err = stat(mFilename.c_str(), &fileStat );
-		if (0 != err)
-			return 0;
-		cachedSize = (size_t) (fileStat.st_size);
+        struct stat fileStat;
+        int err = stat(mFilename.c_str(), &fileStat );
+        if (0 != err)
+            return 0;
+        cachedSize = (size_t) (fileStat.st_size);
 #endif
-	}
-	return cachedSize;
+    }
+    return cachedSize;
 }
 
 // ----------------------------------------------------------------------------------
 void DefaultIOStream::Flush()
 {
-	if (mFile) {
-		::fflush(mFile);
-	}
+    if (mFile) {
+        ::fflush(mFile);
+    }
 }
 
 // ----------------------------------------------------------------------------------

+ 43 - 43
code/DefaultIOStream.h

@@ -47,17 +47,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/importerdesc.h"
 #include "Defines.h"
 
-namespace Assimp	{
+namespace Assimp    {
 
 // ----------------------------------------------------------------------------------
-//!	@class	DefaultIOStream
-//!	@brief	Default IO implementation, use standard IO operations
+//! @class  DefaultIOStream
+//! @brief  Default IO implementation, use standard IO operations
 //! @note   An instance of this class can exist without a valid file handle
 //!         attached to it. All calls fail, but the instance can nevertheless be
 //!         used with no restrictions.
 class DefaultIOStream : public IOStream
 {
-	friend class DefaultIOSystem;
+    friend class DefaultIOSystem;
 #if __ANDROID__
 #if __ANDROID_API__ > 9
 #if defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
@@ -67,72 +67,72 @@ class DefaultIOStream : public IOStream
 #endif // __ANDROID__
 
 protected:
-	DefaultIOStream();
-	DefaultIOStream(FILE* pFile, const std::string &strFilename);
+    DefaultIOStream();
+    DefaultIOStream(FILE* pFile, const std::string &strFilename);
 
 public:
-	/** Destructor public to allow simple deletion to close the file. */
-	~DefaultIOStream ();
+    /** Destructor public to allow simple deletion to close the file. */
+    ~DefaultIOStream ();
 
-	// -------------------------------------------------------------------
-	/// Read from stream
+    // -------------------------------------------------------------------
+    /// Read from stream
     size_t Read(void* pvBuffer,
-		size_t pSize,
-		size_t pCount);
+        size_t pSize,
+        size_t pCount);
 
 
-	// -------------------------------------------------------------------
-	/// Write to stream
+    // -------------------------------------------------------------------
+    /// Write to stream
     size_t Write(const void* pvBuffer,
-		size_t pSize,
-		size_t pCount);
+        size_t pSize,
+        size_t pCount);
 
-	// -------------------------------------------------------------------
-	/// Seek specific position
-	aiReturn Seek(size_t pOffset,
-		aiOrigin pOrigin);
+    // -------------------------------------------------------------------
+    /// Seek specific position
+    aiReturn Seek(size_t pOffset,
+        aiOrigin pOrigin);
 
-	// -------------------------------------------------------------------
-	/// Get current seek position
+    // -------------------------------------------------------------------
+    /// Get current seek position
     size_t Tell() const;
 
-	// -------------------------------------------------------------------
-	/// Get size of file
-	size_t FileSize() const;
+    // -------------------------------------------------------------------
+    /// Get size of file
+    size_t FileSize() const;
 
-	// -------------------------------------------------------------------
-	/// Flush file contents
-	void Flush();
+    // -------------------------------------------------------------------
+    /// Flush file contents
+    void Flush();
 
 private:
-	//	File datastructure, using clib
-	FILE* mFile;
-	//	Filename
-	std::string	mFilename;
+    //  File datastructure, using clib
+    FILE* mFile;
+    //  Filename
+    std::string mFilename;
 
-	// Cached file size
-	mutable size_t cachedSize;
+    // Cached file size
+    mutable size_t cachedSize;
 };
 
 
 // ----------------------------------------------------------------------------------
 inline DefaultIOStream::DefaultIOStream () :
-	mFile		(NULL),
-	mFilename	(""),
-	cachedSize	(SIZE_MAX)
+    mFile       (NULL),
+    mFilename   (""),
+    cachedSize  (SIZE_MAX)
 {
-	// empty
+    // empty
 }
 
 
 // ----------------------------------------------------------------------------------
 inline DefaultIOStream::DefaultIOStream (FILE* pFile,
-		const std::string &strFilename) :
-	mFile(pFile),
-	mFilename(strFilename),
-	cachedSize	(SIZE_MAX)
+        const std::string &strFilename) :
+    mFile(pFile),
+    mFilename(strFilename),
+    cachedSize  (SIZE_MAX)
 {
-	// empty
+    // empty
 }
 // ----------------------------------------------------------------------------------
 

+ 51 - 51
code/DefaultIOSystem.cpp

@@ -60,47 +60,47 @@ using namespace Assimp;
 // Constructor.
 DefaultIOSystem::DefaultIOSystem()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor.
 DefaultIOSystem::~DefaultIOSystem()
 {
-	// nothing to do here
+    // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Tests for the existence of a file at the given path.
 bool DefaultIOSystem::Exists( const char* pFile) const
 {
-	FILE* file = ::fopen( pFile, "rb");
-	if( !file)
-		return false;
+    FILE* file = ::fopen( pFile, "rb");
+    if( !file)
+        return false;
 
-	::fclose( file);
-	return true;
+    ::fclose( file);
+    return true;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Open a new file with a given path.
 IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
 {
-	ai_assert(NULL != strFile);
-	ai_assert(NULL != strMode);
+    ai_assert(NULL != strFile);
+    ai_assert(NULL != strMode);
 
-	FILE* file = ::fopen( strFile, strMode);
-	if( NULL == file)
-		return NULL;
+    FILE* file = ::fopen( strFile, strMode);
+    if( NULL == file)
+        return NULL;
 
-	return new DefaultIOStream(file, (std::string) strFile);
+    return new DefaultIOStream(file, (std::string) strFile);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Closes the given file and releases all resources associated with it.
 void DefaultIOSystem::Close( IOStream* pFile)
 {
-	delete pFile;
+    delete pFile;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -108,9 +108,9 @@ void DefaultIOSystem::Close( IOStream* pFile)
 char DefaultIOSystem::getOsSeparator() const
 {
 #ifndef _WIN32
-	return '/';
+    return '/';
 #else
-	return '\\';
+    return '\\';
 #endif
 }
 
@@ -118,80 +118,80 @@ char DefaultIOSystem::getOsSeparator() const
 // IOSystem default implementation (ComparePaths isn't a pure virtual function)
 bool IOSystem::ComparePaths (const char* one, const char* second) const
 {
-	return !ASSIMP_stricmp(one,second);
+    return !ASSIMP_stricmp(one,second);
 }
 
 // maximum path length
 // XXX http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
 #ifdef PATH_MAX
-#	define PATHLIMIT PATH_MAX
+#   define PATHLIMIT PATH_MAX
 #else
-#	define PATHLIMIT 4096
+#   define PATHLIMIT 4096
 #endif
 
 // ------------------------------------------------------------------------------------------------
 // Convert a relative path into an absolute path
 inline void MakeAbsolutePath (const char* in, char* _out)
 {
-	ai_assert(in && _out);
-	char* ret;
+    ai_assert(in && _out);
+    char* ret;
 #ifdef _WIN32
-	ret = ::_fullpath(_out, in,PATHLIMIT);
+    ret = ::_fullpath(_out, in,PATHLIMIT);
 #else
-    	// use realpath
-    	ret = realpath(in, _out);
+        // use realpath
+        ret = realpath(in, _out);
 #endif
-	if(!ret) {
-		// preserve the input path, maybe someone else is able to fix
-		// the path before it is accessed (e.g. our file system filter)
-		DefaultLogger::get()->warn("Invalid path: "+std::string(in));
-		strcpy(_out,in);
-	}
+    if(!ret) {
+        // preserve the input path, maybe someone else is able to fix
+        // the path before it is accessed (e.g. our file system filter)
+        DefaultLogger::get()->warn("Invalid path: "+std::string(in));
+        strcpy(_out,in);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 // DefaultIOSystem's more specialized implementation
 bool DefaultIOSystem::ComparePaths (const char* one, const char* second) const
 {
-	// chances are quite good both paths are formatted identically,
-	// so we can hopefully return here already
-	if( !ASSIMP_stricmp(one,second) )
-		return true;
+    // chances are quite good both paths are formatted identically,
+    // so we can hopefully return here already
+    if( !ASSIMP_stricmp(one,second) )
+        return true;
 
-	char temp1[PATHLIMIT];
-	char temp2[PATHLIMIT];
+    char temp1[PATHLIMIT];
+    char temp2[PATHLIMIT];
 
-	MakeAbsolutePath (one, temp1);
-	MakeAbsolutePath (second, temp2);
+    MakeAbsolutePath (one, temp1);
+    MakeAbsolutePath (second, temp2);
 
-	return !ASSIMP_stricmp(temp1,temp2);
+    return !ASSIMP_stricmp(temp1,temp2);
 }
 
 
 std::string DefaultIOSystem::fileName(std::string path)
 {
-	std::string ret = path;
-	std::size_t last = ret.find_last_of("\\/");
-	if (last != std::string::npos) ret = ret.substr(last + 1);
-	return ret;
+    std::string ret = path;
+    std::size_t last = ret.find_last_of("\\/");
+    if (last != std::string::npos) ret = ret.substr(last + 1);
+    return ret;
 }
 
 
 std::string DefaultIOSystem::completeBaseName(std::string path)
 {
-	std::string ret = fileName(path);
-	std::size_t pos = ret.find_last_of('.');
-	if(pos != ret.npos) ret = ret.substr(0, pos);
-	return ret;
+    std::string ret = fileName(path);
+    std::size_t pos = ret.find_last_of('.');
+    if(pos != ret.npos) ret = ret.substr(0, pos);
+    return ret;
 }
 
 
 std::string DefaultIOSystem::absolutePath(std::string path)
 {
-	std::string ret = path;
-	std::size_t last = ret.find_last_of("\\/");
-	if (last != std::string::npos) ret = ret.substr(0, last);
-	return ret;
+    std::string ret = path;
+    std::size_t last = ret.find_last_of("\\/");
+    if (last != std::string::npos) ret = ret.substr(0, last);
+    return ret;
 }
 
 #undef PATHLIMIT

+ 31 - 31
code/DefaultIOSystem.h

@@ -44,53 +44,53 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "../include/assimp/IOSystem.hpp"
 
-namespace Assimp	{
+namespace Assimp    {
 
 // ---------------------------------------------------------------------------
 /** Default implementation of IOSystem using the standard C file functions */
 class DefaultIOSystem : public IOSystem
 {
 public:
-	/** Constructor. */
+    /** Constructor. */
     DefaultIOSystem();
 
-	/** Destructor. */
-	~DefaultIOSystem();
+    /** Destructor. */
+    ~DefaultIOSystem();
 
-	// -------------------------------------------------------------------
-	/** Tests for the existence of a file at the given path. */
-	bool Exists( const char* pFile) const;
+    // -------------------------------------------------------------------
+    /** Tests for the existence of a file at the given path. */
+    bool Exists( const char* pFile) const;
 
-	// -------------------------------------------------------------------
-	/** Returns the directory separator. */
-	char getOsSeparator() const;
+    // -------------------------------------------------------------------
+    /** Returns the directory separator. */
+    char getOsSeparator() const;
 
-	// -------------------------------------------------------------------
-	/** Open a new file with a given path. */
-	IOStream* Open( const char* pFile, const char* pMode = "rb");
+    // -------------------------------------------------------------------
+    /** Open a new file with a given path. */
+    IOStream* Open( const char* pFile, const char* pMode = "rb");
 
-	// -------------------------------------------------------------------
-	/** Closes the given file and releases all resources associated with it. */
-	void Close( IOStream* pFile);
+    // -------------------------------------------------------------------
+    /** Closes the given file and releases all resources associated with it. */
+    void Close( IOStream* pFile);
 
-	// -------------------------------------------------------------------
-	/** Compare two paths */
-	bool ComparePaths (const char* one, const char* second) const;
+    // -------------------------------------------------------------------
+    /** Compare two paths */
+    bool ComparePaths (const char* one, const char* second) const;
 
-	/** @brief get the file name of a full filepath
-	 * example: /tmp/archive.tar.gz -> archive.tar.gz
-	 */
-	static std::string fileName(std::string path);
+    /** @brief get the file name of a full filepath
+     * example: /tmp/archive.tar.gz -> archive.tar.gz
+     */
+    static std::string fileName(std::string path);
 
-	/** @brief get the complete base name of a full filepath
-	 * example: /tmp/archive.tar.gz -> archive.tar
-	 */
-	static std::string completeBaseName(std::string path);
+    /** @brief get the complete base name of a full filepath
+     * example: /tmp/archive.tar.gz -> archive.tar
+     */
+    static std::string completeBaseName(std::string path);
 
-	/** @brief get the path of a full filepath
-	 * example: /tmp/archive.tar.gz -> /tmp/
-	 */
-	static std::string absolutePath(std::string path);
+    /** @brief get the path of a full filepath
+     * example: /tmp/archive.tar.gz -> /tmp/
+     */
+    static std::string absolutePath(std::string path);
 };
 
 } //!ns Assimp

+ 221 - 221
code/DefaultLogger.cpp

@@ -56,13 +56,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <stdio.h>
 
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-#	include <boost/thread/thread.hpp>
-#	include <boost/thread/mutex.hpp>
+#   include <boost/thread/thread.hpp>
+#   include <boost/thread/mutex.hpp>
 
 boost::mutex loggerMutex;
 #endif
 
-namespace Assimp	{
+namespace Assimp    {
 
 // ----------------------------------------------------------------------------------
 NullLogger DefaultLogger::s_pNullLogger;
@@ -74,347 +74,347 @@ static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::War
 // Represents a log-stream + its error severity
 struct LogStreamInfo
 {
-	unsigned int m_uiErrorSeverity;
-	LogStream *m_pStream;
-
-	// Constructor
-	LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
-		m_uiErrorSeverity( uiErrorSev ),
-		m_pStream( pStream )
-	{
-		// empty
-	}
-
-	// Destructor
-	~LogStreamInfo()
-	{
-		delete m_pStream;
-	}
+    unsigned int m_uiErrorSeverity;
+    LogStream *m_pStream;
+
+    // Constructor
+    LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
+        m_uiErrorSeverity( uiErrorSev ),
+        m_pStream( pStream )
+    {
+        // empty
+    }
+
+    // Destructor
+    ~LogStreamInfo()
+    {
+        delete m_pStream;
+    }
 };
 
 // ----------------------------------------------------------------------------------
 // Construct a default log stream
-LogStream* LogStream::createDefaultStream(aiDefaultLogStream	streams,
-	const char* name /*= "AssimpLog.txt"*/,
-	IOSystem* io		    /*= NULL*/)
+LogStream* LogStream::createDefaultStream(aiDefaultLogStream    streams,
+    const char* name /*= "AssimpLog.txt"*/,
+    IOSystem* io            /*= NULL*/)
 {
-	switch (streams)
-	{
-		// This is a platform-specific feature
-	case aiDefaultLogStream_DEBUGGER:
+    switch (streams)
+    {
+        // This is a platform-specific feature
+    case aiDefaultLogStream_DEBUGGER:
 #ifdef WIN32
-		return new Win32DebugLogStream();
+        return new Win32DebugLogStream();
 #else
-		return NULL;
+        return NULL;
 #endif
 
-		// Platform-independent default streams
-	case aiDefaultLogStream_STDERR:
-		return new StdOStreamLogStream(std::cerr);
-	case aiDefaultLogStream_STDOUT:
-		return new StdOStreamLogStream(std::cout);
-	case aiDefaultLogStream_FILE:
-		return (name && *name ? new FileLogStream(name,io) : NULL);
-	default:
-		// We don't know this default log stream, so raise an assertion
-		ai_assert(false);
-
-	};
-
-	// For compilers without dead code path detection
-	return NULL;
+        // Platform-independent default streams
+    case aiDefaultLogStream_STDERR:
+        return new StdOStreamLogStream(std::cerr);
+    case aiDefaultLogStream_STDOUT:
+        return new StdOStreamLogStream(std::cout);
+    case aiDefaultLogStream_FILE:
+        return (name && *name ? new FileLogStream(name,io) : NULL);
+    default:
+        // We don't know this default log stream, so raise an assertion
+        ai_assert(false);
+
+    };
+
+    // For compilers without dead code path detection
+    return NULL;
 }
 
 // ----------------------------------------------------------------------------------
-//	Creates the only singleton instance
+//  Creates the only singleton instance
 Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
-	LogSeverity severity                       /*= NORMAL*/,
-	unsigned int defStreams                    /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
-	IOSystem* io		                       /*= NULL*/)
+    LogSeverity severity                       /*= NORMAL*/,
+    unsigned int defStreams                    /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
+    IOSystem* io                               /*= NULL*/)
 {
-	// enter the mutex here to avoid concurrency problems
+    // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-	boost::mutex::scoped_lock lock(loggerMutex);
+    boost::mutex::scoped_lock lock(loggerMutex);
 #endif
 
-	if (m_pLogger && !isNullLogger() )
-		delete m_pLogger;
+    if (m_pLogger && !isNullLogger() )
+        delete m_pLogger;
 
-	m_pLogger = new DefaultLogger( severity );
+    m_pLogger = new DefaultLogger( severity );
 
-	// Attach default log streams
-	// Stream the log to the MSVC debugger?
-	if (defStreams & aiDefaultLogStream_DEBUGGER)
-		m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_DEBUGGER));
+    // Attach default log streams
+    // Stream the log to the MSVC debugger?
+    if (defStreams & aiDefaultLogStream_DEBUGGER)
+        m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_DEBUGGER));
 
-	// Stream the log to COUT?
-	if (defStreams & aiDefaultLogStream_STDOUT)
-		m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDOUT));
+    // Stream the log to COUT?
+    if (defStreams & aiDefaultLogStream_STDOUT)
+        m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDOUT));
 
-	// Stream the log to CERR?
-	if (defStreams & aiDefaultLogStream_STDERR)
-		 m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDERR));
+    // Stream the log to CERR?
+    if (defStreams & aiDefaultLogStream_STDERR)
+         m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDERR));
 
-	// Stream the log to a file
-	if (defStreams & aiDefaultLogStream_FILE && name && *name)
-		m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_FILE,name,io));
+    // Stream the log to a file
+    if (defStreams & aiDefaultLogStream_FILE && name && *name)
+        m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_FILE,name,io));
 
-	return m_pLogger;
+    return m_pLogger;
 }
 
 // ----------------------------------------------------------------------------------
-void Logger::debug(const char* message)	{
-
-	// SECURITY FIX: otherwise it's easy to produce overruns since
-	// sometimes importers will include data from the input file
-	// (i.e. node names) in their messages.
-	if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
-		return;
-	}
-	return OnDebug(message);
+void Logger::debug(const char* message) {
+
+    // SECURITY FIX: otherwise it's easy to produce overruns since
+    // sometimes importers will include data from the input file
+    // (i.e. node names) in their messages.
+    if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
+        return;
+    }
+    return OnDebug(message);
 }
 
 // ----------------------------------------------------------------------------------
-void Logger::info(const char* message)	{
+void Logger::info(const char* message)  {
 
-	// SECURITY FIX: see above
-	if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
-		return;
-	}
-	return OnInfo(message);
+    // SECURITY FIX: see above
+    if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
+        return;
+    }
+    return OnInfo(message);
 }
 
 // ----------------------------------------------------------------------------------
-void Logger::warn(const char* message)	{
+void Logger::warn(const char* message)  {
 
-	// SECURITY FIX: see above
-	if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
-		return;
-	}
-	return OnWarn(message);
+    // SECURITY FIX: see above
+    if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
+        return;
+    }
+    return OnWarn(message);
 }
 
 // ----------------------------------------------------------------------------------
-void Logger::error(const char* message)	{
+void Logger::error(const char* message) {
 
-	// SECURITY FIX: see above
-	if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
-		return;
-	}
-	return OnError(message);
+    // SECURITY FIX: see above
+    if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
+        return;
+    }
+    return OnError(message);
 }
 
 // ----------------------------------------------------------------------------------
 void DefaultLogger::set( Logger *logger )
 {
-	// enter the mutex here to avoid concurrency problems
+    // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-	boost::mutex::scoped_lock lock(loggerMutex);
+    boost::mutex::scoped_lock lock(loggerMutex);
 #endif
 
-	if (!logger)logger = &s_pNullLogger;
-	if (m_pLogger && !isNullLogger() )
-		delete m_pLogger;
+    if (!logger)logger = &s_pNullLogger;
+    if (m_pLogger && !isNullLogger() )
+        delete m_pLogger;
 
-	DefaultLogger::m_pLogger = logger;
+    DefaultLogger::m_pLogger = logger;
 }
 
 // ----------------------------------------------------------------------------------
 bool DefaultLogger::isNullLogger()
 {
-	return m_pLogger == &s_pNullLogger;
+    return m_pLogger == &s_pNullLogger;
 }
 
 // ----------------------------------------------------------------------------------
-//	Singleton getter
+//  Singleton getter
 Logger *DefaultLogger::get()
 {
-	return m_pLogger;
+    return m_pLogger;
 }
 
 // ----------------------------------------------------------------------------------
-//	Kills the only instance
+//  Kills the only instance
 void DefaultLogger::kill()
 {
-	// enter the mutex here to avoid concurrency problems
+    // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
-	boost::mutex::scoped_lock lock(loggerMutex);
+    boost::mutex::scoped_lock lock(loggerMutex);
 #endif
 
-	if (m_pLogger == &s_pNullLogger)return;
-	delete m_pLogger;
-	m_pLogger = &s_pNullLogger;
+    if (m_pLogger == &s_pNullLogger)return;
+    delete m_pLogger;
+    m_pLogger = &s_pNullLogger;
 }
 
 // ----------------------------------------------------------------------------------
-//	Debug message
+//  Debug message
 void DefaultLogger::OnDebug( const char* message )
 {
-	if ( m_Severity == Logger::NORMAL )
-		return;
+    if ( m_Severity == Logger::NORMAL )
+        return;
 
-	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
-	::sprintf(msg,"Debug, T%u: %s", GetThreadID(), message );
+    char msg[MAX_LOG_MESSAGE_LENGTH + 16];
+    ::sprintf(msg,"Debug, T%u: %s", GetThreadID(), message );
 
-	WriteToStreams( msg, Logger::Debugging );
+    WriteToStreams( msg, Logger::Debugging );
 }
 
 // ----------------------------------------------------------------------------------
-//	Logs an info
+//  Logs an info
 void DefaultLogger::OnInfo( const char* message )
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
-	::sprintf(msg,"Info,  T%u: %s", GetThreadID(), message );
+    char msg[MAX_LOG_MESSAGE_LENGTH + 16];
+    ::sprintf(msg,"Info,  T%u: %s", GetThreadID(), message );
 
-	WriteToStreams( msg , Logger::Info );
+    WriteToStreams( msg , Logger::Info );
 }
 
 // ----------------------------------------------------------------------------------
-//	Logs a warning
+//  Logs a warning
 void DefaultLogger::OnWarn( const char* message )
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
-	::sprintf(msg,"Warn,  T%u: %s", GetThreadID(), message );
+    char msg[MAX_LOG_MESSAGE_LENGTH + 16];
+    ::sprintf(msg,"Warn,  T%u: %s", GetThreadID(), message );
 
-	WriteToStreams( msg, Logger::Warn );
+    WriteToStreams( msg, Logger::Warn );
 }
 
 // ----------------------------------------------------------------------------------
-//	Logs an error
+//  Logs an error
 void DefaultLogger::OnError( const char* message )
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
-	::sprintf(msg,"Error, T%u: %s", GetThreadID(), message );
+    char msg[MAX_LOG_MESSAGE_LENGTH + 16];
+    ::sprintf(msg,"Error, T%u: %s", GetThreadID(), message );
 
-	WriteToStreams( msg, Logger::Err );
+    WriteToStreams( msg, Logger::Err );
 }
 
 // ----------------------------------------------------------------------------------
-//	Will attach a new stream
+//  Will attach a new stream
 bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
 {
-	if (!pStream)
-		return false;
-
-	if (0 == severity)	{
-		severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
-	}
-
-	for ( StreamIt it = m_StreamArray.begin();
-		it != m_StreamArray.end();
-		++it )
-	{
-		if ( (*it)->m_pStream == pStream )
-		{
-			(*it)->m_uiErrorSeverity |= severity;
-			return true;
-		}
-	}
-
-	LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream );
-	m_StreamArray.push_back( pInfo );
-	return true;
+    if (!pStream)
+        return false;
+
+    if (0 == severity)  {
+        severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
+    }
+
+    for ( StreamIt it = m_StreamArray.begin();
+        it != m_StreamArray.end();
+        ++it )
+    {
+        if ( (*it)->m_pStream == pStream )
+        {
+            (*it)->m_uiErrorSeverity |= severity;
+            return true;
+        }
+    }
+
+    LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream );
+    m_StreamArray.push_back( pInfo );
+    return true;
 }
 
 // ----------------------------------------------------------------------------------
-//	Detatch a stream
+//  Detatch a stream
 bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
 {
-	if (!pStream)
-		return false;
-
-	if (0 == severity)	{
-		severity = SeverityAll;
-	}
-
-	for ( StreamIt it = m_StreamArray.begin();
-		it != m_StreamArray.end();
-		++it )
-	{
-		if ( (*it)->m_pStream == pStream )
-		{
-			(*it)->m_uiErrorSeverity &= ~severity;
-			if ( (*it)->m_uiErrorSeverity == 0 )
-			{
-				// don't delete the underlying stream 'cause the caller gains ownership again
-				(**it).m_pStream = NULL;
-				delete *it;
-				m_StreamArray.erase( it );
-				break;
-			}
-			return true;
-		}
-	}
-	return false;
+    if (!pStream)
+        return false;
+
+    if (0 == severity)  {
+        severity = SeverityAll;
+    }
+
+    for ( StreamIt it = m_StreamArray.begin();
+        it != m_StreamArray.end();
+        ++it )
+    {
+        if ( (*it)->m_pStream == pStream )
+        {
+            (*it)->m_uiErrorSeverity &= ~severity;
+            if ( (*it)->m_uiErrorSeverity == 0 )
+            {
+                // don't delete the underlying stream 'cause the caller gains ownership again
+                (**it).m_pStream = NULL;
+                delete *it;
+                m_StreamArray.erase( it );
+                break;
+            }
+            return true;
+        }
+    }
+    return false;
 }
 
 // ----------------------------------------------------------------------------------
-//	Constructor
+//  Constructor
 DefaultLogger::DefaultLogger(LogSeverity severity)
 
-	:	Logger	( severity )
-	,	noRepeatMsg	(false)
-	,	lastLen( 0 )
+    :   Logger  ( severity )
+    ,   noRepeatMsg (false)
+    ,   lastLen( 0 )
 {
-	lastMsg[0] = '\0';
+    lastMsg[0] = '\0';
 }
 
 // ----------------------------------------------------------------------------------
-//	Destructor
+//  Destructor
 DefaultLogger::~DefaultLogger()
 {
-	for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
-		// also frees the underlying stream, we are its owner.
-		delete *it;
-	}
+    for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
+        // also frees the underlying stream, we are its owner.
+        delete *it;
+    }
 }
 
 // ----------------------------------------------------------------------------------
-//	Writes message to stream
+//  Writes message to stream
 void DefaultLogger::WriteToStreams(const char *message,
-	ErrorSeverity ErrorSev )
+    ErrorSeverity ErrorSev )
 {
-	ai_assert(NULL != message);
-
-	// Check whether this is a repeated message
-	if (! ::strncmp( message,lastMsg, lastLen-1))
-	{
-		if (!noRepeatMsg)
-		{
-			noRepeatMsg = true;
-			message = "Skipping one or more lines with the same contents\n";
-		}
-		else return;
-	}
-	else
-	{
-		// append a new-line character to the message to be printed
-		lastLen = ::strlen(message);
-		::memcpy(lastMsg,message,lastLen+1);
-		::strcat(lastMsg+lastLen,"\n");
-
-		message = lastMsg;
-		noRepeatMsg = false;
-		++lastLen;
-	}
-	for ( ConstStreamIt it = m_StreamArray.begin();
-		it != m_StreamArray.end();
-		++it)
-	{
-		if ( ErrorSev & (*it)->m_uiErrorSeverity )
-			(*it)->m_pStream->write( message);
-	}
+    ai_assert(NULL != message);
+
+    // Check whether this is a repeated message
+    if (! ::strncmp( message,lastMsg, lastLen-1))
+    {
+        if (!noRepeatMsg)
+        {
+            noRepeatMsg = true;
+            message = "Skipping one or more lines with the same contents\n";
+        }
+        else return;
+    }
+    else
+    {
+        // append a new-line character to the message to be printed
+        lastLen = ::strlen(message);
+        ::memcpy(lastMsg,message,lastLen+1);
+        ::strcat(lastMsg+lastLen,"\n");
+
+        message = lastMsg;
+        noRepeatMsg = false;
+        ++lastLen;
+    }
+    for ( ConstStreamIt it = m_StreamArray.begin();
+        it != m_StreamArray.end();
+        ++it)
+    {
+        if ( ErrorSev & (*it)->m_uiErrorSeverity )
+            (*it)->m_pStream->write( message);
+    }
 }
 
 // ----------------------------------------------------------------------------------
-//	Returns thread id, if not supported only a zero will be returned.
+//  Returns thread id, if not supported only a zero will be returned.
 unsigned int DefaultLogger::GetThreadID()
 {
-	// fixme: we can get this value via boost::threads
+    // fixme: we can get this value via boost::threads
 #ifdef WIN32
-	return (unsigned int)::GetCurrentThreadId();
+    return (unsigned int)::GetCurrentThreadId();
 #else
-	return 0; // not supported
+    return 0; // not supported
 #endif
 }
 

+ 5 - 5
code/DefaultProgressHandler.h

@@ -45,17 +45,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_DEFAULTPROGRESSHANDLER_H
 
 #include "../include/assimp/ProgressHandler.hpp"
-namespace Assimp	{
+namespace Assimp    {
 
 // ------------------------------------------------------------------------------------
 /** @brief Internal default implementation of the #ProgressHandler interface. */
 class DefaultProgressHandler
-	: public ProgressHandler	{
+    : public ProgressHandler    {
 
 
-	virtual bool Update(float /*percentage*/) {
-		return false;
-	}
+    virtual bool Update(float /*percentage*/) {
+        return false;
+    }
 
 
 }; // !class DefaultProgressHandler

+ 2 - 2
code/Defines.h

@@ -40,10 +40,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // We need those constants, workaround for any platforms where nobody defined them yet
 #if (!defined SIZE_MAX)
-#	define SIZE_MAX (~((size_t)0))
+#   define SIZE_MAX (~((size_t)0))
 #endif
 
 #if (!defined UINT_MAX)
-#	define UINT_MAX (~((unsigned int)0))
+#   define UINT_MAX (~((unsigned int)0))
 #endif
 

+ 36 - 36
code/Exceptional.h

@@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using std::runtime_error;
 
 #ifdef _MSC_VER
-#	pragma warning(disable : 4275)
+#   pragma warning(disable : 4275)
 #endif
 
 // ---------------------------------------------------------------------------
@@ -54,14 +54,14 @@ using std::runtime_error;
  *  unrecoverable error occurs while importing. Loading APIs return
  *  NULL instead of a valid aiScene then.  */
 class DeadlyImportError
-	: public runtime_error
+    : public runtime_error
 {
 public:
-	/** Constructor with arguments */
-	explicit DeadlyImportError( const std::string& pErrorText)
-		: runtime_error(pErrorText)
-	{
-	}
+    /** Constructor with arguments */
+    explicit DeadlyImportError( const std::string& pErrorText)
+        : runtime_error(pErrorText)
+    {
+    }
 
 private:
 };
@@ -69,57 +69,57 @@ private:
 typedef DeadlyImportError DeadlyExportError;
 
 #ifdef _MSC_VER
-#	pragma warning(default : 4275)
+#   pragma warning(default : 4275)
 #endif
 
 // ---------------------------------------------------------------------------
 template <typename T>
-struct ExceptionSwallower	{
-	T operator ()() const {
-		return T();
-	}
+struct ExceptionSwallower   {
+    T operator ()() const {
+        return T();
+    }
 };
 
 // ---------------------------------------------------------------------------
 template <typename T>
-struct ExceptionSwallower<T*>	{
-	T* operator ()() const {
-		return NULL;
-	}
+struct ExceptionSwallower<T*>   {
+    T* operator ()() const {
+        return NULL;
+    }
 };
 
 // ---------------------------------------------------------------------------
 template <>
-struct ExceptionSwallower<aiReturn>	{
-	aiReturn operator ()() const {
-		try {
-			throw;
-		}
-		catch (std::bad_alloc&) {
-			return aiReturn_OUTOFMEMORY;
-		}
-		catch (...) {
-			return aiReturn_FAILURE;
-		}
-	}
+struct ExceptionSwallower<aiReturn> {
+    aiReturn operator ()() const {
+        try {
+            throw;
+        }
+        catch (std::bad_alloc&) {
+            return aiReturn_OUTOFMEMORY;
+        }
+        catch (...) {
+            return aiReturn_FAILURE;
+        }
+    }
 };
 
 // ---------------------------------------------------------------------------
 template <>
-struct ExceptionSwallower<void>	{
-	void operator ()() const {
-		return;
-	}
+struct ExceptionSwallower<void> {
+    void operator ()() const {
+        return;
+    }
 };
 
 #define ASSIMP_BEGIN_EXCEPTION_REGION()\
 {\
-	try {
+    try {
 
 #define ASSIMP_END_EXCEPTION_REGION(type)\
-	} catch(...) {\
-		return ExceptionSwallower<type>()();\
-	}\
+    } catch(...) {\
+        return ExceptionSwallower<type>()();\
+    }\
 }
 
 #endif // INCLUDED_EXCEPTIONAL_H

+ 262 - 262
code/Exporter.cpp

@@ -95,52 +95,52 @@ void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportPrope
 Exporter::ExportFormatEntry gExporters[] =
 {
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
-	Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
+    Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_XFILE_EXPORTER
-	Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
-		aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
+    Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
+        aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
-	Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0),
+    Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
-	Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
-		aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */),
+    Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
+        aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_STL_EXPORTER
-	Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL,
-		aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
-	),
-	Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary,
-		aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
-	),
+    Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL,
+        aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
+    ),
+    Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary,
+        aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
+    ),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
-	Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly,
-		aiProcess_PreTransformVertices
-	),
-	Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
-		aiProcess_PreTransformVertices
-	),
+    Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly,
+        aiProcess_PreTransformVertices
+    ),
+    Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
+        aiProcess_PreTransformVertices
+    ),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
-	Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
-		aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
+    Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
+        aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
-	Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
+    Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
-	Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0),
+    Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0),
 #endif
 };
 
@@ -150,42 +150,42 @@ Exporter::ExportFormatEntry gExporters[] =
 class ExporterPimpl {
 public:
 
-	ExporterPimpl()
-		: blob()
-		, mIOSystem(new Assimp::DefaultIOSystem())
-		, mIsDefaultIOHandler(true)
-	{
-		GetPostProcessingStepInstanceList(mPostProcessingSteps);
+    ExporterPimpl()
+        : blob()
+        , mIOSystem(new Assimp::DefaultIOSystem())
+        , mIsDefaultIOHandler(true)
+    {
+        GetPostProcessingStepInstanceList(mPostProcessingSteps);
 
-		// grab all builtin exporters
-		mExporters.resize(ASSIMP_NUM_EXPORTERS);
-		std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin());
-	}
+        // grab all builtin exporters
+        mExporters.resize(ASSIMP_NUM_EXPORTERS);
+        std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin());
+    }
 
-	~ExporterPimpl()
-	{
-		delete blob;
+    ~ExporterPimpl()
+    {
+        delete blob;
 
-		// Delete all post-processing plug-ins
-		for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
-			delete mPostProcessingSteps[a];
-		}
-	}
+        // Delete all post-processing plug-ins
+        for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
+            delete mPostProcessingSteps[a];
+        }
+    }
 
 public:
 
-	aiExportDataBlob* blob;
-	boost::shared_ptr< Assimp::IOSystem > mIOSystem;
-	bool mIsDefaultIOHandler;
+    aiExportDataBlob* blob;
+    boost::shared_ptr< Assimp::IOSystem > mIOSystem;
+    bool mIsDefaultIOHandler;
 
-	/** Post processing steps we can apply at the imported data. */
-	std::vector< BaseProcess* > mPostProcessingSteps;
+    /** Post processing steps we can apply at the imported data. */
+    std::vector< BaseProcess* > mPostProcessingSteps;
 
-	/** Last fatal export error */
-	std::string mError;
+    /** Last fatal export error */
+    std::string mError;
 
-	/** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
-	std::vector<Exporter::ExportFormatEntry> mExporters;
+    /** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
+    std::vector<Exporter::ExportFormatEntry> mExporters;
 };
 
 
@@ -208,306 +208,306 @@ Exporter :: Exporter()
 // ------------------------------------------------------------------------------------------------
 Exporter :: ~Exporter()
 {
-	FreeBlob();
+    FreeBlob();
 
-	delete pimpl;
+    delete pimpl;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void Exporter :: SetIOHandler( IOSystem* pIOHandler)
 {
-	pimpl->mIsDefaultIOHandler = !pIOHandler;
-	pimpl->mIOSystem.reset(pIOHandler);
+    pimpl->mIsDefaultIOHandler = !pIOHandler;
+    pimpl->mIOSystem.reset(pIOHandler);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 IOSystem* Exporter :: GetIOHandler() const
 {
-	return pimpl->mIOSystem.get();
+    return pimpl->mIOSystem.get();
 }
 
 
 // ------------------------------------------------------------------------------------------------
 bool Exporter :: IsDefaultIOHandler() const
 {
-	return pimpl->mIsDefaultIOHandler;
+    return pimpl->mIsDefaultIOHandler;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const aiExportDataBlob* Exporter :: ExportToBlob(  const aiScene* pScene, const char* pFormatId, unsigned int, const ExportProperties* pProperties)
 {
-	if (pimpl->blob) {
-		delete pimpl->blob;
-		pimpl->blob = NULL;
-	}
+    if (pimpl->blob) {
+        delete pimpl->blob;
+        pimpl->blob = NULL;
+    }
 
 
-	boost::shared_ptr<IOSystem> old = pimpl->mIOSystem;
+    boost::shared_ptr<IOSystem> old = pimpl->mIOSystem;
 
-	BlobIOSystem* blobio = new BlobIOSystem();
-	pimpl->mIOSystem = boost::shared_ptr<IOSystem>( blobio );
+    BlobIOSystem* blobio = new BlobIOSystem();
+    pimpl->mIOSystem = boost::shared_ptr<IOSystem>( blobio );
 
-	if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
-		pimpl->mIOSystem = old;
-		return NULL;
-	}
+    if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
+        pimpl->mIOSystem = old;
+        return NULL;
+    }
 
-	pimpl->blob = blobio->GetBlobChain();
-	pimpl->mIOSystem = old;
+    pimpl->blob = blobio->GetBlobChain();
+    pimpl->mIOSystem = old;
 
-	return pimpl->blob;
+    return pimpl->blob;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 bool IsVerboseFormat(const aiMesh* mesh)
 {
-	// avoid slow vector<bool> specialization
-	std::vector<unsigned int> seen(mesh->mNumVertices,0);
-	for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
-		const aiFace& f = mesh->mFaces[i];
-		for(unsigned int j = 0; j < f.mNumIndices; ++j) {
-			if(++seen[f.mIndices[j]] == 2) {
-				// found a duplicate index
-				return false;
-			}
-		}
-	}
-	return true;
+    // avoid slow vector<bool> specialization
+    std::vector<unsigned int> seen(mesh->mNumVertices,0);
+    for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
+        const aiFace& f = mesh->mFaces[i];
+        for(unsigned int j = 0; j < f.mNumIndices; ++j) {
+            if(++seen[f.mIndices[j]] == 2) {
+                // found a duplicate index
+                return false;
+            }
+        }
+    }
+    return true;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 bool IsVerboseFormat(const aiScene* pScene)
 {
-	for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
-		if(!IsVerboseFormat(pScene->mMeshes[i])) {
-			return false;
-		}
-	}
-	return true;
+    for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
+        if(!IsVerboseFormat(pScene->mMeshes[i])) {
+            return false;
+        }
+    }
+    return true;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties)
 {
-	ASSIMP_BEGIN_EXCEPTION_REGION();
-
-	// when they create scenes from scratch, users will likely create them not in verbose
-	// format. They will likely not be aware that there is a flag in the scene to indicate
-	// this, however. To avoid surprises and bug reports, we check for duplicates in
-	// meshes upfront.
-	const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);
-
-	pimpl->mError = "";
-	for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
-		const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
-		if (!strcmp(exp.mDescription.id,pFormatId)) {
-
-			try {
-
-				// Always create a full copy of the scene. We might optimize this one day,
-				// but for now it is the most pragmatic way.
-				aiScene* scenecopy_tmp;
-				SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
-
-				std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
-				const ScenePrivateData* const priv = ScenePriv(pScene);
-
-				// steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
-				// original state before the step was applied first. When checking which steps we don't need
-				// to run, those are excluded.
-				const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
-
-				// Erase all pp steps that were already applied to this scene
-				const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
-					? (priv->mPPStepsApplied & ~nonIdempotentSteps)
-					: 0u);
-
-				// If no extra postprocessing was specified, and we obtained this scene from an
-				// Assimp importer, apply the reverse steps automatically.
-				// TODO: either drop this, or document it. Otherwise it is just a bad surprise.
-				//if (!pPreprocessing && priv) {
-				//	pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
-				//}
-
-				// If the input scene is not in verbose format, but there is at least postprocessing step that relies on it,
-				// we need to run the MakeVerboseFormat step first.
-				bool must_join_again = false;
-				if (!is_verbose_format) {
-
-					bool verbosify = false;
-					for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
-						BaseProcess* const p = pimpl->mPostProcessingSteps[a];
-
-						if (p->IsActive(pp) && p->RequireVerboseFormat()) {
-							verbosify = true;
-							break;
-						}
-					}
-
-					if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
-						DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
-
-						MakeVerboseFormatProcess proc;
-						proc.Execute(scenecopy.get());
-
-						if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
-							must_join_again = true;
-						}
-					}
-				}
-
-				if (pp) {
-					// the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
-					{
-						FlipWindingOrderProcess step;
-						if (step.IsActive(pp)) {
-							step.Execute(scenecopy.get());
-						}
-					}
-
-					{
-						FlipUVsProcess step;
-						if (step.IsActive(pp)) {
-							step.Execute(scenecopy.get());
-						}
-					}
-
-					{
-						MakeLeftHandedProcess step;
-						if (step.IsActive(pp)) {
-							step.Execute(scenecopy.get());
-						}
-					}
-
-					// dispatch other processes
-					for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
-						BaseProcess* const p = pimpl->mPostProcessingSteps[a];
-
-						if (p->IsActive(pp)
-							&& !dynamic_cast<FlipUVsProcess*>(p)
-							&& !dynamic_cast<FlipWindingOrderProcess*>(p)
-							&& !dynamic_cast<MakeLeftHandedProcess*>(p)) {
-
-							p->Execute(scenecopy.get());
-						}
-					}
-					ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
-					ai_assert(privOut);
-
-					privOut->mPPStepsApplied |= pp;
-				}
-
-				if(must_join_again) {
-					JoinVerticesProcess proc;
-					proc.Execute(scenecopy.get());
-				}
-
-				ExportProperties emptyProperties;  // Never pass NULL ExportProperties so Exporters don't have to worry.
-				exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties);
-			}
-			catch (DeadlyExportError& err) {
-				pimpl->mError = err.what();
-				return AI_FAILURE;
-			}
-			return AI_SUCCESS;
-		}
-	}
-
-	pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
-	ASSIMP_END_EXCEPTION_REGION(aiReturn);
-	return AI_FAILURE;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // when they create scenes from scratch, users will likely create them not in verbose
+    // format. They will likely not be aware that there is a flag in the scene to indicate
+    // this, however. To avoid surprises and bug reports, we check for duplicates in
+    // meshes upfront.
+    const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);
+
+    pimpl->mError = "";
+    for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
+        const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
+        if (!strcmp(exp.mDescription.id,pFormatId)) {
+
+            try {
+
+                // Always create a full copy of the scene. We might optimize this one day,
+                // but for now it is the most pragmatic way.
+                aiScene* scenecopy_tmp;
+                SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
+
+                std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
+                const ScenePrivateData* const priv = ScenePriv(pScene);
+
+                // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
+                // original state before the step was applied first. When checking which steps we don't need
+                // to run, those are excluded.
+                const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
+
+                // Erase all pp steps that were already applied to this scene
+                const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
+                    ? (priv->mPPStepsApplied & ~nonIdempotentSteps)
+                    : 0u);
+
+                // If no extra postprocessing was specified, and we obtained this scene from an
+                // Assimp importer, apply the reverse steps automatically.
+                // TODO: either drop this, or document it. Otherwise it is just a bad surprise.
+                //if (!pPreprocessing && priv) {
+                //  pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
+                //}
+
+                // If the input scene is not in verbose format, but there is at least postprocessing step that relies on it,
+                // we need to run the MakeVerboseFormat step first.
+                bool must_join_again = false;
+                if (!is_verbose_format) {
+
+                    bool verbosify = false;
+                    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
+                        BaseProcess* const p = pimpl->mPostProcessingSteps[a];
+
+                        if (p->IsActive(pp) && p->RequireVerboseFormat()) {
+                            verbosify = true;
+                            break;
+                        }
+                    }
+
+                    if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
+                        DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
+
+                        MakeVerboseFormatProcess proc;
+                        proc.Execute(scenecopy.get());
+
+                        if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
+                            must_join_again = true;
+                        }
+                    }
+                }
+
+                if (pp) {
+                    // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
+                    {
+                        FlipWindingOrderProcess step;
+                        if (step.IsActive(pp)) {
+                            step.Execute(scenecopy.get());
+                        }
+                    }
+
+                    {
+                        FlipUVsProcess step;
+                        if (step.IsActive(pp)) {
+                            step.Execute(scenecopy.get());
+                        }
+                    }
+
+                    {
+                        MakeLeftHandedProcess step;
+                        if (step.IsActive(pp)) {
+                            step.Execute(scenecopy.get());
+                        }
+                    }
+
+                    // dispatch other processes
+                    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
+                        BaseProcess* const p = pimpl->mPostProcessingSteps[a];
+
+                        if (p->IsActive(pp)
+                            && !dynamic_cast<FlipUVsProcess*>(p)
+                            && !dynamic_cast<FlipWindingOrderProcess*>(p)
+                            && !dynamic_cast<MakeLeftHandedProcess*>(p)) {
+
+                            p->Execute(scenecopy.get());
+                        }
+                    }
+                    ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
+                    ai_assert(privOut);
+
+                    privOut->mPPStepsApplied |= pp;
+                }
+
+                if(must_join_again) {
+                    JoinVerticesProcess proc;
+                    proc.Execute(scenecopy.get());
+                }
+
+                ExportProperties emptyProperties;  // Never pass NULL ExportProperties so Exporters don't have to worry.
+                exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties);
+            }
+            catch (DeadlyExportError& err) {
+                pimpl->mError = err.what();
+                return AI_FAILURE;
+            }
+            return AI_SUCCESS;
+        }
+    }
+
+    pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
+    ASSIMP_END_EXCEPTION_REGION(aiReturn);
+    return AI_FAILURE;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const char* Exporter :: GetErrorString() const
 {
-	return pimpl->mError.c_str();
+    return pimpl->mError.c_str();
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void Exporter :: FreeBlob( )
 {
-	delete pimpl->blob;
-	pimpl->blob = NULL;
+    delete pimpl->blob;
+    pimpl->blob = NULL;
 
-	pimpl->mError = "";
+    pimpl->mError = "";
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const aiExportDataBlob* Exporter :: GetBlob() const
 {
-	return pimpl->blob;
+    return pimpl->blob;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const aiExportDataBlob* Exporter :: GetOrphanedBlob() const
 {
-	const aiExportDataBlob* tmp = pimpl->blob;
-	pimpl->blob = NULL;
-	return tmp;
+    const aiExportDataBlob* tmp = pimpl->blob;
+    pimpl->blob = NULL;
+    return tmp;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 size_t Exporter :: GetExportFormatCount() const
 {
-	return pimpl->mExporters.size();
+    return pimpl->mExporters.size();
 }
 
 // ------------------------------------------------------------------------------------------------
 const aiExportFormatDesc* Exporter :: GetExportFormatDescription( size_t pIndex ) const
 {
-	if (pIndex >= GetExportFormatCount()) {
-		return NULL;
-	}
+    if (pIndex >= GetExportFormatCount()) {
+        return NULL;
+    }
 
-	// Return from static storage if the requested index is built-in.
-	if (pIndex < sizeof(gExporters) / sizeof(gExporters[0])) {
-		return &gExporters[pIndex].mDescription;
-	}
+    // Return from static storage if the requested index is built-in.
+    if (pIndex < sizeof(gExporters) / sizeof(gExporters[0])) {
+        return &gExporters[pIndex].mDescription;
+    }
 
-	return &pimpl->mExporters[pIndex].mDescription;
+    return &pimpl->mExporters[pIndex].mDescription;
 }
 
 // ------------------------------------------------------------------------------------------------
 aiReturn Exporter :: RegisterExporter(const ExportFormatEntry& desc)
 {
-	BOOST_FOREACH(const ExportFormatEntry& e, pimpl->mExporters) {
-		if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
-			return aiReturn_FAILURE;
-		}
-	}
+    BOOST_FOREACH(const ExportFormatEntry& e, pimpl->mExporters) {
+        if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
+            return aiReturn_FAILURE;
+        }
+    }
 
-	pimpl->mExporters.push_back(desc);
-	return aiReturn_SUCCESS;
+    pimpl->mExporters.push_back(desc);
+    return aiReturn_SUCCESS;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void Exporter :: UnregisterExporter(const char* id)
 {
-	for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) {
-		if (!strcmp((*it).mDescription.id,id)) {
-			pimpl->mExporters.erase(it);
-			break;
-		}
-	}
+    for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) {
+        if (!strcmp((*it).mDescription.id,id)) {
+            pimpl->mExporters.erase(it);
+            break;
+        }
+    }
 }
 
 ExportProperties :: ExportProperties() {}
 
 ExportProperties::ExportProperties(const ExportProperties &other)
-	 : mIntProperties(other.mIntProperties),
+     : mIntProperties(other.mIntProperties),
    mFloatProperties(other.mFloatProperties),
    mStringProperties(other.mStringProperties),
    mMatrixProperties(other.mMatrixProperties)
@@ -520,95 +520,95 @@ ExportProperties::ExportProperties(const ExportProperties &other)
 // Set a configuration property
 bool ExportProperties :: SetPropertyInteger(const char* szName, int iValue)
 {
-	return SetGenericProperty<int>(mIntProperties, szName,iValue);
+    return SetGenericProperty<int>(mIntProperties, szName,iValue);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 bool ExportProperties :: SetPropertyFloat(const char* szName, float iValue)
 {
-	return SetGenericProperty<float>(mFloatProperties, szName,iValue);
+    return SetGenericProperty<float>(mFloatProperties, szName,iValue);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 bool ExportProperties :: SetPropertyString(const char* szName, const std::string& value)
 {
-	return SetGenericProperty<std::string>(mStringProperties, szName,value);
+    return SetGenericProperty<std::string>(mStringProperties, szName,value);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 bool ExportProperties :: SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
 {
-	return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
+    return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 int ExportProperties :: GetPropertyInteger(const char* szName,
-	int iErrorReturn /*= 0xffffffff*/) const
+    int iErrorReturn /*= 0xffffffff*/) const
 {
-	return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
+    return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 float ExportProperties :: GetPropertyFloat(const char* szName,
-	float iErrorReturn /*= 10e10*/) const
+    float iErrorReturn /*= 10e10*/) const
 {
-	return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
+    return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 const std::string ExportProperties :: GetPropertyString(const char* szName,
-	const std::string& iErrorReturn /*= ""*/) const
+    const std::string& iErrorReturn /*= ""*/) const
 {
-	return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
+    return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Has a configuration property
 const aiMatrix4x4 ExportProperties :: GetPropertyMatrix(const char* szName,
-	const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
+    const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
 {
-	return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
+    return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Has a configuration property
 bool ExportProperties :: HasPropertyInteger(const char* szName) const
 {
-	return HasGenericProperty<int>(mIntProperties, szName);
+    return HasGenericProperty<int>(mIntProperties, szName);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Has a configuration property
 bool ExportProperties :: HasPropertyBool(const char* szName) const
 {
-	return HasGenericProperty<int>(mIntProperties, szName);
+    return HasGenericProperty<int>(mIntProperties, szName);
 };
 
 // ------------------------------------------------------------------------------------------------
 // Has a configuration property
 bool ExportProperties :: HasPropertyFloat(const char* szName) const
 {
-	return HasGenericProperty<float>(mFloatProperties, szName);
+    return HasGenericProperty<float>(mFloatProperties, szName);
 };
 
 // ------------------------------------------------------------------------------------------------
 // Has a configuration property
 bool ExportProperties :: HasPropertyString(const char* szName) const
 {
-	return HasGenericProperty<std::string>(mStringProperties, szName);
+    return HasGenericProperty<std::string>(mStringProperties, szName);
 };
 
 // ------------------------------------------------------------------------------------------------
 // Has a configuration property
 bool ExportProperties :: HasPropertyMatrix(const char* szName) const
 {
-	return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
+    return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
 };
 
 

+ 180 - 180
code/FBXAnimation.cpp

@@ -56,37 +56,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	using namespace Util;
+    using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
 AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
 : Object(id, element, name)
 {
-	const Scope& sc = GetRequiredScope(element);
-	const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
-	const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
-
-	ParseVectorDataArray(keys, KeyTime);
-	ParseVectorDataArray(values, KeyValueFloat);
-
-	if(keys.size() != values.size()) {
-		DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
-	}
-
-	// check if the key times are well-ordered
-	if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
-		DOMError("the keyframes are not in ascending order",&KeyTime);
-	}
-
-	const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
-	if(KeyAttrDataFloat) {
-		ParseVectorDataArray(attributes, *KeyAttrDataFloat);
-	}
-
-	const Element* KeyAttrFlags = sc["KeyAttrFlags"];
-	if(KeyAttrFlags) {
-		ParseVectorDataArray(flags, *KeyAttrFlags);
-	}
+    const Scope& sc = GetRequiredScope(element);
+    const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
+    const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
+
+    ParseVectorDataArray(keys, KeyTime);
+    ParseVectorDataArray(values, KeyValueFloat);
+
+    if(keys.size() != values.size()) {
+        DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
+    }
+
+    // check if the key times are well-ordered
+    if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
+        DOMError("the keyframes are not in ascending order",&KeyTime);
+    }
+
+    const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
+    if(KeyAttrDataFloat) {
+        ParseVectorDataArray(attributes, *KeyAttrDataFloat);
+    }
+
+    const Element* KeyAttrFlags = sc["KeyAttrFlags"];
+    if(KeyAttrFlags) {
+        ParseVectorDataArray(flags, *KeyAttrFlags);
+    }
 }
 
 
@@ -99,61 +99,61 @@ AnimationCurve::~AnimationCurve()
 
 // ------------------------------------------------------------------------------------------------
 AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
-	const char* const * target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/)
+    const char* const * target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/)
 : Object(id, element, name)
 , target()
 , doc(doc)
 {
-	const Scope& sc = GetRequiredScope(element);
-
-	// find target node
-	const char* whitelist[] = {"Model","NodeAttribute"};
-	const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,2);
-
-	BOOST_FOREACH(const Connection* con, conns) {
-
-		// link should go for a property
-		if (!con->PropertyName().length()) {
-			continue;
-		}
-
-		if(target_prop_whitelist) {
-			const char* const s = con->PropertyName().c_str();
-			bool ok = false;
-			for (size_t i = 0; i < whitelist_size; ++i) {
-				if (!strcmp(s, target_prop_whitelist[i])) {
-					ok = true;
-					break;
-				}
-			}
-
-			if (!ok) {
-				throw std::range_error("AnimationCurveNode target property is not in whitelist");
-			}
-		}
-
-		const Object* const ob = con->DestinationObject();
-		if(!ob) {
-			DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
-			continue;
-		}
-
-		// XXX support constraints as DOM class
-		//ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
-		target = ob;
-		if(!target) {
-			continue;
-		}
-
-		prop = con->PropertyName();
-		break;
-	}
-
-	if(!target) {
-		DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
-	}
-
-	props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
+    const Scope& sc = GetRequiredScope(element);
+
+    // find target node
+    const char* whitelist[] = {"Model","NodeAttribute"};
+    const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,2);
+
+    BOOST_FOREACH(const Connection* con, conns) {
+
+        // link should go for a property
+        if (!con->PropertyName().length()) {
+            continue;
+        }
+
+        if(target_prop_whitelist) {
+            const char* const s = con->PropertyName().c_str();
+            bool ok = false;
+            for (size_t i = 0; i < whitelist_size; ++i) {
+                if (!strcmp(s, target_prop_whitelist[i])) {
+                    ok = true;
+                    break;
+                }
+            }
+
+            if (!ok) {
+                throw std::range_error("AnimationCurveNode target property is not in whitelist");
+            }
+        }
+
+        const Object* const ob = con->DestinationObject();
+        if(!ob) {
+            DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
+            continue;
+        }
+
+        // XXX support constraints as DOM class
+        //ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
+        target = ob;
+        if(!target) {
+            continue;
+        }
+
+        prop = con->PropertyName();
+        break;
+    }
+
+    if(!target) {
+        DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
+    }
+
+    props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
 }
 
 
@@ -167,34 +167,34 @@ AnimationCurveNode::~AnimationCurveNode()
 // ------------------------------------------------------------------------------------------------
 const AnimationCurveMap& AnimationCurveNode::Curves() const
 {
-	if(curves.empty()) {
-		// resolve attached animation curves
-		const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
-
-		BOOST_FOREACH(const Connection* con, conns) {
-
-			// link should go for a property
-			if (!con->PropertyName().length()) {
-				continue;
-			}
-
-			const Object* const ob = con->SourceObject();
-			if(!ob) {
-				DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
-				continue;
-			}
-
-			const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
-			if(!anim) {
-				DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
-				continue;
-			}
-
-			curves[con->PropertyName()] = anim;
-		}
-	}
-
-	return curves;
+    if(curves.empty()) {
+        // resolve attached animation curves
+        const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
+
+        BOOST_FOREACH(const Connection* con, conns) {
+
+            // link should go for a property
+            if (!con->PropertyName().length()) {
+                continue;
+            }
+
+            const Object* const ob = con->SourceObject();
+            if(!ob) {
+                DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
+                continue;
+            }
+
+            const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
+            if(!anim) {
+                DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
+                continue;
+            }
+
+            curves[con->PropertyName()] = anim;
+        }
+    }
+
+    return curves;
 }
 
 
@@ -203,10 +203,10 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::s
 : Object(id, element, name)
 , doc(doc)
 {
-	const Scope& sc = GetRequiredScope(element);
+    const Scope& sc = GetRequiredScope(element);
 
-	// note: the props table here bears little importance and is usually absent
-	props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
+    // note: the props table here bears little importance and is usually absent
+    props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
 }
 
 
@@ -219,85 +219,85 @@ AnimationLayer::~AnimationLayer()
 
 // ------------------------------------------------------------------------------------------------
 AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/,
-	size_t whitelist_size /*= 0*/) const
+    size_t whitelist_size /*= 0*/) const
 {
-	AnimationCurveNodeList nodes;
-
-	// resolve attached animation nodes
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
-	nodes.reserve(conns.size());
-
-	BOOST_FOREACH(const Connection* con, conns) {
-
-		// link should not go to a property
-		if (con->PropertyName().length()) {
-			continue;
-		}
-
-		const Object* const ob = con->SourceObject();
-		if(!ob) {
-			DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
-			continue;
-		}
-
-		const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
-		if(!anim) {
-			DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
-			continue;
-		}
-
-		if(target_prop_whitelist) {
-			const char* s = anim->TargetProperty().c_str();
-			bool ok = false;
-			for (size_t i = 0; i < whitelist_size; ++i) {
-				if (!strcmp(s, target_prop_whitelist[i])) {
-					ok = true;
-					break;
-				}
-			}
-			if(!ok) {
-				continue;
-			}
-		}
-		nodes.push_back(anim);
-	}
-
-	return nodes; // pray for NRVO
+    AnimationCurveNodeList nodes;
+
+    // resolve attached animation nodes
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
+    nodes.reserve(conns.size());
+
+    BOOST_FOREACH(const Connection* con, conns) {
+
+        // link should not go to a property
+        if (con->PropertyName().length()) {
+            continue;
+        }
+
+        const Object* const ob = con->SourceObject();
+        if(!ob) {
+            DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
+            continue;
+        }
+
+        const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
+        if(!anim) {
+            DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
+            continue;
+        }
+
+        if(target_prop_whitelist) {
+            const char* s = anim->TargetProperty().c_str();
+            bool ok = false;
+            for (size_t i = 0; i < whitelist_size; ++i) {
+                if (!strcmp(s, target_prop_whitelist[i])) {
+                    ok = true;
+                    break;
+                }
+            }
+            if(!ok) {
+                continue;
+            }
+        }
+        nodes.push_back(anim);
+    }
+
+    return nodes; // pray for NRVO
 }
 
 // ------------------------------------------------------------------------------------------------
 AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc)
 : Object(id, element, name)
 {
-	const Scope& sc = GetRequiredScope(element);
-
-	// note: we don't currently use any of these properties so we shouldn't bother if it is missing
-	props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
-
-	// resolve attached animation layers
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
-	layers.reserve(conns.size());
-
-	BOOST_FOREACH(const Connection* con, conns) {
-
-		// link should not go to a property
-		if (con->PropertyName().length()) {
-			continue;
-		}
-
-		const Object* const ob = con->SourceObject();
-		if(!ob) {
-			DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
-			continue;
-		}
-
-		const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
-		if(!anim) {
-			DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
-			continue;
-		}
-		layers.push_back(anim);
-	}
+    const Scope& sc = GetRequiredScope(element);
+
+    // note: we don't currently use any of these properties so we shouldn't bother if it is missing
+    props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
+
+    // resolve attached animation layers
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
+    layers.reserve(conns.size());
+
+    BOOST_FOREACH(const Connection* con, conns) {
+
+        // link should not go to a property
+        if (con->PropertyName().length()) {
+            continue;
+        }
+
+        const Object* const ob = con->SourceObject();
+        if(!ob) {
+            DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
+            continue;
+        }
+
+        const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
+        if(!anim) {
+            DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
+            continue;
+        }
+        layers.push_back(anim);
+    }
 }
 
 

+ 248 - 248
code/FBXBinaryTokenizer.cpp

@@ -58,22 +58,22 @@ namespace FBX {
 
 // ------------------------------------------------------------------------------------------------
 Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset)
-	:
-	#ifdef DEBUG
-	contents(sbegin, static_cast<size_t>(send-sbegin)),
-	#endif
-	sbegin(sbegin)
-	, send(send)
-	, type(type)
-	, line(offset)
-	, column(BINARY_MARKER)
+    :
+    #ifdef DEBUG
+    contents(sbegin, static_cast<size_t>(send-sbegin)),
+    #endif
+    sbegin(sbegin)
+    , send(send)
+    , type(type)
+    , line(offset)
+    , column(BINARY_MARKER)
 {
-	ai_assert(sbegin);
-	ai_assert(send);
+    ai_assert(sbegin);
+    ai_assert(send);
 
-	// binary tokens may have zero length because they are sometimes dummies
-	// inserted by TokenizeBinary()
-	ai_assert(send >= sbegin);
+    // binary tokens may have zero length because they are sometimes dummies
+    // inserted by TokenizeBinary()
+    ai_assert(send >= sbegin);
 }
 
 
@@ -84,85 +84,85 @@ namespace {
 AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset) AI_WONT_RETURN_SUFFIX;
 AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset)
 {
-	throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
+    throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
 }
 
 
 // ------------------------------------------------------------------------------------------------
 uint32_t Offset(const char* begin, const char* cursor)
 {
-	ai_assert(begin <= cursor);
-	return static_cast<unsigned int>(cursor - begin);
+    ai_assert(begin <= cursor);
+    return static_cast<unsigned int>(cursor - begin);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void TokenizeError(const std::string& message, const char* begin, const char* cursor)
 {
-	TokenizeError(message, Offset(begin, cursor));
+    TokenizeError(message, Offset(begin, cursor));
 }
 
 
 // ------------------------------------------------------------------------------------------------
 uint32_t ReadWord(const char* input, const char*& cursor, const char* end)
 {
-	if(Offset(cursor, end) < 4) {
-		TokenizeError("cannot ReadWord, out of bounds",input, cursor);
-	}
+    if(Offset(cursor, end) < 4) {
+        TokenizeError("cannot ReadWord, out of bounds",input, cursor);
+    }
 
-	uint32_t word = *reinterpret_cast<const uint32_t*>(cursor);
-	AI_SWAP4(word);
+    uint32_t word = *reinterpret_cast<const uint32_t*>(cursor);
+    AI_SWAP4(word);
 
-	cursor += 4;
+    cursor += 4;
 
-	return word;
+    return word;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 uint8_t ReadByte(const char* input, const char*& cursor, const char* end)
 {
-	if(Offset(cursor, end) < 1) {
-		TokenizeError("cannot ReadByte, out of bounds",input, cursor);
-	}
+    if(Offset(cursor, end) < 1) {
+        TokenizeError("cannot ReadByte, out of bounds",input, cursor);
+    }
 
-	uint8_t word = *reinterpret_cast<const uint8_t*>(cursor);
-	++cursor;
+    uint8_t word = *reinterpret_cast<const uint8_t*>(cursor);
+    ++cursor;
 
-	return word;
+    return word;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end,
-	bool long_length = false,
-	bool allow_null = false)
+    bool long_length = false,
+    bool allow_null = false)
 {
-	const uint32_t len_len = long_length ? 4 : 1;
-	if(Offset(cursor, end) < len_len) {
-		TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
-	}
+    const uint32_t len_len = long_length ? 4 : 1;
+    if(Offset(cursor, end) < len_len) {
+        TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
+    }
 
-	const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
+    const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
 
-	if (Offset(cursor, end) < length) {
-		TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
-	}
+    if (Offset(cursor, end) < length) {
+        TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
+    }
 
-	sbegin_out = cursor;
-	cursor += length;
+    sbegin_out = cursor;
+    cursor += length;
 
-	send_out = cursor;
+    send_out = cursor;
 
-	if(!allow_null) {
-		for (unsigned int i = 0; i < length; ++i) {
-			if(sbegin_out[i] == '\0') {
-				TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
-			}
-		}
-	}
+    if(!allow_null) {
+        for (unsigned int i = 0; i < length; ++i) {
+            if(sbegin_out[i] == '\0') {
+                TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
+            }
+        }
+    }
 
-	return length;
+    return length;
 }
 
 
@@ -170,203 +170,203 @@ unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const ch
 // ------------------------------------------------------------------------------------------------
 void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end)
 {
-	if(Offset(cursor, end) < 1) {
-		TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
-	}
-
-	const char type = *cursor;
-	sbegin_out = cursor++;
-
-	switch(type)
-	{
-		// 16 bit int
-	case 'Y':
-		cursor += 2;
-		break;
-
-		// 1 bit bool flag (yes/no)
-	case 'C':
-		cursor += 1;
-		break;
-
-		// 32 bit int
-	case 'I':
-		// <- fall thru
-
-		// float
-	case 'F':
-		cursor += 4;
-		break;
-
-		// double
-	case 'D':
-		cursor += 8;
-		break;
-
-		// 64 bit int
-	case 'L':
-		cursor += 8;
-		break;
-
-		// note: do not write cursor += ReadWord(...cursor) as this would be UB
-
-		// raw binary data
-	case 'R':
-	{
-		const uint32_t length = ReadWord(input, cursor, end);
-		cursor += length;
-		break;
-	}
-
-	case 'b':
-		// TODO: what is the 'b' type code? Right now we just skip over it /
-		// take the full range we could get
-		cursor = end;
-		break;
-
-		// array of *
-	case 'f':
-	case 'd':
-	case 'l':
-	case 'i':	{
-
-		const uint32_t length = ReadWord(input, cursor, end);
-		const uint32_t encoding = ReadWord(input, cursor, end);
-
-		const uint32_t comp_len = ReadWord(input, cursor, end);
-
-		// compute length based on type and check against the stored value
-		if(encoding == 0) {
-			uint32_t stride = 0;
-			switch(type)
-			{
-			case 'f':
-			case 'i':
-				stride = 4;
-				break;
-
-			case 'd':
-			case 'l':
-				stride = 8;
-				break;
-
-			default:
-				ai_assert(false);
-			};
+    if(Offset(cursor, end) < 1) {
+        TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
+    }
+
+    const char type = *cursor;
+    sbegin_out = cursor++;
+
+    switch(type)
+    {
+        // 16 bit int
+    case 'Y':
+        cursor += 2;
+        break;
+
+        // 1 bit bool flag (yes/no)
+    case 'C':
+        cursor += 1;
+        break;
+
+        // 32 bit int
+    case 'I':
+        // <- fall thru
+
+        // float
+    case 'F':
+        cursor += 4;
+        break;
+
+        // double
+    case 'D':
+        cursor += 8;
+        break;
+
+        // 64 bit int
+    case 'L':
+        cursor += 8;
+        break;
+
+        // note: do not write cursor += ReadWord(...cursor) as this would be UB
+
+        // raw binary data
+    case 'R':
+    {
+        const uint32_t length = ReadWord(input, cursor, end);
+        cursor += length;
+        break;
+    }
+
+    case 'b':
+        // TODO: what is the 'b' type code? Right now we just skip over it /
+        // take the full range we could get
+        cursor = end;
+        break;
+
+        // array of *
+    case 'f':
+    case 'd':
+    case 'l':
+    case 'i':   {
+
+        const uint32_t length = ReadWord(input, cursor, end);
+        const uint32_t encoding = ReadWord(input, cursor, end);
+
+        const uint32_t comp_len = ReadWord(input, cursor, end);
+
+        // compute length based on type and check against the stored value
+        if(encoding == 0) {
+            uint32_t stride = 0;
+            switch(type)
+            {
+            case 'f':
+            case 'i':
+                stride = 4;
+                break;
+
+            case 'd':
+            case 'l':
+                stride = 8;
+                break;
+
+            default:
+                ai_assert(false);
+            };
             ai_assert(stride > 0);
-			if(length * stride != comp_len) {
-				TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
-			}
-		}
-		// zip/deflate algorithm (encoding==1)? take given length. anything else? die
-		else if (encoding != 1) {
-			TokenizeError("cannot ReadData, unknown encoding",input, cursor);
-		}
-		cursor += comp_len;
-		break;
-	}
-
-		// string
-	case 'S': {
-		const char* sb, *se;
-		// 0 characters can legally happen in such strings
-		ReadString(sb, se, input, cursor, end, true, true);
-		break;
-	}
-	default:
-		TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
-	}
-
-	if(cursor > end) {
-		TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor);
-	}
-
-	// the type code is contained in the returned range
-	send_out = cursor;
+            if(length * stride != comp_len) {
+                TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
+            }
+        }
+        // zip/deflate algorithm (encoding==1)? take given length. anything else? die
+        else if (encoding != 1) {
+            TokenizeError("cannot ReadData, unknown encoding",input, cursor);
+        }
+        cursor += comp_len;
+        break;
+    }
+
+        // string
+    case 'S': {
+        const char* sb, *se;
+        // 0 characters can legally happen in such strings
+        ReadString(sb, se, input, cursor, end, true, true);
+        break;
+    }
+    default:
+        TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
+    }
+
+    if(cursor > end) {
+        TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor);
+    }
+
+    // the type code is contained in the returned range
+    send_out = cursor;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end)
 {
-	// the first word contains the offset at which this block ends
-	const uint32_t end_offset = ReadWord(input, cursor, end);
-
-	// we may get 0 if reading reached the end of the file -
-	// fbx files have a mysterious extra footer which I don't know
-	// how to extract any information from, but at least it always
-	// starts with a 0.
-	if(!end_offset) {
-		return false;
-	}
-
-	if(end_offset > Offset(input, end)) {
-		TokenizeError("block offset is out of range",input, cursor);
-	}
-	else if(end_offset < Offset(input, cursor)) {
-		TokenizeError("block offset is negative out of range",input, cursor);
-	}
-
-	// the second data word contains the number of properties in the scope
-	const uint32_t prop_count = ReadWord(input, cursor, end);
-
-	// the third data word contains the length of the property list
-	const uint32_t prop_length = ReadWord(input, cursor, end);
-
-	// now comes the name of the scope/key
-	const char* sbeg, *send;
-	ReadString(sbeg, send, input, cursor, end);
-
-	output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
-
-	// now come the individual properties
-	const char* begin_cursor = cursor;
-	for (unsigned int i = 0; i < prop_count; ++i) {
-		ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
-
-		output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
-
-		if(i != prop_count-1) {
-			output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
-		}
-	}
-
-	if (Offset(begin_cursor, cursor) != prop_length) {
-		TokenizeError("property length not reached, something is wrong",input, cursor);
-	}
-
-	// at the end of each nested block, there is a NUL record to indicate
-	// that the sub-scope exists (i.e. to distinguish between P: and P : {})
-	// this NUL record is 13 bytes long.
+    // the first word contains the offset at which this block ends
+    const uint32_t end_offset = ReadWord(input, cursor, end);
+
+    // we may get 0 if reading reached the end of the file -
+    // fbx files have a mysterious extra footer which I don't know
+    // how to extract any information from, but at least it always
+    // starts with a 0.
+    if(!end_offset) {
+        return false;
+    }
+
+    if(end_offset > Offset(input, end)) {
+        TokenizeError("block offset is out of range",input, cursor);
+    }
+    else if(end_offset < Offset(input, cursor)) {
+        TokenizeError("block offset is negative out of range",input, cursor);
+    }
+
+    // the second data word contains the number of properties in the scope
+    const uint32_t prop_count = ReadWord(input, cursor, end);
+
+    // the third data word contains the length of the property list
+    const uint32_t prop_length = ReadWord(input, cursor, end);
+
+    // now comes the name of the scope/key
+    const char* sbeg, *send;
+    ReadString(sbeg, send, input, cursor, end);
+
+    output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
+
+    // now come the individual properties
+    const char* begin_cursor = cursor;
+    for (unsigned int i = 0; i < prop_count; ++i) {
+        ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
+
+        output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
+
+        if(i != prop_count-1) {
+            output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
+        }
+    }
+
+    if (Offset(begin_cursor, cursor) != prop_length) {
+        TokenizeError("property length not reached, something is wrong",input, cursor);
+    }
+
+    // at the end of each nested block, there is a NUL record to indicate
+    // that the sub-scope exists (i.e. to distinguish between P: and P : {})
+    // this NUL record is 13 bytes long.
 #define BLOCK_SENTINEL_LENGTH 13
 
-	if (Offset(input, cursor) < end_offset) {
+    if (Offset(input, cursor) < end_offset) {
 
-		if (end_offset - Offset(input, cursor) < BLOCK_SENTINEL_LENGTH) {
-			TokenizeError("insufficient padding bytes at block end",input, cursor);
-		}
+        if (end_offset - Offset(input, cursor) < BLOCK_SENTINEL_LENGTH) {
+            TokenizeError("insufficient padding bytes at block end",input, cursor);
+        }
 
-		output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
+        output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
 
-		// XXX this is vulnerable to stack overflowing ..
-		while(Offset(input, cursor) < end_offset - BLOCK_SENTINEL_LENGTH) {
-			ReadScope(output_tokens, input, cursor, input + end_offset - BLOCK_SENTINEL_LENGTH);
-		}
-		output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
+        // XXX this is vulnerable to stack overflowing ..
+        while(Offset(input, cursor) < end_offset - BLOCK_SENTINEL_LENGTH) {
+            ReadScope(output_tokens, input, cursor, input + end_offset - BLOCK_SENTINEL_LENGTH);
+        }
+        output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
 
-		for (unsigned int i = 0; i < BLOCK_SENTINEL_LENGTH; ++i) {
-			if(cursor[i] != '\0') {
-				TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
-			}
-		}
-		cursor += BLOCK_SENTINEL_LENGTH;
-	}
+        for (unsigned int i = 0; i < BLOCK_SENTINEL_LENGTH; ++i) {
+            if(cursor[i] != '\0') {
+                TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
+            }
+        }
+        cursor += BLOCK_SENTINEL_LENGTH;
+    }
 
-	if (Offset(input, cursor) != end_offset) {
-		TokenizeError("scope length not reached, something is wrong",input, cursor);
-	}
+    if (Offset(input, cursor) != end_offset) {
+        TokenizeError("scope length not reached, something is wrong",input, cursor);
+    }
 
-	return true;
+    return true;
 }
 
 
@@ -375,26 +375,26 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
 // ------------------------------------------------------------------------------------------------
 void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length)
 {
-	ai_assert(input);
+    ai_assert(input);
 
-	if(length < 0x1b) {
-		TokenizeError("file is too short",0);
-	}
+    if(length < 0x1b) {
+        TokenizeError("file is too short",0);
+    }
 
-	if (strncmp(input,"Kaydara FBX Binary",18)) {
-		TokenizeError("magic bytes not found",0);
-	}
+    if (strncmp(input,"Kaydara FBX Binary",18)) {
+        TokenizeError("magic bytes not found",0);
+    }
 
 
-	//uint32_t offset = 0x1b;
+    //uint32_t offset = 0x1b;
 
-	const char* cursor = input + 0x1b;
+    const char* cursor = input + 0x1b;
 
-	while (cursor < input + length) {
-		if(!ReadScope(output_tokens, input, cursor, input + length)) {
-			break;
-		}
-	}
+    while (cursor < input + length) {
+        if(!ReadScope(output_tokens, input, cursor, input + length)) {
+            break;
+        }
+    }
 }
 
 } // !FBX

+ 12 - 12
code/FBXCompileConfig.h

@@ -46,21 +46,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 //
 #if _MSC_VER > 1500 || (defined __GNUC___)
-#	define ASSIMP_FBX_USE_UNORDERED_MULTIMAP
-#	else
-#	define fbx_unordered_map map
-#	define fbx_unordered_multimap multimap
+#   define ASSIMP_FBX_USE_UNORDERED_MULTIMAP
+#   else
+#   define fbx_unordered_map map
+#   define fbx_unordered_multimap multimap
 #endif
 
 #ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
-#	include <unordered_map>
-#	if _MSC_VER > 1600
-#		define fbx_unordered_map unordered_map
-#		define fbx_unordered_multimap unordered_multimap
-#	else
-#		define fbx_unordered_map tr1::unordered_map
-#		define fbx_unordered_multimap tr1::unordered_multimap
-#	endif
+#   include <unordered_map>
+#   if _MSC_VER > 1600
+#       define fbx_unordered_map unordered_map
+#       define fbx_unordered_multimap unordered_multimap
+#   else
+#       define fbx_unordered_map tr1::unordered_map
+#       define fbx_unordered_multimap tr1::unordered_multimap
+#   endif
 #endif
 
 #endif

File diff suppressed because it is too large
+ 2873 - 2873
code/FBXConverter.cpp


+ 1 - 1
code/FBXConverter.h

@@ -49,7 +49,7 @@ struct aiScene;
 namespace Assimp {
 namespace FBX {
 
-	class Document;
+    class Document;
 
 
 /** Convert a FBX #Document to #aiScene

+ 58 - 58
code/FBXDeformer.cpp

@@ -55,16 +55,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	using namespace Util;
+    using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
 Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-	: Object(id,element,name)
+    : Object(id,element,name)
 {
-	const Scope& sc = GetRequiredScope(element);
+    const Scope& sc = GetRequiredScope(element);
 
-	const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
-	props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
+    const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
+    props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
 }
 
 
@@ -80,44 +80,44 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const
 : Deformer(id,element,doc,name)
 , node()
 {
-	const Scope& sc = GetRequiredScope(element);
-
-	const Element* const Indexes = sc["Indexes"];
-	const Element* const Weights = sc["Weights"];
-
-	const Element& Transform = GetRequiredElement(sc,"Transform",&element);
-	const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element);
-
-	transform = ReadMatrix(Transform);
-	transformLink = ReadMatrix(TransformLink);
-
-	// it is actually possible that there be Deformer's with no weights
-	if (!!Indexes != !!Weights) {
-		DOMError("either Indexes or Weights are missing from Cluster",&element);
-	}
-
-	if(Indexes) {
-		ParseVectorDataArray(indices,*Indexes);
-		ParseVectorDataArray(weights,*Weights);
-	}
-
-	if(indices.size() != weights.size()) {
-		DOMError("sizes of index and weight array don't match up",&element);
-	}
-
-	// read assigned node
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
-	BOOST_FOREACH(const Connection* con, conns) {
-		const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
-		if(mod) {
-			node = mod;
-			break;
-		}
-	}
-
-	if (!node) {
-		DOMError("failed to read target Node for Cluster",&element);
-	}
+    const Scope& sc = GetRequiredScope(element);
+
+    const Element* const Indexes = sc["Indexes"];
+    const Element* const Weights = sc["Weights"];
+
+    const Element& Transform = GetRequiredElement(sc,"Transform",&element);
+    const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element);
+
+    transform = ReadMatrix(Transform);
+    transformLink = ReadMatrix(TransformLink);
+
+    // it is actually possible that there be Deformer's with no weights
+    if (!!Indexes != !!Weights) {
+        DOMError("either Indexes or Weights are missing from Cluster",&element);
+    }
+
+    if(Indexes) {
+        ParseVectorDataArray(indices,*Indexes);
+        ParseVectorDataArray(weights,*Weights);
+    }
+
+    if(indices.size() != weights.size()) {
+        DOMError("sizes of index and weight array don't match up",&element);
+    }
+
+    // read assigned node
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
+    BOOST_FOREACH(const Connection* con, conns) {
+        const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
+        if(mod) {
+            node = mod;
+            break;
+        }
+    }
+
+    if (!node) {
+        DOMError("failed to read target Node for Cluster",&element);
+    }
 }
 
 
@@ -132,25 +132,25 @@ Cluster::~Cluster()
 Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 : Deformer(id,element,doc,name)
 {
-	const Scope& sc = GetRequiredScope(element);
+    const Scope& sc = GetRequiredScope(element);
 
-	const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"];
-	if(Link_DeformAcuracy) {
-		accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0));
-	}
+    const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"];
+    if(Link_DeformAcuracy) {
+        accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0));
+    }
 
-	// resolve assigned clusters
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
+    // resolve assigned clusters
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
 
-	clusters.reserve(conns.size());
-	BOOST_FOREACH(const Connection* con, conns) {
+    clusters.reserve(conns.size());
+    BOOST_FOREACH(const Connection* con, conns) {
 
-		const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
-		if(cluster) {
-			clusters.push_back(cluster);
-			continue;
-		}
-	}
+        const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
+        if(cluster) {
+            clusters.push_back(cluster);
+            continue;
+        }
+    }
 }
 
 

+ 434 - 434
code/FBXDocument.cpp

@@ -80,141 +80,141 @@ LazyObject::~LazyObject()
 // ------------------------------------------------------------------------------------------------
 const Object* LazyObject::Get(bool dieOnError)
 {
-	if(IsBeingConstructed() || FailedToConstruct()) {
-		return NULL;
-	}
-
-	if (object.get()) {
-		return object.get();
-	}
-
-	// if this is the root object, we return a dummy since there
-	// is no root object int he fbx file - it is just referenced
-	// with id 0.
-	if(id == 0L) {
-		object.reset(new Object(id, element, "Model::RootNode"));
-		return object.get();
-	}
-
-	const Token& key = element.KeyToken();
-	const TokenList& tokens = element.Tokens();
-
-	if(tokens.size() < 3) {
-		DOMError("expected at least 3 tokens: id, name and class tag",&element);
-	}
-
-	const char* err;
-	std::string name = ParseTokenAsString(*tokens[1],err);
-	if (err) {
-		DOMError(err,&element);
-	}
-
-	// small fix for binary reading: binary fbx files don't use
-	// prefixes such as Model:: in front of their names. The
-	// loading code expects this at many places, though!
-	// so convert the binary representation (a 0x0001) to the
-	// double colon notation.
-	if(tokens[1]->IsBinary()) {
-		for (size_t i = 0; i < name.length(); ++i) {
-			if (name[i] == 0x0 && name[i+1] == 0x1) {
-				name = name.substr(i+2) + "::" + name.substr(0,i);
-			}
-		}
-	}
-
-	const std::string classtag = ParseTokenAsString(*tokens[2],err);
-	if (err) {
-		DOMError(err,&element);
-	}
-
-	// prevent recursive calls
-	flags |= BEING_CONSTRUCTED;
-
-	try {
-		// this needs to be relatively fast since it happens a lot,
-		// so avoid constructing strings all the time.
-		const char* obtype = key.begin();
-		const size_t length = static_cast<size_t>(key.end()-key.begin());
-		if (!strncmp(obtype,"Geometry",length)) {
-			if (!strcmp(classtag.c_str(),"Mesh")) {
-				object.reset(new MeshGeometry(id,element,name,doc));
-			}
-		}
-		else if (!strncmp(obtype,"NodeAttribute",length)) {
-			if (!strcmp(classtag.c_str(),"Camera")) {
-				object.reset(new Camera(id,element,doc,name));
-			}
-			else if (!strcmp(classtag.c_str(),"CameraSwitcher")) {
-				object.reset(new CameraSwitcher(id,element,doc,name));
-			}
-			else if (!strcmp(classtag.c_str(),"Light")) {
-				object.reset(new Light(id,element,doc,name));
-			}
-			else if (!strcmp(classtag.c_str(),"Null")) {
-				object.reset(new Null(id,element,doc,name));
-			}
-			else if (!strcmp(classtag.c_str(),"LimbNode")) {
-				object.reset(new LimbNode(id,element,doc,name));
-			}
-		}
-		else if (!strncmp(obtype,"Deformer",length)) {
-			if (!strcmp(classtag.c_str(),"Cluster")) {
-				object.reset(new Cluster(id,element,doc,name));
-			}
-			else if (!strcmp(classtag.c_str(),"Skin")) {
-				object.reset(new Skin(id,element,doc,name));
-			}
-		}
-		else if (!strncmp(obtype,"Model",length)) {
-			// FK and IK effectors are not supported
-			if (strcmp(classtag.c_str(),"IKEffector") && strcmp(classtag.c_str(),"FKEffector")) {
-				object.reset(new Model(id,element,doc,name));
-			}
-		}
-		else if (!strncmp(obtype,"Material",length)) {
-			object.reset(new Material(id,element,doc,name));
-		}
-		else if (!strncmp(obtype,"Texture",length)) {
-			object.reset(new Texture(id,element,doc,name));
-		}
-		else if (!strncmp(obtype,"LayeredTexture",length)) {
-			object.reset(new LayeredTexture(id,element,doc,name));
-		}
-		else if (!strncmp(obtype,"AnimationStack",length)) {
-			object.reset(new AnimationStack(id,element,name,doc));
-		}
-		else if (!strncmp(obtype,"AnimationLayer",length)) {
-			object.reset(new AnimationLayer(id,element,name,doc));
-		}
-		// note: order matters for these two
-		else if (!strncmp(obtype,"AnimationCurve",length)) {
-			object.reset(new AnimationCurve(id,element,name,doc));
-		}
-		else if (!strncmp(obtype,"AnimationCurveNode",length)) {
-			object.reset(new AnimationCurveNode(id,element,name,doc));
-		}
-	}
-	catch(std::exception& ex) {
-		flags &= ~BEING_CONSTRUCTED;
-		flags |= FAILED_TO_CONSTRUCT;
-
-		if(dieOnError || doc.Settings().strictMode) {
-			throw;
-		}
-
-		// note: the error message is already formatted, so raw logging is ok
-		if(!DefaultLogger::isNullLogger()) {
-			DefaultLogger::get()->error(ex.what());
-		}
-		return NULL;
-	}
-
-	if (!object.get()) {
-		//DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
-	}
-
-	flags &= ~BEING_CONSTRUCTED;
-	return object.get();
+    if(IsBeingConstructed() || FailedToConstruct()) {
+        return NULL;
+    }
+
+    if (object.get()) {
+        return object.get();
+    }
+
+    // if this is the root object, we return a dummy since there
+    // is no root object int he fbx file - it is just referenced
+    // with id 0.
+    if(id == 0L) {
+        object.reset(new Object(id, element, "Model::RootNode"));
+        return object.get();
+    }
+
+    const Token& key = element.KeyToken();
+    const TokenList& tokens = element.Tokens();
+
+    if(tokens.size() < 3) {
+        DOMError("expected at least 3 tokens: id, name and class tag",&element);
+    }
+
+    const char* err;
+    std::string name = ParseTokenAsString(*tokens[1],err);
+    if (err) {
+        DOMError(err,&element);
+    }
+
+    // small fix for binary reading: binary fbx files don't use
+    // prefixes such as Model:: in front of their names. The
+    // loading code expects this at many places, though!
+    // so convert the binary representation (a 0x0001) to the
+    // double colon notation.
+    if(tokens[1]->IsBinary()) {
+        for (size_t i = 0; i < name.length(); ++i) {
+            if (name[i] == 0x0 && name[i+1] == 0x1) {
+                name = name.substr(i+2) + "::" + name.substr(0,i);
+            }
+        }
+    }
+
+    const std::string classtag = ParseTokenAsString(*tokens[2],err);
+    if (err) {
+        DOMError(err,&element);
+    }
+
+    // prevent recursive calls
+    flags |= BEING_CONSTRUCTED;
+
+    try {
+        // this needs to be relatively fast since it happens a lot,
+        // so avoid constructing strings all the time.
+        const char* obtype = key.begin();
+        const size_t length = static_cast<size_t>(key.end()-key.begin());
+        if (!strncmp(obtype,"Geometry",length)) {
+            if (!strcmp(classtag.c_str(),"Mesh")) {
+                object.reset(new MeshGeometry(id,element,name,doc));
+            }
+        }
+        else if (!strncmp(obtype,"NodeAttribute",length)) {
+            if (!strcmp(classtag.c_str(),"Camera")) {
+                object.reset(new Camera(id,element,doc,name));
+            }
+            else if (!strcmp(classtag.c_str(),"CameraSwitcher")) {
+                object.reset(new CameraSwitcher(id,element,doc,name));
+            }
+            else if (!strcmp(classtag.c_str(),"Light")) {
+                object.reset(new Light(id,element,doc,name));
+            }
+            else if (!strcmp(classtag.c_str(),"Null")) {
+                object.reset(new Null(id,element,doc,name));
+            }
+            else if (!strcmp(classtag.c_str(),"LimbNode")) {
+                object.reset(new LimbNode(id,element,doc,name));
+            }
+        }
+        else if (!strncmp(obtype,"Deformer",length)) {
+            if (!strcmp(classtag.c_str(),"Cluster")) {
+                object.reset(new Cluster(id,element,doc,name));
+            }
+            else if (!strcmp(classtag.c_str(),"Skin")) {
+                object.reset(new Skin(id,element,doc,name));
+            }
+        }
+        else if (!strncmp(obtype,"Model",length)) {
+            // FK and IK effectors are not supported
+            if (strcmp(classtag.c_str(),"IKEffector") && strcmp(classtag.c_str(),"FKEffector")) {
+                object.reset(new Model(id,element,doc,name));
+            }
+        }
+        else if (!strncmp(obtype,"Material",length)) {
+            object.reset(new Material(id,element,doc,name));
+        }
+        else if (!strncmp(obtype,"Texture",length)) {
+            object.reset(new Texture(id,element,doc,name));
+        }
+        else if (!strncmp(obtype,"LayeredTexture",length)) {
+            object.reset(new LayeredTexture(id,element,doc,name));
+        }
+        else if (!strncmp(obtype,"AnimationStack",length)) {
+            object.reset(new AnimationStack(id,element,name,doc));
+        }
+        else if (!strncmp(obtype,"AnimationLayer",length)) {
+            object.reset(new AnimationLayer(id,element,name,doc));
+        }
+        // note: order matters for these two
+        else if (!strncmp(obtype,"AnimationCurve",length)) {
+            object.reset(new AnimationCurve(id,element,name,doc));
+        }
+        else if (!strncmp(obtype,"AnimationCurveNode",length)) {
+            object.reset(new AnimationCurveNode(id,element,name,doc));
+        }
+    }
+    catch(std::exception& ex) {
+        flags &= ~BEING_CONSTRUCTED;
+        flags |= FAILED_TO_CONSTRUCT;
+
+        if(dieOnError || doc.Settings().strictMode) {
+            throw;
+        }
+
+        // note: the error message is already formatted, so raw logging is ok
+        if(!DefaultLogger::isNullLogger()) {
+            DefaultLogger::get()->error(ex.what());
+        }
+        return NULL;
+    }
+
+    if (!object.get()) {
+        //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
+    }
+
+    flags &= ~BEING_CONSTRUCTED;
+    return object.get();
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -254,214 +254,214 @@ Document::Document(const Parser& parser, const ImportSettings& settings)
 : settings(settings)
 , parser(parser)
 {
-	// Cannot use array default initialization syntax because vc8 fails on it
-	for (unsigned int i = 0; i < sizeof(creationTimeStamp) / sizeof(creationTimeStamp[0]); ++i) {
-		creationTimeStamp[i] = 0;
-	}
+    // Cannot use array default initialization syntax because vc8 fails on it
+    for (unsigned int i = 0; i < sizeof(creationTimeStamp) / sizeof(creationTimeStamp[0]); ++i) {
+        creationTimeStamp[i] = 0;
+    }
 
-	ReadHeader();
-	ReadPropertyTemplates();
+    ReadHeader();
+    ReadPropertyTemplates();
 
-	ReadGlobalSettings();
+    ReadGlobalSettings();
 
-	// This order is important, connections need parsed objects to check
-	// whether connections are ok or not. Objects may not be evaluated yet,
-	// though, since this may require valid connections.
-	ReadObjects();
-	ReadConnections();
+    // This order is important, connections need parsed objects to check
+    // whether connections are ok or not. Objects may not be evaluated yet,
+    // though, since this may require valid connections.
+    ReadObjects();
+    ReadConnections();
 }
 
 
 // ------------------------------------------------------------------------------------------------
 Document::~Document()
 {
-	BOOST_FOREACH(ObjectMap::value_type& v, objects) {
-		delete v.second;
-	}
-
-	BOOST_FOREACH(ConnectionMap::value_type& v, src_connections) {
-		delete v.second;
-	}
-	// |dest_connections| contain the same Connection objects as the |src_connections|
+    BOOST_FOREACH(ObjectMap::value_type& v, objects) {
+        delete v.second;
+    }
+
+    BOOST_FOREACH(ConnectionMap::value_type& v, src_connections) {
+        delete v.second;
+    }
+    // |dest_connections| contain the same Connection objects as the |src_connections|
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void Document::ReadHeader()
 {
-	// Read ID objects from "Objects" section
-	const Scope& sc = parser.GetRootScope();
-	const Element* const ehead = sc["FBXHeaderExtension"];
-	if(!ehead || !ehead->Compound()) {
-		DOMError("no FBXHeaderExtension dictionary found");
-	}
-
-	const Scope& shead = *ehead->Compound();
-	fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
-
-	// While we maye have some success with newer files, we don't support
-	// the older 6.n fbx format
-	if(fbxVersion < 7100) {
-		DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
-	}
-	if(fbxVersion > 7300) {
-		if(Settings().strictMode) {
-			DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013"
-				" (turn off strict mode to try anyhow) ");
-		}
-		else {
-			DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013,"
-				" trying to read it nevertheless");
-		}
-	}
-
-
-	const Element* const ecreator = shead["Creator"];
-	if(ecreator) {
-		creator = ParseTokenAsString(GetRequiredToken(*ecreator,0));
-	}
-
-	const Element* const etimestamp = shead["CreationTimeStamp"];
-	if(etimestamp && etimestamp->Compound()) {
-		const Scope& stimestamp = *etimestamp->Compound();
-		creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0));
-		creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0));
-		creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0));
-		creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0));
-		creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0));
-		creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0));
-		creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0));
-	}
+    // Read ID objects from "Objects" section
+    const Scope& sc = parser.GetRootScope();
+    const Element* const ehead = sc["FBXHeaderExtension"];
+    if(!ehead || !ehead->Compound()) {
+        DOMError("no FBXHeaderExtension dictionary found");
+    }
+
+    const Scope& shead = *ehead->Compound();
+    fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
+
+    // While we maye have some success with newer files, we don't support
+    // the older 6.n fbx format
+    if(fbxVersion < 7100) {
+        DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
+    }
+    if(fbxVersion > 7300) {
+        if(Settings().strictMode) {
+            DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013"
+                " (turn off strict mode to try anyhow) ");
+        }
+        else {
+            DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013,"
+                " trying to read it nevertheless");
+        }
+    }
+
+
+    const Element* const ecreator = shead["Creator"];
+    if(ecreator) {
+        creator = ParseTokenAsString(GetRequiredToken(*ecreator,0));
+    }
+
+    const Element* const etimestamp = shead["CreationTimeStamp"];
+    if(etimestamp && etimestamp->Compound()) {
+        const Scope& stimestamp = *etimestamp->Compound();
+        creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0));
+        creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0));
+        creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0));
+        creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0));
+        creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0));
+        creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0));
+        creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0));
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void Document::ReadGlobalSettings()
 {
-	const Scope& sc = parser.GetRootScope();
-	const Element* const ehead = sc["GlobalSettings"];
-	if(!ehead || !ehead->Compound()) {
-		DOMWarning("no GlobalSettings dictionary found");
+    const Scope& sc = parser.GetRootScope();
+    const Element* const ehead = sc["GlobalSettings"];
+    if(!ehead || !ehead->Compound()) {
+        DOMWarning("no GlobalSettings dictionary found");
 
-		globals.reset(new FileGlobalSettings(*this, boost::make_shared<const PropertyTable>()));
-		return;
-	}
+        globals.reset(new FileGlobalSettings(*this, boost::make_shared<const PropertyTable>()));
+        return;
+    }
 
-	boost::shared_ptr<const PropertyTable> props = GetPropertyTable(*this, "", *ehead, *ehead->Compound(), true);
+    boost::shared_ptr<const PropertyTable> props = GetPropertyTable(*this, "", *ehead, *ehead->Compound(), true);
 
-	if(!props) {
-		DOMError("GlobalSettings dictionary contains no property table");
-	}
+    if(!props) {
+        DOMError("GlobalSettings dictionary contains no property table");
+    }
 
-	globals.reset(new FileGlobalSettings(*this, props));
+    globals.reset(new FileGlobalSettings(*this, props));
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void Document::ReadObjects()
 {
-	// read ID objects from "Objects" section
-	const Scope& sc = parser.GetRootScope();
-	const Element* const eobjects = sc["Objects"];
-	if(!eobjects || !eobjects->Compound()) {
-		DOMError("no Objects dictionary found");
-	}
-
-	// add a dummy entry to represent the Model::RootNode object (id 0),
-	// which is only indirectly defined in the input file
-	objects[0] = new LazyObject(0L, *eobjects, *this);
-
-	const Scope& sobjects = *eobjects->Compound();
-	BOOST_FOREACH(const ElementMap::value_type& el, sobjects.Elements()) {
-
-		// extract ID
-		const TokenList& tok = el.second->Tokens();
-
-		if (tok.empty()) {
-			DOMError("expected ID after object key",el.second);
-		}
-
-		const char* err;
-
-		const uint64_t id = ParseTokenAsID(*tok[0], err);
-		if(err) {
-			DOMError(err,el.second);
-		}
-
-		// id=0 is normally implicit
-		if(id == 0L) {
-			DOMError("encountered object with implicitly defined id 0",el.second);
-		}
-
-		if(objects.find(id) != objects.end()) {
-			DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
-		}
-
-		objects[id] = new LazyObject(id, *el.second, *this);
-
-		// grab all animation stacks upfront since there is no listing of them
-		if(!strcmp(el.first.c_str(),"AnimationStack")) {
-			animationStacks.push_back(id);
-		}
-	}
+    // read ID objects from "Objects" section
+    const Scope& sc = parser.GetRootScope();
+    const Element* const eobjects = sc["Objects"];
+    if(!eobjects || !eobjects->Compound()) {
+        DOMError("no Objects dictionary found");
+    }
+
+    // add a dummy entry to represent the Model::RootNode object (id 0),
+    // which is only indirectly defined in the input file
+    objects[0] = new LazyObject(0L, *eobjects, *this);
+
+    const Scope& sobjects = *eobjects->Compound();
+    BOOST_FOREACH(const ElementMap::value_type& el, sobjects.Elements()) {
+
+        // extract ID
+        const TokenList& tok = el.second->Tokens();
+
+        if (tok.empty()) {
+            DOMError("expected ID after object key",el.second);
+        }
+
+        const char* err;
+
+        const uint64_t id = ParseTokenAsID(*tok[0], err);
+        if(err) {
+            DOMError(err,el.second);
+        }
+
+        // id=0 is normally implicit
+        if(id == 0L) {
+            DOMError("encountered object with implicitly defined id 0",el.second);
+        }
+
+        if(objects.find(id) != objects.end()) {
+            DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
+        }
+
+        objects[id] = new LazyObject(id, *el.second, *this);
+
+        // grab all animation stacks upfront since there is no listing of them
+        if(!strcmp(el.first.c_str(),"AnimationStack")) {
+            animationStacks.push_back(id);
+        }
+    }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void Document::ReadPropertyTemplates()
 {
-	const Scope& sc = parser.GetRootScope();
-	// read property templates from "Definitions" section
-	const Element* const edefs = sc["Definitions"];
-	if(!edefs || !edefs->Compound()) {
-		DOMWarning("no Definitions dictionary found");
-		return;
-	}
-
-	const Scope& sdefs = *edefs->Compound();
-	const ElementCollection otypes = sdefs.GetCollection("ObjectType");
-	for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
-		const Element& el = *(*it).second;
-		const Scope* sc = el.Compound();
-		if(!sc) {
-			DOMWarning("expected nested scope in ObjectType, ignoring",&el);
-			continue;
-		}
-
-		const TokenList& tok = el.Tokens();
-		if(tok.empty()) {
-			DOMWarning("expected name for ObjectType element, ignoring",&el);
-			continue;
-		}
-
-		const std::string& oname = ParseTokenAsString(*tok[0]);
-
-		const ElementCollection templs = sc->GetCollection("PropertyTemplate");
-		for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) {
-			const Element& el = *(*it).second;
-			const Scope* sc = el.Compound();
-			if(!sc) {
-				DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
-				continue;
-			}
-
-			const TokenList& tok = el.Tokens();
-			if(tok.empty()) {
-				DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
-				continue;
-			}
-
-			const std::string& pname = ParseTokenAsString(*tok[0]);
-
-			const Element* Properties70 = (*sc)["Properties70"];
-			if(Properties70) {
-				boost::shared_ptr<const PropertyTable> props = boost::make_shared<const PropertyTable>(
-					*Properties70,boost::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
-				);
-
-				templates[oname+"."+pname] = props;
-			}
-		}
-	}
+    const Scope& sc = parser.GetRootScope();
+    // read property templates from "Definitions" section
+    const Element* const edefs = sc["Definitions"];
+    if(!edefs || !edefs->Compound()) {
+        DOMWarning("no Definitions dictionary found");
+        return;
+    }
+
+    const Scope& sdefs = *edefs->Compound();
+    const ElementCollection otypes = sdefs.GetCollection("ObjectType");
+    for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
+        const Element& el = *(*it).second;
+        const Scope* sc = el.Compound();
+        if(!sc) {
+            DOMWarning("expected nested scope in ObjectType, ignoring",&el);
+            continue;
+        }
+
+        const TokenList& tok = el.Tokens();
+        if(tok.empty()) {
+            DOMWarning("expected name for ObjectType element, ignoring",&el);
+            continue;
+        }
+
+        const std::string& oname = ParseTokenAsString(*tok[0]);
+
+        const ElementCollection templs = sc->GetCollection("PropertyTemplate");
+        for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) {
+            const Element& el = *(*it).second;
+            const Scope* sc = el.Compound();
+            if(!sc) {
+                DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
+                continue;
+            }
+
+            const TokenList& tok = el.Tokens();
+            if(tok.empty()) {
+                DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
+                continue;
+            }
+
+            const std::string& pname = ParseTokenAsString(*tok[0]);
+
+            const Element* Properties70 = (*sc)["Properties70"];
+            if(Properties70) {
+                boost::shared_ptr<const PropertyTable> props = boost::make_shared<const PropertyTable>(
+                    *Properties70,boost::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
+                );
+
+                templates[oname+"."+pname] = props;
+            }
+        }
+    }
 }
 
 
@@ -469,202 +469,202 @@ void Document::ReadPropertyTemplates()
 // ------------------------------------------------------------------------------------------------
 void Document::ReadConnections()
 {
-	const Scope& sc = parser.GetRootScope();
-	// read property templates from "Definitions" section
-	const Element* const econns = sc["Connections"];
-	if(!econns || !econns->Compound()) {
-		DOMError("no Connections dictionary found");
-	}
-
-	uint64_t insertionOrder = 0l;
-
-	const Scope& sconns = *econns->Compound();
-	const ElementCollection conns = sconns.GetCollection("C");
-	for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
-		const Element& el = *(*it).second;
-		const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
-		const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
-		const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
-
-		// OO = object-object connection
-		// OP = object-property connection, in which case the destination property follows the object ID
-		const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : "");
-
-		if(objects.find(src) == objects.end()) {
-			DOMWarning("source object for connection does not exist",&el);
-			continue;
-		}
-
-		// dest may be 0 (root node) but we added a dummy object before
-		if(objects.find(dest) == objects.end()) {
-			DOMWarning("destination object for connection does not exist",&el);
-			continue;
-		}
-
-		// add new connection
-		const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
-		src_connections.insert(ConnectionMap::value_type(src,c));
-		dest_connections.insert(ConnectionMap::value_type(dest,c));
-	}
+    const Scope& sc = parser.GetRootScope();
+    // read property templates from "Definitions" section
+    const Element* const econns = sc["Connections"];
+    if(!econns || !econns->Compound()) {
+        DOMError("no Connections dictionary found");
+    }
+
+    uint64_t insertionOrder = 0l;
+
+    const Scope& sconns = *econns->Compound();
+    const ElementCollection conns = sconns.GetCollection("C");
+    for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
+        const Element& el = *(*it).second;
+        const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
+        const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
+        const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
+
+        // OO = object-object connection
+        // OP = object-property connection, in which case the destination property follows the object ID
+        const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : "");
+
+        if(objects.find(src) == objects.end()) {
+            DOMWarning("source object for connection does not exist",&el);
+            continue;
+        }
+
+        // dest may be 0 (root node) but we added a dummy object before
+        if(objects.find(dest) == objects.end()) {
+            DOMWarning("destination object for connection does not exist",&el);
+            continue;
+        }
+
+        // add new connection
+        const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
+        src_connections.insert(ConnectionMap::value_type(src,c));
+        dest_connections.insert(ConnectionMap::value_type(dest,c));
+    }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const std::vector<const AnimationStack*>& Document::AnimationStacks() const
 {
-	if (!animationStacksResolved.empty() || !animationStacks.size()) {
-		return animationStacksResolved;
-	}
-
-	animationStacksResolved.reserve(animationStacks.size());
-	BOOST_FOREACH(uint64_t id, animationStacks) {
-		LazyObject* const lazy = GetObject(id);
-		const AnimationStack* stack;
-		if(!lazy || !(stack = lazy->Get<AnimationStack>())) {
-			DOMWarning("failed to read AnimationStack object");
-			continue;
-		}
-		animationStacksResolved.push_back(stack);
-	}
-
-	return animationStacksResolved;
+    if (!animationStacksResolved.empty() || !animationStacks.size()) {
+        return animationStacksResolved;
+    }
+
+    animationStacksResolved.reserve(animationStacks.size());
+    BOOST_FOREACH(uint64_t id, animationStacks) {
+        LazyObject* const lazy = GetObject(id);
+        const AnimationStack* stack;
+        if(!lazy || !(stack = lazy->Get<AnimationStack>())) {
+            DOMWarning("failed to read AnimationStack object");
+            continue;
+        }
+        animationStacksResolved.push_back(stack);
+    }
+
+    return animationStacksResolved;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 LazyObject* Document::GetObject(uint64_t id) const
 {
-	ObjectMap::const_iterator it = objects.find(id);
-	return it == objects.end() ? NULL : (*it).second;
+    ObjectMap::const_iterator it = objects.find(id);
+    return it == objects.end() ? NULL : (*it).second;
 }
 
 #define MAX_CLASSNAMES 6
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id,
-	const ConnectionMap& conns) const
+    const ConnectionMap& conns) const
 {
-	std::vector<const Connection*> temp;
+    std::vector<const Connection*> temp;
 
-	const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
-		conns.equal_range(id);
+    const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
+        conns.equal_range(id);
 
-	temp.reserve(std::distance(range.first,range.second));
-	for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
-		temp.push_back((*it).second);
-	}
+    temp.reserve(std::distance(range.first,range.second));
+    for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
+        temp.push_back((*it).second);
+    }
 
-	std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
+    std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
 
-	return temp; // NRVO should handle this
+    return temp; // NRVO should handle this
 }
 
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
-	const ConnectionMap& conns,
-	const char* const* classnames,
-	size_t count) const
+    const ConnectionMap& conns,
+    const char* const* classnames,
+    size_t count) const
 
 {
-	ai_assert(classnames);
-	ai_assert(count != 0 && count <= MAX_CLASSNAMES);
+    ai_assert(classnames);
+    ai_assert(count != 0 && count <= MAX_CLASSNAMES);
 
-	size_t lenghts[MAX_CLASSNAMES];
+    size_t lenghts[MAX_CLASSNAMES];
 
-	const size_t c = count;
-	for (size_t i = 0; i < c; ++i) {
-		lenghts[i] = strlen(classnames[i]);
-	}
+    const size_t c = count;
+    for (size_t i = 0; i < c; ++i) {
+        lenghts[i] = strlen(classnames[i]);
+    }
 
-	std::vector<const Connection*> temp;
+    std::vector<const Connection*> temp;
 
-	const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
-		conns.equal_range(id);
+    const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
+        conns.equal_range(id);
 
-	temp.reserve(std::distance(range.first,range.second));
-	for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
-		const Token& key = (is_src
-			? (*it).second->LazyDestinationObject()
-			: (*it).second->LazySourceObject()
-		).GetElement().KeyToken();
+    temp.reserve(std::distance(range.first,range.second));
+    for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
+        const Token& key = (is_src
+            ? (*it).second->LazyDestinationObject()
+            : (*it).second->LazySourceObject()
+        ).GetElement().KeyToken();
 
-		const char* obtype = key.begin();
+        const char* obtype = key.begin();
 
-		for (size_t i = 0; i < c; ++i) {
-			ai_assert(classnames[i]);
-			if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lenghts[i] && !strncmp(classnames[i],obtype,lenghts[i])) {
-				obtype = NULL;
-				break;
-			}
-		}
+        for (size_t i = 0; i < c; ++i) {
+            ai_assert(classnames[i]);
+            if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lenghts[i] && !strncmp(classnames[i],obtype,lenghts[i])) {
+                obtype = NULL;
+                break;
+            }
+        }
 
-		if(obtype) {
-			continue;
-		}
+        if(obtype) {
+            continue;
+        }
 
-		temp.push_back((*it).second);
-	}
+        temp.push_back((*it).second);
+    }
 
-	std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
-	return temp; // NRVO should handle this
+    std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
+    return temp; // NRVO should handle this
 }
 
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const
 {
-	return GetConnectionsSequenced(source, ConnectionsBySource());
+    return GetConnectionsSequenced(source, ConnectionsBySource());
 }
 
 
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t dest,
-	const char* classname) const
+    const char* classname) const
 {
-	const char* arr[] = {classname};
-	return GetConnectionsBySourceSequenced(dest, arr,1);
+    const char* arr[] = {classname};
+    return GetConnectionsBySourceSequenced(dest, arr,1);
 }
 
 
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source,
-	const char* const* classnames, size_t count) const
+    const char* const* classnames, size_t count) const
 {
-	return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
+    return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
-	const char* classname) const
+    const char* classname) const
 {
-	const char* arr[] = {classname};
-	return GetConnectionsByDestinationSequenced(dest, arr,1);
+    const char* arr[] = {classname};
+    return GetConnectionsByDestinationSequenced(dest, arr,1);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const
 {
-	return GetConnectionsSequenced(dest, ConnectionsByDestination());
+    return GetConnectionsSequenced(dest, ConnectionsByDestination());
 }
 
 
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
-	const char* const* classnames, size_t count) const
+    const char* const* classnames, size_t count) const
 
 {
-	return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
+    return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 Connection::Connection(uint64_t insertionOrder,  uint64_t src, uint64_t dest, const std::string& prop,
-	const Document& doc)
+    const Document& doc)
 
 : insertionOrder(insertionOrder)
 , prop(prop)
@@ -672,9 +672,9 @@ Connection::Connection(uint64_t insertionOrder,  uint64_t src, uint64_t dest, co
 , dest(dest)
 , doc(doc)
 {
-	ai_assert(doc.Objects().find(src) != doc.Objects().end());
-	// dest may be 0 (root node)
-	ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
+    ai_assert(doc.Objects().find(src) != doc.Objects().end());
+    // dest may be 0 (root node)
+    ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
 }
 
 
@@ -688,36 +688,36 @@ Connection::~Connection()
 // ------------------------------------------------------------------------------------------------
 LazyObject& Connection::LazySourceObject() const
 {
-	LazyObject* const lazy = doc.GetObject(src);
-	ai_assert(lazy);
-	return *lazy;
+    LazyObject* const lazy = doc.GetObject(src);
+    ai_assert(lazy);
+    return *lazy;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 LazyObject& Connection::LazyDestinationObject() const
 {
-	LazyObject* const lazy = doc.GetObject(dest);
-	ai_assert(lazy);
-	return *lazy;
+    LazyObject* const lazy = doc.GetObject(dest);
+    ai_assert(lazy);
+    return *lazy;
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const Object* Connection::SourceObject() const
 {
-	LazyObject* const lazy = doc.GetObject(src);
-	ai_assert(lazy);
-	return lazy->Get();
+    LazyObject* const lazy = doc.GetObject(src);
+    ai_assert(lazy);
+    return lazy->Get();
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const Object* Connection::DestinationObject() const
 {
-	LazyObject* const lazy = doc.GetObject(dest);
-	ai_assert(lazy);
-	return lazy->Get();
+    LazyObject* const lazy = doc.GetObject(dest);
+    ai_assert(lazy);
+    return lazy->Get();
 }
 
 } // !FBX

File diff suppressed because it is too large
+ 399 - 399
code/FBXDocument.h


+ 42 - 42
code/FBXDocumentUtil.cpp

@@ -59,16 +59,16 @@ namespace Util {
 // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
 void DOMError(const std::string& message, const Token& token)
 {
-	throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
+    throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
 }
 
 // ------------------------------------------------------------------------------------------------
 void DOMError(const std::string& message, const Element* element /*= NULL*/)
 {
-	if(element) {
-		DOMError(message,element->KeyToken());
-	}
-	throw DeadlyImportError("FBX-DOM " + message);
+    if(element) {
+        DOMError(message,element->KeyToken());
+    }
+    throw DeadlyImportError("FBX-DOM " + message);
 }
 
 
@@ -76,55 +76,55 @@ void DOMError(const std::string& message, const Element* element /*= NULL*/)
 // print warning, do return
 void DOMWarning(const std::string& message, const Token& token)
 {
-	if(DefaultLogger::get()) {
-		DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
-	}
+    if(DefaultLogger::get()) {
+        DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
 {
-	if(element) {
-		DOMWarning(message,element->KeyToken());
-		return;
-	}
-	if(DefaultLogger::get()) {
-		DefaultLogger::get()->warn("FBX-DOM: " + message);
-	}
+    if(element) {
+        DOMWarning(message,element->KeyToken());
+        return;
+    }
+    if(DefaultLogger::get()) {
+        DefaultLogger::get()->warn("FBX-DOM: " + message);
+    }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // fetch a property table and the corresponding property template
 boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
-	const std::string& templateName,
-	const Element &element,
-	const Scope& sc,
-	bool no_warn /*= false*/)
+    const std::string& templateName,
+    const Element &element,
+    const Scope& sc,
+    bool no_warn /*= false*/)
 {
-	const Element* const Properties70 = sc["Properties70"];
-	boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
-		static_cast<const PropertyTable*>(NULL));
-
-	if(templateName.length()) {
-		PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
-		if(it != doc.Templates().end()) {
-			templateProps = (*it).second;
-		}
-	}
-
-	if(!Properties70) {
-		if(!no_warn) {
-			DOMWarning("property table (Properties70) not found",&element);
-		}
-		if(templateProps) {
-			return templateProps;
-		}
-		else {
-			return boost::make_shared<const PropertyTable>();
-		}
-	}
-	return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
+    const Element* const Properties70 = sc["Properties70"];
+    boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
+        static_cast<const PropertyTable*>(NULL));
+
+    if(templateName.length()) {
+        PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
+        if(it != doc.Templates().end()) {
+            templateProps = (*it).second;
+        }
+    }
+
+    if(!Properties70) {
+        if(!no_warn) {
+            DOMWarning("property table (Properties70) not found",&element);
+        }
+        if(templateProps) {
+            return templateProps;
+        }
+        else {
+            return boost::make_shared<const PropertyTable>();
+        }
+    }
+    return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
 }
 } // !Util
 } // !FBX

+ 38 - 38
code/FBXDocumentUtil.h

@@ -68,50 +68,50 @@ void DOMWarning(const std::string& message, const Element* element = NULL);
 
 // fetch a property table and the corresponding property template
 boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
-	const std::string& templateName,
-	const Element &element,
-	const Scope& sc,
-	bool no_warn = false);
+    const std::string& templateName,
+    const Element &element,
+    const Scope& sc,
+    bool no_warn = false);
 
 
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 inline const T* ProcessSimpleConnection(const Connection& con,
-	bool is_object_property_conn,
-	const char* name,
-	const Element& element,
-	const char** propNameOut = NULL)
+    bool is_object_property_conn,
+    const char* name,
+    const Element& element,
+    const char** propNameOut = NULL)
 {
-	if (is_object_property_conn && !con.PropertyName().length()) {
-		DOMWarning("expected incoming " + std::string(name) +
-			" link to be an object-object connection, ignoring",
-			&element
-			);
-		return NULL;
-	}
-	else if (!is_object_property_conn && con.PropertyName().length()) {
-		DOMWarning("expected incoming " + std::string(name) +
-			" link to be an object-property connection, ignoring",
-			&element
-			);
-		return NULL;
-	}
-
-	if(is_object_property_conn && propNameOut) {
-		// note: this is ok, the return value of PropertyValue() is guaranteed to
-		// remain valid and unchanged as long as the document exists.
-		*propNameOut = con.PropertyName().c_str();
-	}
-
-	const Object* const ob = con.SourceObject();
-	if(!ob) {
-		DOMWarning("failed to read source object for incoming" + std::string(name) +
-			" link, ignoring",
-			&element);
-		return NULL;
-	}
-
-	return dynamic_cast<const T*>(ob);
+    if (is_object_property_conn && !con.PropertyName().length()) {
+        DOMWarning("expected incoming " + std::string(name) +
+            " link to be an object-object connection, ignoring",
+            &element
+            );
+        return NULL;
+    }
+    else if (!is_object_property_conn && con.PropertyName().length()) {
+        DOMWarning("expected incoming " + std::string(name) +
+            " link to be an object-property connection, ignoring",
+            &element
+            );
+        return NULL;
+    }
+
+    if(is_object_property_conn && propNameOut) {
+        // note: this is ok, the return value of PropertyValue() is guaranteed to
+        // remain valid and unchanged as long as the document exists.
+        *propNameOut = con.PropertyName().c_str();
+    }
+
+    const Object* const ob = con.SourceObject();
+    if(!ob) {
+        DOMWarning("failed to read source object for incoming" + std::string(name) +
+            " link, ignoring",
+            &element);
+        return NULL;
+    }
+
+    return dynamic_cast<const T*>(ob);
 }
 
 

+ 82 - 82
code/FBXImportSettings.h

@@ -50,88 +50,88 @@ namespace FBX {
 /** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
 struct ImportSettings
 {
-	ImportSettings()
-		: strictMode(true)
-		, readAllLayers(true)
-		, readAllMaterials(false)
-		, readMaterials(true)
-		, readCameras(true)
-		, readLights(true)
-		, readAnimations(true)
-		, readWeights(true)
-		, preservePivots(true)
-		, optimizeEmptyAnimationCurves(true)
-	{}
-
-
-	/** enable strict mode:
-	 *   - only accept fbx 2012, 2013 files
-	 *   - on the slightest error, give up.
-	 *
-	 *  Basically, strict mode means that the fbx file will actually
-	 *  be validated. Strict mode is off by default. */
-	bool strictMode;
-
-	/** specifies whether all geometry layers are read and scanned for
-	  * usable data channels. The FBX spec indicates that many readers
-	  * will only read the first channel and that this is in some way
-	  * the recommended way- in reality, however, it happens a lot that
-	  * vertex data is spread among multiple layers. The default
-	  * value for this option is true.*/
-	bool readAllLayers;
-
-	/** specifies whether all materials are read, or only those that
-	 *  are referenced by at least one mesh. Reading all materials
-	 *  may make FBX reading a lot slower since all objects
-	 *  need to be processed .
-	 *  This bit is ignored unless readMaterials=true*/
-	bool readAllMaterials;
-
-
-	/** import materials (true) or skip them and assign a default
-	 *  material. The default value is true.*/
-	bool readMaterials;
-
-	/** import cameras? Default value is true.*/
-	bool readCameras;
-
-	/** import light sources? Default value is true.*/
-	bool readLights;
-
-	/** import animations (i.e. animation curves, the node
-	 *  skeleton is always imported). Default value is true. */
-	bool readAnimations;
-
-	/** read bones (vertex weights and deform info).
-	 *  Default value is true. */
-	bool readWeights;
-
-	/** preserve transformation pivots and offsets. Since these can
-	 *  not directly be represented in assimp, additional dummy
-	 *  nodes will be generated. Note that settings this to false
-	 *  can make animation import a lot slower. The default value
-	 *  is true.
-	 *
-	 *  The naming scheme for the generated nodes is:
-	 *    <OriginalName>_$AssimpFbx$_<TransformName>
-	 *
-	 *  where <TransformName> is one of
-	 *    RotationPivot
-	 *    RotationOffset
-	 *    PreRotation
-	 *    PostRotation
-	 *    ScalingPivot
-	 *    ScalingOffset
-	 *    Translation
-	 *    Scaling
-	 *    Rotation
-	 **/
-	bool preservePivots;
-
-	/** do not import animation curves that specify a constant
-	 *  values matching the corresponding node transformation.
-	 *  The default value is true. */
-	bool optimizeEmptyAnimationCurves;
+    ImportSettings()
+        : strictMode(true)
+        , readAllLayers(true)
+        , readAllMaterials(false)
+        , readMaterials(true)
+        , readCameras(true)
+        , readLights(true)
+        , readAnimations(true)
+        , readWeights(true)
+        , preservePivots(true)
+        , optimizeEmptyAnimationCurves(true)
+    {}
+
+
+    /** enable strict mode:
+     *   - only accept fbx 2012, 2013 files
+     *   - on the slightest error, give up.
+     *
+     *  Basically, strict mode means that the fbx file will actually
+     *  be validated. Strict mode is off by default. */
+    bool strictMode;
+
+    /** specifies whether all geometry layers are read and scanned for
+      * usable data channels. The FBX spec indicates that many readers
+      * will only read the first channel and that this is in some way
+      * the recommended way- in reality, however, it happens a lot that
+      * vertex data is spread among multiple layers. The default
+      * value for this option is true.*/
+    bool readAllLayers;
+
+    /** specifies whether all materials are read, or only those that
+     *  are referenced by at least one mesh. Reading all materials
+     *  may make FBX reading a lot slower since all objects
+     *  need to be processed .
+     *  This bit is ignored unless readMaterials=true*/
+    bool readAllMaterials;
+
+
+    /** import materials (true) or skip them and assign a default
+     *  material. The default value is true.*/
+    bool readMaterials;
+
+    /** import cameras? Default value is true.*/
+    bool readCameras;
+
+    /** import light sources? Default value is true.*/
+    bool readLights;
+
+    /** import animations (i.e. animation curves, the node
+     *  skeleton is always imported). Default value is true. */
+    bool readAnimations;
+
+    /** read bones (vertex weights and deform info).
+     *  Default value is true. */
+    bool readWeights;
+
+    /** preserve transformation pivots and offsets. Since these can
+     *  not directly be represented in assimp, additional dummy
+     *  nodes will be generated. Note that settings this to false
+     *  can make animation import a lot slower. The default value
+     *  is true.
+     *
+     *  The naming scheme for the generated nodes is:
+     *    <OriginalName>_$AssimpFbx$_<TransformName>
+     *
+     *  where <TransformName> is one of
+     *    RotationPivot
+     *    RotationOffset
+     *    PreRotation
+     *    PostRotation
+     *    ScalingPivot
+     *    ScalingOffset
+     *    Translation
+     *    Scaling
+     *    Rotation
+     **/
+    bool preservePivots;
+
+    /** do not import animation curves that specify a constant
+     *  values matching the corresponding node transformation.
+     *  The default value is true. */
+    bool optimizeEmptyAnimationCurves;
 };
 
 

+ 77 - 77
code/FBXImporter.cpp

@@ -61,7 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/Importer.hpp"
 
 namespace Assimp {
-	template<> const std::string LogFunctions<FBXImporter>::log_prefix = "FBX: ";
+    template<> const std::string LogFunctions<FBXImporter>::log_prefix = "FBX: ";
 }
 
 using namespace Assimp;
@@ -70,16 +70,16 @@ using namespace Assimp::FBX;
 
 namespace {
 static const aiImporterDesc desc = {
-	"Autodesk FBX Importer",
-	"",
-	"",
-	"",
-	aiImporterFlags_SupportTextFlavour,
-	0,
-	0,
-	0,
-	0,
-	"fbx"
+    "Autodesk FBX Importer",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "fbx"
 };
 }
 
@@ -98,24 +98,24 @@ FBXImporter::~FBXImporter()
 // Returns whether the class can handle the format of the given file.
 bool FBXImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-	const std::string& extension = GetExtension(pFile);
-	if (extension == "fbx") {
-		return true;
-	}
-
-	else if ((!extension.length() || checkSig) && pIOHandler)	{
-		// at least ascii FBX files usually have a 'FBX' somewhere in their head
-		const char* tokens[] = {"fbx"};
-		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-	}
-	return false;
+    const std::string& extension = GetExtension(pFile);
+    if (extension == "fbx") {
+        return true;
+    }
+
+    else if ((!extension.length() || checkSig) && pIOHandler)   {
+        // at least ascii FBX files usually have a 'FBX' somewhere in their head
+        const char* tokens[] = {"fbx"};
+        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
+    }
+    return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // List all extensions handled by this loader
 const aiImporterDesc* FBXImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 
@@ -123,69 +123,69 @@ const aiImporterDesc* FBXImporter::GetInfo () const
 // Setup configuration properties for the loader
 void FBXImporter::SetupProperties(const Importer* pImp)
 {
-	settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
-	settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
-	settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
-	settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
-	settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
-	settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
-	settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
-	settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
-	settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
+    settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
+    settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
+    settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
+    settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
+    settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
+    settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
+    settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
+    settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
+    settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void FBXImporter::InternReadFile( const std::string& pFile,
-	aiScene* pScene, IOSystem* pIOHandler)
+    aiScene* pScene, IOSystem* pIOHandler)
 {
-	boost::scoped_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
-	if (!stream) {
-		ThrowException("Could not open file for reading");
-	}
-
-	// read entire file into memory - no streaming for this, fbx
-	// files can grow large, but the assimp output data structure
-	// then becomes very large, too. Assimp doesn't support
-	// streaming for its output data structures so the net win with
-	// streaming input data would be very low.
-	std::vector<char> contents;
-	contents.resize(stream->FileSize()+1);
+    boost::scoped_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
+    if (!stream) {
+        ThrowException("Could not open file for reading");
+    }
+
+    // read entire file into memory - no streaming for this, fbx
+    // files can grow large, but the assimp output data structure
+    // then becomes very large, too. Assimp doesn't support
+    // streaming for its output data structures so the net win with
+    // streaming input data would be very low.
+    std::vector<char> contents;
+    contents.resize(stream->FileSize()+1);
     stream->Read( &*contents.begin(), 1, contents.size()-1 );
     contents[ contents.size() - 1 ] = 0;
-	const char* const begin = &*contents.begin();
-
-	// broadphase tokenizing pass in which we identify the core
-	// syntax elements of FBX (brackets, commas, key:value mappings)
-	TokenList tokens;
-	try {
-
-		bool is_binary = false;
-		if (!strncmp(begin,"Kaydara FBX Binary",18)) {
-			is_binary = true;
-			TokenizeBinary(tokens,begin,contents.size());
-		}
-		else {
-			Tokenize(tokens,begin);
-		}
-
-		// use this information to construct a very rudimentary
-		// parse-tree representing the FBX scope structure
-		Parser parser(tokens, is_binary);
-
-		// take the raw parse-tree and convert it to a FBX DOM
-		Document doc(parser,settings);
-
-		// convert the FBX DOM to aiScene
-		ConvertToAssimpScene(pScene,doc);
-
-		std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
-	}
-	catch(std::exception&) {
-		std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
-		throw;
-	}
+    const char* const begin = &*contents.begin();
+
+    // broadphase tokenizing pass in which we identify the core
+    // syntax elements of FBX (brackets, commas, key:value mappings)
+    TokenList tokens;
+    try {
+
+        bool is_binary = false;
+        if (!strncmp(begin,"Kaydara FBX Binary",18)) {
+            is_binary = true;
+            TokenizeBinary(tokens,begin,contents.size());
+        }
+        else {
+            Tokenize(tokens,begin);
+        }
+
+        // use this information to construct a very rudimentary
+        // parse-tree representing the FBX scope structure
+        Parser parser(tokens, is_binary);
+
+        // take the raw parse-tree and convert it to a FBX DOM
+        Document doc(parser,settings);
+
+        // convert the FBX DOM to aiScene
+        ConvertToAssimpScene(pScene,doc);
+
+        std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
+    }
+    catch(std::exception&) {
+        std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
+        throw;
+    }
 }
 
 #endif // !ASSIMP_BUILD_NO_FBX_IMPORTER

+ 23 - 23
code/FBXImporter.h

@@ -49,13 +49,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "FBXImportSettings.h"
 
-namespace Assimp	{
+namespace Assimp    {
 
-	// TinyFormatter.h
-	namespace Formatter {
-		template <typename T,typename TR, typename A> class basic_formatter;
-		typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
-	}
+    // TinyFormatter.h
+    namespace Formatter {
+        template <typename T,typename TR, typename A> class basic_formatter;
+        typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
+    }
 
 
 // -------------------------------------------------------------------------------------------
@@ -67,38 +67,38 @@ namespace Assimp	{
 class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter>
 {
 public:
-	FBXImporter();
-	~FBXImporter();
+    FBXImporter();
+    ~FBXImporter();
 
 
 public:
 
-	// --------------------
-	bool CanRead( const std::string& pFile,
-		IOSystem* pIOHandler,
-		bool checkSig
-	) const;
+    // --------------------
+    bool CanRead( const std::string& pFile,
+        IOSystem* pIOHandler,
+        bool checkSig
+    ) const;
 
 protected:
 
-	// --------------------
-	const aiImporterDesc* GetInfo () const;
+    // --------------------
+    const aiImporterDesc* GetInfo () const;
 
-	// --------------------
-	void SetupProperties(const Importer* pImp);
+    // --------------------
+    void SetupProperties(const Importer* pImp);
 
-	// --------------------
-	void InternReadFile( const std::string& pFile,
-		aiScene* pScene,
-		IOSystem* pIOHandler
-	);
+    // --------------------
+    void InternReadFile( const std::string& pFile,
+        aiScene* pScene,
+        IOSystem* pIOHandler
+    );
 
 private:
 
 
 private:
 
-	FBX::ImportSettings settings;
+    FBX::ImportSettings settings;
 
 }; // !class FBXImporter
 

+ 148 - 148
code/FBXMaterial.cpp

@@ -55,85 +55,85 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	using namespace Util;
+    using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
 Material::Material(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 : Object(id,element,name)
 {
-	const Scope& sc = GetRequiredScope(element);
-
-	const Element* const ShadingModel = sc["ShadingModel"];
-	const Element* const MultiLayer = sc["MultiLayer"];
-
-	if(MultiLayer) {
-		multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
-	}
-
-	if(ShadingModel) {
-		shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
-	}
-	else {
-		DOMWarning("shading mode not specified, assuming phong",&element);
-		shading = "phong";
-	}
-
-	std::string templateName;
-
-	const char* const sh = shading.c_str();
-	if(!strcmp(sh,"phong")) {
-		templateName = "Material.FbxSurfacePhong";
-	}
-	else if(!strcmp(sh,"lambert")) {
-		templateName = "Material.FbxSurfaceLambert";
-	}
-	else {
-		DOMWarning("shading mode not recognized: " + shading,&element);
-	}
-
-	props = GetPropertyTable(doc,templateName,element,sc);
-
-	// resolve texture links
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
-	BOOST_FOREACH(const Connection* con, conns) {
-
-		// texture link to properties, not objects
-		if (!con->PropertyName().length()) {
-			continue;
-		}
-
-		const Object* const ob = con->SourceObject();
-		if(!ob) {
-			DOMWarning("failed to read source object for texture link, ignoring",&element);
-			continue;
-		}
-
-		const Texture* const tex = dynamic_cast<const Texture*>(ob);
-		if(!tex) {
-			const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
-			if(!layeredTexture) {
-				DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
-				continue;
-			}
-			const std::string& prop = con->PropertyName();
-			if (layeredTextures.find(prop) != layeredTextures.end()) {
-				DOMWarning("duplicate layered texture link: " + prop,&element);
-			}
-
-			layeredTextures[prop] = layeredTexture;
-			((LayeredTexture*)layeredTexture)->fillTexture(doc);
-		}
-		else
-		{
-			const std::string& prop = con->PropertyName();
-			if (textures.find(prop) != textures.end()) {
-				DOMWarning("duplicate texture link: " + prop,&element);
-			}
-
-			textures[prop] = tex;
-		}
-
-	}
+    const Scope& sc = GetRequiredScope(element);
+
+    const Element* const ShadingModel = sc["ShadingModel"];
+    const Element* const MultiLayer = sc["MultiLayer"];
+
+    if(MultiLayer) {
+        multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
+    }
+
+    if(ShadingModel) {
+        shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
+    }
+    else {
+        DOMWarning("shading mode not specified, assuming phong",&element);
+        shading = "phong";
+    }
+
+    std::string templateName;
+
+    const char* const sh = shading.c_str();
+    if(!strcmp(sh,"phong")) {
+        templateName = "Material.FbxSurfacePhong";
+    }
+    else if(!strcmp(sh,"lambert")) {
+        templateName = "Material.FbxSurfaceLambert";
+    }
+    else {
+        DOMWarning("shading mode not recognized: " + shading,&element);
+    }
+
+    props = GetPropertyTable(doc,templateName,element,sc);
+
+    // resolve texture links
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
+    BOOST_FOREACH(const Connection* con, conns) {
+
+        // texture link to properties, not objects
+        if (!con->PropertyName().length()) {
+            continue;
+        }
+
+        const Object* const ob = con->SourceObject();
+        if(!ob) {
+            DOMWarning("failed to read source object for texture link, ignoring",&element);
+            continue;
+        }
+
+        const Texture* const tex = dynamic_cast<const Texture*>(ob);
+        if(!tex) {
+            const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
+            if(!layeredTexture) {
+                DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
+                continue;
+            }
+            const std::string& prop = con->PropertyName();
+            if (layeredTextures.find(prop) != layeredTextures.end()) {
+                DOMWarning("duplicate layered texture link: " + prop,&element);
+            }
+
+            layeredTextures[prop] = layeredTexture;
+            ((LayeredTexture*)layeredTexture)->fillTexture(doc);
+        }
+        else
+        {
+            const std::string& prop = con->PropertyName();
+            if (textures.find(prop) != textures.end()) {
+                DOMWarning("duplicate texture link: " + prop,&element);
+            }
+
+            textures[prop] = tex;
+        }
+
+    }
 }
 
 
@@ -148,57 +148,57 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const
 : Object(id,element,name)
 , uvScaling(1.0f,1.0f)
 {
-	const Scope& sc = GetRequiredScope(element);
-
-	const Element* const Type = sc["Type"];
-	const Element* const FileName = sc["FileName"];
-	const Element* const RelativeFilename = sc["RelativeFilename"];
-	const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
-	const Element* const ModelUVScaling = sc["ModelUVScaling"];
-	const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
-	const Element* const Cropping = sc["Cropping"];
-
-	if(Type) {
-		type = ParseTokenAsString(GetRequiredToken(*Type,0));
-	}
-
-	if(FileName) {
-		fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
-	}
-
-	if(RelativeFilename) {
-		relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
-	}
-
-	if(ModelUVTranslation) {
-		uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
-			ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
-		);
-	}
-
-	if(ModelUVScaling) {
-		uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
-			ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
-		);
-	}
-
-	if(Cropping) {
-		crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
-		crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
-		crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
-		crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
-	}
-	else {
-		// vc8 doesn't support the crop() syntax in initialization lists
-		// (and vc9 WARNS about the new (i.e. compliant) behaviour).
-		crop[0] = crop[1] = crop[2] = crop[3] = 0;
-	}
-
-	if(Texture_Alpha_Source) {
-		alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
-	}
-
-	props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
+    const Scope& sc = GetRequiredScope(element);
+
+    const Element* const Type = sc["Type"];
+    const Element* const FileName = sc["FileName"];
+    const Element* const RelativeFilename = sc["RelativeFilename"];
+    const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
+    const Element* const ModelUVScaling = sc["ModelUVScaling"];
+    const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
+    const Element* const Cropping = sc["Cropping"];
+
+    if(Type) {
+        type = ParseTokenAsString(GetRequiredToken(*Type,0));
+    }
+
+    if(FileName) {
+        fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
+    }
+
+    if(RelativeFilename) {
+        relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
+    }
+
+    if(ModelUVTranslation) {
+        uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
+            ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
+        );
+    }
+
+    if(ModelUVScaling) {
+        uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
+            ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
+        );
+    }
+
+    if(Cropping) {
+        crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
+        crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
+        crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
+        crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
+    }
+    else {
+        // vc8 doesn't support the crop() syntax in initialization lists
+        // (and vc9 WARNS about the new (i.e. compliant) behaviour).
+        crop[0] = crop[1] = crop[2] = crop[3] = 0;
+    }
+
+    if(Texture_Alpha_Source) {
+        alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
+    }
+
+    props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
 }
 
 
@@ -213,20 +213,20 @@ LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Docume
 ,blendMode(BlendMode_Modulate)
 ,alpha(1)
 {
-	const Scope& sc = GetRequiredScope(element);
+    const Scope& sc = GetRequiredScope(element);
 
-	const Element* const BlendModes = sc["BlendModes"];
-	const Element* const Alphas = sc["Alphas"];
+    const Element* const BlendModes = sc["BlendModes"];
+    const Element* const Alphas = sc["Alphas"];
 
 
-	if(BlendModes!=0)
-	{
-		blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
-	}
-	if(Alphas!=0)
-	{
-		alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
-	}
+    if(BlendModes!=0)
+    {
+        blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
+    }
+    if(Alphas!=0)
+    {
+        alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
+    }
 }
 
 LayeredTexture::~LayeredTexture()
@@ -236,21 +236,21 @@ LayeredTexture::~LayeredTexture()
 
 void LayeredTexture::fillTexture(const Document& doc)
 {
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
-	for(size_t i = 0; i < conns.size();++i)
-	{
-		const Connection* con = conns.at(i);
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
+    for(size_t i = 0; i < conns.size();++i)
+    {
+        const Connection* con = conns.at(i);
 
-		const Object* const ob = con->SourceObject();
-		if(!ob) {
-			DOMWarning("failed to read source object for texture link, ignoring",&element);
-			continue;
-		}
+        const Object* const ob = con->SourceObject();
+        if(!ob) {
+            DOMWarning("failed to read source object for texture link, ignoring",&element);
+            continue;
+        }
 
-		const Texture* const tex = dynamic_cast<const Texture*>(ob);
+        const Texture* const tex = dynamic_cast<const Texture*>(ob);
 
-		texture = tex;
-	}
+        texture = tex;
+    }
 }
 
 } //!FBX

+ 380 - 380
code/FBXMeshGeometry.cpp

@@ -57,22 +57,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	using namespace Util;
+    using namespace Util;
 
 
 // ------------------------------------------------------------------------------------------------
 Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
-	: Object(id, element,name)
-	, skin()
+    : Object(id, element,name)
+    , skin()
 {
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
-	BOOST_FOREACH(const Connection* con, conns) {
-		const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
-		if(sk) {
-			skin = sk;
-			break;
-		}
-	}
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
+    BOOST_FOREACH(const Connection* con, conns) {
+        const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
+        if(sk) {
+            skin = sk;
+            break;
+        }
+    }
 }
 
 
@@ -88,98 +88,98 @@ Geometry::~Geometry()
 MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
 : Geometry(id, element,name, doc)
 {
-	const Scope* sc = element.Compound();
-	if (!sc) {
-		DOMError("failed to read Geometry object (class: Mesh), no data scope found");
-	}
-
-	// must have Mesh elements:
-	const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
-	const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
-
-	// optional Mesh elements:
-	const ElementCollection& Layer = sc->GetCollection("Layer");
-
-	std::vector<aiVector3D> tempVerts;
-	ParseVectorDataArray(tempVerts,Vertices);
-
-	if(tempVerts.empty()) {
-		FBXImporter::LogWarn("encountered mesh with no vertices");
-		return;
-	}
-
-	std::vector<int> tempFaces;
-	ParseVectorDataArray(tempFaces,PolygonVertexIndex);
-
-	if(tempFaces.empty()) {
-		FBXImporter::LogWarn("encountered mesh with no faces");
-		return;
-	}
-
-	vertices.reserve(tempFaces.size());
-	faces.reserve(tempFaces.size() / 3);
-
-	mapping_offsets.resize(tempVerts.size());
-	mapping_counts.resize(tempVerts.size(),0);
-	mappings.resize(tempFaces.size());
-
-	const size_t vertex_count = tempVerts.size();
-
-	// generate output vertices, computing an adjacency table to
-	// preserve the mapping from fbx indices to *this* indexing.
-	unsigned int count = 0;
-	BOOST_FOREACH(int index, tempFaces) {
-		const int absi = index < 0 ? (-index - 1) : index;
-		if(static_cast<size_t>(absi) >= vertex_count) {
-			DOMError("polygon vertex index out of range",&PolygonVertexIndex);
-		}
-
-		vertices.push_back(tempVerts[absi]);
-		++count;
-
-		++mapping_counts[absi];
-
-		if (index < 0) {
-			faces.push_back(count);
-			count = 0;
-		}
-	}
-
-	unsigned int cursor = 0;
-	for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
-		mapping_offsets[i] = cursor;
-		cursor += mapping_counts[i];
-
-		mapping_counts[i] = 0;
-	}
-
-	cursor = 0;
-	BOOST_FOREACH(int index, tempFaces) {
-		const int absi = index < 0 ? (-index - 1) : index;
-		mappings[mapping_offsets[absi] + mapping_counts[absi]++] = cursor++;
-	}
-
-	// if settings.readAllLayers is true:
-	//  * read all layers, try to load as many vertex channels as possible
-	// if settings.readAllLayers is false:
-	//  * read only the layer with index 0, but warn about any further layers
-	for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
-		const TokenList& tokens = (*it).second->Tokens();
-
-		const char* err;
-		const int index = ParseTokenAsInt(*tokens[0], err);
-		if(err) {
-			DOMError(err,&element);
-		}
-
-		if(doc.Settings().readAllLayers || index == 0) {
-			const Scope& layer = GetRequiredScope(*(*it).second);
-			ReadLayer(layer);
-		}
-		else {
-			FBXImporter::LogWarn("ignoring additional geometry layers");
-		}
-	}
+    const Scope* sc = element.Compound();
+    if (!sc) {
+        DOMError("failed to read Geometry object (class: Mesh), no data scope found");
+    }
+
+    // must have Mesh elements:
+    const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
+    const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
+
+    // optional Mesh elements:
+    const ElementCollection& Layer = sc->GetCollection("Layer");
+
+    std::vector<aiVector3D> tempVerts;
+    ParseVectorDataArray(tempVerts,Vertices);
+
+    if(tempVerts.empty()) {
+        FBXImporter::LogWarn("encountered mesh with no vertices");
+        return;
+    }
+
+    std::vector<int> tempFaces;
+    ParseVectorDataArray(tempFaces,PolygonVertexIndex);
+
+    if(tempFaces.empty()) {
+        FBXImporter::LogWarn("encountered mesh with no faces");
+        return;
+    }
+
+    vertices.reserve(tempFaces.size());
+    faces.reserve(tempFaces.size() / 3);
+
+    mapping_offsets.resize(tempVerts.size());
+    mapping_counts.resize(tempVerts.size(),0);
+    mappings.resize(tempFaces.size());
+
+    const size_t vertex_count = tempVerts.size();
+
+    // generate output vertices, computing an adjacency table to
+    // preserve the mapping from fbx indices to *this* indexing.
+    unsigned int count = 0;
+    BOOST_FOREACH(int index, tempFaces) {
+        const int absi = index < 0 ? (-index - 1) : index;
+        if(static_cast<size_t>(absi) >= vertex_count) {
+            DOMError("polygon vertex index out of range",&PolygonVertexIndex);
+        }
+
+        vertices.push_back(tempVerts[absi]);
+        ++count;
+
+        ++mapping_counts[absi];
+
+        if (index < 0) {
+            faces.push_back(count);
+            count = 0;
+        }
+    }
+
+    unsigned int cursor = 0;
+    for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
+        mapping_offsets[i] = cursor;
+        cursor += mapping_counts[i];
+
+        mapping_counts[i] = 0;
+    }
+
+    cursor = 0;
+    BOOST_FOREACH(int index, tempFaces) {
+        const int absi = index < 0 ? (-index - 1) : index;
+        mappings[mapping_offsets[absi] + mapping_counts[absi]++] = cursor++;
+    }
+
+    // if settings.readAllLayers is true:
+    //  * read all layers, try to load as many vertex channels as possible
+    // if settings.readAllLayers is false:
+    //  * read only the layer with index 0, but warn about any further layers
+    for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
+        const TokenList& tokens = (*it).second->Tokens();
+
+        const char* err;
+        const int index = ParseTokenAsInt(*tokens[0], err);
+        if(err) {
+            DOMError(err,&element);
+        }
+
+        if(doc.Settings().readAllLayers || index == 0) {
+            const Scope& layer = GetRequiredScope(*(*it).second);
+            ReadLayer(layer);
+        }
+        else {
+            FBXImporter::LogWarn("ignoring additional geometry layers");
+        }
+    }
 }
 
 
@@ -194,141 +194,141 @@ MeshGeometry::~MeshGeometry()
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadLayer(const Scope& layer)
 {
-	const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
-	for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
-		const Scope& elayer = GetRequiredScope(*(*eit).second);
+    const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
+    for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
+        const Scope& elayer = GetRequiredScope(*(*eit).second);
 
-		ReadLayerElement(elayer);
-	}
+        ReadLayerElement(elayer);
+    }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadLayerElement(const Scope& layerElement)
 {
-	const Element& Type = GetRequiredElement(layerElement,"Type");
-	const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
+    const Element& Type = GetRequiredElement(layerElement,"Type");
+    const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
 
-	const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
-	const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
+    const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
+    const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
 
-	const Scope& top = GetRequiredScope(element);
-	const ElementCollection candidates = top.GetCollection(type);
+    const Scope& top = GetRequiredScope(element);
+    const ElementCollection candidates = top.GetCollection(type);
 
-	for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
-		const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
-		if(index == typedIndex) {
-			ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
-			return;
-		}
-	}
+    for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
+        const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
+        if(index == typedIndex) {
+            ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
+            return;
+        }
+    }
 
-	FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
-		<< type << ", index: " << typedIndex);
+    FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
+        << type << ", index: " << typedIndex);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
 {
-	const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
-		GetRequiredElement(source,"MappingInformationType"),0)
-	);
-
-	const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
-		GetRequiredElement(source,"ReferenceInformationType"),0)
-	);
-
-	if (type == "LayerElementUV") {
-		if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
-			FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
-				<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
-			return;
-		}
-
-		const Element* Name = source["Name"];
-		uvNames[index] = "";
-		if(Name) {
-			uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
-		}
-
-		ReadVertexDataUV(uvs[index],source,
-			MappingInformationType,
-			ReferenceInformationType
-		);
-	}
-	else if (type == "LayerElementMaterial") {
-		if (materials.size() > 0) {
-			FBXImporter::LogError("ignoring additional material layer");
-			return;
-		}
-
-		std::vector<int> temp_materials;
-
-		ReadVertexDataMaterials(temp_materials,source,
-			MappingInformationType,
-			ReferenceInformationType
-		);
-
-		// sometimes, there will be only negative entries. Drop the material
-		// layer in such a case (I guess it means a default material should
-		// be used). This is what the converter would do anyway, and it
-		// avoids loosing the material if there are more material layers
-		// coming of which at least one contains actual data (did observe
-		// that with one test file).
-		const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less<int>(),0));
-		if(count_neg == temp_materials.size()) {
-			FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
-			return;
-		}
-
-		std::swap(temp_materials, materials);
-	}
-	else if (type == "LayerElementNormal") {
-		if (normals.size() > 0) {
-			FBXImporter::LogError("ignoring additional normal layer");
-			return;
-		}
-
-		ReadVertexDataNormals(normals,source,
-			MappingInformationType,
-			ReferenceInformationType
-		);
-	}
-	else if (type == "LayerElementTangent") {
-		if (tangents.size() > 0) {
-			FBXImporter::LogError("ignoring additional tangent layer");
-			return;
-		}
-
-		ReadVertexDataTangents(tangents,source,
-			MappingInformationType,
-			ReferenceInformationType
-		);
-	}
-	else if (type == "LayerElementBinormal") {
-		if (binormals.size() > 0) {
-			FBXImporter::LogError("ignoring additional binormal layer");
-			return;
-		}
-
-		ReadVertexDataBinormals(binormals,source,
-			MappingInformationType,
-			ReferenceInformationType
-		);
-	}
-	else if (type == "LayerElementColor") {
-		if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
-			FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
-				<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
-			return;
-		}
-
-		ReadVertexDataColors(colors[index],source,
-			MappingInformationType,
-			ReferenceInformationType
-		);
-	}
+    const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
+        GetRequiredElement(source,"MappingInformationType"),0)
+    );
+
+    const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
+        GetRequiredElement(source,"ReferenceInformationType"),0)
+    );
+
+    if (type == "LayerElementUV") {
+        if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
+            FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
+                << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
+            return;
+        }
+
+        const Element* Name = source["Name"];
+        uvNames[index] = "";
+        if(Name) {
+            uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
+        }
+
+        ReadVertexDataUV(uvs[index],source,
+            MappingInformationType,
+            ReferenceInformationType
+        );
+    }
+    else if (type == "LayerElementMaterial") {
+        if (materials.size() > 0) {
+            FBXImporter::LogError("ignoring additional material layer");
+            return;
+        }
+
+        std::vector<int> temp_materials;
+
+        ReadVertexDataMaterials(temp_materials,source,
+            MappingInformationType,
+            ReferenceInformationType
+        );
+
+        // sometimes, there will be only negative entries. Drop the material
+        // layer in such a case (I guess it means a default material should
+        // be used). This is what the converter would do anyway, and it
+        // avoids loosing the material if there are more material layers
+        // coming of which at least one contains actual data (did observe
+        // that with one test file).
+        const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less<int>(),0));
+        if(count_neg == temp_materials.size()) {
+            FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
+            return;
+        }
+
+        std::swap(temp_materials, materials);
+    }
+    else if (type == "LayerElementNormal") {
+        if (normals.size() > 0) {
+            FBXImporter::LogError("ignoring additional normal layer");
+            return;
+        }
+
+        ReadVertexDataNormals(normals,source,
+            MappingInformationType,
+            ReferenceInformationType
+        );
+    }
+    else if (type == "LayerElementTangent") {
+        if (tangents.size() > 0) {
+            FBXImporter::LogError("ignoring additional tangent layer");
+            return;
+        }
+
+        ReadVertexDataTangents(tangents,source,
+            MappingInformationType,
+            ReferenceInformationType
+        );
+    }
+    else if (type == "LayerElementBinormal") {
+        if (binormals.size() > 0) {
+            FBXImporter::LogError("ignoring additional binormal layer");
+            return;
+        }
+
+        ReadVertexDataBinormals(binormals,source,
+            MappingInformationType,
+            ReferenceInformationType
+        );
+    }
+    else if (type == "LayerElementColor") {
+        if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
+            FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
+                << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
+            return;
+        }
+
+        ReadVertexDataColors(colors[index],source,
+            MappingInformationType,
+            ReferenceInformationType
+        );
+    }
 }
 
 
@@ -338,201 +338,201 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
 // tangents ..
 template <typename T>
 void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
-	const std::string& MappingInformationType,
-	const std::string& ReferenceInformationType,
-	const char* dataElementName,
-	const char* indexDataElementName,
-	size_t vertex_count,
-	const std::vector<unsigned int>& mapping_counts,
-	const std::vector<unsigned int>& mapping_offsets,
-	const std::vector<unsigned int>& mappings)
+    const std::string& MappingInformationType,
+    const std::string& ReferenceInformationType,
+    const char* dataElementName,
+    const char* indexDataElementName,
+    size_t vertex_count,
+    const std::vector<unsigned int>& mapping_counts,
+    const std::vector<unsigned int>& mapping_offsets,
+    const std::vector<unsigned int>& mappings)
 {
-	std::vector<T> tempUV;
-	ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
-
-	// handle permutations of Mapping and Reference type - it would be nice to
-	// deal with this more elegantly and with less redundancy, but right
-	// now it seems unavoidable.
-	if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
-		data_out.resize(vertex_count);
-		for (size_t i = 0, e = tempUV.size(); i < e; ++i) {
-
-			const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
-			for (unsigned int j = istart; j < iend; ++j) {
-				data_out[mappings[j]] = tempUV[i];
-			}
-		}
-	}
-	else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
-		data_out.resize(vertex_count);
-
-		std::vector<int> uvIndices;
-		ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
-
-		for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
-
-			const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
-			for (unsigned int j = istart; j < iend; ++j) {
-				if(static_cast<size_t>(uvIndices[i]) >= tempUV.size()) {
-					DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
-				}
-				data_out[mappings[j]] = tempUV[uvIndices[i]];
-			}
-		}
-	}
-	else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
-		if (tempUV.size() != vertex_count) {
-			FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
-				<< tempUV.size() << ", expected " << vertex_count
-			);
-			return;
-		}
-
-		data_out.swap(tempUV);
-	}
-	else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
-		data_out.resize(vertex_count);
-
-		std::vector<int> uvIndices;
-		ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
-
-		if (uvIndices.size() != vertex_count) {
-			FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
-			return;
-		}
-
-		unsigned int next = 0;
-		BOOST_FOREACH(int i, uvIndices) {
-			if(static_cast<size_t>(i) >= tempUV.size()) {
-				DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
-			}
-
-			data_out[next++] = tempUV[i];
-		}
-	}
-	else {
-		FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
-			<< MappingInformationType << "," << ReferenceInformationType);
-	}
+    std::vector<T> tempUV;
+    ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
+
+    // handle permutations of Mapping and Reference type - it would be nice to
+    // deal with this more elegantly and with less redundancy, but right
+    // now it seems unavoidable.
+    if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
+        data_out.resize(vertex_count);
+        for (size_t i = 0, e = tempUV.size(); i < e; ++i) {
+
+            const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
+            for (unsigned int j = istart; j < iend; ++j) {
+                data_out[mappings[j]] = tempUV[i];
+            }
+        }
+    }
+    else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
+        data_out.resize(vertex_count);
+
+        std::vector<int> uvIndices;
+        ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
+
+        for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
+
+            const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
+            for (unsigned int j = istart; j < iend; ++j) {
+                if(static_cast<size_t>(uvIndices[i]) >= tempUV.size()) {
+                    DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
+                }
+                data_out[mappings[j]] = tempUV[uvIndices[i]];
+            }
+        }
+    }
+    else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
+        if (tempUV.size() != vertex_count) {
+            FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
+                << tempUV.size() << ", expected " << vertex_count
+            );
+            return;
+        }
+
+        data_out.swap(tempUV);
+    }
+    else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
+        data_out.resize(vertex_count);
+
+        std::vector<int> uvIndices;
+        ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
+
+        if (uvIndices.size() != vertex_count) {
+            FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
+            return;
+        }
+
+        unsigned int next = 0;
+        BOOST_FOREACH(int i, uvIndices) {
+            if(static_cast<size_t>(i) >= tempUV.size()) {
+                DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
+            }
+
+            data_out[next++] = tempUV[i];
+        }
+    }
+    else {
+        FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
+            << MappingInformationType << "," << ReferenceInformationType);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source,
-	const std::string& MappingInformationType,
-	const std::string& ReferenceInformationType)
+    const std::string& MappingInformationType,
+    const std::string& ReferenceInformationType)
 {
-	ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
-		"Normals",
-		"NormalsIndex",
-		vertices.size(),
-		mapping_counts,
-		mapping_offsets,
-		mappings);
+    ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
+        "Normals",
+        "NormalsIndex",
+        vertices.size(),
+        mapping_counts,
+        mapping_offsets,
+        mappings);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
-	const std::string& MappingInformationType,
-	const std::string& ReferenceInformationType)
+    const std::string& MappingInformationType,
+    const std::string& ReferenceInformationType)
 {
-	ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
-		"UV",
-		"UVIndex",
-		vertices.size(),
-		mapping_counts,
-		mapping_offsets,
-		mappings);
+    ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
+        "UV",
+        "UVIndex",
+        vertices.size(),
+        mapping_counts,
+        mapping_offsets,
+        mappings);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
-	const std::string& MappingInformationType,
-	const std::string& ReferenceInformationType)
+    const std::string& MappingInformationType,
+    const std::string& ReferenceInformationType)
 {
-	ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
-		"Colors",
-		"ColorIndex",
-		vertices.size(),
-		mapping_counts,
-		mapping_offsets,
-		mappings);
+    ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
+        "Colors",
+        "ColorIndex",
+        vertices.size(),
+        mapping_counts,
+        mapping_offsets,
+        mappings);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
-	const std::string& MappingInformationType,
-	const std::string& ReferenceInformationType)
+    const std::string& MappingInformationType,
+    const std::string& ReferenceInformationType)
 {
-	const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
-	ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
-		str,
-		"TangentIndex",
-		vertices.size(),
-		mapping_counts,
-		mapping_offsets,
-		mappings);
+    const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
+    ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
+        str,
+        "TangentIndex",
+        vertices.size(),
+        mapping_counts,
+        mapping_offsets,
+        mappings);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source,
-	const std::string& MappingInformationType,
-	const std::string& ReferenceInformationType)
+    const std::string& MappingInformationType,
+    const std::string& ReferenceInformationType)
 {
-	const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
-	ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
-		str,
-		"BinormalIndex",
-		vertices.size(),
-		mapping_counts,
-		mapping_offsets,
-		mappings);
+    const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
+    ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
+        str,
+        "BinormalIndex",
+        vertices.size(),
+        mapping_counts,
+        mapping_offsets,
+        mappings);
 }
 
 
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source,
-	const std::string& MappingInformationType,
-	const std::string& ReferenceInformationType)
+    const std::string& MappingInformationType,
+    const std::string& ReferenceInformationType)
 {
-	const size_t face_count = faces.size();
-	ai_assert(face_count);
-
-	// materials are handled separately. First of all, they are assigned per-face
-	// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
-	// has a slightly different meaning for materials.
-	ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
-
-	if (MappingInformationType == "AllSame") {
-		// easy - same material for all faces
-		if (materials_out.empty()) {
-			FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
-			return;
-		}
-		else if (materials_out.size() > 1) {
-			FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
-			materials_out.clear();
-		}
-
-		materials.assign(vertices.size(),materials_out[0]);
-	}
-	else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
-		materials.resize(face_count);
-
-		if(materials_out.size() != face_count) {
-			FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
-				<< materials_out.size() << ", expected " << face_count
-			);
-			return;
-		}
-	}
-	else {
-		FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
-			<< MappingInformationType << "," << ReferenceInformationType);
-	}
+    const size_t face_count = faces.size();
+    ai_assert(face_count);
+
+    // materials are handled separately. First of all, they are assigned per-face
+    // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
+    // has a slightly different meaning for materials.
+    ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
+
+    if (MappingInformationType == "AllSame") {
+        // easy - same material for all faces
+        if (materials_out.empty()) {
+            FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
+            return;
+        }
+        else if (materials_out.size() > 1) {
+            FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
+            materials_out.clear();
+        }
+
+        materials.assign(vertices.size(),materials_out[0]);
+    }
+    else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
+        materials.resize(face_count);
+
+        if(materials_out.size() != face_count) {
+            FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
+                << materials_out.size() << ", expected " << face_count
+            );
+            return;
+        }
+    }
+    else {
+        FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
+            << MappingInformationType << "," << ReferenceInformationType);
+    }
 }
 
 } // !FBX

+ 64 - 64
code/FBXModel.cpp

@@ -55,27 +55,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	using namespace Util;
+    using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
 Model::Model(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-	: Object(id,element,name)
-	, shading("Y")
+    : Object(id,element,name)
+    , shading("Y")
 {
-	const Scope& sc = GetRequiredScope(element);
-	const Element* const Shading = sc["Shading"];
-	const Element* const Culling = sc["Culling"];
+    const Scope& sc = GetRequiredScope(element);
+    const Element* const Shading = sc["Shading"];
+    const Element* const Culling = sc["Culling"];
 
-	if(Shading) {
-		shading = GetRequiredToken(*Shading,0).StringContents();
-	}
+    if(Shading) {
+        shading = GetRequiredToken(*Shading,0).StringContents();
+    }
 
-	if (Culling) {
-		culling = ParseTokenAsString(GetRequiredToken(*Culling,0));
-	}
+    if (Culling) {
+        culling = ParseTokenAsString(GetRequiredToken(*Culling,0));
+    }
 
-	props = GetPropertyTable(doc,"Model.FbxNode",element,sc);
-	ResolveLinks(element,doc);
+    props = GetPropertyTable(doc,"Model.FbxNode",element,sc);
+    ResolveLinks(element,doc);
 }
 
 
@@ -89,64 +89,64 @@ Model::~Model()
 // ------------------------------------------------------------------------------------------------
 void Model::ResolveLinks(const Element& element, const Document& doc)
 {
-	const char* const arr[] = {"Geometry","Material","NodeAttribute"};
-
-	// resolve material
-	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3);
-
-	materials.reserve(conns.size());
-	geometry.reserve(conns.size());
-	attributes.reserve(conns.size());
-	BOOST_FOREACH(const Connection* con, conns) {
-
-		// material and geometry links should be Object-Object connections
-		if (con->PropertyName().length()) {
-			continue;
-		}
-
-		const Object* const ob = con->SourceObject();
-		if(!ob) {
-			DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
-			continue;
-		}
-
-		const Material* const mat = dynamic_cast<const Material*>(ob);
-		if(mat) {
-			materials.push_back(mat);
-			continue;
-		}
-
-		const Geometry* const geo = dynamic_cast<const Geometry*>(ob);
-		if(geo) {
-			geometry.push_back(geo);
-			continue;
-		}
-
-		const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob);
-		if(att) {
-			attributes.push_back(att);
-			continue;
-		}
-
-		DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element);
-		continue;
-	}
+    const char* const arr[] = {"Geometry","Material","NodeAttribute"};
+
+    // resolve material
+    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3);
+
+    materials.reserve(conns.size());
+    geometry.reserve(conns.size());
+    attributes.reserve(conns.size());
+    BOOST_FOREACH(const Connection* con, conns) {
+
+        // material and geometry links should be Object-Object connections
+        if (con->PropertyName().length()) {
+            continue;
+        }
+
+        const Object* const ob = con->SourceObject();
+        if(!ob) {
+            DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
+            continue;
+        }
+
+        const Material* const mat = dynamic_cast<const Material*>(ob);
+        if(mat) {
+            materials.push_back(mat);
+            continue;
+        }
+
+        const Geometry* const geo = dynamic_cast<const Geometry*>(ob);
+        if(geo) {
+            geometry.push_back(geo);
+            continue;
+        }
+
+        const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob);
+        if(att) {
+            attributes.push_back(att);
+            continue;
+        }
+
+        DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element);
+        continue;
+    }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 bool Model::IsNull() const
 {
-	const std::vector<const NodeAttribute*>& attrs = GetAttributes();
-	BOOST_FOREACH(const NodeAttribute* att, attrs) {
+    const std::vector<const NodeAttribute*>& attrs = GetAttributes();
+    BOOST_FOREACH(const NodeAttribute* att, attrs) {
 
-		const Null* null_tag = dynamic_cast<const Null*>(att);
-		if(null_tag) {
-			return true;
-		}
-	}
+        const Null* null_tag = dynamic_cast<const Null*>(att);
+        if(null_tag) {
+            return true;
+        }
+    }
 
-	return false;
+    return false;
 }
 
 

+ 26 - 26
code/FBXNodeAttribute.cpp

@@ -54,21 +54,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	using namespace Util;
+    using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
 NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-	: Object(id,element,name)
+    : Object(id,element,name)
 {
-	const Scope& sc = GetRequiredScope(element);
+    const Scope& sc = GetRequiredScope(element);
 
-	const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
+    const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
 
-	// hack on the deriving type but Null/LimbNode attributes are the only case in which
-	// the property table is by design absent and no warning should be generated
-	// for it.
-	const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
-	props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
+    // hack on the deriving type but Null/LimbNode attributes are the only case in which
+    // the property table is by design absent and no warning should be generated
+    // for it.
+    const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
+    props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
 }
 
 
@@ -81,24 +81,24 @@ NodeAttribute::~NodeAttribute()
 
 // ------------------------------------------------------------------------------------------------
 CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-	: NodeAttribute(id,element,doc,name)
+    : NodeAttribute(id,element,doc,name)
 {
-	const Scope& sc = GetRequiredScope(element);
-	const Element* const CameraId = sc["CameraId"];
-	const Element* const CameraName = sc["CameraName"];
-	const Element* const CameraIndexName = sc["CameraIndexName"];
-
-	if(CameraId) {
-		cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
-	}
-
-	if(CameraName) {
-		cameraName = GetRequiredToken(*CameraName,0).StringContents();
-	}
-
-	if(CameraIndexName && CameraIndexName->Tokens().size()) {
-		cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
-	}
+    const Scope& sc = GetRequiredScope(element);
+    const Element* const CameraId = sc["CameraId"];
+    const Element* const CameraName = sc["CameraName"];
+    const Element* const CameraIndexName = sc["CameraIndexName"];
+
+    if(CameraId) {
+        cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
+    }
+
+    if(CameraName) {
+        cameraName = GetRequiredToken(*CameraName,0).StringContents();
+    }
+
+    if(CameraIndexName && CameraIndexName->Tokens().size()) {
+        cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
+    }
 }
 
 

File diff suppressed because it is too large
+ 486 - 486
code/FBXParser.cpp


+ 56 - 56
code/FBXParser.h

@@ -60,18 +60,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	class Scope;
-	class Parser;
-	class Element;
+    class Scope;
+    class Parser;
+    class Element;
 
-	// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
-	typedef std::vector< Scope* > ScopeList;
-	typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
+    // XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
+    typedef std::vector< Scope* > ScopeList;
+    typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
 
-	typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
+    typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
 
-#	define new_Scope new Scope
-#	define new_Element new Element
+#   define new_Scope new Scope
+#   define new_Element new Element
 
 
 /** FBX data entity that consists of a key:value tuple.
@@ -89,28 +89,28 @@ class Element
 {
 public:
 
-	Element(const Token& key_token, Parser& parser);
-	~Element();
+    Element(const Token& key_token, Parser& parser);
+    ~Element();
 
 public:
 
-	const Scope* Compound() const {
-		return compound.get();
-	}
+    const Scope* Compound() const {
+        return compound.get();
+    }
 
-	const Token& KeyToken() const {
-		return key_token;
-	}
+    const Token& KeyToken() const {
+        return key_token;
+    }
 
-	const TokenList& Tokens() const {
-		return tokens;
-	}
+    const TokenList& Tokens() const {
+        return tokens;
+    }
 
 private:
 
-	const Token& key_token;
-	TokenList tokens;
-	boost::scoped_ptr<Scope> compound;
+    const Token& key_token;
+    TokenList tokens;
+    boost::scoped_ptr<Scope> compound;
 };
 
 
@@ -131,27 +131,27 @@ class Scope
 
 public:
 
-	Scope(Parser& parser, bool topLevel = false);
-	~Scope();
+    Scope(Parser& parser, bool topLevel = false);
+    ~Scope();
 
 public:
 
-	const Element* operator[] (const std::string& index) const {
-		ElementMap::const_iterator it = elements.find(index);
-		return it == elements.end() ? NULL : (*it).second;
-	}
+    const Element* operator[] (const std::string& index) const {
+        ElementMap::const_iterator it = elements.find(index);
+        return it == elements.end() ? NULL : (*it).second;
+    }
 
-	ElementCollection GetCollection(const std::string& index) const {
-		return elements.equal_range(index);
-	}
+    ElementCollection GetCollection(const std::string& index) const {
+        return elements.equal_range(index);
+    }
 
-	const ElementMap& Elements() const	{
-		return elements;
-	}
+    const ElementMap& Elements() const  {
+        return elements;
+    }
 
 private:
 
-	ElementMap elements;
+    ElementMap elements;
 };
 
 
@@ -161,43 +161,43 @@ class Parser
 {
 public:
 
-	/** Parse given a token list. Does not take ownership of the tokens -
-	 *  the objects must persist during the entire parser lifetime */
-	Parser (const TokenList& tokens,bool is_binary);
-	~Parser();
+    /** Parse given a token list. Does not take ownership of the tokens -
+     *  the objects must persist during the entire parser lifetime */
+    Parser (const TokenList& tokens,bool is_binary);
+    ~Parser();
 
 public:
 
-	const Scope& GetRootScope() const {
-		return *root.get();
-	}
+    const Scope& GetRootScope() const {
+        return *root.get();
+    }
 
 
-	bool IsBinary() const {
-		return is_binary;
-	}
+    bool IsBinary() const {
+        return is_binary;
+    }
 
 private:
 
-	friend class Scope;
-	friend class Element;
+    friend class Scope;
+    friend class Element;
 
-	TokenPtr AdvanceToNextToken();
+    TokenPtr AdvanceToNextToken();
 
-	TokenPtr LastToken() const;
-	TokenPtr CurrentToken() const;
+    TokenPtr LastToken() const;
+    TokenPtr CurrentToken() const;
 
 
 
 private:
 
-	const TokenList& tokens;
+    const TokenList& tokens;
 
-	TokenPtr last, current;
-	TokenList::const_iterator cursor;
-	boost::scoped_ptr<Scope> root;
+    TokenPtr last, current;
+    TokenList::const_iterator cursor;
+    boost::scoped_ptr<Scope> root;
 
-	const bool is_binary;
+    const bool is_binary;
 };
 
 

+ 108 - 108
code/FBXProperties.cpp

@@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	using namespace Util;
+    using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
 Property::Property()
@@ -72,46 +72,46 @@ namespace {
 // read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
 Property* ReadTypedProperty(const Element& element)
 {
-	ai_assert(element.KeyToken().StringContents() == "P");
-
-	const TokenList& tok = element.Tokens();
-	ai_assert(tok.size() >= 5);
-
-	const std::string& s = ParseTokenAsString(*tok[1]);
-	const char* const cs = s.c_str();
-	if (!strcmp(cs,"KString")) {
-		return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
-	}
-	else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
-		return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
-	}
-	else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
-		return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
-	}
-	else if (!strcmp(cs, "ULongLong")) {
-		return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
-	}
-	else if (!strcmp(cs, "KTime")) {
-		return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
-	}
-	else if (!strcmp(cs,"Vector3D") ||
-		!strcmp(cs,"ColorRGB") ||
-		!strcmp(cs,"Vector") ||
-		!strcmp(cs,"Color") ||
-		!strcmp(cs,"Lcl Translation") ||
-		!strcmp(cs,"Lcl Rotation") ||
-		!strcmp(cs,"Lcl Scaling")
-		) {
-		return new TypedProperty<aiVector3D>(aiVector3D(
-			ParseTokenAsFloat(*tok[4]),
-			ParseTokenAsFloat(*tok[5]),
-			ParseTokenAsFloat(*tok[6]))
-		);
-	}
-	else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) {
-		return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
-	}
-	return NULL;
+    ai_assert(element.KeyToken().StringContents() == "P");
+
+    const TokenList& tok = element.Tokens();
+    ai_assert(tok.size() >= 5);
+
+    const std::string& s = ParseTokenAsString(*tok[1]);
+    const char* const cs = s.c_str();
+    if (!strcmp(cs,"KString")) {
+        return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
+    }
+    else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
+        return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
+    }
+    else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
+        return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
+    }
+    else if (!strcmp(cs, "ULongLong")) {
+        return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
+    }
+    else if (!strcmp(cs, "KTime")) {
+        return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
+    }
+    else if (!strcmp(cs,"Vector3D") ||
+        !strcmp(cs,"ColorRGB") ||
+        !strcmp(cs,"Vector") ||
+        !strcmp(cs,"Color") ||
+        !strcmp(cs,"Lcl Translation") ||
+        !strcmp(cs,"Lcl Rotation") ||
+        !strcmp(cs,"Lcl Scaling")
+        ) {
+        return new TypedProperty<aiVector3D>(aiVector3D(
+            ParseTokenAsFloat(*tok[4]),
+            ParseTokenAsFloat(*tok[5]),
+            ParseTokenAsFloat(*tok[6]))
+        );
+    }
+    else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) {
+        return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
+    }
+    return NULL;
 }
 
 
@@ -119,13 +119,13 @@ Property* ReadTypedProperty(const Element& element)
 // peek into an element and check if it contains a FBX property, if so return its name.
 std::string PeekPropertyName(const Element& element)
 {
-	ai_assert(element.KeyToken().StringContents() == "P");
-	const TokenList& tok = element.Tokens();
-	if(tok.size() < 4) {
-		return "";
-	}
+    ai_assert(element.KeyToken().StringContents() == "P");
+    const TokenList& tok = element.Tokens();
+    if(tok.size() < 4) {
+        return "";
+    }
 
-	return ParseTokenAsString(*tok[0]);
+    return ParseTokenAsString(*tok[0]);
 }
 
 } //! anon
@@ -144,89 +144,89 @@ PropertyTable::PropertyTable(const Element& element, boost::shared_ptr<const Pro
 : templateProps(templateProps)
 , element(&element)
 {
-	const Scope& scope = GetRequiredScope(element);
-	BOOST_FOREACH(const ElementMap::value_type& v, scope.Elements()) {
-		if(v.first != "P") {
-			DOMWarning("expected only P elements in property table",v.second);
-			continue;
-		}
-
-		const std::string& name = PeekPropertyName(*v.second);
-		if(!name.length()) {
-			DOMWarning("could not read property name",v.second);
-			continue;
-		}
-
-		LazyPropertyMap::const_iterator it = lazyProps.find(name);
-		if (it != lazyProps.end()) {
-			DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
-			continue;
-		}
-
-		lazyProps[name] = v.second;
-	}
+    const Scope& scope = GetRequiredScope(element);
+    BOOST_FOREACH(const ElementMap::value_type& v, scope.Elements()) {
+        if(v.first != "P") {
+            DOMWarning("expected only P elements in property table",v.second);
+            continue;
+        }
+
+        const std::string& name = PeekPropertyName(*v.second);
+        if(!name.length()) {
+            DOMWarning("could not read property name",v.second);
+            continue;
+        }
+
+        LazyPropertyMap::const_iterator it = lazyProps.find(name);
+        if (it != lazyProps.end()) {
+            DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
+            continue;
+        }
+
+        lazyProps[name] = v.second;
+    }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 PropertyTable::~PropertyTable()
 {
-	BOOST_FOREACH(PropertyMap::value_type& v, props) {
-		delete v.second;
-	}
+    BOOST_FOREACH(PropertyMap::value_type& v, props) {
+        delete v.second;
+    }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 const Property* PropertyTable::Get(const std::string& name) const
 {
-	PropertyMap::const_iterator it = props.find(name);
-	if (it == props.end()) {
-		// hasn't been parsed yet?
-		LazyPropertyMap::const_iterator lit = lazyProps.find(name);
-		if(lit != lazyProps.end()) {
-			props[name] = ReadTypedProperty(*(*lit).second);
-			it = props.find(name);
-
-			ai_assert(it != props.end());
-		}
-
-		if (it == props.end()) {
-			// check property template
-			if(templateProps) {
-				return templateProps->Get(name);
-			}
-
-			return NULL;
-		}
-	}
-
-	return (*it).second;
+    PropertyMap::const_iterator it = props.find(name);
+    if (it == props.end()) {
+        // hasn't been parsed yet?
+        LazyPropertyMap::const_iterator lit = lazyProps.find(name);
+        if(lit != lazyProps.end()) {
+            props[name] = ReadTypedProperty(*(*lit).second);
+            it = props.find(name);
+
+            ai_assert(it != props.end());
+        }
+
+        if (it == props.end()) {
+            // check property template
+            if(templateProps) {
+                return templateProps->Get(name);
+            }
+
+            return NULL;
+        }
+    }
+
+    return (*it).second;
 }
 
 DirectPropertyMap PropertyTable::GetUnparsedProperties() const
 {
-	DirectPropertyMap result;
+    DirectPropertyMap result;
 
-	// Loop through all the lazy properties (which is all the properties)
-	BOOST_FOREACH(const LazyPropertyMap::value_type& element, lazyProps) {
+    // Loop through all the lazy properties (which is all the properties)
+    BOOST_FOREACH(const LazyPropertyMap::value_type& element, lazyProps) {
 
-		// Skip parsed properties
-		if (props.end() != props.find(element.first)) continue;
+        // Skip parsed properties
+        if (props.end() != props.find(element.first)) continue;
 
-		// Read the element's value.
-		// Wrap the naked pointer (since the call site is required to acquire ownership)
-		// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
-		boost::shared_ptr<Property> prop = boost::shared_ptr<Property>(ReadTypedProperty(*element.second));
+        // Read the element's value.
+        // Wrap the naked pointer (since the call site is required to acquire ownership)
+        // std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
+        boost::shared_ptr<Property> prop = boost::shared_ptr<Property>(ReadTypedProperty(*element.second));
 
-		// Element could not be read. Skip it.
-		if (!prop) continue;
+        // Element could not be read. Skip it.
+        if (!prop) continue;
 
-		// Add to result
-		result[element.first] = prop;
-	}
+        // Add to result
+        result[element.first] = prop;
+    }
 
-	return result;
+    return result;
 }
 
 

+ 61 - 61
code/FBXProperties.h

@@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-	class Element;
+    class Element;
 
 
 /** Represents a dynamic property. Type info added by deriving classes,
@@ -67,18 +67,18 @@ class Property
 {
 protected:
 
-	Property();
+    Property();
 
 public:
 
-	virtual ~Property();
+    virtual ~Property();
 
 public:
 
-	template <typename T>
-	const T* As() const {
-		return dynamic_cast<const T*>(this);
-	}
+    template <typename T>
+    const T* As() const {
+        return dynamic_cast<const T*>(this);
+    }
 };
 
 
@@ -87,19 +87,19 @@ class TypedProperty : public Property
 {
 public:
 
-	TypedProperty(const T& value)
-		: value(value)
-	{
-	}
+    TypedProperty(const T& value)
+        : value(value)
+    {
+    }
 
 public:
 
-	const T& Value() const {
-		return value;
-	}
+    const T& Value() const {
+        return value;
+    }
 
 private:
-	T value;
+    T value;
 };
 
 
@@ -112,76 +112,76 @@ class PropertyTable
 {
 public:
 
-	// in-memory property table with no source element
-	PropertyTable();
+    // in-memory property table with no source element
+    PropertyTable();
 
-	PropertyTable(const Element& element, boost::shared_ptr<const PropertyTable> templateProps);
-	~PropertyTable();
+    PropertyTable(const Element& element, boost::shared_ptr<const PropertyTable> templateProps);
+    ~PropertyTable();
 
 public:
 
-	const Property* Get(const std::string& name) const;
+    const Property* Get(const std::string& name) const;
 
-	// PropertyTable's need not be coupled with FBX elements so this can be NULL
-	const Element* GetElement() const {
-		return element;
-	}
+    // PropertyTable's need not be coupled with FBX elements so this can be NULL
+    const Element* GetElement() const {
+        return element;
+    }
 
-	const PropertyTable* TemplateProps() const {
-		return templateProps.get();
-	}
+    const PropertyTable* TemplateProps() const {
+        return templateProps.get();
+    }
 
-	DirectPropertyMap GetUnparsedProperties() const;
+    DirectPropertyMap GetUnparsedProperties() const;
 
 private:
 
-	LazyPropertyMap lazyProps;
-	mutable PropertyMap props;
-	const boost::shared_ptr<const PropertyTable> templateProps;
-	const Element* const element;
+    LazyPropertyMap lazyProps;
+    mutable PropertyMap props;
+    const boost::shared_ptr<const PropertyTable> templateProps;
+    const Element* const element;
 };
 
 
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 inline T PropertyGet(const PropertyTable& in, const std::string& name,
-	const T& defaultValue)
+    const T& defaultValue)
 {
-	const Property* const prop = in.Get(name);
-	if(!prop) {
-		return defaultValue;
-	}
-
-	// strong typing, no need to be lenient
-	const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
-	if(!tprop) {
-		return defaultValue;
-	}
-
-	return tprop->Value();
+    const Property* const prop = in.Get(name);
+    if(!prop) {
+        return defaultValue;
+    }
+
+    // strong typing, no need to be lenient
+    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
+    if(!tprop) {
+        return defaultValue;
+    }
+
+    return tprop->Value();
 }
 
 
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 inline T PropertyGet(const PropertyTable& in, const std::string& name,
-	bool& result)
+    bool& result)
 {
-	const Property* const prop = in.Get(name);
-	if(!prop) {
-		result = false;
-		return T();
-	}
-
-	// strong typing, no need to be lenient
-	const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
-	if(!tprop) {
-		result = false;
-		return T();
-	}
-
-	result = true;
-	return tprop->Value();
+    const Property* const prop = in.Get(name);
+    if(!prop) {
+        result = false;
+        return T();
+    }
+
+    // strong typing, no need to be lenient
+    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
+    if(!tprop) {
+        result = false;
+        return T();
+    }
+
+    result = true;
+    return tprop->Value();
 }
 
 

Some files were not shown because too many files changed in this diff