From 4b4526953e31fe0386f8e097b384cb35d17aaaf4 Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Mon, 2 Feb 2009 20:29:27 +0000 Subject: [PATCH] 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 --- code/AssimpPCH.h | 2 + code/FindInstancesProcess.cpp | 254 ++++++++++++++++++ code/FindInstancesProcess.h | 134 +++++++++ code/Importer.cpp | 17 +- code/JoinVerticesProcess.cpp | 4 +- code/JoinVerticesProcess.h | 14 - code/PretransformVertices.cpp | 28 +- code/ProcessHelper.h | 84 ++++-- .../BoostWorkaround/boost/scoped_array.hpp | 5 - .../BoostWorkaround/boost/static_assert.hpp | 20 ++ include/aiPostProcess.h | 12 +- tools/assimp_view/assimp_view.cpp | 1 + workspaces/vc8/assimp.vcproj | 12 + workspaces/vc9/assimp.vcproj | 12 + 14 files changed, 529 insertions(+), 70 deletions(-) create mode 100644 code/FindInstancesProcess.cpp create mode 100644 code/FindInstancesProcess.h create mode 100644 include/BoostWorkaround/boost/static_assert.hpp diff --git a/code/AssimpPCH.h b/code/AssimpPCH.h index fcdca4dee..f60793fad 100644 --- a/code/AssimpPCH.h +++ b/code/AssimpPCH.h @@ -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/format.hpp" # include "../include/BoostWorkaround/boost/foreach.hpp" +# include "../include/BoostWorkaround/boost/static_assert.hpp" #else @@ -115,6 +116,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # include # include # include +# include #endif // ! ASSIMP_BUILD_BOOST_WORKAROUND #endif // !! ASSIMP_PCH_INCLUDED diff --git a/code/FindInstancesProcess.cpp b/code/FindInstancesProcess.cpp new file mode 100644 index 000000000..400e57fa0 --- /dev/null +++ b/code/FindInstancesProcess.cpp @@ -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 hashes (new uint64_t[pScene->mNumMeshes]); + boost::scoped_array 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"); + } +} diff --git a/code/FindInstancesProcess.h b/code/FindInstancesProcess.h new file mode 100644 index 000000000..abb330dfb --- /dev/null +++ b/code/FindInstancesProcess.h @@ -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 diff --git a/code/Importer.cpp b/code/Importer.cpp index 05d307d8b..e61294f71 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -196,6 +196,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS # include "TextureTransform.h" #endif +#ifndef AI_BUILD_NO_FINDINSTANCES_PROCESS +# include "FindInstancesProcess.h" +#endif using namespace Assimp; using namespace Assimp::Intern; @@ -334,6 +337,14 @@ Importer::Importer() mPostProcessingSteps.push_back( new ValidateDSProcess()); #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) mPostProcessingSteps.push_back( new FindDegeneratesProcess()); @@ -353,12 +364,6 @@ Importer::Importer() mPostProcessingSteps.push_back( new TextureTransformStep()); #endif - - - -#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS) - mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess()); -#endif #if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS) mPostProcessingSteps.push_back( new PretransformVertices()); #endif diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index 301960e58..39aac209a 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -209,7 +209,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) if( (uv.mBitangent - v.mBitangent).SquareLength() > squareEpsilon) continue; // 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) continue; 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) continue; // 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) continue; if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon) diff --git a/code/JoinVerticesProcess.h b/code/JoinVerticesProcess.h index 2b495c4d5..ce0b195a2 100644 --- a/code/JoinVerticesProcess.h +++ b/code/JoinVerticesProcess.h @@ -95,20 +95,6 @@ protected: * @param meshIndex Index of the mesh to process */ 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 diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index 72e731502..89450d77d 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssimpPCH.h" #include "PretransformVertices.h" - +#include "ProcessHelper.h" using namespace Assimp; @@ -95,32 +95,8 @@ unsigned int GetMeshVFormat(aiMesh* pcMesh) if (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 - // 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++); + const unsigned int iRet = GetMeshVFormatUnique(pcMesh); // store the value for later use pcMesh->mBones = (aiBone**)(unsigned long)iRet; diff --git a/code/ProcessHelper.h b/code/ProcessHelper.h index 9de4e599f..8aec59b86 100644 --- a/code/ProcessHelper.h +++ b/code/ProcessHelper.h @@ -48,11 +48,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -typedef std::pair< unsigned int,float > PerVertexWeight; -typedef std::vector< PerVertexWeight > VertexWeightTable; +// some aliases to make the whole stuff easier to read +typedef std::pair < unsigned int,float > PerVertexWeight; +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) { const float epsilon = 1e-5f; @@ -71,20 +87,54 @@ inline float ComputePositionEpsilon(const aiMesh* pMesh) 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 -// NOTE: delete result with operator delete[] ... +// please .... delete result with operator delete[] ... 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]; for (unsigned int i = 0; i < pMesh->mNumBones;++i) { aiBone* bone = pMesh->mBones[i]; - for (unsigned int a = 0; a < bone->mNumWeights;++a) - { - aiVertexWeight& weight = bone->mWeights[a]; + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + const aiVertexWeight& weight = bone->mWeights[a]; avPerVertexWeights[weight.mVertexId].push_back( std::pair(i,weight.mWeight)); } @@ -93,7 +143,7 @@ inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh) } -// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------- // Get a string for a given aiTextureType inline const char* TextureTypeToString(aiTextureType in) { @@ -120,7 +170,7 @@ inline const char* TextureTypeToString(aiTextureType in) } } -// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------- // Get a string for a given aiTextureMapping 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 { 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>::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]; _Type& blubb = *it; 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 { bool IsActive( unsigned int pFlags) const diff --git a/include/BoostWorkaround/boost/scoped_array.hpp b/include/BoostWorkaround/boost/scoped_array.hpp index 2274c7d2f..0d83f4581 100644 --- a/include/BoostWorkaround/boost/scoped_array.hpp +++ b/include/BoostWorkaround/boost/scoped_array.hpp @@ -38,11 +38,6 @@ public: return ptr; } - inline operator T*() - { - return ptr; - } - inline T* operator-> () { return ptr; diff --git a/include/BoostWorkaround/boost/static_assert.hpp b/include/BoostWorkaround/boost/static_assert.hpp new file mode 100644 index 000000000..4326c240d --- /dev/null +++ b/include/BoostWorkaround/boost/static_assert.hpp @@ -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 class static_assertion_failure; + template <> class static_assertion_failure {}; + } +} + + +#define BOOST_STATIC_ASSERT(eval) \ +{boost::detail::static_assertion_failure<(eval)> assert_dummy;assert_dummy;} + +#endif +#endif // !! AI_BOOST_STATIC_ASSERT_INCLUDED \ No newline at end of file diff --git a/include/aiPostProcess.h b/include/aiPostProcess.h index 652be73d3..59984c40c 100644 --- a/include/aiPostProcess.h +++ b/include/aiPostProcess.h @@ -243,8 +243,18 @@ enum aiPostProcessSteps * coordinates and generates a new, transformed, UV channel for it. * Most applications won't support UV transformations, so you will * 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 }; diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index 971acdeee..9577234d8 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -146,6 +146,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter) aiProcess_FindInvalidData | // detect invalid model data, such as invalid normal vectors aiProcess_GenUVCoords | // convert spherical, cylindrical, box and planar mapping to proper UVs aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation ...) + aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master // aiProcess_PreTransformVertices | 0); diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index 543e8b96b..5ff938073 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -1254,6 +1254,10 @@ RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp" > + + @@ -2046,6 +2050,14 @@ RelativePath="..\..\code\FindDegenerates.h" > + + + + diff --git a/workspaces/vc9/assimp.vcproj b/workspaces/vc9/assimp.vcproj index 96e9acb55..2334f8d87 100644 --- a/workspaces/vc9/assimp.vcproj +++ b/workspaces/vc9/assimp.vcproj @@ -1253,6 +1253,10 @@ RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp" > + + @@ -2045,6 +2049,14 @@ RelativePath="..\..\code\FindDegenerates.h" > + + + +