Bufixes to the ASE loader, added "RemoveRedundantMaterials"-Step. Rewrite debug output.
git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@74 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
76ebdecd7a
commit
8aa56a62c2
|
@ -105,7 +105,7 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
|||
void ASEImporter::InternReadFile(
|
||||
const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rt"));
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL)
|
||||
|
@ -846,9 +846,9 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
|
|||
}
|
||||
++iBase;
|
||||
}
|
||||
p_pcOut->mFaces[q].mIndices[0] = iBase-2;
|
||||
p_pcOut->mFaces[q].mIndices[1] = iBase-1;
|
||||
p_pcOut->mFaces[q].mIndices[2] = iBase;
|
||||
p_pcOut->mFaces[q].mIndices[0] = iBase-3;
|
||||
p_pcOut->mFaces[q].mIndices[1] = iBase-2;
|
||||
p_pcOut->mFaces[q].mIndices[2] = iBase-1;
|
||||
}
|
||||
}
|
||||
// convert texture coordinates
|
||||
|
@ -1071,14 +1071,13 @@ void ASEImporter::BuildMaterialIndices()
|
|||
ai_assert(NULL != pcScene);
|
||||
|
||||
// iterate through all materials and check whether we need them
|
||||
unsigned int iNum = 0;
|
||||
for (unsigned int iMat = 0; iMat < this->mParser->m_vMaterials.size();++iMat)
|
||||
{
|
||||
if (this->mParser->m_vMaterials[iMat].bNeed)
|
||||
{
|
||||
// convert it to the aiMaterial layout
|
||||
this->ConvertMaterial(this->mParser->m_vMaterials[iMat]);
|
||||
iNum++;
|
||||
++pcScene->mNumMaterials;
|
||||
}
|
||||
for (unsigned int iSubMat = 0; iSubMat < this->mParser->m_vMaterials[
|
||||
iMat].avSubMaterials.size();++iSubMat)
|
||||
|
@ -1087,17 +1086,16 @@ void ASEImporter::BuildMaterialIndices()
|
|||
{
|
||||
// convert it to the aiMaterial layout
|
||||
this->ConvertMaterial(this->mParser->m_vMaterials[iMat].avSubMaterials[iSubMat]);
|
||||
iNum++;
|
||||
++pcScene->mNumMaterials;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allocate the output material array
|
||||
pcScene->mNumMaterials = iNum;
|
||||
pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials];
|
||||
Dot3DS::Material** pcIntMaterials = new Dot3DS::Material*[pcScene->mNumMaterials];
|
||||
|
||||
iNum = 0;
|
||||
unsigned int iNum = 0;
|
||||
for (unsigned int iMat = 0; iMat < this->mParser->m_vMaterials.size();++iMat)
|
||||
{
|
||||
if (this->mParser->m_vMaterials[iMat].bNeed)
|
||||
|
|
|
@ -83,7 +83,11 @@ using namespace Assimp::ASE;
|
|||
{ \
|
||||
return; \
|
||||
} \
|
||||
else if(IsLineEnd(*this->m_szFile))++this->iLineNumber; \
|
||||
if(IsLineEnd(*this->m_szFile) && !bLastWasEndLine) \
|
||||
{ \
|
||||
++this->iLineNumber; \
|
||||
bLastWasEndLine = true; \
|
||||
} else bLastWasEndLine = false; \
|
||||
++this->m_szFile;
|
||||
|
||||
#define AI_ASE_HANDLE_SECTION(iDepth, level, msg) \
|
||||
|
@ -102,7 +106,11 @@ using namespace Assimp::ASE;
|
|||
this->LogError("Encountered unexpected EOL while parsing a " msg \
|
||||
" chunk (Level " level ")"); \
|
||||
} \
|
||||
else if(IsLineEnd(*this->m_szFile))++this->iLineNumber; \
|
||||
if(IsLineEnd(*this->m_szFile) && !bLastWasEndLine) \
|
||||
{ \
|
||||
++this->iLineNumber; \
|
||||
bLastWasEndLine = true; \
|
||||
} else bLastWasEndLine = false; \
|
||||
++this->m_szFile;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -120,6 +128,7 @@ Parser::Parser (const char* szFile)
|
|||
this->iLastFrame = 0;
|
||||
this->iFrameSpeed = 30; // use 30 as default value for this property
|
||||
this->iTicksPerFrame = 1; // use 1 as default value for this property
|
||||
this->bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::LogWarning(const char* szWarn)
|
||||
|
@ -177,7 +186,12 @@ bool Parser::SkipToNextToken()
|
|||
char me = *this->m_szFile;
|
||||
|
||||
// increase the line number counter if necessary
|
||||
if (IsLineEnd(me))++this->iLineNumber;
|
||||
if (IsLineEnd(me) && !bLastWasEndLine)
|
||||
{
|
||||
++this->iLineNumber;
|
||||
bLastWasEndLine = true;
|
||||
}
|
||||
else bLastWasEndLine = false;
|
||||
if ('*' == me || '}' == me || '{' == me)return true;
|
||||
else if ('\0' == me)return false;
|
||||
|
||||
|
|
|
@ -550,6 +550,9 @@ public:
|
|||
|
||||
//! Ticks per frame
|
||||
unsigned int iTicksPerFrame;
|
||||
|
||||
//! true if the last character read was an end-line character
|
||||
bool bLastWasEndLine;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -130,6 +130,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#if (!defined AI_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
|
||||
# include "ImproveCacheLocality.h"
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
||||
# include "RemoveRedundantMaterials.h"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -142,7 +146,8 @@ Importer::Importer() :
|
|||
{
|
||||
// allocate a default IO handler
|
||||
mIOHandler = new DefaultIOSystem;
|
||||
mIsDefaultHandler = true;
|
||||
mIsDefaultHandler = true;
|
||||
bExtraVerbose = false; // disable extra verbose mode by default
|
||||
|
||||
// add an instance of each worker class here
|
||||
#if (!defined AI_BUILD_NO_X_IMPORTER)
|
||||
|
@ -182,7 +187,10 @@ Importer::Importer() :
|
|||
// add an instance of each post processing step here in the order
|
||||
// of sequence it is executed
|
||||
#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS)
|
||||
mPostProcessingSteps.push_back( new ValidateDSProcess());
|
||||
mPostProcessingSteps.push_back( new ValidateDSProcess()); // must be first
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
||||
mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
|
||||
mPostProcessingSteps.push_back( new TriangulateProcess());
|
||||
|
@ -328,6 +336,14 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
|
|||
// if successful, apply all active post processing steps to the imported data
|
||||
if( mScene)
|
||||
{
|
||||
if (bExtraVerbose)
|
||||
{
|
||||
pFlags |= aiProcess_ValidateDataStructure;
|
||||
|
||||
// use the MSB to tell the ValidateDS-Step that e're in extra verbose mode
|
||||
// TODO: temporary solution, clean up later
|
||||
mScene->mFlags |= 0x80000000;
|
||||
}
|
||||
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)
|
||||
{
|
||||
BaseProcess* process = mPostProcessingSteps[a];
|
||||
|
@ -336,7 +352,21 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
|
|||
process->ExecuteOnScene( this );
|
||||
}
|
||||
if( !mScene)break; // error string has already been set ...
|
||||
|
||||
// if the extra verbose mode is active execute the
|
||||
// VaidateDataStructureStep again after each step
|
||||
if (bExtraVerbose && a)
|
||||
{
|
||||
DefaultLogger::get()->debug("Extra verbose: revalidating data structures");
|
||||
((ValidateDSProcess*)mPostProcessingSteps[0])->ExecuteOnScene (this);
|
||||
if( !mScene)
|
||||
{
|
||||
DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures");
|
||||
break; // error string has already been set ...
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bExtraVerbose)mScene->mFlags &= ~0x80000000;
|
||||
}
|
||||
|
||||
// if failed, extract the error string
|
||||
|
|
|
@ -63,6 +63,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ImproveCacheLocalityProcess::ImproveCacheLocalityProcess()
|
||||
|
@ -93,14 +97,14 @@ void ImproveCacheLocalityProcess::Execute( aiScene* pScene)
|
|||
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
this->ProcessMesh( pScene->mMeshes[a]);
|
||||
this->ProcessMesh( pScene->mMeshes[a],a);
|
||||
}
|
||||
DefaultLogger::get()->debug("ImproveCacheLocalityProcess finished. ");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Improves the cache coherency of a specific mesh
|
||||
void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh)
|
||||
void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshNum)
|
||||
{
|
||||
ai_assert(NULL != pMesh);
|
||||
|
||||
|
@ -162,12 +166,7 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh)
|
|||
}
|
||||
}
|
||||
delete[] piFIFOStack;
|
||||
|
||||
float fACMR = (float)iCacheMisses / pMesh->mNumFaces;
|
||||
char szBuff[16];
|
||||
sprintf(szBuff,"%f",fACMR);
|
||||
DefaultLogger::get()->debug("Input ACMR: " + std::string(szBuff));
|
||||
|
||||
|
||||
// first we need to build a vertex-triangle adjacency list
|
||||
VertexTriangleAdjacency adj(pMesh->mFaces,pMesh->mNumFaces, pMesh->mNumVertices,true);
|
||||
|
@ -347,11 +346,15 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
char szBuff[128]; // should be sufficiently large in every case
|
||||
float fACMR2 = (float)iCacheMisses / pMesh->mNumFaces;
|
||||
|
||||
fACMR = (float)iCacheMisses / pMesh->mNumFaces;
|
||||
sprintf(szBuff,"%f",fACMR);
|
||||
DefaultLogger::get()->debug("Output ACMR: " + std::string(szBuff));
|
||||
|
||||
sprintf(szBuff,"Mesh %i | ACMR in: %f out: %f | ~%.1f%%",meshNum,fACMR,fACMR2,
|
||||
((fACMR - fACMR2) / fACMR) * 100.f);
|
||||
DefaultLogger::get()->info(szBuff);
|
||||
}
|
||||
// sort the output index buffer back to the input array
|
||||
piCSIter = piIBOutput;
|
||||
|
||||
|
|
|
@ -89,8 +89,9 @@ protected:
|
|||
// -------------------------------------------------------------------
|
||||
/** Executes the postprocessing step on the given mesh
|
||||
* @param pMesh The mesh to process.
|
||||
* @param meshNum Index of the mesh to process
|
||||
*/
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
void ProcessMesh( aiMesh* pMesh, unsigned int meshNum);
|
||||
|
||||
|
||||
//! Configuration parameter: specifies the size of the cache to
|
||||
|
|
|
@ -53,6 +53,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
JoinVerticesProcess::JoinVerticesProcess()
|
||||
|
@ -80,22 +84,44 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
|
|||
{
|
||||
DefaultLogger::get()->debug("JoinVerticesProcess begin");
|
||||
|
||||
bool bHas = false;
|
||||
// get the total number of vertices BEFORE the step is executed
|
||||
int iNumOldVertices = 0;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
if( this->ProcessMesh( pScene->mMeshes[a]))
|
||||
bHas = true;
|
||||
iNumOldVertices += pScene->mMeshes[a]->mNumVertices;
|
||||
}
|
||||
|
||||
// execute the step
|
||||
int iNumVertices = 0;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
iNumVertices += this->ProcessMesh( pScene->mMeshes[a],a);
|
||||
}
|
||||
// if logging is active, print detailled statistics
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
if (iNumOldVertices == iNumVertices)DefaultLogger::get()->debug("JoinVerticesProcess finished ");
|
||||
else
|
||||
{
|
||||
char szBuff[128]; // should be sufficiently large in every case
|
||||
sprintf(szBuff,"JoinVerticesProcess finished | Verts in: %i out: %i | ~%.1f%%",
|
||||
iNumOldVertices,
|
||||
iNumVertices,
|
||||
((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f);
|
||||
DefaultLogger::get()->info(szBuff);
|
||||
}
|
||||
}
|
||||
if (bHas)DefaultLogger::get()->info("JoinVerticesProcess finished. Found vertices to join");
|
||||
else DefaultLogger::get()->debug("JoinVerticesProcess finished. There was nothing to do.");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Unites identical vertices in the given mesh
|
||||
bool JoinVerticesProcess::ProcessMesh( aiMesh* pMesh)
|
||||
int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
||||
{
|
||||
// helper structure to hold all the data a single vertex can possibly have
|
||||
typedef struct Vertex vertex;
|
||||
|
||||
if (!pMesh->HasPositions() || !pMesh->HasFaces())
|
||||
return 0;
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
|
@ -216,6 +242,17 @@ bool JoinVerticesProcess::ProcessMesh( aiMesh* pMesh)
|
|||
}
|
||||
}
|
||||
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
char szBuff[128]; // should be sufficiently large in every case
|
||||
sprintf(szBuff,"Mesh %i | Verts in: %i out: %i | ~%.1f%%",
|
||||
meshIndex,
|
||||
pMesh->mNumVertices,
|
||||
uniqueVertices.size(),
|
||||
((pMesh->mNumVertices - uniqueVertices.size()) / (float)pMesh->mNumVertices) * 100.f);
|
||||
DefaultLogger::get()->info(szBuff);
|
||||
}
|
||||
|
||||
// replace vertex data with the unique data sets
|
||||
pMesh->mNumVertices = (unsigned int)uniqueVertices.size();
|
||||
// Position
|
||||
|
@ -310,5 +347,5 @@ bool JoinVerticesProcess::ProcessMesh( aiMesh* pMesh)
|
|||
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
||||
memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
|
||||
}
|
||||
return (iOldVerts != pMesh->mNumVertices);
|
||||
return pMesh->mNumVertices;
|
||||
}
|
||||
|
|
|
@ -90,8 +90,9 @@ protected:
|
|||
// -------------------------------------------------------------------
|
||||
/** Unites identical vertices in the given mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
* @param meshIndex Index of the mesh to process
|
||||
*/
|
||||
bool ProcessMesh( aiMesh* pMesh);
|
||||
int ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Little helper function to calculate the quadratic difference
|
||||
|
|
|
@ -47,6 +47,67 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// hashing function taken from
|
||||
// http://www.azillionmonkeys.com/qed/hash.html
|
||||
// (incremental version of the hashing function)
|
||||
// (stdint.h should have been been included here)
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t SuperFastHash (const char * data, int len, uint32_t hash = 0) {
|
||||
uint32_t tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += get16bits (data);
|
||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof (uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
|
@ -230,13 +291,30 @@ aiReturn aiGetMaterialString(const aiMaterial* pMat,
|
|||
return AI_FAILURE;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t MaterialHelper::ComputeHash()
|
||||
{
|
||||
uint32_t hash = 1503; // magic start value, choosen to be my birthday :-)
|
||||
for (unsigned int i = 0; i < this->mNumProperties;++i)
|
||||
{
|
||||
aiMaterialProperty* prop;
|
||||
|
||||
// NOTE: We need to exclude the material name from the hash
|
||||
if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey->data,AI_MATKEY_NAME))
|
||||
{
|
||||
hash = SuperFastHash(prop->mKey->data,prop->mKey->length,hash);
|
||||
hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn MaterialHelper::RemoveProperty (const char* pKey)
|
||||
{
|
||||
ai_assert(NULL != pKey);
|
||||
|
||||
for (unsigned int i = 0; i < this->mNumProperties;++i)
|
||||
{
|
||||
if (NULL != this->mProperties[i])
|
||||
if (this->mProperties[i]) // just for safety
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey->data, pKey ))
|
||||
{
|
||||
|
@ -272,7 +350,7 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
unsigned int iOutIndex = 0xFFFFFFFF;
|
||||
for (unsigned int i = 0; i < this->mNumProperties;++i)
|
||||
{
|
||||
if (NULL != this->mProperties[i])
|
||||
if (this->mProperties[i])
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey->data, pKey ))
|
||||
{
|
||||
|
@ -304,8 +382,7 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// resize the array ... allocate
|
||||
// storage for 5 other properties
|
||||
// resize the array ... allocate storage for 5 other properties
|
||||
if (this->mNumProperties == this->mNumAllocated)
|
||||
{
|
||||
unsigned int iOld = this->mNumAllocated;
|
||||
|
|
|
@ -104,6 +104,17 @@ public:
|
|||
*/
|
||||
aiReturn RemoveProperty (const char* pKey);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes a hash (hopefully unique) from all material properties
|
||||
* The hash value must be updated after material properties have
|
||||
* been changed.
|
||||
*
|
||||
* \return Unique hash
|
||||
*/
|
||||
uint32_t ComputeHash();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Copy the property list of a material
|
||||
* \param pcDest Destination material
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 "RemoveRedundantMaterials" post processing step
|
||||
*/
|
||||
|
||||
// internal headers
|
||||
#include "RemoveRedundantMaterials.h"
|
||||
#include "MaterialSystem.h"
|
||||
|
||||
// public ASSIMP headers
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/aiPostProcess.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
RemoveRedundantMatsProcess::RemoveRedundantMatsProcess()
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
DefaultLogger::get()->debug("RemoveRedundantMatsProcess begin");
|
||||
|
||||
unsigned int iCnt = 0;
|
||||
if (pScene->mNumMaterials)
|
||||
{
|
||||
// TODO: reimplement this algorithm to work in-place
|
||||
|
||||
unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials];
|
||||
unsigned int iNewNum = 0;
|
||||
|
||||
// iterate through all materials and calculate a hash for them
|
||||
// store all hashes in a list and so a quick search whether
|
||||
// we do already have a specific hash. This allows us to
|
||||
// determine which materials are identical.
|
||||
uint32_t* aiHashes;
|
||||
aiHashes = new uint32_t[pScene->mNumMaterials];
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
{
|
||||
uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash();
|
||||
for (unsigned int a = 0; a < i;++a)
|
||||
{
|
||||
if (me == aiHashes[a])
|
||||
{
|
||||
++iCnt;
|
||||
me = 0;
|
||||
aiMappingTable[i] = aiMappingTable[a];
|
||||
delete pScene->mMaterials[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (me)
|
||||
{
|
||||
aiMappingTable[i] = iNewNum++;
|
||||
}
|
||||
}
|
||||
if (iCnt)
|
||||
{
|
||||
// build an output material list
|
||||
aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
|
||||
::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
|
||||
for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
|
||||
{
|
||||
// generate new names for all modified materials
|
||||
const unsigned int idx = aiMappingTable[p];
|
||||
if (!ppcMaterials[idx])
|
||||
{
|
||||
aiString sz;
|
||||
sz.length = ::sprintf(sz.data,"aiMaterial #%i",p);
|
||||
ppcMaterials[idx] = pScene->mMaterials[p];
|
||||
((MaterialHelper*)pScene->mMaterials[p])->AddProperty(&sz,AI_MATKEY_NAME);
|
||||
}
|
||||
}
|
||||
// update all material indices
|
||||
for (unsigned int p = 0; p < pScene->mNumMeshes;++p)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[p];
|
||||
mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
|
||||
}
|
||||
// delete the old material list
|
||||
delete[] pScene->mMaterials;
|
||||
pScene->mMaterials = ppcMaterials;
|
||||
pScene->mNumMaterials = iNewNum;
|
||||
}
|
||||
// delete temporary storage
|
||||
delete[] aiHashes;
|
||||
delete[] aiMappingTable;
|
||||
}
|
||||
if (!iCnt)DefaultLogger::get()->debug("RemoveRedundantMatsProcess finished ");
|
||||
else
|
||||
{
|
||||
char szBuffer[128]; // should be sufficiently large
|
||||
::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. Found %i redundant materials",iCnt);
|
||||
DefaultLogger::get()->info(szBuffer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
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 remove redundant materials */
|
||||
#ifndef AI_REMOVEREDUNDANTMATERIALS_H_INC
|
||||
#define AI_REMOVEREDUNDANTMATERIALS_H_INC
|
||||
|
||||
#include "BaseProcess.h"
|
||||
#include "../include/aiMesh.h"
|
||||
|
||||
class RemoveRedundantMatsTest;
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** RemoveRedundantMatsProcess: Class to remove redundant materials
|
||||
*/
|
||||
class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
friend class ::RemoveRedundantMatsTest; // grant the unit test full access to us
|
||||
|
||||
protected:
|
||||
/** Constructor to be privately used by Importer */
|
||||
RemoveRedundantMatsProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~RemoveRedundantMatsProcess();
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
* @param pFlags The processing flags the importer was called with. A bitwise
|
||||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
};
|
||||
}; // end of namespace Assimp
|
||||
|
||||
#endif // !!AI_REMOVEREDUNDANTMATERIALS_H_INC
|
|
@ -293,7 +293,10 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
|
|||
{
|
||||
this->ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
|
||||
}
|
||||
if (abRefList[face.mIndices[a]])
|
||||
// the MSB flag is temporarily used by the extra verbose
|
||||
// mode to tell us that the JoinVerticesProcess might have
|
||||
// been executed already.
|
||||
if ( !(this->mScene->mFlags & 0x80000000 ) && 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);
|
||||
|
|
|
@ -154,7 +154,15 @@ enum aiPostProcessSteps
|
|||
* basing on the algorithm described in this paper:
|
||||
* http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf
|
||||
*/
|
||||
aiProcess_ImproveCacheLocality = 0x1600
|
||||
aiProcess_ImproveCacheLocality = 0x800,
|
||||
|
||||
/** Searches for redundant materials and removes them.
|
||||
*
|
||||
* This is especially useful in combination with the PretransformVertices
|
||||
* and OptimizeGraph steps. Both steps join small meshes, but they
|
||||
* can't do that if two meshes have different materials.
|
||||
*/
|
||||
aiProcess_RemoveRedundantMaterials = 0x1000,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -198,6 +198,16 @@ public:
|
|||
inline const aiScene* GetScene()
|
||||
{return this->mScene;}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Enables the "extra verbose" mode. In this mode the data
|
||||
* structure is validated after each post-process step to make sure
|
||||
* all steps behave consequently in the same manner when modifying
|
||||
* data structures.
|
||||
*/
|
||||
inline void SetExtraVerbose(bool bDo)
|
||||
{this->bExtraVerbose = bDo;}
|
||||
|
||||
private:
|
||||
|
||||
/** Empty copy constructor. */
|
||||
|
@ -222,6 +232,9 @@ protected:
|
|||
|
||||
/** The error description, if there was one. */
|
||||
std::string mErrorString;
|
||||
|
||||
/** Used for testing */
|
||||
bool bExtraVerbose;
|
||||
};
|
||||
|
||||
} // End of namespace Assimp
|
||||
|
|
|
@ -133,7 +133,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
|
|||
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_ValidateDataStructure | aiProcess_ImproveCacheLocality); // validate the output data structure
|
||||
aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials); // validate the output data structure
|
||||
|
||||
// get the end time of zje operation, calculate delta t
|
||||
double fEnd = (double)timeGetTime();
|
||||
|
|
|
@ -675,14 +675,6 @@
|
|||
RelativePath="..\..\test\unit\Main.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\ut3DSLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utASELoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utFixInfacingNormals.cpp"
|
||||
>
|
||||
|
@ -711,14 +703,6 @@
|
|||
RelativePath="..\..\test\unit\utMaterialSystem.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utMDLLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utOBJLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utPretransformVertices.cpp"
|
||||
>
|
||||
|
|
|
@ -654,6 +654,10 @@
|
|||
RelativePath="..\..\include\assimp.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\DefaultLogger.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\IOStream.h"
|
||||
>
|
||||
|
@ -762,6 +766,10 @@
|
|||
RelativePath="..\..\code\RemoveComments.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\RemoveRedundantMaterials.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SpatialSort.h"
|
||||
>
|
||||
|
@ -1090,6 +1098,10 @@
|
|||
RelativePath="..\..\code\RemoveComments.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\RemoveRedundantMaterials.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SpatialSort.cpp"
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue