vrshoot
diff libs/assimp/OptimizeMeshes.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/OptimizeMeshes.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,243 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file OptimizeMeshes.cpp 1.46 + * @brief Implementation of the aiProcess_OptimizeMeshes step 1.47 + */ 1.48 + 1.49 +#include "AssimpPCH.h" 1.50 +#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS 1.51 + 1.52 +using namespace Assimp; 1.53 +#include "OptimizeMeshes.h" 1.54 +#include "ProcessHelper.h" 1.55 +#include "SceneCombiner.h" 1.56 + 1.57 +// ------------------------------------------------------------------------------------------------ 1.58 +// Constructor to be privately used by Importer 1.59 +OptimizeMeshesProcess::OptimizeMeshesProcess() 1.60 +: pts (false) 1.61 +, max_verts (0xffffffff) 1.62 +, max_faces (0xffffffff) 1.63 +{} 1.64 + 1.65 +// ------------------------------------------------------------------------------------------------ 1.66 +// Destructor, private as well 1.67 +OptimizeMeshesProcess::~OptimizeMeshesProcess() 1.68 +{} 1.69 + 1.70 +// ------------------------------------------------------------------------------------------------ 1.71 +// Returns whether the processing step is present in the given flag field. 1.72 +bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const 1.73 +{ 1.74 + // Our behaviour needs to be different if the SortByPType or SplitLargeMeshes 1.75 + // steps are active. Thus we need to query their flags here and store the 1.76 + // information, although we're breaking const-correctness. 1.77 + // That's a serious design flaw, consider redesign. 1.78 + if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) { 1.79 + pts = (0 != (pFlags & aiProcess_SortByPType)); 1.80 + max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : 0; 1.81 + return true; 1.82 + } 1.83 + return false; 1.84 +} 1.85 + 1.86 +// ------------------------------------------------------------------------------------------------ 1.87 +// Setup properties for the postprocessing step 1.88 +void OptimizeMeshesProcess::SetupProperties(const Importer* pImp) 1.89 +{ 1.90 + if (max_verts == 0xdeadbeef /* magic hack */) { 1.91 + max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); 1.92 + max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); 1.93 + } 1.94 +} 1.95 + 1.96 +// ------------------------------------------------------------------------------------------------ 1.97 +// Execute step 1.98 +void OptimizeMeshesProcess::Execute( aiScene* pScene) 1.99 +{ 1.100 + const unsigned int num_old = pScene->mNumMeshes; 1.101 + if (num_old <= 1) { 1.102 + DefaultLogger::get()->debug("Skipping OptimizeMeshesProcess"); 1.103 + return; 1.104 + } 1.105 + 1.106 + DefaultLogger::get()->debug("OptimizeMeshesProcess begin"); 1.107 + mScene = pScene; 1.108 + 1.109 + // need to clear persistent members from previous runs 1.110 + merge_list.clear(); 1.111 + output.clear(); 1.112 + 1.113 + merge_list.reserve(pScene->mNumMeshes); 1.114 + output.reserve(pScene->mNumMeshes); 1.115 + 1.116 + // Prepare lookup tables 1.117 + meshes.resize(pScene->mNumMeshes); 1.118 + FindInstancedMeshes(pScene->mRootNode); 1.119 + if (max_verts == 0xdeadbeef) /* undo the magic hack */ 1.120 + max_verts = 0xffffffff; 1.121 + 1.122 + // ... instanced meshes are immediately processed and added to the output list 1.123 + for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) { 1.124 + meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]); 1.125 + 1.126 + if (meshes[i].instance_cnt > 1 && meshes[i].output_id == 0xffffffff) { 1.127 + meshes[i].output_id = n++; 1.128 + output.push_back(mScene->mMeshes[i]); 1.129 + } 1.130 + } 1.131 + 1.132 + // and process all nodes in the scenegraoh recursively 1.133 + ProcessNode(pScene->mRootNode); 1.134 + if (!output.size()) { 1.135 + throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong"); 1.136 + } 1.137 + 1.138 + meshes.clear(); 1.139 + ai_assert(output.size() <= num_old); 1.140 + 1.141 + mScene->mNumMeshes = output.size(); 1.142 + std::copy(output.begin(),output.end(),mScene->mMeshes); 1.143 + 1.144 + if (output.size() != num_old) { 1.145 + char tmp[512]; 1.146 + ::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes); 1.147 + DefaultLogger::get()->info(tmp); 1.148 + } 1.149 + else DefaultLogger::get()->debug("OptimizeMeshesProcess finished"); 1.150 +} 1.151 + 1.152 +// ------------------------------------------------------------------------------------------------ 1.153 +// Process meshes for a single node 1.154 +void OptimizeMeshesProcess::ProcessNode( aiNode* pNode) 1.155 +{ 1.156 + for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { 1.157 + unsigned int& im = pNode->mMeshes[i]; 1.158 + 1.159 + if (meshes[im].instance_cnt > 1) { 1.160 + im = meshes[im].output_id; 1.161 + } 1.162 + else { 1.163 + merge_list.clear(); 1.164 + unsigned int verts = 0, faces = 0; 1.165 + 1.166 + // Find meshes to merge with us 1.167 + for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) { 1.168 + register unsigned int am = pNode->mMeshes[a]; 1.169 + if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) { 1.170 + 1.171 + merge_list.push_back(mScene->mMeshes[am]); 1.172 + verts += mScene->mMeshes[am]->mNumVertices; 1.173 + faces += mScene->mMeshes[am]->mNumFaces; 1.174 + 1.175 + --pNode->mNumMeshes; 1.176 + for (unsigned int n = a; n < pNode->mNumMeshes; ++n) 1.177 + pNode->mMeshes[n] = pNode->mMeshes[n+1]; 1.178 + 1.179 + --a; 1.180 + } 1.181 + } 1.182 + 1.183 + // and merge all meshes which we found, replace the old ones 1.184 + if (!merge_list.empty()) { 1.185 + merge_list.push_back(mScene->mMeshes[im]); 1.186 + 1.187 + aiMesh* out; 1.188 + SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end()); 1.189 + output.push_back(out); 1.190 + } 1.191 + else { 1.192 + output.push_back(mScene->mMeshes[im]); 1.193 + } 1.194 + im = output.size()-1; 1.195 + } 1.196 + } 1.197 + 1.198 + 1.199 + for (unsigned int i = 0; i < pNode->mNumChildren; ++i) 1.200 + ProcessNode(pNode->mChildren[i]); 1.201 +} 1.202 + 1.203 +// ------------------------------------------------------------------------------------------------ 1.204 +// Check whether two meshes can be joined 1.205 +bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned int verts, unsigned int faces ) 1.206 +{ 1.207 + if (meshes[a].vertex_format != meshes[b].vertex_format) 1.208 + return false; 1.209 + 1.210 + aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b]; 1.211 + 1.212 + if ((0xffffffff != max_verts && verts+mb->mNumVertices > max_verts) || 1.213 + (0xffffffff != max_faces && faces+mb->mNumFaces > max_faces)) { 1.214 + return false; 1.215 + } 1.216 + 1.217 + // Never merge unskinned meshes with skinned meshes 1.218 + if (ma->mMaterialIndex != mb->mMaterialIndex || ma->HasBones() != mb->HasBones()) 1.219 + return false; 1.220 + 1.221 + // Never merge meshes with different kinds of primitives if SortByPType did already 1.222 + // do its work. We would destroy everything again ... 1.223 + if (pts && ma->mPrimitiveTypes != mb->mPrimitiveTypes) 1.224 + return false; 1.225 + 1.226 + // If both meshes are skinned, check whether we have many bones defined in both meshes. 1.227 + // If yes, we can savely join them. 1.228 + if (ma->HasBones()) { 1.229 + // TODO 1.230 + return false; 1.231 + } 1.232 + return true; 1.233 +} 1.234 + 1.235 +// ------------------------------------------------------------------------------------------------ 1.236 +// Buidl a LUT of all instanced meshes 1.237 +void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode) 1.238 +{ 1.239 + for (unsigned int i = 0; i < pNode->mNumMeshes;++i) 1.240 + ++meshes[pNode->mMeshes[i]].instance_cnt; 1.241 + 1.242 + for (unsigned int i = 0; i < pNode->mNumChildren; ++i) 1.243 + FindInstancedMeshes(pNode->mChildren[i]); 1.244 +} 1.245 + 1.246 +#endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS