瀏覽代碼

ASE and 3DS cleanup - face ordering improved.
Further work on target camera animation support in both loaders. Some general animation problems in both formats remaining, too.
Added GenUVCoords and TransformUV-steps (see ML). The latter has been fully implemented, test file are there. GenUVCoords is a dummy for the moment.
Boost workaround for shared_array.
Further work on the documentation.
Updated material system (see ML).
Bug fixing in the AC loader, lights are now supported, too.


git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@243 67173fc5-114c-0410-ac8e-9d2fd5bffc1f

aramis_acg 17 年之前
父節點
當前提交
32342857d8
共有 57 個文件被更改,包括 3317 次插入2335 次删除
  1. 172 271
      code/3DSConverter.cpp
  2. 15 28
      code/3DSHelper.h
  3. 34 27
      code/3DSLoader.cpp
  4. 0 4
      code/3DSLoader.h
  5. 44 7
      code/ACLoader.cpp
  6. 3 0
      code/ACLoader.h
  7. 167 194
      code/ASELoader.cpp
  8. 31 32
      code/ASEParser.cpp
  9. 1 6
      code/ASEParser.h
  10. 2 0
      code/AssimpPCH.h
  11. 1 1
      code/BaseImporter.cpp
  12. 175 0
      code/ComputeUVMappingProcess.cpp
  13. 125 0
      code/ComputeUVMappingProcess.h
  14. 23 0
      code/ConvertToLHProcess.cpp
  15. 7 0
      code/ConvertToLHProcess.h
  16. 1 0
      code/FindDegenerates.cpp
  17. 19 11
      code/FindInvalidDataProcess.cpp
  18. 1 0
      code/Hash.h
  19. 41 19
      code/IRRMeshLoader.cpp
  20. 32 7
      code/Importer.cpp
  21. 1 4
      code/LWOBLoader.cpp
  22. 28 9
      code/LWOFileData.h
  23. 103 46
      code/LWOLoader.cpp
  24. 3 5
      code/LWOLoader.h
  25. 126 40
      code/LWOMaterial.cpp
  26. 1 1
      code/MDLFileData.h
  27. 203 283
      code/MaterialSystem.cpp
  28. 40 16
      code/MaterialSystem.h
  29. 48 0
      code/ProcessHelper.h
  30. 14 9
      code/RemoveRedundantMaterials.cpp
  31. 16 8
      code/TargetAnimation.cpp
  32. 16 8
      code/TargetAnimation.h
  33. 457 434
      code/TextureTransform.cpp
  34. 111 93
      code/TextureTransform.h
  35. 117 95
      code/ValidateDataStructure.cpp
  36. 2 3
      code/ValidateDataStructure.h
  37. 11 12
      code/XFileImporter.cpp
  38. 4 1
      code/makefile
  39. 4 2
      code/makefile.mingw
  40. 85 0
      include/BoostWorkaround/boost/scoped_array.h
  41. 18 1
      include/BoostWorkaround/boost/scoped_ptr.hpp
  42. 6 0
      include/aiCamera.h
  43. 17 9
      include/aiConfig.h
  44. 2 0
      include/aiDefines.h
  45. 6 0
      include/aiLight.h
  46. 548 424
      include/aiMaterial.h
  47. 146 135
      include/aiMaterial.inl
  48. 17 1
      include/aiMatrix3x3.h
  49. 21 0
      include/aiMatrix3x3.inl
  50. 17 0
      include/aiMesh.h
  51. 24 3
      include/aiPostProcess.h
  52. 67 14
      include/aiTypes.h
  53. 65 61
      tools/assimp_view/Display.cpp
  54. 31 2
      tools/assimp_view/Material.cpp
  55. 18 0
      tools/assimp_view/Shaders.cpp
  56. 2 1
      tools/assimp_view/assimp_view.cpp
  57. 28 8
      workspaces/vc8/assimp.vcproj

+ 172 - 271
code/3DSConverter.cpp

@@ -46,7 +46,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 // internal headers
 // internal headers
 #include "3DSLoader.h"
 #include "3DSLoader.h"
-#include "TextureTransform.h"
 #include "TargetAnimation.h"
 #include "TargetAnimation.h"
 
 
 using namespace Assimp;
 using namespace Assimp;
@@ -159,41 +158,60 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
 // Generate out unique verbose format representation
 // Generate out unique verbose format representation
 void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
 void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
 {
 {
-	unsigned int iBase = 0;
-
 	// Allocate output storage
 	// Allocate output storage
 	std::vector<aiVector3D> vNew  (sMesh.mFaces.size() * 3);
 	std::vector<aiVector3D> vNew  (sMesh.mFaces.size() * 3);
-	std::vector<aiVector2D> vNew2;
-	if (sMesh.mTexCoords.size())vNew2.resize(sMesh.mFaces.size() * 3);
+	std::vector<aiVector3D> vNew2;
+	if (sMesh.mTexCoords.size())
+		vNew2.resize(sMesh.mFaces.size() * 3);
 
 
-	for (unsigned int i = 0; i < sMesh.mFaces.size();++i)
+	for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
 	{
 	{
-		uint32_t iTemp1,iTemp2;
-
-		// positions
-		vNew[iBase]   = sMesh.mPositions[sMesh.mFaces[i].mIndices[2]];
-		iTemp1 = iBase++;
-		vNew[iBase]   = sMesh.mPositions[sMesh.mFaces[i].mIndices[1]];
-		iTemp2 = iBase++;
-		vNew[iBase]   = sMesh.mPositions[sMesh.mFaces[i].mIndices[0]];
+		D3DS::Face& face = sMesh.mFaces[i];
 
 
-		// texture coordinates
-		if (sMesh.mTexCoords.size())
+		// Positions
+		for (unsigned int a = 0; a < 3;++a,++base)
 		{
 		{
-			vNew2[iTemp1]   = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[2]];
-			vNew2[iTemp2]   = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[1]];
-			vNew2[iBase]    = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[0]];
-		}
+			vNew[base] = sMesh.mPositions[face.mIndices[a]];
+			if (sMesh.mTexCoords.size())
+				vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
 
 
-		sMesh.mFaces[i].mIndices[2] = iBase++;
-		sMesh.mFaces[i].mIndices[0] = iTemp1;
-		sMesh.mFaces[i].mIndices[1] = iTemp2;
+			face.mIndices[a] = base;
+		}
 	}
 	}
 	sMesh.mPositions = vNew;
 	sMesh.mPositions = vNew;
 	sMesh.mTexCoords = vNew2;
 	sMesh.mTexCoords = vNew2;
 	return;
 	return;
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+void CopyTexture(MaterialHelper& 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 
+	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
 // Convert a 3DS material to an aiMaterial
 void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
 void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
@@ -207,12 +225,11 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
 		tex.Set( mBackgroundImage);
 		tex.Set( mBackgroundImage);
 		mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
 		mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
 
 
-		// be sure this is only done for the first material
+		// Be sure this is only done for the first material
 		mBackgroundImage = std::string("");
 		mBackgroundImage = std::string("");
 	}
 	}
 
 
-	// At first add the base ambient color of the
-	// scene to	the material
+	// At first add the base ambient color of the scene to the material
 	oldMat.mAmbient.r += mClrAmbient.r;
 	oldMat.mAmbient.r += mClrAmbient.r;
 	oldMat.mAmbient.g += mClrAmbient.g;
 	oldMat.mAmbient.g += mClrAmbient.g;
 	oldMat.mAmbient.b += mClrAmbient.b;
 	oldMat.mAmbient.b += mClrAmbient.b;
@@ -221,13 +238,13 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
 	name.Set( oldMat.mName);
 	name.Set( oldMat.mName);
 	mat.AddProperty( &name, AI_MATKEY_NAME);
 	mat.AddProperty( &name, AI_MATKEY_NAME);
 
 
-	// material colors
+	// Material colors
 	mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
 	mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
 	mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
 	mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
 	mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
 	mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
 	mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
 	mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
 
 
-	// phong shininess and shininess strength
+	// Phong shininess and shininess strength
 	if (D3DS::Discreet3DS::Phong == oldMat.mShading || 
 	if (D3DS::Discreet3DS::Phong == oldMat.mShading || 
 		D3DS::Discreet3DS::Metal == oldMat.mShading)
 		D3DS::Discreet3DS::Metal == oldMat.mShading)
 	{
 	{
@@ -242,20 +259,20 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
 		}
 		}
 	}
 	}
 
 
-	// opacity
+	// Opacity
 	mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
 	mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
 
 
-	// bump height scaling
+	// Bump height scaling
 	mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
 	mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
 
 
-	// two sided rendering?
+	// Two sided rendering?
 	if (oldMat.mTwoSided)
 	if (oldMat.mTwoSided)
 	{
 	{
 		int i = 1;
 		int i = 1;
 		mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
 		mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
 	}
 	}
 
 
-	// shading mode
+	// Shading mode
 	aiShadingMode eShading = aiShadingMode_NoShading;
 	aiShadingMode eShading = aiShadingMode_NoShading;
 	switch (oldMat.mShading)
 	switch (oldMat.mShading)
 	{
 	{
@@ -263,8 +280,14 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
 			eShading = aiShadingMode_Flat; break;
 			eShading = aiShadingMode_Flat; break;
 
 
 		// I don't know what "Wire" shading should be,
 		// I don't know what "Wire" shading should be,
-		// assume it is simple lambertian diffuse (L dot N) shading
+		// assume it is simple lambertian diffuse shading
 		case D3DS::Discreet3DS::Wire:
 		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:
 		case D3DS::Discreet3DS::Gouraud:
 			eShading = aiShadingMode_Gouraud; break;
 			eShading = aiShadingMode_Gouraud; break;
 
 
@@ -283,112 +306,29 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
 	}
 	}
 	mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
 	mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
 
 
-	if (D3DS::Discreet3DS::Wire == oldMat.mShading)
-	{
-		// set the wireframe flag
-		unsigned int iWire = 1;
-		mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
-	}
-
-	// texture, if there is one
 	// DIFFUSE texture
 	// DIFFUSE texture
 	if( oldMat.sTexDiffuse.mMapName.length() > 0)
 	if( oldMat.sTexDiffuse.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( oldMat.sTexDiffuse.mMapName);
-		mat.AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
+		CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
 
 
-		if (is_not_qnan(oldMat.sTexDiffuse.mTextureBlend))
-			mat.AddProperty<float>( &oldMat.sTexDiffuse.mTextureBlend, 1, AI_MATKEY_TEXBLEND_DIFFUSE(0));
-
-		if (aiTextureMapMode_Clamp != oldMat.sTexDiffuse.mMapMode)
-		{
-			int i = (int)oldMat.sTexSpecular.mMapMode;
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
-		}
-	}
 	// SPECULAR texture
 	// SPECULAR texture
 	if( oldMat.sTexSpecular.mMapName.length() > 0)
 	if( oldMat.sTexSpecular.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( oldMat.sTexSpecular.mMapName);
-		mat.AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(0));
-
-		if (is_not_qnan(oldMat.sTexSpecular.mTextureBlend))
-			mat.AddProperty<float>( &oldMat.sTexSpecular.mTextureBlend, 1, AI_MATKEY_TEXBLEND_SPECULAR(0));
+		CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
 
 
-		if (aiTextureMapMode_Clamp != oldMat.sTexSpecular.mMapMode)
-		{
-			int i = (int)oldMat.sTexSpecular.mMapMode;
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_U_SPECULAR(0));
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_V_SPECULAR(0));
-		}
-	}
 	// OPACITY texture
 	// OPACITY texture
 	if( oldMat.sTexOpacity.mMapName.length() > 0)
 	if( oldMat.sTexOpacity.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( oldMat.sTexOpacity.mMapName);
-		mat.AddProperty( &tex, AI_MATKEY_TEXTURE_OPACITY(0));
+		CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
 
 
-		if (is_not_qnan(oldMat.sTexOpacity.mTextureBlend))
-			mat.AddProperty<float>( &oldMat.sTexOpacity.mTextureBlend, 1,AI_MATKEY_TEXBLEND_OPACITY(0));
-		if (aiTextureMapMode_Clamp != oldMat.sTexOpacity.mMapMode)
-		{
-			int i = (int)oldMat.sTexOpacity.mMapMode;
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_U_OPACITY(0));
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_V_OPACITY(0));
-		}
-	}
 	// EMISSIVE texture
 	// EMISSIVE texture
 	if( oldMat.sTexEmissive.mMapName.length() > 0)
 	if( oldMat.sTexEmissive.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( oldMat.sTexEmissive.mMapName);
-		mat.AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(0));
+		CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
 
 
-		if (is_not_qnan(oldMat.sTexEmissive.mTextureBlend))
-			mat.AddProperty<float>( &oldMat.sTexEmissive.mTextureBlend, 1, AI_MATKEY_TEXBLEND_EMISSIVE(0));
-		if (aiTextureMapMode_Clamp != oldMat.sTexEmissive.mMapMode)
-		{
-			int i = (int)oldMat.sTexEmissive.mMapMode;
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_U_EMISSIVE(0));
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_V_EMISSIVE(0));
-		}
-	}
-	// BUMP texturee
+	// BUMP texture
 	if( oldMat.sTexBump.mMapName.length() > 0)
 	if( oldMat.sTexBump.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( oldMat.sTexBump.mMapName);
-		mat.AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(0));
+		CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
 
 
-		if (is_not_qnan(oldMat.sTexBump.mTextureBlend))
-			mat.AddProperty<float>( &oldMat.sTexBump.mTextureBlend, 1, AI_MATKEY_TEXBLEND_HEIGHT(0));
-		if (aiTextureMapMode_Clamp != oldMat.sTexBump.mMapMode)
-		{
-			int i = (int)oldMat.sTexBump.mMapMode;
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_U_HEIGHT(0));
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_V_HEIGHT(0));
-		}
-	}
 	// SHININESS texture
 	// SHININESS texture
 	if( oldMat.sTexShininess.mMapName.length() > 0)
 	if( oldMat.sTexShininess.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( oldMat.sTexShininess.mMapName);
-		mat.AddProperty( &tex, AI_MATKEY_TEXTURE_SHININESS(0));
-
-		if (is_not_qnan(oldMat.sTexShininess.mTextureBlend))
-			mat.AddProperty<float>( &oldMat.sTexShininess.mTextureBlend, 1, AI_MATKEY_TEXBLEND_SHININESS(0));
-		if (aiTextureMapMode_Clamp != oldMat.sTexShininess.mMapMode)
-		{
-			int i = (int)oldMat.sTexShininess.mMapMode;
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_U_SHININESS(0));
-			mat.AddProperty<int>(&i,1,AI_MATKEY_MAPPINGMODE_V_SHININESS(0));
-		}
-	}
+		CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
 
 
 	// Store the name of the material itself, too
 	// Store the name of the material itself, too
 	if( oldMat.mName.length())
 	if( oldMat.mName.length())
@@ -425,74 +365,51 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
 		// now generate submeshes
 		// now generate submeshes
 		for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
 		for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
 		{
 		{
-			if (aiSplit[p].size() != 0)
+			if (aiSplit[p].size())
 			{
 			{
-				aiMesh* p_pcOut = new aiMesh();
-				p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+				aiMesh* meshOut = new aiMesh();
+				meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
 
 
 				// be sure to setup the correct material index
 				// be sure to setup the correct material index
-				p_pcOut->mMaterialIndex = p;
+				meshOut->mMaterialIndex = p;
 
 
 				// use the color data as temporary storage
 				// use the color data as temporary storage
-				p_pcOut->mColors[0] = (aiColor4D*)(&*i);
-				avOutMeshes.push_back(p_pcOut);
+				meshOut->mColors[0] = (aiColor4D*)(&*i);
+				avOutMeshes.push_back(meshOut);
 				
 				
 				// convert vertices
 				// convert vertices
-				p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
-				p_pcOut->mNumVertices = p_pcOut->mNumFaces*3;
+				meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
+				meshOut->mNumVertices = meshOut->mNumFaces*3;
 
 
 				// allocate enough storage for faces
 				// allocate enough storage for faces
-				p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
-				iFaceCnt += p_pcOut->mNumFaces;
-
-				if (p_pcOut->mNumVertices)
+				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())
 				{
 				{
-					p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
-					p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices];
-					unsigned int iBase = 0;
-
-					for (unsigned int q = 0; q < aiSplit[p].size();++q)
-					{
-						unsigned int iIndex = aiSplit[p][q];
-
-						p_pcOut->mFaces[q].mIndices = new unsigned int[3];
-						p_pcOut->mFaces[q].mNumIndices = 3;
-
-						p_pcOut->mFaces[q].mIndices[2] = iBase;
-						p_pcOut->mVertices[iBase]  = (*i).mPositions[(*i).mFaces[iIndex].mIndices[0]];
-						p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].mIndices[0]];
-
-						p_pcOut->mFaces[q].mIndices[1] = iBase;
-						p_pcOut->mVertices[iBase]  = (*i).mPositions[(*i).mFaces[iIndex].mIndices[1]];
-						p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].mIndices[1]];
-
-						p_pcOut->mFaces[q].mIndices[0] = iBase;
-						p_pcOut->mVertices[iBase]  = (*i).mPositions[(*i).mFaces[iIndex].mIndices[2]];
-						p_pcOut->mNormals[iBase++] = (*i).mNormals[(*i).mFaces[iIndex].mIndices[2]];
-					}
+					meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
 				}
 				}
-				// convert texture coordinates
-				if ((*i).mTexCoords.size())
+				for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
 				{
 				{
-					p_pcOut->mTextureCoords[0] = new aiVector3D[p_pcOut->mNumVertices];
+					register unsigned int index = aiSplit[p][q];
+					aiFace& face = meshOut->mFaces[q];
 
 
-					unsigned int iBase = 0;
-					for (unsigned int q = 0; q < aiSplit[p].size();++q)
-					{
-						unsigned int iIndex2 = aiSplit[p][q];
+					face.mIndices = new unsigned int[3];
+					face.mNumIndices = 3;
 
 
-						aiVector2D* pc = &(*i).mTexCoords[(*i).mFaces[iIndex2].mIndices[0]];
-						p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc->x,pc->y,0.0f);
+					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];
 
 
-						pc = &(*i).mTexCoords[(*i).mFaces[iIndex2].mIndices[1]];
-						p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc->x,pc->y,0.0f);
+						if ((*i).mTexCoords.size())
+							meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
 
 
-						pc = &(*i).mTexCoords[(*i).mFaces[iIndex2].mIndices[2]];
-						p_pcOut->mTextureCoords[0][iBase++] = aiVector3D(pc->x,pc->y,0.0f);
+						face.mIndices[a] = base;
 					}
 					}
-					// apply texture coordinate scalings
-					TextureTransform::BakeScaleNOffset ( p_pcOut, &mScene->mMaterials[
-						p_pcOut->mMaterialIndex] );
 				}
 				}
 			}
 			}
 		}
 		}
@@ -508,20 +425,12 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
 	// We should have at least one face here
 	// We should have at least one face here
 	if (!iFaceCnt)
 	if (!iFaceCnt)
 		throw new ImportErrorException("No faces loaded. The mesh is empty");
 		throw new ImportErrorException("No faces loaded. The mesh is empty");
-
-	// for each material in the scene we need to setup the UV source
-	// set for each texture
-	for (unsigned int a = 0; a < pcOut->mNumMaterials;++a)
-	{
-		TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &mScene->mMaterials[a] );
-	}
-	return;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Add a node to the scenegraph and setup its final transformation
 // Add a node to the scenegraph and setup its final transformation
-void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn,
-	aiMatrix4x4& absTrafo)
+void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
+	D3DS::Node* pcIn, aiMatrix4x4& absTrafo)
 {
 {
 	std::vector<unsigned int> iArray;
 	std::vector<unsigned int> iArray;
 	iArray.reserve(3);
 	iArray.reserve(3);
@@ -529,11 +438,12 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
 	aiMatrix4x4 abs;
 	aiMatrix4x4 abs;
 	if (pcIn->mName == "$$$DUMMY")
 	if (pcIn->mName == "$$$DUMMY")
 	{
 	{
-		// Append the "real" name of the dummy to the string
-		pcIn->mName.append(pcIn->mDummyName);
+		// FIX: Append the "real" name of the dummy to the string
+		pcIn->mName = "Dummy." + pcIn->mDummyName;
 	}
 	}
 	else // if (pcIn->mName != "$$$DUMMY")
 	else // if (pcIn->mName != "$$$DUMMY")
 	{		
 	{		
+		// Find all meshes with the same name as the node
 		for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
 		for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
 		{
 		{
 			const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
 			const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
@@ -544,13 +454,10 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
 		}
 		}
 		if (!iArray.empty())
 		if (!iArray.empty())
 		{
 		{
-			// The matrix should be identical for all meshes with the same name.
-			// It HAS to be identical for all meshes ........
-			aiMatrix4x4& mTrafo = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat;
-			aiMatrix4x4 mInv = mTrafo;
-			if (!configSkipPivot)
-				mInv.Inverse();
-
+			// The matrix should be identical for all meshes with the 
+			// same name. It HAS to be identical for all meshes .....
+			aiMatrix4x4 mInv = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat;
+			mInv.Inverse();
 			const aiVector3D& pivot = pcIn->vPivot;
 			const aiVector3D& pivot = pcIn->vPivot;
 
 
 			pcOut->mNumMeshes = (unsigned int)iArray.size();
 			pcOut->mNumMeshes = (unsigned int)iArray.size();
@@ -560,31 +467,24 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
 				const unsigned int iIndex = iArray[i];
 				const unsigned int iIndex = iArray[i];
 				aiMesh* const mesh = pcSOut->mMeshes[iIndex];
 				aiMesh* const mesh = pcSOut->mMeshes[iIndex];
 
 
-				// Pivot point adjustment.
+				// Pivot point adjustment
 				// See: http://www.zfx.info/DisplayThread.php?MID=235690#235690
 				// See: http://www.zfx.info/DisplayThread.php?MID=235690#235690
 				const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
 				const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
 				aiVector3D* pvCurrent = mesh->mVertices;
 				aiVector3D* pvCurrent = mesh->mVertices;
 
 
-				if(pivot.x || pivot.y || pivot.z && !configSkipPivot)
+				if(pivot.x || pivot.y || pivot.z)
 				{
 				{
-					while (pvCurrent != pvEnd)
+					for (;pvCurrent != pvEnd;++pvCurrent)
 					{
 					{
 						*pvCurrent = mInv * (*pvCurrent);
 						*pvCurrent = mInv * (*pvCurrent);
-						pvCurrent->x -= pivot.x;
-						pvCurrent->y -= pivot.y;
-						pvCurrent->z -= pivot.z;
-						++pvCurrent;
+						*pvCurrent -= pivot;
 					}
 					}
 				}
 				}
 				else
 				else
 				{
 				{
-					while (pvCurrent != pvEnd)
-					{
+					for (;pvCurrent != pvEnd;++pvCurrent)
 						*pvCurrent = mInv * (*pvCurrent);
 						*pvCurrent = mInv * (*pvCurrent);
-						++pvCurrent;
-					}
 				}
 				}
-
 				// Setup the mesh index
 				// Setup the mesh index
 				pcOut->mMeshes[i] = iIndex;
 				pcOut->mMeshes[i] = iIndex;
 			}
 			}
@@ -648,73 +548,82 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Nod
 			}
 			}
 		}
 		}
 
 
-		if (pcIn->aTargetPositionKeys.size() > 1)
+		//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);
+		//}
+
+		// Allocate a new nda, increment the nda index
+		aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
+		nda->mNodeName.Set(pcIn->mName);
+
+		// POSITION keys
+		if (pcIn->aPositionKeys.size()  > 0)
 		{
 		{
-			//DefaultLogger::get()->debug("3DS: Converting target track ...");
-
-			//// Camera or spot light - need to convert the separate
-			//// target position channel to our representation
-			//TargetAnimationHelper helper;
-
-			//helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
-			//helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
-
-			//// 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);
+			nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
+			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
+			::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
+				sizeof(aiVectorKey)*nda->mNumPositionKeys);
 		}
 		}
 
 
-		// Just for safety ... we *should* have at least one track here
-		if (pcIn->aPositionKeys.size()  > 1  || pcIn->aRotationKeys.size()   > 1   ||
-			pcIn->aScalingKeys.size()   > 1)
+		// ROTATION keys
+		if (pcIn->aRotationKeys.size()  > 0)
 		{
 		{
-			// Allocate a new nda, increment the nda index
-			aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
-			nda->mNodeName.Set(pcIn->mName);
+			nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
+			nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
 
 
-			// POSITION keys
-			if (pcIn->aPositionKeys.size()  > 0)
+			// Rotations are quaternion offsets
+			aiQuaternion abs;
+			for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
 			{
 			{
-				nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
-				nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
-				::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
-					sizeof(aiVectorKey)*nda->mNumPositionKeys);
-			}
+				const aiQuatKey& q = pcIn->aRotationKeys[n];
 
 
-			// ROTATION keys
-			if (pcIn->aRotationKeys.size()  > 0)
-			{
-				nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
-				nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
-				::memcpy(nda->mRotationKeys,&pcIn->aRotationKeys[0],
-					sizeof(aiQuatKey)*nda->mNumRotationKeys);
+				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);
-			}
+		// 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);
 		}
 		}
 	}
 	}
 
 
@@ -864,14 +773,6 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
 		pcOld->mChildren[0] = NULL;
 		pcOld->mChildren[0] = NULL;
 		delete pcOld;
 		delete pcOld;
 	}
 	}
-
-#if 0
-	// modify the transformation of the root node to change
-	// the coordinate system of the whole scene from Max' to OpenGL
-	pcOut->mRootNode->mTransformation.a3 *= -1.f;
-	pcOut->mRootNode->mTransformation.b3 *= -1.f;
-	pcOut->mRootNode->mTransformation.c3 *= -1.f;
-#endif
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 15 - 28
code/3DSHelper.h

@@ -38,21 +38,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
-/** @file Defines helper data structures for the import of 3DS files.
-http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
+/** @file Defines helper data structures for the import of 3DS files */
 
 
 #ifndef AI_3DSFILEHELPER_H_INC
 #ifndef AI_3DSFILEHELPER_H_INC
 #define AI_3DSFILEHELPER_H_INC
 #define AI_3DSFILEHELPER_H_INC
 
 
-#include <string>
-#include <vector>
-#include <sstream>
-
-#include "../include/aiTypes.h"
-#include "../include/aiQuaternion.h"
-#include "../include/aiMesh.h"
-#include "../include/aiAnim.h"
-#include "../include/aiMaterial.h"
 
 
 #include "SpatialSort.h"
 #include "SpatialSort.h"
 #include "SmoothingGroups.h"
 #include "SmoothingGroups.h"
@@ -66,12 +56,13 @@ namespace D3DS	{
 /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
 /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
 *  and data structures.
 *  and data structures.
 */
 */
-// ---------------------------------------------------------------------------
 class Discreet3DS
 class Discreet3DS
 {
 {
-public:
+private:
 	inline Discreet3DS() {}
 	inline Discreet3DS() {}
 
 
+public:
+
 	//! data structure for a single chunk in a .3ds file
 	//! data structure for a single chunk in a .3ds file
 	struct Chunk
 	struct Chunk
 	{
 	{
@@ -79,10 +70,6 @@ public:
 		uint32_t	Size;
 		uint32_t	Size;
 	} PACK_STRUCT;
 	} PACK_STRUCT;
 
 
-	//! source for this used own structures,
-	//! replaced it with out standard math helpers
-	typedef aiMatrix3x3 MatTransform;
-	typedef aiVector3D MatTranslate;
 
 
 	//! Used for shading field in material3ds structure
 	//! Used for shading field in material3ds structure
 	//! From AutoDesk 3ds SDK
 	//! From AutoDesk 3ds SDK
@@ -301,26 +288,22 @@ public:
 	};
 	};
 };
 };
 
 
-#include "./../include/Compiler/poppack1.h"
-
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper structure representing a 3ds mesh face */
 /** Helper structure representing a 3ds mesh face */
 struct Face : public FaceWithSmoothingGroup
 struct Face : public FaceWithSmoothingGroup
 {
 {
-	//! Specifies that the face normal must be flipped.
-	//! todo: do we really need this?
-	bool bFlipped;
 };
 };
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper structure representing a texture */
 /** Helper structure representing a texture */
 struct Texture
 struct Texture
 {
 {
 	//! Default constructor
 	//! Default constructor
 	Texture()
 	Texture()
-		: mScaleU	(1.0f)
-		, mScaleV	(1.0f)
-		, mOffsetU	(0.0f)
+		: mOffsetU	(0.0f)
 		, mOffsetV	(0.0f)
 		, mOffsetV	(0.0f)
+		, mScaleU	(1.0f)
+		, mScaleV	(1.0f)
 		, mRotation	(0.0f)
 		, mRotation	(0.0f)
 		, mMapMode	(aiTextureMapMode_Wrap)
 		, mMapMode	(aiTextureMapMode_Wrap)
 		, iUVSrc	(0)
 		, iUVSrc	(0)
@@ -335,10 +318,10 @@ struct Texture
 	std::string mMapName;
 	std::string mMapName;
 
 
 	//! Specifies texture coordinate offsets/scaling/rotations
 	//! Specifies texture coordinate offsets/scaling/rotations
-	float mScaleU;
-	float mScaleV;
 	float mOffsetU;
 	float mOffsetU;
 	float mOffsetV;
 	float mOffsetV;
+	float mScaleU;
+	float mScaleV;
 	float mRotation;
 	float mRotation;
 
 
 	//! Specifies the mapping mode to be used for the texture
 	//! Specifies the mapping mode to be used for the texture
@@ -348,6 +331,9 @@ struct Texture
 	bool bPrivate;
 	bool bPrivate;
 	int iUVSrc;
 	int iUVSrc;
 };
 };
+
+#include "./../include/Compiler/poppack1.h"
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper structure representing a 3ds material */
 /** Helper structure representing a 3ds material */
 struct Material
 struct Material
@@ -414,6 +400,7 @@ struct Material
 	unsigned int iBakeUVTransform;
 	unsigned int iBakeUVTransform;
 	Texture* pcSingleTexture;
 	Texture* pcSingleTexture;
 };
 };
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper structure to represent a 3ds file mesh */
 /** Helper structure to represent a 3ds file mesh */
 struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
 struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
@@ -433,7 +420,7 @@ struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
 	std::string mName;
 	std::string mName;
 
 
 	//! Texture coordinates
 	//! Texture coordinates
-	std::vector<aiVector2D> mTexCoords;
+	std::vector<aiVector3D> mTexCoords;
 
 
 	//! Face materials
 	//! Face materials
 	std::vector<unsigned int> mFaceMaterials;
 	std::vector<unsigned int> mFaceMaterials;

+ 34 - 27
code/3DSLoader.cpp

@@ -104,7 +104,7 @@ bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandle
 // Setup configuration properties
 // Setup configuration properties
 void Discreet3DSImporter::SetupProperties(const Importer* pImp)
 void Discreet3DSImporter::SetupProperties(const Importer* pImp)
 {
 {
-	configSkipPivot = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false;
+	// nothing to be done for the moment
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -141,7 +141,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
 	// internal verbose representation. Finally compute normal
 	// internal verbose representation. Finally compute normal
 	// vectors from the smoothing groups we read from the
 	// vectors from the smoothing groups we read from the
 	// file.
 	// file.
-	for (std::vector<D3DS::Mesh>::iterator i =  mScene->mMeshes.begin(),
+	for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(),
 		 end = mScene->mMeshes.end(); i != end;++i)
 		 end = mScene->mMeshes.end(); i != end;++i)
 	{
 	{
 		CheckIndices(*i);
 		CheckIndices(*i);
@@ -149,9 +149,6 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
 		ComputeNormalsWithSmoothingsGroups<D3DS::Face>(*i);
 		ComputeNormalsWithSmoothingsGroups<D3DS::Face>(*i);
 	}
 	}
 
 
-	// Apply scaling and offsets to all texture coordinates
-	TextureTransform::ApplyScaleNOffset(mScene->mMaterials);
-
 	// Replace all occurences of the default material with a
 	// Replace all occurences of the default material with a
 	// valid material. Generate it if no material containing
 	// valid material. Generate it if no material containing
 	// DEFAULT in its name has been found in the file
 	// DEFAULT in its name has been found in the file
@@ -678,6 +675,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 		}
 		}
 		else l = & mCurrentNode->aPositionKeys;
 		else l = & mCurrentNode->aPositionKeys;
 
 
+		l->reserve(numFrames);
 		for (unsigned int i = 0; i < numFrames;++i)
 		for (unsigned int i = 0; i < numFrames;++i)
 		{
 		{
 			unsigned int fidx = stream->GetI2();
 			unsigned int fidx = stream->GetI2();
@@ -724,6 +722,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 
 
 		stream->IncPtr(10);
 		stream->IncPtr(10);
 		unsigned int numFrames = stream->GetI2();
 		unsigned int numFrames = stream->GetI2();
+		l->reserve(numFrames);
 		stream->IncPtr(2);
 		stream->IncPtr(2);
 
 
 		for (unsigned int i = 0; i < numFrames;++i)
 		for (unsigned int i = 0; i < numFrames;++i)
@@ -776,6 +775,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 
 
 		bool sortKeys = false;
 		bool sortKeys = false;
 		std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys;
 		std::vector<aiQuatKey>* l = &mCurrentNode->aRotationKeys;
+		l->reserve(numFrames);
 
 
 		for (unsigned int i = 0; i < numFrames;++i)
 		for (unsigned int i = 0; i < numFrames;++i)
 		{
 		{
@@ -825,6 +825,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 
 
 		bool sortKeys = false;
 		bool sortKeys = false;
 		std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys;
 		std::vector<aiVectorKey>* l = &mCurrentNode->aScalingKeys;
+		l->reserve(numFrames);
 
 
 		for (unsigned int i = 0; i < numFrames;++i)
 		for (unsigned int i = 0; i < numFrames;++i)
 		{
 		{
@@ -924,7 +925,7 @@ void Discreet3DSImporter::ParseFaceChunk()
 		}
 		}
 
 
 		// Now continue and read all material indices
 		// Now continue and read all material indices
-		cnt = stream->GetI2();
+		cnt = (uint16_t)stream->GetI2();
 		for (unsigned int i = 0; i < cnt;++i)
 		for (unsigned int i = 0; i < cnt;++i)
 		{
 		{
 			unsigned int fidx = (uint16_t)stream->GetI2();
 			unsigned int fidx = (uint16_t)stream->GetI2();
@@ -957,7 +958,8 @@ void Discreet3DSImporter::ParseMeshChunk()
 	case Discreet3DS::CHUNK_VERTLIST:
 	case Discreet3DS::CHUNK_VERTLIST:
 		{
 		{
 		// This is the list of all vertices in the current mesh
 		// This is the list of all vertices in the current mesh
-		int num = stream->GetI2();
+		int num = (int)(uint16_t)stream->GetI2();
+		mMesh.mPositions.reserve(num);
 		while (num-- > 0)
 		while (num-- > 0)
 		{
 		{
 			aiVector3D v;
 			aiVector3D v;
@@ -985,8 +987,8 @@ void Discreet3DSImporter::ParseMeshChunk()
 		mMesh.mMat.c4 = stream->GetF4();
 		mMesh.mMat.c4 = stream->GetF4();
 
 
 		// Now check whether the matrix has got a negative determinant
 		// Now check whether the matrix has got a negative determinant
-		// If yes, we need to flip all vertices' x axis ....
-		// From lib3ds, mesh.c
+		// If yes, we need to flip all vertices' Z axis ....
+		// This code has been taken from lib3ds
 		if (mMesh.mMat.Determinant() < 0.0f)
 		if (mMesh.mMat.Determinant() < 0.0f)
 		{
 		{
 			// Compute the inverse of the matrix
 			// Compute the inverse of the matrix
@@ -994,10 +996,10 @@ void Discreet3DSImporter::ParseMeshChunk()
 			mInv.Inverse();
 			mInv.Inverse();
 
 
 			aiMatrix4x4 mMe = mMesh.mMat;
 			aiMatrix4x4 mMe = mMesh.mMat;
-			mMe.a1 *= -1.0f;
-			mMe.b1 *= -1.0f;
 			mMe.c1 *= -1.0f;
 			mMe.c1 *= -1.0f;
-			mMe.d1 *= -1.0f;
+			mMe.c2 *= -1.0f;
+			mMe.c3 *= -1.0f;
+			mMe.c4 *= -1.0f;
 			mInv = mInv * mMe;
 			mInv = mInv * mMe;
 
 
 			// Now transform all vertices
 			// Now transform all vertices
@@ -1010,16 +1012,19 @@ void Discreet3DSImporter::ParseMeshChunk()
 				c[2]= mInv[0][2]*a[0] + mInv[1][2]*a[1] + mInv[2][2]*a[2] + mInv[3][2];
 				c[2]= mInv[0][2]*a[0] + mInv[1][2]*a[1] + mInv[2][2]*a[2] + mInv[3][2];
 				mMesh.mPositions[i] = c;
 				mMesh.mPositions[i] = c;
 			}
 			}
+
+			DefaultLogger::get()->info("3DS: Flipping mesh Z-Axis");
 		}}
 		}}
 		break;
 		break;
 
 
 	case Discreet3DS::CHUNK_MAPLIST:
 	case Discreet3DS::CHUNK_MAPLIST:
 		{
 		{
 		// This is the list of all UV coords in the current mesh
 		// This is the list of all UV coords in the current mesh
-		int num = stream->GetI2();
+		int num = (int)(uint16_t)stream->GetI2();
+		mMesh.mTexCoords.reserve(num);
 		while (num-- > 0)
 		while (num-- > 0)
 		{
 		{
-			aiVector2D v;
+			aiVector3D v;
 			v.x = stream->GetF4();
 			v.x = stream->GetF4();
 			v.y = stream->GetF4();
 			v.y = stream->GetF4();
 			mMesh.mTexCoords.push_back(v);
 			mMesh.mTexCoords.push_back(v);
@@ -1029,7 +1034,8 @@ void Discreet3DSImporter::ParseMeshChunk()
 	case Discreet3DS::CHUNK_FACELIST:
 	case Discreet3DS::CHUNK_FACELIST:
 		{
 		{
 		// This is the list of all faces in the current mesh
 		// This is the list of all faces in the current mesh
-		int num = stream->GetI2();
+		int num = (int)(uint16_t)stream->GetI2();
+		mMesh.mFaces.reserve(num);
 		while (num-- > 0)
 		while (num-- > 0)
 		{
 		{
 			// 3DS faces are ALWAYS triangles
 			// 3DS faces are ALWAYS triangles
@@ -1226,6 +1232,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
 	// recursively continue processing this hierarchy level
 	// recursively continue processing this hierarchy level
 	return ParseMaterialChunk();
 	return ParseMaterialChunk();
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 {
 {
@@ -1262,7 +1269,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 		if (0.0f == pcOut->mScaleU)
 		if (0.0f == pcOut->mScaleU)
 		{
 		{
 			DefaultLogger::get()->warn("Texture coordinate scaling in the "
 			DefaultLogger::get()->warn("Texture coordinate scaling in the "
-				"x direction is zero. Assuming this should be 1.0 ... ");
+				"x direction is zero. Assuming 1");
 			pcOut->mScaleU = 1.0f;
 			pcOut->mScaleU = 1.0f;
 		}
 		}
 		break;
 		break;
@@ -1272,14 +1279,14 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 		if (0.0f == pcOut->mScaleV)
 		if (0.0f == pcOut->mScaleV)
 		{
 		{
 			DefaultLogger::get()->warn("Texture coordinate scaling in the "
 			DefaultLogger::get()->warn("Texture coordinate scaling in the "
-				"y direction is zero. Assuming this should be 1.0 ... ");
+				"y direction is zero. Assuming 1");
 			pcOut->mScaleV = 1.0f;
 			pcOut->mScaleV = 1.0f;
 		}
 		}
 		break;
 		break;
 
 
 	case Discreet3DS::CHUNK_MAT_MAP_UOFFSET:
 	case Discreet3DS::CHUNK_MAT_MAP_UOFFSET:
 		// Texture coordinate offset in the U direction
 		// Texture coordinate offset in the U direction
-		pcOut->mOffsetU = stream->GetF4();
+		pcOut->mOffsetU = -stream->GetF4();
 		break;
 		break;
 
 
 	case Discreet3DS::CHUNK_MAT_MAP_VOFFSET:
 	case Discreet3DS::CHUNK_MAT_MAP_VOFFSET:
@@ -1288,24 +1295,24 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 		break;
 		break;
 
 
 	case Discreet3DS::CHUNK_MAT_MAP_ANG:
 	case Discreet3DS::CHUNK_MAT_MAP_ANG:
-		// Texture coordinate rotation, CCW in radians
-		pcOut->mRotation = stream->GetF4();
+		// Texture coordinate rotation, CCW in DEGREES
+		pcOut->mRotation = -AI_DEG_TO_RAD( stream->GetF4() );
 		break;
 		break;
 
 
 	case Discreet3DS::CHUNK_MAT_MAP_TILING:
 	case Discreet3DS::CHUNK_MAT_MAP_TILING:
 		{
 		{
 		uint16_t iFlags = stream->GetI2();
 		uint16_t iFlags = stream->GetI2();
 
 
-		// check whether the mirror flag is set
+		// Get the mapping mode (for both axes)
 		if (iFlags & 0x2u)
 		if (iFlags & 0x2u)
-		{
 			pcOut->mMapMode = aiTextureMapMode_Mirror;
 			pcOut->mMapMode = aiTextureMapMode_Mirror;
+		
+		else if (iFlags & 0x10u)
+			pcOut->mMapMode = aiTextureMapMode_Decal;
+		
+		// wrapping in all remaining cases
+		else pcOut->mMapMode = aiTextureMapMode_Wrap;
 		}
 		}
-		// assume that "decal" means clamping ...
-		else if (iFlags & 0x10u && iFlags & 0x1u)
-		{
-			pcOut->mMapMode = aiTextureMapMode_Clamp;
-		}}
 		break;
 		break;
 	};
 	};
 
 

+ 0 - 4
code/3DSLoader.h

@@ -238,12 +238,8 @@ protected:
 	*/
 	*/
 	void CheckIndices(D3DS::Mesh& sMesh);
 	void CheckIndices(D3DS::Mesh& sMesh);
 
 
-
 protected:
 protected:
 
 
-	/** Configuration option: skip pivot chunks */
-	bool configSkipPivot;
-
 	/** Stream to read from */
 	/** Stream to read from */
 	StreamReaderLE* stream;
 	StreamReaderLE* stream;
 
 

+ 44 - 7
code/ACLoader.cpp

@@ -151,11 +151,30 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
 	if (!TokenMatch(buffer,"OBJECT",6))
 	if (!TokenMatch(buffer,"OBJECT",6))
 		return;
 		return;
 
 
+	SkipSpaces(&buffer);
+
 	++mNumMeshes;
 	++mNumMeshes;
 
 
 	objects.push_back(Object());
 	objects.push_back(Object());
 	Object& obj = objects.back();
 	Object& obj = objects.back();
 
 
+	aiLight* light = NULL;
+	if (!ASSIMP_stricmp(buffer,"light"))
+	{
+		// 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
+		light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",mLights->size()-1);
+		obj.name = std::string( light->mName.data );
+
+	}
+
 	while (GetNextLine())
 	while (GetNextLine())
 	{
 	{
 		if (TokenMatch(buffer,"kids",4))
 		if (TokenMatch(buffer,"kids",4))
@@ -176,6 +195,13 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
 		{
 		{
 			SkipSpaces(&buffer);
 			SkipSpaces(&buffer);
 			AI_AC_GET_STRING(obj.name);
 			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))
 		else if (TokenMatch(buffer,"texture",7))
 		{
 		{
@@ -219,8 +245,6 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
 				obj.vertices.push_back(aiVector3D());
 				obj.vertices.push_back(aiVector3D());
 				aiVector3D& v = obj.vertices.back();
 				aiVector3D& v = obj.vertices.back();
 				AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
 				AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
-				//std::swap(v.z,v.y);
-				v.z *= -1.f;
 			}
 			}
 		}
 		}
 		else if (TokenMatch(buffer,"numsurf",7))
 		else if (TokenMatch(buffer,"numsurf",7))
@@ -597,7 +621,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
 	node->mTransformation = aiMatrix4x4 ( object.rotation );
 	node->mTransformation = aiMatrix4x4 ( object.rotation );
 
 
 	node->mTransformation.a4 = object.translation.x;
 	node->mTransformation.a4 = object.translation.x;
-	node->mTransformation.b4 = object.translation.y;
+	node->mTransformation.b4 = -object.translation.y;
 	node->mTransformation.c4 = object.translation.z;
 	node->mTransformation.c4 = object.translation.z;
 
 
 	return node;
 	return node;
@@ -644,6 +668,9 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
 	std::vector<Object> rootObjects;
 	std::vector<Object> rootObjects;
 	rootObjects.reserve(5);
 	rootObjects.reserve(5);
 
 
+	std::vector<aiLight*> lights;
+	mLights = & lights;
+
 	while (GetNextLine())
 	while (GetNextLine())
 	{
 	{
 		if (TokenMatch(buffer,"MATERIAL",8))
 		if (TokenMatch(buffer,"MATERIAL",8))
@@ -662,9 +689,9 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
 			}
 			}
 
 
 			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
 			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.rgb);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.rgb);
-			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,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("shi",3,1,&mat.shin);
 			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
 			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
 		}
 		}
@@ -701,6 +728,9 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
 	pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
 	pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
 	if (1 != rootObjects.size())delete root;
 	if (1 != rootObjects.size())delete root;
 
 
+	if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
+		pScene->mRootNode->mName.Set("<AC3DWorld>");
+
 	// build output arrays
 	// build output arrays
 	if (meshes.empty())
 	if (meshes.empty())
 	{
 	{
@@ -710,10 +740,17 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
 	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
 	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
 	::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
 	::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
 
 
-	// build output arrays
+
 	pScene->mNumMaterials = (unsigned int)omaterials.size();
 	pScene->mNumMaterials = (unsigned int)omaterials.size();
 	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
 	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
 	::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
 	::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
+
+	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 AI_BUILD_NO_AC_IMPORTER
 #endif //!defined AI_BUILD_NO_AC_IMPORTER

+ 3 - 0
code/ACLoader.h

@@ -236,6 +236,9 @@ private:
 	// basing on this information we can find a
 	// basing on this information we can find a
 	// good estimate how many meshes we'll have in the final scene.
 	// good estimate how many meshes we'll have in the final scene.
 	unsigned int mNumMeshes;
 	unsigned int mNumMeshes;
+
+	// current list of light sources
+	std::vector<aiLight*>* mLights;
 };
 };
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp

+ 167 - 194
code/ASELoader.cpp

@@ -48,12 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ASELoader.h"
 #include "ASELoader.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
 #include "StringComparison.h"
 #include "StringComparison.h"
-#include "TextureTransform.h"
 #include "SkeletonMeshBuilder.h"
 #include "SkeletonMeshBuilder.h"
+#include "TargetAnimation.h"
 
 
 // utilities
 // utilities
 #include "fast_atof.h"
 #include "fast_atof.h"
-#include "qnan.h"
 
 
 using namespace Assimp;
 using namespace Assimp;
 using namespace Assimp::ASE;
 using namespace Assimp::ASE;
@@ -156,15 +155,15 @@ void ASEImporter::InternReadFile( const std::string& pFile,
 		std::vector<aiMesh*> avOutMeshes;
 		std::vector<aiMesh*> avOutMeshes;
 		avOutMeshes.reserve(mParser->m_vMeshes.size()*2);
 		avOutMeshes.reserve(mParser->m_vMeshes.size()*2);
 		for (std::vector<ASE::Mesh>::iterator
 		for (std::vector<ASE::Mesh>::iterator
-			i =  mParser->m_vMeshes.begin();
-			i != mParser->m_vMeshes.end();++i)
+			i =  mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i)
 		{
 		{
 			if ((*i).bSkip)continue;
 			if ((*i).bSkip)continue;
 
 
-			// Now we need to create proper meshes from the import we 
-			// need to split them by materials, build valid vertex/
-			// face lists ...
-			BuildUniqueRepresentation(*i);
+				// First of all - we need to build an unique mesh representation
+				// that we can recompute the normal vectors easily. This is
+				// also a prerequisite for the second code path in ConvertMeshes()
+				// so it's difficult to optimize it away. TODO!
+				BuildUniqueRepresentation(*i);
 
 
 			// Need to generate proper vertex normals if necessary
 			// Need to generate proper vertex normals if necessary
 			if(GenerateNormals(*i))
 			if(GenerateNormals(*i))
@@ -305,8 +304,12 @@ void ASEImporter::BuildAnimations()
 		// that represent the node transformation.
 		// that represent the node transformation.
 		if ((*i)->mAnim.akeyPositions.size() > 1 || 
 		if ((*i)->mAnim.akeyPositions.size() > 1 || 
 			(*i)->mAnim.akeyRotations.size() > 1 ||
 			(*i)->mAnim.akeyRotations.size() > 1 ||
-			(*i)->mAnim.akeyScaling.size()   > 1 ||
-			(*i)->mTargetAnim.akeyPositions.size() > 1 
+			(*i)->mAnim.akeyScaling.size()   > 1)
+		{
+			++iNum;
+		}
+
+		if ((*i)->mTargetAnim.akeyPositions.size() > 1 
 			 && is_not_qnan( (*i)->mTargetPosition.x ))
 			 && is_not_qnan( (*i)->mTargetPosition.x ))
 		{
 		{
 			++iNum;
 			++iNum;
@@ -337,6 +340,21 @@ void ASEImporter::BuildAnimations()
 				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
 				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
 				nd->mNodeName.Set(me->mName + ".Target");
 				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
 				// Allocate the key array and fill it
 				nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size();
 				nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size();
 				nd->mPositionKeys    = new aiVectorKey[nd->mNumPositionKeys];
 				nd->mPositionKeys    = new aiVectorKey[nd->mNumPositionKeys];
@@ -345,7 +363,8 @@ void ASEImporter::BuildAnimations()
 					nd->mNumPositionKeys * sizeof(aiVectorKey));
 					nd->mNumPositionKeys * sizeof(aiVectorKey));
 			}
 			}
 
 
-			if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1)
+			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
 				// Begin a new node animation channel for this node
 				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
 				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
@@ -424,8 +443,6 @@ void ASEImporter::BuildCameras()
 			out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); 
 			out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); 
 			out->mHorizontalFOV = in.mFOV;
 			out->mHorizontalFOV = in.mFOV;
 
 
-			// TODO: Implement proper camera target
-
 			out->mName.Set(in.mName);
 			out->mName.Set(in.mName);
 		}
 		}
 	}
 	}
@@ -480,7 +497,7 @@ void ASEImporter::AddNodes(std::vector<BaseNode*>& nodes,
 	aiNode* pcParent,const char* szName)
 	aiNode* pcParent,const char* szName)
 {
 {
 	aiMatrix4x4 m;
 	aiMatrix4x4 m;
-	this->AddNodes(nodes,pcParent,szName,m);
+	AddNodes(nodes,pcParent,szName,m);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -580,6 +597,12 @@ void ASEImporter::AddNodes (std::vector<BaseNode*>& nodes,
 		mParentAdjust.Inverse();
 		mParentAdjust.Inverse();
 		node->mTransformation = mParentAdjust*snode->mTransform;
 		node->mTransformation = mParentAdjust*snode->mTransform;
 
 
+		// Add sub nodes - prevent stack overflow
+		if (node->mName != node->mParent->mName)
+		{
+			AddNodes(nodes,node,node->mName.data,snode->mTransform);
+		}
+
 		// Further processing depends on the type of the node
 		// Further processing depends on the type of the node
 		if (snode->mType == ASE::BaseNode::Mesh)
 		if (snode->mType == ASE::BaseNode::Mesh)
 		{
 		{
@@ -597,39 +620,43 @@ void ASEImporter::AddNodes (std::vector<BaseNode*>& nodes,
 			// target (the direction information is contained in *this*
 			// target (the direction information is contained in *this*
 			// node's animation track but the exact target position
 			// node's animation track but the exact target position
 			// would be lost otherwise)
 			// would be lost otherwise)
-			apcNodes.push_back(new aiNode());
-			aiNode* node = apcNodes.back();
+			if (!node->mNumChildren)
+			{
+				node->mChildren = new aiNode*[1];
+			}
 
 
-			node->mName.Set ( snode->mName + ".Target" );
-			node->mTransformation.a4 = snode->mTargetPosition.x;
-			node->mTransformation.b4 = snode->mTargetPosition.y;
-			node->mTransformation.c4 = snode->mTargetPosition.z;
+			aiNode* nd = new aiNode();
 
 
-			node->mParent = pcParent;
-		}
+			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;
 
 
-		// add sub nodes
-		// aiMatrix4x4 mNewAbs =  mat * node->mTransformation;
+			nd->mParent = node;
 
 
-		// prevent stack overflow
-		if (node->mName != node->mParent->mName)
-		{
-			AddNodes(nodes,node,node->mName.data,snode->mTransform);
+			// 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
+	// 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();
 	pcParent->mNumChildren = (unsigned int)apcNodes.size();
 	if (pcParent->mNumChildren)
 	if (pcParent->mNumChildren)
 	{
 	{
-		pcParent->mChildren = new aiNode*[apcNodes.size()];
+		pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */];
 
 
 		// now build all nodes for our nice new children
 		// now build all nodes for our nice new children
 		for (unsigned int p = 0; p < apcNodes.size();++p)
 		for (unsigned int p = 0; p < apcNodes.size();++p)
-		{
 			pcParent->mChildren[p] = apcNodes[p];
 			pcParent->mChildren[p] = apcNodes[p];
-		}
 	}
 	}
 	return;
 	return;
 }
 }
@@ -643,7 +670,7 @@ void ASEImporter::BuildNodes()
 	pcScene->mRootNode = new aiNode();
 	pcScene->mRootNode = new aiNode();
 	pcScene->mRootNode->mNumMeshes = 0;
 	pcScene->mRootNode->mNumMeshes = 0;
 	pcScene->mRootNode->mMeshes = 0;
 	pcScene->mRootNode->mMeshes = 0;
-	pcScene->mRootNode->mName.Set("<root>");
+	pcScene->mRootNode->mName.Set("<ASERoot>");
 
 
 	// Setup the coordinate system transformation
 	// Setup the coordinate system transformation
 	//pcScene->mRootNode->mTransformation.c3 *= -1.f;
 	//pcScene->mRootNode->mTransformation.c3 *= -1.f;
@@ -708,7 +735,7 @@ void ASEImporter::BuildNodes()
 		{
 		{
 			const ASE::BaseNode* src = *i;
 			const ASE::BaseNode* src = *i;
 
 
-			// the parent is not known, so we can assume that we must add 
+			// The parent is not known, so we can assume that we must add 
 			// this node to the root node of the whole scene
 			// this node to the root node of the whole scene
 			aiNode* pcNode = new aiNode();
 			aiNode* pcNode = new aiNode();
 			pcNode->mParent = pcScene->mRootNode;
 			pcNode->mParent = pcScene->mRootNode;
@@ -731,16 +758,18 @@ void ASEImporter::BuildNodes()
 	for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
 	for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
 		pcScene->mMeshes[i]->mColors[2] = NULL;
 		pcScene->mMeshes[i]->mColors[2] = NULL;
 
 
-	// if there is only one subnode, set it as root node
+	// If there is only one subnode, set it as root node
 	// FIX: The sub node may not have animations assigned
 	// FIX: The sub node may not have animations assigned
 	if (1 == pcScene->mRootNode->mNumChildren && !pcScene->mNumAnimations)
 	if (1 == pcScene->mRootNode->mNumChildren && !pcScene->mNumAnimations)
 	{
 	{
 		aiNode* cc = pcScene->mRootNode->mChildren[0];
 		aiNode* cc = pcScene->mRootNode->mChildren[0];
 		aiNode* pc = pcScene->mRootNode;
 		aiNode* pc = pcScene->mRootNode;
 
 
+		if (!cc->mName.length)
+			cc->mName = pc->mName;
+
 		pcScene->mRootNode = cc;
 		pcScene->mRootNode = cc;
-		pcScene->mRootNode->mParent = NULL;
-		cc->mTransformation = pc->mTransformation * cc->mTransformation;
+		cc->mParent = NULL;
 
 
 		// make sure the destructor won't delete us ...
 		// make sure the destructor won't delete us ...
 		delete[] pc->mChildren;
 		delete[] pc->mChildren;
@@ -803,17 +832,12 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)
 		for (unsigned int n = 0; n < 3;++n,++iCurrent)
 		for (unsigned int n = 0; n < 3;++n,++iCurrent)
 		{
 		{
 			mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
 			mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
-			//std::swap((float&)mPositions[iCurrent].z,(float&)mPositions[iCurrent].y); // DX-to-OGL
-			//mPositions[iCurrent].y *= -1.f;
 
 
 			// add texture coordinates
 			// add texture coordinates
 			for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
 			for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
 			{
 			{
-				if (!mesh.amTexCoords[c].empty())
-				{
-					amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]];
-					// amTexCoords[c][iCurrent].y = 1.f- amTexCoords[c][iCurrent].y; // DX-to-OGL
-				}
+				if (mesh.amTexCoords[c].empty())break;
+				amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]];
 			}
 			}
 			// add vertex colors
 			// add vertex colors
 			if (!mesh.mVertexColors.empty())
 			if (!mesh.mVertexColors.empty())
@@ -825,9 +849,6 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)
 			{
 			{
 				mNormals[iCurrent] = mesh.mNormals[fi*3+n];
 				mNormals[iCurrent] = mesh.mNormals[fi*3+n];
 				mNormals[iCurrent].Normalize();
 				mNormals[iCurrent].Normalize();
-
-				//std::swap((float&)mNormals[iCurrent].z,(float&)mNormals[iCurrent].y); // DX-to-OGL
-				//mNormals[iCurrent].y *= -1.0f;
 			}
 			}
 
 
 			// handle bone vertices
 			// handle bone vertices
@@ -838,11 +859,9 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)
 				//  will fix that again ...)
 				//  will fix that again ...)
 				mBoneVertices[iCurrent] =  mesh.mBoneVertices[(*i).mIndices[n]];
 				mBoneVertices[iCurrent] =  mesh.mBoneVertices[(*i).mIndices[n]];
 			}
 			}
+
+			(*i).mIndices[n] = iCurrent;
 		}
 		}
-		// we need to flip the order of the indices
-		(*i).mIndices[0] = iCurrent-1;
-		(*i).mIndices[1] = iCurrent-2;
-		(*i).mIndices[2] = iCurrent-3;
 	}
 	}
 
 
 	// replace the old arrays
 	// replace the old arrays
@@ -852,20 +871,37 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)
 
 
 	for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
 	for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
 		mesh.amTexCoords[c] = amTexCoords[c];
 		mesh.amTexCoords[c] = amTexCoords[c];
-	return;
+}
+
+// ------------------------------------------------------------------------------------------------
+void CopyASETexture(MaterialHelper& 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 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));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ASEImporter::ConvertMaterial(ASE::Material& mat)
 void ASEImporter::ConvertMaterial(ASE::Material& mat)
 {
 {
-	// allocate the output material
+	// LARGE TODO: Much code her is copied from 3DS ... join them maybe?
+
+	// Allocate the output material
 	mat.pcInstance = new MaterialHelper();
 	mat.pcInstance = new MaterialHelper();
 
 
 	// At first add the base ambient color of the
 	// At first add the base ambient color of the
 	// scene to	the material
 	// scene to	the material
-	mat.mAmbient.r += this->mParser->m_clrAmbient.r;
-	mat.mAmbient.g += this->mParser->m_clrAmbient.g;
-	mat.mAmbient.b += this->mParser->m_clrAmbient.b;
+	mat.mAmbient.r += mParser->m_clrAmbient.r;
+	mat.mAmbient.g += mParser->m_clrAmbient.g;
+	mat.mAmbient.b += mParser->m_clrAmbient.b;
 
 
 	aiString name;
 	aiString name;
 	name.Set( mat.mName);
 	name.Set( mat.mName);
@@ -883,7 +919,7 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
 		mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
 		mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
 		mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
 		mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
 	}
 	}
-	// if there is no shininess, we can disable phong lighting
+	// If there is no shininess, we can disable phong lighting
 	else if (D3DS::Discreet3DS::Metal == mat.mShading ||
 	else if (D3DS::Discreet3DS::Metal == mat.mShading ||
 		D3DS::Discreet3DS::Phong == mat.mShading ||
 		D3DS::Discreet3DS::Phong == mat.mShading ||
 		D3DS::Discreet3DS::Blinn == mat.mShading)
 		D3DS::Discreet3DS::Blinn == mat.mShading)
@@ -894,6 +930,12 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
 	// opacity
 	// opacity
 	mat.pcInstance->AddProperty<float>( &mat.mTransparency,1,AI_MATKEY_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
 	// shading mode
 	aiShadingMode eShading = aiShadingMode_NoShading;
 	aiShadingMode eShading = aiShadingMode_NoShading;
@@ -906,9 +948,14 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
 		case D3DS::Discreet3DS::Blinn :
 		case D3DS::Discreet3DS::Blinn :
 			eShading = aiShadingMode_Blinn; break;
 			eShading = aiShadingMode_Blinn; break;
 
 
-		// I don't know what "Wire" shading should be,
-		// assume it is simple lambertian diffuse (L dot N) shading
+			// I don't know what "Wire" shading should be,
+			// assume it is simple lambertian diffuse (L dot N) shading
 		case D3DS::Discreet3DS::Wire:
 		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:
 		case D3DS::Discreet3DS::Gouraud:
 			eShading = aiShadingMode_Gouraud; break;
 			eShading = aiShadingMode_Gouraud; break;
 		case D3DS::Discreet3DS::Metal :
 		case D3DS::Discreet3DS::Metal :
@@ -916,84 +963,33 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
 	}
 	}
 	mat.pcInstance->AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
 	mat.pcInstance->AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
 
 
-	if (D3DS::Discreet3DS::Wire == mat.mShading)
-	{
-		// set the wireframe flag
-		unsigned int iWire = 1;
-		mat.pcInstance->AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
-	}
-
-	// texture, if there is one
+	// DIFFUSE texture
 	if( mat.sTexDiffuse.mMapName.length() > 0)
 	if( mat.sTexDiffuse.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( mat.sTexDiffuse.mMapName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0));
+		CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE);
 
 
-		if (is_not_qnan(mat.sTexDiffuse.mTextureBlend))
-			mat.pcInstance->AddProperty<float>( &mat.sTexDiffuse.mTextureBlend, 1, 
-			AI_MATKEY_TEXBLEND_DIFFUSE(0));
-	}
+	// SPECULAR texture
 	if( mat.sTexSpecular.mMapName.length() > 0)
 	if( mat.sTexSpecular.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( mat.sTexSpecular.mMapName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(0));
+		CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR);
 
 
-		if (is_not_qnan(mat.sTexSpecular.mTextureBlend))
-			mat.pcInstance->AddProperty<float>( &mat.sTexSpecular.mTextureBlend, 1,
-			AI_MATKEY_TEXBLEND_SPECULAR(0));
-	}
+	// AMBIENT texture
+	if( mat.sTexAmbient.mMapName.length() > 0)
+		CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT);
+
+	// OPACITY texture
 	if( mat.sTexOpacity.mMapName.length() > 0)
 	if( mat.sTexOpacity.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( mat.sTexOpacity.mMapName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_OPACITY(0));
+		CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY);
 
 
-		if (is_not_qnan(mat.sTexOpacity.mTextureBlend))
-			mat.pcInstance->AddProperty<float>( &mat.sTexOpacity.mTextureBlend, 1,
-			AI_MATKEY_TEXBLEND_OPACITY(0));
-	}
+	// EMISSIVE texture
 	if( mat.sTexEmissive.mMapName.length() > 0)
 	if( mat.sTexEmissive.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( mat.sTexEmissive.mMapName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(0));
-
-		if (is_not_qnan(mat.sTexEmissive.mTextureBlend))
-			mat.pcInstance->AddProperty<float>( &mat.sTexEmissive.mTextureBlend, 1, 
-			AI_MATKEY_TEXBLEND_EMISSIVE(0));
-	}
-	if( mat.sTexAmbient.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( mat.sTexAmbient.mMapName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(0));
+		CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE);
 
 
-		if (is_not_qnan(mat.sTexAmbient.mTextureBlend))
-			mat.pcInstance->AddProperty<float>( &mat.sTexAmbient.mTextureBlend, 1, 
-			AI_MATKEY_TEXBLEND_AMBIENT(0));
-	}
+	// BUMP texture
 	if( mat.sTexBump.mMapName.length() > 0)
 	if( mat.sTexBump.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( mat.sTexBump.mMapName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(0));
+		CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT);
 
 
-		if (is_not_qnan(mat.sTexBump.mTextureBlend))
-			mat.pcInstance->AddProperty<float>( &mat.sTexBump.mTextureBlend, 1,
-			AI_MATKEY_TEXBLEND_HEIGHT(0));
-	}
+	// SHININESS texture
 	if( mat.sTexShininess.mMapName.length() > 0)
 	if( mat.sTexShininess.mMapName.length() > 0)
-	{
-		aiString tex;
-		tex.Set( mat.sTexShininess.mMapName);
-		mat.pcInstance->AddProperty( &tex, AI_MATKEY_TEXTURE_SHININESS(0));
-
-		if (is_not_qnan(mat.sTexShininess.mTextureBlend))
-			mat.pcInstance->AddProperty<float>( &mat.sTexBump.mTextureBlend, 1, 
-			AI_MATKEY_TEXBLEND_SHININESS(0));
-	}
+		CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS);
 
 
 	// store the name of the material itself, too
 	// store the name of the material itself, too
 	if( mat.mName.length() > 0)
 	if( mat.mName.length() > 0)
@@ -1081,12 +1077,12 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 					p_pcOut->mNormals  = new aiVector3D[p_pcOut->mNumVertices];
 					p_pcOut->mNormals  = new aiVector3D[p_pcOut->mNumVertices];
 					for (unsigned int q = 0; q < aiSplit[p].size();++q)
 					for (unsigned int q = 0; q < aiSplit[p].size();++q)
 					{
 					{
-					iIndex = aiSplit[p][q];
+						iIndex = aiSplit[p][q];
 
 
 						p_pcOut->mFaces[q].mIndices = new unsigned int[3];
 						p_pcOut->mFaces[q].mIndices = new unsigned int[3];
 						p_pcOut->mFaces[q].mNumIndices = 3;
 						p_pcOut->mFaces[q].mNumIndices = 3;
 
 
-						for (unsigned int t = 0; t < 3;++t)
+						for (unsigned int t = 0; t < 3;++t, ++iBase)
 						{
 						{
 							const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
 							const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
 
 
@@ -1110,13 +1106,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 									}
 									}
 								}
 								}
 							}
 							}
-							++iBase;
+							p_pcOut->mFaces[q].mIndices[t] = iBase;
 						}
 						}
-
-						// Flip the face order 
-						p_pcOut->mFaces[q].mIndices[0] = iBase-3;
-						p_pcOut->mFaces[q].mIndices[1] = iBase-2;
-						p_pcOut->mFaces[q].mIndices[2] = iBase-1;
 					}
 					}
 				}
 				}
 				// convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
 				// convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
@@ -1134,12 +1125,12 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 								p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
 								p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
 							}
 							}
 						}
 						}
-						// setup the number of valid vertex components
+						// Setup the number of valid vertex components
 						p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
 						p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
 					}
 					}
 				}
 				}
 
 
-				// convert vertex colors (only one set supported)
+				// Convert vertex colors (only one set supported)
 				if (!mesh.mVertexColors.empty())
 				if (!mesh.mVertexColors.empty())
 				{
 				{
 					p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
 					p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
@@ -1153,6 +1144,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 						}
 						}
 					}
 					}
 				}
 				}
+				// Copy bones
 				if (!mesh.mBones.empty())
 				if (!mesh.mBones.empty())
 				{
 				{
 					p_pcOut->mNumBones = 0;
 					p_pcOut->mNumBones = 0;
@@ -1211,7 +1203,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 		p_pcOut->mColors[2] = (aiColor4D*) &mesh;
 		p_pcOut->mColors[2] = (aiColor4D*) &mesh;
 		avOutMeshes.push_back(p_pcOut);
 		avOutMeshes.push_back(p_pcOut);
 
 
-		// if the mesh hasn't faces or vertices, there are two cases
+		// If the mesh hasn't faces or vertices, there are two cases
 		// possible: 1. the model is invalid. 2. This is a dummy
 		// possible: 1. the model is invalid. 2. This is a dummy
 		// helper object which we are going to remove later ...
 		// helper object which we are going to remove later ...
 		if (mesh.mFaces.empty() || mesh.mPositions.empty())
 		if (mesh.mFaces.empty() || mesh.mPositions.empty())
@@ -1264,10 +1256,10 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 			p_pcOut->mFaces[iFace].mNumIndices = 3;
 			p_pcOut->mFaces[iFace].mNumIndices = 3;
 			p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
 			p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
 
 
-			// copy indices (flip the face order, too)
-			p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[2];
+			// 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[1] = mesh.mFaces[iFace].mIndices[1];
-			p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[0];
+			p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2];
 		}
 		}
 
 
 		// copy vertex bones
 		// copy vertex bones
@@ -1328,23 +1320,20 @@ void ASEImporter::BuildMaterialIndices()
 	// iterate through all materials and check whether we need them
 	// iterate through all materials and check whether we need them
 	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
 	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
 	{
 	{
-		if (mParser->m_vMaterials[iMat].bNeed)
+		ASE::Material& mat = mParser->m_vMaterials[iMat];
+		if (mat.bNeed)
 		{
 		{
-			// convert it to the aiMaterial layout
-			ASE::Material& mat = mParser->m_vMaterials[iMat];
+			// Convert it to the aiMaterial layout
 			ConvertMaterial(mat);
 			ConvertMaterial(mat);
-			TextureTransform::ApplyScaleNOffset(mat);
 			++pcScene->mNumMaterials;
 			++pcScene->mNumMaterials;
 		}
 		}
-		for (unsigned int iSubMat = 0; iSubMat < mParser->m_vMaterials[
-			iMat].avSubMaterials.size();++iSubMat)
+		for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
 		{
 		{
-			if (mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed)
+			ASE::Material& submat = mat.avSubMaterials[iSubMat];
+			if (submat.bNeed)
 			{
 			{
-				// convert it to the aiMaterial layout
-				ASE::Material& mat = mParser->m_vMaterials[iMat].avSubMaterials[iSubMat];
-				ConvertMaterial(mat);
-				TextureTransform::ApplyScaleNOffset(mat);
+				// Convert it to the aiMaterial layout
+				ConvertMaterial(submat);
 				++pcScene->mNumMaterials;
 				++pcScene->mNumMaterials;
 			}
 			}
 		}
 		}
@@ -1357,77 +1346,60 @@ void ASEImporter::BuildMaterialIndices()
 	unsigned int iNum = 0;
 	unsigned int iNum = 0;
 	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
 	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
 	{
 	{
-		if (mParser->m_vMaterials[iMat].bNeed)
+		ASE::Material& mat = mParser->m_vMaterials[iMat];
+		if (mat.bNeed)
 		{
 		{
-			ai_assert(NULL != mParser->m_vMaterials[iMat].pcInstance);
-			pcScene->mMaterials[iNum] = mParser->m_vMaterials[iMat].pcInstance;
+			ai_assert(NULL != mat.pcInstance);
+			pcScene->mMaterials[iNum] = mat.pcInstance;
 
 
-			// store the internal material, too
-			pcIntMaterials[iNum] = &mParser->m_vMaterials[iMat];
+			// Store the internal material, too
+			pcIntMaterials[iNum] = &mat;
 
 
-			// iterate through all meshes and search for one which is using
+			// Iterate through all meshes and search for one which is using
 			// this top-level material index
 			// this top-level material index
 			for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
 			for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
 			{
 			{
-				if (ASE::Face::DEFAULT_MATINDEX == pcScene->mMeshes[iMesh]->mMaterialIndex &&
-					iMat == (uintptr_t)pcScene->mMeshes[iMesh]->mColors[3])
+				aiMesh* mesh = pcScene->mMeshes[iMesh];
+				if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
+					iMat == (uintptr_t)mesh->mColors[3])
 				{
 				{
-					pcScene->mMeshes[iMesh]->mMaterialIndex = iNum;
-					pcScene->mMeshes[iMesh]->mColors[3] = NULL;
+					mesh->mMaterialIndex = iNum;
+					mesh->mColors[3] = NULL;
 				}
 				}
 			}
 			}
 			iNum++;
 			iNum++;
 		}
 		}
-		for (unsigned int iSubMat = 0; iSubMat < mParser->m_vMaterials[iMat].avSubMaterials.size();++iSubMat)
+		for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
 		{
 		{
-			if (mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed)
+			ASE::Material& submat = mat.avSubMaterials[iSubMat];
+			if (submat.bNeed)
 			{
 			{
-				ai_assert(NULL != mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].pcInstance);
-				pcScene->mMaterials[iNum] = mParser->m_vMaterials[iMat].
-					avSubMaterials[iSubMat].pcInstance;
+				ai_assert(NULL != submat.pcInstance);
+				pcScene->mMaterials[iNum] = submat.pcInstance;
 
 
-				// store the internal material, too
-				pcIntMaterials[iNum] = &mParser->m_vMaterials[iMat].avSubMaterials[iSubMat];
+				// Store the internal material, too
+				pcIntMaterials[iNum] = &submat;
 
 
-				// iterate through all meshes and search for one which is using
+				// Iterate through all meshes and search for one which is using
 				// this sub-level material index
 				// this sub-level material index
 				for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
 				for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
 				{
 				{
-					if (iSubMat == pcScene->mMeshes[iMesh]->mMaterialIndex &&
-						iMat == (uintptr_t)pcScene->mMeshes[iMesh]->mColors[3])
+					aiMesh* mesh = pcScene->mMeshes[iMesh];
+					if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3])
 					{
 					{
-						pcScene->mMeshes[iMesh]->mMaterialIndex = iNum;
-						pcScene->mMeshes[iMesh]->mColors[3]     = NULL;
+						mesh->mMaterialIndex = iNum;
+						mesh->mColors[3]     = NULL;
 					}
 					}
 				}
 				}
 				iNum++;
 				iNum++;
 			}
 			}
 		}
 		}
 	}
 	}
-	// prepare for the next step
-	for (unsigned int hans = 0; hans < mParser->m_vMaterials.size();++hans)
-		TextureTransform::ApplyScaleNOffset(mParser->m_vMaterials[hans]);
-
-	// now we need to iterate through all meshes,
-	// generating correct texture coordinates and material uv indices
-	for (unsigned int curie = 0; curie < pcScene->mNumMeshes;++curie)
-	{
-		aiMesh* pcMesh = pcScene->mMeshes[curie];
 
 
-		// apply texture coordinate transformations
-		TextureTransform::BakeScaleNOffset(pcMesh,pcIntMaterials[pcMesh->mMaterialIndex]);
-	}
-	for (unsigned int hans = 0; hans < pcScene->mNumMaterials;++hans)
-	{
-		// setup the correct UV indices for each material
-		TextureTransform::SetupMatUVSrc(pcScene->mMaterials[hans],
-			pcIntMaterials[hans]);
-	}
+	// Dekete our temporary array
 	delete[] pcIntMaterials;
 	delete[] pcIntMaterials;
-
-	// finished!
-	return;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Generate normal vectors basing on smoothing groups
 // Generate normal vectors basing on smoothing groups
 bool ASEImporter::GenerateNormals(ASE::Mesh& mesh)
 bool ASEImporter::GenerateNormals(ASE::Mesh& mesh)
@@ -1446,6 +1418,7 @@ bool ASEImporter::GenerateNormals(ASE::Mesh& mesh)
 			}
 			}
 		}
 		}
 	}
 	}
+
 	// The array will be reused
 	// The array will be reused
 	ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
 	ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
 	return false;
 	return false;

+ 31 - 32
code/ASEParser.cpp

@@ -634,6 +634,12 @@ void Parser::ParseLV2MaterialBlock(ASE::Material& mat)
 				mat.mSpecularExponent *= 15;
 				mat.mSpecularExponent *= 15;
 				continue;
 				continue;
 			}
 			}
+			// two-sided material
+			if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) )
+			{
+				mat.mTwoSided = true;
+				continue;
+			}
 			// material shininess strength
 			// material shininess strength
 			if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22))
 			if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22))
 			{
 			{
@@ -1387,7 +1393,7 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh)
 				continue;
 				continue;
 			}
 			}
 			// Number of vertex colors in the mesh
 			// Number of vertex colors in the mesh
-			if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,14))
+			if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15))
 			{
 			{
 				ParseLV4MeshLong(iNumCVertices);
 				ParseLV4MeshLong(iNumCVertices);
 				continue;
 				continue;
@@ -1877,44 +1883,38 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
 {
 {
 	AI_ASE_PARSER_INIT();
 	AI_ASE_PARSER_INIT();
 
 
-	// allocate enough storage for the normals
+	// Allocate enough storage for the normals
 	sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f ));
 	sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f ));
-	unsigned int iIndex = 0, faceIdx = 0xffffffff;
+	unsigned int index, faceIdx = 0xffffffff;
 
 
-	// ********************************************************************
-	// just smooth both vertex and face normals together, so it will still
-	// work if one one of the two is missing. If one of the two is invalid
-	// the result will be partly corrected by this trick.
-	// ********************************************************************
+	// Smooth the vertex and face normals together. The result
+	// will be edgy then, but otherwise everything would be soft ...
 	while (true)
 	while (true)
 	{
 	{
 		if ('*' == *filePtr)
 		if ('*' == *filePtr)
 		{
 		{
 			++filePtr;
 			++filePtr;
-			if (0xffffffff != faceIdx && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17))
+			if (faceIdx != 0xffffffff && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17))
 			{
 			{
 				aiVector3D vNormal;
 				aiVector3D vNormal;
-				ParseLV4MeshFloatTriple(&vNormal.x,iIndex);
-
-				if (iIndex == sMesh.mFaces[faceIdx].mIndices[0])
-				{
-					iIndex = 0;
-				}
-				else if (iIndex == sMesh.mFaces[faceIdx].mIndices[1])
-				{
-					iIndex = 1;
-				}
-				else if (iIndex == sMesh.mFaces[faceIdx].mIndices[2])
-				{
-					iIndex = 2;
-				}
+				ParseLV4MeshFloatTriple(&vNormal.x,index);
+
+				// 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
 				else
 				{
 				{
-					LogWarning("Normal index doesn't fit to face index");
+					DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
 					continue;
 					continue;
 				}
 				}
+
 				// We'll renormalize later
 				// We'll renormalize later
-				sMesh.mNormals[faceIdx*3 + iIndex] += vNormal;
+				sMesh.mNormals[faceIdx*3+index] += vNormal;
 				continue;
 				continue;
 			}
 			}
 			if (TokenMatch(filePtr,"MESH_FACENORMAL",15))
 			if (TokenMatch(filePtr,"MESH_FACENORMAL",15))
@@ -1922,15 +1922,14 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
 				aiVector3D vNormal;
 				aiVector3D vNormal;
 				ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
 				ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
 
 
-				if (iIndex >= sMesh.mFaces.size())
+				if (faceIdx >= sMesh.mFaces.size())
 				{
 				{
-					LogWarning("Face normal index is too large");
-					faceIdx = 0xffffffff;
+					DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section");
 					continue;
 					continue;
 				}
 				}
-				sMesh.mNormals[faceIdx*3]    += vNormal;
-				sMesh.mNormals[faceIdx*3 +1] += vNormal;
-				sMesh.mNormals[faceIdx*3 +2] += vNormal;
+
+				// We'll renormalize later
+				sMesh.mNormals[faceIdx*3] += vNormal;
 				continue;
 				continue;
 			}
 			}
 		}
 		}
@@ -2037,7 +2036,7 @@ void Parser::ParseLV4MeshFace(ASE::Face& out)
 			return;
 			return;
 		}
 		}
 		
 		
-		// parse smoothing groups until we don_t anymore see commas
+		// Parse smoothing groups until we don't anymore see commas
 		// FIX: There needn't always be a value, sad but true
 		// FIX: There needn't always be a value, sad but true
 		while (true)
 		while (true)
 		{
 		{

+ 1 - 6
code/ASEParser.h

@@ -82,6 +82,7 @@ struct Material : public D3DS::Material
 	//! Can we remove this material?
 	//! Can we remove this material?
 	bool bNeed;
 	bool bNeed;
 };
 };
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file face */
 /** Helper structure to represent an ASE file face */
 struct Face : public FaceWithSmoothingGroup
 struct Face : public FaceWithSmoothingGroup
@@ -175,12 +176,6 @@ struct Animation
 		,	mPositionType	(TRACK)
 		,	mPositionType	(TRACK)
 	{}
 	{}
 
 
-	/** ONLY ONE OF THESE SETS IS USED 
-	 * 
-	 *  Bezier and TCB channels are converted to a normal
-	 *  trac later.
-	 */
-
 	//! List of track rotation keyframes
 	//! List of track rotation keyframes
 	std::vector< aiQuatKey > akeyRotations;
 	std::vector< aiQuatKey > akeyRotations;
 
 

+ 2 - 0
code/AssimpPCH.h

@@ -107,12 +107,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifdef ASSIMP_BUILD_BOOST_WORKAROUND
 #ifdef ASSIMP_BUILD_BOOST_WORKAROUND
 
 
 #	include "../include/BoostWorkaround/boost/scoped_ptr.hpp"
 #	include "../include/BoostWorkaround/boost/scoped_ptr.hpp"
+#	include "../include/BoostWorkaround/boost/scoped_array.hpp"
 #	include "../include/BoostWorkaround/boost/format.hpp"
 #	include "../include/BoostWorkaround/boost/format.hpp"
 #	include "../include/BoostWorkaround/boost/common_factor_rt.hpp"
 #	include "../include/BoostWorkaround/boost/common_factor_rt.hpp"
 
 
 #else
 #else
 
 
 #	include <boost/scoped_ptr.hpp>
 #	include <boost/scoped_ptr.hpp>
+#	include <boost/scoped_array.hpp>
 #	include <boost/format.hpp>
 #	include <boost/format.hpp>
 #	include	<boost/math/common_factor_rt.hpp> 
 #	include	<boost/math/common_factor_rt.hpp> 
 
 

+ 1 - 1
code/BaseImporter.cpp

@@ -110,7 +110,7 @@ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler,
 	if (pStream.get() )
 	if (pStream.get() )
 	{
 	{
 		// read 200 characters from the file
 		// read 200 characters from the file
-		boost::scoped_ptr<char> _buffer (new char[searchBytes]);
+		boost::scoped_array<char> _buffer (new char[searchBytes+1 /* for the '\0' */]);
 		char* buffer = _buffer.get();
 		char* buffer = _buffer.get();
 
 
 		unsigned int read = (unsigned int)pStream->Read(buffer,1,searchBytes);
 		unsigned int read = (unsigned int)pStream->Read(buffer,1,searchBytes);

+ 175 - 0
code/ComputeUVMappingProcess.cpp

@@ -0,0 +1,175 @@
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development Team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file GenUVCoords step */
+
+
+#include "AssimpPCH.h"
+#include "ComputeUVMappingProcess.h"
+#include "ProcessHelper.h"
+
+using namespace Assimp;
+
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+ComputeUVMappingProcess::ComputeUVMappingProcess()
+{
+	// nothing to do here
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+ComputeUVMappingProcess::~ComputeUVMappingProcess()
+{
+	// 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;
+}
+
+// ------------------------------------------------------------------------------------------------
+unsigned int ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,aiAxis axis)
+{
+	DefaultLogger::get()->error("Mapping type currently not implemented");
+	return 0;
+}
+
+// ------------------------------------------------------------------------------------------------
+unsigned int ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,aiAxis axis)
+{
+	DefaultLogger::get()->error("Mapping type currently not implemented");
+	return 0;
+}
+
+// ------------------------------------------------------------------------------------------------
+unsigned int ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,aiAxis axis)
+{
+	DefaultLogger::get()->error("Mapping type currently not implemented");
+	return 0;
+}
+
+// ------------------------------------------------------------------------------------------------
+unsigned int ComputeUVMappingProcess::ComputeBoxMapping(aiMesh* mesh)
+{
+	DefaultLogger::get()->error("Mapping type currently not implemented");
+	return 0;
+}
+
+// ------------------------------------------------------------------------------------------------
+void ComputeUVMappingProcess::Execute( aiScene* pScene) 
+{
+	DefaultLogger::get()->debug("GenUVCoordsProcess begin");
+	char buffer[1024];
+
+	/*  Iterate through all materials and search for non-UV mapped textures
+	 */
+	for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
+	{
+		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,%i). Mapping type: %s",
+							TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
+							MappingTypeToString(mapping));
+
+						DefaultLogger::get()->info(buffer);
+					}
+
+					aiAxis axis;
+
+					// 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"))
+						{
+							axis = *((aiAxis*)prop2->mData);
+							break;
+						}
+					}
+
+					/*   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];
+						if (mesh->mMaterialIndex != i) continue;
+
+						switch (mapping)
+						{
+						case aiTextureMapping_SPHERE:
+							ComputeSphereMapping(mesh,axis);
+							break;
+						case aiTextureMapping_CYLINDER:
+							ComputeCylinderMapping(mesh,axis);
+							break;
+						case aiTextureMapping_PLANE:
+							ComputePlaneMapping(mesh,axis);
+							break;
+						case aiTextureMapping_BOX:
+							ComputeBoxMapping(mesh);
+							break;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	DefaultLogger::get()->debug("GenUVCoordsProcess finished");
+}

+ 125 - 0
code/ComputeUVMappingProcess.h

@@ -0,0 +1,125 @@
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development Team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file Defines a post processing step to compute UV coordinates
+  from abstract mappings, such as box or spherical*/
+#ifndef AI_COMPUTEUVMAPPING_H_INC
+#define AI_COMPUTEUVMAPPING_H_INC
+
+#include "BaseProcess.h"
+#include "../include/aiMesh.h"
+
+class ComputeUVMappingTest;
+namespace Assimp
+	{
+
+// ---------------------------------------------------------------------------
+/** ComputeUVMappingProcess - converts special mappings, such as spherical,
+ *  cylindrical or boxed to proper UV coordinates for rendering.
+*/
+class ASSIMP_API ComputeUVMappingProcess : public BaseProcess
+{
+	friend class Importer;
+	friend class ::ComputeUVMappingTest; // grant the unit test full access to us
+
+protected:
+	/** Constructor to be privately used by Importer */
+	ComputeUVMappingProcess();
+
+	/** Destructor, private as well */
+	~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);
+
+protected:
+
+	// -------------------------------------------------------------------
+	/** Computes spherical UV coordinates for a mesh
+	 *
+	 *  @param mesh Mesh to be processed
+	 *  @param axis Main axis
+	 *  @return Index of the newly generated UV channel
+	*/
+	unsigned int ComputeSphereMapping(aiMesh* mesh,aiAxis axis);
+
+	// -------------------------------------------------------------------
+	/** Computes cylindrical UV coordinates for a mesh
+	 *
+	 *  @param mesh Mesh to be processed
+	 *  @param axis Main axis
+	 *  @return Index of the newly generated UV channel
+	*/
+	unsigned int ComputeCylinderMapping(aiMesh* mesh,aiAxis axis);
+
+	// -------------------------------------------------------------------
+	/** Computes planar UV coordinates for a mesh
+	 *
+	 *  @param mesh Mesh to be processed
+	 *  @param axis Main axis
+	 *  @return Index of the newly generated UV channel
+	*/
+	unsigned int ComputePlaneMapping(aiMesh* mesh,aiAxis axis);
+
+	// -------------------------------------------------------------------
+	/** Computes cubic UV coordinates for a mesh
+	 *
+	 *  @param mesh Mesh to be processed
+	 *  @return Index of the newly generated UV channel
+	*/
+	unsigned int ComputeBoxMapping(aiMesh* mesh);
+};
+
+} // end of namespace Assimp
+
+#endif // AI_COMPUTEUVMAPPING_H_INC

+ 23 - 0
code/ConvertToLHProcess.cpp

@@ -141,6 +141,10 @@ void ConvertToLHProcess::Execute( aiScene* pScene)
 	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
 	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
 		ProcessMesh( pScene->mMeshes[a]);
 		ProcessMesh( pScene->mMeshes[a]);
 
 
+	// process all materials - we need to adjust UV transformations
+	for( unsigned int a = 0; a < pScene->mNumMaterials; a++)
+		ProcessMaterial( pScene->mMaterials[a]);
+
 	// transform all animation channels affecting the root node as well
 	// transform all animation channels affecting the root node as well
 	for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
 	for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
 	{
 	{
@@ -155,6 +159,25 @@ void ConvertToLHProcess::Execute( aiScene* pScene)
 	DefaultLogger::get()->debug("ConvertToLHProcess finished");
 	DefaultLogger::get()->debug("ConvertToLHProcess finished");
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Converts a single material to left handed coordinates. 
+void ConvertToLHProcess::ProcessMaterial (aiMaterial* mat)
+{
+	for (unsigned int a = 0; a < mat->mNumProperties;++a)
+	{
+		aiMaterialProperty* prop = mat->mProperties[a];
+		if (!::strcmp( prop->mKey.data, "$tex.uvtrafo"))
+		{
+			ai_assert( prop->mDataLength >= sizeof(aiUVTransform));
+			aiUVTransform* uv = (aiUVTransform*)prop->mData;
+
+			// just flip it, that's everything
+			uv->mTranslation.y *= -1.f;
+			uv->mRotation *= -1.f;
+		}
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Converts a single mesh to left handed coordinates. 
 // Converts a single mesh to left handed coordinates. 
 void ConvertToLHProcess::ProcessMesh( aiMesh* pMesh)
 void ConvertToLHProcess::ProcessMesh( aiMesh* pMesh)

+ 7 - 0
code/ConvertToLHProcess.h

@@ -108,6 +108,13 @@ protected:
 	 */
 	 */
 	void ProcessMesh( aiMesh* pMesh);
 	void ProcessMesh( aiMesh* pMesh);
 
 
+	// -------------------------------------------------------------------
+	/** Converts a single material to left handed coordinates. 
+	 * This simply means all UV offsets are inverted.
+	 * @param mat The material to convert.
+	 */
+	void ProcessMaterial (aiMaterial* mat);
+
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Converts the given animation to LH coordinates. 
 	/** Converts the given animation to LH coordinates. 
 	 * The rotation and translation keys are transformed, the scale keys
 	 * The rotation and translation keys are transformed, the scale keys

+ 1 - 0
code/FindDegenerates.cpp

@@ -108,6 +108,7 @@ void FindDegeneratesProcess::Execute( aiScene* pScene)
 						// application attemps to access this data.
 						// application attemps to access this data.
 						face.mIndices[face.mNumIndices] = 0xdeadbeef;
 						face.mIndices[face.mNumIndices] = 0xdeadbeef;
 
 
+
 						if(first)
 						if(first)
 						{
 						{
 							++deg;
 							++deg;

+ 19 - 11
code/FindInvalidDataProcess.cpp

@@ -284,7 +284,16 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
 int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 {
 {
 	bool ret = false;
 	bool ret = false;
-	std::vector<bool> dirtyMask;
+	std::vector<bool> dirtyMask(pMesh->mNumVertices,true);
+
+	// Ignore elements that are not referenced by vertices.
+	// (they are, for example, caused by the FindDegenerates step)
+	for (unsigned int m = 0; m < pMesh->mNumFaces;++m)
+	{
+		const aiFace& f = pMesh->mFaces[m];
+		for (unsigned int i = 0; i < f.mNumIndices;++i)
+			dirtyMask[f.mIndices[i]] = false;
+	}
 
 
 	// process vertex positions
 	// process vertex positions
 	if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask))
 	if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask))
@@ -311,9 +320,7 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 	// -- we don't validate vertex colors, it's difficult to say whether
 	// -- we don't validate vertex colors, it's difficult to say whether
 	// they are invalid or not.
 	// they are invalid or not.
 
 
-	// normals and tangents are undefined for point and line faces.
-	// we generate a small lookup table in which we mark all
-	// indices into the normals/tangents array that MAY be invalid
+	// Normals and tangents are undefined for point and line faces.
 	if (pMesh->mNormals || pMesh->mTangents)
 	if (pMesh->mNormals || pMesh->mTangents)
 	{
 	{
 		if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
 		if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
@@ -322,8 +329,7 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 			if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
 			if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
 				aiPrimitiveType_POLYGON  & pMesh->mPrimitiveTypes)
 				aiPrimitiveType_POLYGON  & pMesh->mPrimitiveTypes)
 			{
 			{
-				// we need the lookup table
-				dirtyMask.resize(pMesh->mNumVertices,false);
+				// We need to update the lookup-table
 				for (unsigned int m = 0; m < pMesh->mNumFaces;++m)
 				for (unsigned int m = 0; m < pMesh->mNumFaces;++m)
 				{
 				{
 					const aiFace& f = pMesh->mFaces[m];
 					const aiFace& f = pMesh->mFaces[m];
@@ -334,27 +340,29 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 					else if (1 == f.mNumIndices)dirtyMask[f.mIndices[0]] = true;
 					else if (1 == f.mNumIndices)dirtyMask[f.mIndices[0]] = true;
 				}
 				}
 			}
 			}
+			// Normals, tangents and bitangents are undefined for
+			// the whole mesh (and should not even be there)
 			else return ret;
 			else return ret;
 		}
 		}
 
 
-		// process mesh normals
+		// Process mesh normals
 		if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices,
 		if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices,
 			"normals",dirtyMask,true,false))
 			"normals",dirtyMask,true,false))
 			ret = true;
 			ret = true;
 
 
-		// process mesh tangents
+		// Process mesh tangents
 		if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,
 		if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,
 			"tangents",dirtyMask))
 			"tangents",dirtyMask))
 		{
 		{
-			delete[] pMesh->mBitangents; pMesh->mBitangents = NULL;
+			delete[] pMesh->mTangents; pMesh->mTangents = NULL;
 			ret = true;
 			ret = true;
 		}
 		}
 
 
-		// process mesh bitangents
+		// Process mesh bitangents
 		if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,
 		if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,
 			"bitangents",dirtyMask))
 			"bitangents",dirtyMask))
 		{
 		{
-			delete[] pMesh->mTangents; pMesh->mTangents = NULL;
+			delete[] pMesh->mBitangents; pMesh->mBitangents = NULL;
 			ret = true;
 			ret = true;
 		}
 		}
 	}
 	}

+ 1 - 0
code/Hash.h

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // http://www.azillionmonkeys.com/qed/hash.html
 // http://www.azillionmonkeys.com/qed/hash.html
 // (incremental version of the hashing function)
 // (incremental version of the hashing function)
 // (stdint.h should have been been included here)
 // (stdint.h should have been been included here)
+// ------------------------------------------------------------------------------------------------
 #undef get16bits
 #undef get16bits
 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
   || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
   || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)

+ 41 - 19
code/IRRMeshLoader.cpp

@@ -429,20 +429,6 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
 					// lightmap settings to the last texture.
 					// lightmap settings to the last texture.
 					if (cnt && matFlags & AI_IRRMESH_MAT_lightmap)
 					if (cnt && matFlags & AI_IRRMESH_MAT_lightmap)
 					{
 					{
-						static const char* PropArray[4] =
-						{
-							AI_MATKEY_TEXBLEND_DIFFUSE(0),
-							AI_MATKEY_TEXBLEND_DIFFUSE(1),
-							AI_MATKEY_TEXBLEND_DIFFUSE(2),
-							AI_MATKEY_TEXBLEND_DIFFUSE(3)
-						};
-						static const char* PropArray2[4] =
-						{
-							AI_MATKEY_TEXOP_DIFFUSE(0),
-							AI_MATKEY_TEXOP_DIFFUSE(1),
-							AI_MATKEY_TEXOP_DIFFUSE(2),
-							AI_MATKEY_TEXOP_DIFFUSE(3)
-						};
 						float f = 1.f;
 						float f = 1.f;
 
 
 						// Additive lightmap?
 						// Additive lightmap?
@@ -460,8 +446,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
 						{
 						{
 							f = 4.f;
 							f = 4.f;
 						}
 						}
-						mat->AddProperty( &f, 1, PropArray  [cnt-1]);
-						mat->AddProperty( &op,1, PropArray2 [cnt-1]);
+						mat->AddProperty( &f, 1, AI_MATKEY_TEXBLEND_DIFFUSE(cnt-1));
+						mat->AddProperty( &op,1, AI_MATKEY_TEXOP_DIFFUSE(cnt-1));
 					}
 					}
 
 
 					return mat;
 					return mat;
@@ -600,13 +586,28 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
 				if (curMat)
 				if (curMat)
 				{
 				{
 					DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please");
 					DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please");
-					delete curMat;
+					delete curMat;curMat = NULL;
 				}
 				}
 				curMat = ParseMaterial(curMatFlags);
 				curMat = ParseMaterial(curMatFlags);
 			}
 			}
 			/* no else here! */ if (!ASSIMP_stricmp(reader->getNodeName(),"vertices"))
 			/* no else here! */ if (!ASSIMP_stricmp(reader->getNodeName(),"vertices"))
 			{
 			{
 				int num = reader->getAttributeValueAsInt("vertexCount");
 				int num = reader->getAttributeValueAsInt("vertexCount");
+
+				if (!num)
+				{
+					// This is possible ... remove the mesh from the list
+					// and skip further reading
+
+					DefaultLogger::get()->warn("IRRMESH: Found mesh with zero vertices");
+
+					delete curMat;curMat = NULL;
+
+					curMesh = NULL;
+					textMeaning = 0;
+					continue;
+				}
+
 				curVertices.reserve (num);
 				curVertices.reserve (num);
 				curNormals.reserve  (num);
 				curNormals.reserve  (num);
 				curColors.reserve   (num);
 				curColors.reserve   (num);
@@ -648,6 +649,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
 				}
 				}
 				else if (ASSIMP_stricmp("standard", t))
 				else if (ASSIMP_stricmp("standard", t))
 				{
 				{
+					delete curMat;
 					DefaultLogger::get()->warn("IRRMESH: Unknown vertex format");
 					DefaultLogger::get()->warn("IRRMESH: Unknown vertex format");
 				}
 				}
 				else vertexFormat = 0;
 				else vertexFormat = 0;
@@ -655,8 +657,11 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
 			}
 			}
 			else if (!ASSIMP_stricmp(reader->getNodeName(),"indices"))
 			else if (!ASSIMP_stricmp(reader->getNodeName(),"indices"))
 			{
 			{
-				if (curVertices.empty())
+				if (curVertices.empty() && curMat)
+				{
+					delete curMat;
 					throw new ImportErrorException("IRRMESH: indices must come after vertices");
 					throw new ImportErrorException("IRRMESH: indices must come after vertices");
+				}
 
 
 				textMeaning = 2;
 				textMeaning = 2;
 
 
@@ -665,6 +670,23 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
 
 
 				// allocate storage for all faces
 				// allocate storage for all faces
 				curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount");
 				curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount");
+				if (!curMesh->mNumVertices)
+				{
+					// This is possible ... remove the mesh from the list
+					// and skip further reading
+
+					DefaultLogger::get()->warn("IRRMESH: Found mesh with zero indices");
+
+					// mesh - away
+					delete curMesh; curMesh = NULL;
+
+					// material - away
+					delete curMat;curMat = NULL;
+
+					textMeaning = 0;
+					continue;
+				}
+
 				if (curMesh->mNumVertices % 3)
 				if (curMesh->mNumVertices % 3)
 				{
 				{
 					DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3");
 					DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3");
@@ -888,7 +910,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
 		};
 		};
 	}
 	}
 
 
-	// end of the last buffer. A material and a mesh should be there
+	// End of the last buffer. A material and a mesh should be there
 	if (curMat || curMesh)
 	if (curMat || curMesh)
 	{
 	{
 		if ( !curMat || !curMesh)
 		if ( !curMat || !curMesh)

+ 32 - 7
code/Importer.cpp

@@ -189,6 +189,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_BUILD_NO_SORTBYPTYPE_PROCESS
 #ifndef AI_BUILD_NO_SORTBYPTYPE_PROCESS
 #	include "SortByPTypeProcess.h"
 #	include "SortByPTypeProcess.h"
 #endif
 #endif
+#ifndef AI_BUILD_NO_GENUVCOORDS_PROCESS
+#	include "ComputeUVMappingProcess.h"
+#endif
+#ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
+#	include "TextureTransform.h"
+#endif
+
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
@@ -290,7 +297,7 @@ Importer::Importer() :
 	mImporter.push_back( new ColladaLoader());
 	mImporter.push_back( new ColladaLoader());
 #endif
 #endif
 
 
-	// add an instance of each post processing step here in the order 
+	// Add an instance of each post processing step here in the order 
 	// of sequence it is executed. steps that are added here are not validated -
 	// of sequence it is executed. steps that are added here are not validated -
 	// as RegisterPPStep() does - all dependencies must be there.
 	// as RegisterPPStep() does - all dependencies must be there.
 	mPostProcessingSteps.reserve(25);
 	mPostProcessingSteps.reserve(25);
@@ -310,6 +317,17 @@ Importer::Importer() :
 #endif
 #endif
 
 
 
 
+	
+#ifndef AI_BUILD_NO_GENUVCOORDS_PROCESS
+	mPostProcessingSteps.push_back( new ComputeUVMappingProcess());
+#endif
+#ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
+	mPostProcessingSteps.push_back( new TextureTransformStep());
+#endif
+
+
+
+
 #if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
 #if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
 	mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
 	mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
 #endif
 #endif
@@ -371,6 +389,9 @@ Importer::Importer() :
 	mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess());
 	mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess());
 #endif
 #endif
 
 
+
+
+
 	// allocate a SharedPostProcessInfo object and store pointers to it
 	// allocate a SharedPostProcessInfo object and store pointers to it
 	// in all post-process steps in the list.
 	// in all post-process steps in the list.
 	mPPShared = new SharedPostProcessInfo();
 	mPPShared = new SharedPostProcessInfo();
@@ -412,7 +433,9 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
 {
 {
 	ai_assert(NULL != pImp);
 	ai_assert(NULL != pImp);
 
 
-	// check whether we would have two loaders for the same file extension now
+	// Check whether we would have two loaders for the same file extension now
+	// This is absolutely OK, but we should warn the developer of the new
+	// loader that his code will propably never be called.
 
 
 	std::string st;
 	std::string st;
 	pImp->GetExtensionList(st);
 	pImp->GetExtensionList(st);
@@ -423,15 +446,14 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
 	{
 	{
 		if (IsExtensionSupported(std::string(sz)))
 		if (IsExtensionSupported(std::string(sz)))
 		{
 		{
-			DefaultLogger::get()->error(std::string( "The file extension " ) + sz + " is already in use");
-			return AI_FAILURE;
+			DefaultLogger::get()->warn(std::string( "The file extension " ) + sz + " is already in use");
 		}
 		}
 		sz = ::strtok(NULL,";");
 		sz = ::strtok(NULL,";");
 	}
 	}
 #endif
 #endif
 
 
 	// add the loader
 	// add the loader
-	this->mImporter.push_back(pImp);
+	mImporter.push_back(pImp);
 	DefaultLogger::get()->info("Registering custom importer: " + st);
 	DefaultLogger::get()->info("Registering custom importer: " + st);
 	return AI_SUCCESS;
 	return AI_SUCCESS;
 }
 }
@@ -729,7 +751,7 @@ const std::string& Importer::GetPropertyString(const char* szName,
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
+inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
 {
 {
 	iScene += sizeof(aiNode);
 	iScene += sizeof(aiNode);
 	iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
 	iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
@@ -816,6 +838,10 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
 	}
 	}
 	in.total += in.animations;
 	in.total += in.animations;
 
 
+	// add all cameras and all lights
+	in.total += in.cameras = sizeof(aiCamera) *  mScene->mNumCameras;
+	in.total += in.lights  = sizeof(aiLight)  *  mScene->mNumLights;
+
 	// add all nodes
 	// add all nodes
 	AddNodeWeight(in.nodes,mScene->mRootNode);
 	AddNodeWeight(in.nodes,mScene->mRootNode);
 	in.total += in.nodes;
 	in.total += in.nodes;
@@ -832,6 +858,5 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
 		}
 		}
 	}
 	}
 	in.total += in.materials;
 	in.total += in.materials;
-	return;
 }
 }
 
 

+ 1 - 4
code/LWOBLoader.cpp

@@ -45,11 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "AssimpPCH.h"
 #include "AssimpPCH.h"
 
 
-// internal headers
+// Internal headers
 #include "LWOLoader.h"
 #include "LWOLoader.h"
-#include "MaterialSystem.h"
-#include "ByteSwap.h"
-
 using namespace Assimp;
 using namespace Assimp;
 
 
 
 

+ 28 - 9
code/LWOFileData.h

@@ -62,6 +62,7 @@ namespace LWO {
 
 
 #define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L','W','O','B')
 #define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L','W','O','B')
 #define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L','W','O','2')
 #define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L','W','O','2')
+#define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L','X','O','B')
 
 
 // chunks specific to the LWOB format
 // chunks specific to the LWOB format
 #define AI_LWO_SRFS  AI_IFF_FOURCC('S','R','F','S')
 #define AI_LWO_SRFS  AI_IFF_FOURCC('S','R','F','S')
@@ -178,6 +179,7 @@ namespace LWO {
 #define AI_LWO_AVAL  AI_IFF_FOURCC('A','V','A','L')
 #define AI_LWO_AVAL  AI_IFF_FOURCC('A','V','A','L')
 #define AI_LWO_GVAL  AI_IFF_FOURCC('G','V','A','L')
 #define AI_LWO_GVAL  AI_IFF_FOURCC('G','V','A','L')
 #define AI_LWO_BLOK  AI_IFF_FOURCC('B','L','O','K')
 #define AI_LWO_BLOK  AI_IFF_FOURCC('B','L','O','K')
+#define AI_LWO_VCOL  AI_IFF_FOURCC('V','C','O','L')
 
 
 /* texture layer */
 /* texture layer */
 #define AI_LWO_TYPE  AI_IFF_FOURCC('T','Y','P','E')
 #define AI_LWO_TYPE  AI_IFF_FOURCC('T','Y','P','E')
@@ -236,10 +238,13 @@ namespace LWO {
 
 
 /* VMAP types */
 /* VMAP types */
 #define AI_LWO_TXUV  AI_IFF_FOURCC('T','X','U','V')
 #define AI_LWO_TXUV  AI_IFF_FOURCC('T','X','U','V')
-#define AI_LWO_RGB   AI_IFF_FOURCC(' ','R','G','B')
+#define AI_LWO_RGB   AI_IFF_FOURCC('R','G','B',' ')
 #define AI_LWO_RGBA  AI_IFF_FOURCC('R','G','B','A')
 #define AI_LWO_RGBA  AI_IFF_FOURCC('R','G','B','A')
 #define AI_LWO_WGHT  AI_IFF_FOURCC('W','G','H','T')
 #define AI_LWO_WGHT  AI_IFF_FOURCC('W','G','H','T')
 
 
+// MODO extension - per-vertex normal vectors
+#define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M')
+
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a face in a LWO file
 /** \brief Data structure for a face in a LWO file
@@ -318,15 +323,11 @@ struct VColorChannel : public VMapEntry
 
 
 		register unsigned int m = num*dims;
 		register unsigned int m = num*dims;
 		rawData.reserve(m + (m>>2u)); // 25% as  extra storage for VMADs
 		rawData.reserve(m + (m>>2u)); // 25% as  extra storage for VMADs
-		rawData.resize(m,0.f);
+		rawData.resize(m);
+
+		for (aiColor4D* p = (aiColor4D*)&rawData[0]; p < (aiColor4D*)&rawData[m-1]; ++p)
+			*p = aiColor4D();
 
 
-		for (std::vector<float>::iterator it = rawData.begin(), end = rawData.end();
-			 it != end;++it )	
-		{
-			for (unsigned int i = 0; i< 3;++i,++it)
-				*it = 0.f;
-			*it = 1.f;
-		}
 		abAssigned.resize(num,false);
 		abAssigned.resize(num,false);
 	}
 	}
 };
 };
@@ -351,6 +352,15 @@ struct WeightChannel : public VMapEntry
 	{}
 	{}
 };
 };
 
 
+// ---------------------------------------------------------------------------
+/** \brief Represents a vertex-normals channel (MODO extension)
+ */
+struct NormalChannel : public VMapEntry
+{
+	NormalChannel()
+		: VMapEntry(3)
+	{}
+};
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a LWO file texture
 /** \brief Data structure for a LWO file texture
@@ -515,8 +525,10 @@ struct Surface
 		, mColorHighlights		(0.f)
 		, mColorHighlights		(0.f)
 		, mMaximumSmoothAngle	(0.f) // 0 == not specified, no smoothing
 		, mMaximumSmoothAngle	(0.f) // 0 == not specified, no smoothing
 		, mVCMap				("")
 		, mVCMap				("")
+		, mVCMapType			(AI_LWO_RGBA)
 		, mIOR					(1.f) // vakuum
 		, mIOR					(1.f) // vakuum
 		, mBumpIntensity		(1.f)
 		, mBumpIntensity		(1.f)
+		, mWireframe			(false)
 	{}
 	{}
 
 
 	//! Name of the surface
 	//! Name of the surface
@@ -537,6 +549,7 @@ struct Surface
 
 
 	//! Vertex color map to be used to color the surface
 	//! Vertex color map to be used to color the surface
 	std::string mVCMap;
 	std::string mVCMap;
+	uint32_t mVCMapType;
 
 
 	//! Names of the special shaders to be applied to the surface
 	//! Names of the special shaders to be applied to the surface
 	ShaderList mShaders;
 	ShaderList mShaders;
@@ -554,6 +567,9 @@ struct Surface
 
 
 	//! Bump intensity scaling
 	//! Bump intensity scaling
 	float mBumpIntensity;
 	float mBumpIntensity;
+
+	//! Wireframe flag
+	bool mWireframe;
 };
 };
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
@@ -606,6 +622,9 @@ struct Layer
 	/** UV channel list from the file */
 	/** UV channel list from the file */
 	UVChannelList mUVChannels;
 	UVChannelList mUVChannels;
 
 
+	/** Normal vector channel from the file */
+	NormalChannel mNormals;
+
 	/** Temporary face list from the file*/
 	/** Temporary face list from the file*/
 	FaceList mFaces;
 	FaceList mFaces;
 
 

+ 103 - 46
code/LWOLoader.cpp

@@ -79,11 +79,10 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
 	if (extension.length() < 4)return false;
 	if (extension.length() < 4)return false;
 	if (extension[0] != '.')return false;
 	if (extension[0] != '.')return false;
 
 
-	if (extension[1] != 'l' && extension[1] != 'L')return false;
-	if (extension[2] != 'w' && extension[2] != 'W')return false;
-	if (extension[3] != 'o' && extension[3] != 'O')return false;
-
-	return true;
+	return ! (extension[1] != 'l' && extension[1] != 'L' ||
+			  extension[2] != 'w' && extension[2] != 'W' &&
+			  extension[2] != 'x' && extension[2] != 'X' ||
+			  extension[3] != 'o' && extension[3] != 'O');
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -151,11 +150,29 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 		LoadLWOBFile();
 		LoadLWOBFile();
 	}
 	}
 
 
-	// new lightwave format
+	// New lightwave format
 	else if (AI_LWO_FOURCC_LWO2 == fileType)
 	else if (AI_LWO_FOURCC_LWO2 == fileType)
 	{
 	{
 		DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)");
 		DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)");
+	}
+	// MODO file format
+	else if (AI_LWO_FOURCC_LXOB == fileType)
+	{
+		DefaultLogger::get()->info("LWO file format: LXOB (Modo)");
+	}
+	// we don't know this format
+	else 
+	{
+		char szBuff[5];
+		szBuff[0] = (char)(fileType >> 24u);
+		szBuff[1] = (char)(fileType >> 16u);
+		szBuff[2] = (char)(fileType >> 8u);
+		szBuff[3] = (char)(fileType);
+		throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff);
+	}
 
 
+	if (AI_LWO_FOURCC_LWOB != fileType)
+	{
 		mIsLWO2 = true;
 		mIsLWO2 = true;
 		LoadLWO2File();
 		LoadLWO2File();
 
 
@@ -172,17 +189,6 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 		}
 		}
 	}
 	}
 
 
-	// we don't know this format
-	else 
-	{
-		char szBuff[5];
-		szBuff[0] = (char)(fileType >> 24u);
-		szBuff[1] = (char)(fileType >> 16u);
-		szBuff[2] = (char)(fileType >> 8u);
-		szBuff[3] = (char)(fileType);
-		throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff);
-	}
-
 	// now, as we have loaded all data, we can resolve cross-referenced tags and clips
 	// now, as we have loaded all data, we can resolve cross-referenced tags and clips
 	ResolveTags();
 	ResolveTags();
 	ResolveClips();
 	ResolveClips();
@@ -249,7 +255,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 					mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
 					mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
 				}
 				}
 
 
-				aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+				aiVector3D *nrm = NULL, * pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
 				aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
 				aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
 				mesh->mMaterialIndex = i;
 				mesh->mMaterialIndex = i;
 
 
@@ -276,8 +282,12 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 					pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices];
 					pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices];
 
 
 					// LightWave doesn't support more than 2 UV components
 					// LightWave doesn't support more than 2 UV components
+					// so we can directly setup this value
 					mesh->mNumUVComponents[0] = 2;
 					mesh->mNumUVComponents[0] = 2;
 				}
 				}
+
+				if (layer.mNormals.name.length())
+					nrm = mesh->mNormals = new aiVector3D[mesh->mNumVertices];
 		
 		
 				aiColor4D* pvVC[AI_MAX_NUMBER_OF_COLOR_SETS];
 				aiColor4D* pvVC[AI_MAX_NUMBER_OF_COLOR_SETS];
 				for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui)	
 				for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui)	
@@ -320,11 +330,24 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 							pp++;
 							pp++;
 						}
 						}
 
 
+						// process normals (MODO extension)
+						if (nrm)
+						{
+							*nrm++ = ((aiVector3D*)&layer.mNormals.rawData[0])[idx];
+						}
+
 						// process vertex colors
 						// process vertex colors
 						for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w)	
 						for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w)	
 						{
 						{
 							if (0xffffffff == vVColorIndices[w])break;
 							if (0xffffffff == vVColorIndices[w])break;
-							*(pvVC[w])++ = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
+							*pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
+
+							// If a RGB color map is explicitly requested delete the
+							// alpha channel - it could theoretically be != 1.
+							if(_mSurfaces[i].mVCMapType == AI_LWO_RGB)
+								pvVC[w]->a = 1.f;
+
+							pvVC[w]++;
 						}
 						}
 
 
 #if 0
 #if 0
@@ -343,16 +366,19 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 					pf++;
 					pf++;
 				}
 				}
 
 
-				// compute normal vectors for the mesh - we can't use our GenSmoothNormal-
-				// Step here since it wouldn't handle smoothing groups correctly for LWO.
-				// So we use a separate implementation.
-				ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
-
+				if (!mesh->mNormals)
+				{
+					// Compute normal vectors for the mesh - we can't use our GenSmoothNormal-
+					// Step here since it wouldn't handle smoothing groups correctly for LWO.
+					// So we use a separate implementation.
+					ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
+				}
+				else DefaultLogger::get()->debug("LWO2: No need to compute normals, they're already there");
 				++p;
 				++p;
 			}
 			}
 		}
 		}
 
 
-		// generate nodes to render the mesh. Store the parent index
+		// Generate nodes to render the mesh. Store the parent index
 		// in the mParent member of the nodes
 		// in the mParent member of the nodes
 		aiNode* pcNode = new aiNode();
 		aiNode* pcNode = new aiNode();
 		apcNodes.push_back(pcNode);
 		apcNodes.push_back(pcNode);
@@ -367,7 +393,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 	if (apcNodes.empty() || apcMeshes.empty())
 	if (apcNodes.empty() || apcMeshes.empty())
 		throw new ImportErrorException("LWO: No meshes loaded");
 		throw new ImportErrorException("LWO: No meshes loaded");
 
 
-	// the RemoveRedundantMaterials step will clean this up later
+	// The RemoveRedundantMaterials step will clean this up later
 	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
 	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
 	for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat)
 	for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat)
 	{
 	{
@@ -510,7 +536,6 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>&
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void LWOImporter::AddChildren(aiNode* node, uintptr_t parent, std::vector<aiNode*>& apcNodes)
 void LWOImporter::AddChildren(aiNode* node, uintptr_t parent, std::vector<aiNode*>& apcNodes)
 {
 {
-	parent -= 1;
 	for (uintptr_t i  = 0; i < (uintptr_t)apcNodes.size();++i)
 	for (uintptr_t i  = 0; i < (uintptr_t)apcNodes.size();++i)
 	{
 	{
 		if (i == parent)continue;
 		if (i == parent)continue;
@@ -706,10 +731,15 @@ void LWOImporter::LoadLWO2Polygons(unsigned int length)
 	LE_NCONST uint16_t* const end	= (LE_NCONST uint16_t*)(mFileBuffer+length);
 	LE_NCONST uint16_t* const end	= (LE_NCONST uint16_t*)(mFileBuffer+length);
 	uint32_t type = GetU4();
 	uint32_t type = GetU4();
 
 
-	if (type != AI_LWO_FACE)
+	// Determine the type of the polygons
+	switch (type)
 	{
 	{
-		DefaultLogger::get()->warn("LWO2: Only POLS.FACE chunks are supported.");
-		return;
+	case  AI_LWO_PTCH:
+	case  AI_LWO_FACE:
+
+		break;
+	default:
+		DefaultLogger::get()->warn("LWO2: Unsupported polygon type (PTCH and FACE are supported)");
 	}
 	}
 
 
 	// first find out how many faces and vertices we'll finally need
 	// first find out how many faces and vertices we'll finally need
@@ -829,19 +859,26 @@ VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPol
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <class T>
 template <class T>
-void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx)
+inline void CreateNewEntry(T& chan, unsigned int srcIdx)
+{
+	if (!chan.name.length())return;
+
+	chan.abAssigned[srcIdx] = true;
+	chan.abAssigned.resize(chan.abAssigned.size()+1,false);
+
+	for (unsigned int a = 0; a < chan.dims;++a)
+		chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]);
+}
+
+// ------------------------------------------------------------------------------------------------
+template <class T>
+inline void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx)
 {
 {
 	for (typename std::vector< T >::iterator 
 	for (typename std::vector< T >::iterator 
 		it =  list.begin(), end = list.end();
 		it =  list.begin(), end = list.end();
 		it != end;++it)
 		it != end;++it)
 	{
 	{
-		T& chan = *it;
-
-		chan.abAssigned[srcIdx] = true;
-		chan.abAssigned.resize(chan.abAssigned.size()+1,false);
-
-		for (unsigned int a = 0; a < chan.dims;++a)
-			chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]);
+		CreateNewEntry( *it, srcIdx );
 	}
 	}
 }
 }
 
 
@@ -911,7 +948,24 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
 		}
 		}
 		base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
 		base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
 		break;
 		break;
-	default: return;
+
+	case AI_LWO_MODO_NORM:
+
+		/*  This is a non-standard extension chunk used by Luxology's MODO.
+		 *  It stores per-vertex normals. This VMAP exists just once, has
+		 *  3 dimensions and is btw extremely beautiful.
+		 */
+		if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length())
+			return;
+
+		DefaultLogger::get()->info("Non-standard extension: MODO VMAP.NORM.vert_normals");
+		
+		mCurLayer->mNormals.name = name;
+		base = & mCurLayer->mNormals;
+		break;
+
+	default: 
+		return;
 	};
 	};
 	base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
 	base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
 
 
@@ -946,20 +1000,22 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
 				if (polyIdx >= numFaces)
 				if (polyIdx >= numFaces)
 				{
 				{
 					DefaultLogger::get()->warn("LWO2: VMAD polygon index is out of range");
 					DefaultLogger::get()->warn("LWO2: VMAD polygon index is out of range");
-					mFileBuffer += base->dims*4;continue;
+					mFileBuffer += base->dims*4;
+					continue;
 				}
 				}
 
 
 				LWO::Face& src = list[polyIdx];
 				LWO::Face& src = list[polyIdx];
-				refList.resize(refList.size()+src.mNumIndices, 0xffffffff);
 
 
-				// generate new vertex positions
+				// generate a new unique vertex for the corresponding index - but only
+				// if we can find the index in the face
 				for (unsigned int i = 0; i < src.mNumIndices;++i)
 				for (unsigned int i = 0; i < src.mNumIndices;++i)
 				{
 				{
 					register unsigned int srcIdx = src.mIndices[i];
 					register unsigned int srcIdx = src.mIndices[i];
-					if (idx == srcIdx)
-					{
-						idx = (unsigned int)pointList.size();
-					}
+					if (idx != srcIdx)continue;
+
+					refList.resize(refList.size()+1, 0xffffffff);
+						
+					idx = (unsigned int)pointList.size();
 					src.mIndices[i] = (unsigned int)pointList.size();
 					src.mIndices[i] = (unsigned int)pointList.size();
 
 
 					// store the index of the new vertex in the old vertex
 					// store the index of the new vertex in the old vertex
@@ -971,6 +1027,7 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
 					CreateNewEntry(mCurLayer->mVColorChannels,	srcIdx );
 					CreateNewEntry(mCurLayer->mVColorChannels,	srcIdx );
 					CreateNewEntry(mCurLayer->mUVChannels,		srcIdx );
 					CreateNewEntry(mCurLayer->mUVChannels,		srcIdx );
 					CreateNewEntry(mCurLayer->mWeightChannels,	srcIdx );
 					CreateNewEntry(mCurLayer->mWeightChannels,	srcIdx );
+					CreateNewEntry(mCurLayer->mNormals,	srcIdx );
 				}
 				}
 			}
 			}
 		}
 		}

+ 3 - 5
code/LWOLoader.h

@@ -100,7 +100,7 @@ protected:
 	 */
 	 */
 	void GetExtensionList(std::string& append)
 	void GetExtensionList(std::string& append)
 	{
 	{
-		append.append("*.lwo");
+		append.append("*.lwo;*.lxo");
 	}
 	}
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
@@ -257,12 +257,10 @@ private:
 	 *
 	 *
 	 *  @param pcMat Output material
 	 *  @param pcMat Output material
 	 *  @param in Input texture list
 	 *  @param in Input texture list
-	 *  @param type Type identifier of the texture list. This is the string
-	 *    that appears in the middle of all material keys - e.g. "diffuse",
-	 *    "shininess", "glossiness" or "specular". 
+	 *  @param type Type identifier of the texture list
 	*/
 	*/
 	bool HandleTextures(MaterialHelper* pcMat, const TextureList& in,
 	bool HandleTextures(MaterialHelper* pcMat, const TextureList& in,
-		const char* type);
+		aiTextureType type);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Adjust a texture path
 	/** Adjust a texture path

+ 126 - 40
code/LWOMaterial.cpp

@@ -59,16 +59,20 @@ T lerp(const T& one, const T& two, float val)
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
+// Convert a lightwave mapping mode to our's
 inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
 inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
 {
 {
 	switch (in)
 	switch (in)
 	{	
 	{	
 		case LWO::Texture::REPEAT:
 		case LWO::Texture::REPEAT:
 			return aiTextureMapMode_Wrap;
 			return aiTextureMapMode_Wrap;
+
 		case LWO::Texture::MIRROR:
 		case LWO::Texture::MIRROR:
 			return aiTextureMapMode_Mirror;
 			return aiTextureMapMode_Mirror;
+
 		case LWO::Texture::RESET:
 		case LWO::Texture::RESET:
 			DefaultLogger::get()->warn("LWO2: Unsupported texture map mode: RESET");
 			DefaultLogger::get()->warn("LWO2: Unsupported texture map mode: RESET");
+
 			// fall though here
 			// fall though here
 		case LWO::Texture::EDGE:
 		case LWO::Texture::EDGE:
 			return aiTextureMapMode_Clamp;
 			return aiTextureMapMode_Clamp;
@@ -77,23 +81,67 @@ inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, const char* type)
+bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, aiTextureType type)
 {
 {
-	ai_assert(NULL != pcMat && NULL != type);
+	ai_assert(NULL != pcMat);
 
 
 	unsigned int cur = 0, temp = 0;
 	unsigned int cur = 0, temp = 0;
-	char buffer[512];
 	aiString s;
 	aiString s;
 	bool ret = false;
 	bool ret = false;
 
 
 	for (TextureList::const_iterator it = in.begin(), end = in.end();
 	for (TextureList::const_iterator it = in.begin(), end = in.end();
 		 it != end;++it)
 		 it != end;++it)
 	{
 	{
-		if (!(*it).enabled || !(*it).bCanUse || 0xffffffff == (*it).mRealUVIndex)continue;
+		if (!(*it).enabled || !(*it).bCanUse)continue;
 		ret = true;
 		ret = true;
 
 
-		// add the path to the texture
-		sprintf(buffer,"$tex.file.%s[%i]",type,cur);
+		// Convert lightwave's mapping modes to ours. We let them
+		// as they are, the GenUVcoords step will compute UV 
+		// channels if they're not there.
+
+		aiTextureMapping mapping;
+		switch ((*it).mapMode)
+		{
+			case LWO::Texture::Planar:
+				mapping = aiTextureMapping_PLANE;
+				break;
+			case LWO::Texture::Cylindrical:
+				mapping = aiTextureMapping_CYLINDER;
+				break;
+			case LWO::Texture::Spherical:
+				mapping = aiTextureMapping_SPHERE;
+				break;
+			case LWO::Texture::Cubic:
+				mapping = aiTextureMapping_BOX;
+				break;
+			case LWO::Texture::FrontProjection:
+				DefaultLogger::get()->error("LWO2: Unsupported texture mapping: FrontProjection");
+				mapping = aiTextureMapping_OTHER;
+				break;
+			case LWO::Texture::UV:
+				{
+					if( 0xffffffff == (*it).mRealUVIndex )
+					{
+						// We have no UV index for this texture, so we can't display it
+						continue;
+					}
+
+					// add the UV source index
+					temp = (*it).mRealUVIndex;
+					pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_UVWSRC(type,cur));
+
+					mapping = aiTextureMapping_UV;
+				}
+				break;
+		};
+
+		if (mapping != aiTextureMapping_UV)
+		{
+			// Setup the main axis (the enum values map one to one)
+			pcMat->AddProperty<int>((int*)&(*it).majorAxis,1,AI_MATKEY_TEXMAP_AXIS(type,cur));
+			DefaultLogger::get()->debug("LWO2: Setting up non-UV mapping");
+		}
+
 
 
 		// The older LWOB format does not use indirect references to clips.
 		// The older LWOB format does not use indirect references to clips.
 		// The file name of a texture is directly specified in the tex chunk.
 		// The file name of a texture is directly specified in the tex chunk.
@@ -133,14 +181,12 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, c
 			AdjustTexturePath(ss);
 			AdjustTexturePath(ss);
 			s.Set(ss);
 			s.Set(ss);
 		}
 		}
-		pcMat->AddProperty(&s,buffer);
+		pcMat->AddProperty(&s,AI_MATKEY_TEXTURE(type,cur));
 
 
 		// add the blend factor
 		// add the blend factor
-		sprintf(buffer,"$tex.blend.%s[%i]",type,cur);
-		pcMat->AddProperty(&(*it).mStrength,1,buffer);
+		pcMat->AddProperty<float>(&(*it).mStrength,1,AI_MATKEY_TEXBLEND(type,cur));
 
 
 		// add the blend operation
 		// add the blend operation
-		sprintf(buffer,"$tex.op.%s[%i]",type,cur);
 		switch ((*it).blendType)
 		switch ((*it).blendType)
 		{
 		{
 			case LWO::Texture::Normal:
 			case LWO::Texture::Normal:
@@ -166,22 +212,18 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, c
 				DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement");
 				DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement");
 
 
 		}
 		}
-		pcMat->AddProperty<int>((int*)&temp,1,buffer);
+		pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_TEXOP(type,cur));
 
 
-		// add the UV source index
-		sprintf(buffer,"$tex.uvw.%s[%i]",type,cur);
-		temp = (*it).mRealUVIndex;
-		pcMat->AddProperty<int>((int*)&temp,1,buffer);
+		// setup the mapping mode
+		pcMat->AddProperty<int>((int*)&mapping,1,AI_MATKEY_MAPPING(type,cur));
 
 
 		// add the u-wrapping
 		// add the u-wrapping
-		sprintf(buffer,"$tex.mapmodeu.%s[%i]",type,cur);
 		temp = (unsigned int)GetMapMode((*it).wrapModeWidth);
 		temp = (unsigned int)GetMapMode((*it).wrapModeWidth);
-		pcMat->AddProperty<int>((int*)&temp,1,buffer);
+		pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_MAPPINGMODE_U(type,cur));
 
 
 		// add the v-wrapping
 		// add the v-wrapping
-		sprintf(buffer,"$tex.mapmodev.%s[%i]",type,cur);
 		temp = (unsigned int)GetMapMode((*it).wrapModeHeight);
 		temp = (unsigned int)GetMapMode((*it).wrapModeHeight);
-		pcMat->AddProperty<int>((int*)&temp,1,buffer);
+		pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_MAPPINGMODE_V(type,cur));
 
 
 		++cur;
 		++cur;
 	}
 	}
@@ -237,17 +279,20 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
 	pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
 	pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
 
 
 	// opacity
 	// opacity
-	float f = 1.0f-surf.mTransparency;
-	pcMat->AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
+	if (10e10f != surf.mTransparency)
+	{
+		float f = 1.0f-surf.mTransparency;
+		pcMat->AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
+	}
 
 
 	// ADD TEXTURES to the material
 	// ADD TEXTURES to the material
 	// TODO: find out how we can handle COLOR textures correctly...
 	// TODO: find out how we can handle COLOR textures correctly...
-	bool b = HandleTextures(pcMat,surf.mColorTextures,"diffuse");
-	b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,"diffuse"));
-	HandleTextures(pcMat,surf.mSpecularTextures,"specular");
-	HandleTextures(pcMat,surf.mGlossinessTextures,"shininess");
-	HandleTextures(pcMat,surf.mBumpTextures,"height");
-	HandleTextures(pcMat,surf.mOpacityTextures,"opacity");
+	bool b = HandleTextures(pcMat,surf.mColorTextures,aiTextureType_DIFFUSE);
+	b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,aiTextureType_DIFFUSE));
+	HandleTextures(pcMat,surf.mSpecularTextures,aiTextureType_SPECULAR);
+	HandleTextures(pcMat,surf.mGlossinessTextures,aiTextureType_SHININESS);
+	HandleTextures(pcMat,surf.mBumpTextures,aiTextureType_HEIGHT);
+	HandleTextures(pcMat,surf.mOpacityTextures,aiTextureType_OPACITY);
 
 
 	// now we need to know which shader we must use
 	// now we need to know which shader we must use
 	// iterate through the shader list of the surface and 
 	// iterate through the shader list of the surface and 
@@ -255,7 +300,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
 	for (ShaderList::const_iterator it = surf.mShaders.begin(), end = surf.mShaders.end();
 	for (ShaderList::const_iterator it = surf.mShaders.begin(), end = surf.mShaders.end();
 		 it != end;++it)
 		 it != end;++it)
 	{
 	{
-		if (!(*it).enabled)continue;
+		//if (!(*it).enabled)continue;
 		if ((*it).functionName == "LW_SuperCelShader" ||
 		if ((*it).functionName == "LW_SuperCelShader" ||
 			(*it).functionName == "AH_CelShader")
 			(*it).functionName == "AH_CelShader")
 		{
 		{
@@ -298,20 +343,11 @@ void LWOImporter::FindUVChannels(LWO::TextureList& list, LWO::Layer& layer,
 	for (TextureList::iterator it = list.begin(), end = list.end();
 	for (TextureList::iterator it = list.begin(), end = list.end();
 		 it != end;++it)
 		 it != end;++it)
 	{
 	{
-		if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex)continue;
-		switch ((*it).mapMode)
+		// Ignore textures with non-UV mappings for the moment.
+		if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex ||
+			(*it).mapMode != LWO::Texture::UV)
 		{
 		{
-			// TODO: implement these special mappings ...
-		case LWO::Texture::Spherical:
-		case LWO::Texture::Cylindrical:
-		case LWO::Texture::Cubic:
-		case LWO::Texture::Planar:
-		case LWO::Texture::FrontProjection:
-
-			DefaultLogger::get()->warn("LWO2: Only UV mapping is currently supported.");
 			continue;
 			continue;
-
-		default: ;
 		}
 		}
 		for (unsigned int i = 0; i < layer.mUVChannels.size();++i)
 		for (unsigned int i = 0; i < layer.mUVChannels.size();++i)
 		{
 		{
@@ -391,6 +427,9 @@ void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
 		switch (head->type)
 		switch (head->type)
 		{
 		{
 		case AI_LWO_PROJ:
 		case AI_LWO_PROJ:
+			tex.mapMode = (Texture::MappingMode)GetU2();
+			break;
+		case AI_LWO_WRAP:
 			tex.wrapModeWidth  = (Texture::Wrap)GetU2();
 			tex.wrapModeWidth  = (Texture::Wrap)GetU2();
 			tex.wrapModeHeight = (Texture::Wrap)GetU2();
 			tex.wrapModeHeight = (Texture::Wrap)GetU2();
 			break;
 			break;
@@ -650,10 +689,45 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
 			// transparency
 			// transparency
 		case AI_LWO_TRAN:
 		case AI_LWO_TRAN:
 			{
 			{
+				if (surf.mTransparency == 10e10f)break;
+
 				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4);
 				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4);
 				surf.mTransparency = GetF4();
 				surf.mTransparency = GetF4();
 				break;
 				break;
 			}
 			}
+			// transparency mode
+		case AI_LWO_ALPH:
+			{
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ALPH,6);
+				uint16_t mode = GetU2();
+				switch (mode)
+				{
+					// The surface has no effect on the alpha channel when rendered
+				case 0:
+					surf.mTransparency = 10e10f;
+					break;
+
+					// The alpha channel will be written with the constant value
+					// following the mode in the subchunk. 
+				case 1:
+					surf.mTransparency = GetF4();
+					break;
+
+					// The alpha value comes from the shadow density
+				case 3:
+					DefaultLogger::get()->error("LWO2: Unsupported alpha mode: shadow_density");
+					surf.mTransparency = 10e10f;
+				}
+				break;
+			}
+			// wireframe mode
+		case AI_LWO_LINE:
+			{
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LINE,2);
+				if (GetU2() & 0x1)
+					surf.mWireframe = true;
+				break;
+			}
 			// glossiness
 			// glossiness
 		case AI_LWO_GLOS:
 		case AI_LWO_GLOS:
 			{
 			{
@@ -696,6 +770,18 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
 				surf.mMaximumSmoothAngle = GetF4();
 				surf.mMaximumSmoothAngle = GetF4();
 				break;
 				break;
 			}
 			}
+			// vertex color channel to be applied to the surface
+		case AI_LWO_VCOL:
+			{
+				AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,VCOL,12);
+				surf.mDiffuseValue *= GetF4();				// strength
+				ReadVSizedIntLWO2(mFileBuffer);             // skip envelope
+				surf.mVCMapType = GetU4();					// type of the channel
+
+				// name of the channel
+				GetS0(surf.mVCMap, (unsigned int) (next - mFileBuffer ));
+				break;
+			}
 			// surface bock entry
 			// surface bock entry
 		case AI_LWO_BLOK:
 		case AI_LWO_BLOK:
 			{
 			{

+ 1 - 1
code/MDLFileData.h

@@ -110,7 +110,7 @@ namespace MDL	{
 // material key that is set for dummy materials that are
 // material key that is set for dummy materials that are
 // just referencing another material
 // just referencing another material
 #if (!defined AI_MDL7_REFERRER_MATERIAL)
 #if (!defined AI_MDL7_REFERRER_MATERIAL)
-#	define AI_MDL7_REFERRER_MATERIAL "&&&referrer&&&"
+#	define AI_MDL7_REFERRER_MATERIAL "&&&referrer&&&",0,0
 #endif
 #endif
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------

+ 203 - 283
code/MaterialSystem.cpp

@@ -43,15 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
-// we are using sprintf only on fixed-size buffers, so the
-// compiler should automatically expand the template sprintf_s<>
-#if _MSC_VER >= 1400
-#	define sprintf sprintf_s
-#endif
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 aiReturn aiGetMaterialProperty(const aiMaterial* pMat, 
 aiReturn aiGetMaterialProperty(const aiMaterial* pMat, 
 	const char* pKey,
 	const char* pKey,
+	unsigned int type,
+    unsigned int index,
 	const aiMaterialProperty** pPropOut)
 	const aiMaterialProperty** pPropOut)
 {
 {
 	ai_assert (pMat != NULL);
 	ai_assert (pMat != NULL);
@@ -59,22 +55,25 @@ aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
 	ai_assert (pPropOut != NULL);
 	ai_assert (pPropOut != NULL);
 
 
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
+	{
+		aiMaterialProperty* prop = pMat->mProperties[i];
+
+		if (prop && !::strcmp( prop->mKey.data, pKey ) &&
+			prop->mSemantic == type && prop->mIndex == index)
 		{
 		{
-		if (NULL != pMat->mProperties[i])
-			{
-			if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
-				{
-				*pPropOut = pMat->mProperties[i];
-				return AI_SUCCESS;
-				}
-			}
+			*pPropOut = pMat->mProperties[i];
+			return AI_SUCCESS;
 		}
 		}
+	}
 	*pPropOut = NULL;
 	*pPropOut = NULL;
 	return AI_FAILURE;
 	return AI_FAILURE;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, 
 aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, 
 	const char* pKey,
 	const char* pKey,
+	unsigned int type,
+    unsigned int index,
 	float* pOut,
 	float* pOut,
 	unsigned int* pMax)
 	unsigned int* pMax)
 {
 {
@@ -84,56 +83,51 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
 
 
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
 	{
 	{
-		if (NULL != pMat->mProperties[i])
+		aiMaterialProperty* prop = pMat->mProperties[i];
+
+		if (prop && !::strcmp( prop->mKey.data, pKey ) &&
+			prop->mSemantic == type && prop->mIndex == index)
 		{
 		{
-			if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
+			// data is given in floats, simply copy it
+			if( aiPTI_Float == pMat->mProperties[i]->mType ||
+				aiPTI_Buffer == pMat->mProperties[i]->mType)
 			{
 			{
-				// data is given in floats, simply copy it
-				if( aiPTI_Float == pMat->mProperties[i]->mType ||
-					aiPTI_Buffer == pMat->mProperties[i]->mType)
-				{
-					unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(float);
+				unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(float);
 
 
-					if (NULL != pMax)
-						iWrite = *pMax < iWrite ? *pMax : iWrite;
+				if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
+				::memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (float));
 
 
-					memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (float));
-					
-					if (NULL != pMax)
-						*pMax = iWrite;
-				}
-				// data is given in ints, convert to float
-				else if( aiPTI_Integer == pMat->mProperties[i]->mType)
-				{
-					unsigned int iWrite = pMat->mProperties[i]->
-						mDataLength / sizeof(int);
-
-					if (NULL != pMax)
-						iWrite = *pMax < iWrite ? *pMax : iWrite;
-
-					for (unsigned int a = 0; a < iWrite;++a)
-					{
-						pOut[a] = (float) ((int*)pMat->mProperties[i]->mData)[a];
-					}
-					if (NULL != pMax)
-						*pMax = iWrite;
-				}
-				// it is a string ... no way to read something out of this
-				else
+				if (pMax)*pMax = iWrite;
+			}
+			// data is given in ints, convert to float
+			else if( aiPTI_Integer == pMat->mProperties[i]->mType)
+			{
+				unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(int);
+
+				if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
+				for (unsigned int a = 0; a < iWrite;++a)
 				{
 				{
-					if (NULL != pMax)
-						*pMax = 0;
-					return AI_FAILURE;
+					pOut[a] = (float) ((int*)pMat->mProperties[i]->mData)[a];
 				}
 				}
-				return AI_SUCCESS;
+				if (pMax)*pMax = iWrite;
+			}
+			// it is a string ... no way to read something out of this
+			else
+			{
+				if (pMax)*pMax = 0;
+				return AI_FAILURE;
 			}
 			}
+			return AI_SUCCESS;
 		}
 		}
 	}
 	}
 	return AI_FAILURE;
 	return AI_FAILURE;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat, 
 aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat, 
 	const char* pKey,
 	const char* pKey,
+	unsigned int type,
+    unsigned int index,
 	int* pOut,
 	int* pOut,
 	unsigned int* pMax)
 	unsigned int* pMax)
 {
 {
@@ -142,69 +136,66 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
 	ai_assert (pOut != NULL);
 	ai_assert (pOut != NULL);
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
 	{
 	{
-		if (NULL != pMat->mProperties[i])
+		aiMaterialProperty* prop = pMat->mProperties[i];
+
+		if (prop && !::strcmp( prop->mKey.data, pKey ) &&
+			prop->mSemantic == type && prop->mIndex == index)
 		{
 		{
-			if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
+			// data is given in ints, simply copy it
+			if( aiPTI_Integer == pMat->mProperties[i]->mType ||
+				aiPTI_Buffer == pMat->mProperties[i]->mType)
 			{
 			{
-				// data is given in ints, simply copy it
-				if( aiPTI_Integer == pMat->mProperties[i]->mType ||
-					aiPTI_Buffer == pMat->mProperties[i]->mType)
-				{
-					unsigned int iWrite = pMat->mProperties[i]->
-						mDataLength / sizeof(int);
+				unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(int);
 
 
-					if (NULL != pMax)
-						iWrite = *pMax < iWrite ? *pMax : iWrite;
+				if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
+				::memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (int));
 
 
-					memcpy (pOut, pMat->mProperties[i]->mData, iWrite * sizeof (int));
-					
-					if (NULL != pMax)
-						*pMax = iWrite;
-				}
-				// data is given in floats convert to int (lossy!)
-				else if( aiPTI_Float == pMat->mProperties[i]->mType)
-				{
-					unsigned int iWrite = pMat->mProperties[i]->
-						mDataLength / sizeof(float);
-
-					if (NULL != pMax)
-						iWrite = *pMax < iWrite ? *pMax : iWrite;
-
-					for (unsigned int a = 0; a < iWrite;++a)
-					{
-						pOut[a] = (int) ((float*)pMat->mProperties[i]->mData)[a];
-					}
-					if (NULL != pMax)
-						*pMax = iWrite;
-				}
-				// it is a string ... no way to read something out of this
-				else
+				if (pMax)*pMax = iWrite;
+			}
+			// data is given in floats convert to int (lossy!)
+			else if( aiPTI_Float == pMat->mProperties[i]->mType)
+			{
+				unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(float);
+
+				if (pMax)iWrite = *pMax < iWrite ? *pMax : iWrite;
+				for (unsigned int a = 0; a < iWrite;++a)
 				{
 				{
-					if (NULL != pMax)
-						*pMax = 0;
-					return AI_FAILURE;
+					pOut[a] = (int) ((float*)pMat->mProperties[i]->mData)[a];
 				}
 				}
-				return AI_SUCCESS;
+				if (pMax)*pMax = iWrite;
 			}
 			}
+			// it is a string ... no way to read something out of this
+			else
+			{
+				if (pMax)*pMax = 0;
+				return AI_FAILURE;
+			}
+			return AI_SUCCESS;
 		}
 		}
 	}
 	}
 	return AI_FAILURE;
 	return AI_FAILURE;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 aiReturn aiGetMaterialColor(const aiMaterial* pMat, 
 aiReturn aiGetMaterialColor(const aiMaterial* pMat, 
 	const char* pKey,
 	const char* pKey,
+	unsigned int type,
+    unsigned int index,
 	aiColor4D* pOut)
 	aiColor4D* pOut)
 {
 {
 	unsigned int iMax = 4;
 	unsigned int iMax = 4;
-	aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,(float*)pOut,&iMax);
+	aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,type,index,(float*)pOut,&iMax);
 
 
 	// if no alpha channel is provided set it to 1.0 by default
 	// if no alpha channel is provided set it to 1.0 by default
 	if (3 == iMax)pOut->a = 1.0f;
 	if (3 == iMax)pOut->a = 1.0f;
 	return eRet;
 	return eRet;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 aiReturn aiGetMaterialString(const aiMaterial* pMat, 
 aiReturn aiGetMaterialString(const aiMaterial* pMat, 
 	const char* pKey,
 	const char* pKey,
+	unsigned int type,
+    unsigned int index,
 	aiString* pOut)
 	aiString* pOut)
 {
 {
 	ai_assert (pMat != NULL);
 	ai_assert (pMat != NULL);
@@ -213,37 +204,39 @@ aiReturn aiGetMaterialString(const aiMaterial* pMat,
 
 
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
 	for (unsigned int i = 0; i < pMat->mNumProperties;++i)
 	{
 	{
-		if (NULL != pMat->mProperties[i])
+		aiMaterialProperty* prop = pMat->mProperties[i];
+
+		if (prop && !::strcmp( prop->mKey.data, pKey ) &&
+			prop->mSemantic == type && prop->mIndex == index)
 		{
 		{
-			if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
+			if( aiPTI_String == pMat->mProperties[i]->mType)
 			{
 			{
-				if( aiPTI_String == pMat->mProperties[i]->mType)
-				{
-					const aiString* pcSrc = (const aiString*)pMat->mProperties[i]->mData; 
-					::memcpy (pOut->data, pcSrc->data, (pOut->length = pcSrc->length)+1);
-				}
-				// wrong type
-				else return AI_FAILURE;
-				return AI_SUCCESS;
+				const aiString* pcSrc = (const aiString*)pMat->mProperties[i]->mData; 
+				::memcpy (pOut->data, pcSrc->data, (pOut->length = pcSrc->length)+1);
 			}
 			}
+			// Wrong type
+			else return AI_FAILURE;
+			return AI_SUCCESS;
 		}
 		}
 	}
 	}
 	return AI_FAILURE;
 	return AI_FAILURE;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 MaterialHelper::MaterialHelper()
 MaterialHelper::MaterialHelper()
 {
 {
-	// allocate 5 entries by default
-	this->mNumProperties = 0;
-	this->mNumAllocated = 5;
-	this->mProperties = new aiMaterialProperty*[5];
-	return;
+	// Allocate 5 entries by default
+	mNumProperties = 0;
+	mNumAllocated = 5;
+	mProperties = new aiMaterialProperty*[5];
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 MaterialHelper::~MaterialHelper()
 MaterialHelper::~MaterialHelper()
 {
 {
 	Clear();
 	Clear();
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void MaterialHelper::Clear()
 void MaterialHelper::Clear()
 {
 {
@@ -252,7 +245,11 @@ void MaterialHelper::Clear()
 		// delete this entry
 		// delete this entry
 		delete mProperties[i];
 		delete mProperties[i];
 	}
 	}
+	mNumProperties = 0;
+
+	// The array remains
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 uint32_t MaterialHelper::ComputeHash()
 uint32_t MaterialHelper::ComputeHash()
 {
 {
@@ -262,45 +259,62 @@ uint32_t MaterialHelper::ComputeHash()
 		aiMaterialProperty* prop;
 		aiMaterialProperty* prop;
 
 
 		// NOTE: We need to exclude the material name from the hash
 		// NOTE: We need to exclude the material name from the hash
-		if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey.data,AI_MATKEY_NAME)) 
+		if ((prop = this->mProperties[i]) && ::strcmp(prop->mKey.data,"$mat.name")) 
 		{
 		{
 			hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash);
 			hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash);
 			hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
 			hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
+
+			// Combine the semantic and the index with the hash
+			// We print them to a string to make sure the quality
+			// of the hash isn't decreased.
+			char buff[32];
+			unsigned int len;
+			
+			len = itoa10(buff,prop->mSemantic);
+			hash = SuperFastHash(buff,len-1,hash);
+
+			len = itoa10(buff,prop->mIndex);
+			hash = SuperFastHash(buff,len-1,hash);
 		}
 		}
 	}
 	}
 	return hash;
 	return hash;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-aiReturn MaterialHelper::RemoveProperty (const char* pKey)
+aiReturn MaterialHelper::RemoveProperty (const char* pKey,unsigned int type,
+    unsigned int index)
 {
 {
 	ai_assert(NULL != pKey);
 	ai_assert(NULL != pKey);
 
 
-	for (unsigned int i = 0; i < this->mNumProperties;++i)
+	for (unsigned int i = 0; i < mNumProperties;++i)
 	{
 	{
-		if (this->mProperties[i]) // just for safety
+		aiMaterialProperty* prop = mProperties[i];
+
+		if (prop && !::strcmp( prop->mKey.data, pKey ) &&
+			prop->mSemantic == type && prop->mIndex == index)
 		{
 		{
-			if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey ))
+			// Delete this entry
+			delete mProperties[i];
+
+			// collapse the array behind --.
+			--mNumProperties;
+			for (unsigned int a = i; a < mNumProperties;++a)
 			{
 			{
-				// delete this entry
-				delete this->mProperties[i];
-				
-				// collapse the array behind --.
-				--this->mNumProperties;
-				for (unsigned int a = i; a < this->mNumProperties;++a)
-				{
-					this->mProperties[a] = this->mProperties[a+1];
-				}
-				return AI_SUCCESS;
+				mProperties[a] = mProperties[a+1];
 			}
 			}
+			return AI_SUCCESS;
 		}
 		}
 	}
 	}
 
 
 	return AI_FAILURE;
 	return AI_FAILURE;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
 aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
-	const unsigned int pSizeInBytes,
+	unsigned int pSizeInBytes,
 	const char* pKey,
 	const char* pKey,
+	unsigned int type,
+    unsigned int index,
 	aiPropertyTypeInfo pType)
 	aiPropertyTypeInfo pType)
 {
 {
 	ai_assert (pInput != NULL);
 	ai_assert (pInput != NULL);
@@ -310,27 +324,30 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
 	// first search the list whether there is already an entry
 	// first search the list whether there is already an entry
 	// with this name.
 	// with this name.
 	unsigned int iOutIndex = 0xFFFFFFFF;
 	unsigned int iOutIndex = 0xFFFFFFFF;
-	for (unsigned int i = 0; i < this->mNumProperties;++i)
+	for (unsigned int i = 0; i < mNumProperties;++i)
 	{
 	{
-		if (this->mProperties[i])
+		aiMaterialProperty* prop = mProperties[i];
+
+		if (prop && !::strcmp( prop->mKey.data, pKey ) &&
+			prop->mSemantic == type && prop->mIndex == index)
 		{
 		{
-			if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey ))
-			{
-				// delete this entry
-				delete this->mProperties[i];
-				iOutIndex = i;
-			}
+			// delete this entry
+			delete this->mProperties[i];
+			iOutIndex = i;
 		}
 		}
 	}
 	}
 
 
+	// Allocate a new material property
 	aiMaterialProperty* pcNew = new aiMaterialProperty();
 	aiMaterialProperty* pcNew = new aiMaterialProperty();
 
 
-	// fill this
+	// Fill this
 	pcNew->mType = pType;
 	pcNew->mType = pType;
+	pcNew->mSemantic = type;
+	pcNew->mIndex = index;
 
 
 	pcNew->mDataLength = pSizeInBytes;
 	pcNew->mDataLength = pSizeInBytes;
 	pcNew->mData = new char[pSizeInBytes];
 	pcNew->mData = new char[pSizeInBytes];
-	memcpy (pcNew->mData,pInput,pSizeInBytes);
+	::memcpy (pcNew->mData,pInput,pSizeInBytes);
 
 
 	pcNew->mKey.length = ::strlen(pKey);
 	pcNew->mKey.length = ::strlen(pKey);
 	ai_assert ( MAXLEN > pcNew->mKey.length);
 	ai_assert ( MAXLEN > pcNew->mKey.length);
@@ -338,37 +355,41 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
 
 
 	if (0xFFFFFFFF != iOutIndex)
 	if (0xFFFFFFFF != iOutIndex)
 	{
 	{
-		this->mProperties[iOutIndex] = pcNew;
+		mProperties[iOutIndex] = pcNew;
 		return AI_SUCCESS;
 		return AI_SUCCESS;
 	}
 	}
 
 
 	// resize the array ... allocate storage for 5 other properties
 	// resize the array ... allocate storage for 5 other properties
-	if (this->mNumProperties == this->mNumAllocated)
+	if (mNumProperties == mNumAllocated)
 	{
 	{
-		unsigned int iOld = this->mNumAllocated;
-		this->mNumAllocated += 5;
+		unsigned int iOld = mNumAllocated;
+		mNumAllocated += 5;
 
 
-		aiMaterialProperty** ppTemp = new aiMaterialProperty*[this->mNumAllocated];
+		aiMaterialProperty** ppTemp = new aiMaterialProperty*[mNumAllocated];
 		if (NULL == ppTemp)return AI_OUTOFMEMORY;
 		if (NULL == ppTemp)return AI_OUTOFMEMORY;
 
 
-		::memcpy (ppTemp,this->mProperties,iOld * sizeof(void*));
+		::memcpy (ppTemp,mProperties,iOld * sizeof(void*));
 
 
-		delete[] this->mProperties;
-		this->mProperties = ppTemp;
+		delete[] mProperties;
+		mProperties = ppTemp;
 	}
 	}
 	// push back ...
 	// push back ...
-	this->mProperties[this->mNumProperties++] = pcNew;
+	mProperties[mNumProperties++] = pcNew;
 	return AI_SUCCESS;
 	return AI_SUCCESS;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 aiReturn MaterialHelper::AddProperty (const aiString* pInput,
 aiReturn MaterialHelper::AddProperty (const aiString* pInput,
-	const char* pKey)
+	const char* pKey,
+	unsigned int type,
+    unsigned int index)
 {
 {
-	// fix ... don't keep the whole string buffer
+	// Fix ... don't keep the whole string buffer
 	return this->AddBinaryProperty(pInput,(unsigned int)pInput->length+1+
 	return this->AddBinaryProperty(pInput,(unsigned int)pInput->length+1+
 		(unsigned int)(((uint8_t*)&pInput->data - (uint8_t*)&pInput->length)),
 		(unsigned int)(((uint8_t*)&pInput->data - (uint8_t*)&pInput->length)),
-		pKey,aiPTI_String);
+		pKey,type,index, aiPTI_String);
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest, 
 void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest, 
 	const MaterialHelper* pcSrc)
 	const MaterialHelper* pcSrc)
@@ -400,7 +421,8 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
 		for (unsigned int q = 0; q < iOldNum;++q)
 		for (unsigned int q = 0; q < iOldNum;++q)
 		{
 		{
 			prop = pcDest->mProperties[q];
 			prop = pcDest->mProperties[q];
-			if (!ASSIMP_stricmp(propSrc->mKey.data,prop->mKey.data))
+			if (prop && prop->mKey == propSrc->mKey &&
+			prop->mSemantic == propSrc->mSemantic && prop->mIndex == propSrc->mIndex)
 			{
 			{
 				delete prop;
 				delete prop;
 
 
@@ -411,171 +433,69 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
 			}
 			}
 		}
 		}
 
 
+		// Allocate the output property and copy the source property
 		prop = pcDest->mProperties[i] = new aiMaterialProperty();
 		prop = pcDest->mProperties[i] = new aiMaterialProperty();
 		prop->mKey = propSrc->mKey;
 		prop->mKey = propSrc->mKey;
 		prop->mDataLength = propSrc->mDataLength;
 		prop->mDataLength = propSrc->mDataLength;
 		prop->mType = propSrc->mType;
 		prop->mType = propSrc->mType;
+		prop->mSemantic = propSrc->mSemantic;
+		prop->mIndex = propSrc->mIndex;
+
 		prop->mData = new char[propSrc->mDataLength];
 		prop->mData = new char[propSrc->mDataLength];
 		::memcpy(prop->mData,propSrc->mData,prop->mDataLength);
 		::memcpy(prop->mData,propSrc->mData,prop->mDataLength);
 	}
 	}
 	return;
 	return;
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// we need this dummy because the compiler would otherwise complain about
-// empty, but controlled statements ...
-void DummyAssertFunction()
-{
-	ai_assert(false);
-}
-// ------------------------------------------------------------------------------------------------
-aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
-	unsigned int iIndex,
-	unsigned int iTexType,
-	aiString* szOut,
-	unsigned int* piUVIndex,
-	float* pfBlendFactor,
-	aiTextureOp* peTextureOp,
-	aiTextureMapMode* peMapMode)
+aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
+    aiTextureType type,
+    unsigned int  index,
+    C_STRUCT aiString* path,
+	aiTextureMapping* _mapping	/*= NULL*/,
+    unsigned int* uvindex		/*= NULL*/,
+    float* blend				/*= NULL*/,
+    aiTextureOp* op				/*= NULL*/,
+	aiTextureMapMode* mapmode	/*= NULL*/)
 {
 {
-	ai_assert(NULL != pcMat);
-	ai_assert(NULL != szOut);
-
-	const char* szPathBase;
-	const char* szUVBase;
-	const char* szBlendBase;
-	const char* szOpBase;
-	const char* aszMapModeBase[3];
-	switch (iTexType)
-	{
-	case AI_TEXTYPE_DIFFUSE:
-		szPathBase	= AI_MATKEY_TEXTURE_DIFFUSE_;
-		szUVBase	= AI_MATKEY_UVWSRC_DIFFUSE_;
-		szBlendBase = AI_MATKEY_TEXBLEND_DIFFUSE_;
-		szOpBase	= AI_MATKEY_TEXOP_DIFFUSE_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_DIFFUSE_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_DIFFUSE_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_DIFFUSE_;
-		break;
-	case AI_TEXTYPE_SPECULAR:
-		szPathBase	= AI_MATKEY_TEXTURE_SPECULAR_;
-		szUVBase	= AI_MATKEY_UVWSRC_SPECULAR_;
-		szBlendBase = AI_MATKEY_TEXBLEND_SPECULAR_;
-		szOpBase	= AI_MATKEY_TEXOP_SPECULAR_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_SPECULAR_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_SPECULAR_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_SPECULAR_;
-		break;
-	case AI_TEXTYPE_AMBIENT:
-		szPathBase	= AI_MATKEY_TEXTURE_AMBIENT_;
-		szUVBase	= AI_MATKEY_UVWSRC_AMBIENT_;
-		szBlendBase = AI_MATKEY_TEXBLEND_AMBIENT_;
-		szOpBase	= AI_MATKEY_TEXOP_AMBIENT_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_AMBIENT_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_AMBIENT_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_AMBIENT_;
-		break;
-	case AI_TEXTYPE_EMISSIVE:
-		szPathBase	= AI_MATKEY_TEXTURE_EMISSIVE_;
-		szUVBase	= AI_MATKEY_UVWSRC_EMISSIVE_;
-		szBlendBase = AI_MATKEY_TEXBLEND_EMISSIVE_;
-		szOpBase	= AI_MATKEY_TEXOP_EMISSIVE_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_EMISSIVE_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_EMISSIVE_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_EMISSIVE_;
-		break;
-	case AI_TEXTYPE_HEIGHT:
-		szPathBase	= AI_MATKEY_TEXTURE_HEIGHT_;
-		szUVBase	= AI_MATKEY_UVWSRC_HEIGHT_;
-		szBlendBase = AI_MATKEY_TEXBLEND_HEIGHT_;
-		szOpBase	= AI_MATKEY_TEXOP_HEIGHT_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_HEIGHT_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_HEIGHT_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_HEIGHT_;
-		break;
-	case AI_TEXTYPE_NORMALS:
-		szPathBase	= AI_MATKEY_TEXTURE_NORMALS_;
-		szUVBase	= AI_MATKEY_UVWSRC_NORMALS_;
-		szBlendBase = AI_MATKEY_TEXBLEND_NORMALS_;
-		szOpBase	= AI_MATKEY_TEXOP_NORMALS_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_NORMALS_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_NORMALS_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_NORMALS_;
-		break;
-	case AI_TEXTYPE_SHININESS:
-		szPathBase	= AI_MATKEY_TEXTURE_SHININESS_;
-		szUVBase	= AI_MATKEY_UVWSRC_SHININESS_;
-		szBlendBase = AI_MATKEY_TEXBLEND_SHININESS_;
-		szOpBase	= AI_MATKEY_TEXOP_SHININESS_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_SHININESS_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_SHININESS_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_SHININESS_;
-		break;
-	case AI_TEXTYPE_OPACITY:
-		szPathBase	= AI_MATKEY_TEXTURE_OPACITY_;
-		szUVBase	= AI_MATKEY_UVWSRC_OPACITY_;
-		szBlendBase = AI_MATKEY_TEXBLEND_OPACITY_;
-		szOpBase	= AI_MATKEY_TEXOP_OPACITY_;
-		aszMapModeBase[0] = AI_MATKEY_MAPPINGMODE_U_OPACITY_;
-		aszMapModeBase[1] = AI_MATKEY_MAPPINGMODE_V_OPACITY_;
-		aszMapModeBase[2] = AI_MATKEY_MAPPINGMODE_W_OPACITY_;
-		break;
-	default: return AI_FAILURE;
-	};
-
-	char szKey[256];
-	if (iIndex > 100)return AI_FAILURE;
-
-	// get the path to the texture
-	if(0 >= sprintf(szKey,"%s[%i]",szPathBase,iIndex))DummyAssertFunction();
-	if (AI_SUCCESS != aiGetMaterialString(pcMat,szKey,szOut))
+	ai_assert(NULL != mat && NULL != path);
+
+	// Get the path to the texture
+	aiString string;
+	if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),&string))
 	{
 	{
 		return AI_FAILURE;
 		return AI_FAILURE;
 	}
 	}
-	// get the UV index of the texture
-	if (piUVIndex)
-	{
-		int iUV;
-		if(0 >= sprintf(szKey,"%s[%i]",szUVBase,iIndex))DummyAssertFunction();
-		if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,&iUV))
-			iUV = 0;
 
 
-		*piUVIndex = iUV;
-	}
-	// get the blend factor of the texture
-	if (pfBlendFactor)
-	{
-		float fBlend;
-		if(0 >= sprintf(szKey,"%s[%i]",szBlendBase,iIndex))DummyAssertFunction();
-		if (AI_SUCCESS != aiGetMaterialFloat(pcMat,szKey,&fBlend))
-			fBlend = 1.0f;
+	// Determine the mapping type of the texture
+	aiTextureMapping mapping = aiTextureMapping_UV;
+	aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index),(int*)&mapping);
+	if (_mapping)*_mapping = mapping;
 
 
-		*pfBlendFactor = fBlend;
+	// Get the UV index of the texture
+	if (aiTextureMapping_UV == mapping && uvindex)
+	{
+		aiGetMaterialInteger(mat,AI_MATKEY_UVWSRC(type,index),(int*)uvindex);
 	}
 	}
 
 
-	// get the texture operation of the texture
-	if (peTextureOp)
+	// Get the blend factor of the texture
+	if (blend)
 	{
 	{
-		aiTextureOp op;
-		if(0 >= sprintf(szKey,"%s[%i]",szOpBase,iIndex))DummyAssertFunction();
-		if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&op))
-			op = aiTextureOp_Multiply;
+		aiGetMaterialFloat(mat,AI_MATKEY_TEXBLEND(type,index),blend);
+	}
 
 
-		*peTextureOp = op;
+	// Get the texture operation of the texture
+	if (op)
+	{
+		aiGetMaterialInteger(mat,AI_MATKEY_TEXOP(type,index),(int*)op);
 	}
 	}
 
 
 	// get the texture mapping modes for the texture
 	// get the texture mapping modes for the texture
-	if (peMapMode)
+	if (mapmode)
 	{
 	{
-		aiTextureMapMode eMode;
-		for (unsigned int q = 0; q < 3;++q)
-		{
-			if(0 >= sprintf(szKey,"%s[%i]",aszMapModeBase[q],iIndex))DummyAssertFunction();
-			if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&eMode))
-			{
-				eMode = aiTextureMapMode_Wrap;
-			}
-			peMapMode[q] = eMode;
-		}
+		aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U(type,index),(int*)&mapmode[0]);
+		aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V(type,index),(int*)&mapmode[1]);		
+		aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_W(type,index),(int*)&mapmode[2]);
 	}
 	}
 	return AI_SUCCESS;
 	return AI_SUCCESS;
 }
 }

+ 40 - 16
code/MaterialSystem.h

@@ -65,11 +65,15 @@ public:
 	 *  \param pInput Pointer to input data
 	 *  \param pInput Pointer to input data
 	 *  \param pSizeInBytes Size of input data
 	 *  \param pSizeInBytes Size of input data
 	 *  \param pKey Key/Usage of the property (AI_MATKEY_XXX)
 	 *  \param pKey Key/Usage of the property (AI_MATKEY_XXX)
+	 *  \param type Set by the AI_MATKEY_XXX macro
+	 *  \param index Set by the AI_MATKEY_XXX macro
 	 *  \param pType Type information hint
 	 *  \param pType Type information hint
      */
      */
 	aiReturn AddBinaryProperty (const void* pInput,
 	aiReturn AddBinaryProperty (const void* pInput,
-		const unsigned int pSizeInBytes,
+		unsigned int pSizeInBytes,
 		const char* pKey,
 		const char* pKey,
+		unsigned int type,
+		unsigned int index,
 		aiPropertyTypeInfo pType);
 		aiPropertyTypeInfo pType);
 
 
 
 
@@ -79,9 +83,13 @@ public:
 	 *
 	 *
 	 *  \param pInput Input string
 	 *  \param pInput Input string
 	 *  \param pKey Key/Usage of the property (AI_MATKEY_XXX)
 	 *  \param pKey Key/Usage of the property (AI_MATKEY_XXX)
+	 *  \param type Set by the AI_MATKEY_XXX macro
+	 *  \param index Set by the AI_MATKEY_XXX macro
 	 */
 	 */
 	aiReturn AddProperty (const aiString* pInput,
 	aiReturn AddProperty (const aiString* pInput,
-		const char* pKey);
+		const char* pKey,
+		unsigned int type,
+		unsigned int index);
 
 
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
@@ -89,20 +97,26 @@ public:
 	 *  \param pInput Pointer to the input data
 	 *  \param pInput Pointer to the input data
 	 *  \param pNumValues Number of values in the array
 	 *  \param pNumValues Number of values in the array
 	 *  \param pKey Key/Usage of the property (AI_MATKEY_XXX)
 	 *  \param pKey Key/Usage of the property (AI_MATKEY_XXX)
+	 *  \param type Set by the AI_MATKEY_XXX macro
+	 *  \param index Set by the AI_MATKEY_XXX macro
 	 */
 	 */
 	template<class TYPE>
 	template<class TYPE>
 	aiReturn AddProperty (const TYPE* pInput,
 	aiReturn AddProperty (const TYPE* pInput,
-		const unsigned int pNumValues,
-		const char* pKey);
+		unsigned int pNumValues,
+		const char* pKey,
+		unsigned int type,
+		unsigned int index);
 
 
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Remove a given key from the list
 	/** Remove a given key from the list
 	 *  The function fails if the key isn't found
 	 *  The function fails if the key isn't found
 	 *
 	 *
-	 *  \param pKey Key/Usage to be deleted
+	 *  \param pKey Key to be deleted
 	 */
 	 */
-	aiReturn RemoveProperty (const char* pKey);
+	aiReturn RemoveProperty (const char* pKey,
+		unsigned int type,
+		unsigned int index);
 
 
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
@@ -136,11 +150,13 @@ public:
 template<class TYPE>
 template<class TYPE>
 aiReturn MaterialHelper::AddProperty (const TYPE* pInput,
 aiReturn MaterialHelper::AddProperty (const TYPE* pInput,
 	const unsigned int pNumValues,
 	const unsigned int pNumValues,
-	const char* pKey)
+	const char* pKey,
+	unsigned int type,
+	unsigned int index)
 {
 {
 	return this->AddBinaryProperty((const void*)pInput,
 	return this->AddBinaryProperty((const void*)pInput,
 		pNumValues * sizeof(TYPE),
 		pNumValues * sizeof(TYPE),
-		pKey,aiPTI_Buffer);
+		pKey,type,index,aiPTI_Buffer);
 }
 }
 
 
 
 
@@ -149,11 +165,13 @@ aiReturn MaterialHelper::AddProperty (const TYPE* pInput,
 template<>
 template<>
 inline aiReturn MaterialHelper::AddProperty<float> (const float* pInput,
 inline aiReturn MaterialHelper::AddProperty<float> (const float* pInput,
 	const unsigned int pNumValues,
 	const unsigned int pNumValues,
-	const char* pKey)
+	const char* pKey,
+	unsigned int type,
+	unsigned int index)
 {
 {
 	return this->AddBinaryProperty((const void*)pInput,
 	return this->AddBinaryProperty((const void*)pInput,
 		pNumValues * sizeof(float),
 		pNumValues * sizeof(float),
-		pKey,aiPTI_Float);
+		pKey,type,index,aiPTI_Float);
 }
 }
 
 
 
 
@@ -162,11 +180,13 @@ inline aiReturn MaterialHelper::AddProperty<float> (const float* pInput,
 template<>
 template<>
 inline aiReturn MaterialHelper::AddProperty<aiColor4D> (const aiColor4D* pInput,
 inline aiReturn MaterialHelper::AddProperty<aiColor4D> (const aiColor4D* pInput,
 	const unsigned int pNumValues,
 	const unsigned int pNumValues,
-	const char* pKey)
+	const char* pKey,
+	unsigned int type,
+	unsigned int index)
 {
 {
 	return this->AddBinaryProperty((const void*)pInput,
 	return this->AddBinaryProperty((const void*)pInput,
 		pNumValues * sizeof(aiColor4D),
 		pNumValues * sizeof(aiColor4D),
-		pKey,aiPTI_Float);
+		pKey,type,index,aiPTI_Float);
 }
 }
 
 
 
 
@@ -175,11 +195,13 @@ inline aiReturn MaterialHelper::AddProperty<aiColor4D> (const aiColor4D* pInput,
 template<>
 template<>
 inline aiReturn MaterialHelper::AddProperty<aiColor3D> (const aiColor3D* pInput,
 inline aiReturn MaterialHelper::AddProperty<aiColor3D> (const aiColor3D* pInput,
 	const unsigned int pNumValues,
 	const unsigned int pNumValues,
-	const char* pKey)
+	const char* pKey,
+	unsigned int type,
+	unsigned int index)
 {
 {
 	return this->AddBinaryProperty((const void*)pInput,
 	return this->AddBinaryProperty((const void*)pInput,
 		pNumValues * sizeof(aiColor3D),
 		pNumValues * sizeof(aiColor3D),
-		pKey,aiPTI_Float);
+		pKey,type,index,aiPTI_Float);
 }
 }
 
 
 
 
@@ -188,11 +210,13 @@ inline aiReturn MaterialHelper::AddProperty<aiColor3D> (const aiColor3D* pInput,
 template<>
 template<>
 inline aiReturn MaterialHelper::AddProperty<int> (const int* pInput,
 inline aiReturn MaterialHelper::AddProperty<int> (const int* pInput,
 	const unsigned int pNumValues,
 	const unsigned int pNumValues,
-	const char* pKey)
+	const char* pKey,
+	unsigned int type,
+	unsigned int index)
 {
 {
 	return this->AddBinaryProperty((const void*)pInput,
 	return this->AddBinaryProperty((const void*)pInput,
 		pNumValues * sizeof(int),
 		pNumValues * sizeof(int),
-		pKey,aiPTI_Integer);
+		pKey,type,index,aiPTI_Integer);
 }
 }
 }
 }
 
 

+ 48 - 0
code/ProcessHelper.h

@@ -93,6 +93,54 @@ inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh)
 }
 }
 
 
 
 
+// ------------------------------------------------------------------------------------------------
+// Get a string for a given aiTextureType
+inline const char* TextureTypeToString(aiTextureType in)
+{
+	switch (in)
+	{
+	case aiTextureType_DIFFUSE:
+		return "Diffuse";
+	case aiTextureType_SPECULAR:
+		return "Specular";
+	case aiTextureType_AMBIENT:
+		return "Ambient";
+	case aiTextureType_EMISSIVE:
+		return "Emissive";
+	case aiTextureType_OPACITY:
+		return "Opacity";
+	case aiTextureType_NORMALS:
+		return "Normals";
+	case aiTextureType_HEIGHT:
+		return "Height";
+	case aiTextureType_SHININESS:
+		return "Shininess";
+	}
+	return "LARGE ERROR, please leave the room immediately and call the police";
+}
+
+// ------------------------------------------------------------------------------------------------
+// Get a string for a given aiTextureMapping
+inline const char* MappingTypeToString(aiTextureMapping in)
+{
+	switch (in)
+	{
+	case aiTextureMapping_UV:
+		return "UV";
+	case aiTextureMapping_BOX:
+		return "Box";
+	case aiTextureMapping_SPHERE:
+		return "Sphere";
+	case aiTextureMapping_CYLINDER:
+		return "Cylinder";
+	case aiTextureMapping_PLANE:
+		return "Plane";
+	case aiTextureMapping_OTHER:
+		return "Other";
+	}
+	return "LARGE ERROR, please leave the room immediately and call the police";
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 class ComputeSpatialSortProcess : public BaseProcess
 class ComputeSpatialSortProcess : public BaseProcess
 {
 {

+ 14 - 9
code/RemoveRedundantMaterials.cpp

@@ -47,34 +47,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
-#if _MSC_VER >= 1400
-#	define sprintf sprintf_s
-#endif
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 RemoveRedundantMatsProcess::RemoveRedundantMatsProcess()
 RemoveRedundantMatsProcess::RemoveRedundantMatsProcess()
 {
 {
+	// nothing to do here
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
 RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess()
 RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess()
 {
 {
 	// nothing to do here
 	// nothing to do here
 }
 }
-// -------------------------------------------------------------------
+
+// ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 // Returns whether the processing step is present in the given flag field.
 bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const
 bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const
 {
 {
 	return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
 	return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
 }
 }
-// -------------------------------------------------------------------
+
+// ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 // Executes the post processing step on the given imported data.
 void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 {
 {
 	DefaultLogger::get()->debug("RemoveRedundantMatsProcess begin");
 	DefaultLogger::get()->debug("RemoveRedundantMatsProcess begin");
 
 
-	unsigned int iCnt = 0;
+	unsigned int iCnt = 0, unreferenced = 0;
 	if (pScene->mNumMaterials)
 	if (pScene->mNumMaterials)
 	{
 	{
 		// TODO: reimplement this algorithm to work in-place
 		// TODO: reimplement this algorithm to work in-place
@@ -95,7 +95,11 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 		for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
 		for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
 		{
 		{
 			// if the material is not referenced ... remove it
 			// if the material is not referenced ... remove it
-			if (!abReferenced[i])continue;
+			if (!abReferenced[i])
+			{
+				++unreferenced;
+				continue;
+			}
 
 
 			uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash();
 			uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash();
 			for (unsigned int a = 0; a < i;++a)
 			for (unsigned int a = 0; a < i;++a)
@@ -153,7 +157,8 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 	else 
 	else 
 	{
 	{
 		char szBuffer[128]; // should be sufficiently large
 		char szBuffer[128]; // should be sufficiently large
-		::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. Found %i redundant materials",iCnt);
+		::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. %i redundant and %i unused materials",
+			iCnt,unreferenced);
 		DefaultLogger::get()->info(szBuffer);
 		DefaultLogger::get()->info(szBuffer);
 	}
 	}
 }
 }

+ 16 - 8
code/TargetAnimation.cpp

@@ -45,20 +45,20 @@ using namespace Assimp;
 
 
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-KeyIterator::KeyIterator(std::vector<aiVectorKey>* _objPos,
+KeyIterator::KeyIterator(const std::vector<aiVectorKey>* _objPos,
 	const std::vector<aiVectorKey>* _targetObjPos,
 	const std::vector<aiVectorKey>* _targetObjPos,
 	const aiVector3D*  defaultObjectPos /*= NULL*/,
 	const aiVector3D*  defaultObjectPos /*= NULL*/,
 	const aiVector3D*  defaultTargetPos /*= NULL*/)
 	const aiVector3D*  defaultTargetPos /*= NULL*/)
 		
 		
 		:	reachedEnd		(false)
 		:	reachedEnd		(false)
 		,	curTime			(-1.)
 		,	curTime			(-1.)
-		,	objPos(_objPos)
+		,	objPos			(_objPos)
 		,	targetObjPos	(_targetObjPos)
 		,	targetObjPos	(_targetObjPos)
 		,	nextObjPos		(0)
 		,	nextObjPos		(0)
 		,	nextTargetObjPos(0)
 		,	nextTargetObjPos(0)
 {
 {
 	// Generate default transformation tracks if necessary
 	// Generate default transformation tracks if necessary
-	if (!objPos)
+	if (!objPos || objPos->empty())
 	{
 	{
 		defaultObjPos.resize(1);
 		defaultObjPos.resize(1);
 		defaultObjPos.front().mTime  = 10e10;
 		defaultObjPos.front().mTime  = 10e10;
@@ -68,7 +68,7 @@ KeyIterator::KeyIterator(std::vector<aiVectorKey>* _objPos,
 
 
 		objPos = & defaultObjPos;
 		objPos = & defaultObjPos;
 	}
 	}
-	if (!targetObjPos)
+	if (!targetObjPos || targetObjPos->empty())
 	{
 	{
 		defaultTargetObjPos.resize(1);
 		defaultTargetObjPos.resize(1);
 		defaultTargetObjPos.front().mTime  = 10e10;
 		defaultTargetObjPos.front().mTime  = 10e10;
@@ -129,7 +129,7 @@ void KeyIterator::operator ++()
 			const aiVectorKey& last  = targetObjPos->at(nextTargetObjPos);
 			const aiVectorKey& last  = targetObjPos->at(nextTargetObjPos);
 			const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1);
 			const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1);
 
 
-			/*curTargetPosition = Interpolate(first.mValue, last.mValue,
+		/*	curTargetPosition = Interpolate(first.mValue, last.mValue,
 				(curTime-first.mTime) / (last.mTime-first.mTime));*/
 				(curTime-first.mTime) / (last.mTime-first.mTime));*/
 		}
 		}
 
 
@@ -177,23 +177,31 @@ void TargetAnimationHelper::SetTargetAnimationChannel (
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 void TargetAnimationHelper::SetMainAnimationChannel (
 void TargetAnimationHelper::SetMainAnimationChannel (
-	std::vector<aiVectorKey>* _objectPositions)
+	const std::vector<aiVectorKey>* _objectPositions)
 {
 {
 	ai_assert(NULL != _objectPositions);
 	ai_assert(NULL != _objectPositions);
 	objectPositions = _objectPositions;
 	objectPositions = _objectPositions;
 }
 }
 
 
+// ---------------------------------------------------------------------------
+void TargetAnimationHelper::SetFixedMainAnimationChannel(
+	const aiVector3D& fixed)
+{
+	objectPositions = NULL; // just to avoid confusion
+	fixedMain = fixed;
+}
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 void TargetAnimationHelper::Process(std::vector<aiVectorKey>* distanceTrack)
 void TargetAnimationHelper::Process(std::vector<aiVectorKey>* distanceTrack)
 {
 {
-	ai_assert(NULL != objectPositions);
+	ai_assert(NULL != targetPositions);
 
 
 	// Iterate through all object keys and interpolate their values if necessary.
 	// Iterate through all object keys and interpolate their values if necessary.
 	// Then get the corresponding target position, compute the difference
 	// Then get the corresponding target position, compute the difference
 	// vector between object and target position. Then compute a rotation matrix
 	// vector between object and target position. Then compute a rotation matrix
 	// that rotates the base vector of the object coordinate system at that time
 	// that rotates the base vector of the object coordinate system at that time
 	// to match the diff vector. 
 	// to match the diff vector. 
-	KeyIterator iter(objectPositions,targetPositions);
+	KeyIterator iter(objectPositions,targetPositions,&fixedMain);
 	unsigned int curTarget;
 	unsigned int curTarget;
 	for (;!iter.Finished();++iter)
 	for (;!iter.Finished();++iter)
 	{
 	{

+ 16 - 8
code/TargetAnimation.h

@@ -69,7 +69,7 @@ public:
 	 *  @param defaultTargetPos Default target position to be used if
 	 *  @param defaultTargetPos Default target position to be used if
 	 *	  no animated track is available. May be NULL.
 	 *	  no animated track is available. May be NULL.
 	 */
 	 */
-	KeyIterator(std::vector<aiVectorKey>* _objPos,
+	KeyIterator(const std::vector<aiVectorKey>* _objPos,
 		const std::vector<aiVectorKey>* _targetObjPos,
 		const std::vector<aiVectorKey>* _targetObjPos,
 		const aiVector3D*  defaultObjectPos = NULL,
 		const aiVector3D*  defaultObjectPos = NULL,
 		const aiVector3D*  defaultTargetPos = NULL);
 		const aiVector3D*  defaultTargetPos = NULL);
@@ -129,7 +129,8 @@ class ASSIMP_API TargetAnimationHelper
 public:
 public:
 
 
 	TargetAnimationHelper()
 	TargetAnimationHelper()
-		:	objectPositions		(NULL)
+		:	targetPositions		(NULL)
+		,	objectPositions		(NULL)
 	{}
 	{}
 
 
 
 
@@ -141,8 +142,8 @@ public:
 	 *
 	 *
 	 *  @param targetPositions Translation channel
 	 *  @param targetPositions Translation channel
 	 */
 	 */
-	void SetTargetAnimationChannel (
-		const std::vector<aiVectorKey>* targetPositions);
+	void SetTargetAnimationChannel (const 
+		std::vector<aiVectorKey>* targetPositions);
 
 
 
 
 	// ------------------------------------------------------------------
 	// ------------------------------------------------------------------
@@ -150,9 +151,16 @@ public:
 	 *
 	 *
 	 *  @param objectPositions Translation channel
 	 *  @param objectPositions Translation channel
 	 */
 	 */
-	void SetMainAnimationChannel (
+	void SetMainAnimationChannel ( const
 		std::vector<aiVectorKey>* objectPositions);
 		std::vector<aiVectorKey>* objectPositions);
 
 
+	// ------------------------------------------------------------------
+	/** Sets the main animation channel to a fixed value 
+	 *
+	 *  @param fixed Fixed value for the main animation channel
+	 */
+	void SetFixedMainAnimationChannel(const aiVector3D& fixed);
+
 
 
 	// ------------------------------------------------------------------
 	// ------------------------------------------------------------------
 	/** Computes final animation channels
 	/** Computes final animation channels
@@ -163,11 +171,11 @@ public:
 
 
 private:
 private:
 
 
-	const std::vector<aiVectorKey>* targetPositions;
-	std::vector<aiVectorKey> *objectPositions;
+	const std::vector<aiVectorKey>* targetPositions,*objectPositions;
+	aiVector3D fixedMain;
 };
 };
 
 
 
 
 } // ! end namespace Assimp
 } // ! end namespace Assimp
 
 
-#endif // include guard
+#endif // include guard

+ 457 - 434
code/TextureTransform.cpp

@@ -44,533 +44,556 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AssimpPCH.h"
 #include "AssimpPCH.h"
 #include "TextureTransform.h"
 #include "TextureTransform.h"
 
 
-namespace Assimp
-{
+using namespace Assimp;
+
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void TextureTransform::PreProcessUVTransform(
-	D3DS::Texture& rcIn)
+// Constructor to be privately used by Importer
+TextureTransformStep::TextureTransformStep()
 {
 {
-	char szTemp[512];
-	int iField;
+	// nothing to do here
+}
 
 
-	if (rcIn.mOffsetU)
-	{
-		if ((iField = (int)rcIn.mOffsetU))
-		{
-			if (aiTextureMapMode_Wrap == rcIn.mMapMode)
-			{
-				float fNew = rcIn.mOffsetU-(float)iField;
-				sprintf(szTemp,"[wrap] Found texture coordinate U offset %f. "
-					"This can be optimized to %f",rcIn.mOffsetU,fNew);
-	
-				DefaultLogger::get()->info(szTemp);
-				rcIn.mOffsetU = fNew;
-			}
-			else if (aiTextureMapMode_Mirror == rcIn.mMapMode)
-			{
-				if (0 != (iField % 2))iField--;
-				float fNew = rcIn.mOffsetU-(float)iField;
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+TextureTransformStep::~TextureTransformStep()
+{
+	// nothing to do here
+}
 
 
-				sprintf(szTemp,"[mirror] Found texture coordinate U offset %f. "
-					"This can be optimized to %f",rcIn.mOffsetU,fNew);
+// ------------------------------------------------------------------------------------------------
+// Returns whether the processing step is present in the given flag field.
+bool TextureTransformStep::IsActive( unsigned int pFlags) const
+{
+	return	(pFlags & aiProcess_TransformUVCoords) != 0;
+}
 
 
-				DefaultLogger::get()->info(szTemp);
-				rcIn.mOffsetU = fNew;
-			}
-			else if (aiTextureMapMode_Clamp == rcIn.mMapMode)
-			{
-				sprintf(szTemp,"[clamp] Found texture coordinate U offset %f. "
-					"This can be clamped to 1.0f",rcIn.mOffsetU);
+// ------------------------------------------------------------------------------------------------
+// Setup properties
+void TextureTransformStep::SetupProperties(const Importer* pImp)
+{
+	configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL);
+}
 
 
-				DefaultLogger::get()->info(szTemp);
-				rcIn.mOffsetU = 1.0f;
-			}
-		}
-	}
-	if (rcIn.mOffsetV)
-	{
-		if ((iField = (int)rcIn.mOffsetV))
-		{
-			if (aiTextureMapMode_Wrap == rcIn.mMapMode)
-			{
-				float fNew = rcIn.mOffsetV-(float)iField;
-				sprintf(szTemp,"[wrap] Found texture coordinate V offset %f. "
-					"This can be optimized to %f",rcIn.mOffsetV,fNew);
+// ------------------------------------------------------------------------------------------------
+void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
+{
+	/*  This function tries to simplify the input UV transformation.
+	 *  That's very important as it allows us to reduce the number 
+	 *  of output UV channels. The oder in which the transformations
+	 *  are applied is - as always - scaling, rotation, translation.
+	 */
 
 
-				DefaultLogger::get()->info(szTemp);
-				rcIn.mOffsetV = fNew;
-			}
-			else if (aiTextureMapMode_Mirror == rcIn.mMapMode)
-			{
-				if (0 != (iField % 2))iField--;
-				float fNew = rcIn.mOffsetV-(float)iField;
+	char szTemp[512];
+	int rounded = 0;
 
 
-				sprintf(szTemp,"[mirror] Found texture coordinate V offset %f. "
-					"This can be optimized to %f",rcIn.mOffsetV,fNew);
-				
-				DefaultLogger::get()->info(szTemp);
-				rcIn.mOffsetV = fNew;
-			}
-			else if (aiTextureMapMode_Clamp == rcIn.mMapMode)
-			{
-				sprintf(szTemp,"[clamp] Found texture coordinate U offset %f. "
-					"This can be clamped to 1.0f",rcIn.mOffsetV);
 
 
-				DefaultLogger::get()->info(szTemp);
-				rcIn.mOffsetV = 1.0f;
-			}
-		}
-	}
-	if (rcIn.mRotation)
+	/* Optimize the rotation angle. That's slightly difficult as
+	 * we have an inprecise floating-point number (when comparing
+	 * UV transformations we'll take that into account by using
+	 * an epsilon of 5 degrees). If there is a rotation value, we can't
+	 * perform any further optimizations.
+	 */
+	if (info.mRotation)
 	{
 	{
-		if ((iField = (int)(rcIn.mRotation / 3.141592654f)))
+		float out = info.mRotation;
+		if ((rounded = (int)(info.mRotation / (float)AI_MATH_TWO_PI)))
 		{
 		{
-			float fNew = rcIn.mRotation-(float)iField*3.141592654f;
+			out -= rounded*(float)AI_MATH_PI;
 
 
-			sprintf(szTemp,"[wrap] Found texture coordinate rotation %f. "
-				"This can be optimized to %f",rcIn.mRotation,fNew);
+			sprintf(szTemp,"Texture coordinate rotation %f can "
+				"be simplified to %f",info.mRotation,out);
 			DefaultLogger::get()->info(szTemp);
 			DefaultLogger::get()->info(szTemp);
-
-			rcIn.mRotation = fNew;
 		}
 		}
+
+		// Next step - convert negative rotation angles to positives
+		if (out < 0.f)
+			out = (float)AI_MATH_TWO_PI * 2 + out;
+
+		info.mRotation = out;
+		return;
 	}
 	}
-	return;
-}
-// ------------------------------------------------------------------------------------------------
-void TextureTransform::AddToList(std::vector<STransformVecInfo>& rasVec,
-	D3DS::Texture* pcTex)
-{
-	// check whether the texture is existing
-	if (0 == pcTex->mMapName.length())return;
 
 
-	// search for an identical transformation in our list
-	for (std::vector<STransformVecInfo>::iterator
-		i =  rasVec.begin();
-		i != rasVec.end();++i)
+	float absTranslationX = info.mScaling.x * info.mTranslation.x;
+	float absTranslationY = info.mScaling.y * info.mTranslation.y;
+
+	/* Optimize UV translation in the U direction. To determine whether
+	 * or not we can optimize we need to look at the requested mapping
+	 * type (e.g. if mirroring is active there IS a difference between
+	 * offset 2 and 3)
+	 */
+	if ((rounded  = (int)absTranslationX))
 	{
 	{
-		if ((*i).fOffsetU == pcTex->mOffsetU &&
-			(*i).fOffsetV == pcTex->mOffsetV && 
-			(*i).fScaleU  == pcTex->mScaleU  &&
-			(*i).fScaleV  == pcTex->mScaleV  &&
-			(*i).fRotation == pcTex->mRotation &&
-			(*i).iUVIndex == (unsigned int)pcTex->iUVSrc)
+		float out;
+		szTemp[0] = 0;
+		if (aiTextureMapMode_Wrap == info.mapU)
 		{
 		{
-			(*i).pcTextures.push_back(pcTex);
-			return;
+			// Wrap - simple take the fraction of the field
+			out = (absTranslationX-(float)rounded) / info.mScaling.x;
+			sprintf(szTemp,"[w] UV U offset %f can "
+				"be simplified to %f",info.mTranslation.x,out);
 		}
 		}
-	}
-	// this is a new transformation, so add it to the list
-	STransformVecInfo sInfo;
-	sInfo.fScaleU = pcTex->mScaleU;
-	sInfo.fScaleV = pcTex->mScaleV;
-	sInfo.fOffsetU = pcTex->mOffsetU;
-	sInfo.fOffsetV = pcTex->mOffsetV;
-	sInfo.fRotation = pcTex->mRotation;
-	sInfo.iUVIndex = pcTex->iUVSrc;
-
-	// add the texture to the list
-	sInfo.pcTextures.push_back(pcTex);
-
-	// and add the transformation itself to the second list
-	rasVec.push_back(sInfo);
-}
-// ------------------------------------------------------------------------------------------------
-void TextureTransform::ApplyScaleNOffset(D3DS::Material& material)
-{
-	unsigned int iCnt = 0;
-	D3DS::Texture* pcTexture = NULL;
-
-	// diffuse texture
-	if (material.sTexDiffuse.mMapName.length())
-	{
-		PreProcessUVTransform(material.sTexDiffuse);
-		if (HasUVTransform(material.sTexDiffuse))
+		else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded)
 		{
 		{
-			material.sTexDiffuse.bPrivate = true;
-			pcTexture = &material.sTexDiffuse;
-			++iCnt;
+			// Mirror 
+			if (rounded % 2)rounded--;
+			out = (absTranslationX-(float)rounded) / info.mScaling.x;
+
+			sprintf(szTemp,"[m/d] UV U offset %f can "
+				"be simplified to %f",info.mTranslation.x,out);
 		}
 		}
-	}
-	// specular texture
-	if (material.sTexSpecular.mMapName.length())
-	{
-		PreProcessUVTransform(material.sTexSpecular);
-		if (HasUVTransform(material.sTexSpecular))
+		else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU)
 		{
 		{
-			material.sTexSpecular.bPrivate = true;
-			pcTexture = &material.sTexSpecular;
-			++iCnt;
+			// Clamp - translations beyond 1,1 are senseless
+			sprintf(szTemp,"[c] UV U offset %f can "
+				"be clamped to 1.0f",info.mTranslation.x);
+
+			out = 1.f;
 		}
 		}
-	}
-	// ambient texture
-	if (material.sTexAmbient.mMapName.length())
-	{
-		PreProcessUVTransform(material.sTexAmbient);
-		if (HasUVTransform(material.sTexAmbient))
+		if (szTemp[0])
 		{
 		{
-			material.sTexAmbient.bPrivate = true;
-			pcTexture = &material.sTexAmbient;
-			++iCnt;
+			DefaultLogger::get()->info(szTemp);
+			info.mTranslation.x = out;
 		}
 		}
 	}
 	}
-	// emissive texture
-	if (material.sTexEmissive.mMapName.length())
+
+	/* Optimize UV translation in the V direction. To determine whether
+	 * or not we can optimize we need to look at the requested mapping
+	 * type (e.g. if mirroring is active there IS a difference between
+	 * offset 2 and 3)
+	 */
+	if ((rounded  = (int)absTranslationY))
 	{
 	{
-		PreProcessUVTransform(material.sTexEmissive);
-		if (HasUVTransform(material.sTexEmissive))
+		float out;
+		szTemp[0] = 0;
+		if (aiTextureMapMode_Wrap == info.mapV)
 		{
 		{
-			material.sTexEmissive.bPrivate = true;
-			pcTexture = &material.sTexEmissive;
-			++iCnt;
+			// Wrap - simple take the fraction of the field
+			out = (absTranslationY-(float)rounded) / info.mScaling.y;
+			sprintf(szTemp,"[w] UV V offset %f can "
+				"be simplified to %f",info.mTranslation.y,out);
 		}
 		}
-	}
-	// opacity texture
-	if (material.sTexOpacity.mMapName.length())
-	{
-		PreProcessUVTransform(material.sTexOpacity);
-		if (HasUVTransform(material.sTexOpacity))
+		else if (aiTextureMapMode_Mirror == info.mapV  && 1 != rounded)
 		{
 		{
-			material.sTexOpacity.bPrivate = true;
-			pcTexture = &material.sTexOpacity;
-			++iCnt;
+			// Mirror 
+			if (rounded % 2)rounded--;
+			out = (absTranslationY-(float)rounded) / info.mScaling.y;
+
+			sprintf(szTemp,"[m/d] UV V offset %f can "
+				"be simplified to %f",info.mTranslation.y,out);
 		}
 		}
-	}
-	// bump texture
-	if (material.sTexBump.mMapName.length())
-	{
-		PreProcessUVTransform(material.sTexBump);
-		if (HasUVTransform(material.sTexBump))
+		else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV)
 		{
 		{
-			material.sTexBump.bPrivate = true;
-			pcTexture = &material.sTexBump;
-			++iCnt;
+			// Clamp - translations beyond 1,1 are senseless
+			sprintf(szTemp,"[c] UV V offset %f can"
+				"be clamped to 1.0f",info.mTranslation.y);
+
+			out = 1.f;
 		}
 		}
-	}
-	// shininess texture
-	if (material.sTexShininess.mMapName.length())
-	{
-		PreProcessUVTransform(material.sTexShininess);
-		if (HasUVTransform(material.sTexShininess))
+		if (szTemp[0])
 		{
 		{
-			material.sTexBump.bPrivate = true;
-			pcTexture = &material.sTexShininess;
-			++iCnt;
+			DefaultLogger::get()->info(szTemp);
+			info.mTranslation.y = out;
 		}
 		}
 	}
 	}
-	if (0 != iCnt)
+	return;
+}
+
+// ------------------------------------------------------------------------------------------------
+void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n)
+{
+	// Don't set if == 0 && wasn't set before
+	for (std::list<TTUpdateInfo>::const_iterator it = l.begin();
+		 it != l.end(); ++it)
 	{
 	{
-		// if only one texture needs scaling/offset operations
-		// we can apply them directly to the first texture
-		// coordinate sets of all meshes referencing *this* material
-		// However, we can't do it  now. We need to wait until
-		// everything is sorted by materials.
-		if (1 == iCnt && 0 == pcTexture->iUVSrc)
+		const TTUpdateInfo& info = *it;
+
+		if (info.directShortcut)
+			*info.directShortcut = n;
+		else if (!n)
 		{
 		{
-			material.iBakeUVTransform = 1;
-			material.pcSingleTexture = pcTexture;
+			info.mat->AddProperty<int>((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index));
 		}
 		}
-		// we will need to generate a separate new texture channel
-		// for each texture. 
-		// However, we can't do it  now. We need to wait until
-		// everything is sorted by materials.
-		else material.iBakeUVTransform = 2;
 	}
 	}
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void TextureTransform::ApplyScaleNOffset(std::vector<D3DS::Material>& materials)
+inline const char* MappingModeToChar(aiTextureMapMode map)
 {
 {
-	unsigned int iNum = 0;
-	for (std::vector<D3DS::Material>::iterator
-		i =  materials.begin();
-		i != materials.end();++i,++iNum)
-	{
-		ApplyScaleNOffset(*i);
-	}
-	return;
+	if (aiTextureMapMode_Wrap == map)
+		return "-w";
+
+	if (aiTextureMapMode_Mirror == map)
+		return "-m";
+	
+	return "-c";
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void TextureTransform::BakeScaleNOffset(
-	aiMesh* pcMesh, D3DS::Material* pcSrc)
+void TextureTransformStep::Execute( aiScene* pScene) 
 {
 {
-	// NOTE: we don't use a texture matrix to do the transformation
-	// it is more efficient this way ... 
+	DefaultLogger::get()->debug("TransformUVCoordsProcess begin");
+	
 
 
-	if (!pcMesh->mTextureCoords[0])return;
-	if (0x1 == pcSrc->iBakeUVTransform)
+	/*  We build a per-mesh list of texture transformations we'll need
+	 *  to apply. To achieve this, we iterate through all materials, 
+	 *  find all textures and get their transformations and UV indices. 
+	 *  Then we search for all meshes using this material.
+	 */
+	typedef std::list<STransformVecInfo> MeshTrafoList;
+	std::vector<MeshTrafoList> meshLists(pScene->mNumMeshes);
+
+	for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
 	{
 	{
-		char szTemp[512];
-		int iLen;
-#if _MSC_VER >= 1400
-		iLen = ::sprintf_s(szTemp,
-#else
-		iLen = ::sprintf(szTemp,
-#endif
-			"Transforming existing UV channel. Source UV: %i" 
-			" OffsetU: %f" 
-			" OffsetV: %f" 
-			" ScaleU: %f" 
-			" ScaleV: %f" 
-			" Rotation (rad): %f",0,
-			pcSrc->pcSingleTexture->mOffsetU,
-			pcSrc->pcSingleTexture->mOffsetV,
-			pcSrc->pcSingleTexture->mScaleU,
-			pcSrc->pcSingleTexture->mScaleV,
-			pcSrc->pcSingleTexture->mRotation);
-
-		ai_assert(0 < iLen);
-		DefaultLogger::get()->info(std::string(szTemp,iLen));
-
-		if (!pcSrc->pcSingleTexture->mRotation)
+		aiMaterial* mat = pScene->mMaterials[i];
+		for (unsigned int a = 0; a < mat->mNumProperties;++a)
 		{
 		{
-			for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
+			aiMaterialProperty* prop = mat->mProperties[a];
+			if (!::strcmp( prop->mKey.data, "$tex.file"))
 			{
 			{
-				// scaling
-				pcMesh->mTextureCoords[0][i].x *= pcSrc->pcSingleTexture->mScaleU;
-				pcMesh->mTextureCoords[0][i].y *= pcSrc->pcSingleTexture->mScaleV;
+				STransformVecInfo info;
 
 
-				// offset
-				pcMesh->mTextureCoords[0][i].x += pcSrc->pcSingleTexture->mOffsetU;
-				pcMesh->mTextureCoords[0][i].y += pcSrc->pcSingleTexture->mOffsetV;
-			}
-		}
-		else
-		{
-			const float fSin = sinf(pcSrc->pcSingleTexture->mRotation);
-			const float fCos = cosf(pcSrc->pcSingleTexture->mRotation);
-			for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
-			{
-				// scaling
-				pcMesh->mTextureCoords[0][i].x *= pcSrc->pcSingleTexture->mScaleU;
-				pcMesh->mTextureCoords[0][i].y *= pcSrc->pcSingleTexture->mScaleV;
+				// Setup a shortcut structure to allow for a fast updating
+				// of the UV index later
+				TTUpdateInfo update;
+				update.mat = (MaterialHelper*) mat;
+				update.semantic = prop->mSemantic;
+				update.index = prop->mIndex;
+
+				// Get textured properties and transform
+				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.uvwsrc"))
+					{
+						info.uvIndex = *((int*)prop2->mData);
+
+						// Store a direct pointer for later use
+						update.directShortcut = (unsigned int*) &prop2->mData;
+					}
+
+					else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu"))
+						info.mapU = *((aiTextureMapMode*)prop2->mData);
+
+					else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev"))
+						info.mapV = *((aiTextureMapMode*)prop2->mData);
+
+					else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo"))
+					{
+						// ValidateDS should check this
+						ai_assert(prop2->mDataLength >= 20); 
 
 
-				// rotation
-				pcMesh->mTextureCoords[0][i].x *= fCos;
-				pcMesh->mTextureCoords[0][i].y *= fSin;
+						::memcpy(&info.mTranslation.x,prop2->mData,
+							sizeof(float)*5);
 
 
-				// offset
-				pcMesh->mTextureCoords[0][i].x += pcSrc->pcSingleTexture->mOffsetU;
-				pcMesh->mTextureCoords[0][i].y += pcSrc->pcSingleTexture->mOffsetV;
+						delete[] prop2->mData;
+
+						// Directly remove this property from the list 
+						mat->mNumProperties--;
+						for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3)
+							mat->mProperties[a3] = mat->mProperties[a3+1];
+
+						// Warn: could be an underflow, but nevertheless it should work
+						--a2; 
+					}
+				}
+
+				// Find out which transformations are to be evaluated
+				if (!(configFlags & AI_UVTRAFO_ROTATION))
+					info.mRotation = 0.f;
+
+				if (!(configFlags & AI_UVTRAFO_SCALING))
+					info.mScaling = aiVector2D(1.f,1.f);
+
+				if (!(configFlags & AI_UVTRAFO_TRANSLATION))
+					info.mTranslation = aiVector2D(0.f,0.f);
+
+				// Do some preprocessing
+				PreProcessUVTransform(info);
+				info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u);
+
+				// Find out whether this material is used by more than
+				// one mesh. This will make our task much, much more difficult!
+				unsigned int cnt = 0;
+				for (unsigned int n = 0; n < pScene->mNumMeshes;++n)
+				{
+					if (pScene->mMeshes[n]->mMaterialIndex == i)
+						++cnt;
+				}
+
+				if (!cnt)continue;
+				else if (1 != cnt)
+				{
+					// This material is referenced by more than one mesh!
+					// So we need to make sure the UV index for the texture
+					// is identical for each of it ...
+					info.lockedPos = AI_TT_UV_IDX_LOCK_TBD;
+				}
+
+				// Get all coresponding meshes
+				for (unsigned int n = 0; n < pScene->mNumMeshes;++n)
+				{
+					aiMesh* mesh = pScene->mMeshes[n];
+					if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0]) continue;
+
+					unsigned int uv = info.uvIndex;
+					if (!mesh->mTextureCoords[uv])
+					{
+						// If the requested UV index is not available,
+						// take the first one instead.
+						uv = 0;
+					}
+					
+					if (mesh->mNumUVComponents[info.uvIndex] >= 3)
+					{
+						DefaultLogger::get()->warn("UV transformations on 3D mapping channels "
+							"are not supported by this step");
+
+						continue;
+					}
+
+					MeshTrafoList::iterator it;
+
+					// Check whether we have this transform setup already
+					for (it = meshLists[n].begin();it != meshLists[n].end(); ++it)
+					{
+						if ((*it) == info && (*it).uvIndex == uv)
+						{
+							(*it).updateList.push_back(update);
+							break;
+						}
+					}
+					if (it == meshLists[n].end())
+					{
+						meshLists[n].push_back(info);
+						meshLists[n].back().uvIndex = uv;
+						meshLists[n].back().updateList.push_back(update);
+					}
+				}
 			}
 			}
 		}
 		}
 	}
 	}
-	else if (0x2 == pcSrc->iBakeUVTransform)
+
+	char buffer[1024]; // should be sufficiently large
+	unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0;
+
+	// Now process all meshes. Important: we don't remove unreferenced UV channels.
+	// This is a job for the RemoveUnreferencedData-Step.
+	for (unsigned int q = 0; q < pScene->mNumMeshes;++q)
 	{
 	{
-		// first save all texture coordinate sets
-		aiVector3D* apvOriginalSets[AI_MAX_NUMBER_OF_TEXTURECOORDS];
-		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
+		aiMesh* mesh = pScene->mMeshes[q];
+		MeshTrafoList& trafo =  meshLists[q];
+
+		inChannels += mesh->GetNumUVChannels();
+
+		if (!mesh->mTextureCoords[0] || trafo.empty() || 
+			trafo.size() == 1 && trafo.begin()->IsUntransformed())
 		{
 		{
-			apvOriginalSets[i] = pcMesh->mTextureCoords[i];
+			outChannels += mesh->GetNumUVChannels();
+			continue;
 		}
 		}
-		unsigned int iNextEmpty = 0;
-		while (pcMesh->mTextureCoords[++iNextEmpty]);
-
-		aiVector3D* apvOutputSets[AI_MAX_NUMBER_OF_TEXTURECOORDS];
-		for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
-			apvOutputSets[i] = NULL;
-
-		// now we need to find all textures in the material
-		// which require scaling/offset operations
-		std::vector<STransformVecInfo> sOps;
-		sOps.reserve(10);
-		TextureTransform::AddToList(sOps,&pcSrc->sTexDiffuse);
-		TextureTransform::AddToList(sOps,&pcSrc->sTexSpecular);
-		TextureTransform::AddToList(sOps,&pcSrc->sTexEmissive);
-		TextureTransform::AddToList(sOps,&pcSrc->sTexOpacity);
-		TextureTransform::AddToList(sOps,&pcSrc->sTexBump);
-		TextureTransform::AddToList(sOps,&pcSrc->sTexShininess);
-		TextureTransform::AddToList(sOps,&pcSrc->sTexAmbient);
-
-		// check the list and find out how many we won't be able
-		// to generate.
-		std::vector<STransformVecInfo*> sFilteredOps;
-		unsigned int iNumUntransformed = 0;
-		sFilteredOps.reserve(sOps.size());
+
+		// Move untransformed UV channels to the first
+		// position in the list .... except if we need
+		// a new locked index which should be as small as possible
+		bool veto = false;
+		unsigned int cnt = 0;
+		unsigned int untransformed = 0;
+
+		MeshTrafoList::iterator it,it2;
+		for (it = trafo.begin();it != trafo.end(); ++it,++cnt)
 		{
 		{
-			std::vector<STransformVecInfo*> sWishList;
-			sWishList.reserve(sOps.size());
-			for (unsigned int iUV = 0; iUV < AI_MAX_NUMBER_OF_TEXTURECOORDS;++iUV)
+			if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD)
 			{
 			{
-				for (std::vector<STransformVecInfo>::iterator
-					i =  sOps.begin();
-					i != sOps.end();++i)
-				{
-					if (iUV != (*i).iUVIndex)continue;
-					if ((*i).IsUntransformed())
-					{
-						sFilteredOps.push_back(&(*i));
-					}
-					else sWishList.push_back(&(*i));
-				}
+				// Lock this index and make sure it won't be changed
+				(*it).lockedPos = cnt;
+				veto = true;
+				continue;
 			}
 			}
-			// are we able to generate all?
-			const int iDiff = AI_MAX_NUMBER_OF_TEXTURECOORDS-(int)
-				(sWishList.size()+sFilteredOps.size());
 
 
-			iNumUntransformed  = (unsigned int)sFilteredOps.size();
-			if (0 >= iDiff)
+			if (!veto && it != trafo.begin() && (*it).IsUntransformed())
 			{
 			{
-				DefaultLogger::get()->warn("There are too many combinations of different "
-					"UV transformation operations to generate an own UV channel for each "
-					"(maximum is AI_MAX_NUMBER_OF_TEXTURECOORDS = 4 or 6). "
-					"An untransformed UV channel will be used for all remaining transformations");
-				
-				std::vector<STransformVecInfo*>::const_iterator nash =  sWishList.begin();
-				for (;nash != sWishList.end()-iDiff;++nash)
-				{
-					sFilteredOps.push_back(*nash);
-				}
+				trafo.push_front((*it));
+				trafo.erase(it);
+
+				break;
 			}
 			}
-			else
+		}
+
+		// Find all that are not at their 'locked' position 
+		// and move them to it. Conflicts are possible but
+		// quite unlikely.
+		cnt = 0;
+		for (it = trafo.begin();it != trafo.end(); ++it,++cnt)
+		{
+			if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt)
 			{
 			{
-				for (std::vector<STransformVecInfo*>::const_iterator
-					nash =  sWishList.begin();
-					nash != sWishList.end();++nash)sFilteredOps.push_back(*nash);
+				it2 = trafo.begin();unsigned int t = 0;
+				while (t != (*it).lockedPos)++it2;
+
+				if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE)
+				{
+					DefaultLogger::get()->error("Channel mismatch, can't compute all transformations properly");
+					continue;
+				}
+
+				std::swap(*it2,*it);
+				if ((*it).lockedPos == untransformed)untransformed = cnt;
 			}
 			}
 		}
 		}
 
 
-		// now fill in all output IV indices
-		unsigned int iNum = 0;
-		for (std::vector<STransformVecInfo*>::iterator
-			bogart =  sFilteredOps.begin();
-			bogart != sFilteredOps.end();++bogart,++iNum)
+		// ... and add dummies for all unreferenced channels
+		// at the end of the list
+		bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+		for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
+			ref[n] = (!mesh->mTextureCoords[n] ? true : false);
+
+		for (it = trafo.begin();it != trafo.end(); ++it)
+			ref[(*it).uvIndex] = true;
+
+		for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
 		{
 		{
-			(**bogart).iUVIndex = iNum;
+			if (ref[n])continue;
+			trafo.push_back(STransformVecInfo());
+			trafo.back().uvIndex = n;
 		}
 		}
 
 
-		iNum = 0;
-		for (; iNum < iNumUntransformed; ++iNum)
-			pcMesh->mTextureCoords[iNum] = apvOriginalSets[iNum];
-
-		// now generate the texture coordinate sets
-		for (std::vector<STransformVecInfo*>::iterator
-			i =  sFilteredOps.begin()+iNumUntransformed;
-			i != sFilteredOps.end();++i,++iNum)
+		// Then check whether this list breaks the channel limit.
+		// The unimportant ones are at the end of the list, so
+		// it shouldn't be too worse if we remove them.
+		unsigned int size = (unsigned int)trafo.size();
+		if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS)
 		{
 		{
-			const aiVector3D* _pvBase = apvOriginalSets[(**i).iUVIndex];
-			aiVector3D* _pvOut = new aiVector3D[pcMesh->mNumVertices];
-			pcMesh->mTextureCoords[iNum] = _pvOut;
-
-			char szTemp[512];
-			int iLen;
-#if _MSC_VER >= 1400
-			iLen = ::sprintf_s(szTemp,
-#else
-			iLen = ::sprintf(szTemp,
-#endif
-				"Generating additional UV channel. Source UV: %i" 
-				" OffsetU: %f" 
-				" OffsetV: %f" 
-				" ScaleU: %f" 
-				" ScaleV: %f" 
-				" Rotation (rad): %f",0,
-				(**i).fOffsetU,
-				(**i).fOffsetV,
-				(**i).fScaleU,
-				(**i).fScaleV,
-				(**i).fRotation);
-			ai_assert(0 < iLen);
-			DefaultLogger::get()->info(std::string(szTemp,iLen));
-
-			const aiVector3D* pvBase = _pvBase;
-			aiVector3D* pvOut = _pvOut;
-			if (0.0f == (**i).fRotation)
+			if (!DefaultLogger::isNullLogger())
 			{
 			{
-				for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
-				{
-					// scaling
-					pvOut->x = pvBase->x * (**i).fScaleU;
-					pvOut->y = pvBase->y * (**i).fScaleV;
-
-					// offset
-					pvOut->x += (**i).fOffsetU;
-					pvOut->y += (**i).fOffsetV;
+				::sprintf(buffer,"%i UV channels required but just %i available", 
+					trafo.size(),AI_MAX_NUMBER_OF_TEXTURECOORDS);
 
 
-					pvBase++;
-					pvOut++;
-				}
+				DefaultLogger::get()->error(buffer);
 			}
 			}
-			else
-			{
-				const float fSin = sinf((**i).fRotation);
-				const float fCos = cosf((**i).fRotation);
-				for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
-				{
-					// scaling
-					pvOut->x = pvBase->x * (**i).fScaleU;
-					pvOut->y = pvBase->y * (**i).fScaleV;
+			size = AI_MAX_NUMBER_OF_TEXTURECOORDS;
+		}
 
 
-					// rotation
-					pvOut->x *= fCos;
-					pvOut->y *= fSin;
 
 
-					// offset
-					pvOut->x += (**i).fOffsetU;
-					pvOut->y += (**i).fOffsetV;
+		aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS];
+		for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
+			old[n] = mesh->mTextureCoords[n];
 
 
-					pvBase++;
-					pvOut++;
-				}
+		// Now continue and generate the output channels. Channels
+		// that we're not going to need later can be overridden.
+		it = trafo.begin();
+		for (unsigned int n = 0; n < trafo.size();++n,++it)
+		{
+			if (n >= size)
+			{
+				// Try to use an untransformed channel for all channels we threw over board
+				UpdateUVIndex((*it).updateList,untransformed);
+				continue;
 			}
 			}
-		}
 
 
-		// now check which source texture coordinate sets
-		// can be deleted because they're not anymore required
-		for (iNum = 0; iNum < AI_MAX_NUMBER_OF_TEXTURECOORDS;++iNum)
-		{
-			for (unsigned int z = 0; z < iNumUntransformed;++z)
+			outChannels++;
+
+			// Write to the log
+			if (!DefaultLogger::isNullLogger())
+			{
+				sprintf(buffer,"Mesh %i, channel %i: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s",
+					q,n,
+					(*it).mTranslation.x,
+					(*it).mTranslation.y,
+					(*it).mScaling.x,
+					(*it).mScaling.y,
+					AI_RAD_TO_DEG( (*it).mRotation),
+					MappingModeToChar ((*it).mapU),
+					MappingModeToChar ((*it).mapV));
+
+				DefaultLogger::get()->info(buffer);
+			}
+
+			// Check whether we need a new buffer here
+			if (mesh->mTextureCoords[n])
 			{
 			{
-				if (apvOriginalSets[iNum] == pcMesh->mTextureCoords[z])
+				it2 = it;++it2;
+				for (unsigned int m = n+1; m < size;++m, ++it2)
 				{
 				{
-					apvOriginalSets[iNum] = NULL;
-					break;
+					if ((*it2).uvIndex == n)
+					{
+						it2 = trafo.begin();
+						break;
+					}
 				}
 				}
+				if (it2 == trafo.begin())
+				{
+					mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
+				} 
 			}
 			}
-			if (apvOriginalSets[iNum])delete[] apvOriginalSets[iNum];
-		}
-	}
+			else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
 
 
-	// setup bitflags to indicate which texture coordinate
-	// channels are used (this class works for 2d texture coordinates only)
+			aiVector3D* src = old[(*it).uvIndex];
+			aiVector3D* dest, *end;
+			dest = mesh->mTextureCoords[n];
 
 
-	unsigned int iIndex = 0;
-	while (pcMesh->HasTextureCoords(iIndex))pcMesh->mNumUVComponents[iIndex++] = 2;
-	return;
-}
-// ------------------------------------------------------------------------------------------------
-void TextureTransform::SetupMatUVSrc (aiMaterial* pcMat, const D3DS::Material* pcMatIn)
-{
-	ai_assert(NULL != pcMat);
-	ai_assert(NULL != pcMatIn);
-	
-	MaterialHelper* pcHelper = (MaterialHelper*)pcMat;
+			ai_assert(NULL != src);
+
+			// Copy the data to the destination array
+			if (dest != src)
+				::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
 
 
-	if(pcMatIn->sTexDiffuse.mMapName.length() > 0)
-		pcHelper->AddProperty<int>(&pcMatIn->sTexDiffuse.iUVSrc,1,
-			AI_MATKEY_UVWSRC_DIFFUSE(0));
+			end = dest + mesh->mNumVertices;
+
+			// Build a transformation matrix and transform all UV coords with it
+			if (!(*it).IsUntransformed())
+			{
+				const aiVector2D& trl = (*it).mTranslation;
+				const aiVector2D& scl = (*it).mScaling;
+
+				++transformedChannels;
+				aiMatrix3x3 matrix;
+
+				aiMatrix3x3 m2,m3,m4,m5;
+
+				m4.a1 = scl.x;
+				m4.b2 = scl.y;
+				
+				m2.a3 = m2.b3 = 0.5f;
+				m3.a3 = m3.b3 = -0.5f;
 
 
-	if(pcMatIn->sTexSpecular.mMapName.length() > 0)
-		pcHelper->AddProperty<int>(&pcMatIn->sTexSpecular.iUVSrc,1,
-			AI_MATKEY_UVWSRC_SPECULAR(0));
+				if ((*it).mRotation > AI_TT_ROTATION_EPSILON )
+					aiMatrix3x3::Rotation((*it).mRotation,matrix);
 
 
-	if(pcMatIn->sTexEmissive.mMapName.length() > 0)
-		pcHelper->AddProperty<int>(&pcMatIn->sTexEmissive.iUVSrc,1,
-			AI_MATKEY_UVWSRC_EMISSIVE(0));
+				m5.a3 += trl.x; m5.b3 += trl.y;
+				matrix = m2 * m4 * matrix * m3 * m5;
+				
 
 
-	if(pcMatIn->sTexBump.mMapName.length() > 0)
-		pcHelper->AddProperty<int>(&pcMatIn->sTexBump.iUVSrc,1,
-			AI_MATKEY_UVWSRC_HEIGHT(0));
+				for (src = dest; src != end; ++src)
+				{
+					src->z = 1.f;
+					*src = matrix * *src;
+					src->x /= src->z;
+					src->y /= src->z;
+					src->z = 0.f;
+				}
+			}
 
 
-	if(pcMatIn->sTexShininess.mMapName.length() > 0)
-		pcHelper->AddProperty<int>(&pcMatIn->sTexShininess.iUVSrc,1,
-			AI_MATKEY_UVWSRC_SHININESS(0));
+			// Update all UV indices
+			UpdateUVIndex((*it).updateList,n);
+		}
+	}
 
 
-	if(pcMatIn->sTexOpacity.mMapName.length() > 0)
-		pcHelper->AddProperty<int>(&pcMatIn->sTexOpacity.iUVSrc,1,
-			AI_MATKEY_UVWSRC_OPACITY(0));
+	// Print some detailled statistics into the log
+	if (!DefaultLogger::isNullLogger())
+	{
+		if (transformedChannels)
+		{
+			::sprintf(buffer,"TransformUVCoordsProcess end: %i output channels (in: %i, modified: %i)",
+				outChannels,inChannels,transformedChannels);
 
 
-	if(pcMatIn->sTexAmbient.mMapName.length() > 0)
-		pcHelper->AddProperty<int>(&pcMatIn->sTexAmbient.iUVSrc,1,
-			AI_MATKEY_UVWSRC_AMBIENT(0));
+			DefaultLogger::get()->info(buffer);
+		}
+		else DefaultLogger::get()->debug("TransformUVCoordsProcess finished");
+	}
 }
 }
-};
+
+

+ 111 - 93
code/TextureTransform.h

@@ -38,56 +38,107 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
-/** @file Definition of a helper class that processes texture transformations */
+/** @file Definition of a helper step that processes texture transformations */
 #ifndef AI_TEXTURE_TRANSFORM_H_INCLUDED
 #ifndef AI_TEXTURE_TRANSFORM_H_INCLUDED
 #define AI_TEXTURE_TRANSFORM_H_INCLUDED
 #define AI_TEXTURE_TRANSFORM_H_INCLUDED
 
 
 #include "BaseImporter.h"
 #include "BaseImporter.h"
-#include "../include/aiTypes.h"
-#include "../include/aiMaterial.h"
-#include "../include/aiMesh.h"
-
+#include "BaseProcess.h"
 
 
 struct aiNode;
 struct aiNode;
-#include "3DSHelper.h"
 
 
-namespace Assimp
+namespace Assimp	{
+
+#define AI_TT_UV_IDX_LOCK_TBD	0xffffffff
+#define AI_TT_UV_IDX_LOCK_NONE	0xeeeeeeee
+
+
+#define AI_TT_ROTATION_EPSILON	((float)AI_DEG_TO_RAD(0.5))
+
+// ---------------------------------------------------------------------------
+/** Small helper structure representing a shortcut into the material list
+ *  to be able to update some values quickly.
+*/
+struct TTUpdateInfo
 {
 {
+	TTUpdateInfo()
+		:	mat				(NULL)
+		,	directShortcut	(NULL)
+		,	semantic		(0)
+		,	index			(0)
+	{}
+
+	//! Direct shortcut, if available
+	unsigned int* directShortcut;
+
+	//! Material 
+	MaterialHelper* mat;
+
+	//! Texture type and index
+	unsigned int semantic, index;
+};
 
 
-using namespace Assimp::D3DS;
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper class representing texture coordinate transformations
 /** Helper class representing texture coordinate transformations
 */
 */
-struct STransformVecInfo 
+struct STransformVecInfo : public aiUVTransform
 {
 {
-	//! Construction. The resulting matrix is the identity
-	STransformVecInfo ()
-		: 
-		fScaleU(1.0f),fScaleV(1.0f),
-		fOffsetU(0.0f),fOffsetV(0.0f),
-		fRotation(0.0f),
-		iUVIndex(0)
-	{}
 
 
-	//! Texture coordinate scaling in the x-direction 
-	float fScaleU;
-	//! Texture coordinate scaling in the y-direction 
-	float fScaleV;
-	//! Texture coordinate offset in the x-direction
-	float fOffsetU;
-	//! Texture coordinate offset in the y-direction
-	float fOffsetV;
-	//! Texture coordinate rotation, clockwise, in radians
-	float fRotation;
+	STransformVecInfo()
+		:	uvIndex		(0)
+		,	mapU		(aiTextureMapMode_Wrap)
+		,	mapV		(aiTextureMapMode_Wrap)
+		,	lockedPos	(AI_TT_UV_IDX_LOCK_NONE)
+	{}
 
 
 	//! Source texture coordinate index
 	//! Source texture coordinate index
-	unsigned int iUVIndex;
+	unsigned int uvIndex;
+
+	//! Texture mapping mode in the u, v direction
+	aiTextureMapMode mapU,mapV;
+
+	//! Locked destination UV index
+	//! AI_TT_UV_IDX_LOCK_TBD - to be determined
+	//! AI_TT_UV_IDX_LOCK_NONE - none (default)
+	unsigned int lockedPos;
+
+	//! Update info - shortcuts into all materials
+	//! that are referencing this transform setup
+	std::list<TTUpdateInfo> updateList;
+
+
+	// -------------------------------------------------------------------
+	/** Compare two transform setups
+	*/
+	inline bool operator== (const STransformVecInfo& other) const
+	{
+		// We use a small epsilon here
+		const float epsilon = 0.05f;
+
+		if (fabs( mTranslation.x - other.mTranslation.x ) > epsilon ||
+			fabs( mTranslation.y - other.mTranslation.y ) > epsilon)
+		{
+			return false;
+		}
+
+		if (fabs( mScaling.x - other.mScaling.x ) > epsilon ||
+			fabs( mScaling.y - other.mScaling.y ) > epsilon)
+		{
+			return false;
+		}
 
 
+		if (fabs( mRotation - other.mRotation) > epsilon)
+		{
+			return false;
+		}
+		return true;
+	}
 
 
-	//! List of all textures that use this texture
-	//! coordinate transformations
-	std::vector<D3DS::Texture*> pcTextures; 
+	inline bool operator!= (const STransformVecInfo& other) const
+	{
+			return !(*this == other);
+	}
 
 
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
@@ -95,8 +146,9 @@ struct STransformVecInfo
 	*/
 	*/
 	inline bool IsUntransformed() const
 	inline bool IsUntransformed() const
 	{
 	{
-		return 1.0f == fScaleU && 1.0f == fScaleV &&
-			!fOffsetU && !fOffsetV && !fRotation;
+		return (1.0f == mScaling.x && 1.f == mScaling.y &&
+			!mTranslation.x && !mTranslation.y && 
+			mRotation < AI_TT_ROTATION_EPSILON);
 	}
 	}
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
@@ -106,26 +158,26 @@ struct STransformVecInfo
 	{
 	{
 		mOut = aiMatrix3x3();
 		mOut = aiMatrix3x3();
 
 
-		if (1.0f != this->fScaleU || 1.0f != this->fScaleV)
+		if (1.0f != mScaling.x || 1.0f != mScaling.y)
 		{
 		{
 			aiMatrix3x3 mScale;
 			aiMatrix3x3 mScale;
-			mScale.a1 = this->fScaleU;
-			mScale.b2 = this->fScaleV;
+			mScale.a1 = mScaling.x;
+			mScale.b2 = mScaling.y;
 			mOut = mScale;
 			mOut = mScale;
 		}
 		}
-		if (this->fRotation)
+		if (mRotation)
 		{
 		{
 			aiMatrix3x3 mRot; 
 			aiMatrix3x3 mRot; 
-			mRot.a1 = mRot.b2 = cosf(this->fRotation);
-			mRot.a2 = mRot.b1 = sinf(this->fRotation);
+			mRot.a1 = mRot.b2 = cos(mRotation);
+			mRot.a2 = mRot.b1 = sin(mRotation);
 			mRot.a2 = -mRot.a2;
 			mRot.a2 = -mRot.a2;
 			mOut *= mRot;
 			mOut *= mRot;
 		}
 		}
-		if (this->fOffsetU || this->fOffsetV)
+		if (mTranslation.x || mTranslation.y)
 		{
 		{
 			aiMatrix3x3 mTrans; 
 			aiMatrix3x3 mTrans; 
-			mTrans.a3 = this->fOffsetU;
-			mTrans.b3 = this->fOffsetV;
+			mTrans.a3 = mTranslation.x;
+			mTrans.b3 = mTranslation.y;
 			mOut *= mTrans;
 			mOut *= mTrans;
 		}
 		}
 	}
 	}
@@ -133,73 +185,39 @@ struct STransformVecInfo
 
 
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** Helper class used by the ASE/ASK and 3DS loaders to handle texture
- *  coordinate transformations correctly (such as offsets, scaling)
+/** Helper step to compute final UV coordinate sets if there are scalings
+ *  or rotations in the original data read from the file.
 */
 */
-class ASSIMP_API TextureTransform
+class ASSIMP_API TextureTransformStep : public BaseProcess
 {
 {
-	//! Constructor, it is not possible to create instances of this class
-	TextureTransform() {}
 public:
 public:
 
 
+	TextureTransformStep();
+	~TextureTransformStep();
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	/** Returns true if a texture requires UV transformations
-	 * \param rcIn Input texture
-	*/
-	inline static bool HasUVTransform(
-		const D3DS::Texture& rcIn)
-	{
-		return (rcIn.mOffsetU || rcIn.mOffsetV ||
-			1.0f != rcIn.mScaleU  ||  1.0f != rcIn.mScaleV || rcIn.mRotation);
-	}
+	bool IsActive( unsigned int pFlags) const;
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	/** Must be called before HasUVTransform(rcIn) is called 
-	 * \param rcIn Input texture
-	*/
-	static void PreProcessUVTransform(
-		D3DS::Texture& rcIn);
+	void Execute( aiScene* pScene);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	/** Check whether the texture coordinate transformation of
-	 *  a texture is already contained in a given list
-	 * \param rasVec List of transformations
-	 * \param pcTex Pointer to the texture
-	*/
-	static void AddToList(std::vector<STransformVecInfo>& rasVec,
-		D3DS::Texture* pcTex);
+	void SetupProperties(const Importer* pImp);
 
 
-	// -------------------------------------------------------------------
-	/** Get a full list of all texture coordinate offsets required
-	 *  for a material
-	 * \param materials List of materials to be processed
-	*/
-	static void ApplyScaleNOffset(std::vector<D3DS::Material>& materials);
 
 
-	// -------------------------------------------------------------------
-	/** Get a full list of all texture coordinate offsets required
-	 *  for a material
-	 * \param material Material to be processed
-	*/
-	static void ApplyScaleNOffset(D3DS::Material& material);
+protected:
 
 
-	// -------------------------------------------------------------------
-	/** Precompute as many texture coordinate transformations as possible
-	 * \param pcMesh Mesh containing the texture coordinate data
-	 * \param pcSrc Input material. Must have been passed to
-	 * ApplyScaleNOffset
-	*/
-	static void BakeScaleNOffset(aiMesh* pcMesh, D3DS::Material* pcSrc);
 
 
-	
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	/** Setup the correct UV source for a material
-	 * \param pcMat Final material to be changed
-	 * \param pcMatIn Input material, unconverted
+	/** Preprocess a specific UV transformation setup
+	 *
+	 *  @param info Transformation setup to be preprocessed.
 	*/
 	*/
-	static void SetupMatUVSrc (aiMaterial* pcMat, 
-		const D3DS::Material* pcMatIn);
+	void PreProcessUVTransform(STransformVecInfo& info);
+
+private:
+
+	unsigned int configFlags;
 };
 };
 
 
 }
 }

+ 117 - 95
code/ValidateDataStructure.cpp

@@ -418,7 +418,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
 		{
 		{
 			if (face.mIndices[a] >= pMesh->mNumVertices)
 			if (face.mIndices[a] >= pMesh->mNumVertices)
 			{
 			{
-				this->ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
+				ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
 			}
 			}
 			// the MSB flag is temporarily used by the extra verbose
 			// the MSB flag is temporarily used by the extra verbose
 			// mode to tell us that the JoinVerticesProcess might have 
 			// mode to tell us that the JoinVerticesProcess might have 
@@ -523,6 +523,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
 		ReportError("aiMesh::mBones is non-null although there are no bones");
 		ReportError("aiMesh::mBones is non-null although there are no bones");
 	}
 	}
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::Validate( const aiMesh* pMesh,
 void ValidateDSProcess::Validate( const aiMesh* pMesh,
 	const aiBone* pBone,float* afSum)
 	const aiBone* pBone,float* afSum)
@@ -548,6 +549,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh,
 		afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight;
 		afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight;
 	}
 	}
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
 void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
 {
 {
@@ -576,36 +578,54 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
 	// Animation duration is allowed to be zero in cases where the anim contains only a single key frame.
 	// Animation duration is allowed to be zero in cases where the anim contains only a single key frame.
 	// if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero");
 	// if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero");
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
 void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
-	const char* szType)
+	aiTextureType type)
 {
 {
-	ai_assert(NULL != szType);
+	const char* szType;
+	switch (type)
+	{
+	case aiTextureType_DIFFUSE:
+		szType = "Diffuse";break;
 
 
-	// search all keys of the material ...
-	// textures must be specified with rising indices (e.g. diffuse #2 may not be
-	// specified if diffuse #1 is not there ...)
+	case aiTextureType_SPECULAR:
+		szType = "Specular";break;
 
 
-	// "$tex.file.<szType>[<index>]"
-	char szBaseBuf[512];
-	int iLen;
-	iLen = ::sprintf(szBaseBuf,"$tex.file.%s",szType);
-	if (0 >= iLen)return;
+	case aiTextureType_AMBIENT:
+		szType = "Ambient";break;
+
+	case aiTextureType_EMISSIVE:
+		szType = "Emissive";break;
+
+	case aiTextureType_OPACITY:
+		szType = "Opacity";break;
+
+	case aiTextureType_SHININESS:
+		szType = "Shininess";break;
+
+	case aiTextureType_NORMALS:
+		szType = "Normals";break;
+
+	case aiTextureType_HEIGHT:
+		szType = "Height";break;
+	};
+
+	// ****************************************************************************
+	// Search all keys of the material ...
+	// textures must be specified with ascending indices 
+	// (e.g. diffuse #2 may not be specified if diffuse #1 is not there ...)
+	// ****************************************************************************
 
 
 	int iNumIndices = 0;
 	int iNumIndices = 0;
 	int iIndex = -1;
 	int iIndex = -1;
 	for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
 	for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
 	{
 	{
 		aiMaterialProperty* prop = pMaterial->mProperties[i];
 		aiMaterialProperty* prop = pMaterial->mProperties[i];
-		if (0 == ASSIMP_strincmp( prop->mKey.data, szBaseBuf, iLen ))
+		if (!::strcmp(prop->mKey.data,"$tex.file") && prop->mSemantic == type)
 		{
 		{
-			const char* sz = &prop->mKey.data[iLen];
-			if (*sz)
-			{
-				++sz;
-				iIndex = std::max(iIndex, (int)strtol10(sz,0));
-				++iNumIndices;
-			}
+			iIndex = std::max(iIndex, (int) prop->mIndex);
+			++iNumIndices;
 
 
 			if (aiPTI_String != prop->mType)
 			if (aiPTI_String != prop->mType)
 				this->ReportError("Material property %s is expected to be a string",prop->mKey.data);
 				this->ReportError("Material property %s is expected to be a string",prop->mKey.data);
@@ -613,52 +633,73 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
 	}
 	}
 	if (iIndex +1 != iNumIndices)
 	if (iIndex +1 != iNumIndices)
 	{
 	{
-		this->ReportError("%s #%i is set, but there are only %i %s textures",
+		ReportError("%s #%i is set, but there are only %i %s textures",
 			szType,iIndex,iNumIndices,szType);
 			szType,iIndex,iNumIndices,szType);
 	}
 	}
 	if (!iNumIndices)return;
 	if (!iNumIndices)return;
 
 
-	// now check whether all UV indices are valid ...
-	iLen = ::sprintf(szBaseBuf,"$tex.uvw.%s",szType);
-	if (0 >= iLen)return;
+	// TODO: check whether the mappings are correctly
+	std::vector<aiTextureMapping> mappings(iNumIndices);
 
 
+	// Now check whether all UV indices are valid ...
 	bool bNoSpecified = true;
 	bool bNoSpecified = true;
 	for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
 	for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
 	{
 	{
 		aiMaterialProperty* prop = pMaterial->mProperties[i];
 		aiMaterialProperty* prop = pMaterial->mProperties[i];
-		if (0 == ASSIMP_strincmp( prop->mKey.data, szBaseBuf, iLen ))
+		if (prop->mSemantic != type)continue;
+
+		if ((int)prop->mIndex >= iNumIndices)
+		{
+			ReportError("Found texture property with index %i, although there "
+				"are only %i textures of type %s",
+				prop->mIndex, iNumIndices, szType);
+		}
+			
+		if (!::strcmp(prop->mKey.data,"$tex.mapping"))
+		{
+			if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping))
+			{
+				ReportError("Material property %s%i is expected to be an integer (size is %i)",
+					prop->mKey.data,prop->mIndex,prop->mDataLength);
+			}
+			mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData);
+		}
+		else if (!::strcmp(prop->mKey.data,"$tex.uvtrafo"))
+		{
+			if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform))
+			{
+				ReportError("Material property %s%i is expected to be 5 floats large (size is %i)",
+					prop->mKey.data,prop->mIndex, prop->mDataLength);
+			}
+			mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData);
+		}
+		else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc"))
 		{
 		{
 			if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)
 			if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)
-				this->ReportError("Material property %s is expected to be an integer",prop->mKey.data);
-
-			const char* sz = &prop->mKey.data[iLen];
-			if (*sz)
 			{
 			{
-				++sz;
-				iIndex = strtol10(sz,NULL);
-				bNoSpecified = false;
+				ReportError("Material property %s%i is expected to be an integer (size is %i)",
+					prop->mKey.data,prop->mIndex,prop->mDataLength);
+			}
+			bNoSpecified = false;
 
 
-				// ignore UV indices for texture channel that are not there ...
-				if (iIndex >= iNumIndices)
-				{
-					// get the value
-					iIndex = *((unsigned int*)prop->mData);
+			// Ignore UV indices for texture channels that are not there ...
+
+			// Get the value
+			iIndex = *((unsigned int*)prop->mData);
 
 
-					// check whether there is a mesh using this material
-					// which has not enough UV channels ...
-					for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
+			// Check whether there is a mesh using this material
+			// which has not enough UV channels ...
+			for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
+			{
+				aiMesh* mesh = this->mScene->mMeshes[a];
+				if(mesh->mMaterialIndex == (unsigned int)i)
+				{
+					int iChannels = 0;
+					while (mesh->HasTextureCoords(iChannels))++iChannels;
+					if (iIndex >= iChannels)
 					{
 					{
-						aiMesh* mesh = this->mScene->mMeshes[a];
-						if(mesh->mMaterialIndex == (unsigned int)iIndex)
-						{
-							int iChannels = 0;
-							while (mesh->HasTextureCoords(iChannels))++iChannels;
-							if (iIndex >= iChannels)
-							{
-								this->ReportError("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
-									iIndex,prop->mKey.data,a,iChannels);
-							}
-						}
+						ReportError("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
+							iIndex,prop->mKey.data,a,iChannels);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -669,7 +710,7 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
 		// Assume that all textures are using the first UV channel
 		// Assume that all textures are using the first UV channel
 		for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
 		for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
 		{
 		{
-			aiMesh* mesh = this->mScene->mMeshes[a];
+			aiMesh* mesh = mScene->mMeshes[a];
 			if(mesh->mMaterialIndex == (unsigned int)iIndex)
 			if(mesh->mMaterialIndex == (unsigned int)iIndex)
 			{
 			{
 				if (!mesh->mTextureCoords[0])
 				if (!mesh->mTextureCoords[0])
@@ -766,15 +807,16 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial)
 	}
 	}
 
 
 	// check whether there are invalid texture keys
 	// check whether there are invalid texture keys
-	SearchForInvalidTextures(pMaterial,"diffuse");
-	SearchForInvalidTextures(pMaterial,"specular");
-	SearchForInvalidTextures(pMaterial,"ambient");
-	SearchForInvalidTextures(pMaterial,"emissive");
-	SearchForInvalidTextures(pMaterial,"opacity");
-	SearchForInvalidTextures(pMaterial,"shininess");
-	SearchForInvalidTextures(pMaterial,"normals");
-	SearchForInvalidTextures(pMaterial,"height");
+	SearchForInvalidTextures(pMaterial,aiTextureType_DIFFUSE);
+	SearchForInvalidTextures(pMaterial,aiTextureType_SPECULAR);
+	SearchForInvalidTextures(pMaterial,aiTextureType_AMBIENT);
+	SearchForInvalidTextures(pMaterial,aiTextureType_EMISSIVE);
+	SearchForInvalidTextures(pMaterial,aiTextureType_OPACITY);
+	SearchForInvalidTextures(pMaterial,aiTextureType_SHININESS);
+	SearchForInvalidTextures(pMaterial,aiTextureType_HEIGHT);
+	SearchForInvalidTextures(pMaterial,aiTextureType_NORMALS);
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::Validate( const aiTexture* pTexture)
 void ValidateDSProcess::Validate( const aiTexture* pTexture)
 {
 {
@@ -806,7 +848,7 @@ void ValidateDSProcess::Validate( const aiTexture* pTexture)
 	}
 	}
 
 
 	const char* sz = pTexture->achFormatHint;
 	const char* sz = pTexture->achFormatHint;
- 	if (	sz[0] >= 'A' && sz[0] <= 'Z' ||
+ 	if (sz[0] >= 'A' && sz[0] <= 'Z' ||
 		sz[1] >= 'A' && sz[1] <= 'Z' ||
 		sz[1] >= 'A' && sz[1] <= 'Z' ||
 		sz[2] >= 'A' && sz[2] <= 'Z' ||
 		sz[2] >= 'A' && sz[2] <= 'Z' ||
 		sz[3] >= 'A' && sz[3] <= 'Z')
 		sz[3] >= 'A' && sz[3] <= 'Z')
@@ -814,35 +856,13 @@ void ValidateDSProcess::Validate( const aiTexture* pTexture)
 		this->ReportError("aiTexture::achFormatHint contains non-lowercase characters");
 		this->ReportError("aiTexture::achFormatHint contains non-lowercase characters");
 	}
 	}
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
 void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
 	 const aiNodeAnim* pNodeAnim)
 	 const aiNodeAnim* pNodeAnim)
 {
 {
-	this->Validate(&pNodeAnim->mNodeName);
+	Validate(&pNodeAnim->mNodeName);
 
 
-#if 0
-	// check whether there is a bone with this name ...
-	unsigned int i = 0;
-	for (; i < this->mScene->mNumMeshes;++i)
-	{
-		aiMesh* mesh = this->mScene->mMeshes[i];
-		for (unsigned int a = 0; a < mesh->mNumBones;++a)
-		{
-			if (mesh->mBones[a]->mName == pNodeAnim->mBoneName)
-				goto __break_out;
-		}
-	}
-__break_out:
-	if (i == this->mScene->mNumMeshes)
-	{
-		this->ReportWarning("aiNodeAnim::mBoneName is \"%s\". However, no bone with this name was found",
-			pNodeAnim->mBoneName.data);
-	}
-	if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mNumRotationKeys && !pNodeAnim->mNumScalingKeys)
-	{
-		this->ReportWarning("A bone animation channel has no keys");
-	}
-#endif
 	// otherwise check whether one of the keys exceeds the total duration of the animation
 	// otherwise check whether one of the keys exceeds the total duration of the animation
 	if (pNodeAnim->mNumPositionKeys)
 	if (pNodeAnim->mNumPositionKeys)
 	{
 	{
@@ -934,11 +954,12 @@ __break_out:
 		ReportError("A node animation channel must have at least one subtrack");
 		ReportError("A node animation channel must have at least one subtrack");
 	}
 	}
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::Validate( const aiNode* pNode)
 void ValidateDSProcess::Validate( const aiNode* pNode)
 {
 {
-	if (!pNode)this->ReportError("A node of the scenegraph is NULL");
-	if (pNode != this->mScene->mRootNode && !pNode->mParent)
+	if (!pNode)ReportError("A node of the scenegraph is NULL");
+	if (pNode != mScene->mRootNode && !pNode->mParent)
 		this->ReportError("A node has no valid parent (aiNode::mParent is NULL)");
 		this->ReportError("A node has no valid parent (aiNode::mParent is NULL)");
 
 
 	this->Validate(&pNode->mName);
 	this->Validate(&pNode->mName);
@@ -948,21 +969,21 @@ void ValidateDSProcess::Validate( const aiNode* pNode)
 	{
 	{
 		if (!pNode->mMeshes)
 		if (!pNode->mMeshes)
 		{
 		{
-			this->ReportError("aiNode::mMeshes is NULL (aiNode::mNumMeshes is %i)",
+			ReportError("aiNode::mMeshes is NULL (aiNode::mNumMeshes is %i)",
 				pNode->mNumMeshes);
 				pNode->mNumMeshes);
 		}
 		}
 		std::vector<bool> abHadMesh;
 		std::vector<bool> abHadMesh;
-		abHadMesh.resize(this->mScene->mNumMeshes,false);
+		abHadMesh.resize(mScene->mNumMeshes,false);
 		for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
 		for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
 		{
 		{
-			if (pNode->mMeshes[i] >= this->mScene->mNumMeshes)
+			if (pNode->mMeshes[i] >= mScene->mNumMeshes)
 			{
 			{
-				this->ReportError("aiNode::mMeshes[%i] is out of range (maximum is %i)",
-					pNode->mMeshes[i],this->mScene->mNumMeshes-1);
+				ReportError("aiNode::mMeshes[%i] is out of range (maximum is %i)",
+					pNode->mMeshes[i],mScene->mNumMeshes-1);
 			}
 			}
 			if (abHadMesh[pNode->mMeshes[i]])
 			if (abHadMesh[pNode->mMeshes[i]])
 			{
 			{
-				this->ReportError("aiNode::mMeshes[%i] is already referenced by this node (value: %i)",
+				ReportError("aiNode::mMeshes[%i] is already referenced by this node (value: %i)",
 					i,pNode->mMeshes[i]);
 					i,pNode->mMeshes[i]);
 			}
 			}
 			abHadMesh[pNode->mMeshes[i]] = true;
 			abHadMesh[pNode->mMeshes[i]] = true;
@@ -977,10 +998,11 @@ void ValidateDSProcess::Validate( const aiNode* pNode)
 		}
 		}
 		for (unsigned int i = 0; i < pNode->mNumChildren;++i)
 		for (unsigned int i = 0; i < pNode->mNumChildren;++i)
 		{
 		{
-			this->Validate(pNode->mChildren[i]);
+			Validate(pNode->mChildren[i]);
 		}
 		}
 	}
 	}
 }
 }
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::Validate( const aiString* pString)
 void ValidateDSProcess::Validate( const aiString* pString)
 {
 {
@@ -995,11 +1017,11 @@ void ValidateDSProcess::Validate( const aiString* pString)
 		if ('\0' == *sz)
 		if ('\0' == *sz)
 		{
 		{
 			if (pString->length != (unsigned int)(sz-pString->data))
 			if (pString->length != (unsigned int)(sz-pString->data))
-				this->ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
+				ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
 			break;
 			break;
 		}
 		}
 		else if (sz >= &pString->data[MAXLEN])
 		else if (sz >= &pString->data[MAXLEN])
-			this->ReportError("aiString::data is invalid. There is no terminal character");
+			ReportError("aiString::data is invalid. There is no terminal character");
 		++sz;
 		++sz;
 	}
 	}
 }
 }

+ 2 - 3
code/ValidateDataStructure.h

@@ -134,11 +134,10 @@ protected:
 	/** Search the material data structure for invalid or corrupt
 	/** Search the material data structure for invalid or corrupt
 	 *  texture keys.
 	 *  texture keys.
 	 * @param pMaterial Input material
 	 * @param pMaterial Input material
-	 * @param szType Type of the texture (the purpose string that
-	 *  occurs in material keys, e.g. "diffuse", "ambient")
+	 * @param type Type of the texture
 	 */
 	 */
 	void SearchForInvalidTextures(const aiMaterial* pMaterial,
 	void SearchForInvalidTextures(const aiMaterial* pMaterial,
-		const char* szType);
+		aiTextureType type);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Validates a texture
 	/** Validates a texture

+ 11 - 12
code/XFileImporter.cpp

@@ -611,7 +611,6 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, const std::vector<XFile::
 				std::string sz = otex.mName;
 				std::string sz = otex.mName;
 				if (!sz.length())continue;
 				if (!sz.length())continue;
 
 
-				char key[256];
 
 
 				// find the file name
 				// find the file name
 				const size_t iLen = sz.length();
 				const size_t iLen = sz.length();
@@ -634,35 +633,35 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, const std::vector<XFile::
 					if( isalpha( sz[c]))
 					if( isalpha( sz[c]))
 						sz[c] = tolower( sz[c]);
 						sz[c] = tolower( sz[c]);
 
 
+
+				// Place texture filename property under the corresponding name
+				aiString tex( oldMat.mTextures[b].mName);
+
 				// bump map
 				// bump map
 				if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s))
 				if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s))
 				{
 				{
-					::sprintf(key,AI_MATKEY_TEXTURE_HEIGHT_ "[%i]",iHM++);
+					mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
 				} else
 				} else
 				if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s))
 				if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s))
 				{
 				{
-					::sprintf(key,AI_MATKEY_TEXTURE_NORMALS_ "[%i]",iNM++);
+					mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
 				} else
 				} else
 				if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s))
 				if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s))
 				{
 				{
-					::sprintf(key,AI_MATKEY_TEXTURE_SPECULAR_ "[%i]",iSM++);
+					mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
 				} else
 				} else
 				if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s))
 				if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s))
 				{
 				{
-					::sprintf(key,AI_MATKEY_TEXTURE_AMBIENT_ "[%i]",iAM++);
+					mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
 				} else
 				} else
 				if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s))
 				if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s))
 				{
 				{
-					::sprintf(key,AI_MATKEY_TEXTURE_EMISSIVE_ "[%i]",iEM++);
+					mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
 				} else
 				} else
 				{
 				{
-					// assume it is a diffuse texture
-					::sprintf(key,AI_MATKEY_TEXTURE_DIFFUSE_ "[%i]",iDM++);
+					// Assume it is a diffuse texture
+					mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
 				}
 				}
-
-				// place texture filename property under the corresponding name
-				aiString tex( oldMat.mTextures[b].mName);
-				mat->AddProperty( &tex, key);
 			}
 			}
 		}
 		}
 
 

+ 4 - 1
code/makefile

@@ -74,7 +74,10 @@ SOURCES = AssimpPCH.cpp \
 	Q3DLoader.cpp \
 	Q3DLoader.cpp \
 	ScenePreprocessor.cpp \
 	ScenePreprocessor.cpp \
 	B3DImporter.cpp \
 	B3DImporter.cpp \
-	TargetAnimation.cpp
+	TargetAnimation.cpp \
+	ComputeUVMappingProcess.cpp  \
+	ColladaLoader.cpp \
+	ColladaParser.cpp
 
 
 OBJECTS = $(SOURCES:.cpp=.o)
 OBJECTS = $(SOURCES:.cpp=.o)
 
 

+ 4 - 2
code/makefile.mingw

@@ -74,8 +74,10 @@ SOURCES = AssimpPCH.cpp \
 	Q3DLoader.cpp \
 	Q3DLoader.cpp \
 	ScenePreprocessor.cpp \
 	ScenePreprocessor.cpp \
 	B3DImporter.cpp \
 	B3DImporter.cpp \
-	TargetAnimation.cpp
-	
+	TargetAnimation.cpp \
+	ComputeUVMappingProcess.cpp \
+	ColladaLoader.cpp \
+	ColladaParser.cpp
 
 
 OBJECTS = $(SOURCES:.cpp=.o)
 OBJECTS = $(SOURCES:.cpp=.o)
 
 

+ 85 - 0
include/BoostWorkaround/boost/scoped_array.h

@@ -0,0 +1,85 @@
+
+#ifndef __AI_BOOST_SCOPED_ARRAY_INCLUDED
+#define __AI_BOOST_SCOPED_ARRAY_INCLUDED
+
+#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace boost {
+
+// small replacement for boost::scoped_array
+template <class T>
+class scoped_array
+{
+public:
+
+	// provide a default construtctor 
+	scoped_array()
+		: ptr(0)
+	{
+	}
+
+	// construction from an existing heap object of type T
+	scoped_array(T* _ptr)
+		: ptr(_ptr)
+	{
+	}
+	
+	// automatic destruction of the wrapped object at the 
+	// end of our lifetime
+	~scoped_array()
+	{
+		delete[] ptr;
+	}
+	
+	inline T* get()
+	{
+		return ptr;
+	}
+	
+	inline operator T*()
+	{
+		return ptr;
+	}
+	
+	inline T* operator-> () 
+	{
+		return ptr;
+	}
+
+	inline void reset (T* t = 0)
+	{
+		delete[] ptr;
+		ptr = t;
+	}
+
+	T & operator[](std::ptrdiff_t i) const
+	{
+		return ptr[i];
+	}
+
+	void swap(scoped_array & b)
+	{
+		std::swap(ptr, b.ptr);
+	}
+	
+private:
+	
+	// encapsulated object pointer
+	T* ptr;
+
+};
+
+template<class T> 
+inline void swap(scoped_array<T> & a, scoped_array<T> & b)
+{
+	a.swap(b);
+}
+
+} // end of namespace boost
+
+#else
+#	error "scoped_array.h was already included"
+#endif
+#endif // __AI_BOOST_SCOPED_ARRAY_INCLUDED

+ 18 - 1
include/BoostWorkaround/boost/scoped_ptr.hpp

@@ -16,7 +16,7 @@ public:
 
 
 	// provide a default construtctor 
 	// provide a default construtctor 
 	scoped_ptr()
 	scoped_ptr()
-		: ptr(NULL)
+		: ptr(0)
 	{
 	{
 	}
 	}
 
 
@@ -47,6 +47,17 @@ public:
 	{
 	{
 		return ptr;
 		return ptr;
 	}
 	}
+
+	inline void reset (T* t = 0)
+	{
+		delete ptr;
+		ptr = t;
+	}
+
+	void swap(scoped_ptr & b)
+	{
+		std::swap(ptr, b.ptr);
+	}
 	
 	
 private:
 private:
 	
 	
@@ -55,6 +66,12 @@ private:
 
 
 };
 };
 
 
+template<class T> 
+inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b)
+{
+	a.swap(b);
+}
+
 } // end of namespace boost
 } // end of namespace boost
 
 
 #else
 #else

+ 6 - 0
include/aiCamera.h

@@ -55,6 +55,12 @@ extern "C" {
 /** Helper structure to describe a virtual camera. 
 /** Helper structure to describe a virtual camera. 
  *
  *
  * Cameras have a representation in the node graph and can be animated.
  * Cameras have a representation in the node graph and can be animated.
+ * Note - some file formats (such as 3DS, ASE) export a "target point" -
+ * the point the camera is looking at (it can even be animated). Assimp
+ * writes the target point as a subnode of the camera's main node,
+ * called "<camName>.Target". However, this is just additional information
+ * then, the transformation tracks of the camera main node make the
+ * camera already point in the right direction.
  *
  *
 */
 */
 struct aiCamera
 struct aiCamera

+ 17 - 9
include/aiConfig.h

@@ -101,15 +101,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_CONFIG_IMPORT_SMD_KEYFRAME		"imp.smd.kf"
 #define AI_CONFIG_IMPORT_SMD_KEYFRAME		"imp.smd.kf"
 
 
 
 
-// ---------------------------------------------------------------------------
-/** \brief Configures the 3DS loader to ignore pivot points in the file
- *
- * There are some faulty 3DS files which look only correctly with
- * pivot points disabled.
- * Property type: integer (0: false; !0: true). Default value: false.
- */
-#define AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT	"imp.3ds.nopivot"
-
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** \brief Configures the AC loader to collect all surfaces which have the
 /** \brief Configures the AC loader to collect all surfaces which have the
@@ -305,6 +296,23 @@ enum aiComponent
 #define AI_CONFIG_PP_SBP_REMOVE				"pp.sbp.remove"
 #define AI_CONFIG_PP_SBP_REMOVE				"pp.sbp.remove"
 
 
 
 
+
+#define AI_UVTRAFO_SCALING 0x1
+#define AI_UVTRAFO_ROTATION 0x2
+#define AI_UVTRAFO_TRANSLATION 0x4
+#define AI_UVTRAFO_ALL (AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION | AI_UVTRAFO_TRANSLATION)
+
+// ---------------------------------------------------------------------------
+/** \brief Input parameter to the #aiProcess_TransformUVCoords step:
+ *  Specifies which UV transformations are evaluated.
+ *
+ *  This is a bitwise combination of the AI_UVTRAFO_XXX flags (integer
+ *  property, of course). By default all transformations are enabled 
+ * (AI_UVTRAFO_ALL).
+ */
+#define AI_CONFIG_PP_TUV_EVALUATE				"pp.tuv.process"
+
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** \brief Causes assimp to favour speed against import quality.
 /** \brief Causes assimp to favour speed against import quality.
  *
  *

+ 2 - 0
include/aiDefines.h

@@ -78,6 +78,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 	// OPTIMIZEGRAPH
 	// OPTIMIZEGRAPH
 	// SORTBYPTYPE
 	// SORTBYPTYPE
 	// FINDINVALIDDATA
 	// FINDINVALIDDATA
+	// TRANSFORMTEXCOORDS
+	// GENUVCOORDS
 	// ************************************************************
 	// ************************************************************
 
 
 
 

+ 6 - 0
include/aiLight.h

@@ -87,6 +87,12 @@ enum aiLightSourceType
  *  Assimp supports multiple sorts of light sources, including
  *  Assimp supports multiple sorts of light sources, including
  *  directional, point and spot lights. All of them are defined with just
  *  directional, point and spot lights. All of them are defined with just
  *  a single structure and distinguished by their parameters.
  *  a single structure and distinguished by their parameters.
+ *  Note - some file formats (such as 3DS, ASE) export a "target point" -
+ *  the point a spot light is looking at (it can even be animated). Assimp
+ *  writes the target point as a subnode of a spotlights's main node,
+ *  called "<spotName>.Target". However, this is just additional information
+ *  then, the transformation tracks of the main node make the
+ *  spot light already point in the right direction.
 */
 */
 struct aiLight
 struct aiLight
 {
 {

文件差異過大導致無法顯示
+ 548 - 424
include/aiMaterial.h


+ 146 - 135
include/aiMaterial.inl

@@ -1,135 +1,146 @@
-/*
----------------------------------------------------------------------------
-Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------------
-
-Copyright (c) 2006-2008, ASSIMP Development Team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms, 
-with or without modification, are permitted provided that the following 
-conditions are met:
-
-* Redistributions of source code must retain the above
-  copyright notice, this list of conditions and the
-  following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-  copyright notice, this list of conditions and the
-  following disclaimer in the documentation and/or other
-  materials provided with the distribution.
-
-* Neither the name of the ASSIMP team, nor the names of its
-  contributors may be used to endorse or promote products
-  derived from this software without specific prior
-  written permission of the ASSIMP Development Team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
-*/
-
-/** @file Defines the material system of the library
- *
- */
-
-#ifndef AI_MATERIAL_INL_INC
-#define AI_MATERIAL_INL_INC
-
-// ---------------------------------------------------------------------------
-inline aiReturn aiMaterial::GetTexture(unsigned int iIndex,
-	unsigned int iTexType,
-	aiString* szPath,
-	unsigned int* piUVIndex		,
-	float* pfBlendFactor		,
-	aiTextureOp* peTextureOp	,
-	aiTextureMapMode* peMapMode )
-{
-	return aiGetMaterialTexture(this,iIndex,iTexType,szPath,
-		piUVIndex,pfBlendFactor,peTextureOp,peMapMode);
-}
-// ---------------------------------------------------------------------------
-template <typename Type>
-inline aiReturn aiMaterial::Get(const char* pKey,Type* pOut,
-	unsigned int* pMax)
-{
-	unsigned int iNum = pMax ? *pMax : 1;
-
-	aiMaterialProperty* prop;
-	aiReturn ret = aiGetMaterialProperty(this,pKey,&prop);
-	if ( AI_SUCCESS == ret )
-	{
-		if (prop->mDataLength < sizeof(Type)*iNum)return AI_FAILURE;
-		if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE;
-
-		iNum = std::min((size_t)iNum,prop->mDataLength / sizeof(Type));
-		::memcpy(pOut,prop->mData,iNum * sizeof(Type));
-		if (pMax)*pMax = iNum;
-	}
-	return ret;
-}
-// ---------------------------------------------------------------------------
-template <typename Type>
-inline aiReturn aiMaterial::Get(const char* pKey,Type& pOut)
-{
-	aiMaterialProperty* prop;
-	aiReturn ret = aiGetMaterialProperty(this,pKey,&prop);
-	if ( AI_SUCCESS == ret )
-	{
-		if (prop->mDataLength < sizeof(Type))return AI_FAILURE;
-		if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE;
-
-		::memcpy(&pOut,prop->mData,sizeof(Type));
-	}
-	return ret;
-}
-// ---------------------------------------------------------------------------
-template <>
-inline aiReturn aiMaterial::Get<float>(const char* pKey,float* pOut,
-	unsigned int* pMax)
-{
-	return aiGetMaterialFloatArray(this,pKey,pOut,pMax);
-}
-// ---------------------------------------------------------------------------
-template <>
-inline aiReturn aiMaterial::Get<int>(const char* pKey,int* pOut,
-	unsigned int* pMax)
-{
-	return aiGetMaterialIntegerArray(this,pKey,pOut,pMax);
-}
-// ---------------------------------------------------------------------------
-template <>
-inline aiReturn aiMaterial::Get<float>(const char* pKey,float& pOut)
-{
-	return aiGetMaterialFloat(this,pKey,&pOut);
-}
-// ---------------------------------------------------------------------------
-template <>
-inline aiReturn aiMaterial::Get<int>(const char* pKey,int& pOut)
-{
-	return aiGetMaterialInteger(this,pKey,&pOut);
-}
-// ---------------------------------------------------------------------------
-template <>
-inline aiReturn aiMaterial::Get<aiColor4D>(const char* pKey,aiColor4D& pOut)
-{
-	return aiGetMaterialColor(this,pKey,&pOut);
-}
-// ---------------------------------------------------------------------------
-template <>
-inline aiReturn aiMaterial::Get<aiString>(const char* pKey,aiString& pOut)
-{
-	return aiGetMaterialString(this,pKey,&pOut);
-}
-
-#endif //! AI_MATERIAL_INL_INC
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (ASSIMP)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development Team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the following 
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+/** @file Defines the material system of the library
+ *
+ */
+
+#ifndef AI_MATERIAL_INL_INC
+#define AI_MATERIAL_INL_INC
+
+// ---------------------------------------------------------------------------
+inline aiReturn aiMaterial::GetTexture( aiTextureType type,
+    unsigned int  idx,
+    C_STRUCT aiString* path,
+	aiTextureMapping* mapping	/*= NULL*/,
+    unsigned int* uvindex		/*= NULL*/,
+    float* blend				/*= NULL*/,
+    aiTextureOp* op				/*= NULL*/,
+	aiTextureMapMode* mapmode	/*= NULL*/)
+{
+	return aiGetMaterialTexture(this,type,idx,path,mapping,uvindex,blend,op,mapmode);
+}
+
+// ---------------------------------------------------------------------------
+template <typename Type>
+inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
+	unsigned int idx, Type* pOut,
+	unsigned int* pMax)
+{
+	unsigned int iNum = pMax ? *pMax : 1;
+
+	aiMaterialProperty* prop;
+	aiReturn ret = aiGetMaterialProperty(this,pKey,type,idx,&prop);
+	if ( AI_SUCCESS == ret )
+	{
+		if (prop->mDataLength < sizeof(Type)*iNum)return AI_FAILURE;
+		if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE;
+
+		iNum = std::min((size_t)iNum,prop->mDataLength / sizeof(Type));
+		::memcpy(pOut,prop->mData,iNum * sizeof(Type));
+		if (pMax)*pMax = iNum;
+	}
+	return ret;
+}
+
+// ---------------------------------------------------------------------------
+template <typename Type>
+inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type,
+	unsigned int idx,Type& pOut)
+{
+	aiMaterialProperty* prop;
+	aiReturn ret = aiGetMaterialProperty(this,pKey,type,idx,&prop);
+	if ( AI_SUCCESS == ret )
+	{
+		if (prop->mDataLength < sizeof(Type))return AI_FAILURE;
+		if (strcmp(prop->mData,(char*)aiPTI_Buffer)!=0)return AI_FAILURE;
+
+		::memcpy(&pOut,prop->mData,sizeof(Type));
+	}
+	return ret;
+}
+
+// ---------------------------------------------------------------------------
+template <>
+inline aiReturn aiMaterial::Get<float>(const char* pKey,unsigned int type,
+	unsigned int idx,float* pOut,
+	unsigned int* pMax)
+{
+	return aiGetMaterialFloatArray(this,pKey,type,idx,pOut,pMax);
+}
+// ---------------------------------------------------------------------------
+template <>
+inline aiReturn aiMaterial::Get<int>(const char* pKey,unsigned int type,
+	unsigned int idx,int* pOut,
+	unsigned int* pMax)
+{
+	return aiGetMaterialIntegerArray(this,pKey,type,idx,pOut,pMax);
+}
+// ---------------------------------------------------------------------------
+template <>
+inline aiReturn aiMaterial::Get<float>(const char* pKey,unsigned int type,
+	unsigned int idx,float& pOut)
+{
+	return aiGetMaterialFloat(this,pKey,type,idx,&pOut);
+}
+// ---------------------------------------------------------------------------
+template <>
+inline aiReturn aiMaterial::Get<int>(const char* pKey,unsigned int type,
+	unsigned int idx,int& pOut)
+{
+	return aiGetMaterialInteger(this,pKey,type,idx,&pOut);
+}
+// ---------------------------------------------------------------------------
+template <>
+inline aiReturn aiMaterial::Get<aiColor4D>(const char* pKey,unsigned int type,
+	unsigned int idx,aiColor4D& pOut)
+{
+	return aiGetMaterialColor(this,pKey,type,idx,&pOut);
+}
+// ---------------------------------------------------------------------------
+template <>
+inline aiReturn aiMaterial::Get<aiString>(const char* pKey,unsigned int type,
+	unsigned int idx,aiString& pOut)
+{
+	return aiGetMaterialString(this,pKey,type,idx,&pOut);
+}
+
+#endif //! AI_MATERIAL_INL_INC

+ 17 - 1
include/aiMatrix3x3.h

@@ -48,11 +48,11 @@ extern "C" {
 #endif
 #endif
 
 
 struct aiMatrix4x4;
 struct aiMatrix4x4;
+struct aiVector2D;
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Represents a row-major 3x3 matrix 
 /** Represents a row-major 3x3 matrix 
 */
 */
-// ---------------------------------------------------------------------------
 struct aiMatrix3x3
 struct aiMatrix3x3
 {
 {
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -77,6 +77,22 @@ struct aiMatrix3x3
 	aiMatrix3x3 operator* (const aiMatrix3x3& m) const;
 	aiMatrix3x3 operator* (const aiMatrix3x3& m) const;
 	aiMatrix3x3& Transpose();
 	aiMatrix3x3& Transpose();
 
 
+
+	/** \brief Returns a rotation matrix 
+	 *  \param a Rotation angle, in radians
+	 *  \param out Receives the output matrix
+	 *  \return Reference to the output matrix
+	 */
+	static aiMatrix3x3& Rotation(float a, aiMatrix3x3& out);
+
+
+	/** \brief Returns a translation matrix 
+	 *  \param v Translation vector
+	 *  \param out Receives the output matrix
+	 *  \return Reference to the output matrix
+	 */
+	static aiMatrix3x3& Translation( const aiVector2D& v, aiMatrix3x3& out);
+
 #endif // __cplusplus
 #endif // __cplusplus
 
 
 
 

+ 21 - 0
include/aiMatrix3x3.inl

@@ -51,6 +51,27 @@ inline aiMatrix3x3& aiMatrix3x3::Transpose()
 	return *this;
 	return *this;
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+inline aiMatrix3x3& aiMatrix3x3::Rotation(float a, aiMatrix3x3& out)
+{
+	out.a1 = out.b2 = ::cos(a);
+	out.b1 = ::sin(a);
+	out.a2 = - out.b1;
+
+	out.a3 = out.b3 = out.c1 = out.c2 = 0.f;
+	out.c3 = 1.f;
+
+	return out;
+}
+
+// ------------------------------------------------------------------------------------------------
+inline aiMatrix3x3& aiMatrix3x3::Translation( const aiVector2D& v, aiMatrix3x3& out)
+{
+	out = aiMatrix3x3();
+	out.a3 = v.x;
+	out.b3 = v.y;
+	return out;
+}
 
 
 
 
 #endif // __cplusplus
 #endif // __cplusplus

+ 17 - 0
include/aiMesh.h

@@ -504,6 +504,23 @@ struct aiMesh
 		else 
 		else 
 			return mTextureCoords[pIndex] != NULL && mNumVertices > 0; 
 			return mTextureCoords[pIndex] != NULL && mNumVertices > 0; 
 	}
 	}
+
+	//! Get the number of UV channels the mesh contains
+	inline unsigned int GetNumUVChannels() const 
+	{
+		unsigned int n = 0;
+		while (n < AI_MAX_NUMBER_OF_TEXTURECOORDS && mTextureCoords[n])++n;
+		return n;
+	}
+
+	//! Get the number of vertex color channels the mesh contains
+	inline unsigned int GetNumColorChannels() const 
+	{
+		unsigned int n = 0;
+		while (n < AI_MAX_NUMBER_OF_COLOR_SETS && mColors[n])++n;
+		return n;
+	}
+
 	//! Check whether the mesh contains bones
 	//! Check whether the mesh contains bones
 	inline bool HasBones() const
 	inline bool HasBones() const
 		{ return mBones != NULL && mNumBones > 0; }
 		{ return mBones != NULL && mNumBones > 0; }

+ 24 - 3
include/aiPostProcess.h

@@ -230,7 +230,6 @@ enum aiPostProcessSteps
 	*/
 	*/
 	aiProcess_FindDegenerates = 0x10000,
 	aiProcess_FindDegenerates = 0x10000,
 
 
-
 	/** This step searches all meshes for invalid data, such as zeroed
 	/** This step searches all meshes for invalid data, such as zeroed
 	 *  normal vectors or invalid UV coords and removes them.
 	 *  normal vectors or invalid UV coords and removes them.
 	 *
 	 *
@@ -240,6 +239,26 @@ enum aiPostProcessSteps
 	 * The step will also remove meshes that are infinitely small.
 	 * The step will also remove meshes that are infinitely small.
 	*/
 	*/
 	aiProcess_FindInvalidData = 0x20000,
 	aiProcess_FindInvalidData = 0x20000,
+
+	/** This step converts non-UV mappings (such as spherical or
+	 *  cylindrical) to proper UV mapping channels.
+	 *
+	 * Most applications will support UV mapping only, so you will
+	 * propably want to specify this step in every case.
+	*/
+	aiProcess_GenUVCoords = 0x40000,
+
+	/** This step pretransforms UV coordinates by the UV transformations
+	 *  (such as scalings or rotations).
+	 *
+	 * UV transformations are specified per-texture - see the
+	 * AI_MATKEY_UVTRANSFORM key for more information on this topic.
+	 * This step finds all textures with transformed input UV
+	 * coordinates and generates a new, transformed, UV channel for it.
+	 * Most applications won't support UV transformations, so you will
+	 * propably want to specify this step in every case.
+	*/
+	aiProcess_TransformUVCoords = 0x80000,
 };
 };
 
 
 
 
@@ -254,7 +273,8 @@ enum aiPostProcessSteps
 	aiProcess_CalcTangentSpace		|  \
 	aiProcess_CalcTangentSpace		|  \
 	aiProcess_GenNormals			|  \
 	aiProcess_GenNormals			|  \
 	aiProcess_JoinIdenticalVertices |  \
 	aiProcess_JoinIdenticalVertices |  \
-	aiProcess_Triangulate
+	aiProcess_Triangulate			|  \
+	aiProcess_GenUVCoords
 
 
 
 
  /** @def AI_POSTPROCESS_DEFAULT_REALTIME
  /** @def AI_POSTPROCESS_DEFAULT_REALTIME
@@ -274,7 +294,8 @@ enum aiPostProcessSteps
 	aiProcess_RemoveRedundantMaterials      |  \
 	aiProcess_RemoveRedundantMaterials      |  \
 	aiProcess_SplitLargeMeshes				|  \
 	aiProcess_SplitLargeMeshes				|  \
 	aiProcess_OptimizeGraph					|  \
 	aiProcess_OptimizeGraph					|  \
-	aiProcess_Triangulate
+	aiProcess_Triangulate					|  \
+	aiProcess_GenUVCoords
 
 
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 67 - 14
include/aiTypes.h

@@ -47,13 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "aiDefines.h"
 #include "aiDefines.h"
 
 
-// include math helper classes and their implementations
+// include math helper classes 
 #include "aiVector3D.h"
 #include "aiVector3D.h"
 #include "aiMatrix3x3.h"
 #include "aiMatrix3x3.h"
 #include "aiMatrix4x4.h"
 #include "aiMatrix4x4.h"
-#include "aiVector3D.inl"
-#include "aiMatrix3x3.inl"
-#include "aiMatrix4x4.inl"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 #	include <string>
 #	include <string>
@@ -72,7 +69,6 @@ const size_t MAXLEN = 1024;
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Represents a two-dimensional vector. 
 /** Represents a two-dimensional vector. 
 */
 */
-// ---------------------------------------------------------------------------
 struct aiVector2D
 struct aiVector2D
 {
 {
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -86,6 +82,25 @@ struct aiVector2D
 	float x, y;
 	float x, y;
 } PACK_STRUCT;
 } PACK_STRUCT;
 
 
+
+// ---------------------------------------------------------------------------
+/** Represents a plane in a three-dimensional, euclidean space
+*/
+struct aiPlane
+{
+#ifdef __cplusplus
+	aiPlane () : a(0.f), b(0.f), c(0.f), d(0.f) {}
+	aiPlane (float _a, float _b, float _c, float _d) 
+		: a(_a), b(_b), c(_c), d(_d) {}
+
+	aiPlane (const aiPlane& o) : a(o.a), b(o.b), c(o.c), d(o.d) {}
+	
+#endif // !__cplusplus
+
+	//! Plane equation
+	float a,b,c,d;
+} PACK_STRUCT;
+
 // aiVector3D type moved to separate header due to size of operators
 // aiVector3D type moved to separate header due to size of operators
 // aiQuaternion type moved to separate header due to size of operators
 // aiQuaternion type moved to separate header due to size of operators
 // aiMatrix4x4 type moved to separate header due to size of operators
 // aiMatrix4x4 type moved to separate header due to size of operators
@@ -93,7 +108,6 @@ struct aiVector2D
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Represents a color in Red-Green-Blue space. 
 /** Represents a color in Red-Green-Blue space. 
 */
 */
-// ---------------------------------------------------------------------------
 struct aiColor3D
 struct aiColor3D
 {
 {
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -136,7 +150,6 @@ struct aiColor3D
 /** Represents a color in Red-Green-Blue space including an 
 /** Represents a color in Red-Green-Blue space including an 
 *   alpha component. 
 *   alpha component. 
 */
 */
-// ---------------------------------------------------------------------------
 struct aiColor4D
 struct aiColor4D
 {
 {
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -157,7 +170,7 @@ struct aiColor4D
 
 
 	inline bool IsBlack() const
 	inline bool IsBlack() const
 	{
 	{
-		// the alpha component doesn't care here. black is black.
+		// The alpha component doesn't care here. black is black.
 		return !r && !g && !b;
 		return !r && !g && !b;
 	}
 	}
 
 
@@ -173,7 +186,6 @@ struct aiColor4D
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Represents a string, zero byte terminated 
 /** Represents a string, zero byte terminated 
 */
 */
-// ---------------------------------------------------------------------------
 struct aiString
 struct aiString
 {
 {
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -188,7 +200,7 @@ struct aiString
 		length(rOther.length) 
 		length(rOther.length) 
 	{
 	{
 		::memcpy( data, rOther.data, rOther.length);
 		::memcpy( data, rOther.data, rOther.length);
-		this->data[this->length] = '\0';
+		data[length] = '\0';
 	}
 	}
 
 
 	//! Constructor from std::string
 	//! Constructor from std::string
@@ -212,17 +224,36 @@ struct aiString
 	//! comparison operator
 	//! comparison operator
 	bool operator==(const aiString& other) const
 	bool operator==(const aiString& other) const
 	{
 	{
-		return  (this->length == other.length &&
+		return  (length == other.length &&
 				 0 == strcmp(this->data,other.data));
 				 0 == strcmp(this->data,other.data));
 	}
 	}
 
 
 	//! inverse comparison operator
 	//! inverse comparison operator
 	bool operator!=(const aiString& other) const
 	bool operator!=(const aiString& other) const
 	{
 	{
-		return  (this->length != other.length ||
+		return  (length != other.length ||
 				 0 != ::strcmp(this->data,other.data));
 				 0 != ::strcmp(this->data,other.data));
 	}
 	}
 
 
+	//! Append a string to the string
+	inline void Append (const char* app)
+	{
+		const size_t len = ::strlen(app);
+		if (!len)return;
+
+		if (length + len >= MAXLEN)
+			return;
+
+		::memcpy(&data[length],app,len+1);
+		length += len;
+	}
+
+	//! Clear the string
+	inline void Clear ()
+	{
+		length  = 0;
+		data[0] = '\0';
+	}
 
 
 #endif // !__cplusplus
 #endif // !__cplusplus
 
 
@@ -240,18 +271,21 @@ struct aiString
 * To check whether or not a function failed check against
 * To check whether or not a function failed check against
 * AI_SUCCESS. The error codes are mainly used by the C-API.
 * AI_SUCCESS. The error codes are mainly used by the C-API.
 */
 */
-// ---------------------------------------------------------------------------
 enum aiReturn
 enum aiReturn
 {
 {
 	//! Indicates that a function was successful
 	//! Indicates that a function was successful
 	AI_SUCCESS = 0x0,
 	AI_SUCCESS = 0x0,
+
 	//! Indicates that a function failed
 	//! Indicates that a function failed
 	AI_FAILURE = -0x1,
 	AI_FAILURE = -0x1,
+
 	//! Indicates that a file was invalid
 	//! Indicates that a file was invalid
 	AI_INVALIDFILE = -0x2,
 	AI_INVALIDFILE = -0x2,
+
 	//! Indicates that not enough memory was available
 	//! Indicates that not enough memory was available
 	//! to perform the requested operation
 	//! to perform the requested operation
 	AI_OUTOFMEMORY = -0x3,
 	AI_OUTOFMEMORY = -0x3,
+
 	//! Indicates that an illegal argument has been
 	//! Indicates that an illegal argument has been
 	//! passed to a function. This is rarely used,
 	//! passed to a function. This is rarely used,
 	//! most functions assert in this case.
 	//! most functions assert in this case.
@@ -264,7 +298,6 @@ enum aiReturn
  *  animations) of an import.
  *  animations) of an import.
  *  @see Importer::GetMemoryRequirements()
  *  @see Importer::GetMemoryRequirements()
 */
 */
-// ---------------------------------------------------------------------------
 struct aiMemoryInfo
 struct aiMemoryInfo
 {
 {
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -276,6 +309,8 @@ struct aiMemoryInfo
 		, meshes     (0)
 		, meshes     (0)
 		, nodes      (0)
 		, nodes      (0)
 		, animations (0)
 		, animations (0)
+		, cameras	 (0)
+		, lights	 (0)
 		, total      (0)
 		, total      (0)
 	{}
 	{}
 
 
@@ -283,14 +318,25 @@ struct aiMemoryInfo
 
 
 	//! Storage allocated for texture data, in bytes
 	//! Storage allocated for texture data, in bytes
 	unsigned int textures;
 	unsigned int textures;
+
 	//! Storage allocated for material data, in bytes
 	//! Storage allocated for material data, in bytes
 	unsigned int materials;
 	unsigned int materials;
+
 	//! Storage allocated for mesh data, in bytes
 	//! Storage allocated for mesh data, in bytes
 	unsigned int meshes;
 	unsigned int meshes;
+
 	//! Storage allocated for node data, in bytes
 	//! Storage allocated for node data, in bytes
 	unsigned int nodes;
 	unsigned int nodes;
+
 	//! Storage allocated for animation data, in bytes
 	//! Storage allocated for animation data, in bytes
 	unsigned int animations;
 	unsigned int animations;
+
+	//! Storage allocated for camera data, in bytes
+	unsigned int cameras;
+
+	//! Storage allocated for light data, in bytes
+	unsigned int lights;
+
 	//! Storage allocated for the import, in bytes
 	//! Storage allocated for the import, in bytes
 	unsigned int total;
 	unsigned int total;
 };
 };
@@ -299,5 +345,12 @@ struct aiMemoryInfo
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif //!  __cplusplus
 #endif //!  __cplusplus
+
+// Include implementations
+#include "aiVector3D.inl"
+#include "aiMatrix3x3.inl"
+#include "aiMatrix4x4.inl"
+
+
 #endif //!! include guard
 #endif //!! include guard
 
 

+ 65 - 61
tools/assimp_view/Display.cpp

@@ -244,7 +244,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 		AssetHelper::MeshHelper* pcMesh = g_pcAsset->apcMeshes[i];
 		AssetHelper::MeshHelper* pcMesh = g_pcAsset->apcMeshes[i];
 		switch (this->m_pcCurrentTexture->iType)
 		switch (this->m_pcCurrentTexture->iType)
 		{
 		{
-		case AI_TEXTYPE_DIFFUSE:
+		case aiTextureType_DIFFUSE:
 			if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture != piTexture)
 			if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture != piTexture)
 			{
 			{
 				pcMesh->piDiffuseTexture->Release();
 				pcMesh->piDiffuseTexture->Release();
@@ -257,7 +257,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 				}
 				}
 			}
 			}
 			break;
 			break;
-		case AI_TEXTYPE_AMBIENT:
+		case aiTextureType_AMBIENT:
 			if (pcMesh->piAmbientTexture && pcMesh->piAmbientTexture != piTexture)
 			if (pcMesh->piAmbientTexture && pcMesh->piAmbientTexture != piTexture)
 			{
 			{
 				pcMesh->piAmbientTexture->Release();
 				pcMesh->piAmbientTexture->Release();
@@ -270,7 +270,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 				}
 				}
 			}
 			}
 			break;
 			break;
-		case AI_TEXTYPE_SPECULAR:
+		case aiTextureType_SPECULAR:
 			if (pcMesh->piSpecularTexture && pcMesh->piSpecularTexture != piTexture)
 			if (pcMesh->piSpecularTexture && pcMesh->piSpecularTexture != piTexture)
 			{
 			{
 				pcMesh->piSpecularTexture->Release();
 				pcMesh->piSpecularTexture->Release();
@@ -283,7 +283,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 				}
 				}
 			}
 			}
 			break;
 			break;
-		case AI_TEXTYPE_EMISSIVE:
+		case aiTextureType_EMISSIVE:
 			if (pcMesh->piEmissiveTexture && pcMesh->piEmissiveTexture != piTexture)
 			if (pcMesh->piEmissiveTexture && pcMesh->piEmissiveTexture != piTexture)
 			{
 			{
 				pcMesh->piEmissiveTexture->Release();
 				pcMesh->piEmissiveTexture->Release();
@@ -296,7 +296,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 				}
 				}
 			}
 			}
 			break;
 			break;
-		case AI_TEXTYPE_SHININESS:
+		case aiTextureType_SHININESS:
 			if (pcMesh->piShininessTexture && pcMesh->piShininessTexture != piTexture)
 			if (pcMesh->piShininessTexture && pcMesh->piShininessTexture != piTexture)
 			{
 			{
 				pcMesh->piShininessTexture->Release();
 				pcMesh->piShininessTexture->Release();
@@ -309,8 +309,8 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 				}
 				}
 			}
 			}
 			break;
 			break;
-		case AI_TEXTYPE_NORMALS:
-		case AI_TEXTYPE_HEIGHT:
+		case aiTextureType_NORMALS:
+		case aiTextureType_HEIGHT:
 			if (pcMesh->piNormalTexture && pcMesh->piNormalTexture != piTexture)
 			if (pcMesh->piNormalTexture && pcMesh->piNormalTexture != piTexture)
 			{
 			{
 				pcMesh->piNormalTexture->Release();
 				pcMesh->piNormalTexture->Release();
@@ -325,7 +325,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 				}
 				}
 			}
 			}
 			break;
 			break;
-		default: //case AI_TEXTYPE_OPACITY && case AI_TEXTYPE_OPACITY | 0x40000000:
+		default: //case aiTextureType_OPACITY && case aiTextureType_OPACITY | 0x40000000:
 			if (pcMesh->piOpacityTexture && pcMesh->piOpacityTexture != piTexture)
 			if (pcMesh->piOpacityTexture && pcMesh->piOpacityTexture != piTexture)
 			{
 			{
 				pcMesh->piOpacityTexture->Release();
 				pcMesh->piOpacityTexture->Release();
@@ -340,42 +340,44 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 			break;
 			break;
 		};
 		};
 	}
 	}
-
 	// now update the material itself
 	// now update the material itself
 	aiString szOld;
 	aiString szOld;
 	const char* szKey = NULL;
 	const char* szKey = NULL;
+#if 0
 	switch (this->m_pcCurrentTexture->iType)
 	switch (this->m_pcCurrentTexture->iType)
 	{
 	{
-	case AI_TEXTYPE_DIFFUSE:
+	case aiTextureType_DIFFUSE:
 		szKey = AI_MATKEY_TEXTURE_DIFFUSE(0);
 		szKey = AI_MATKEY_TEXTURE_DIFFUSE(0);
 		break;
 		break;
-	case AI_TEXTYPE_AMBIENT:
+	case aiTextureType_AMBIENT:
 		szKey = AI_MATKEY_TEXTURE_AMBIENT(0);
 		szKey = AI_MATKEY_TEXTURE_AMBIENT(0);
 		break;
 		break;
-	case AI_TEXTYPE_SPECULAR:
+	case aiTextureType_SPECULAR:
 		szKey = AI_MATKEY_TEXTURE_SPECULAR(0);
 		szKey = AI_MATKEY_TEXTURE_SPECULAR(0);
 		break;
 		break;
-	case AI_TEXTYPE_EMISSIVE:
+	case aiTextureType_EMISSIVE:
 		szKey = AI_MATKEY_TEXTURE_EMISSIVE(0);
 		szKey = AI_MATKEY_TEXTURE_EMISSIVE(0);
 		break;
 		break;
-	case AI_TEXTYPE_NORMALS:
+	case aiTextureType_NORMALS:
 		szKey = AI_MATKEY_TEXTURE_NORMALS(0);
 		szKey = AI_MATKEY_TEXTURE_NORMALS(0);
 		break;
 		break;
-	case AI_TEXTYPE_HEIGHT:
+	case aiTextureType_HEIGHT:
 		szKey = AI_MATKEY_TEXTURE_HEIGHT(0);
 		szKey = AI_MATKEY_TEXTURE_HEIGHT(0);
 		break;
 		break;
-	case AI_TEXTYPE_SHININESS:
+	case aiTextureType_SHININESS:
 		szKey = AI_MATKEY_TEXTURE_SHININESS(0);
 		szKey = AI_MATKEY_TEXTURE_SHININESS(0);
 		break;
 		break;
-	default: //case AI_TEXTYPE_OPACITY && case AI_TEXTYPE_OPACITY | 0x40000000:
+	default: //case aiTextureType_OPACITY && case aiTextureType_OPACITY | 0x40000000:
 		szKey = AI_MATKEY_TEXTURE_OPACITY(0);
 		szKey = AI_MATKEY_TEXTURE_OPACITY(0);
 		break;
 		break;
 	};
 	};
+#endif
 	ai_assert(NULL != szKey);
 	ai_assert(NULL != szKey);
 
 
-	aiGetMaterialString(pcMat,szKey,&szOld);
-	pcMat->AddProperty(&szString,szKey);
+	aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE(m_pcCurrentTexture->iType,0),&szOld);
+	pcMat->AddProperty(&szString,AI_MATKEY_TEXTURE(m_pcCurrentTexture->iType,0));
 
 
+#if 0
 	char szBuffer[512];
 	char szBuffer[512];
 	sprintf(szBuffer,"%s%s",szKey,"_old");
 	sprintf(szBuffer,"%s%s",szKey,"_old");
 
 
@@ -388,6 +390,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 	{
 	{
 		pcMat->RemoveProperty(szBuffer);
 		pcMat->RemoveProperty(szBuffer);
 	}
 	}
+#endif
 	return 1;
 	return 1;
 }
 }
 //-------------------------------------------------------------------------------
 //-------------------------------------------------------------------------------
@@ -426,31 +429,31 @@ int CDisplay::AddTextureToDisplayList(unsigned int iType,
 	IDirect3DTexture9** piTexture;
 	IDirect3DTexture9** piTexture;
 	switch (iType)
 	switch (iType)
 	{
 	{
-	case AI_TEXTYPE_DIFFUSE:
+	case aiTextureType_DIFFUSE:
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piDiffuseTexture;
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piDiffuseTexture;
 		szType = "Diffuse";
 		szType = "Diffuse";
 		break;
 		break;
-	case AI_TEXTYPE_SPECULAR:
+	case aiTextureType_SPECULAR:
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piSpecularTexture;
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piSpecularTexture;
 		szType = "Specular";
 		szType = "Specular";
 		break;
 		break;
-	case AI_TEXTYPE_AMBIENT:
+	case aiTextureType_AMBIENT:
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piAmbientTexture;
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piAmbientTexture;
 		szType = "Ambient";
 		szType = "Ambient";
 		break;
 		break;
-	case AI_TEXTYPE_EMISSIVE:
+	case aiTextureType_EMISSIVE:
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piEmissiveTexture;
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piEmissiveTexture;
 		szType = "Emissive";
 		szType = "Emissive";
 		break;
 		break;
-	case AI_TEXTYPE_HEIGHT:
+	case aiTextureType_HEIGHT:
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture;
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture;
 		szType = "HeightMap";
 		szType = "HeightMap";
 		break;
 		break;
-	case AI_TEXTYPE_NORMALS:
+	case aiTextureType_NORMALS:
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture;
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture;
 		szType = "NormalMap";
 		szType = "NormalMap";
 		break;
 		break;
-	case AI_TEXTYPE_SHININESS:
+	case aiTextureType_SHININESS:
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piShininessTexture;
 		piTexture = &g_pcAsset->apcMeshes[iMesh]->piShininessTexture;
 		szType = "Shininess";
 		szType = "Shininess";
 		break;
 		break;
@@ -578,8 +581,8 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
 		(LPARAM)(LPTVINSERTSTRUCT)&sNew);
 		(LPARAM)(LPTVINSERTSTRUCT)&sNew);
 
 
 	// for each texture in the list ... add it
 	// for each texture in the list ... add it
-	// NOTE: This expects that AI_TEXTYPE_DIFFUSE is 7
-	ai_assert(7 == AI_TEXTYPE_DIFFUSE);
+	// NOTE: This expects that aiTextureType_DIFFUSE is 7
+	ai_assert(7 == aiTextureType_DIFFUSE);
 	unsigned int iUV;
 	unsigned int iUV;
 	float fBlend;
 	float fBlend;
 	aiTextureOp eOp;
 	aiTextureOp eOp;
@@ -590,12 +593,12 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
 		unsigned int iNum = 0;
 		unsigned int iNum = 0;
 		while (true)
 		while (true)
 		{
 		{
-			if (AI_SUCCESS != aiGetMaterialTexture(pcMat,iNum,i,
-				&szPath,&iUV,&fBlend,&eOp))
+			if (AI_SUCCESS != aiGetMaterialTexture(pcMat,(aiTextureType)i,iNum,
+				&szPath,NULL, &iUV,&fBlend,&eOp))
 			{
 			{
 				break;
 				break;
 			}
 			}
-			if (AI_TEXTYPE_OPACITY == i)bNoOpacity = false;
+			if (aiTextureType_OPACITY == i)bNoOpacity = false;
 			AddTextureToDisplayList(i,iNum,&szPath,hTexture,iUV,fBlend,eOp,iMesh);
 			AddTextureToDisplayList(i,iNum,&szPath,hTexture,iUV,fBlend,eOp,iMesh);
 			++iNum;
 			++iNum;
 		}
 		}
@@ -619,7 +622,7 @@ int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
 		{
 		{
 			// seems the diffuse texture contains alpha, therefore it has been
 			// seems the diffuse texture contains alpha, therefore it has been
 			// added to the opacity channel, too. Add a special value ...
 			// added to the opacity channel, too. Add a special value ...
-			AddTextureToDisplayList(AI_TEXTYPE_OPACITY | 0x40000000,
+			AddTextureToDisplayList(aiTextureType_OPACITY | 0x40000000,
 				0,&szPath,hTexture,iUV,fBlend,eOp,iMesh);
 				0,&szPath,hTexture,iUV,fBlend,eOp,iMesh);
 		}
 		}
 	}
 	}
@@ -967,7 +970,7 @@ int CDisplay::OnSetupTextureView(TextureInfo* pcNew)
 		ShowNormalUIComponents();
 		ShowNormalUIComponents();
 	}
 	}
 
 
-	if ((AI_TEXTYPE_OPACITY | 0x40000000) == pcNew->iType)
+	if ((aiTextureType_OPACITY | 0x40000000) == pcNew->iType)
 	{
 	{
 		// for opacity textures display a warn message
 		// for opacity textures display a warn message
 		CLogDisplay::Instance().AddEntry("[INFO] This texture is not existing in the "
 		CLogDisplay::Instance().AddEntry("[INFO] This texture is not existing in the "
@@ -1204,7 +1207,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam)
 					g_pcAsset->apcMeshes[i],"DIFFUSE_COLOR"));
 					g_pcAsset->apcMeshes[i],"DIFFUSE_COLOR"));
 			}
 			}
 		}
 		}
-		szMatKey = AI_MATKEY_COLOR_DIFFUSE;
+		szMatKey = "$clr.diffuse";
 		break;
 		break;
 	case ID_SOLONG_CLEARSPECULARCOLOR:
 	case ID_SOLONG_CLEARSPECULARCOLOR:
 		for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
 		for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
@@ -1215,7 +1218,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam)
 					g_pcAsset->apcMeshes[i],"SPECULAR_COLOR"));
 					g_pcAsset->apcMeshes[i],"SPECULAR_COLOR"));
 			}
 			}
 		}
 		}
-		szMatKey = AI_MATKEY_COLOR_SPECULAR;
+		szMatKey = "$clr.specular";
 		break;
 		break;
 	case ID_SOLONG_CLEARAMBIENTCOLOR:
 	case ID_SOLONG_CLEARAMBIENTCOLOR:
 		for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
 		for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
@@ -1226,7 +1229,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam)
 					g_pcAsset->apcMeshes[i],"AMBIENT_COLOR"));
 					g_pcAsset->apcMeshes[i],"AMBIENT_COLOR"));
 			}
 			}
 		}
 		}
-		szMatKey = AI_MATKEY_COLOR_AMBIENT;
+		szMatKey = "$clr.ambient";
 		break;
 		break;
 	case ID_SOLONG_CLEAREMISSIVECOLOR:
 	case ID_SOLONG_CLEAREMISSIVECOLOR:
 		for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
 		for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
@@ -1237,7 +1240,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam)
 					g_pcAsset->apcMeshes[i],"EMISSIVE_COLOR"));
 					g_pcAsset->apcMeshes[i],"EMISSIVE_COLOR"));
 			}
 			}
 		}
 		}
-		szMatKey = AI_MATKEY_COLOR_EMISSIVE;
+		szMatKey = "$clr.emissive";
 		break;
 		break;
 	default:
 	default:
 
 
@@ -1283,7 +1286,7 @@ int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam)
 		// change the material key ...
 		// change the material key ...
 		Assimp::MaterialHelper* pcMat = (Assimp::MaterialHelper*)g_pcAsset->pcScene->mMaterials[
 		Assimp::MaterialHelper* pcMat = (Assimp::MaterialHelper*)g_pcAsset->pcScene->mMaterials[
 			this->m_pcCurrentMaterial->iIndex];
 			this->m_pcCurrentMaterial->iIndex];
-		pcMat->AddProperty<aiColor4D>(&clrOld,1,szMatKey);
+		pcMat->AddProperty<aiColor4D>(&clrOld,1,szMatKey,0,0);
 
 
 		if (ID_SOLONG_CLEARSPECULARCOLOR == LOWORD(wParam) &&
 		if (ID_SOLONG_CLEARSPECULARCOLOR == LOWORD(wParam) &&
 			aiShadingMode_Gouraud == apclrOut.front().pMesh->eShadingMode)
 			aiShadingMode_Gouraud == apclrOut.front().pMesh->eShadingMode)
@@ -1420,35 +1423,35 @@ int CDisplay::HandleTreeViewPopup2(WPARAM wParam,LPARAM lParam)
 
 
 		switch (this->m_pcCurrentTexture->iType)
 		switch (this->m_pcCurrentTexture->iType)
 		{
 		{
-		case AI_TEXTYPE_DIFFUSE:
+		case aiTextureType_DIFFUSE:
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_DIFFUSE(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_DIFFUSE(0));
 			break;
 			break;
-		case AI_TEXTYPE_SPECULAR:
+		case aiTextureType_SPECULAR:
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_SPECULAR(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_SPECULAR(0));
 			break;
 			break;
-		case AI_TEXTYPE_AMBIENT:
+		case aiTextureType_AMBIENT:
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_AMBIENT(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_AMBIENT(0));
 			break;
 			break;
-		case AI_TEXTYPE_EMISSIVE:
+		case aiTextureType_EMISSIVE:
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_EMISSIVE(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_EMISSIVE(0));
 			break;
 			break;
-		case AI_TEXTYPE_NORMALS:
+		case aiTextureType_NORMALS:
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_NORMALS(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_NORMALS(0));
 			break;
 			break;
-		case AI_TEXTYPE_HEIGHT:
+		case aiTextureType_HEIGHT:
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_HEIGHT(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_HEIGHT(0));
 			break;
 			break;
-		case AI_TEXTYPE_SHININESS:
+		case aiTextureType_SHININESS:
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_SHININESS(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_SHININESS(0));
 			break;
 			break;
-		case (AI_TEXTYPE_OPACITY | 0x40000000):
+		case (aiTextureType_OPACITY | 0x40000000):
 		
 		
 			// set a special property to indicate that no alpha channel is required
 			// set a special property to indicate that no alpha channel is required
 			{int iVal = 1;
 			{int iVal = 1;
-			pcMat->AddProperty<int>(&iVal,1,"no_a_from_d");}
+			pcMat->AddProperty<int>(&iVal,1,"no_a_from_d",0,0);}
 
 
 			break;
 			break;
-		default: //case AI_TEXTYPE_OPACITY
+		default: //case aiTextureType_OPACITY
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_OPACITY(0));
 			pcMat->RemoveProperty(AI_MATKEY_TEXTURE_OPACITY(0));
 		};
 		};
 
 
@@ -1505,41 +1508,42 @@ int CDisplay::HandleTreeViewPopup2(WPARAM wParam,LPARAM lParam)
 		TreeView_Select(GetDlgItem(g_hDlg,IDC_TREE1),this->m_hRoot,TVGN_CARET);
 		TreeView_Select(GetDlgItem(g_hDlg,IDC_TREE1),this->m_hRoot,TVGN_CARET);
 		return 1;
 		return 1;
 		}
 		}
-
+#if 0
 	case ID_HEY_RESETTEXTURE:
 	case ID_HEY_RESETTEXTURE:
 		{
 		{
 		aiString szOld;
 		aiString szOld;
 		aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[this->m_pcCurrentTexture->iMatIndex];
 		aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[this->m_pcCurrentTexture->iMatIndex];
 		switch (this->m_pcCurrentTexture->iType)
 		switch (this->m_pcCurrentTexture->iType)
 		{
 		{
-		case AI_TEXTYPE_DIFFUSE:
+		case aiTextureType_DIFFUSE:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0) "_old",&szOld);
 			break;
 			break;
-		case AI_TEXTYPE_SPECULAR:
+		case aiTextureType_SPECULAR:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0) "_old",&szOld);
 			break;
 			break;
-		case AI_TEXTYPE_AMBIENT:
+		case aiTextureType_AMBIENT:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0) "_old",&szOld);
 			break;
 			break;
-		case AI_TEXTYPE_EMISSIVE:
+		case aiTextureType_EMISSIVE:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0) "_old",&szOld);
 			break;
 			break;
-		case AI_TEXTYPE_NORMALS:
+		case aiTextureType_NORMALS:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0) "_old",&szOld);
 			break;
 			break;
-		case AI_TEXTYPE_HEIGHT:
+		case aiTextureType_HEIGHT:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0) "_old",&szOld);
 			break;
 			break;
-		case AI_TEXTYPE_SHININESS:
+		case aiTextureType_SHININESS:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0) "_old",&szOld);
 			break;
 			break;
-		default : //case AI_TEXTYPE_OPACITY && case AI_TEXTYPE_OPACITY | 0x40000000:
+		default : //case aiTextureType_OPACITY && case aiTextureType_OPACITY | 0x40000000:
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0) "_old",&szOld);
 			aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0) "_old",&szOld);
 			break;
 			break;
 		};
 		};
 		if (0 != szOld.length)this->ReplaceCurrentTexture(szOld.data);
 		if (0 != szOld.length)this->ReplaceCurrentTexture(szOld.data);
 		return 1;
 		return 1;
 		}
 		}
+#endif
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -2195,11 +2199,11 @@ int CDisplay::RenderTextureView()
 	// commit the texture to the shader
 	// commit the texture to the shader
 	g_piPassThroughEffect->SetTexture("TEXTURE_2D",*this->m_pcCurrentTexture->piTexture);
 	g_piPassThroughEffect->SetTexture("TEXTURE_2D",*this->m_pcCurrentTexture->piTexture);
 
 
-	if (AI_TEXTYPE_OPACITY == this->m_pcCurrentTexture->iType)
+	if (aiTextureType_OPACITY == this->m_pcCurrentTexture->iType)
 	{
 	{
 		g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromR");
 		g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromR");
 	}
 	}
-	else if ((AI_TEXTYPE_OPACITY | 0x40000000) == this->m_pcCurrentTexture->iType)
+	else if ((aiTextureType_OPACITY | 0x40000000) == this->m_pcCurrentTexture->iType)
 	{
 	{
 		g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromA");
 		g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromA");
 	}
 	}
@@ -2212,8 +2216,8 @@ int CDisplay::RenderTextureView()
 	g_piPassThroughEffect->Begin(&dw,0);
 	g_piPassThroughEffect->Begin(&dw,0);
 	g_piPassThroughEffect->BeginPass(0);
 	g_piPassThroughEffect->BeginPass(0);
 
 
-	if (AI_TEXTYPE_HEIGHT == this->m_pcCurrentTexture->iType ||
-		AI_TEXTYPE_NORMALS == this->m_pcCurrentTexture->iType)
+	if (aiTextureType_HEIGHT == this->m_pcCurrentTexture->iType ||
+		aiTextureType_NORMALS == this->m_pcCurrentTexture->iType)
 	{
 	{
 		// manually disable alpha blending
 		// manually disable alpha blending
 		g_piDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);
 		g_piDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);

+ 31 - 2
tools/assimp_view/Material.cpp

@@ -786,6 +786,9 @@ int CMaterialManager::CreateMaterial(
 
 
 	aiString szPath;
 	aiString szPath;
 
 
+	aiTextureMapMode mapU(aiTextureMapMode_Wrap),mapV(aiTextureMapMode_Wrap);
+
+	bool bib =false;
 	if (pcSource->mTextureCoords[0])
 	if (pcSource->mTextureCoords[0])
 	{
 	{
 
 
@@ -795,6 +798,9 @@ int CMaterialManager::CreateMaterial(
 		if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath))
 		if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath))
 		{
 		{
 			LoadTexture(&pcMesh->piDiffuseTexture,&szPath);
 			LoadTexture(&pcMesh->piDiffuseTexture,&szPath);
+
+			aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0),(int*)&mapU);
+			aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0),(int*)&mapV);
 		}
 		}
 
 
 		if (pcSource->mTextureCoords[1])
 		if (pcSource->mTextureCoords[1])
@@ -833,7 +839,7 @@ int CMaterialManager::CreateMaterial(
 
 
 				// NOTE: This special value is set by the tree view if the user
 				// NOTE: This special value is set by the tree view if the user
 				// manually removes the alpha texture from the view ...
 				// manually removes the alpha texture from the view ...
-				if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",&iVal))
+				if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",0,0,&iVal))
 				{
 				{
 					pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture;
 					pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture;
 					pcMesh->piOpacityTexture->AddRef();
 					pcMesh->piOpacityTexture->AddRef();
@@ -879,6 +885,7 @@ int CMaterialManager::CreateMaterial(
 			{
 			{
 				LoadTexture(&pcMesh->piNormalTexture,&szPath);
 				LoadTexture(&pcMesh->piNormalTexture,&szPath);
 			}
 			}
+			else bib = true;
 			bHM = true;
 			bHM = true;
 		}
 		}
 
 
@@ -968,6 +975,28 @@ int CMaterialManager::CreateMaterial(
 		sMacro[iCurrent].Name = "AV_DIFFUSE_TEXTURE";
 		sMacro[iCurrent].Name = "AV_DIFFUSE_TEXTURE";
 		sMacro[iCurrent].Definition = "1";
 		sMacro[iCurrent].Definition = "1";
 		++iCurrent;
 		++iCurrent;
+
+		if (mapU == aiTextureMapMode_Wrap)
+			sMacro[iCurrent].Name = "AV_WRAPU";
+		else if (mapU == aiTextureMapMode_Mirror)
+			sMacro[iCurrent].Name = "AV_MIRRORU";
+		else // if (mapU == aiTextureMapMode_Clamp)
+			sMacro[iCurrent].Name = "AV_CLAMPU";
+
+		sMacro[iCurrent].Definition = "1";
+		++iCurrent;
+
+
+
+		if (mapV == aiTextureMapMode_Wrap)
+			sMacro[iCurrent].Name = "AV_WRAPV";
+		else if (mapV == aiTextureMapMode_Mirror)
+			sMacro[iCurrent].Name = "AV_MIRRORV";
+		else // if (mapV == aiTextureMapMode_Clamp)
+			sMacro[iCurrent].Name = "AV_CLAMPV";
+
+		sMacro[iCurrent].Definition = "1";
+		++iCurrent;
 	}
 	}
 	if (pcMesh->piDiffuseTexture2)
 	if (pcMesh->piDiffuseTexture2)
 	{
 	{
@@ -993,7 +1022,7 @@ int CMaterialManager::CreateMaterial(
 		sMacro[iCurrent].Definition = "1";
 		sMacro[iCurrent].Definition = "1";
 		++iCurrent;
 		++iCurrent;
 	}
 	}
-	if (pcMesh->piNormalTexture)
+	if (pcMesh->piNormalTexture && !bib)
 	{
 	{
 		sMacro[iCurrent].Name = "AV_NORMAL_TEXTURE";
 		sMacro[iCurrent].Name = "AV_NORMAL_TEXTURE";
 		sMacro[iCurrent].Definition = "1";
 		sMacro[iCurrent].Definition = "1";

+ 18 - 0
tools/assimp_view/Shaders.cpp

@@ -530,6 +530,24 @@ std::string g_szMaterialShader = std::string(
 		"sampler DIFFUSE_SAMPLER\n"
 		"sampler DIFFUSE_SAMPLER\n"
 		"{\n"
 		"{\n"
 		  "Texture = <DIFFUSE_TEXTURE>;\n"
 		  "Texture = <DIFFUSE_TEXTURE>;\n"
+		  "#ifdef AV_WRAPU\n"
+		  "AddressU = WRAP;\n"
+		  "#endif\n"
+		  "#ifdef AV_MIRRORU\n"
+		  "AddressU = MIRROR;\n"
+		  "#endif\n"
+		  "#ifdef AV_CLAMPU\n"
+		  "AddressU = CLAMP;\n"
+		  "#endif\n"
+		  "#ifdef AV_WRAPV\n"
+		  "AddressV = WRAP;\n"
+		  "#endif\n"
+		  "#ifdef AV_MIRRORV\n"
+		  "AddressV = MIRROR;\n"
+		  "#endif\n"
+		  "#ifdef AV_CLAMPV\n"
+		  "AddressV = CLAMP;\n"
+		  "#endif\n"
 		  "MinFilter=LINEAR;\n"
 		  "MinFilter=LINEAR;\n"
 		  "MagFilter=LINEAR;\n"
 		  "MagFilter=LINEAR;\n"
 		  "MipFilter=LINEAR;\n"
 		  "MipFilter=LINEAR;\n"

+ 2 - 1
tools/assimp_view/assimp_view.cpp

@@ -140,7 +140,8 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
 		aiProcess_SplitLargeMeshes      | // split large, unrenderable meshes into submeshes
 		aiProcess_SplitLargeMeshes      | // split large, unrenderable meshes into submeshes
 		aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality 
 		aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality 
 		| aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType |
 		| aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType |
-		aiProcess_FindDegenerates | aiProcess_FindInvalidData); // validate the output data structure
+		aiProcess_FindDegenerates | aiProcess_FindInvalidData |
+		aiProcess_GenUVCoords | aiProcess_TransformUVCoords ); // validate the output data structure
 
 
 	// get the end time of zje operation, calculate delta t
 	// get the end time of zje operation, calculate delta t
 	double fEnd = (double)timeGetTime();
 	double fEnd = (double)timeGetTime();

+ 28 - 8
workspaces/vc8/assimp.vcproj

@@ -726,6 +726,10 @@
 					RelativePath="..\..\include\BoostWorkaround\boost\format.hpp"
 					RelativePath="..\..\include\BoostWorkaround\boost\format.hpp"
 					>
 					>
 				</File>
 				</File>
+				<File
+					RelativePath="..\..\include\BoostWorkaround\boost\scoped_array.h"
+					>
+				</File>
 				<File
 				<File
 					RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp"
 					RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp"
 					>
 					>
@@ -903,14 +907,6 @@
 				RelativePath="..\..\code\TargetAnimation.h"
 				RelativePath="..\..\code\TargetAnimation.h"
 				>
 				>
 			</File>
 			</File>
-			<File
-				RelativePath="..\..\code\TextureTransform.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\TextureTransform.h"
-				>
-			</File>
 			<File
 			<File
 				RelativePath="..\..\code\VertexTriangleAdjacency.cpp"
 				RelativePath="..\..\code\VertexTriangleAdjacency.cpp"
 				>
 				>
@@ -1344,6 +1340,14 @@
 					<File
 					<File
 						RelativePath="..\..\code\ACLoader.cpp"
 						RelativePath="..\..\code\ACLoader.cpp"
 						>
 						>
+						<FileConfiguration
+							Name="Debug|Win32"
+							>
+							<Tool
+								Name="VCCLCompilerTool"
+								GeneratePreprocessedFile="0"
+							/>
+						</FileConfiguration>
 					</File>
 					</File>
 					<File
 					<File
 						RelativePath="..\..\code\ACLoader.h"
 						RelativePath="..\..\code\ACLoader.h"
@@ -1454,6 +1458,14 @@
 					RelativePath="..\..\code\CalcTangentsProcess.h"
 					RelativePath="..\..\code\CalcTangentsProcess.h"
 					>
 					>
 				</File>
 				</File>
+				<File
+					RelativePath="..\..\code\ComputeUVMappingProcess.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\ComputeUVMappingProcess.h"
+					>
+				</File>
 				<File
 				<File
 					RelativePath="..\..\code\ConvertToLHProcess.cpp"
 					RelativePath="..\..\code\ConvertToLHProcess.cpp"
 					>
 					>
@@ -1574,6 +1586,14 @@
 					RelativePath="..\..\code\SplitLargeMeshes.h"
 					RelativePath="..\..\code\SplitLargeMeshes.h"
 					>
 					>
 				</File>
 				</File>
+				<File
+					RelativePath="..\..\code\TextureTransform.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\TextureTransform.h"
+					>
+				</File>
 				<File
 				<File
 					RelativePath="..\..\code\TriangulateProcess.cpp"
 					RelativePath="..\..\code\TriangulateProcess.cpp"
 					>
 					>

部分文件因文件數量過多而無法顯示