Removed OptimizeGraph step - actually it isn't really useful, although I got it working very well.
Updated credits. VC9 workspace updated by hand (no vc9 ...) so be careful. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@300 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
6557c28ef7
commit
462bb953c2
3
CREDITS
3
CREDITS
|
@ -55,3 +55,6 @@ supplied patches for linux and SCons.
|
||||||
|
|
||||||
- T. R.
|
- T. R.
|
||||||
The GUY who performed some of the CSM mocaps.
|
The GUY who performed some of the CSM mocaps.
|
||||||
|
|
||||||
|
- Andy Maloney
|
||||||
|
Contributed fixes for the documentation and the doxygen markup
|
||||||
|
|
|
@ -181,9 +181,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS
|
#ifndef AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS
|
||||||
# include "RemoveRedundantMaterials.h"
|
# include "RemoveRedundantMaterials.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS
|
|
||||||
# include "OptimizeGraphProcess.h"
|
|
||||||
#endif
|
|
||||||
#ifndef AI_BUILD_NO_FINDINVALIDDATA_PROCESS
|
#ifndef AI_BUILD_NO_FINDINVALIDDATA_PROCESS
|
||||||
# include "FindInvalidDataProcess.h"
|
# include "FindInvalidDataProcess.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -376,10 +373,6 @@ Importer::Importer()
|
||||||
mPostProcessingSteps.push_back( new FindInvalidDataProcess());
|
mPostProcessingSteps.push_back( new FindInvalidDataProcess());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
|
|
||||||
mPostProcessingSteps.push_back( new OptimizeGraphProcess());
|
|
||||||
#endif
|
|
||||||
#if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
|
#if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
|
||||||
mPostProcessingSteps.push_back( new FixInfacingNormalsProcess());
|
mPostProcessingSteps.push_back( new FixInfacingNormalsProcess());
|
||||||
#endif
|
#endif
|
||||||
|
@ -564,15 +557,6 @@ bool ValidateFlags(unsigned int pFlags)
|
||||||
"aiProcess_GenNormals may not be specified together");
|
"aiProcess_GenNormals may not be specified together");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pFlags & aiProcess_PreTransformVertices &&
|
|
||||||
pFlags & aiProcess_OptimizeGraph)
|
|
||||||
{
|
|
||||||
DefaultLogger::get()->error("aiProcess_PreTransformVertives and "
|
|
||||||
"aiProcess_OptimizeGraph may not be specified together");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif // ! DEBUG
|
#endif // ! DEBUG
|
||||||
|
|
|
@ -1,636 +0,0 @@
|
||||||
/*
|
|
||||||
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.
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Implementation of the OptimizeGraphProcess post-processing step*/
|
|
||||||
|
|
||||||
#include "AssimpPCH.h"
|
|
||||||
|
|
||||||
#include "OptimizeGraphProcess.h"
|
|
||||||
#include "Hash.h"
|
|
||||||
|
|
||||||
|
|
||||||
using namespace Assimp;
|
|
||||||
|
|
||||||
// MSB for type unsigned int
|
|
||||||
#define AI_OG_UINT_MSB (1u<<((sizeof(unsigned int)*8u)-1u))
|
|
||||||
#define AI_OG_UINT_MSB_2 (AI_OG_UINT_MSB>>1)
|
|
||||||
|
|
||||||
// check whether a node/a mesh is locked
|
|
||||||
#define AI_OG_IS_NODE_LOCKED(nd) (nd->mNumChildren & AI_OG_UINT_MSB)
|
|
||||||
#define AI_OG_IS_MESH_LOCKED(ms) (ms->mNumBones & AI_OG_UINT_MSB)
|
|
||||||
|
|
||||||
// check whether a node has locked meshes in its list
|
|
||||||
#define AI_OG_HAS_NODE_LOCKED_MESHES(nd) (nd->mNumChildren & AI_OG_UINT_MSB_2)
|
|
||||||
|
|
||||||
// unmask the two upper bits of an unsigned int
|
|
||||||
#define AI_OG_UNMASK(p) (p & (~(AI_OG_UINT_MSB|AI_OG_UINT_MSB_2)))
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Constructor to be privately used by Importer
|
|
||||||
OptimizeGraphProcess::OptimizeGraphProcess()
|
|
||||||
{
|
|
||||||
configMinNumFaces = AI_OG_MIN_NUM_FACES;
|
|
||||||
configJoinInequalTransforms = AI_OG_JOIN_INEQUAL_TRANSFORMS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Destructor, private as well
|
|
||||||
OptimizeGraphProcess::~OptimizeGraphProcess()
|
|
||||||
{
|
|
||||||
// nothing to do here
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Returns whether the processing step is present in the given flag field.
|
|
||||||
bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const
|
|
||||||
{
|
|
||||||
return (pFlags & aiProcess_OptimizeGraph) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Setup properties of the step
|
|
||||||
void OptimizeGraphProcess::SetupProperties(const Importer* pImp)
|
|
||||||
{
|
|
||||||
// join nods with inequal transformations?
|
|
||||||
configJoinInequalTransforms = pImp->GetPropertyInteger(AI_CONFIG_PP_OG_JOIN_INEQUAL_TRANSFORMS,
|
|
||||||
AI_OG_JOIN_INEQUAL_TRANSFORMS) != 0 ? true : false;
|
|
||||||
|
|
||||||
// minimum face number per node
|
|
||||||
configMinNumFaces = pImp->GetPropertyInteger(AI_CONFIG_PP_OG_MIN_NUM_FACES,
|
|
||||||
AI_OG_MIN_NUM_FACES);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::FindLockedNodes(aiNode* node)
|
|
||||||
{
|
|
||||||
ai_assert(NULL != node);
|
|
||||||
|
|
||||||
// process animations
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
|
|
||||||
{
|
|
||||||
aiAnimation* pani = pScene->mAnimations[i];
|
|
||||||
for (unsigned int a = 0; a < pani->mNumChannels;++a)
|
|
||||||
{
|
|
||||||
aiNodeAnim* pba = pani->mChannels[a];
|
|
||||||
if (pba->mNodeName == node->mName)
|
|
||||||
{
|
|
||||||
// this node is locked, it is referenced by an animation channel
|
|
||||||
node->mNumChildren |= AI_OG_UINT_MSB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process cameras
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumCameras;++i)
|
|
||||||
{
|
|
||||||
aiCamera* p = pScene->mCameras[i];
|
|
||||||
if (p->mName == node->mName)
|
|
||||||
{
|
|
||||||
// this node is locked, it is referenced by a camera
|
|
||||||
node->mNumChildren |= AI_OG_UINT_MSB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process lights
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumLights;++i)
|
|
||||||
{
|
|
||||||
aiLight* p = pScene->mLights[i];
|
|
||||||
if (p->mName == node->mName)
|
|
||||||
{
|
|
||||||
// this node is locked, it is referenced by a light
|
|
||||||
node->mNumChildren |= AI_OG_UINT_MSB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// call all children
|
|
||||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
|
||||||
FindLockedNodes(node->mChildren[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::FindLockedMeshes(aiNode* node, MeshRefCount* pRefCount)
|
|
||||||
{
|
|
||||||
ai_assert(NULL != node && NULL != pRefCount);
|
|
||||||
for (unsigned int i = 0;i < node->mNumMeshes;++i)
|
|
||||||
{
|
|
||||||
unsigned int m = node->mMeshes[i];
|
|
||||||
if (pRefCount[m].first)
|
|
||||||
{
|
|
||||||
// we have already one reference - lock the first node
|
|
||||||
// that had a referenced to this mesh too if it has only
|
|
||||||
// one mesh assigned. If there are multiple meshes,
|
|
||||||
// the others could still be used for optimizations.
|
|
||||||
if (pRefCount[m].second)
|
|
||||||
{
|
|
||||||
pRefCount[m].second->mNumChildren |= (pRefCount[m].second->mNumMeshes <= 1
|
|
||||||
? AI_OG_UINT_MSB : AI_OG_UINT_MSB_2);
|
|
||||||
|
|
||||||
pRefCount[m].second = NULL;
|
|
||||||
}
|
|
||||||
pScene->mMeshes[m]->mNumBones |= AI_OG_UINT_MSB;
|
|
||||||
|
|
||||||
// lock this node
|
|
||||||
node->mNumChildren |= (node->mNumMeshes <= 1
|
|
||||||
? AI_OG_UINT_MSB : AI_OG_UINT_MSB_2);
|
|
||||||
}
|
|
||||||
else pRefCount[m].second = node;
|
|
||||||
++pRefCount[m].first;
|
|
||||||
}
|
|
||||||
// call all children
|
|
||||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
|
||||||
FindLockedMeshes(node->mChildren[i],pRefCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::FindLockedMeshes(aiNode* node)
|
|
||||||
{
|
|
||||||
ai_assert(NULL != node);
|
|
||||||
MeshRefCount* pRefCount = new MeshRefCount[pScene->mNumMeshes];
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
|
||||||
pRefCount[i] = MeshRefCount();
|
|
||||||
|
|
||||||
// execute the algorithm
|
|
||||||
FindLockedMeshes(node,pRefCount);
|
|
||||||
|
|
||||||
delete[] pRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::UnlockNodes(aiNode* node)
|
|
||||||
{
|
|
||||||
ai_assert(NULL != node);
|
|
||||||
node->mNumChildren &= ~(AI_OG_UINT_MSB|AI_OG_UINT_MSB_2);
|
|
||||||
|
|
||||||
// call all children
|
|
||||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
|
||||||
UnlockNodes(node->mChildren[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::UnlockMeshes()
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
|
||||||
pScene->mMeshes[i]->mNumBones &= ~AI_OG_UINT_MSB;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::ComputeMeshHashes()
|
|
||||||
{
|
|
||||||
mMeshHashes.resize(pScene->mNumMeshes);
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
|
||||||
{
|
|
||||||
unsigned int iRet = 0;
|
|
||||||
aiMesh* pcMesh = pScene->mMeshes[i];
|
|
||||||
|
|
||||||
// normals
|
|
||||||
if (pcMesh->HasNormals())iRet |= 0x1;
|
|
||||||
// tangents and bitangents
|
|
||||||
if (pcMesh->HasTangentsAndBitangents())iRet |= 0x2;
|
|
||||||
|
|
||||||
// texture coordinates
|
|
||||||
unsigned int p = 0;
|
|
||||||
ai_assert(4 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
|
|
||||||
while (pcMesh->HasTextureCoords(p))
|
|
||||||
{
|
|
||||||
iRet |= (0x100 << p++);
|
|
||||||
|
|
||||||
// NOTE: meshes with numUVComp != 3 && != 2 aren't handled correctly here
|
|
||||||
ai_assert(pcMesh->mNumUVComponents[p] == 3 || pcMesh->mNumUVComponents[p] == 2);
|
|
||||||
if (3 == pcMesh->mNumUVComponents[p])
|
|
||||||
iRet |= (0x1000 << p++);
|
|
||||||
}
|
|
||||||
// vertex colors
|
|
||||||
p = 0;
|
|
||||||
ai_assert(4 >= AI_MAX_NUMBER_OF_COLOR_SETS);
|
|
||||||
while (pcMesh->HasVertexColors(p))iRet |= (0x10000 << p++);
|
|
||||||
mMeshHashes[i] = iRet;
|
|
||||||
|
|
||||||
// material index -store it in the upper 1 1/2 bytes, so
|
|
||||||
// are able to encode 2^12 material indices.
|
|
||||||
|
|
||||||
iRet |= (pcMesh->mMaterialIndex << 20u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
inline unsigned int OptimizeGraphProcess::BinarySearch(NodeIndexList& sortedArray,
|
|
||||||
unsigned int min, unsigned int& index, unsigned int iStart)
|
|
||||||
{
|
|
||||||
unsigned int first = iStart,last = (unsigned int)sortedArray.size()-1;
|
|
||||||
while (first <= last)
|
|
||||||
{
|
|
||||||
unsigned int mid = (first + last) / 2;
|
|
||||||
unsigned int id = sortedArray[mid].second;
|
|
||||||
|
|
||||||
if (min > id)
|
|
||||||
first = mid + 1;
|
|
||||||
else if (min <= id)
|
|
||||||
{
|
|
||||||
last = mid - 1;
|
|
||||||
if (!mid || min > sortedArray[last].second)
|
|
||||||
{
|
|
||||||
index = sortedArray[last].first;
|
|
||||||
return mid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (unsigned int)sortedArray.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::ApplyNodeMeshesOptimization(aiNode* pNode)
|
|
||||||
{
|
|
||||||
ai_assert(NULL != pNode);
|
|
||||||
|
|
||||||
// find all meshes which are compatible and could therefore be joined.
|
|
||||||
// we can't join meshes that are locked
|
|
||||||
std::vector<aiMesh*> apcMeshes(pNode->mNumMeshes);
|
|
||||||
unsigned int iNumMeshes;
|
|
||||||
|
|
||||||
for (unsigned int m = 0, ttt = 0; m < pNode->mNumMeshes;++m)
|
|
||||||
{
|
|
||||||
iNumMeshes = 0;
|
|
||||||
|
|
||||||
unsigned int nm = pNode->mMeshes[m];
|
|
||||||
if (0xffffffff == nm || AI_OG_IS_MESH_LOCKED(pScene->mMeshes[nm]))continue;
|
|
||||||
|
|
||||||
for (unsigned int q = m+1; q < pNode->mNumMeshes;++q)
|
|
||||||
{
|
|
||||||
register unsigned int nq = pNode->mMeshes[q];
|
|
||||||
|
|
||||||
// skip locked meshes
|
|
||||||
if (AI_OG_IS_MESH_LOCKED(pScene->mMeshes[nq]))continue;
|
|
||||||
|
|
||||||
// compare the mesh hashes
|
|
||||||
if (mMeshHashes[nm] == mMeshHashes[nq])
|
|
||||||
{
|
|
||||||
apcMeshes[iNumMeshes++] = pScene->mMeshes[nq];
|
|
||||||
pNode->mMeshes[q] = 0xffffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
aiMesh* out;
|
|
||||||
if (iNumMeshes > 0)
|
|
||||||
{
|
|
||||||
apcMeshes[iNumMeshes++] = pScene->mMeshes[nm];
|
|
||||||
// JoinMeshes(apcMeshes,out,iNumMeshes);
|
|
||||||
}
|
|
||||||
else out = pScene->mMeshes[nm];
|
|
||||||
|
|
||||||
pNode->mMeshes[ttt++] = (unsigned int)mOutputMeshes.size();
|
|
||||||
mOutputMeshes.push_back(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::TransformMeshes(aiNode* quak,aiNode* pNode)
|
|
||||||
{
|
|
||||||
for (unsigned int pl = 0; pl < quak->mNumMeshes;++pl)
|
|
||||||
{
|
|
||||||
aiMesh* mariusIsHot = pScene->mMeshes[quak->mMeshes[pl]];
|
|
||||||
aiMatrix4x4 mMatTransform = pNode->mTransformation;
|
|
||||||
|
|
||||||
// transformation: first back to the parent's local space,
|
|
||||||
// later into the local space of the destination child node
|
|
||||||
mMatTransform.Inverse();
|
|
||||||
mMatTransform = quak->mTransformation * mMatTransform;
|
|
||||||
|
|
||||||
// transform all vertices
|
|
||||||
for (unsigned int oo =0; oo < mariusIsHot->mNumVertices;++oo)
|
|
||||||
mariusIsHot->mVertices[oo] = mMatTransform * mariusIsHot->mVertices[oo];
|
|
||||||
|
|
||||||
// transform all normal vectors
|
|
||||||
if (mariusIsHot->HasNormals())
|
|
||||||
{
|
|
||||||
mMatTransform.Inverse().Transpose();
|
|
||||||
for (unsigned int oo =0; oo < mariusIsHot->mNumVertices;++oo)
|
|
||||||
mariusIsHot->mNormals[oo] = mMatTransform * mariusIsHot->mNormals[oo];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::ApplyOptimizations(aiNode* node)
|
|
||||||
{
|
|
||||||
ai_assert(NULL != node);
|
|
||||||
|
|
||||||
unsigned int iJoinedIndex = 0;
|
|
||||||
|
|
||||||
// first: node index; second: number of faces in node
|
|
||||||
NodeIndexList aiBelowTreshold;
|
|
||||||
aiBelowTreshold.reserve(node->mNumChildren);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
|
||||||
{
|
|
||||||
aiNode* pChild = node->mChildren[i];
|
|
||||||
if (AI_OG_IS_NODE_LOCKED(pChild) || !pChild->mNumMeshes)continue;
|
|
||||||
|
|
||||||
// find out how many faces this node is referencing
|
|
||||||
unsigned int iFaceCnt = 0;
|
|
||||||
for (unsigned int a = 0; a < pChild->mNumMeshes;++a)
|
|
||||||
iFaceCnt += pScene->mMeshes[pChild->mMeshes[a]]->mNumFaces;
|
|
||||||
|
|
||||||
// are we below the treshold?
|
|
||||||
if (iFaceCnt < configMinNumFaces)
|
|
||||||
{
|
|
||||||
aiBelowTreshold.push_back(NodeIndexEntry());
|
|
||||||
NodeIndexEntry& p = aiBelowTreshold.back();
|
|
||||||
p.first = i;
|
|
||||||
p.second = iFaceCnt;
|
|
||||||
p.pNode = pChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aiBelowTreshold.empty())
|
|
||||||
{
|
|
||||||
// some typedefs for the data structures we'll need
|
|
||||||
typedef std::pair<unsigned int, unsigned int> JoinListEntry;
|
|
||||||
std::vector<JoinListEntry> aiJoinList(aiBelowTreshold.size());
|
|
||||||
std::vector<unsigned int> aiTempList(aiBelowTreshold.size());
|
|
||||||
|
|
||||||
unsigned int iNumJoins, iNumTemp;
|
|
||||||
|
|
||||||
// sort the list by size
|
|
||||||
std::sort(aiBelowTreshold.begin(),aiBelowTreshold.end());
|
|
||||||
|
|
||||||
unsigned int iStart = 0;
|
|
||||||
for (NodeIndexList::const_iterator it = aiBelowTreshold.begin(),end = aiBelowTreshold.end();
|
|
||||||
it != end; /*++it */++iStart)
|
|
||||||
{
|
|
||||||
aiNode* pNode = node->mChildren[(*it).first];
|
|
||||||
|
|
||||||
// get the hash of the mesh
|
|
||||||
const unsigned int iMeshVFormat = mMeshHashes[pNode->mMeshes[0]];
|
|
||||||
|
|
||||||
// we search for a node with more faces than this ... find
|
|
||||||
// the one that fits best and continue until we've reached
|
|
||||||
// treshold size.
|
|
||||||
int iDiff = configMinNumFaces-(*it).second;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
// do a binary search and start the iteration there
|
|
||||||
unsigned int index;
|
|
||||||
unsigned int start = BinarySearch(aiBelowTreshold,iDiff,index,iStart);
|
|
||||||
|
|
||||||
if (index == (*it).first)start++;
|
|
||||||
|
|
||||||
if (start >= aiBelowTreshold.size())
|
|
||||||
{
|
|
||||||
// there is no node with enough faces. take the first
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: implement algorithm to find the best possible combination ...
|
|
||||||
iNumTemp = 0;
|
|
||||||
|
|
||||||
while( start < aiBelowTreshold.size())
|
|
||||||
{
|
|
||||||
// check whether the node has akready been processed before
|
|
||||||
const NodeIndexEntry& entry = aiBelowTreshold[start];
|
|
||||||
if (!entry.pNode)continue;
|
|
||||||
|
|
||||||
const aiNode* pip = node->mChildren[entry.first];
|
|
||||||
if (configJoinInequalTransforms )
|
|
||||||
{
|
|
||||||
// we need to check whether this node has locked meshes
|
|
||||||
// in this case we can't add it here - the meshes will
|
|
||||||
// be transformed from one to another coordinate space
|
|
||||||
|
|
||||||
if (!AI_OG_HAS_NODE_LOCKED_MESHES(pip) || pip->mTransformation == pNode->mTransformation)
|
|
||||||
aiTempList[iNumTemp++] = start;
|
|
||||||
}
|
|
||||||
else if (node->mChildren[entry.first]->mTransformation == pNode->mTransformation)
|
|
||||||
{
|
|
||||||
aiTempList[iNumTemp++] = start;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iNumTemp)
|
|
||||||
{
|
|
||||||
// search for a node which has a mesh with
|
|
||||||
// - the same material index
|
|
||||||
// - the same vertex layout
|
|
||||||
unsigned int d = iNumJoins = 0;
|
|
||||||
for (unsigned int m = 0; m < iNumTemp;++m)
|
|
||||||
{
|
|
||||||
register unsigned int mn = aiTempList[m];
|
|
||||||
aiNode* pip = aiBelowTreshold[mn].pNode;
|
|
||||||
|
|
||||||
for (unsigned int tt = 0; tt < pip->mNumMeshes;++tt)
|
|
||||||
{
|
|
||||||
register unsigned int mm = pip->mMeshes[tt];
|
|
||||||
|
|
||||||
if (mMeshHashes [ mm ] == iMeshVFormat)
|
|
||||||
{
|
|
||||||
d = mn;
|
|
||||||
goto break_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break_out:
|
|
||||||
aiJoinList[iNumJoins++] = JoinListEntry( aiBelowTreshold[d].first, d );
|
|
||||||
iDiff -= aiBelowTreshold[d].second;
|
|
||||||
}
|
|
||||||
// did we reach the target treshold?
|
|
||||||
if (iDiff <= 0)break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// did we found any nodes to be joined with *this* one?
|
|
||||||
if (iNumJoins)
|
|
||||||
{
|
|
||||||
unsigned int iNumTotalChilds = pNode->mNumChildren;
|
|
||||||
unsigned int iNumTotalMeshes = pNode->mNumMeshes;
|
|
||||||
std::vector<JoinListEntry>::const_iterator wend = aiJoinList.begin()+iNumJoins;
|
|
||||||
|
|
||||||
// get output array bounds
|
|
||||||
for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
|
|
||||||
wit != wend;++wit )
|
|
||||||
{
|
|
||||||
aiNode*& quak = node->mChildren[(*wit).first];
|
|
||||||
iNumTotalChilds += AI_OG_UNMASK( quak->mNumChildren );
|
|
||||||
iNumTotalMeshes += quak->mNumMeshes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build the output child list
|
|
||||||
if (iNumTotalChilds != pNode->mNumChildren)
|
|
||||||
{
|
|
||||||
aiNode** ppc = pNode->mChildren;
|
|
||||||
delete[] pNode->mChildren;
|
|
||||||
pNode->mChildren = new aiNode*[iNumTotalChilds];
|
|
||||||
::memcpy(pNode->mChildren,ppc, sizeof(void*)* AI_OG_UNMASK( pNode->mNumChildren ));
|
|
||||||
|
|
||||||
for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
|
|
||||||
wit != wend;++wit )
|
|
||||||
{
|
|
||||||
aiNode*& quak = node->mChildren[(*wit).first];
|
|
||||||
::memcpy(pNode->mChildren+pNode->mNumChildren,
|
|
||||||
quak->mChildren, sizeof(void*)*quak->mNumChildren);
|
|
||||||
|
|
||||||
pNode->mNumChildren += AI_OG_UNMASK( quak->mNumChildren );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// build the output mesh list
|
|
||||||
unsigned int* ppc = pNode->mMeshes;
|
|
||||||
delete[] pNode->mMeshes;
|
|
||||||
pNode->mMeshes = new unsigned int[iNumTotalMeshes];
|
|
||||||
::memcpy(pNode->mMeshes,ppc, sizeof(void*)*pNode->mNumMeshes);
|
|
||||||
|
|
||||||
for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
|
|
||||||
wit != wend;++wit )
|
|
||||||
{
|
|
||||||
aiNode*& quak = node->mChildren[(*wit).first];
|
|
||||||
::memcpy(pNode->mMeshes+pNode->mNumMeshes,
|
|
||||||
quak->mMeshes, sizeof(unsigned int)*quak->mNumMeshes);
|
|
||||||
|
|
||||||
// if the node has a transformation matrix that is not equal to ours,
|
|
||||||
// we'll need to transform all vertices of the mesh into our
|
|
||||||
// local coordinate space.
|
|
||||||
if (configJoinInequalTransforms && quak->mTransformation != pNode->mTransformation)
|
|
||||||
TransformMeshes(quak,pNode);
|
|
||||||
|
|
||||||
pNode->mNumMeshes += quak->mNumMeshes;
|
|
||||||
|
|
||||||
// remove the joined nodes from all lists.
|
|
||||||
aiBelowTreshold[(*wit).second].pNode = NULL;
|
|
||||||
if ((*wit).second == iStart+1)++iStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now generate an output name for the joined nodes
|
|
||||||
if (1 == iNumTotalChilds)
|
|
||||||
{
|
|
||||||
pNode->mName.length = ::sprintf( pNode->mName.data, "<Joined_%i_%i>",
|
|
||||||
iJoinedIndex++,iNumJoins+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now optimize the meshes in this node
|
|
||||||
ApplyNodeMeshesOptimization(pNode);
|
|
||||||
|
|
||||||
// note - this has been optimized away. The search in the binary
|
|
||||||
// list starts with iStart, which is incremented each iteration
|
|
||||||
++it; // = aiBelowTreshold.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// call all children recursively
|
|
||||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
|
||||||
ApplyOptimizations(node->mChildren[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void OptimizeGraphProcess::BuildOutputMeshList()
|
|
||||||
{
|
|
||||||
// all meshes should have been deleted before if they are
|
|
||||||
// not contained in the new mesh list
|
|
||||||
|
|
||||||
if (pScene->mNumMeshes < mOutputMeshes.size())
|
|
||||||
{
|
|
||||||
delete[] pScene->mMeshes;
|
|
||||||
pScene->mMeshes = new aiMesh*[mOutputMeshes.size()];
|
|
||||||
}
|
|
||||||
pScene->mNumMeshes = (unsigned int)mOutputMeshes.size();
|
|
||||||
::memcpy(pScene->mMeshes,&mOutputMeshes[0],pScene->mNumMeshes*sizeof(void*));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Executes the post processing step on the given imported data.
|
|
||||||
void OptimizeGraphProcess::Execute( aiScene* pScene)
|
|
||||||
{
|
|
||||||
throw new ImportErrorException("This step is disabled in this beta");
|
|
||||||
this->pScene = pScene;
|
|
||||||
/*
|
|
||||||
|
|
||||||
a) the term "mesh node" stands for a node with numMeshes > 0
|
|
||||||
b) the term "animation node" stands for a node with numMeshes == 0,
|
|
||||||
regardless whether the node is referenced by animation channels,
|
|
||||||
lights or cameras
|
|
||||||
|
|
||||||
Algorithm:
|
|
||||||
|
|
||||||
1. Compute hashes for all meshes that we're able to check whether
|
|
||||||
two meshes are compatible.
|
|
||||||
3. Find out which nodes may not be moved, so to speak are "locked" - a
|
|
||||||
locked node will never be joined with neighbors.
|
|
||||||
- A node lock is indicated by a set MSB in the aiNode::mNumChildren member
|
|
||||||
4. Find out which meshes are locked - they are referenced by
|
|
||||||
more than one node. They will never be joined. Mark all
|
|
||||||
nodes referencing such a mesh as "locked", too.
|
|
||||||
- A mesh lock is indicated by a set MSB in the aiMesh::mNumBones member
|
|
||||||
5. For each unlocked node count the face numbers of all assigned meshes
|
|
||||||
- if it is below the pre-defined treshold add the node to a list.
|
|
||||||
For each node in the list - try to find enough joinable nodes to
|
|
||||||
have enough faces all together.
|
|
||||||
Two nodes are joined if:
|
|
||||||
- none of them is locked
|
|
||||||
- (optional) their world matrices are identical
|
|
||||||
- nodes whose meshes share the same material indices are prefered
|
|
||||||
Two meshes in one node are joined if:
|
|
||||||
- their material indices are identical
|
|
||||||
- none of them is locked
|
|
||||||
- they share the same vertex format
|
|
||||||
6. Build the final mesh list
|
|
||||||
7. For all meshes and all nodes - remove locks.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
throw new ImportErrorException("OG step is still undeer development and not yet finished");
|
|
||||||
|
|
||||||
// STEP 1
|
|
||||||
ComputeMeshHashes();
|
|
||||||
|
|
||||||
// STEP 2
|
|
||||||
FindLockedNodes(pScene->mRootNode);
|
|
||||||
|
|
||||||
// STEP 3
|
|
||||||
FindLockedMeshes(pScene->mRootNode);
|
|
||||||
|
|
||||||
// STEP 4
|
|
||||||
ApplyOptimizations(pScene->mRootNode);
|
|
||||||
|
|
||||||
// STEP 5
|
|
||||||
BuildOutputMeshList();
|
|
||||||
|
|
||||||
// STEP 6
|
|
||||||
UnlockNodes(pScene->mRootNode);
|
|
||||||
UnlockMeshes();
|
|
||||||
}
|
|
|
@ -1,275 +0,0 @@
|
||||||
/*
|
|
||||||
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.
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Defines a post processing step to refactor the output node graph to
|
|
||||||
be more compact */
|
|
||||||
#ifndef AI_OPTIMIZEGRAPHPROCESS_H_INC
|
|
||||||
#define AI_OPTIMIZEGRAPHPROCESS_H_INC
|
|
||||||
|
|
||||||
#include "BaseProcess.h"
|
|
||||||
|
|
||||||
struct aiMesh;
|
|
||||||
struct aiNode;
|
|
||||||
struct aiBone;
|
|
||||||
class OptimizeGraphProcessTest;
|
|
||||||
|
|
||||||
namespace Assimp {
|
|
||||||
|
|
||||||
// NOTE: If you change these limits, don't forget to change the
|
|
||||||
// corresponding values in all Assimp ports
|
|
||||||
|
|
||||||
// **********************************************************
|
|
||||||
// Java: ConfigProperty.java,
|
|
||||||
// ConfigProperty.OG_MIN_NUM_FACES
|
|
||||||
// ConfigProperty.JOIN_INEQUAL_TRANSFORMS
|
|
||||||
// **********************************************************
|
|
||||||
|
|
||||||
#if (!defined AI_OG_MAX_DEPTH)
|
|
||||||
# define AI_OG_MAX_DEPTH 0x4
|
|
||||||
#endif // !! AI_LMW_MAX_WEIGHTS
|
|
||||||
|
|
||||||
#if (!defined AI_OG_MIN_NUM_FACES)
|
|
||||||
# define AI_OG_MIN_NUM_FACES 0xffffffff
|
|
||||||
#endif // !! AI_LMW_MAX_WEIGHTS
|
|
||||||
|
|
||||||
#if (!defined AI_OG_JOIN_INEQUAL_TRANSFORMS)
|
|
||||||
# define AI_OG_JOIN_INEQUAL_TRANSFORMS false
|
|
||||||
#endif // !! AI_LMW_MAX_WEIGHTS
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
struct NodeIndexEntry : public std::pair<unsigned int, unsigned int>
|
|
||||||
{
|
|
||||||
// binary operator < for use with std::sort
|
|
||||||
bool operator< (const NodeIndexEntry& other)
|
|
||||||
{
|
|
||||||
return second < other.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pointer to the original node
|
|
||||||
aiNode* pNode;
|
|
||||||
};
|
|
||||||
typedef std::vector<NodeIndexEntry> NodeIndexList;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
/** This post processing step reformats the output node graph to be more
|
|
||||||
* compact. There are several options, e.g. maximum hierachy depth or
|
|
||||||
* minimum mesh size. Some files store every face as a new mesh, so
|
|
||||||
* some Assimp steps (such as FixInfacingNormals or SmoothNormals) don't
|
|
||||||
* work properly on these meshes. This step joins such small meshes and
|
|
||||||
* nodes. Animations are kept during the step.
|
|
||||||
* @note Use the PretransformVertices step to remove the node graph
|
|
||||||
* completely (and all animations, too).
|
|
||||||
*/
|
|
||||||
class ASSIMP_API OptimizeGraphProcess : public BaseProcess
|
|
||||||
{
|
|
||||||
friend class Importer;
|
|
||||||
friend class ::OptimizeGraphProcessTest;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** Constructor to be privately used by Importer */
|
|
||||||
OptimizeGraphProcess();
|
|
||||||
|
|
||||||
/** Destructor, private as well */
|
|
||||||
~OptimizeGraphProcess();
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::pair< unsigned int, aiNode* > MeshRefCount;
|
|
||||||
typedef unsigned int MeshHash;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Returns whether the processing step is present in the given flag.
|
|
||||||
* @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;
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Called prior to ExecuteOnScene().
|
|
||||||
* The function is a request to the process to update its configuration
|
|
||||||
* basing on the Importer's configuration property list.
|
|
||||||
*/
|
|
||||||
void SetupProperties(const Importer* pImp);
|
|
||||||
|
|
||||||
|
|
||||||
// set the configMinNumfaces property
|
|
||||||
inline void SetMinNumFaces(unsigned int n)
|
|
||||||
{
|
|
||||||
configMinNumFaces = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** 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);
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Removes animation nodes from the tree.
|
|
||||||
* @param node Current node
|
|
||||||
* @param out Receives a list of replacement nodes for *this* node -
|
|
||||||
* if *this* node should be kept, it must be added to the list.
|
|
||||||
*/
|
|
||||||
void RemoveAnimationNodes (aiNode* node,std::vector<aiNode*>& out);
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Finds and marks all locked nodes in the tree.
|
|
||||||
* A node is locked if it is referenced by animations.
|
|
||||||
* @param node ROot node to start with
|
|
||||||
* @note A locked node has the MSB set in its mNumChildren member
|
|
||||||
*/
|
|
||||||
void FindLockedNodes(aiNode* node);
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Searches for locked meshes. A mesh is locked if it is referenced
|
|
||||||
* by more than one node in the hierarchy.
|
|
||||||
* @param node Root node to start with
|
|
||||||
*/
|
|
||||||
void FindLockedMeshes(aiNode* node);
|
|
||||||
void FindLockedMeshes(aiNode* node, MeshRefCount* pRefCount);
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Unlocks all nodes in the output tree.
|
|
||||||
* @param node Root node to start with
|
|
||||||
*/
|
|
||||||
void UnlockNodes(aiNode* node);
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Unlocks all meshes in the output tree.
|
|
||||||
*/
|
|
||||||
void UnlockMeshes();
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Apply the final optimization algorithm to the tree.
|
|
||||||
* See the Execute-method for a detailled description of the algorithm.
|
|
||||||
* @param node Root node to start with
|
|
||||||
*/
|
|
||||||
void ApplyOptimizations(aiNode* node);
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Binary search for the first element that is >= min.
|
|
||||||
* @param sortedArray Input array
|
|
||||||
* @param min Treshold
|
|
||||||
*/
|
|
||||||
unsigned int BinarySearch(NodeIndexList& sortedArray,
|
|
||||||
unsigned int min, unsigned int& index, unsigned int iStart);
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Compute stable hashes for all meshes and fill mMeshHashes
|
|
||||||
* with the results.
|
|
||||||
*/
|
|
||||||
void ComputeMeshHashes();
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Optimizes the meshes in a single node aftr the joining process.
|
|
||||||
* @param pNode Node to be optimized. Childs noded won't be processed
|
|
||||||
* automatically.
|
|
||||||
*/
|
|
||||||
void ApplyNodeMeshesOptimization(aiNode* pNode);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Build the output mesh list.
|
|
||||||
*/
|
|
||||||
void BuildOutputMeshList();
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** Transform meshes from one coordinate space into another.
|
|
||||||
* @param quak Input space. All meshes referenced by this node -
|
|
||||||
* assuming none of them is locked - are transformed in the
|
|
||||||
* local coordinate space of pNode
|
|
||||||
* @param pNode Destination coordinate space
|
|
||||||
*/
|
|
||||||
void TransformMeshes(aiNode* quak,aiNode* pNode);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/** Configuration option: specifies the minimum number of faces
|
|
||||||
a node should have. The steps tries to join meshes with less
|
|
||||||
vertices that are on the same hierarchy level.
|
|
||||||
If this value is set to a very large value (e.g. 0xffffffff)
|
|
||||||
all meshes on the same hierarchy level are joined - if they
|
|
||||||
aren't animation nodes and if they have the same world matrices
|
|
||||||
*/
|
|
||||||
unsigned int configMinNumFaces;
|
|
||||||
|
|
||||||
|
|
||||||
/** Configuration option: specifies whether nodes with inequal
|
|
||||||
world matrices are joined if they are on the same hierarchy
|
|
||||||
level and if it seems to make sense.
|
|
||||||
*/
|
|
||||||
bool configJoinInequalTransforms;
|
|
||||||
|
|
||||||
/** Working data */
|
|
||||||
aiScene* pScene;
|
|
||||||
|
|
||||||
/** List of hash identifiers for all meshes.
|
|
||||||
The hashes are build from both the meshes vertex format
|
|
||||||
and the material indices. Bones are not taken into account.
|
|
||||||
*/
|
|
||||||
std::vector<MeshHash> mMeshHashes;
|
|
||||||
|
|
||||||
/** List of output meshes.
|
|
||||||
*/
|
|
||||||
std::vector<aiMesh*> mOutputMeshes;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end of namespace Assimp
|
|
||||||
|
|
||||||
#endif // AI_LIMITBONEWEIGHTSPROCESS_H_INC
|
|
|
@ -39,7 +39,6 @@ SOURCES = AssimpPCH.cpp \
|
||||||
ObjFileImporter.cpp \
|
ObjFileImporter.cpp \
|
||||||
ObjFileMtlImporter.cpp \
|
ObjFileMtlImporter.cpp \
|
||||||
ObjFileParser.cpp \
|
ObjFileParser.cpp \
|
||||||
OptimizeGraphProcess.cpp \
|
|
||||||
PlyLoader.cpp \
|
PlyLoader.cpp \
|
||||||
PlyParser.cpp \
|
PlyParser.cpp \
|
||||||
PretransformVertices.cpp \
|
PretransformVertices.cpp \
|
||||||
|
|
|
@ -39,7 +39,6 @@ SOURCES = AssimpPCH.cpp \
|
||||||
ObjFileImporter.cpp \
|
ObjFileImporter.cpp \
|
||||||
ObjFileMtlImporter.cpp \
|
ObjFileMtlImporter.cpp \
|
||||||
ObjFileParser.cpp \
|
ObjFileParser.cpp \
|
||||||
OptimizeGraphProcess.cpp \
|
|
||||||
PlyLoader.cpp \
|
PlyLoader.cpp \
|
||||||
PlyParser.cpp \
|
PlyParser.cpp \
|
||||||
PretransformVertices.cpp \
|
PretransformVertices.cpp \
|
||||||
|
|
|
@ -195,22 +195,6 @@ enum aiPostProcessSteps
|
||||||
*/
|
*/
|
||||||
aiProcess_FixInfacingNormals = 0x2000,
|
aiProcess_FixInfacingNormals = 0x2000,
|
||||||
|
|
||||||
/** This step performs some optimizations on the node graph.
|
|
||||||
*
|
|
||||||
* It is incompatible to the PreTransformVertices-Step. Some configuration
|
|
||||||
* options exist, see aiConfig.h for more details.
|
|
||||||
* Generally, two actions are available:<br>
|
|
||||||
* 1. Remove animation nodes and data from the scene. This allows other
|
|
||||||
* steps for further optimizations.<br>
|
|
||||||
* 2. Combine very small meshes to larger ones. Only if the meshes
|
|
||||||
* are used by the same node or by nodes on the same hierarchy (with
|
|
||||||
* equal local transformations). Unlike PreTransformVertices, the
|
|
||||||
* OptimizeGraph-step doesn't transform vertices from one space
|
|
||||||
* another (at least with the default configuration).<br>
|
|
||||||
*
|
|
||||||
* It is recommended to have this step run with the default configuration.
|
|
||||||
*/
|
|
||||||
aiProcess_OptimizeGraph = 0x4000,
|
|
||||||
|
|
||||||
/** This step splits meshes with more than one primitive type in
|
/** This step splits meshes with more than one primitive type in
|
||||||
* homogeneous submeshes.
|
* homogeneous submeshes.
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
#include "UnitTestPCH.h"
|
|
|
@ -1,35 +0,0 @@
|
||||||
#ifndef TESTOG_H
|
|
||||||
#define TESTOG_H
|
|
||||||
|
|
||||||
#include <cppunit/TestFixture.h>
|
|
||||||
#include <cppunit/extensions/HelperMacros.h>
|
|
||||||
|
|
||||||
#include <aiScene.h>
|
|
||||||
#include <OptimizeGraphProcess.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace Assimp;
|
|
||||||
|
|
||||||
class OptimizeGraphProcessTest : public CPPUNIT_NS :: TestFixture
|
|
||||||
{
|
|
||||||
CPPUNIT_TEST_SUITE (OptimizeGraphProcessTest);
|
|
||||||
CPPUNIT_TEST (testProcess);
|
|
||||||
CPPUNIT_TEST_SUITE_END ();
|
|
||||||
|
|
||||||
public:
|
|
||||||
void setUp (void);
|
|
||||||
void tearDown (void);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void testProcess (void);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
OptimizeGraphProcess* piProcess;
|
|
||||||
aiScene* pcMesh;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1387,14 +1387,6 @@
|
||||||
RelativePath="..\..\test\unit\utMaterialSystem.h"
|
RelativePath="..\..\test\unit\utMaterialSystem.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\test\unit\utOptimizeGraph.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\test\unit\utOptimizeGraph.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\test\unit\utPretransformVertices.cpp"
|
RelativePath="..\..\test\unit\utPretransformVertices.cpp"
|
||||||
>
|
>
|
||||||
|
|
|
@ -2086,14 +2086,6 @@
|
||||||
RelativePath="..\..\code\LimitBoneWeightsProcess.h"
|
RelativePath="..\..\code\LimitBoneWeightsProcess.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\code\OptimizeGraphProcess.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\code\OptimizeGraphProcess.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\PretransformVertices.cpp"
|
RelativePath="..\..\code\PretransformVertices.cpp"
|
||||||
>
|
>
|
||||||
|
|
|
@ -2083,14 +2083,6 @@
|
||||||
RelativePath="..\..\code\LimitBoneWeightsProcess.h"
|
RelativePath="..\..\code\LimitBoneWeightsProcess.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\code\OptimizeGraphProcess.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\code\OptimizeGraphProcess.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\PretransformVertices.cpp"
|
RelativePath="..\..\code\PretransformVertices.cpp"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue