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