nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /// @file ProcessHelper.cpp nuclear@0: /** Implement shared utility functions for postprocessing steps */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #include "ProcessHelper.h" nuclear@0: nuclear@0: nuclear@0: #include nuclear@0: nuclear@0: namespace Assimp { nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: void ConvertListToStrings(const std::string& in, std::list& out) nuclear@0: { nuclear@0: const char* s = in.c_str(); nuclear@0: while (*s) { nuclear@0: SkipSpacesAndLineEnd(&s); nuclear@0: if (*s == '\'') { nuclear@0: const char* base = ++s; nuclear@0: while (*s != '\'') { nuclear@0: ++s; nuclear@0: if (*s == '\0') { nuclear@0: DefaultLogger::get()->error("ConvertListToString: String list is ill-formatted"); nuclear@0: return; nuclear@0: } nuclear@0: } nuclear@0: out.push_back(std::string(base,(size_t)(s-base))); nuclear@0: ++s; nuclear@0: } nuclear@0: else { nuclear@0: out.push_back(GetNextToken(s)); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, nuclear@0: const aiMatrix4x4& m) nuclear@0: { nuclear@0: min = aiVector3D (10e10f, 10e10f, 10e10f); nuclear@0: max = aiVector3D (-10e10f,-10e10f,-10e10f); nuclear@0: for (unsigned int i = 0;i < mesh->mNumVertices;++i) nuclear@0: { nuclear@0: const aiVector3D v = m * mesh->mVertices[i]; nuclear@0: min = std::min(v,min); nuclear@0: max = std::max(v,max); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max) nuclear@0: { nuclear@0: ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max); nuclear@0: out = min + (max-min)*0.5f; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min, nuclear@0: aiVector3D& max, const aiMatrix4x4& m) nuclear@0: { nuclear@0: FindAABBTransformed(mesh,min,max,m); nuclear@0: out = min + (max-min)*0.5f; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: void FindMeshCenter (aiMesh* mesh, aiVector3D& out) nuclear@0: { nuclear@0: aiVector3D min,max; nuclear@0: FindMeshCenter(mesh,out,min,max); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, nuclear@0: const aiMatrix4x4& m) nuclear@0: { nuclear@0: aiVector3D min,max; nuclear@0: FindMeshCenterTransformed(mesh,out,min,max,m); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: float ComputePositionEpsilon(const aiMesh* pMesh) nuclear@0: { nuclear@0: const float epsilon = 1e-4f; nuclear@0: nuclear@0: // calculate the position bounds so we have a reliable epsilon to check position differences against nuclear@0: aiVector3D minVec, maxVec; nuclear@0: ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec); nuclear@0: return (maxVec - minVec).Length() * epsilon; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: float ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num) nuclear@0: { nuclear@0: const float epsilon = 1e-4f; nuclear@0: nuclear@0: // calculate the position bounds so we have a reliable epsilon to check position differences against nuclear@0: aiVector3D minVec, maxVec, mi, ma; nuclear@0: MinMaxChooser()(minVec,maxVec); nuclear@0: nuclear@0: for (size_t a = 0; a < num; ++a) { nuclear@0: const aiMesh* pMesh = pMeshes[a]; nuclear@0: ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma); nuclear@0: nuclear@0: minVec = std::min(minVec,mi); nuclear@0: maxVec = std::max(maxVec,ma); nuclear@0: } nuclear@0: return (maxVec - minVec).Length() * epsilon; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh) nuclear@0: { nuclear@0: ai_assert(NULL != pcMesh); nuclear@0: nuclear@0: // FIX: the hash may never be 0. Otherwise a comparison against nuclear@0: // nullptr could be successful nuclear@0: unsigned int iRet = 1; nuclear@0: nuclear@0: // normals nuclear@0: if (pcMesh->HasNormals())iRet |= 0x2; nuclear@0: // tangents and bitangents nuclear@0: if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4; nuclear@0: nuclear@0: #ifdef BOOST_STATIC_ASSERT nuclear@0: BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); nuclear@0: BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); nuclear@0: #endif nuclear@0: nuclear@0: // texture coordinates nuclear@0: unsigned int p = 0; nuclear@0: while (pcMesh->HasTextureCoords(p)) nuclear@0: { nuclear@0: iRet |= (0x100 << p); nuclear@0: if (3 == pcMesh->mNumUVComponents[p]) nuclear@0: iRet |= (0x10000 << p); nuclear@0: nuclear@0: ++p; nuclear@0: } nuclear@0: // vertex colors nuclear@0: p = 0; nuclear@0: while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++); nuclear@0: return iRet; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) nuclear@0: { nuclear@0: if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) { nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices]; nuclear@0: for (unsigned int i = 0; i < pMesh->mNumBones;++i) { nuclear@0: nuclear@0: aiBone* bone = pMesh->mBones[i]; nuclear@0: for (unsigned int a = 0; a < bone->mNumWeights;++a) { nuclear@0: const aiVertexWeight& weight = bone->mWeights[a]; nuclear@0: avPerVertexWeights[weight.mVertexId].push_back( std::pair(i,weight.mWeight) ); nuclear@0: } nuclear@0: } nuclear@0: return avPerVertexWeights; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: const char* TextureTypeToString(aiTextureType in) nuclear@0: { nuclear@0: switch (in) nuclear@0: { nuclear@0: case aiTextureType_NONE: nuclear@0: return "n/a"; nuclear@0: case aiTextureType_DIFFUSE: nuclear@0: return "Diffuse"; nuclear@0: case aiTextureType_SPECULAR: nuclear@0: return "Specular"; nuclear@0: case aiTextureType_AMBIENT: nuclear@0: return "Ambient"; nuclear@0: case aiTextureType_EMISSIVE: nuclear@0: return "Emissive"; nuclear@0: case aiTextureType_OPACITY: nuclear@0: return "Opacity"; nuclear@0: case aiTextureType_NORMALS: nuclear@0: return "Normals"; nuclear@0: case aiTextureType_HEIGHT: nuclear@0: return "Height"; nuclear@0: case aiTextureType_SHININESS: nuclear@0: return "Shininess"; nuclear@0: case aiTextureType_DISPLACEMENT: nuclear@0: return "Displacement"; nuclear@0: case aiTextureType_LIGHTMAP: nuclear@0: return "Lightmap"; nuclear@0: case aiTextureType_REFLECTION: nuclear@0: return "Reflection"; nuclear@0: case aiTextureType_UNKNOWN: nuclear@0: return "Unknown"; nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: ai_assert(false); nuclear@0: return "BUG"; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: const char* MappingTypeToString(aiTextureMapping in) nuclear@0: { nuclear@0: switch (in) nuclear@0: { nuclear@0: case aiTextureMapping_UV: nuclear@0: return "UV"; nuclear@0: case aiTextureMapping_BOX: nuclear@0: return "Box"; nuclear@0: case aiTextureMapping_SPHERE: nuclear@0: return "Sphere"; nuclear@0: case aiTextureMapping_CYLINDER: nuclear@0: return "Cylinder"; nuclear@0: case aiTextureMapping_PLANE: nuclear@0: return "Plane"; nuclear@0: case aiTextureMapping_OTHER: nuclear@0: return "Other"; nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: ai_assert(false); nuclear@0: return "BUG"; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------- nuclear@0: aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector &subMeshFaces, unsigned int subFlags) nuclear@0: { nuclear@0: aiMesh *oMesh = new aiMesh(); nuclear@0: std::vector vMap(pMesh->mNumVertices,UINT_MAX); nuclear@0: nuclear@0: size_t numSubVerts = 0; nuclear@0: size_t numSubFaces = subMeshFaces.size(); nuclear@0: nuclear@0: for(unsigned int i=0;imFaces[subMeshFaces[i]]; nuclear@0: nuclear@0: for(unsigned int j=0;jmName = pMesh->mName; nuclear@0: nuclear@0: oMesh->mMaterialIndex = pMesh->mMaterialIndex; nuclear@0: oMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; nuclear@0: nuclear@0: // create all the arrays for this mesh if the old mesh contained them nuclear@0: nuclear@0: oMesh->mNumFaces = subMeshFaces.size(); nuclear@0: oMesh->mNumVertices = numSubVerts; nuclear@0: oMesh->mVertices = new aiVector3D[numSubVerts]; nuclear@0: if( pMesh->HasNormals() ) { nuclear@0: oMesh->mNormals = new aiVector3D[numSubVerts]; nuclear@0: } nuclear@0: nuclear@0: if( pMesh->HasTangentsAndBitangents() ) { nuclear@0: oMesh->mTangents = new aiVector3D[numSubVerts]; nuclear@0: oMesh->mBitangents = new aiVector3D[numSubVerts]; nuclear@0: } nuclear@0: nuclear@0: for( size_t a = 0; pMesh->HasTextureCoords( a) ; ++a ) { nuclear@0: oMesh->mTextureCoords[a] = new aiVector3D[numSubVerts]; nuclear@0: oMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; nuclear@0: } nuclear@0: nuclear@0: for( size_t a = 0; pMesh->HasVertexColors( a); ++a ) { nuclear@0: oMesh->mColors[a] = new aiColor4D[numSubVerts]; nuclear@0: } nuclear@0: nuclear@0: // and copy over the data, generating faces with linear indices along the way nuclear@0: oMesh->mFaces = new aiFace[numSubFaces]; nuclear@0: nuclear@0: for(unsigned int a = 0; a < numSubFaces; ++a ) { nuclear@0: nuclear@0: const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; nuclear@0: aiFace& dstFace = oMesh->mFaces[a]; nuclear@0: dstFace.mNumIndices = srcFace.mNumIndices; nuclear@0: dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; nuclear@0: nuclear@0: // accumulate linearly all the vertices of the source face nuclear@0: for( size_t b = 0; b < dstFace.mNumIndices; ++b ) { nuclear@0: dstFace.mIndices[b] = vMap[srcFace.mIndices[b]]; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: for(unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex ) { nuclear@0: unsigned int nvi = vMap[srcIndex]; nuclear@0: if(nvi==UINT_MAX) { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: oMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; nuclear@0: if( pMesh->HasNormals() ) { nuclear@0: oMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; nuclear@0: } nuclear@0: nuclear@0: if( pMesh->HasTangentsAndBitangents() ) { nuclear@0: oMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; nuclear@0: oMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; nuclear@0: } nuclear@0: for( size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c ) { nuclear@0: oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; nuclear@0: } nuclear@0: for( size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c ) { nuclear@0: oMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(~subFlags&AI_SUBMESH_FLAGS_SANS_BONES) { nuclear@0: std::vector subBones(pMesh->mNumBones,0); nuclear@0: nuclear@0: for(unsigned int a=0;amNumBones;++a) { nuclear@0: const aiBone* bone = pMesh->mBones[a]; nuclear@0: nuclear@0: for(unsigned int b=0;bmNumWeights;b++) { nuclear@0: unsigned int v = vMap[bone->mWeights[b].mVertexId]; nuclear@0: nuclear@0: if(v!=UINT_MAX) { nuclear@0: subBones[a]++; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: for(unsigned int a=0;amNumBones;++a) { nuclear@0: if(subBones[a]>0) { nuclear@0: oMesh->mNumBones++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(oMesh->mNumBones) { nuclear@0: oMesh->mBones = new aiBone*[oMesh->mNumBones](); nuclear@0: unsigned int nbParanoia = oMesh->mNumBones; nuclear@0: nuclear@0: oMesh->mNumBones = 0; //rewind nuclear@0: nuclear@0: for(unsigned int a=0;amNumBones;++a) { nuclear@0: if(subBones[a]==0) { nuclear@0: continue; nuclear@0: } nuclear@0: aiBone *newBone = new aiBone; nuclear@0: oMesh->mBones[oMesh->mNumBones++] = newBone; nuclear@0: nuclear@0: const aiBone* bone = pMesh->mBones[a]; nuclear@0: nuclear@0: newBone->mName = bone->mName; nuclear@0: newBone->mOffsetMatrix = bone->mOffsetMatrix; nuclear@0: newBone->mWeights = new aiVertexWeight[subBones[a]]; nuclear@0: nuclear@0: for(unsigned int b=0;bmNumWeights;b++) { nuclear@0: const unsigned int v = vMap[bone->mWeights[b].mVertexId]; nuclear@0: nuclear@0: if(v!=UINT_MAX) { nuclear@0: aiVertexWeight w(v,bone->mWeights[b].mWeight); nuclear@0: newBone->mWeights[newBone->mNumWeights++] = w; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: ai_assert(nbParanoia==oMesh->mNumBones); nuclear@0: (void)nbParanoia; // remove compiler warning on release build nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return oMesh; nuclear@0: } nuclear@0: nuclear@0: } // namespace Assimp