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: nuclear@0: /** @file Implementation of the SplitLargeMeshes postprocessing step nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: nuclear@0: // internal headers of the post-processing framework nuclear@0: #include "SplitLargeMeshes.h" nuclear@0: #include "ProcessHelper.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() nuclear@0: { nuclear@0: LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle() nuclear@0: { nuclear@0: // nothing to do here nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns whether the processing step is present in the given flag field. nuclear@0: bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const nuclear@0: { nuclear@0: return (pFlags & aiProcess_SplitLargeMeshes) != 0; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Executes the post processing step on the given imported data. nuclear@0: void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) nuclear@0: { nuclear@0: if (0xffffffff == this->LIMIT)return; nuclear@0: nuclear@0: DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle begin"); nuclear@0: std::vector > avList; nuclear@0: nuclear@0: for( unsigned int a = 0; a < pScene->mNumMeshes; a++) nuclear@0: this->SplitMesh(a, pScene->mMeshes[a],avList); nuclear@0: nuclear@0: if (avList.size() != pScene->mNumMeshes) nuclear@0: { nuclear@0: // it seems something has been split. rebuild the mesh list nuclear@0: delete[] pScene->mMeshes; nuclear@0: pScene->mNumMeshes = (unsigned int)avList.size(); nuclear@0: pScene->mMeshes = new aiMesh*[avList.size()]; nuclear@0: nuclear@0: for (unsigned int i = 0; i < avList.size();++i) nuclear@0: pScene->mMeshes[i] = avList[i].first; nuclear@0: nuclear@0: // now we need to update all nodes nuclear@0: this->UpdateNode(pScene->mRootNode,avList); nuclear@0: DefaultLogger::get()->info("SplitLargeMeshesProcess_Triangle finished. Meshes have been split"); nuclear@0: } nuclear@0: else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle finished. There was nothing to do"); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Setup properties nuclear@0: void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) nuclear@0: { nuclear@0: // get the current value of the split property nuclear@0: this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Update a node after some meshes have been split nuclear@0: void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, nuclear@0: const std::vector >& avList) nuclear@0: { nuclear@0: // for every index in out list build a new entry nuclear@0: std::vector aiEntries; nuclear@0: aiEntries.reserve(pcNode->mNumMeshes + 1); nuclear@0: for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) nuclear@0: { nuclear@0: for (unsigned int a = 0; a < avList.size();++a) nuclear@0: { nuclear@0: if (avList[a].second == pcNode->mMeshes[i]) nuclear@0: { nuclear@0: aiEntries.push_back(a); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // now build the new list nuclear@0: delete pcNode->mMeshes; nuclear@0: pcNode->mNumMeshes = (unsigned int)aiEntries.size(); nuclear@0: pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; nuclear@0: nuclear@0: for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) nuclear@0: pcNode->mMeshes[b] = aiEntries[b]; nuclear@0: nuclear@0: // recusively update all other nodes nuclear@0: for (unsigned int i = 0; i < pcNode->mNumChildren;++i) nuclear@0: { nuclear@0: UpdateNode ( pcNode->mChildren[i], avList ); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Executes the post processing step on the given imported data. nuclear@0: void SplitLargeMeshesProcess_Triangle::SplitMesh( nuclear@0: unsigned int a, nuclear@0: aiMesh* pMesh, nuclear@0: std::vector >& avList) nuclear@0: { nuclear@0: if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT) nuclear@0: { nuclear@0: DefaultLogger::get()->info("Mesh exceeds the triangle limit. It will be split ..."); nuclear@0: nuclear@0: // we need to split this mesh into sub meshes nuclear@0: // determine the size of a submesh nuclear@0: const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1; nuclear@0: nuclear@0: const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes; nuclear@0: const unsigned int iOutVertexNum = iOutFaceNum * 3; nuclear@0: nuclear@0: // now generate all submeshes nuclear@0: for (unsigned int i = 0; i < iSubMeshes;++i) nuclear@0: { nuclear@0: aiMesh* pcMesh = new aiMesh; nuclear@0: pcMesh->mNumFaces = iOutFaceNum; nuclear@0: pcMesh->mMaterialIndex = pMesh->mMaterialIndex; nuclear@0: nuclear@0: // the name carries the adjacency information between the meshes nuclear@0: pcMesh->mName = pMesh->mName; nuclear@0: nuclear@0: if (i == iSubMeshes-1) nuclear@0: { nuclear@0: pcMesh->mNumFaces = iOutFaceNum + ( nuclear@0: pMesh->mNumFaces - iOutFaceNum * iSubMeshes); nuclear@0: } nuclear@0: // copy the list of faces nuclear@0: pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; nuclear@0: nuclear@0: const unsigned int iBase = iOutFaceNum * i; nuclear@0: nuclear@0: // get the total number of indices nuclear@0: unsigned int iCnt = 0; nuclear@0: for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p) nuclear@0: { nuclear@0: iCnt += pMesh->mFaces[p].mNumIndices; nuclear@0: } nuclear@0: pcMesh->mNumVertices = iCnt; nuclear@0: nuclear@0: // allocate storage nuclear@0: if (pMesh->mVertices != NULL) nuclear@0: pcMesh->mVertices = new aiVector3D[iCnt]; nuclear@0: nuclear@0: if (pMesh->HasNormals()) nuclear@0: pcMesh->mNormals = new aiVector3D[iCnt]; nuclear@0: nuclear@0: if (pMesh->HasTangentsAndBitangents()) nuclear@0: { nuclear@0: pcMesh->mTangents = new aiVector3D[iCnt]; nuclear@0: pcMesh->mBitangents = new aiVector3D[iCnt]; nuclear@0: } nuclear@0: nuclear@0: // texture coordinates nuclear@0: for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) nuclear@0: { nuclear@0: pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c]; nuclear@0: if (pMesh->HasTextureCoords( c)) nuclear@0: { nuclear@0: pcMesh->mTextureCoords[c] = new aiVector3D[iCnt]; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // vertex colors nuclear@0: for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) nuclear@0: { nuclear@0: if (pMesh->HasVertexColors( c)) nuclear@0: { nuclear@0: pcMesh->mColors[c] = new aiColor4D[iCnt]; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (pMesh->HasBones()) nuclear@0: { nuclear@0: // assume the number of bones won't change in most cases nuclear@0: pcMesh->mBones = new aiBone*[pMesh->mNumBones]; nuclear@0: nuclear@0: // iterate through all bones of the mesh and find those which nuclear@0: // need to be copied to the split mesh nuclear@0: std::vector avTempWeights; nuclear@0: for (unsigned int p = 0; p < pcMesh->mNumBones;++p) nuclear@0: { nuclear@0: aiBone* const bone = pcMesh->mBones[p]; nuclear@0: avTempWeights.clear(); nuclear@0: avTempWeights.reserve(bone->mNumWeights / iSubMeshes); nuclear@0: nuclear@0: for (unsigned int q = 0; q < bone->mNumWeights;++q) nuclear@0: { nuclear@0: aiVertexWeight& weight = bone->mWeights[q]; nuclear@0: if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum) nuclear@0: { nuclear@0: avTempWeights.push_back(weight); nuclear@0: weight = avTempWeights.back(); nuclear@0: weight.mVertexId -= iBase; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (!avTempWeights.empty()) nuclear@0: { nuclear@0: // we'll need this bone. Copy it ... nuclear@0: aiBone* pc = new aiBone(); nuclear@0: pcMesh->mBones[pcMesh->mNumBones++] = pc; nuclear@0: pc->mName = aiString(bone->mName); nuclear@0: pc->mNumWeights = (unsigned int)avTempWeights.size(); nuclear@0: pc->mOffsetMatrix = bone->mOffsetMatrix; nuclear@0: nuclear@0: // no need to reallocate the array for the last submesh. nuclear@0: // Here we can reuse the (large) source array, although nuclear@0: // we'll waste some memory nuclear@0: if (iSubMeshes-1 == i) nuclear@0: { nuclear@0: pc->mWeights = bone->mWeights; nuclear@0: bone->mWeights = NULL; nuclear@0: } nuclear@0: else pc->mWeights = new aiVertexWeight[pc->mNumWeights]; nuclear@0: nuclear@0: // copy the weights nuclear@0: ::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // (we will also need to copy the array of indices) nuclear@0: unsigned int iCurrent = 0; nuclear@0: for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) nuclear@0: { nuclear@0: pcMesh->mFaces[p].mNumIndices = 3; nuclear@0: // allocate a new array nuclear@0: const unsigned int iTemp = p + iBase; nuclear@0: const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices; nuclear@0: nuclear@0: // setup face type and number of indices nuclear@0: pcMesh->mFaces[p].mNumIndices = iNumIndices; nuclear@0: unsigned int* pi = pMesh->mFaces[iTemp].mIndices; nuclear@0: unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices]; nuclear@0: nuclear@0: // need to update the output primitive types nuclear@0: switch (iNumIndices) nuclear@0: { nuclear@0: case 1: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; nuclear@0: break; nuclear@0: case 2: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; nuclear@0: break; nuclear@0: case 3: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; nuclear@0: break; nuclear@0: default: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; nuclear@0: } nuclear@0: nuclear@0: // and copy the contents of the old array, offset by current base nuclear@0: for (unsigned int v = 0; v < iNumIndices;++v) nuclear@0: { nuclear@0: unsigned int iIndex = pi[v]; nuclear@0: unsigned int iIndexOut = iCurrent++; nuclear@0: piOut[v] = iIndexOut; nuclear@0: nuclear@0: // copy positions nuclear@0: if (pMesh->mVertices != NULL) nuclear@0: pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex]; nuclear@0: nuclear@0: // copy normals nuclear@0: if (pMesh->HasNormals()) nuclear@0: pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex]; nuclear@0: nuclear@0: // copy tangents/bitangents nuclear@0: if (pMesh->HasTangentsAndBitangents()) nuclear@0: { nuclear@0: pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex]; nuclear@0: pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex]; nuclear@0: } nuclear@0: nuclear@0: // texture coordinates nuclear@0: for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) nuclear@0: { nuclear@0: if (pMesh->HasTextureCoords( c)) nuclear@0: pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex]; nuclear@0: } nuclear@0: // vertex colors nuclear@0: for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) nuclear@0: { nuclear@0: if (pMesh->HasVertexColors( c)) nuclear@0: pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex]; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // add the newly created mesh to the list nuclear@0: avList.push_back(std::pair(pcMesh,a)); nuclear@0: } nuclear@0: nuclear@0: // now delete the old mesh data nuclear@0: delete pMesh; nuclear@0: } nuclear@0: else avList.push_back(std::pair(pMesh,a)); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() nuclear@0: { nuclear@0: LIMIT = AI_SLM_DEFAULT_MAX_VERTICES; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex() nuclear@0: { nuclear@0: // nothing to do here nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns whether the processing step is present in the given flag field. nuclear@0: bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const nuclear@0: { nuclear@0: return (pFlags & aiProcess_SplitLargeMeshes) != 0; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Executes the post processing step on the given imported data. nuclear@0: void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) nuclear@0: { nuclear@0: std::vector > avList; nuclear@0: nuclear@0: if (0xffffffff == this->LIMIT)return; nuclear@0: nuclear@0: DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex begin"); nuclear@0: for( unsigned int a = 0; a < pScene->mNumMeshes; a++) nuclear@0: this->SplitMesh(a, pScene->mMeshes[a],avList); nuclear@0: nuclear@0: if (avList.size() != pScene->mNumMeshes) nuclear@0: { nuclear@0: // it seems something has been split. rebuild the mesh list nuclear@0: delete[] pScene->mMeshes; nuclear@0: pScene->mNumMeshes = (unsigned int)avList.size(); nuclear@0: pScene->mMeshes = new aiMesh*[avList.size()]; nuclear@0: nuclear@0: for (unsigned int i = 0; i < avList.size();++i) nuclear@0: pScene->mMeshes[i] = avList[i].first; nuclear@0: nuclear@0: // now we need to update all nodes nuclear@0: SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList); nuclear@0: DefaultLogger::get()->info("SplitLargeMeshesProcess_Vertex finished. Meshes have been split"); nuclear@0: } nuclear@0: else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex finished. There was nothing to do"); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Setup properties nuclear@0: void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) nuclear@0: { nuclear@0: this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Executes the post processing step on the given imported data. nuclear@0: void SplitLargeMeshesProcess_Vertex::SplitMesh( nuclear@0: unsigned int a, nuclear@0: aiMesh* pMesh, nuclear@0: std::vector >& avList) nuclear@0: { nuclear@0: if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT) nuclear@0: { nuclear@0: typedef std::vector< std::pair > VertexWeightTable; nuclear@0: nuclear@0: // build a per-vertex weight list if necessary nuclear@0: VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh); nuclear@0: nuclear@0: // we need to split this mesh into sub meshes nuclear@0: // determine the estimated size of a submesh nuclear@0: // (this could be too large. Max waste is a single digit percentage) nuclear@0: const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1; nuclear@0: //const unsigned int iOutVertexNum2 = pMesh->mNumVertices /iSubMeshes; nuclear@0: nuclear@0: // create a std::vector to indicate which vertices nuclear@0: // have already been copied nuclear@0: std::vector avWasCopied; nuclear@0: avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF); nuclear@0: nuclear@0: // try to find a good estimate for the number of output faces nuclear@0: // per mesh. Add 12.5% as buffer nuclear@0: unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes; nuclear@0: iEstimatedSize += iEstimatedSize >> 3; nuclear@0: nuclear@0: // now generate all submeshes nuclear@0: unsigned int iBase = 0; nuclear@0: while (true) nuclear@0: { nuclear@0: const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT; nuclear@0: nuclear@0: aiMesh* pcMesh = new aiMesh; nuclear@0: pcMesh->mNumVertices = 0; nuclear@0: pcMesh->mMaterialIndex = pMesh->mMaterialIndex; nuclear@0: nuclear@0: // the name carries the adjacency information between the meshes nuclear@0: pcMesh->mName = pMesh->mName; nuclear@0: nuclear@0: typedef std::vector BoneWeightList; nuclear@0: if (pMesh->HasBones()) nuclear@0: { nuclear@0: pcMesh->mBones = new aiBone*[pMesh->mNumBones]; nuclear@0: ::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones); nuclear@0: } nuclear@0: nuclear@0: // clear the temporary helper array nuclear@0: if (iBase) nuclear@0: { nuclear@0: // we can't use memset here we unsigned int needn' be 32 bits nuclear@0: for (std::vector::iterator nuclear@0: iter = avWasCopied.begin(),end = avWasCopied.end(); nuclear@0: iter != end;++iter) nuclear@0: { nuclear@0: (*iter) = 0xffffffff; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // output vectors nuclear@0: std::vector vFaces; nuclear@0: nuclear@0: // reserve enough storage for most cases nuclear@0: if (pMesh->HasPositions()) nuclear@0: { nuclear@0: pcMesh->mVertices = new aiVector3D[iOutVertexNum]; nuclear@0: } nuclear@0: if (pMesh->HasNormals()) nuclear@0: { nuclear@0: pcMesh->mNormals = new aiVector3D[iOutVertexNum]; nuclear@0: } nuclear@0: if (pMesh->HasTangentsAndBitangents()) nuclear@0: { nuclear@0: pcMesh->mTangents = new aiVector3D[iOutVertexNum]; nuclear@0: pcMesh->mBitangents = new aiVector3D[iOutVertexNum]; nuclear@0: } nuclear@0: for (unsigned int c = 0; pMesh->HasVertexColors(c);++c) nuclear@0: { nuclear@0: pcMesh->mColors[c] = new aiColor4D[iOutVertexNum]; nuclear@0: } nuclear@0: for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c) nuclear@0: { nuclear@0: pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c]; nuclear@0: pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum]; nuclear@0: } nuclear@0: vFaces.reserve(iEstimatedSize); nuclear@0: nuclear@0: // (we will also need to copy the array of indices) nuclear@0: while (iBase < pMesh->mNumFaces) nuclear@0: { nuclear@0: // allocate a new array nuclear@0: const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices; nuclear@0: nuclear@0: // doesn't catch degenerates but is quite fast nuclear@0: unsigned int iNeed = 0; nuclear@0: for (unsigned int v = 0; v < iNumIndices;++v) nuclear@0: { nuclear@0: unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v]; nuclear@0: nuclear@0: // check whether we do already have this vertex nuclear@0: if (0xFFFFFFFF == avWasCopied[iIndex]) nuclear@0: { nuclear@0: iNeed++; nuclear@0: } nuclear@0: } nuclear@0: if (pcMesh->mNumVertices + iNeed > iOutVertexNum) nuclear@0: { nuclear@0: // don't use this face nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: vFaces.push_back(aiFace()); nuclear@0: aiFace& rFace = vFaces.back(); nuclear@0: nuclear@0: // setup face type and number of indices nuclear@0: rFace.mNumIndices = iNumIndices; nuclear@0: rFace.mIndices = new unsigned int[iNumIndices]; nuclear@0: nuclear@0: // need to update the output primitive types nuclear@0: switch (rFace.mNumIndices) nuclear@0: { nuclear@0: case 1: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; nuclear@0: break; nuclear@0: case 2: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; nuclear@0: break; nuclear@0: case 3: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; nuclear@0: break; nuclear@0: default: nuclear@0: pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; nuclear@0: } nuclear@0: nuclear@0: // and copy the contents of the old array, offset by current base nuclear@0: for (unsigned int v = 0; v < iNumIndices;++v) nuclear@0: { nuclear@0: unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v]; nuclear@0: nuclear@0: // check whether we do already have this vertex nuclear@0: if (0xFFFFFFFF != avWasCopied[iIndex]) nuclear@0: { nuclear@0: rFace.mIndices[v] = avWasCopied[iIndex]; nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: // copy positions nuclear@0: pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]); nuclear@0: nuclear@0: // copy normals nuclear@0: if (pMesh->HasNormals()) nuclear@0: { nuclear@0: pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]); nuclear@0: } nuclear@0: nuclear@0: // copy tangents/bitangents nuclear@0: if (pMesh->HasTangentsAndBitangents()) nuclear@0: { nuclear@0: pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]); nuclear@0: pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]); nuclear@0: } nuclear@0: nuclear@0: // texture coordinates nuclear@0: for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) nuclear@0: { nuclear@0: if (pMesh->HasTextureCoords( c)) nuclear@0: { nuclear@0: pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex]; nuclear@0: } nuclear@0: } nuclear@0: // vertex colors nuclear@0: for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) nuclear@0: { nuclear@0: if (pMesh->HasVertexColors( c)) nuclear@0: { nuclear@0: pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex]; nuclear@0: } nuclear@0: } nuclear@0: // check whether we have bone weights assigned to this vertex nuclear@0: rFace.mIndices[v] = pcMesh->mNumVertices; nuclear@0: if (avPerVertexWeights) nuclear@0: { nuclear@0: VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ]; nuclear@0: if( !table.empty() ) nuclear@0: { nuclear@0: for (VertexWeightTable::const_iterator nuclear@0: iter = table.begin(); nuclear@0: iter != table.end();++iter) nuclear@0: { nuclear@0: // allocate the bone weight array if necessary nuclear@0: BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first]; nuclear@0: if (!pcWeightList) nuclear@0: { nuclear@0: pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList()); nuclear@0: } nuclear@0: pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second)); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: avWasCopied[iIndex] = pcMesh->mNumVertices; nuclear@0: pcMesh->mNumVertices++; nuclear@0: } nuclear@0: iBase++; nuclear@0: if(pcMesh->mNumVertices == iOutVertexNum) nuclear@0: { nuclear@0: // break here. The face is only added if it was complete nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // check which bones we'll need to create for this submesh nuclear@0: if (pMesh->HasBones()) nuclear@0: { nuclear@0: aiBone** ppCurrent = pcMesh->mBones; nuclear@0: for (unsigned int k = 0; k < pMesh->mNumBones;++k) nuclear@0: { nuclear@0: // check whether the bone is existing nuclear@0: BoneWeightList* pcWeightList; nuclear@0: if ((pcWeightList = (BoneWeightList*)pcMesh->mBones[k])) nuclear@0: { nuclear@0: aiBone* pcOldBone = pMesh->mBones[k]; nuclear@0: aiBone* pcOut; nuclear@0: *ppCurrent++ = pcOut = new aiBone(); nuclear@0: pcOut->mName = aiString(pcOldBone->mName); nuclear@0: pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix; nuclear@0: pcOut->mNumWeights = (unsigned int)pcWeightList->size(); nuclear@0: pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights]; nuclear@0: nuclear@0: // copy the vertex weights nuclear@0: ::memcpy(pcOut->mWeights,&pcWeightList->operator[](0), nuclear@0: pcOut->mNumWeights * sizeof(aiVertexWeight)); nuclear@0: nuclear@0: // delete the temporary bone weight list nuclear@0: delete pcWeightList; nuclear@0: pcMesh->mNumBones++; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // copy the face list to the mesh nuclear@0: pcMesh->mFaces = new aiFace[vFaces.size()]; nuclear@0: pcMesh->mNumFaces = (unsigned int)vFaces.size(); nuclear@0: nuclear@0: for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) nuclear@0: pcMesh->mFaces[p] = vFaces[p]; nuclear@0: nuclear@0: // add the newly created mesh to the list nuclear@0: avList.push_back(std::pair(pcMesh,a)); nuclear@0: nuclear@0: if (iBase == pMesh->mNumFaces) nuclear@0: { nuclear@0: // have all faces ... finish the outer loop, too nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // delete the per-vertex weight list again nuclear@0: delete[] avPerVertexWeights; nuclear@0: nuclear@0: // now delete the old mesh data nuclear@0: delete pMesh; nuclear@0: return; nuclear@0: } nuclear@0: avList.push_back(std::pair(pMesh,a)); nuclear@0: return; nuclear@0: }