Changed some runtime asserts to boost::static_asserts.

Added FindInstances postprocessing step. Not fully tested yet, but seems to work well. Enabled it for the viewer, too.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@327 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2009-02-02 20:29:27 +00:00
parent 0c6894f6f9
commit 4b4526953e
14 changed files with 529 additions and 70 deletions

View File

@ -108,6 +108,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# include "../include/BoostWorkaround/boost/scoped_array.hpp" # include "../include/BoostWorkaround/boost/scoped_array.hpp"
# include "../include/BoostWorkaround/boost/format.hpp" # include "../include/BoostWorkaround/boost/format.hpp"
# include "../include/BoostWorkaround/boost/foreach.hpp" # include "../include/BoostWorkaround/boost/foreach.hpp"
# include "../include/BoostWorkaround/boost/static_assert.hpp"
#else #else
@ -115,6 +116,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# include <boost/scoped_array.hpp> # include <boost/scoped_array.hpp>
# include <boost/format.hpp> # include <boost/format.hpp>
# include <boost/foreach.hpp> # include <boost/foreach.hpp>
# include <boost/static_assert.hpp>
#endif // ! ASSIMP_BUILD_BOOST_WORKAROUND #endif // ! ASSIMP_BUILD_BOOST_WORKAROUND
#endif // !! ASSIMP_PCH_INCLUDED #endif // !! ASSIMP_PCH_INCLUDED

View File

@ -0,0 +1,254 @@
/*
---------------------------------------------------------------------------
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 FindInstancesProcess.cpp
* @brief Implementation of the aiProcess_FindInstances postprocessing step
*/
#include "AssimpPCH.h"
#include "FindInstancesProcess.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
FindInstancesProcess::FindInstancesProcess()
{}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FindInstancesProcess::~FindInstancesProcess()
{}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool FindInstancesProcess::IsActive( unsigned int pFlags) const
{
return 0 != (pFlags & aiProcess_FindInstances);
}
// ------------------------------------------------------------------------------------------------
// Compare the bones of two meshes
bool CompareBones(const aiMesh* orig, const aiMesh* inst)
{
for (unsigned int i = 0; i < orig->mNumBones;++i) {
aiBone* aha = orig->mBones[i];
aiBone* oha = inst->mBones[i];
if (aha->mNumWeights != oha->mNumWeights ||
aha->mOffsetMatrix != oha->mOffsetMatrix ||
aha->mNumWeights != oha->mNumWeights) {
return false;
}
// compare weight per weight ---
for (unsigned int n = 0; n < aha->mNumWeights;++n) {
if (aha->mWeights[n].mVertexId != oha->mWeights[n].mVertexId ||
(aha->mWeights[n].mWeight - oha->mWeights[n].mWeight) < 10e-3f) {
return false;
}
}
}
return true;
}
// ------------------------------------------------------------------------------------------------
// Update mesh indices in the node graph
void UpdateMeshIndices(aiNode* node, unsigned int* lookup)
{
for (unsigned int n = 0; n < node->mNumMeshes;++n)
node->mMeshes[n] = lookup[node->mMeshes[n]];
for (unsigned int n = 0; n < node->mNumChildren;++n)
UpdateMeshIndices(node->mChildren[n],lookup);
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void FindInstancesProcess::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("FindInstancesProcess begin");
if (pScene->mNumMeshes) {
// use a pseudo hash for all meshes in the scene to quickly find
// the ones which are possibly equal. This step is executed early
// in the pipeline, so we could, depending on the file format,
// have several thousand small meshes. That's too much for a brute
// everyone-against-everyone check involving up to 25 comparisons
// each.
boost::scoped_array<uint64_t> hashes (new uint64_t[pScene->mNumMeshes]);
boost::scoped_array<unsigned int> remapping (new unsigned int[pScene->mNumMeshes]);
unsigned int numMeshesOut = 0;
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
aiMesh* inst = pScene->mMeshes[i];
hashes[i] = GetMeshHash(inst);
for (int a = i-1; a > 0; --a) {
if (hashes[i] == hashes[a])
{
aiMesh* orig = pScene->mMeshes[a];
if (!orig)
continue;
// check for hash collision .. we needn't check
// the vertex format, it *must* match due to the
// (brilliant) construction of the hash
if (orig->mNumBones != inst->mNumBones ||
orig->mNumFaces != inst->mNumFaces ||
orig->mNumVertices != inst->mNumVertices ||
orig->mMaterialIndex != inst->mMaterialIndex ||
orig->mPrimitiveTypes != inst->mPrimitiveTypes)
continue;
// up to now the meshes are equal. find an appropriate
// epsilon to compare position differences against
float epsilon = ComputePositionEpsilon(inst);
epsilon *= epsilon;
// now compare vertex positions, normals,
// tangents and bitangents using this epsilon.
if (orig->HasPositions()) {
if(!CompareArrays(orig->mVertices,inst->mVertices,orig->mNumVertices,epsilon))
continue;
}
if (orig->HasNormals()) {
if(!CompareArrays(orig->mNormals,inst->mNormals,orig->mNumVertices,epsilon))
continue;
}
if (orig->HasTangentsAndBitangents()) {
if (!CompareArrays(orig->mTangents,inst->mTangents,orig->mNumVertices,epsilon) ||
!CompareArrays(orig->mBitangents,inst->mBitangents,orig->mNumVertices,epsilon))
continue;
}
// use a constant epsilon for colors and UV coordinates
static const float uvEpsilon = 10e-4f;
BOOST_STATIC_ASSERT(4 == AI_MAX_NUMBER_OF_COLOR_SETS);
// as in JIV: manually unrolled as continue wouldn't work as desired in inner loops
if (orig->mTextureCoords[0]) {
if(!CompareArrays(orig->mTextureCoords[0],inst->mTextureCoords[0],orig->mNumVertices,uvEpsilon))
continue;
if (orig->mTextureCoords[1]) {
if(!CompareArrays(orig->mTextureCoords[1],inst->mTextureCoords[1],orig->mNumVertices,uvEpsilon))
continue;
if (orig->mTextureCoords[2]) {
if(!CompareArrays(orig->mTextureCoords[2],inst->mTextureCoords[2],orig->mNumVertices,uvEpsilon))
continue;
if (orig->mTextureCoords[3]) {
if(!CompareArrays(orig->mTextureCoords[3],inst->mTextureCoords[3],orig->mNumVertices,uvEpsilon))
continue;
}
}
}
}
BOOST_STATIC_ASSERT(4 == AI_MAX_NUMBER_OF_COLOR_SETS);
// and the same nasty stuff for vertex colors ...
if (orig->mColors[0]) {
if(!CompareArrays(orig->mColors[0],inst->mColors[0],orig->mNumVertices,uvEpsilon))
continue;
if (orig->mTextureCoords[1]) {
if(!CompareArrays(orig->mColors[1],inst->mColors[1],orig->mNumVertices,uvEpsilon))
continue;
if (orig->mTextureCoords[2]) {
if(!CompareArrays(orig->mColors[2],inst->mColors[2],orig->mNumVertices,uvEpsilon))
continue;
if (orig->mTextureCoords[3]) {
if(!CompareArrays(orig->mColors[3],inst->mColors[3],orig->mNumVertices,uvEpsilon))
continue;
}
}
}
}
// It seems to be strange, but we really need to check whether the
// bones are identical too. Although it's extremely unprobable
// that they're not if control reaches here, but we need to deal
// with unprobable cases, too.
if (!CompareBones(orig,inst))
continue;
// FIXME: Ignore the faces for the moment ... ok!?
// We're still here. Or in other words: 'inst' is an instance of 'orig'.
// Place a marker in our list that we can easily update mesh indices.
remapping[i] = a;
// Delete the instanced mesh, we don't need it anymore
delete inst;
pScene->mMeshes[i] = NULL;
}
}
// If we didn't find a match for the current mesh: keep it
if (pScene->mMeshes[i]) {
remapping[i] = numMeshesOut++;
}
}
ai_assert(0 != numMeshesOut);
if (numMeshesOut != pScene->mNumMeshes) {
// Collapse the meshes array by removing all NULL entries
for (unsigned int real = 0, i = 0; real < numMeshesOut; ++i) {
if (pScene->mMeshes[i])
pScene->mMeshes[real++] = pScene->mMeshes[i];
}
// And update the nodegraph with our nice lookup table
UpdateMeshIndices(pScene->mRootNode,remapping.get());
// write to log
if (!DefaultLogger::isNullLogger()) {
char buffer[512];
::sprintf(buffer,"FindInstancesProcess finished. Found %i instances",pScene->mNumMeshes-numMeshesOut);
DefaultLogger::get()->info(buffer);
}
pScene->mNumMeshes = numMeshesOut;
}
else DefaultLogger::get()->debug("FindInstancesProcess finished. No instanced meshes found");
}
}

View File

@ -0,0 +1,134 @@
/*
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 FindInstancesProcess.h
* @brief Declares the aiProcess_FindInstances post-process step
*/
#ifndef AI_FINDINSTANCES_H_INC
#define AI_FINDINSTANCES_H_INC
#include "BaseProcess.h"
#include "ProcessHelper.h"
class FindInstancesProcessTest;
namespace Assimp {
// -------------------------------------------------------------------------------
/** @brief Get a pseudo(!)-hash representing a mesh.
*
* The hash is built from number of vertices, faces, primitive types,
* .... but *not* from the real mesh data. It isn't absolutely unique.
* @param in Input mesh
* @return Hash.
*/
inline uint64_t GetMeshHash(aiMesh* in)
{
ai_assert(NULL != in);
// ... get an unique value representing the vertex format of the mesh
const unsigned int fhash = GetMeshVFormatUnique(in);
// and bake it with number of vertices/faces/bones/matidx/ptypes
return ((uint64_t)fhash << 32u) | ((
(in->mNumBones << 16u) ^ (in->mNumVertices) ^
(in->mNumFaces<<4u) ^ (in->mMaterialIndex<<15) ^
(in->mPrimitiveTypes<<28)) & 0xffffffff );
}
// -------------------------------------------------------------------------------
/** @brief Perform a component-wise comparison of two arrays
*
* @param first First array
* @param second Second aray
* @param size Size of both arrays
* @param e Epsilon
* @return true if the arrays are identical
*/
inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
unsigned int size, float e)
{
for (const aiVector3D* end = first+size; first != end; ++first,++second) {
if ( (*first - *second).SquareLength() >= e)
return false;
}
return true;
}
// and the same for colors ...
inline bool CompareArrays(const aiColor4D* first, const aiColor4D* second,
unsigned int size, float e)
{
for (const aiColor4D* end = first+size; first != end; ++first,++second) {
if ( GetColorDifference(*first,*second) >= e)
return false;
}
return true;
}
// ---------------------------------------------------------------------------
/** @brief A post-processing steps to search for instanced meshes
*/
class ASSIMP_API FindInstancesProcess : public BaseProcess
{
friend class Importer;
friend class ::FindInstancesProcessTest;
protected:
/** Constructor to be privately used by Importer */
FindInstancesProcess();
/** Destructor, private as well */
~FindInstancesProcess();
public:
// -------------------------------------------------------------------
// Check whether step is active in given flags combination
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
// Execute step on a given scene
void Execute( aiScene* pScene);
private:
}; // ! end class FindInstancesProcess
} // ! end namespace Assimp
#endif // !! AI_FINDINSTANCES_H_INC

View File

@ -196,6 +196,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS #ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
# include "TextureTransform.h" # include "TextureTransform.h"
#endif #endif
#ifndef AI_BUILD_NO_FINDINSTANCES_PROCESS
# include "FindInstancesProcess.h"
#endif
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Intern; using namespace Assimp::Intern;
@ -334,6 +337,14 @@ Importer::Importer()
mPostProcessingSteps.push_back( new ValidateDSProcess()); mPostProcessingSteps.push_back( new ValidateDSProcess());
#endif #endif
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
#endif
#if (!defined AI_BUILD_NO_FINDINSTANCES_PROCESS)
mPostProcessingSteps.push_back( new FindInstancesProcess());
#endif
#if (!defined AI_BUILD_NO_FINDDEGENERATES_PROCESS) #if (!defined AI_BUILD_NO_FINDDEGENERATES_PROCESS)
mPostProcessingSteps.push_back( new FindDegeneratesProcess()); mPostProcessingSteps.push_back( new FindDegeneratesProcess());
@ -353,12 +364,6 @@ Importer::Importer()
mPostProcessingSteps.push_back( new TextureTransformStep()); mPostProcessingSteps.push_back( new TextureTransformStep());
#endif #endif
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
#endif
#if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS) #if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
mPostProcessingSteps.push_back( new PretransformVertices()); mPostProcessingSteps.push_back( new PretransformVertices());
#endif #endif

View File

@ -209,7 +209,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
if( (uv.mBitangent - v.mBitangent).SquareLength() > squareEpsilon) if( (uv.mBitangent - v.mBitangent).SquareLength() > squareEpsilon)
continue; continue;
// manually unrolled because continue wouldn't work as desired in an inner loop // manually unrolled because continue wouldn't work as desired in an inner loop
ai_assert( AI_MAX_NUMBER_OF_COLOR_SETS == 4); BOOST_STATIC_ASSERT(4 == AI_MAX_NUMBER_OF_COLOR_SETS);
if( GetColorDifference( uv.mColors[0], v.mColors[0]) > squareEpsilon) if( GetColorDifference( uv.mColors[0], v.mColors[0]) > squareEpsilon)
continue; continue;
if( GetColorDifference( uv.mColors[1], v.mColors[1]) > squareEpsilon) if( GetColorDifference( uv.mColors[1], v.mColors[1]) > squareEpsilon)
@ -219,7 +219,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
if( GetColorDifference( uv.mColors[3], v.mColors[3]) > squareEpsilon) if( GetColorDifference( uv.mColors[3], v.mColors[3]) > squareEpsilon)
continue; continue;
// texture coord matching manually unrolled as well // texture coord matching manually unrolled as well
ai_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 4); BOOST_STATIC_ASSERT(4 == AI_MAX_NUMBER_OF_TEXTURECOORDS);
if( (uv.mTexCoords[0] - v.mTexCoords[0]).SquareLength() > squareEpsilon) if( (uv.mTexCoords[0] - v.mTexCoords[0]).SquareLength() > squareEpsilon)
continue; continue;
if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon) if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon)

View File

@ -95,20 +95,6 @@ protected:
* @param meshIndex Index of the mesh to process * @param meshIndex Index of the mesh to process
*/ */
int ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); int ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
// -------------------------------------------------------------------
/** Little helper function to calculate the quadratic difference
* of two colours.
* @param pColor1 First color
* @param pColor2 second color
* @return Quadratic color difference
*/
float GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pColor2) const
{
aiColor4D c( pColor1.r - pColor2.r, pColor1.g - pColor2.g,
pColor1.b - pColor2.b, pColor1.a - pColor2.a);
return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a;
}
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssimpPCH.h" #include "AssimpPCH.h"
#include "PretransformVertices.h" #include "PretransformVertices.h"
#include "ProcessHelper.h"
using namespace Assimp; using namespace Assimp;
@ -95,32 +95,8 @@ unsigned int GetMeshVFormat(aiMesh* pcMesh)
if (pcMesh->mBones) if (pcMesh->mBones)
return (unsigned int)(unsigned long)pcMesh->mBones; return (unsigned int)(unsigned long)pcMesh->mBones;
ai_assert(NULL != pcMesh->mVertices);
// FIX: the hash may never be 0. Otherwise a comparison against const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
// nullptr could be successful
unsigned int iRet = 1;
// normals
if (pcMesh->HasNormals())iRet |= 0x2;
// tangents and bitangents
if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4;
// texture coordinates
unsigned int p = 0;
ai_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
while (pcMesh->HasTextureCoords(p))
{
iRet |= (0x100 << p);
if (3 == pcMesh->mNumUVComponents[p])
iRet |= (0x10000 << p);
++p;
}
// vertex colors
p = 0;
ai_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++);
// store the value for later use // store the value for later use
pcMesh->mBones = (aiBone**)(unsigned long)iRet; pcMesh->mBones = (aiBone**)(unsigned long)iRet;

View File

@ -48,11 +48,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
// some aliases to make the whole stuff easier to read
typedef std::pair < unsigned int,float > PerVertexWeight; typedef std::pair < unsigned int,float > PerVertexWeight;
typedef std::vector < PerVertexWeight > VertexWeightTable; typedef std::vector < PerVertexWeight > VertexWeightTable;
// ------------------------------------------------------------------------------------------------ // -------------------------------------------------------------------------------
// compute a good epsilon value for position comparisons /** Little helper function to calculate the quadratic difference
* of two colours.
* @param pColor1 First color
* @param pColor2 second color
* @return Quadratic color difference
*/
inline float GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pColor2)
{
const aiColor4D c (pColor1.r - pColor2.r, pColor1.g - pColor2.g,
pColor1.b - pColor2.b, pColor1.a - pColor2.a);
return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a;
}
// -------------------------------------------------------------------------------
// Compute a good epsilon value for position comparisons on a mesh
inline float ComputePositionEpsilon(const aiMesh* pMesh) inline float ComputePositionEpsilon(const aiMesh* pMesh)
{ {
const float epsilon = 1e-5f; const float epsilon = 1e-5f;
@ -71,20 +87,54 @@ inline float ComputePositionEpsilon(const aiMesh* pMesh)
return (maxVec - minVec).Length() * epsilon; return (maxVec - minVec).Length() * epsilon;
} }
// ------------------------------------------------------------------------------------------------ // -------------------------------------------------------------------------------
// Compute an unique value for the vertex format of a mesh
inline unsigned int GetMeshVFormatUnique(aiMesh* pcMesh)
{
ai_assert(NULL != pcMesh);
// FIX: the hash may never be 0. Otherwise a comparison against
// nullptr could be successful
unsigned int iRet = 1;
// normals
if (pcMesh->HasNormals())iRet |= 0x2;
// tangents and bitangents
if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4;
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
// texture coordinates
unsigned int p = 0;
while (pcMesh->HasTextureCoords(p))
{
iRet |= (0x100 << p);
if (3 == pcMesh->mNumUVComponents[p])
iRet |= (0x10000 << p);
++p;
}
// vertex colors
p = 0;
while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++);
return iRet;
}
// -------------------------------------------------------------------------------
// Compute a per-vertex bone weight table // Compute a per-vertex bone weight table
// NOTE: delete result with operator delete[] ... // please .... delete result with operator delete[] ...
inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh) inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh)
{ {
if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) return NULL; if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones)
return NULL;
VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices]; VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
for (unsigned int i = 0; i < pMesh->mNumBones;++i) for (unsigned int i = 0; i < pMesh->mNumBones;++i)
{ {
aiBone* bone = pMesh->mBones[i]; aiBone* bone = pMesh->mBones[i];
for (unsigned int a = 0; a < bone->mNumWeights;++a) for (unsigned int a = 0; a < bone->mNumWeights;++a) {
{ const aiVertexWeight& weight = bone->mWeights[a];
aiVertexWeight& weight = bone->mWeights[a];
avPerVertexWeights[weight.mVertexId].push_back( avPerVertexWeights[weight.mVertexId].push_back(
std::pair<unsigned int,float>(i,weight.mWeight)); std::pair<unsigned int,float>(i,weight.mWeight));
} }
@ -93,7 +143,7 @@ inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh)
} }
// ------------------------------------------------------------------------------------------------ // -------------------------------------------------------------------------------
// Get a string for a given aiTextureType // Get a string for a given aiTextureType
inline const char* TextureTypeToString(aiTextureType in) inline const char* TextureTypeToString(aiTextureType in)
{ {
@ -120,7 +170,7 @@ inline const char* TextureTypeToString(aiTextureType in)
} }
} }
// ------------------------------------------------------------------------------------------------ // -------------------------------------------------------------------------------
// Get a string for a given aiTextureMapping // Get a string for a given aiTextureMapping
inline const char* MappingTypeToString(aiTextureMapping in) inline const char* MappingTypeToString(aiTextureMapping in)
{ {
@ -143,7 +193,9 @@ inline const char* MappingTypeToString(aiTextureMapping in)
} }
} }
// ------------------------------------------------------------------------------------------------ // -------------------------------------------------------------------------------
// Utility postprocess step to share the spatial sort tree between
// all steps which use it to speedup its computations.
class ComputeSpatialSortProcess : public BaseProcess class ComputeSpatialSortProcess : public BaseProcess
{ {
bool IsActive( unsigned int pFlags) const bool IsActive( unsigned int pFlags) const
@ -159,8 +211,7 @@ class ComputeSpatialSortProcess : public BaseProcess
std::vector<_Type>* p = new std::vector<_Type>(pScene->mNumMeshes); std::vector<_Type>* p = new std::vector<_Type>(pScene->mNumMeshes);
std::vector<_Type>::iterator it = p->begin(); std::vector<_Type>::iterator it = p->begin();
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++it) for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++it) {
{
aiMesh* mesh = pScene->mMeshes[i]; aiMesh* mesh = pScene->mMeshes[i];
_Type& blubb = *it; _Type& blubb = *it;
blubb.first.Fill(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D)); blubb.first.Fill(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D));
@ -171,7 +222,8 @@ class ComputeSpatialSortProcess : public BaseProcess
} }
}; };
// ------------------------------------------------------------------------------------------------ // -------------------------------------------------------------------------------
// ... and the same again to cleanup the whole stuff
class DestroySpatialSortProcess : public BaseProcess class DestroySpatialSortProcess : public BaseProcess
{ {
bool IsActive( unsigned int pFlags) const bool IsActive( unsigned int pFlags) const

View File

@ -38,11 +38,6 @@ public:
return ptr; return ptr;
} }
inline operator T*()
{
return ptr;
}
inline T* operator-> () inline T* operator-> ()
{ {
return ptr; return ptr;

View File

@ -0,0 +1,20 @@
#ifndef AI_BOOST_STATIC_ASSERT_INCLUDED
#define AI_BOOST_STATIC_ASSERT_INCLUDED
#ifndef BOOST_STATIC_ASSERT
namespace boost {
namespace detail {
template <bool b> class static_assertion_failure;
template <> class static_assertion_failure<true> {};
}
}
#define BOOST_STATIC_ASSERT(eval) \
{boost::detail::static_assertion_failure<(eval)> assert_dummy;assert_dummy;}
#endif
#endif // !! AI_BOOST_STATIC_ASSERT_INCLUDED

View File

@ -243,8 +243,18 @@ enum aiPostProcessSteps
* coordinates and generates a new, transformed, UV channel for it. * coordinates and generates a new, transformed, UV channel for it.
* Most applications won't support UV transformations, so you will * Most applications won't support UV transformations, so you will
* probably want to specify this step in every case. * probably want to specify this step in every case.
* todo ... rewrite doc
*/ */
aiProcess_TransformUVCoords = 0x80000 aiProcess_TransformUVCoords = 0x80000,
/** This step searches for duplicate meshes and replaces duplicates
* with references to the first mesh.
*
* todo ... add more doc
*/
aiProcess_FindInstances = 0x100000
}; };

View File

@ -146,6 +146,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
aiProcess_FindInvalidData | // detect invalid model data, such as invalid normal vectors aiProcess_FindInvalidData | // detect invalid model data, such as invalid normal vectors
aiProcess_GenUVCoords | // convert spherical, cylindrical, box and planar mapping to proper UVs aiProcess_GenUVCoords | // convert spherical, cylindrical, box and planar mapping to proper UVs
aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation ...) aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation ...)
aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master
// aiProcess_PreTransformVertices | // aiProcess_PreTransformVertices |
0); 0);

View File

@ -1254,6 +1254,10 @@
RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp" RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp"
> >
</File> </File>
<File
RelativePath="..\..\include\BoostWorkaround\boost\static_assert.hpp"
>
</File>
<Filter <Filter
Name="random" Name="random"
> >
@ -2046,6 +2050,14 @@
RelativePath="..\..\code\FindDegenerates.h" RelativePath="..\..\code\FindDegenerates.h"
> >
</File> </File>
<File
RelativePath="..\..\code\FindInstancesProcess.cpp"
>
</File>
<File
RelativePath="..\..\code\FindInstancesProcess.h"
>
</File>
<File <File
RelativePath="..\..\code\FindInvalidDataProcess.cpp" RelativePath="..\..\code\FindInvalidDataProcess.cpp"
> >

View File

@ -1253,6 +1253,10 @@
RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp" RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp"
> >
</File> </File>
<File
RelativePath="..\..\include\BoostWorkaround\boost\static_assert.hpp"
>
</File>
<Filter <Filter
Name="random" Name="random"
> >
@ -2045,6 +2049,14 @@
RelativePath="..\..\code\FindDegenerates.h" RelativePath="..\..\code\FindDegenerates.h"
> >
</File> </File>
<File
RelativePath="..\..\code\FindInstancesProcess.cpp"
>
</File>
<File
RelativePath="..\..\code\FindInstancesProcess.h"
>
</File>
<File <File
RelativePath="..\..\code\FindInvalidDataProcess.cpp" RelativePath="..\..\code\FindInvalidDataProcess.cpp"
> >