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
pull/1/head
aramis_acg 2008-06-15 10:27:08 +00:00
parent d6fc5de7d5
commit 758e092449
25 changed files with 1287 additions and 182 deletions

View File

@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "3DSLoader.h"
#include "MaterialSystem.h"
#include "TextureTransform.h"
#include "StringComparison.h"
#include "../include/DefaultLogger.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
Dot3DS::Material sMat;
@ -184,12 +185,6 @@ void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
sMesh->mFaces[i].mIndices[0] = iTemp1;
sMesh->mFaces[i].mIndices[1] = iTemp2;
// handle the face order ...
/*if (iTemp1 > iTemp2)
{
sMesh->mFaces[i].bFlipped = true;
}*/
}
}
else
@ -210,12 +205,6 @@ void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
sMesh->mFaces[i].mIndices[0] = iTemp1;
sMesh->mFaces[i].mIndices[1] = iTemp2;
// handle the face order ...
/*if (iTemp1 > iTemp2)
{
sMesh->mFaces[i].bFlipped = true;
}*/
}
}
sMesh->mPositions = vNew;

View File

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

View File

@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ASELoader.h"
#include "3DSSpatialSort.h"
#include "MaterialSystem.h"
#include "StringComparison.h"
#include "TextureTransform.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::ASE;
#define LOGOUT_WARN(x) DefaultLogger::get()->warn(x);
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
ASEImporter::ASEImporter()
@ -619,7 +618,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
if (mesh.iMaterialIndex >= this->mParser->m_vMaterials.size())
{
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
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
aiSplit[vSubMaterials.size()-1].push_back(i);

View File

@ -81,10 +81,14 @@ Parser::Parser (const char* szFile)
void Parser::LogWarning(const char* szWarn)
{
ai_assert(NULL != szWarn);
ai_assert(strlen(szWarn) < 950);
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 ...
DefaultLogger::get()->warn(szTemp);
@ -93,10 +97,14 @@ void Parser::LogWarning(const char* szWarn)
void Parser::LogInfo(const char* szWarn)
{
ai_assert(NULL != szWarn);
ai_assert(strlen(szWarn) < 950);
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 ...
DefaultLogger::get()->info(szTemp);
@ -105,10 +113,14 @@ void Parser::LogInfo(const char* szWarn)
void Parser::LogError(const char* szWarn)
{
ai_assert(NULL != szWarn);
ai_assert(strlen(szWarn) < 950);
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 new ImportErrorException(szTemp);
@ -118,8 +130,12 @@ bool Parser::SkipToNextToken()
{
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;
}
@ -670,21 +686,33 @@ void Parser::ParseLV3MapBlock(Texture& map)
bool Parser::ParseString(std::string& out,const char* szName)
{
char szBuffer[1024];
#if (!defined _MSC_VER) || ( _MSC_VER < 1400)
ai_assert(strlen(szName) < 750);
#endif
// NOTE: The name could also be the texture in some cases
// be prepared that this might occur ...
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);
#endif
this->LogWarning(szBuffer);
return false;
}
// there must be "
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 "
"to be enclosed in double quotation marks",szName);
#endif
this->LogWarning(szBuffer);
return false;
}
@ -695,9 +723,15 @@ bool Parser::ParseString(std::string& out,const char* szName)
if ('\"' == *sz)break;
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 "
"enclosed in double quotation marks but EOF was reached before a closing "
"quotation mark was found",szName);
#endif
this->LogWarning(szBuffer);
return false;
}
@ -968,6 +1002,7 @@ void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh)
this->LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
"Keyframe animation is not supported by Assimp, this element "
"will be ignored");
//this->SkipSection();
continue;
}
// 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]")
}
else if(IsLineEnd(*this->m_szFile))++this->iLineNumber;
this->m_szFile++;
}
return;

View File

@ -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 */
#include "BaseImporter.h"
#include "BaseProcess.h"
#include "../include/DefaultLogger.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/assimp.hpp"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
@ -88,3 +91,28 @@ aiScene* BaseImporter::ReadFile( const std::string& pFile, IOSystem* pIOHandler)
// return what we gathered from the import.
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;
}
}

View File

@ -78,7 +78,16 @@ public:
// -------------------------------------------------------------------
/** 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.
*/
virtual void Execute( aiScene* pScene) = 0;

View File

@ -47,6 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiAssert.h"
#include "../include/aiScene.h"
#include "../include/aiPostProcess.h"
#include "../include/DefaultLogger.h"
#include "BaseImporter.h"
#include "BaseProcess.h"
#include "DefaultIOStream.h"
@ -90,7 +92,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SplitLargeMeshes.h"
#include "PretransformVertices.h"
#include "LimitBoneWeightsProcess.h"
#include "../include/DefaultLogger.h"
#include "ValidateDataStructure.h"
using namespace Assimp;
@ -134,6 +136,7 @@ Importer::Importer() :
#endif
// 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 PretransformVertices());
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
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( mScene)
{
@ -248,10 +248,19 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
{
BaseProcess* process = mPostProcessingSteps[a];
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
return mScene;
}

View File

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

View File

@ -38,10 +38,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#include "../include/aiMaterial.h"
#include "MaterialSystem.h"
#include "StringComparison.h"
#include "../include/aiMaterial.h"
#include "../include/aiAssert.h"
using namespace Assimp;
@ -363,6 +363,13 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
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,
@ -460,7 +467,12 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
char szKey[256];
// 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))
{
return AI_FAILURE;
@ -469,7 +481,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
if (piUVIndex)
{
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))
iUV = 0;
@ -479,7 +495,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
if (pfBlendFactor)
{
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))
fBlend = 1.0f;
@ -490,7 +510,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
if (peTextureOp)
{
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))
op = aiTextureOp_Multiply;
@ -503,7 +527,11 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
aiTextureMapMode eMode;
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))
{
eMode = aiTextureMapMode_Wrap;

View File

@ -47,83 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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
structure easily. */

View File

@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file Implementation of the PLY importer class */
#include "PlyLoader.h"
#include "MaterialSystem.h"
#include "StringComparison.h"
#include "../include/IOStream.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
// become 1, not depending on the angle) use gouraud lighting
if (0.0f != fSpec)
if (fSpec)
{
// scale this with 15 ... hopefully this is correct

View File

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

View File

@ -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

View File

@ -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]);
}
}
}

View File

@ -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

View File

@ -208,27 +208,29 @@ struct aiMaterialProperty
{
/** Specifies the name of the property (key)
*
* Keys are case insensitive.
* Keys are case insensitive.
*/
C_STRUCT aiString* mKey;
/** Size of the buffer mData is pointing to, in bytes
* This value may not be 0.
*/
unsigned int mDataLength;
/** 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;
/** 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;
};
@ -239,8 +241,8 @@ struct aiMaterialProperty
*
* Material data is stored using a key-value structure, called property
* (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
@ -261,6 +263,54 @@ public:
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
@ -370,6 +420,10 @@ public:
* <br>
* <b>Type:</b> string (aiString)<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_ "$tex.file.diffuse"
@ -379,6 +433,10 @@ public:
* <br>
* <b>Type:</b> string (aiString)<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_ "$tex.file.ambient"
@ -388,6 +446,10 @@ public:
* <br>
* <b>Type:</b> string (aiString)<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_ "$tex.file.specular"
@ -397,6 +459,10 @@ public:
* <br>
* <b>Type:</b> string (aiString)<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_ "$tex.file.emissive"
@ -406,6 +472,10 @@ public:
* <br>
* <b>Type:</b> string (aiString)<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_ "$tex.file.normals"
@ -419,15 +489,23 @@ public:
* <br>
* <b>Type:</b> string (aiString)<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
* Defines a specified shininess texture channel of the material
* <br>
* <b>Type:</b> string (aiString)<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_ "$tex.file.shininess"
@ -437,10 +515,15 @@ public:
* <br>
* <b>Type:</b> string (aiString)<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_ "$tex.file.opacity"
// ---------------------------------------------------------------------------
/** @def AI_MATKEY_TEXOP_DIFFUSE
* Specifies the blend operation too be used to combine the Nth
@ -450,8 +533,10 @@ public:
* <b>Type:</b> int (aiTextureOp)<br>
* <b>Default value:</b> 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"]"
/** @see AI_MATKEY_TEXOP_DIFFUSE */
@ -485,8 +570,10 @@ public:
* <b>Type:</b> int<br>
* <b>Default value:</b> 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"]"
/** @see AI_MATKEY_UVWSRC_DIFFUSE */
@ -520,8 +607,10 @@ public:
* <b>Type:</b> float<br>
* <b>Default value:</b> 1.0f<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"]"
/** @see AI_MATKEY_TEXBLEND_DIFFUSE */
@ -556,8 +645,10 @@ public:
* <b>Type:</b> int (aiTextureMapMode)<br>
* <b>Default value:</b> aiTextureMapMode_Wrap<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"]"
/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */
@ -592,8 +683,10 @@ public:
* <b>Type:</b> int (aiTextureMapMode)<br>
* <b>Default value:</b> aiTextureMapMode_Wrap<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"]"
/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */
@ -628,8 +721,10 @@ public:
* <b>Type:</b> int (aiTextureMapMode)<br>
* <b>Default value:</b> aiTextureMapMode_Wrap<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"]"
/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */

View File

@ -395,7 +395,7 @@ struct aiMesh
//! Check whether the mesh contains a 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)
return false;
@ -405,7 +405,7 @@ struct aiMesh
//! Check whether the mesh contains a texture coordinate 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)
return false;

View File

@ -135,7 +135,16 @@ enum aiPostProcessSteps
* If you intend to perform the skinning in hardware, this post processing step
* 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
};
// ---------------------------------------------------------------------------

View File

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

View File

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

View File

@ -48,29 +48,6 @@ namespace AssimpView {
/*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
//

View File

@ -1589,14 +1589,14 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg,
// check whether it is a typical texture file format ...
++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);
}

View File

@ -132,7 +132,8 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
aiProcess_Triangulate | // triangulate n-polygons
aiProcess_GenSmoothNormals | // generate smooth normal vectors if not existing
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
double fEnd = (double)timeGetTime();

View File

@ -46,21 +46,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "resource.h"
// Include ASSIMP headers
#include "aiAnim.h"
#include "aiAssert.h"
#include "aiFileIO.h"
#include "aiMaterial.h"
#include "aiPostProcess.h"
#include "aiMesh.h"
#include "aiScene.h"
#include "aiTypes.h"
#include "IOSystem.h"
#include "IOStream.h"
#include "assimp.h"
#include "assimp.hpp"
#include "LogStream.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
#ifdef min
@ -73,6 +71,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// default movement speed
#define MOVE_SPEED 10.0f
using namespace Assimp;
namespace AssimpView {
#include "AssetHelper.h"

View File

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