Added "ImproveCacheLocality"-Step; Added Unit tests (3 at the moment); Fixed hp spelling errors.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@68 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
This commit is contained in:
aramis_acg
2008-07-22 22:52:16 +00:00
parent 04fe342441
commit e8511e89ff
45 changed files with 2324 additions and 152 deletions
+10
View File
@@ -40,15 +40,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file Implementation of the CPP-API class #Importer */
// STL/CSL heades
#include <fstream>
#include <string>
// public Assimp API
#include "../include/assimp.hpp"
#include "../include/aiAssert.h"
#include "../include/aiScene.h"
#include "../include/aiPostProcess.h"
#include "../include/DefaultLogger.h"
// internal headers
#include "BaseImporter.h"
#include "BaseProcess.h"
#include "DefaultIOStream.h"
@@ -123,6 +127,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS)
# include "ValidateDataStructure.h"
#endif
#if (!defined AI_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
# include "ImproveCacheLocality.h"
#endif
using namespace Assimp;
@@ -210,6 +217,9 @@ Importer::Importer() :
#if (!defined AI_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
mPostProcessingSteps.push_back( new LimitBoneWeightsProcess());
#endif
#if (!defined AI_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess());
#endif
}
// ------------------------------------------------------------------------------------------------
+370
View File
@@ -0,0 +1,370 @@
/*
---------------------------------------------------------------------------
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 join identical vertices
* for all imported meshes
* <br>
* The algorithm is roughly basing on this paper:
* http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf
*/
// STL headers
#include <vector>
#include <stack>
#include <queue>
// public ASSIMP headers
#include "../include/DefaultLogger.h"
#include "../include/aiPostProcess.h"
#include "../include/aiMesh.h"
#include "../include/aiScene.h"
// internal headers
#include "ImproveCacheLocality.h"
#include "VertexTriangleAdjacency.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
ImproveCacheLocalityProcess::ImproveCacheLocalityProcess()
{
// nothing to do here
configCacheDepth = 12; // hardcoded to 12 at the moment
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const
{
return (pFlags & aiProcess_ImproveCacheLocality) != 0;
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void ImproveCacheLocalityProcess::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("ImproveCacheLocalityProcess begin");
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
{
this->ProcessMesh( pScene->mMeshes[a]);
}
DefaultLogger::get()->debug("ImproveCacheLocalityProcess finished. ");
}
// ------------------------------------------------------------------------------------------------
// Improves the cache coherency of a specific mesh
void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh)
{
ai_assert(NULL != pMesh);
// check whether the input data is valid ->
// - there must be vertices and faces (haha)
// - all faces must be triangulated
if (!pMesh->HasFaces() || !pMesh->HasPositions())return;
// find the input ACMR ...
unsigned int* piFIFOStack = new unsigned int[this->configCacheDepth];
::memset(piFIFOStack,0xff,this->configCacheDepth*sizeof(unsigned int));
unsigned int* piCur = piFIFOStack;
const unsigned int* const piCurEnd = piFIFOStack + this->configCacheDepth;
// count the number of cache misses
unsigned int iCacheMisses = 0;
const aiFace* const pcEnd = pMesh->mFaces+pMesh->mNumFaces;
for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace)
{
if (3 != pcFace->mNumIndices)
{
DefaultLogger::get()->error("Unable to improve cache locality of non-triangulated faces");
delete[] piFIFOStack;
return;
}
// although it has not been tested, I'm quite sure degenerated triangles
// would crash if the algorithm was applied to them
#if (defined _DEBUG)
if (pcFace->mIndices[0] == pcFace->mIndices[1] ||
pcFace->mIndices[2] == pcFace->mIndices[1] ||
pcFace->mIndices[2] == pcFace->mIndices[0])
{
DefaultLogger::get()->error("ImproveCacheLocalityProcess: There may be no degenerated triangles ");
return;
}
#endif
for (unsigned int qq = 0; qq < 3;++qq)
{
bool bInCache = false;
for (unsigned int* pp = piFIFOStack;pp < piCurEnd;++pp)
{
if (*pp == pcFace->mIndices[qq])
{
// the vertex is in cache
bInCache = true;
break;
}
}
if (!bInCache)
{
++iCacheMisses;
if (piCurEnd == piCur)piCur = piFIFOStack;
*piCur++ = pcFace->mIndices[qq];
}
}
}
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);
// build a list to store per-vertex caching time stamps
unsigned int* const piCachingStamps = new unsigned int[pMesh->mNumVertices];
::memset(piCachingStamps,0x0,pMesh->mNumVertices*sizeof(unsigned int));
// allocate an empty output index buffer. We store the output
// indices in one large array. Since the number of triangles
// won't change the input faces can be reused. This is how we save
// thousands of redundant mini allocations for aiFace::mIndices
const unsigned int iIdxCnt = pMesh->mNumFaces*3;
unsigned int* const piIBOutput = new unsigned int[iIdxCnt];
unsigned int* piCSIter = piIBOutput;
// allocate the flag array to hold the information
// whether a face has already been emitted or not
std::vector<bool> abEmitted(pMesh->mNumFaces,false);
// dead-end vertex index stack
std::stack<unsigned int> sDeadEndVStack;
// create a copy of the piNumTriPtr buffer
unsigned int* const piNumTriPtr = adj.mLiveTriangles;
const unsigned int* const piNumTriPtrNoModify = new unsigned int[pMesh->mNumVertices];
::memcpy(const_cast<unsigned int* const> (piNumTriPtrNoModify),piNumTriPtr,
pMesh->mNumVertices * sizeof(unsigned int));
// get the largest number of referenced triangles
// and allocate the "candidate buffer"
unsigned int iMaxRefTris = 0;
{
const unsigned int* piCur = adj.mLiveTriangles;
const unsigned int* const piCurEnd = adj.mLiveTriangles+pMesh->mNumVertices;
for (;piCur != piCurEnd;++piCur)
iMaxRefTris = std::max(iMaxRefTris,*piCur);
}
unsigned int* piCandidates = new unsigned int[iMaxRefTris*3];
iCacheMisses = 0;
/** PSEUDOCODE for the algorithm
A = Build-Adjacency(I) Vertex-triangle adjacency
L = Get-Triangle-Counts(A) Per-vertex live triangle counts
C = Zero(Vertex-Count(I)) Per-vertex caching time stamps
D = Empty-Stack() Dead-end vertex stack
E = False(Triangle-Count(I)) Per triangle emitted flag
O = Empty-Index-Buffer() Empty output buffer
f = 0 Arbitrary starting vertex
s = k+1, i = 1 Time stamp and cursor
while f >= 0 For all valid fanning vertices
N = Empty-Set() 1-ring of next candidates
for each Triangle t in Neighbors(A, f)
if !Emitted(E,t)
for each Vertex v in t
Append(O,v) Output vertex
Push(D,v) Add to dead-end stack
Insert(N,v) Register as candidate
L[v] = L[v]-1 Decrease live triangle count
if s-C[v] > k If not in cache
C[v] = s Set time stamp
s = s+1 Increment time stamp
E[t] = true Flag triangle as emitted
Select next fanning vertex
f = Get-Next-Vertex(I,i,k,N,C,s,L,D)
return O
*/
int ivdx = 0;
int ics = 1;
int iStampCnt = this->configCacheDepth+1;
while (ivdx >= 0)
{
unsigned int icnt = piNumTriPtrNoModify[ivdx];
unsigned int* piList = adj.GetAdjacentTriangles(ivdx);
unsigned int* piCurCandidate = piCandidates;
// get all triangles in the neighborhood
for (unsigned int tri = 0; tri < icnt;++tri)
{
// if they have not yet been emitted, add them to the output IB
const unsigned int fidx = *piList++;
if (!abEmitted[fidx])
{
// so iterate through all vertices of the current triangle
const aiFace* pcFace = &pMesh->mFaces[ fidx ];
const unsigned int* const p2 = pcFace->mIndices+3;
for (unsigned int* p = pcFace->mIndices;p != p2;++p)
{
const unsigned int dp = *p;
// the current vertex won't have any free triangles after this step
if (ivdx != dp)
{
// append the vertex to the dead-end stack
sDeadEndVStack.push(dp);
// register as candidate for the next step
*piCurCandidate++ = dp;
// decrease the per-vertex triangle counts
piNumTriPtr[dp]--;
}
// append the vertex to the output index buffer
*piCSIter++ = dp;
// if the vertex is not yet in cache, set its cache count
if (iStampCnt-piCachingStamps[dp] > this->configCacheDepth)
{
piCachingStamps[dp] = iStampCnt++;
++iCacheMisses;
}
}
// flag triangle as emitted
abEmitted[fidx] = true;
}
}
// the vertex has now no living adjacent triangles anymore
piNumTriPtr[ivdx] = 0;
// get next fanning vertex
ivdx = -1;
int max_priority = -1;
for (unsigned int* piCur = piCandidates;piCur != piCurCandidate;++piCur)
{
register const unsigned int dp = *piCur;
// must have live triangles
if (piNumTriPtr[dp] > 0)
{
int priority = 0;
// will the vertex be in cache, even after fanning occurs?
unsigned int tmp;
if ((tmp = iStampCnt-piCachingStamps[dp]) + 2*piNumTriPtr[dp] <= this->configCacheDepth)
priority = tmp;
// keep best candidate
if (priority > max_priority)
{
max_priority = priority;
ivdx = dp;
}
}
}
// did we reach a dead end?
if (-1 == ivdx)
{
// need to get a non-local vertex for which we have a good
// chance that it is still in the cache ...
while (!sDeadEndVStack.empty())
{
unsigned int iCachedIdx = sDeadEndVStack.top();
sDeadEndVStack.pop();
if (piNumTriPtr[ iCachedIdx ] > 0)
{
ivdx = iCachedIdx;
break;
}
}
if (-1 == ivdx)
{
// well, there isn't such a vertex. Simply get the next
// vertex in input order and hope it is not too bad ...
while (ics < (int)pMesh->mNumVertices)
{
++ics;
if (piNumTriPtr[ics] > 0)
{
ivdx = ics;
break;
}
}
}
}
}
fACMR = (float)iCacheMisses / pMesh->mNumFaces;
sprintf(szBuff,"%f",fACMR);
DefaultLogger::get()->debug("Output ACMR: " + std::string(szBuff));
// sort the output index buffer back to the input array
piCSIter = piIBOutput;
for (aiFace* pcFace = pMesh->mFaces; pcFace != pcEnd;++pcFace)
{
pcFace->mIndices[0] = *piCSIter++;
pcFace->mIndices[1] = *piCSIter++;
pcFace->mIndices[2] = *piCSIter++;
}
// delete temporary storage
delete[] piCachingStamps;
delete[] piIBOutput;
delete[] piCandidates;
delete[] piNumTriPtrNoModify;
}
+103
View File
@@ -0,0 +1,103 @@
/*
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 reorder faces for
better cache locality*/
#ifndef AI_IMPROVECACHELOCALITY_H_INC
#define AI_IMPROVECACHELOCALITY_H_INC
#include "BaseProcess.h"
#include "../include/aiTypes.h"
struct aiMesh;
namespace Assimp
{
// ---------------------------------------------------------------------------
/** The ImproveCacheLocalityProcess reorders all faces for improved vertex
* cache locality. It tries to arrange all faces to fans and to render
* faces which share vertices directly one after the other.
*
* @note This step expects the triagulated input data.
*/
class ImproveCacheLocalityProcess : public BaseProcess
{
friend class Importer;
protected:
/** Constructor to be privately used by Importer */
ImproveCacheLocalityProcess();
/** Destructor, private as well */
~ImproveCacheLocalityProcess();
public:
// -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field.
* @param pFlags The processing flags the importer was called with. A bitwise
* combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not.
*/
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
/** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail.
* @param pScene The imported data to work at.
*/
void Execute( aiScene* pScene);
protected:
// -------------------------------------------------------------------
/** Executes the postprocessing step on the given mesh
* @param pMesh The mesh to process.
*/
void ProcessMesh( aiMesh* pMesh);
//! Configuration parameter: specifies the size of the cache to
//! optimize the vertex data for.
unsigned int configCacheDepth;
};
} // end of namespace Assimp
#endif // AI_IMPROVECACHELOCALITY_H_INC
+3 -4
View File
@@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <vector>
#include <assert.h>
#include "JoinVerticesProcess.h"
#include "SpatialSort.h"
#include "../include/DefaultLogger.h"
@@ -177,7 +176,7 @@ bool JoinVerticesProcess::ProcessMesh( aiMesh* pMesh)
if( (uv.mBitangent - v.mBitangent).SquareLength() > squareEpsilon)
continue;
// manually unrolled because continue wouldn't work as desired in an inner loop
assert( AI_MAX_NUMBER_OF_COLOR_SETS == 4);
ai_assert( AI_MAX_NUMBER_OF_COLOR_SETS == 4);
if( GetColorDifference( uv.mColors[0], v.mColors[0]) > squareEpsilon)
continue;
if( GetColorDifference( uv.mColors[1], v.mColors[1]) > squareEpsilon)
@@ -187,7 +186,7 @@ bool JoinVerticesProcess::ProcessMesh( aiMesh* pMesh)
if( GetColorDifference( uv.mColors[3], v.mColors[3]) > squareEpsilon)
continue;
// texture coord matching manually unrolled as well
assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 4);
ai_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 4);
if( (uv.mTexCoords[0] - v.mTexCoords[0]).SquareLength() > squareEpsilon)
continue;
if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon)
@@ -303,7 +302,7 @@ bool JoinVerticesProcess::ProcessMesh( aiMesh* pMesh)
}
// there should be some. At least I think there should be some
assert( newWeights.size() > 0);
ai_assert( newWeights.size() > 0);
// kill the old and replace them with the translated weights
delete [] bone->mWeights;
+67 -20
View File
@@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiPostProcess.h"
#include "../include/aiMesh.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/DefaultLogger.h"
using namespace Assimp;
@@ -122,11 +123,14 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
}
// now cut the weight count if it exceeds the maximum
bool bChanged = false;
for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit)
{
if( vit->size() <= mMaxWeights)
continue;
bChanged = true;
// more than the defined maximum -> first sort by weight in descending order. That's
// why we defined the < operator in such a weird way.
std::sort( vit->begin(), vit->end());
@@ -142,28 +146,71 @@ void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
it->mWeight /= sum;
}
// rebuild the vertex weight array for all bones
typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone;
WeightsPerBone boneWeights( pMesh->mNumBones);
for( unsigned int a = 0; a < vertexWeights.size(); a++)
if (bChanged)
{
const std::vector<Weight>& vw = vertexWeights[a];
for( std::vector<Weight>::const_iterator it = vw.begin(); it != vw.end(); ++it)
boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight));
}
// and finally copy the vertex weight list over to the mesh's bones
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
{
const std::vector<aiVertexWeight>& bw = boneWeights[a];
aiBone* bone = pMesh->mBones[a];
// ignore the bone if no vertex weights were removed there
if( bw.size() == bone->mNumWeights)
continue;
// rebuild the vertex weight array for all bones
typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone;
WeightsPerBone boneWeights( pMesh->mNumBones);
for( unsigned int a = 0; a < vertexWeights.size(); a++)
{
const std::vector<Weight>& vw = vertexWeights[a];
for( std::vector<Weight>::const_iterator it = vw.begin(); it != vw.end(); ++it)
boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight));
}
// copy the weight list. should always be less weights than before, so we don't need a new allocation
assert( bw.size() < bone->mNumWeights);
bone->mNumWeights = (unsigned int) bw.size();
memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
// and finally copy the vertex weight list over to the mesh's bones
std::vector<bool> abNoNeed(pMesh->mNumBones,false);
bChanged = false;
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
{
const std::vector<aiVertexWeight>& bw = boneWeights[a];
aiBone* bone = pMesh->mBones[a];
// ignore the bone if no vertex weights were removed there
// FIX (Aramis, 07|22|08)
// NO! we can't ignore it in this case ... it is possible that
// the number of weights did not change, but the weight values did.
// if( bw.size() == bone->mNumWeights)
// continue;
// FIX (Aramis, 07|21|08)
// It is possible that all weights of a bone have been removed.
// This would naturally cause an exception in &bw[0].
if ( bw.empty() )
{
abNoNeed[a] = bChanged = true;
continue;
}
// copy the weight list. should always be less weights than before, so we don't need a new allocation
ai_assert( bw.size() <= bone->mNumWeights);
bone->mNumWeights = (unsigned int) bw.size();
::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
}
if (bChanged)
{
// the number of new bones is smaller than before, so we can
// reuse the old array, too.
aiBone** ppcCur = pMesh->mBones;
aiBone** ppcSrc = ppcCur;
for (std::vector<bool>::const_iterator
iter = abNoNeed.begin();
iter != abNoNeed.end() ;++iter)
{
if (*iter)
{
delete *ppcSrc;
--pMesh->mNumBones;
}
else *ppcCur++ = *ppcSrc;
++ppcSrc;
}
}
}
}
+4 -2
View File
@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BaseProcess.h"
struct aiMesh;
class LimitBoneWeightsTest;
namespace Assimp
{
@@ -53,8 +54,8 @@ namespace Assimp
// corresponding values in all Assimp ports
// **********************************************************
// Java: PostProcessStep.java,
// PostProcessStep.DEFAULT_BONE_WEIGHT_LIMIT
// Java: ConfigProperty.java,
// ConfigProperty.DEFAULT_BONE_WEIGHT_LIMIT
// **********************************************************
#if (!defined AI_LMW_MAX_WEIGHTS)
@@ -71,6 +72,7 @@ namespace Assimp
class LimitBoneWeightsProcess : public BaseProcess
{
friend class Importer;
friend class ::LimitBoneWeightsTest;
protected:
/** Constructor to be privately used by Importer */
+15 -20
View File
@@ -57,15 +57,14 @@ void CommentRemover::RemoveLineComments(const char* szComment,
// validate parameters
ai_assert(NULL != szComment && NULL != szBuffer && *szComment);
const size_t len = ::strlen(szComment);
while (*szBuffer)
{
if (*szBuffer == *szComment)
if (0 == ::strncmp(szBuffer,szComment,len))
{
if (0 == ::strcmp(szBuffer+1,szComment+1))
{
while (*szBuffer != '\r' && *szBuffer != '\n' && *szBuffer)
*szBuffer++ = chReplacement;
}
while (*szBuffer != '\r' && *szBuffer != '\n' && *szBuffer)
*szBuffer++ = chReplacement;
}
++szBuffer;
}
@@ -80,28 +79,24 @@ void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
NULL != szBuffer && '\0' != *szCommentStart && '\0' != *szCommentEnd);
const size_t len = ::strlen(szCommentEnd);
const size_t len2 = ::strlen(szCommentStart);
while (*szBuffer)
{
if (*szBuffer == *szCommentStart)
if (0 == ::strncmp(szBuffer,szCommentStart,len2))
{
if (0 == ::strcmp(szBuffer+1,szCommentStart+1))
while (*szBuffer)
{
while (*szBuffer)
if (0 == ::strncmp(szBuffer,szCommentEnd,len))
{
if (*szBuffer == *szCommentEnd)
{
if (0 == ::strcmp(szBuffer+1,szCommentEnd+1))
{
for (unsigned int i = 0; i < len;++i)
*szBuffer++ = chReplacement;
goto __continue_outer; // WUHHHAAAAHHAA!
}
}
*szBuffer++ = chReplacement;
for (unsigned int i = 0; i < len;++i)
*szBuffer++ = chReplacement;
goto __continue_outer; // WUHHHAAAAHHAA!
}
return;
*szBuffer++ = chReplacement;
}
return;
}
++szBuffer;
__continue_outer:
+3 -2
View File
@@ -94,15 +94,16 @@ void TriangulateProcess::Execute( aiScene* pScene)
bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
{
// check whether we will need to do something ...
bool bNeed = false;
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
{
const aiFace& face = pMesh->mFaces[a];
if( face.mNumIndices != 3)
{
break;
bNeed = true;
}
return false;
}
if (!bNeed)return false;
std::vector<aiFace> newFaces;
newFaces.reserve( pMesh->mNumFaces*2);
+136
View File
@@ -0,0 +1,136 @@
/*
---------------------------------------------------------------------------
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 VertexTriangleAdjacency helper class
*/
// public ASSIMP headers
#include "../include/DefaultLogger.h"
#include "../include/aiMesh.h"
// internal headers
#include "VertexTriangleAdjacency.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
unsigned int iNumFaces,
unsigned int iNumVertices /*= 0*/,
bool bComputeNumTriangles /*= false*/)
{
// compute the number of referenced vertices if it wasn't specified by the caller
const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
if (!iNumVertices)
{
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
{
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[2]);
}
}
unsigned int* pi;
// allocate storage
if (bComputeNumTriangles)
{
pi = this->mLiveTriangles = new unsigned int[iNumVertices+1];
::memset(this->mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
this->mOffsetTable = new unsigned int[iNumVertices+2]+1;
}
else
{
pi = this->mOffsetTable = new unsigned int[iNumVertices+2]+1;
::memset(this->mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
this->mLiveTriangles = NULL; // important, otherwise the d'tor would crash
}
// get a pointer to the end of the buffer
unsigned int* piEnd = pi+iNumVertices;
*piEnd++ = 0u;
// first pass: compute the number of faces referencing each vertex
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
{
pi[pcFace->mIndices[0]]++;
pi[pcFace->mIndices[1]]++;
pi[pcFace->mIndices[2]]++;
}
// second pass: compute the final offset table
unsigned int iSum = 0;
unsigned int* piCurOut = this->mOffsetTable;
for (unsigned int* piCur = pi; piCur != piEnd;++piCur,++piCurOut)
{
unsigned int iLastSum = iSum;
iSum += *piCur;
*piCurOut = iLastSum;
}
pi = this->mOffsetTable;
// third pass: compute the final table
this->mAdjacencyTable = new unsigned int[iSum];
iSum = 0;
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace,++iSum)
{
unsigned int idx = pcFace->mIndices[0];
this->mAdjacencyTable[pi[idx]++] = iSum;
idx = pcFace->mIndices[1];
this->mAdjacencyTable[pi[idx]++] = iSum;
idx = pcFace->mIndices[2];
this->mAdjacencyTable[pi[idx]++] = iSum;
}
// fourth pass: undo the offset computations made during the third pass
// We could do this in a separate buffer, but this would be TIMES slower.
--this->mOffsetTable;
*this->mOffsetTable = 0u;
}
// ------------------------------------------------------------------------------------------------
VertexTriangleAdjacency::~VertexTriangleAdjacency()
{
// delete all allocated storage
delete[] this->mOffsetTable;
delete[] this->mAdjacencyTable;
delete[] this->mLiveTriangles;
}
+126
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 Defines a helper class to compute a vertex-triangle adjacency map */
#ifndef AI_VTADJACENCY_H_INC
#define AI_VTADJACENCY_H_INC
#include "BaseProcess.h"
#include "../include/aiTypes.h"
#include "../include/aiAssert.h"
struct aiMesh;
namespace Assimp
{
// ---------------------------------------------------------------------------
/** The VertexTriangleAdjacency class computes a vertex-triangle
* adjacency map from a given index buffer.
*
* @note The input data is expected to be triangulated.
*/
class VertexTriangleAdjacency
{
public:
/** Construction from an existing index buffer
* @param pcFaces Index buffer
* @param iNumFaces Number of faces in the buffer
* @param iNumVertices Number of referenced vertices. This value
* is computed automatically if 0 is specified.
* @param bComputeNumTriangles If you want the class to compute
* a list which contains the number of referenced triangles
* per vertex - pass true.
*/
VertexTriangleAdjacency(aiFace* pcFaces,unsigned int iNumFaces,
unsigned int iNumVertices = 0,
bool bComputeNumTriangles = true);
/** Destructor
*/
~VertexTriangleAdjacency();
/** Get all triangles adjacent to a vertex
* @param iVertIndex Index of the vertex
* @return A pointer to the adjacency list
*/
inline unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const
{
ai_assert(iVertIndex < iNumVertices);
const unsigned int ofs = mOffsetTable[iVertIndex];
return &mAdjacencyTable[ofs];
}
/** Get the number of triangles that are referenced by
* a vertex. This function returns a reference that can be modified
* @param iVertIndex Index of the vertex
* @return Number of referenced triangles
*/
inline unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex)
{
ai_assert(iVertIndex < iNumVertices && NULL != mLiveTriangles);
return mLiveTriangles[iVertIndex];
}
public:
//! Offset table
unsigned int* mOffsetTable;
//! Adjacency table
unsigned int* mAdjacencyTable;
//! Table containing the number of referenced triangles per vertex
unsigned int* mLiveTriangles;
//! Debug: Number of referenced vertices
unsigned int iNumVertices;
};
}
#endif // !! AI_VTADJACENCY_H_INC