vrshoot

diff libs/assimp/FindInstancesProcess.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/FindInstancesProcess.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,277 @@
     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  FindInstancesProcess.cpp
    1.46 + *  @brief Implementation of the aiProcess_FindInstances postprocessing step
    1.47 +*/
    1.48 +
    1.49 +#include "AssimpPCH.h"
    1.50 +#include "FindInstancesProcess.h"
    1.51 +
    1.52 +using namespace Assimp;
    1.53 +
    1.54 +// ------------------------------------------------------------------------------------------------
    1.55 +// Constructor to be privately used by Importer
    1.56 +FindInstancesProcess::FindInstancesProcess()
    1.57 +:	configSpeedFlag (false)
    1.58 +{}
    1.59 +
    1.60 +// ------------------------------------------------------------------------------------------------
    1.61 +// Destructor, private as well
    1.62 +FindInstancesProcess::~FindInstancesProcess()
    1.63 +{}
    1.64 +
    1.65 +// ------------------------------------------------------------------------------------------------
    1.66 +// Returns whether the processing step is present in the given flag field.
    1.67 +bool FindInstancesProcess::IsActive( unsigned int pFlags) const
    1.68 +{
    1.69 +	// FindInstances makes absolutely no sense together with PreTransformVertices
    1.70 +	// fixme: spawn error message somewhere else?
    1.71 +	return 0 != (pFlags & aiProcess_FindInstances) && 0 == (pFlags & aiProcess_PreTransformVertices);
    1.72 +}
    1.73 +
    1.74 +// ------------------------------------------------------------------------------------------------
    1.75 +// Setup properties for the step
    1.76 +void FindInstancesProcess::SetupProperties(const Importer* pImp)
    1.77 +{
    1.78 +	// AI_CONFIG_FAVOUR_SPEED
    1.79 +	configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0));
    1.80 +}
    1.81 +
    1.82 +// ------------------------------------------------------------------------------------------------
    1.83 +// Compare the bones of two meshes
    1.84 +bool CompareBones(const aiMesh* orig, const aiMesh* inst)
    1.85 +{
    1.86 +	for (unsigned int i = 0; i < orig->mNumBones;++i) {
    1.87 +		aiBone* aha = orig->mBones[i];
    1.88 +		aiBone* oha = inst->mBones[i];
    1.89 +
    1.90 +		if (aha->mNumWeights   != oha->mNumWeights   ||
    1.91 +			aha->mOffsetMatrix != oha->mOffsetMatrix ||
    1.92 +			aha->mNumWeights   != oha->mNumWeights) {
    1.93 +			return false;
    1.94 +		}
    1.95 +
    1.96 +		// compare weight per weight ---
    1.97 +		for (unsigned int n = 0; n < aha->mNumWeights;++n) {
    1.98 +			if  (aha->mWeights[n].mVertexId != oha->mWeights[n].mVertexId ||
    1.99 +				(aha->mWeights[n].mWeight - oha->mWeights[n].mWeight) < 10e-3f) {
   1.100 +				return false;
   1.101 +			}
   1.102 +		}
   1.103 +	}
   1.104 +	return true;
   1.105 +}
   1.106 +
   1.107 +// ------------------------------------------------------------------------------------------------
   1.108 +// Update mesh indices in the node graph
   1.109 +void UpdateMeshIndices(aiNode* node, unsigned int* lookup)
   1.110 +{
   1.111 +	for (unsigned int n = 0; n < node->mNumMeshes;++n)
   1.112 +		node->mMeshes[n] = lookup[node->mMeshes[n]];
   1.113 +
   1.114 +	for (unsigned int n = 0; n < node->mNumChildren;++n)
   1.115 +		UpdateMeshIndices(node->mChildren[n],lookup);
   1.116 +}
   1.117 +
   1.118 +// ------------------------------------------------------------------------------------------------
   1.119 +// Executes the post processing step on the given imported data.
   1.120 +void FindInstancesProcess::Execute( aiScene* pScene)
   1.121 +{
   1.122 +	DefaultLogger::get()->debug("FindInstancesProcess begin");
   1.123 +	if (pScene->mNumMeshes) {
   1.124 +
   1.125 +		// use a pseudo hash for all meshes in the scene to quickly find 
   1.126 +		// the ones which are possibly equal. This step is executed early 
   1.127 +		// in the pipeline, so we could, depending on the file format,
   1.128 +		// have several thousand small meshes. That's too much for a brute
   1.129 +		// everyone-against-everyone check involving up to 10 comparisons
   1.130 +		// each.
   1.131 +		boost::scoped_array<uint64_t> hashes (new uint64_t[pScene->mNumMeshes]);
   1.132 +		boost::scoped_array<unsigned int> remapping (new unsigned int[pScene->mNumMeshes]);
   1.133 +
   1.134 +		unsigned int numMeshesOut = 0;
   1.135 +		for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
   1.136 +
   1.137 +			aiMesh* inst = pScene->mMeshes[i];
   1.138 +			hashes[i] = GetMeshHash(inst);
   1.139 +
   1.140 +			for (int a = i-1; a >= 0; --a) {
   1.141 +				if (hashes[i] == hashes[a])
   1.142 +				{
   1.143 +					aiMesh* orig = pScene->mMeshes[a];
   1.144 +					if (!orig)
   1.145 +						continue;
   1.146 +					
   1.147 +					// check for hash collision .. we needn't check
   1.148 +					// the vertex format, it *must* match due to the
   1.149 +					// (brilliant) construction of the hash
   1.150 +					if (orig->mNumBones       != inst->mNumBones      ||
   1.151 +						orig->mNumFaces       != inst->mNumFaces      ||
   1.152 +						orig->mNumVertices    != inst->mNumVertices   ||
   1.153 +						orig->mMaterialIndex  != inst->mMaterialIndex ||
   1.154 +						orig->mPrimitiveTypes != inst->mPrimitiveTypes)
   1.155 +						continue;
   1.156 +
   1.157 +					// up to now the meshes are equal. find an appropriate
   1.158 +					// epsilon to compare position differences against
   1.159 +					float epsilon = ComputePositionEpsilon(inst);
   1.160 +					epsilon *= epsilon;
   1.161 +
   1.162 +					// now compare vertex positions, normals,
   1.163 +					// tangents and bitangents using this epsilon.
   1.164 +					if (orig->HasPositions()) {
   1.165 +						if(!CompareArrays(orig->mVertices,inst->mVertices,orig->mNumVertices,epsilon))
   1.166 +							continue;
   1.167 +					}
   1.168 +					if (orig->HasNormals()) {
   1.169 +						if(!CompareArrays(orig->mNormals,inst->mNormals,orig->mNumVertices,epsilon))
   1.170 +							continue;
   1.171 +					}
   1.172 +					if (orig->HasTangentsAndBitangents()) {
   1.173 +						if (!CompareArrays(orig->mTangents,inst->mTangents,orig->mNumVertices,epsilon) ||
   1.174 +							!CompareArrays(orig->mBitangents,inst->mBitangents,orig->mNumVertices,epsilon))
   1.175 +							continue;
   1.176 +					}
   1.177 +
   1.178 +					// use a constant epsilon for colors and UV coordinates
   1.179 +					static const float uvEpsilon = 10e-4f;
   1.180 +
   1.181 +					{
   1.182 +						unsigned int i, end = orig->GetNumUVChannels();
   1.183 +						for(i = 0; i < end; ++i) {
   1.184 +							if (!orig->mTextureCoords[i]) {
   1.185 +								continue;
   1.186 +							}
   1.187 +							if(!CompareArrays(orig->mTextureCoords[i],inst->mTextureCoords[i],orig->mNumVertices,uvEpsilon)) {
   1.188 +								break;	
   1.189 +							}
   1.190 +						}
   1.191 +						if (i != end) {
   1.192 +							continue;
   1.193 +						}
   1.194 +					}
   1.195 +					{
   1.196 +						unsigned int i, end = orig->GetNumColorChannels();
   1.197 +						for(i = 0; i < end; ++i) {
   1.198 +							if (!orig->mColors[i]) {
   1.199 +								continue;
   1.200 +							}
   1.201 +							if(!CompareArrays(orig->mColors[i],inst->mColors[i],orig->mNumVertices,uvEpsilon)) {
   1.202 +								break;	
   1.203 +							}
   1.204 +						}
   1.205 +						if (i != end) {
   1.206 +							continue;
   1.207 +						}
   1.208 +					}
   1.209 +
   1.210 +					// These two checks are actually quite expensive and almost *never* required.
   1.211 +					// Almost. That's why they're still here. But there's no reason to do them
   1.212 +					// in speed-targeted imports.
   1.213 +					if (!configSpeedFlag) {
   1.214 +
   1.215 +						// It seems to be strange, but we really need to check whether the
   1.216 +						// bones are identical too. Although it's extremely unprobable
   1.217 +						// that they're not if control reaches here, we need to deal
   1.218 +						// with unprobable cases, too. It could still be that there are
   1.219 +						// equal shapes which are deformed differently.
   1.220 +						if (!CompareBones(orig,inst))
   1.221 +							continue;
   1.222 +
   1.223 +						// For completeness ... compare even the index buffers for equality
   1.224 +						// face order & winding order doesn't care. Input data is in verbose format.
   1.225 +						boost::scoped_array<unsigned int> ftbl_orig(new unsigned int[orig->mNumVertices]);
   1.226 +						boost::scoped_array<unsigned int> ftbl_inst(new unsigned int[orig->mNumVertices]);
   1.227 +
   1.228 +						for (unsigned int tt = 0; tt < orig->mNumFaces;++tt) {
   1.229 +							aiFace& f = orig->mFaces[tt];
   1.230 +							for (unsigned int nn = 0; nn < f.mNumIndices;++nn)
   1.231 +								ftbl_orig[f.mIndices[nn]] = tt;
   1.232 +
   1.233 +							aiFace& f2 = inst->mFaces[tt];
   1.234 +							for (unsigned int nn = 0; nn < f2.mNumIndices;++nn)
   1.235 +								ftbl_inst[f2.mIndices[nn]] = tt;
   1.236 +						}
   1.237 +						if (0 != ::memcmp(ftbl_inst.get(),ftbl_orig.get(),orig->mNumVertices*sizeof(unsigned int)))
   1.238 +							continue;
   1.239 +					}
   1.240 +
   1.241 +					// We're still here. Or in other words: 'inst' is an instance of 'orig'.
   1.242 +					// Place a marker in our list that we can easily update mesh indices.
   1.243 +					remapping[i] = remapping[a];
   1.244 +
   1.245 +					// Delete the instanced mesh, we don't need it anymore
   1.246 +					delete inst;
   1.247 +					pScene->mMeshes[i] = NULL;
   1.248 +					break;
   1.249 +				}
   1.250 +			}
   1.251 +
   1.252 +			// If we didn't find a match for the current mesh: keep it
   1.253 +			if (pScene->mMeshes[i]) {
   1.254 +				remapping[i] = numMeshesOut++;
   1.255 +			}
   1.256 +		}
   1.257 +		ai_assert(0 != numMeshesOut);
   1.258 +		if (numMeshesOut != pScene->mNumMeshes) {
   1.259 +
   1.260 +			// Collapse the meshes array by removing all NULL entries
   1.261 +			for (unsigned int real = 0, i = 0; real < numMeshesOut; ++i) {
   1.262 +				if (pScene->mMeshes[i])
   1.263 +					pScene->mMeshes[real++] = pScene->mMeshes[i];
   1.264 +			}
   1.265 +
   1.266 +			// And update the nodegraph with our nice lookup table
   1.267 +			UpdateMeshIndices(pScene->mRootNode,remapping.get());
   1.268 +
   1.269 +			// write to log
   1.270 +			if (!DefaultLogger::isNullLogger()) {
   1.271 +			
   1.272 +				char buffer[512];
   1.273 +				::sprintf(buffer,"FindInstancesProcess finished. Found %i instances",pScene->mNumMeshes-numMeshesOut);
   1.274 +				DefaultLogger::get()->info(buffer); 
   1.275 +			}
   1.276 +			pScene->mNumMeshes = numMeshesOut;
   1.277 +		}
   1.278 +		else DefaultLogger::get()->debug("FindInstancesProcess finished. No instanced meshes found"); 
   1.279 +	}
   1.280 +}