浏览代码

Added validation step, added helper macro AI_BUILD_KEY to the material system.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@59 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
aramis_acg 17 年之前
父节点
当前提交
758e092449

+ 2 - 13
code/3DSConverter.cpp

@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "3DSLoader.h"
 #include "3DSLoader.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
 #include "TextureTransform.h"
 #include "TextureTransform.h"
+#include "StringComparison.h"
 
 
 #include "../include/DefaultLogger.h"
 #include "../include/DefaultLogger.h"
 #include "../include/IOStream.h"
 #include "../include/IOStream.h"
@@ -114,7 +115,7 @@ void Dot3DSImporter::ReplaceDefaultMaterial()
 			}
 			}
 		}
 		}
 	}
 	}
-	if (0 != iCnt && iIndex == this->mScene->mMaterials.size())
+	if (iCnt && iIndex == this->mScene->mMaterials.size())
 	{
 	{
 		// we need to create our own default material
 		// we need to create our own default material
 		Dot3DS::Material sMat;
 		Dot3DS::Material sMat;
@@ -184,12 +185,6 @@ void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
 
 
 			sMesh->mFaces[i].mIndices[0] = iTemp1;
 			sMesh->mFaces[i].mIndices[0] = iTemp1;
 			sMesh->mFaces[i].mIndices[1] = iTemp2;
 			sMesh->mFaces[i].mIndices[1] = iTemp2;
-
-			// handle the face order ...
-			/*if (iTemp1 > iTemp2)
-			{
-				sMesh->mFaces[i].bFlipped = true;
-			}*/
 		}
 		}
 	}
 	}
 	else
 	else
@@ -210,12 +205,6 @@ void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
 
 
 			sMesh->mFaces[i].mIndices[0] = iTemp1;
 			sMesh->mFaces[i].mIndices[0] = iTemp1;
 			sMesh->mFaces[i].mIndices[1] = iTemp2;
 			sMesh->mFaces[i].mIndices[1] = iTemp2;
-
-			// handle the face order ...
-			/*if (iTemp1 > iTemp2)
-			{
-				sMesh->mFaces[i].bFlipped = true;
-			}*/
 		}
 		}
 	}
 	}
 	sMesh->mPositions = vNew;
 	sMesh->mPositions = vNew;

+ 1 - 0
code/3DSLoader.cpp

@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "3DSLoader.h"
 #include "3DSLoader.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
 #include "TextureTransform.h"
 #include "TextureTransform.h"
+#include "StringComparison.h"
 
 
 #include "../include/DefaultLogger.h"
 #include "../include/DefaultLogger.h"
 #include "../include/IOStream.h"
 #include "../include/IOStream.h"

+ 3 - 4
code/ASELoader.cpp

@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ASELoader.h"
 #include "ASELoader.h"
 #include "3DSSpatialSort.h"
 #include "3DSSpatialSort.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
+#include "StringComparison.h"
 #include "TextureTransform.h"
 #include "TextureTransform.h"
 #include "fast_atof.h"
 #include "fast_atof.h"
 
 
@@ -58,8 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 using namespace Assimp;
 using namespace Assimp::ASE;
 using namespace Assimp::ASE;
 
 
-#define LOGOUT_WARN(x) DefaultLogger::get()->warn(x);
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 ASEImporter::ASEImporter()
 ASEImporter::ASEImporter()
@@ -619,7 +618,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 	if (mesh.iMaterialIndex >= this->mParser->m_vMaterials.size())
 	if (mesh.iMaterialIndex >= this->mParser->m_vMaterials.size())
 	{
 	{
 		mesh.iMaterialIndex = (unsigned int)this->mParser->m_vMaterials.size()-1;
 		mesh.iMaterialIndex = (unsigned int)this->mParser->m_vMaterials.size()-1;
-		LOGOUT_WARN("Material index is out of range");
+		DefaultLogger::get()->warn("Material index is out of range");
 	}
 	}
 
 
 
 
@@ -640,7 +639,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 			// check range
 			// check range
 			if (mesh.mFaces[i].iMaterial >= vSubMaterials.size())
 			if (mesh.mFaces[i].iMaterial >= vSubMaterials.size())
 				{
 				{
-					LOGOUT_WARN("Submaterial index is out of range");
+					DefaultLogger::get()->warn("Submaterial index is out of range");
 
 
 					// use the last material instead
 					// use the last material instead
 					aiSplit[vSubMaterials.size()-1].push_back(i);
 					aiSplit[vSubMaterials.size()-1].push_back(i);

+ 44 - 8
code/ASEParser.cpp

@@ -81,10 +81,14 @@ Parser::Parser (const char* szFile)
 void Parser::LogWarning(const char* szWarn)
 void Parser::LogWarning(const char* szWarn)
 {
 {
 	ai_assert(NULL != szWarn);
 	ai_assert(NULL != szWarn);
-	ai_assert(strlen(szWarn) < 950);
 
 
 	char szTemp[1024];
 	char szTemp[1024];
-	sprintf(szTemp,"Line %i: %s",this->iLineNumber/2 /* fixme */,szWarn);
+#if _MSC_VER >= 1400
+	sprintf_s(szTemp,"Line %i: %s",this->iLineNumber,szWarn);
+#else
+	ai_assert(strlen(szWarn) < 950);
+	sprintf(szTemp,"Line %i: %s",this->iLineNumber,szWarn);
+#endif
 
 
 	// output the warning to the logger ...
 	// output the warning to the logger ...
 	DefaultLogger::get()->warn(szTemp);
 	DefaultLogger::get()->warn(szTemp);
@@ -93,10 +97,14 @@ void Parser::LogWarning(const char* szWarn)
 void Parser::LogInfo(const char* szWarn)
 void Parser::LogInfo(const char* szWarn)
 {
 {
 	ai_assert(NULL != szWarn);
 	ai_assert(NULL != szWarn);
-	ai_assert(strlen(szWarn) < 950);
 
 
 	char szTemp[1024];
 	char szTemp[1024];
-	sprintf(szTemp,"Line %i: %s",this->iLineNumber/2 /* fixme */,szWarn);
+#if _MSC_VER >= 1400
+	sprintf_s(szTemp,"Line %i: %s",this->iLineNumber,szWarn);
+#else
+	ai_assert(strlen(szWarn) < 950);
+	sprintf(szTemp,"Line %i: %s",this->iLineNumber,szWarn);
+#endif
 
 
 	// output the information to the logger ...
 	// output the information to the logger ...
 	DefaultLogger::get()->info(szTemp);
 	DefaultLogger::get()->info(szTemp);
@@ -105,10 +113,14 @@ void Parser::LogInfo(const char* szWarn)
 void Parser::LogError(const char* szWarn)
 void Parser::LogError(const char* szWarn)
 {
 {
 	ai_assert(NULL != szWarn);
 	ai_assert(NULL != szWarn);
-	ai_assert(strlen(szWarn) < 950);
 
 
 	char szTemp[1024];
 	char szTemp[1024];
-	sprintf(szTemp,"Line %i: %s",this->iLineNumber/2 /* fixme */,szWarn);
+#if _MSC_VER >= 1400
+	sprintf_s(szTemp,"Line %i: %s",this->iLineNumber,szWarn);
+#else
+	ai_assert(strlen(szWarn) < 950);
+	sprintf(szTemp,"Line %i: %s",this->iLineNumber,szWarn);
+#endif
 
 
 	// throw an exception
 	// throw an exception
 	throw new ImportErrorException(szTemp);
 	throw new ImportErrorException(szTemp);
@@ -118,8 +130,12 @@ bool Parser::SkipToNextToken()
 {
 {
 	while (true)
 	while (true)
 	{
 	{
-		if ('*' == *this->m_szFile || '}' == *this->m_szFile || '{' == *this->m_szFile)return true;
-		if ('\0' == *this->m_szFile)return false;
+		char me = *this->m_szFile;
+
+		// increase the line number counter if necessary
+		if (IsLineEnd(me))++this->iLineNumber;
+		else if ('*' == me || '}' == me || '{' == me)return true;
+		else if ('\0' == me)return false;
 
 
 		++this->m_szFile;
 		++this->m_szFile;
 	}
 	}
@@ -670,21 +686,33 @@ void Parser::ParseLV3MapBlock(Texture& map)
 bool Parser::ParseString(std::string& out,const char* szName)
 bool Parser::ParseString(std::string& out,const char* szName)
 {
 {
 	char szBuffer[1024];
 	char szBuffer[1024];
+
+#if (!defined _MSC_VER) || ( _MSC_VER < 1400)
 	ai_assert(strlen(szName) < 750);
 	ai_assert(strlen(szName) < 750);
+#endif
 
 
 	// NOTE: The name could also be the texture in some cases
 	// NOTE: The name could also be the texture in some cases
 	// be prepared that this might occur ...
 	// be prepared that this might occur ...
 	if (!SkipSpaces(this->m_szFile,&this->m_szFile))
 	if (!SkipSpaces(this->m_szFile,&this->m_szFile))
 	{
 	{
+#if _MSC_VER >= 1400
+		sprintf_s(szBuffer,"Unable to parse %s block: Unexpected EOL",szName);
+#else
 		sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName);
 		sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName);
+#endif
 		this->LogWarning(szBuffer);
 		this->LogWarning(szBuffer);
 		return false;
 		return false;
 	}
 	}
 	// there must be "
 	// there must be "
 	if ('\"' != *this->m_szFile)
 	if ('\"' != *this->m_szFile)
 	{
 	{
+#if _MSC_VER >= 1400
+		sprintf_s(szBuffer,"Unable to parse %s block: String is expected "
+			"to be enclosed in double quotation marks",szName);
+#else
 		sprintf(szBuffer,"Unable to parse %s block: String is expected "
 		sprintf(szBuffer,"Unable to parse %s block: String is expected "
 			"to be enclosed in double quotation marks",szName);
 			"to be enclosed in double quotation marks",szName);
+#endif
 		this->LogWarning(szBuffer);
 		this->LogWarning(szBuffer);
 		return false;
 		return false;
 	}
 	}
@@ -695,9 +723,15 @@ bool Parser::ParseString(std::string& out,const char* szName)
 		if ('\"' == *sz)break;
 		if ('\"' == *sz)break;
 		else if ('\0' == sz)
 		else if ('\0' == sz)
 		{
 		{
+#if _MSC_VER >= 1400
+			sprintf_s(szBuffer,"Unable to parse %s block: String is expected to be "
+				"enclosed in double quotation marks but EOF was reached before a closing "
+				"quotation mark was found",szName);
+#else
 			sprintf(szBuffer,"Unable to parse %s block: String is expected to be "
 			sprintf(szBuffer,"Unable to parse %s block: String is expected to be "
 				"enclosed in double quotation marks but EOF was reached before a closing "
 				"enclosed in double quotation marks but EOF was reached before a closing "
 				"quotation mark was found",szName);
 				"quotation mark was found",szName);
+#endif
 			this->LogWarning(szBuffer);
 			this->LogWarning(szBuffer);
 			return false;
 			return false;
 		}
 		}
@@ -968,6 +1002,7 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh)
 				this->LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
 				this->LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
 					"Keyframe animation is not supported by Assimp, this element "
 					"Keyframe animation is not supported by Assimp, this element "
 					"will be ignored");
 					"will be ignored");
+				//this->SkipSection();
 				continue;
 				continue;
 			}
 			}
 			// mesh animation keyframe. Not supported
 			// mesh animation keyframe. Not supported
@@ -1538,6 +1573,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
 		{
 		{
 			BLUBB("Unable to parse *MESH_NORMALS Element: Unexpected EOL [#1]")
 			BLUBB("Unable to parse *MESH_NORMALS Element: Unexpected EOL [#1]")
 		}
 		}
+		else if(IsLineEnd(*this->m_szFile))++this->iLineNumber;
 		this->m_szFile++;
 		this->m_szFile++;
 	}
 	}
 	return;
 	return;

+ 28 - 0
code/BaseImporter.cpp

@@ -41,9 +41,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 /** @file Implementation of the few default functions of the base importer class */
 /** @file Implementation of the few default functions of the base importer class */
 #include "BaseImporter.h"
 #include "BaseImporter.h"
+#include "BaseProcess.h"
+
 #include "../include/DefaultLogger.h"
 #include "../include/DefaultLogger.h"
 #include "../include/aiScene.h"
 #include "../include/aiScene.h"
 #include "../include/aiAssert.h"
 #include "../include/aiAssert.h"
+#include "../include/assimp.hpp"
 using namespace Assimp;
 using namespace Assimp;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -88,3 +91,28 @@ aiScene* BaseImporter::ReadFile( const std::string& pFile, IOSystem* pIOHandler)
 	// return what we gathered from the import. 
 	// return what we gathered from the import. 
 	return scene;
 	return scene;
 }
 }
+
+// ------------------------------------------------------------------------------------------------
+void BaseProcess::ExecuteOnScene( Importer* pImp)
+{
+	ai_assert(NULL != pImp && NULL != pImp->mScene);
+
+	// catch exceptions thrown inside the PostProcess-Step
+	try
+	{
+		this->Execute(pImp->mScene);
+
+	} catch( ImportErrorException* exception)
+	{
+		// extract error description
+		pImp->mErrorString = exception->GetErrorText();
+
+		DefaultLogger::get()->error(pImp->mErrorString);
+
+		delete exception;
+
+		// and kill the partially imported data
+		delete pImp->mScene;
+		pImp->mScene = NULL;
+	}
+}

+ 10 - 1
code/BaseProcess.h

@@ -78,7 +78,16 @@ public:
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Executes the post processing step on the given imported data.
 	/** Executes the post processing step on the given imported data.
-	* At the moment a process is not supposed to fail.
+	* The function deletes the scene if the postprocess step fails (
+	* the object pointer will be set to NULL).
+	* @param pImp Importer instance (pImp->mScene must be valid)
+	*/
+	void ExecuteOnScene( Importer* pImp);
+
+	// -------------------------------------------------------------------
+	/** Executes the post processing step on the given imported data.
+	* A process should throw an ImportErrorException* if it fails.
+	* This method must be implemented by deriving classes.
 	* @param pScene The imported data to work at.
 	* @param pScene The imported data to work at.
 	*/
 	*/
 	virtual void Execute( aiScene* pScene) = 0;
 	virtual void Execute( aiScene* pScene) = 0;

+ 15 - 6
code/Importer.cpp

@@ -47,6 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/aiAssert.h"
 #include "../include/aiAssert.h"
 #include "../include/aiScene.h"
 #include "../include/aiScene.h"
 #include "../include/aiPostProcess.h"
 #include "../include/aiPostProcess.h"
+#include "../include/DefaultLogger.h"
+
 #include "BaseImporter.h"
 #include "BaseImporter.h"
 #include "BaseProcess.h"
 #include "BaseProcess.h"
 #include "DefaultIOStream.h"
 #include "DefaultIOStream.h"
@@ -90,7 +92,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "SplitLargeMeshes.h"
 #include "SplitLargeMeshes.h"
 #include "PretransformVertices.h"
 #include "PretransformVertices.h"
 #include "LimitBoneWeightsProcess.h"
 #include "LimitBoneWeightsProcess.h"
-#include "../include/DefaultLogger.h"
+#include "ValidateDataStructure.h"
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
@@ -134,6 +136,7 @@ Importer::Importer() :
 #endif
 #endif
 
 
 	// add an instance of each post processing step here in the order of sequence it is executed
 	// add an instance of each post processing step here in the order of sequence it is executed
+	mPostProcessingSteps.push_back( new ValidateDSProcess());
 	mPostProcessingSteps.push_back( new TriangulateProcess());
 	mPostProcessingSteps.push_back( new TriangulateProcess());
 	mPostProcessingSteps.push_back( new PretransformVertices());
 	mPostProcessingSteps.push_back( new PretransformVertices());
 	mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Triangle());
 	mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Triangle());
@@ -237,10 +240,7 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
 
 
 	// dispatch the reading to the worker class for this format
 	// dispatch the reading to the worker class for this format
 	mScene = imp->ReadFile( pFile, mIOHandler);
 	mScene = imp->ReadFile( pFile, mIOHandler);
-	// if failed, extract the error string
-	if( !mScene)
-		mErrorString = imp->GetErrorText();
-
+	
 	// if successful, apply all active post processing steps to the imported data
 	// if successful, apply all active post processing steps to the imported data
 	if( mScene)
 	if( mScene)
 	{
 	{
@@ -248,10 +248,19 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
 		{
 		{
 			BaseProcess* process = mPostProcessingSteps[a];
 			BaseProcess* process = mPostProcessingSteps[a];
 			if( process->IsActive( pFlags))
 			if( process->IsActive( pFlags))
-				process->Execute( mScene);
+			{
+				process->ExecuteOnScene( this );
+			}
+			if( !mScene)break; // error string has already been set ...
 		}
 		}
 	}
 	}
 
 
+	// if failed, extract the error string
+	else if( !mScene)
+	{
+		mErrorString = imp->GetErrorText();
+	}
+
 	// either successful or failure - the pointer expresses it anyways
 	// either successful or failure - the pointer expresses it anyways
 	return mScene;
 	return mScene;
 }
 }

+ 1 - 0
code/MD3Loader.cpp

@@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /** @file Implementation of the MD3 importer class */
 /** @file Implementation of the MD3 importer class */
 #include "MD3Loader.h"
 #include "MD3Loader.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
+#include "StringComparison.h"
 
 
 #include "../include/IOStream.h"
 #include "../include/IOStream.h"
 #include "../include/IOSystem.h"
 #include "../include/IOSystem.h"

+ 35 - 7
code/MaterialSystem.cpp

@@ -38,10 +38,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
-#include "../include/aiMaterial.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
+#include "StringComparison.h"
 
 
-
+#include "../include/aiMaterial.h"
 #include "../include/aiAssert.h"
 #include "../include/aiAssert.h"
 
 
 using namespace Assimp;
 using namespace Assimp;
@@ -363,6 +363,13 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
 	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,
 aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
 	unsigned int iIndex,
 	unsigned int iIndex,
 	unsigned int iTexType,
 	unsigned int iTexType,
@@ -460,7 +467,12 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
 	char szKey[256];
 	char szKey[256];
 
 
 	// get the path to the texture
 	// get the path to the texture
-	sprintf(szKey,"%s[%i]",szPathBase,iIndex);
+#if _MSC_VER >= 1400
+	if(0 >= sprintf_s(szKey,"%s[%i]",szPathBase,iIndex))DummyAssertFunction();
+#else
+	if(0 >= sprintf(szKey,"%s[%i]",szPathBase,iIndex))DummyAssertFunction();
+#endif
+
 	if (AI_SUCCESS != aiGetMaterialString(pcMat,szKey,szOut))
 	if (AI_SUCCESS != aiGetMaterialString(pcMat,szKey,szOut))
 	{
 	{
 		return AI_FAILURE;
 		return AI_FAILURE;
@@ -469,7 +481,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
 	if (piUVIndex)
 	if (piUVIndex)
 	{
 	{
 		int iUV;
 		int iUV;
-		sprintf(szKey,"%s[%i]",szUVBase,iIndex);
+#if _MSC_VER >= 1400
+		if(0 >= sprintf_s(szKey,"%s[%i]",szUVBase,iIndex))DummyAssertFunction();
+#else
+		if(0 >= sprintf(szKey,"%s[%i]",szUVBase,iIndex))DummyAssertFunction();
+#endif
 		if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,&iUV))
 		if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,&iUV))
 			iUV = 0;
 			iUV = 0;
 
 
@@ -479,7 +495,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
 	if (pfBlendFactor)
 	if (pfBlendFactor)
 	{
 	{
 		float fBlend;
 		float fBlend;
-		sprintf(szKey,"%s[%i]",szBlendBase,iIndex);
+#if _MSC_VER >= 1400
+		if(0 >= sprintf_s(szKey,"%s[%i]",szBlendBase,iIndex))DummyAssertFunction();
+#else
+		if(0 >= sprintf(szKey,"%s[%i]",szBlendBase,iIndex))DummyAssertFunction();
+#endif
 		if (AI_SUCCESS != aiGetMaterialFloat(pcMat,szKey,&fBlend))
 		if (AI_SUCCESS != aiGetMaterialFloat(pcMat,szKey,&fBlend))
 			fBlend = 1.0f;
 			fBlend = 1.0f;
 
 
@@ -490,7 +510,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
 	if (peTextureOp)
 	if (peTextureOp)
 	{
 	{
 		aiTextureOp op;
 		aiTextureOp op;
-		sprintf(szKey,"%s[%i]",szOpBase,iIndex);
+#if _MSC_VER >= 1400
+		if(0 >= sprintf_s(szKey,"%s[%i]",szOpBase,iIndex))DummyAssertFunction();
+#else
+		if(0 >= sprintf(szKey,"%s[%i]",szOpBase,iIndex))DummyAssertFunction();
+#endif
 		if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&op))
 		if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&op))
 			op = aiTextureOp_Multiply;
 			op = aiTextureOp_Multiply;
 
 
@@ -503,7 +527,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
 		aiTextureMapMode eMode;
 		aiTextureMapMode eMode;
 		for (unsigned int q = 0; q < 3;++q)
 		for (unsigned int q = 0; q < 3;++q)
 		{
 		{
-			sprintf(szKey,"%s[%i]",aszMapModeBase[q],iIndex);
+#if _MSC_VER >= 1400
+			if(0 >= sprintf_s(szKey,"%s[%i]",aszMapModeBase[q],iIndex))DummyAssertFunction();
+#else
+			if(0 >= sprintf(szKey,"%s[%i]",aszMapModeBase[q],iIndex))DummyAssertFunction();
+#endif
 			if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&eMode))
 			if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&eMode))
 			{
 			{
 				eMode = aiTextureMapMode_Wrap;
 				eMode = aiTextureMapMode_Wrap;

+ 0 - 77
code/MaterialSystem.h

@@ -47,83 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp
 namespace Assimp
 {
 {
 
 
-// ---------------------------------------------------------------------------
-/** \brief Helper function to do platform independent string comparison.
- *
- *  This is required since stricmp() is not consistently available on
- *  all platforms. Some platforms use the '_' prefix, others don't even
- *  have such a function. Yes, this is called an ISO standard.
- *
- *  \param s1 First input string
- *  \param s2 Second input string
- */
-// ---------------------------------------------------------------------------
-inline int ASSIMP_stricmp(const char *s1, const char *s2)
-{
-#if (defined _MSC_VER)
-
-	return _stricmp(s1,s2);
-
-#else
-	const char *a1, *a2;
-	a1 = s1;
-	a2 = s2;
-
-	while (true)
-	{
-		char c1 = (char)tolower(*a1); 
-		char c2 = (char)tolower(*a2);
-		if ((0 == c1) && (0 == c2)) return 0;
-		if (c1 < c2) return-1;
-		if (c1 > c2) return 1;
-		++a1; 
-		++a2;
-	}
-#endif
-}
-
-// ---------------------------------------------------------------------------
-/** \brief Helper function to do platform independent string comparison.
- *
- *  This is required since strincmp() is not consistently available on
- *  all platforms. Some platforms use the '_' prefix, others don't even
- *  have such a function. Yes, this is called an ISO standard.
- *
- *  \param s1 First input string
- *  \param s2 Second input string
- *  \param n Macimum number of characters to compare
- */
-// ---------------------------------------------------------------------------
-inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n)
-{
-#if (defined _MSC_VER)
-
-	return _strnicmp(s1,s2,n);
-
-#else
-	const char *a1, *a2;
-	a1 = s1;
-	a2 = s2;
-
-	unsigned int p = 0;
-
-	while (true)
-	{
-		if (p >= n)return 0;
-
-		char c1 = (char)tolower(*a1); 
-		char c2 = (char)tolower(*a2);
-		if ((0 == c1) && (0 == c2)) return 0;
-		if (c1 < c2) return-1;
-		if (c1 > c2) return 1;
-		++a1; 
-		++a2;
-		++p;
-	}
-#endif
-}
-
-
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Internal material helper class. Can be used to fill an aiMaterial
 /** Internal material helper class. Can be used to fill an aiMaterial
     structure easily. */
     structure easily. */

+ 2 - 1
code/PlyLoader.cpp

@@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /** @file Implementation of the PLY importer class */
 /** @file Implementation of the PLY importer class */
 #include "PlyLoader.h"
 #include "PlyLoader.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
+#include "StringComparison.h"
 
 
 #include "../include/IOStream.h"
 #include "../include/IOStream.h"
 #include "../include/IOSystem.h"
 #include "../include/IOSystem.h"
@@ -1063,7 +1064,7 @@ void PLYImporter::LoadMaterial(std::vector<MaterialHelper*>* pvOut)
 
 
 				// if shininess is 0 (and the pow() calculation would therefore always
 				// if shininess is 0 (and the pow() calculation would therefore always
 				// become 1, not depending on the angle) use gouraud lighting
 				// become 1, not depending on the angle) use gouraud lighting
-				if (0.0f != fSpec)
+				if (fSpec)
 				{
 				{
 
 
 					// scale this with 15 ... hopefully this is correct
 					// scale this with 15 ... hopefully this is correct

+ 2 - 1
code/PlyParser.cpp

@@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "PlyLoader.h"
 #include "PlyLoader.h"
 #include "MaterialSystem.h"
 #include "MaterialSystem.h"
 #include "fast_atof.h"
 #include "fast_atof.h"
-#include "../include/DefaultLogger.h"
+#include "StringComparison.h"
 #include "ByteSwap.h"
 #include "ByteSwap.h"
 
 
 #include "../include/IOStream.h"
 #include "../include/IOStream.h"
@@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/aiMesh.h"
 #include "../include/aiMesh.h"
 #include "../include/aiScene.h"
 #include "../include/aiScene.h"
 #include "../include/aiAssert.h"
 #include "../include/aiAssert.h"
+#include "../include/DefaultLogger.h"
 
 
 #include <boost/scoped_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 
 

+ 126 - 0
code/StringComparison.h

@@ -0,0 +1,126 @@
+/*
+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 Definition of platform independent string comparison functions */
+#ifndef AI_STRINGCOMPARISON_H_INC
+#define AI_STRINGCOMPARISON_H_INC
+
+
+namespace Assimp
+{
+
+// ---------------------------------------------------------------------------
+/** \brief Helper function to do platform independent string comparison.
+ *
+ *  This is required since stricmp() is not consistently available on
+ *  all platforms. Some platforms use the '_' prefix, others don't even
+ *  have such a function. Yes, this is called an ISO standard.
+ *
+ *  \param s1 First input string
+ *  \param s2 Second input string
+ */
+// ---------------------------------------------------------------------------
+inline int ASSIMP_stricmp(const char *s1, const char *s2)
+{
+#if (defined _MSC_VER)
+
+	return ::_stricmp(s1,s2);
+
+#else
+	const char *a1, *a2;
+	a1 = s1;
+	a2 = s2;
+
+	while (true)
+	{
+		char c1 = (char)::tolower(*a1); 
+		char c2 = (char)::tolower(*a2);
+		if ((0 == c1) && (0 == c2)) return 0;
+		if (c1 < c2) return-1;
+		if (c1 > c2) return 1;
+		++a1; 
+		++a2;
+	}
+#endif
+}
+
+// ---------------------------------------------------------------------------
+/** \brief Helper function to do platform independent string comparison.
+ *
+ *  This is required since strincmp() is not consistently available on
+ *  all platforms. Some platforms use the '_' prefix, others don't even
+ *  have such a function. Yes, this is called an ISO standard.
+ *
+ *  \param s1 First input string
+ *  \param s2 Second input string
+ *  \param n Macimum number of characters to compare
+ */
+// ---------------------------------------------------------------------------
+inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n)
+{
+#if (defined _MSC_VER)
+
+	return ::_strnicmp(s1,s2,n);
+
+#else
+	const char *a1, *a2;
+	a1 = s1;
+	a2 = s2;
+
+	unsigned int p = 0;
+
+	while (true)
+	{
+		if (p >= n)return 0;
+
+		char c1 = (char)::tolower(*a1); 
+		char c2 = (char)::tolower(*a2);
+		if ((0 == c1) && (0 == c2)) return 0;
+		if (c1 < c2) return-1;
+		if (c1 > c2) return 1;
+		++a1; 
+		++a2;
+		++p;
+	}
+#endif
+}
+};
+
+#endif // !  AI_STRINGCOMPARISON_H_INC

+ 689 - 0
code/ValidateDataStructure.cpp

@@ -0,0 +1,689 @@
+/*
+---------------------------------------------------------------------------
+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 Implementation of the post processing step to validate 
+ * the data structure returned by Assimp
+ */
+#include <vector>
+#include <assert.h>
+
+#include "ValidateDataStructure.h"
+#include "BaseImporter.h"
+#include "StringComparison.h"
+#include "fast_atof.h"
+
+#include "../include/DefaultLogger.h"
+#include "../include/aiPostProcess.h"
+#include "../include/aiMesh.h"
+#include "../include/aiScene.h"
+#include "../include/aiAssert.h"
+
+#include <stdarg.h>
+
+using namespace Assimp;
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+ValidateDSProcess::ValidateDSProcess()
+{
+	// nothing to do here
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+ValidateDSProcess::~ValidateDSProcess()
+{
+	// nothing to do here
+}
+
+// ------------------------------------------------------------------------------------------------
+// Returns whether the processing step is present in the given flag field.
+bool ValidateDSProcess::IsActive( unsigned int pFlags) const
+{
+	return (pFlags & aiProcess_ValidateDataStructure) != 0;
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::ReportError(const char* msg,...)
+{
+	ai_assert(NULL != msg);
+
+	va_list args;
+	va_start(args,msg);
+
+	char szBuffer[3000];
+
+	int iLen;
+#if _MSC_VER >= 1400
+	iLen = vsprintf_s(szBuffer,msg,args);
+#else
+	iLen = vsprintf(szBuffer,msg,args);
+#endif
+
+	if (0 >= iLen)
+	{
+		// :-) should not happen ...
+		throw new ImportErrorException("Idiot ... learn coding!");
+	}
+	va_end(args);
+	throw new ImportErrorException("Validation failed: " + std::string(szBuffer,iLen));
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::ReportWarning(const char* msg,...)
+{
+	ai_assert(NULL != msg);
+
+	va_list args;
+	va_start(args,msg);
+
+	char szBuffer[3000];
+
+	int iLen;
+#if _MSC_VER >= 1400
+	iLen = vsprintf_s(szBuffer,msg,args);
+#else
+	iLen = vsprintf(szBuffer,msg,args);
+#endif
+
+	if (0 >= iLen)
+	{
+		// :-) should not happen ...
+		throw new ImportErrorException("Idiot ... learn coding!");
+	}
+	va_end(args);
+	DefaultLogger::get()->warn("Validation failed: " + std::string(szBuffer,iLen));
+}
+// ------------------------------------------------------------------------------------------------
+// Executes the post processing step on the given imported data.
+void ValidateDSProcess::Execute( aiScene* pScene)
+{
+	this->mScene = pScene;
+	DefaultLogger::get()->debug("ValidateDataStructureProcess begin");
+
+	// validate all meshes
+	if (pScene->mNumMeshes)
+	{
+		if (!pScene->mMeshes)
+		{
+			this->ReportError("aiScene::mMeshes is NULL (aiScene::mNumMeshes is %i)",
+				pScene->mNumMeshes);
+		}
+		for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
+		{
+			if (!pScene->mMeshes[i])
+			{
+				this->ReportError("aiScene::mMeshes[%i] is NULL (aiScene::mNumMeshes is %i)",
+					i,pScene->mNumMeshes);
+			}
+			this->Validate(pScene->mMeshes[i]);
+		}
+	}
+	else this->ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
+
+	// validate all animations
+	if (pScene->mNumAnimations)
+	{
+		if (!pScene->mAnimations)
+		{
+			this->ReportError("aiScene::mAnimations is NULL (aiScene::mNumAnimations is %i)",
+				pScene->mNumAnimations);
+		}
+		for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
+		{
+			if (!pScene->mAnimations[i])
+			{
+				this->ReportError("aiScene::mAnimations[%i] is NULL (aiScene::mNumAnimations is %i)",
+					i,pScene->mNumAnimations);
+			}
+			this->Validate(pScene->mAnimations[i]);
+
+			// check whether there are duplicate animation names
+			for (unsigned int a = i+1; a < pScene->mNumAnimations;++a)
+			{
+				if (pScene->mAnimations[i]->mName == pScene->mAnimations[a]->mName)
+				{
+					this->ReportError("aiScene::mAnimations[%i] has the same name as "
+						"aiScene::mAnimations[%i]",i,a);
+				}
+			}
+		}
+	}
+
+	// validate all textures
+	if (pScene->mNumTextures)
+	{
+		if (!pScene->mTextures)
+		{
+			this->ReportError("aiScene::mTextures is NULL (aiScene::mNumTextures is %i)",
+				pScene->mNumTextures);
+		}
+		for (unsigned int i = 0; i < pScene->mNumTextures;++i)
+		{
+			if (!pScene->mTextures[i])
+			{
+				this->ReportError("aiScene::mTextures[%i] is NULL (aiScene::mNumTextures is %i)",
+					i,pScene->mNumTextures);
+			}
+			this->Validate(pScene->mTextures[i]);
+		}
+	}
+
+	// validate all materials
+	if (pScene->mNumMaterials)
+	{
+		if (!pScene->mMaterials)
+		{
+			this->ReportError("aiScene::mMaterials is NULL (aiScene::mNumMaterials is %i)",
+				pScene->mNumMaterials);
+		}
+		for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
+		{
+			if (!pScene->mMaterials[i])
+			{
+				this->ReportError("aiScene::mMaterials[%i] is NULL (aiScene::mNumMaterials is %i)",
+					i,pScene->mNumMaterials);
+			}
+			this->Validate(pScene->mMaterials[i]);
+		}
+	}
+	else this->ReportError("aiScene::mNumMaterials is 0. At least one material must be there.");
+
+	// validate the node graph of the scene
+	this->Validate(pScene->mRootNode);
+
+	DefaultLogger::get()->debug("ValidateDataStructureProcess end");
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::Validate( const aiMesh* pMesh)
+{
+	// validate the material index of the mesh
+	if (pMesh->mMaterialIndex >= this->mScene->mNumMaterials)
+	{
+		this->ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
+			pMesh->mMaterialIndex,this->mScene->mNumMaterials-1);
+	}
+
+	// positions must always be there ...
+	if (!pMesh->mNumVertices || !pMesh->mVertices)
+	{
+		this->ReportError("The mesh contains no vertices");
+	}
+
+	// faces, too
+	if (!pMesh->mNumFaces || !pMesh->mFaces)
+	{
+		this->ReportError("The mesh contains no faces");
+	}
+
+	// now check whether the face indexing layout is correct:
+	// unique vertices, pseudo-indexed.
+	std::vector<bool> abRefList;
+	abRefList.resize(pMesh->mNumVertices,false);
+	for (unsigned int i = 0; i < pMesh->mNumFaces;++i)
+	{
+		aiFace& face = pMesh->mFaces[i];
+		if (!face.mIndices)this->ReportError("aiMesh::mFaces[%i].mIndices is NULL",i);
+		if (face.mNumIndices < 3)this->ReportError(
+			"aiMesh::mFaces[%i].mIndices is not a triangle or polygon",i);
+
+		for (unsigned int a = 0; a < face.mNumIndices;++a)
+		{
+			if (face.mIndices[a] >= pMesh->mNumVertices)
+			{
+				this->ReportError("aiMesh::mFaces[%i]::mIndices[%a] is out of range",i,a);
+			}
+			if (abRefList[face.mIndices[a]])
+			{
+				this->ReportError("aiMesh::mVertices[%i] is referenced twice - second "
+					"time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
+			}
+			abRefList[face.mIndices[a]] = true;
+		}
+	}
+	abRefList.clear();
+
+	// texture channel 2 may not be set if channel 1 is zero ...
+	{
+	unsigned int i = 0;
+	for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
+	{
+		if (!pMesh->HasTextureCoords(i))break;
+	}
+	for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
+		if (pMesh->HasTextureCoords(i))
+		{
+			this->ReportError("Texture coordinate channel %i is existing, "
+				"although the previous channel was NULL.",i);
+		}
+	}
+	// the same for the vertex colors
+	{
+	unsigned int i = 0;
+	for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
+	{
+		if (!pMesh->HasVertexColors(i))break;
+	}
+	for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
+		if (pMesh->HasVertexColors(i))
+		{
+			this->ReportError("Vertex color channel %i is existing, "
+				"although the previous channel was NULL.",i);
+		}
+	}
+
+	// now validate all bones
+	if (pMesh->HasBones())
+	{
+		if (!pMesh->mBones)
+		{
+			this->ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)",
+				pMesh->mNumBones);
+		}
+
+		// check whether there are duplicate bone names
+		for (unsigned int i = 0; i < pMesh->mNumBones;++i)
+		{
+			if (!pMesh->mBones[i])
+			{
+				this->ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)",
+					i,pMesh->mNumBones);
+			}
+			this->Validate(pMesh,pMesh->mBones[i]);
+
+			for (unsigned int a = i+1; a < pMesh->mNumBones;++a)
+			{
+				if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName)
+				{
+					this->ReportError("aiMesh::mBones[%i] has the same name as "
+						"aiMesh::mBones[%i]",i,a);
+				}
+			}
+		}
+	}
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::Validate( const aiMesh* pMesh,
+	const aiBone* pBone)
+{
+	// check whether all vertices affected by this bone are valid
+	for (unsigned int i = 0; i < pBone->mNumWeights;++i)
+	{
+		if (pBone->mWeights[i].mVertexId > pMesh->mNumVertices)
+		{
+			this->ReportError("aiBone::mWeights[%i].mVertexId is out of range",i);
+		}
+		else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f)
+		{
+			this->ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value",i);
+		}
+	}
+	// TODO: check whether all bone weights for a vertex sum to 1.0 ...
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
+{
+	// validate all materials
+	if (pAnimation->mNumBones)
+	{
+		if (!pAnimation->mBones)
+		{
+			this->ReportError("aiAnimation::mBones is NULL (aiAnimation::mNumBones is %i)",
+				pAnimation->mBones);
+		}
+		for (unsigned int i = 0; i < pAnimation->mNumBones;++i)
+		{
+			if (!pAnimation->mBones[i])
+			{
+				this->ReportError("aiAnimation::mBones[%i] is NULL (aiAnimation::mNumBones is %i)",
+					i,pAnimation->mNumBones);
+			}
+			this->Validate(pAnimation, pAnimation->mBones[i]);
+		}
+	}
+	else this->ReportError("aiAnimation::mNumBones is 0. At least one bone animation channel must be there.");
+	if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero");
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
+	const char* szType)
+{
+	ai_assert(NULL != szType);
+
+	// 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 ...)
+
+	// "$tex.file.<szType>[<index>]"
+	char szBaseBuf[512];
+	int iLen;
+#if _MSC_VER >= 1400
+	iLen = ::sprintf_s(szBaseBuf,"$tex.file.%s",szType);
+#else
+	iLen = ::sprintf(szBaseBuf,"$tex.file.%s",szType);
+#endif
+	if (0 >= iLen)return;
+
+	int iNumIndices = 0;
+	int iIndex = -1;
+	for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
+	{
+		aiMaterialProperty* prop = pMaterial->mProperties[i];
+		if (0 == ASSIMP_strincmp( prop->mKey->data, szBaseBuf, iLen ))
+		{
+			const char* sz = &prop->mKey->data[iLen];
+			if (*sz)
+			{
+				++sz;
+				iIndex = std::max(iIndex, (int)strtol10(sz,NULL));
+				++iNumIndices;
+			}
+
+			if (aiPTI_String != prop->mType)
+				this->ReportError("Material property %s is expected to be a string",prop->mKey);
+		}
+	}
+	if (iIndex +1 != iNumIndices)
+	{
+		this->ReportError("%s #%i is set, but there are only %i %s textures",
+			szType,iIndex,iNumIndices,szType);
+	}
+
+	// now check whether all UV indices are valid ...
+#if _MSC_VER >= 1400
+	iLen = ::sprintf_s(szBaseBuf,"$tex.uvw.%s",szType);
+#else
+	iLen = ::sprintf(szBaseBuf,"$tex.uvw.%s",szType);
+#endif
+	if (0 >= iLen)return;
+	
+	for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
+	{
+		aiMaterialProperty* prop = pMaterial->mProperties[i];
+		if (0 == ASSIMP_strincmp( prop->mKey->data, szBaseBuf, iLen ))
+		{
+			if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)
+				this->ReportError("Material property %s is expected to be an integer",prop->mKey);
+
+			const char* sz = &prop->mKey->data[iLen];
+			if (*sz)
+			{
+				++sz;
+				iIndex = strtol10(sz,NULL);
+
+				// ignore UV indices for texture channel that are not there ...
+				if (iIndex >= iNumIndices)
+				{
+					// 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 < this->mScene->mNumMeshes;++a)
+					{
+						aiMesh* mesh = this->mScene->mMeshes[a];
+						if(mesh->mMaterialIndex == iIndex)
+						{
+							int iChannels = 0;
+							while (mesh->HasTextureCoords(iChannels++));
+							if (iIndex >= iChannels)
+							{
+								this->ReportError("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
+									iIndex,prop->mKey,a,iChannels);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::Validate( const aiMaterial* pMaterial)
+{
+	// check whether there are material keys that are obviously not legal
+	for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
+	{
+		aiMaterialProperty* prop = pMaterial->mProperties[i];
+		if (!prop)
+		{
+			this->ReportError("aiMaterial::mProperties[%i] is NULL (aiMaterial::mNumProperties is %i)",
+				i,pMaterial->mNumProperties);
+		}
+		if (!prop->mDataLength || !prop->mData)
+		{
+			this->ReportError("aiMaterial::mProperties[%i].mDataLength or "
+				"aiMaterial::mProperties[%i].mData is 0",i,i);
+		}
+		// TODO: check whether there is a key with an unknown name ...
+	}
+
+	float fTemp;
+	int iShading;
+	if (AI_SUCCESS == aiGetMaterialInteger( pMaterial,AI_MATKEY_SHADING_MODEL,&iShading))
+	{
+		switch ((aiShadingMode)iShading)
+		{
+		case aiShadingMode_Blinn:
+		case aiShadingMode_CookTorrance:
+		case aiShadingMode_Phong:
+
+			if (AI_SUCCESS != aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS,&fTemp))
+			{
+				this->ReportWarning("A specular shading model is specified but there is no "
+					"AI_MATKEY_SHININESS key");
+			}
+			if (AI_SUCCESS == aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS_STRENGTH,&fTemp) && !fTemp)
+			{
+				this->ReportWarning("A specular shading model is specified but the value of the "
+					"AI_MATKEY_SHININESS_STRENGTH key is 0.0");
+			}
+			break;
+		};
+	}
+
+
+	// 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");
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::Validate( const aiTexture* pTexture)
+{
+	// the data section may NEVER be NULL
+	if (!pTexture->pcData)
+	{
+		this->ReportError("aiTexture::pcData is NULL");
+	}
+	if (pTexture->mHeight)
+	{
+		if (!pTexture->mWidth)this->ReportError("aiTexture::mWidth is zero "
+			"(aiTexture::mHeight is %i, uncompressed texture)",pTexture->mHeight);
+	}
+	else 
+	{
+		if (!pTexture->mWidth)this->ReportError("aiTexture::mWidth is zero (compressed texture)");
+		if ('.' == pTexture->achFormatHint[0])
+		{
+			char szTemp[5];
+			szTemp[0] = pTexture->achFormatHint[0];
+			szTemp[1] = pTexture->achFormatHint[1];
+			szTemp[2] = pTexture->achFormatHint[2];
+			szTemp[3] = pTexture->achFormatHint[3];
+			szTemp[4] = '\0';
+
+			this->ReportWarning("aiTexture::achFormatHint should contain a file extension "
+				"without a leading dot (format hint: %s).",szTemp);
+		}
+	}
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
+	 const aiBoneAnim* pBoneAnim)
+{
+	// 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 == pBoneAnim->mBoneName)
+				break;
+		}
+	}
+	if (i == this->mScene->mNumMeshes)
+	{
+		this->ReportWarning("aiBoneAnim::mBoneName is %s. However, no bone with this name was found",
+			pBoneAnim->mBoneName.data);
+	}
+	if (!pBoneAnim->mNumPositionKeys && !pBoneAnim->mNumRotationKeys && !pBoneAnim->mNumScalingKeys)
+	{
+		this->ReportWarning("A bone animation channel has no keys");
+	}
+
+	// otherwise check whether one of the keys exceeds the total duration of the animation
+	if (pBoneAnim->mNumPositionKeys)
+	{
+		if (!pBoneAnim->mPositionKeys)
+		{
+			this->ReportError("aiBoneAnim::mPositionKeys is NULL (aiBoneAnim::mNumPositionKeys is %i)",
+				pBoneAnim->mNumPositionKeys);
+		}
+		for (unsigned int i = 0; i < pBoneAnim->mNumPositionKeys;++i)
+		{
+			if (pBoneAnim->mPositionKeys[i].mTime > pAnimation->mDuration)
+			{
+				this->ReportError("aiBoneAnim::mPositionKeys[%i].mTime (%.5f) is larger "
+					"than aiAnimation::mDuration (which is %.5f)",i,
+					(float)pBoneAnim->mPositionKeys[i].mTime,
+					(float)pAnimation->mDuration);
+			}
+		}
+	}
+	// rotation keys
+	if (pBoneAnim->mNumRotationKeys)
+	{
+		if (!pBoneAnim->mRotationKeys)
+		{
+			this->ReportError("aiBoneAnim::mRotationKeys is NULL (aiBoneAnim::mNumRotationKeys is %i)",
+				pBoneAnim->mNumRotationKeys);
+		}
+		for (unsigned int i = 0; i < pBoneAnim->mNumRotationKeys;++i)
+		{
+			if (pBoneAnim->mRotationKeys[i].mTime > pAnimation->mDuration)
+			{
+				this->ReportError("aiBoneAnim::mRotationKeys[%i].mTime (%.5f) is larger "
+					"than aiAnimation::mDuration (which is %.5f)",i,
+					(float)pBoneAnim->mRotationKeys[i].mTime,
+					(float)pAnimation->mDuration);
+			}
+		}
+	}
+	// scaling keys
+	if (pBoneAnim->mNumScalingKeys)
+	{
+		if (!pBoneAnim->mScalingKeys)
+		{
+			this->ReportError("aiBoneAnim::mScalingKeys is NULL (aiBoneAnim::mNumScalingKeys is %i)",
+				pBoneAnim->mNumScalingKeys);
+		}
+		for (unsigned int i = 0; i < pBoneAnim->mNumScalingKeys;++i)
+		{
+			if (pBoneAnim->mScalingKeys[i].mTime > pAnimation->mDuration)
+			{
+				this->ReportError("aiBoneAnim::mScalingKeys[%i].mTime (%.5f) is larger "
+					"than aiAnimation::mDuration (which is %.5f)",i,
+					(float)pBoneAnim->mScalingKeys[i].mTime,
+					(float)pAnimation->mDuration);
+			}
+		}
+	}
+}
+// ------------------------------------------------------------------------------------------------
+void ValidateDSProcess::Validate( const aiNode* pNode)
+{
+	if (!pNode)this->ReportError("A node of the scenegraph is NULL");
+	if (pNode != this->mScene->mRootNode && !pNode->mParent)
+		this->ReportError("A node has no valid parent (aiNode::mParent is NULL)");
+
+	// validate all meshes
+	if (pNode->mNumMeshes)
+	{
+		if (!pNode->mMeshes)
+		{
+			this->ReportError("aiNode::mMeshes is NULL (aiNode::mNumMeshes is %i)",
+				pNode->mNumMeshes);
+		}
+		std::vector<bool> abHadMesh;
+		abHadMesh.resize(this->mScene->mNumMeshes,false);
+		for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
+		{
+			if (pNode->mMeshes[i] >= this->mScene->mNumMeshes)
+			{
+				this->ReportError("aiNode::mMeshes[%i] is out of range (maximum is %i)",
+					pNode->mMeshes[i],this->mScene->mNumMeshes-1);
+			}
+			if (abHadMesh[pNode->mMeshes[i]])
+			{
+				this->ReportError("aiNode::mMeshes[%i] is already referenced by this node (value: %i)",
+					i,pNode->mMeshes[i]);
+			}
+			abHadMesh[pNode->mMeshes[i]] = true;
+		}
+	}
+	if (pNode->mNumChildren)
+	{
+		if (!pNode->mChildren)
+		{
+			this->ReportError("aiNode::mChildren is NULL (aiNode::mNumChildren is %i)",
+				pNode->mNumChildren);
+		}
+		for (unsigned int i = 0; i < pNode->mNumChildren;++i)
+		{
+			this->Validate(pNode->mChildren[i]);
+		}
+	}
+}

+ 168 - 0
code/ValidateDataStructure.h

@@ -0,0 +1,168 @@
+/*
+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 validate the loader's
+ * output data structure (for debugging)
+ */
+#ifndef AI_VALIDATEPROCESS_H_INC
+#define AI_VALIDATEPROCESS_H_INC
+
+#include "BaseProcess.h"
+
+struct aiBone;
+struct aiMesh;
+struct aiAnimation;
+struct aiBoneAnim;
+struct aiTexture;
+struct aiMaterial;
+struct aiNode;
+
+namespace Assimp
+{
+
+// ---------------------------------------------------------------------------
+/** Validates the ASSIMP data structure
+ */
+class ValidateDSProcess : public BaseProcess
+{
+	friend class Importer;
+
+protected:
+	/** Constructor to be privately used by Importer */
+	ValidateDSProcess();
+
+	/** Destructor, private as well */
+	~ValidateDSProcess();
+
+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.
+	* A process should throw an ImportErrorException* if it fails.
+	* @param pScene The imported data to work at.
+	*/
+	void Execute( aiScene* pScene);
+
+protected:
+
+	// -------------------------------------------------------------------
+	/** Report a validation error. This will throw an exception,
+	 *  control won't return.
+	 * @param msg Format string for sprintf().
+	 */
+	void ReportError(const char* msg,...);
+
+	// -------------------------------------------------------------------
+	/** Report a validation warning. This won't throw an exception,
+	 *  control will return to the callera.
+	 * @param msg Format string for sprintf().
+	 */
+	void ReportWarning(const char* msg,...);
+
+	// -------------------------------------------------------------------
+	/** Validates a mesh
+	 * @param pMesh Input mesh
+	 */
+	void Validate( const aiMesh* pMesh);
+
+	// -------------------------------------------------------------------
+	/** Validates a bone
+	 * @param pMesh Input mesh
+	 * @param pBone Input bone
+	 */
+	void Validate( const aiMesh* pMesh,const aiBone* pBone);
+
+	// -------------------------------------------------------------------
+	/** Validates an animation
+	 * @param pAnimation Input animation
+	 */
+	void Validate( const aiAnimation* pAnimation);
+
+	// -------------------------------------------------------------------
+	/** Validates a material
+	 * @param pMaterial Input material
+	 */
+	void Validate( const aiMaterial* pMaterial);
+
+	// -------------------------------------------------------------------
+	/** Search the material data structure for invalid or corrupt
+	 *  texture keys.
+	 * @param pMaterial Input material
+	 * @param szType Type of the texture (the purpose string that
+	 *  occurs in material keys, e.g. "diffuse", "ambient")
+	 */
+	void SearchForInvalidTextures(const aiMaterial* pMaterial,
+		const char* szType);
+
+	// -------------------------------------------------------------------
+	/** Validates a texture
+	 * @param pTexture Input texture
+	 */
+	void Validate( const aiTexture* pTexture);
+
+	// -------------------------------------------------------------------
+	/** Validates a bone animation channel
+	 * @param pAnimation Input animation
+	 * @param pBoneAnim Input bone animation
+	 */
+	void Validate( const aiAnimation* pAnimation,
+		const aiBoneAnim* pBoneAnim);
+
+	// -------------------------------------------------------------------
+	/** Validates a node and all of its subnodes
+	 * @param Node Input node
+	 */
+	void Validate( const aiNode* pNode);
+
+private:
+
+	aiScene* mScene;
+};
+
+} // end of namespace Assimp
+
+#endif // AI_VALIDATEPROCESS_H_INC

+ 118 - 23
include/aiMaterial.h

@@ -208,27 +208,29 @@ struct aiMaterialProperty
 {
 {
     /** Specifies the name of the property (key)
     /** Specifies the name of the property (key)
     *
     *
-    *	Keys are case insensitive.
+    * Keys are case insensitive.
     */
     */
     C_STRUCT aiString* mKey;
     C_STRUCT aiString* mKey;
 
 
     /**	Size of the buffer mData is pointing to, in bytes
     /**	Size of the buffer mData is pointing to, in bytes
+	* This value may not be 0.
     */
     */
     unsigned int mDataLength;
     unsigned int mDataLength;
 
 
     /** Type information for the property.
     /** Type information for the property.
     *
     *
-    *  Defines the data layout inside the
-    *  data buffer. This is used by the library
-    *  internally to perform debug checks.
+    * Defines the data layout inside the
+    * data buffer. This is used by the library
+    * internally to perform debug checks.
     */
     */
     aiPropertyTypeInfo mType;
     aiPropertyTypeInfo mType;
 
 
     /**	Binary buffer to hold the property's value
     /**	Binary buffer to hold the property's value
     *
     *
-    *  The buffer has no terminal character. However,
-    *  if a string is stored inside it may use 0 as terminal,
-    *  but it would be contained in mDataLength.
+    * The buffer has no terminal character. However,
+    * if a string is stored inside it may use 0 as terminal,
+    * but it would be contained in mDataLength. This member
+	* is never 0
     */
     */
     char* mData;
     char* mData;
 };
 };
@@ -239,8 +241,8 @@ struct aiMaterialProperty
 *
 *
 *  Material data is stored using a key-value structure, called property
 *  Material data is stored using a key-value structure, called property
 *  (to guarant that the system is maximally flexible).
 *  (to guarant that the system is maximally flexible).
-*  The library defines a set of standard keys, which should be enough
-*  for nearly all purposes. 
+*  The library defines a set of standard keys (AI_MATKEY) which should be 
+*  enough for nearly all purposes. 
 */
 */
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 struct aiMaterial
 struct aiMaterial
@@ -261,6 +263,54 @@ public:
     unsigned int mNumAllocated;
     unsigned int mNumAllocated;
 };
 };
 
 
+// ---------------------------------------------------------------------------
+/** @def AI_BUILD_KEY
+ * Builds a material texture key with a dynamic index.
+ * Applications <b>could</b> do this (C-example):
+ * @code
+ * int i;
+ * struct aiMaterial* pMat = .... 
+ * for (i = 0;true;++i) {
+ *    if (AI_SUCCESS != aiGetMaterialFloat(pMat,AI_MATKEY_TEXTURE_DIFFUSE(i),...)) {
+ *       ...
+ *    }
+ * }
+ * @endcode 
+ * However, this is wrong because AI_MATKEY_TEXTURE_DIFFUSE() builds the key 
+ * string at <b>compile time</b>. <br>
+ * Therefore, the dynamic indexing results in a
+ * material key like this : "$tex.file.diffuse[i]" - and it is not very
+ * propable that there is a key with this name ... (except the programmer
+ * of an ASSIMP loader has made the same mistake :-) ).<br>
+ * This is the right way:
+ * @code
+ * int i;
+ * char szBuffer[512];
+ * struct aiMaterial* pMat = .... 
+ * for (i = 0;true;++i) {
+ *    AI_BUILD_KEY(AI_MATKEY_TEXTURE_DIFFUSE_,i,szBuffer);
+ *    if (AI_SUCCESS != aiGetMaterialFloat(pMat,szBuffer,...)) {
+ *       ...
+ *    }
+ * }
+ * @endcode 
+ * @param base Base material key. This is the same key you'd have used
+ *   normally with an underscore as suffix (e.g. AI_MATKEY_TEXTURE_DIFFUSE_)
+ * @param index Index to be used. Here you may pass a variable!
+ * @param out Array of chars to receive the output value. It must be 
+ *  sufficiently large. This will be checked via a static assertion for
+ *  C++0x. For MSVC8 and later versions the security enhanced version of
+ *  sprintf() will be used. However, if your buffer is at least 512 bytes
+ *  long you'll never overrun.
+*/
+#if _MSC_VER >= 1400
+#	define AI_BUILD_KEY(base,index,out) \
+	::sprintf_s(out,"%s[%i]",base,index);
+#else
+#	define AI_BUILD_KEY(base,index,out) \
+	::sprintf(out,"%s[%i]",base,index);
+#endif
+
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** @def AI_MATKEY_NAME
 /** @def AI_MATKEY_NAME
@@ -370,6 +420,10 @@ public:
  *  <br>
  *  <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
 #define AI_MATKEY_TEXTURE_DIFFUSE(N) "$tex.file.diffuse["#N"]"
 #define AI_MATKEY_TEXTURE_DIFFUSE(N) "$tex.file.diffuse["#N"]"
 #define AI_MATKEY_TEXTURE_DIFFUSE_  "$tex.file.diffuse"
 #define AI_MATKEY_TEXTURE_DIFFUSE_  "$tex.file.diffuse"
@@ -379,6 +433,10 @@ public:
  *  <br>
  *  <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
 #define AI_MATKEY_TEXTURE_AMBIENT(N) "$tex.file.ambient["#N"]"
 #define AI_MATKEY_TEXTURE_AMBIENT(N) "$tex.file.ambient["#N"]"
 #define AI_MATKEY_TEXTURE_AMBIENT_   "$tex.file.ambient"
 #define AI_MATKEY_TEXTURE_AMBIENT_   "$tex.file.ambient"
@@ -388,6 +446,10 @@ public:
  *  <br>
  *  <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
 #define AI_MATKEY_TEXTURE_SPECULAR(N) "$tex.file.specular["#N"]"
 #define AI_MATKEY_TEXTURE_SPECULAR(N) "$tex.file.specular["#N"]"
 #define AI_MATKEY_TEXTURE_SPECULAR_   "$tex.file.specular"
 #define AI_MATKEY_TEXTURE_SPECULAR_   "$tex.file.specular"
@@ -397,6 +459,10 @@ public:
  *  <br>
  *  <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
 #define AI_MATKEY_TEXTURE_EMISSIVE(N) "$tex.file.emissive["#N"]"
 #define AI_MATKEY_TEXTURE_EMISSIVE(N) "$tex.file.emissive["#N"]"
 #define AI_MATKEY_TEXTURE_EMISSIVE_   "$tex.file.emissive"
 #define AI_MATKEY_TEXTURE_EMISSIVE_   "$tex.file.emissive"
@@ -406,6 +472,10 @@ public:
  *  <br>
  *  <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
 #define AI_MATKEY_TEXTURE_NORMALS(N) "$tex.file.normals["#N"]"
 #define AI_MATKEY_TEXTURE_NORMALS(N) "$tex.file.normals["#N"]"
 #define AI_MATKEY_TEXTURE_NORMALS_   "$tex.file.normals"
 #define AI_MATKEY_TEXTURE_NORMALS_   "$tex.file.normals"
@@ -419,15 +489,23 @@ public:
  * <br>
  * <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
-#define AI_MATKEY_TEXTURE_HEIGHT(N) "$tex.file.bump["#N"]"
-#define AI_MATKEY_TEXTURE_HEIGHT_   "$tex.file.bump"
+#define AI_MATKEY_TEXTURE_HEIGHT(N) "$tex.file.height["#N"]"
+#define AI_MATKEY_TEXTURE_HEIGHT_   "$tex.file.height"
 
 
 /** @def AI_MATKEY_TEXTURE_SHININESS
 /** @def AI_MATKEY_TEXTURE_SHININESS
  *  Defines a specified shininess texture channel of the material
  *  Defines a specified shininess texture channel of the material
  *  <br>
  *  <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
 #define AI_MATKEY_TEXTURE_SHININESS(N) "$tex.file.shininess["#N"]"
 #define AI_MATKEY_TEXTURE_SHININESS(N) "$tex.file.shininess["#N"]"
 #define AI_MATKEY_TEXTURE_SHININESS_   "$tex.file.shininess"
 #define AI_MATKEY_TEXTURE_SHININESS_   "$tex.file.shininess"
@@ -437,10 +515,15 @@ public:
  *  <br>
  *  <br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Type:</b> string (aiString)<br>
  * <b>Default value:</b> none <br>
  * <b>Default value:</b> none <br>
+ * @note The key string is built at compile time, therefore it is not 
+ * posible  to use this macro in a loop with varying values for N. 
+ * However, you can  use the macro suffixed with '_' to build the key 
+ * dynamically. The AI_BUILD_KEY()-macro can be used to do this.
 */
 */
 #define AI_MATKEY_TEXTURE_OPACITY(N) "$tex.file.opacity["#N"]"
 #define AI_MATKEY_TEXTURE_OPACITY(N) "$tex.file.opacity["#N"]"
 #define AI_MATKEY_TEXTURE_OPACITY_   "$tex.file.opacity"
 #define AI_MATKEY_TEXTURE_OPACITY_   "$tex.file.opacity"
 
 
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** @def AI_MATKEY_TEXOP_DIFFUSE
 /** @def AI_MATKEY_TEXOP_DIFFUSE
  * Specifies the blend operation too be used to combine the Nth
  * Specifies the blend operation too be used to combine the Nth
@@ -450,8 +533,10 @@ public:
  * <b>Type:</b> int (aiTextureOp)<br>
  * <b>Type:</b> int (aiTextureOp)<br>
  * <b>Default value:</b> 0<br>
  * <b>Default value:</b> 0<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
- * @note Never use an non-numeric index (like a variable) for this.
- * Remember, the key string is built by the preprocessor
+ * @note The key string is built at compile time, therefore it is not posible 
+ * to use this macro in a loop with varying values for N. However, you can 
+ * use the macro suffixed with '_' to build the key dynamically. The 
+ * AI_BUILD_KEY()-macro can be used to do this.
  */
  */
 #define AI_MATKEY_TEXOP_DIFFUSE(N)	"$tex.op.diffuse["#N"]"
 #define AI_MATKEY_TEXOP_DIFFUSE(N)	"$tex.op.diffuse["#N"]"
 /** @see AI_MATKEY_TEXOP_DIFFUSE */
 /** @see AI_MATKEY_TEXOP_DIFFUSE */
@@ -485,8 +570,10 @@ public:
  * <b>Type:</b> int<br>
  * <b>Type:</b> int<br>
  * <b>Default value:</b> 0<br>
  * <b>Default value:</b> 0<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
- * @note Never use an non-numeric index (like a variable) for this.
- * Remember, the key string is built by the preprocessor
+ * @note The key string is built at compile time, therefore it is not posible 
+ * to use this macro in a loop with varying values for N. However, you can 
+ * use the macro suffixed with '_' to build the key dynamically. The 
+ * AI_BUILD_KEY()-macro can be used to do this.
  */
  */
 #define AI_MATKEY_UVWSRC_DIFFUSE(N)		"$tex.uvw.diffuse["#N"]"
 #define AI_MATKEY_UVWSRC_DIFFUSE(N)		"$tex.uvw.diffuse["#N"]"
 /** @see AI_MATKEY_UVWSRC_DIFFUSE */
 /** @see AI_MATKEY_UVWSRC_DIFFUSE */
@@ -520,8 +607,10 @@ public:
  * <b>Type:</b> float<br>
  * <b>Type:</b> float<br>
  * <b>Default value:</b> 1.0f<br>
  * <b>Default value:</b> 1.0f<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
- * @note Never use an non-numeric index (like a variable) for this.
- * Remember, the key string is built by the preprocessor
+ * @note The key string is built at compile time, therefore it is not posible 
+ * to use this macro in a loop with varying values for N. However, you can 
+ * use the macro suffixed with '_' to build the key dynamically. The 
+ * AI_BUILD_KEY()-macro can be used to do this.
  */
  */
 #define AI_MATKEY_TEXBLEND_DIFFUSE(N)	"$tex.blend.diffuse["#N"]"
 #define AI_MATKEY_TEXBLEND_DIFFUSE(N)	"$tex.blend.diffuse["#N"]"
 /** @see AI_MATKEY_TEXBLEND_DIFFUSE */
 /** @see AI_MATKEY_TEXBLEND_DIFFUSE */
@@ -556,8 +645,10 @@ public:
  * <b>Type:</b> int (aiTextureMapMode)<br>
  * <b>Type:</b> int (aiTextureMapMode)<br>
  * <b>Default value:</b> aiTextureMapMode_Wrap<br>
  * <b>Default value:</b> aiTextureMapMode_Wrap<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
- * @note Never use an non-numeric index (like a variable) for this.
- * Remember, the key string is built by the preprocessor
+ * @note The key string is built at compile time, therefore it is not posible 
+ * to use this macro in a loop with varying values for N. However, you can 
+ * use the macro suffixed with '_' to build the key dynamically. The 
+ * AI_BUILD_KEY()-macro can be used to do this.
  */
  */
 #define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N)	"$tex.mapmodeu.diffuse["#N"]"
 #define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N)	"$tex.mapmodeu.diffuse["#N"]"
 /** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */
 /** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */
@@ -592,8 +683,10 @@ public:
  * <b>Type:</b> int (aiTextureMapMode)<br>
  * <b>Type:</b> int (aiTextureMapMode)<br>
  * <b>Default value:</b> aiTextureMapMode_Wrap<br>
  * <b>Default value:</b> aiTextureMapMode_Wrap<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
- * @note Never use an non-numeric index (like a variable) for this.
- * Remember, the key string is built by the preprocessor
+ * @note The key string is built at compile time, therefore it is not posible 
+ * to use this macro in a loop with varying values for N. However, you can 
+ * use the macro suffixed with '_' to build the key dynamically. The 
+ * AI_BUILD_KEY()-macro can be used to do this.
  */
  */
 #define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N)	"$tex.mapmodev.diffuse["#N"]"
 #define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N)	"$tex.mapmodev.diffuse["#N"]"
 /** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */
 /** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */
@@ -628,8 +721,10 @@ public:
  * <b>Type:</b> int (aiTextureMapMode)<br>
  * <b>Type:</b> int (aiTextureMapMode)<br>
  * <b>Default value:</b> aiTextureMapMode_Wrap<br>
  * <b>Default value:</b> aiTextureMapMode_Wrap<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
  * <b>Requires:</b> AI_MATKEY_TEXTURE_DIFFUSE(0)<br>
- * @note Never use an non-numeric index (like a variable) for this.
- * Remember, the key string is built by the preprocessor
+ * @note The key string is built at compile time, therefore it is not posible 
+ * to use this macro in a loop with varying values for N. However, you can 
+ * use the macro suffixed with '_' to build the key dynamically. The 
+ * AI_BUILD_KEY()-macro can be used to do this.
  */
  */
 #define AI_MATKEY_MAPPINGMODE_W_DIFFUSE(N)	"$tex.mapmodew.diffuse["#N"]"
 #define AI_MATKEY_MAPPINGMODE_W_DIFFUSE(N)	"$tex.mapmodew.diffuse["#N"]"
 /** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */
 /** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */

+ 2 - 2
include/aiMesh.h

@@ -395,7 +395,7 @@ struct aiMesh
 
 
 	//! Check whether the mesh contains a vertex color set
 	//! Check whether the mesh contains a vertex color set
 	//! \param pIndex Index of the vertex color set
 	//! \param pIndex Index of the vertex color set
-	inline bool HasVertexColors( unsigned int pIndex) 
+	inline bool HasVertexColors( unsigned int pIndex) const
 	{ 
 	{ 
 		if( pIndex >= AI_MAX_NUMBER_OF_COLOR_SETS) 
 		if( pIndex >= AI_MAX_NUMBER_OF_COLOR_SETS) 
 			return false; 
 			return false; 
@@ -405,7 +405,7 @@ struct aiMesh
 
 
 	//! Check whether the mesh contains a texture coordinate set
 	//! Check whether the mesh contains a texture coordinate set
 	//! \param pIndex Index of the texture coordinates set
 	//! \param pIndex Index of the texture coordinates set
-	inline bool HasTextureCoords( unsigned int pIndex) 
+	inline bool HasTextureCoords( unsigned int pIndex) const
 	{ 
 	{ 
 		if( pIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) 
 		if( pIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) 
 			return false; 
 			return false; 

+ 10 - 1
include/aiPostProcess.h

@@ -135,7 +135,16 @@ enum aiPostProcessSteps
 	* If you intend to perform the skinning in hardware, this post processing step
 	* If you intend to perform the skinning in hardware, this post processing step
 	* might be of interest for you.
 	* might be of interest for you.
 	*/
 	*/
-	aiProcess_LimitBoneWeights = 0x200
+	aiProcess_LimitBoneWeights = 0x200,
+
+	/** Validates the aiScene data structure before it is returned.
+	 * This makes sure that all indices are valid, all animations and
+	 * bones are linked correctly, all material are correct and so on ...
+	 * This is primarily intended for our internal debugging stuff,
+	 * however, it could be of interest for applications like editors
+	 * where stability is more important than loading performance.
+	*/
+	aiProcess_ValidateDataStructure = 0x400
 };
 };
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------

+ 3 - 0
include/assimp.hpp

@@ -83,6 +83,9 @@ class IOSystem;
 */
 */
 class Importer
 class Importer
 {
 {
+	// used internally
+	friend class BaseProcess;
+
 public:
 public:
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------

+ 1 - 1
tools/assimp_view/Display.cpp

@@ -384,7 +384,7 @@ int CDisplay::ReplaceCurrentTexture(const char* szPath)
 		pcMat->AddProperty(&szOld,szBuffer );
 		pcMat->AddProperty(&szOld,szBuffer );
 	}
 	}
 	else if (szString.length == szOld.length && 
 	else if (szString.length == szOld.length && 
-		0 == Assimp::ASSIMP_stricmp(szString.data,szOld.data))
+		0 == ASSIMP_stricmp(szString.data,szOld.data))
 	{
 	{
 		pcMat->RemoveProperty(szBuffer);
 		pcMat->RemoveProperty(szBuffer);
 	}
 	}

+ 0 - 23
tools/assimp_view/Material.cpp

@@ -48,29 +48,6 @@ namespace AssimpView {
 
 
 /*static */ CMaterialManager CMaterialManager::s_cInstance;
 /*static */ CMaterialManager CMaterialManager::s_cInstance;
 
 
-//-------------------------------------------------------------------------------
-// Compiler idependent stricmp() function.
-//
-// Used for case insensitive string comparison
-//-------------------------------------------------------------------------------
-inline int ASSIMP_stricmp(const char *s1, const char *s2)
-{
-	const char *a1, *a2;
-	a1 = s1;
-	a2 = s2;
-
-	while (true)
-	{
-		char c1 = (char)tolower(*a1); 
-		char c2 = (char)tolower(*a2);
-		if ((0 == c1) && (0 == c2)) return 0;
-		if (c1 < c2) return-1;
-		if (c1 > c2) return 1;
-		++a1; 
-		++a2;
-	}
-}
-
 //-------------------------------------------------------------------------------
 //-------------------------------------------------------------------------------
 // D3DX callback function to fill a texture with a checkers pattern
 // D3DX callback function to fill a texture with a checkers pattern
 //
 //

+ 8 - 8
tools/assimp_view/MessageProc.cpp

@@ -1589,14 +1589,14 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg,
 
 
 						// check whether it is a typical texture file format ...
 						// check whether it is a typical texture file format ...
 						++sz;
 						++sz;
-						if (0 == Assimp::ASSIMP_stricmp(sz,"png") ||
-							0 == Assimp::ASSIMP_stricmp(sz,"bmp") ||
-							0 == Assimp::ASSIMP_stricmp(sz,"jpg") ||
-							0 == Assimp::ASSIMP_stricmp(sz,"tga") ||
-							0 == Assimp::ASSIMP_stricmp(sz,"tif") ||
-							0 == Assimp::ASSIMP_stricmp(sz,"hdr") ||
-							0 == Assimp::ASSIMP_stricmp(sz,"ppm") ||
-							0 == Assimp::ASSIMP_stricmp(sz,"pfm"))
+						if (0 == ASSIMP_stricmp(sz,"png") ||
+							0 == ASSIMP_stricmp(sz,"bmp") ||
+							0 == ASSIMP_stricmp(sz,"jpg") ||
+							0 == ASSIMP_stricmp(sz,"tga") ||
+							0 == ASSIMP_stricmp(sz,"tif") ||
+							0 == ASSIMP_stricmp(sz,"hdr") ||
+							0 == ASSIMP_stricmp(sz,"ppm") ||
+							0 == ASSIMP_stricmp(sz,"pfm"))
 						{
 						{
 							CBackgroundPainter::Instance().SetTextureBG(szFile);
 							CBackgroundPainter::Instance().SetTextureBG(szFile);
 						}
 						}

+ 2 - 1
tools/assimp_view/assimp_view.cpp

@@ -132,7 +132,8 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
 		aiProcess_Triangulate			| // triangulate n-polygons
 		aiProcess_Triangulate			| // triangulate n-polygons
 		aiProcess_GenSmoothNormals		| // generate smooth normal vectors if not existing
 		aiProcess_GenSmoothNormals		| // generate smooth normal vectors if not existing
 		aiProcess_ConvertToLeftHanded	| // convert everything to D3D left handed space
 		aiProcess_ConvertToLeftHanded	| // convert everything to D3D left handed space
-		aiProcess_SplitLargeMeshes);      // split large, unrenderable meshes into submeshes
+		aiProcess_SplitLargeMeshes      | // split large, unrenderable meshes into submeshes
+		aiProcess_ValidateDataStructure); // 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();

+ 5 - 5
tools/assimp_view/assimp_view.h

@@ -46,21 +46,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "resource.h"
 #include "resource.h"
 
 
 // Include ASSIMP headers
 // Include ASSIMP headers
-#include "aiAnim.h"
 #include "aiAssert.h"
 #include "aiAssert.h"
 #include "aiFileIO.h"
 #include "aiFileIO.h"
-#include "aiMaterial.h"
 #include "aiPostProcess.h"
 #include "aiPostProcess.h"
-#include "aiMesh.h"
 #include "aiScene.h"
 #include "aiScene.h"
-#include "aiTypes.h"
 #include "IOSystem.h"
 #include "IOSystem.h"
 #include "IOStream.h"
 #include "IOStream.h"
 #include "assimp.h"
 #include "assimp.h"
 #include "assimp.hpp"
 #include "assimp.hpp"
 #include "LogStream.h"
 #include "LogStream.h"
 #include "DefaultLogger.h"
 #include "DefaultLogger.h"
-#include "MaterialSystem.h"
+ 
+#include "MaterialSystem.h"   // MaterialHelper clas
+#include "StringComparison.h" // ASSIMP_stricmp and ASSIMP_strincmp
 
 
 // in order for std::min and std::max to behave properly
 // in order for std::min and std::max to behave properly
 #ifdef min 
 #ifdef min 
@@ -73,6 +71,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // default movement speed 
 // default movement speed 
 #define MOVE_SPEED 10.0f
 #define MOVE_SPEED 10.0f
 
 
+using namespace Assimp;
+
 namespace AssimpView {
 namespace AssimpView {
 
 
 #include "AssetHelper.h"
 #include "AssetHelper.h"

+ 12 - 0
workspaces/vc8/assimp.vcproj

@@ -1033,6 +1033,10 @@
 				RelativePath="..\..\code\SplitLargeMeshes.h"
 				RelativePath="..\..\code\SplitLargeMeshes.h"
 				>
 				>
 			</File>
 			</File>
+			<File
+				RelativePath="..\..\code\StringComparison.h"
+				>
+			</File>
 			<File
 			<File
 				RelativePath="..\..\code\TextureTransform.h"
 				RelativePath="..\..\code\TextureTransform.h"
 				>
 				>
@@ -1041,6 +1045,10 @@
 				RelativePath="..\..\code\TriangulateProcess.h"
 				RelativePath="..\..\code\TriangulateProcess.h"
 				>
 				>
 			</File>
 			</File>
+			<File
+				RelativePath="..\..\code\ValidateDataStructure.h"
+				>
+			</File>
 			<Filter
 			<Filter
 				Name="ObjLoader"
 				Name="ObjLoader"
 				>
 				>
@@ -1333,6 +1341,10 @@
 				RelativePath="..\..\code\TriangulateProcess.cpp"
 				RelativePath="..\..\code\TriangulateProcess.cpp"
 				>
 				>
 			</File>
 			</File>
+			<File
+				RelativePath="..\..\code\ValidateDataStructure.cpp"
+				>
+			</File>
 			<Filter
 			<Filter
 				Name="ObjLoader"
 				Name="ObjLoader"
 				>
 				>