vrshoot

diff libs/assimp/PretransformVertices.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/PretransformVertices.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,712 @@
     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 PretransformVertices.cpp
    1.46 + *  @brief Implementation of the "PretransformVertices" post processing step 
    1.47 +*/
    1.48 +
    1.49 +#include "AssimpPCH.h"
    1.50 +#include "PretransformVertices.h"
    1.51 +#include "ProcessHelper.h"
    1.52 +#include "SceneCombiner.h"
    1.53 +
    1.54 +using namespace Assimp;
    1.55 +
    1.56 +// some array offsets
    1.57 +#define AI_PTVS_VERTEX 0x0
    1.58 +#define AI_PTVS_FACE 0x1
    1.59 +
    1.60 +// ------------------------------------------------------------------------------------------------
    1.61 +// Constructor to be privately used by Importer
    1.62 +PretransformVertices::PretransformVertices()
    1.63 +:	configKeepHierarchy (false)
    1.64 +{
    1.65 +}
    1.66 +
    1.67 +// ------------------------------------------------------------------------------------------------
    1.68 +// Destructor, private as well
    1.69 +PretransformVertices::~PretransformVertices()
    1.70 +{
    1.71 +	// nothing to do here
    1.72 +}
    1.73 +
    1.74 +// ------------------------------------------------------------------------------------------------
    1.75 +// Returns whether the processing step is present in the given flag field.
    1.76 +bool PretransformVertices::IsActive( unsigned int pFlags) const
    1.77 +{
    1.78 +	return	(pFlags & aiProcess_PreTransformVertices) != 0;
    1.79 +}
    1.80 +
    1.81 +// ------------------------------------------------------------------------------------------------
    1.82 +// Setup import configuration
    1.83 +void PretransformVertices::SetupProperties(const Importer* pImp)
    1.84 +{
    1.85 +	// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY and AI_CONFIG_PP_PTV_NORMALIZE
    1.86 +	configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0));
    1.87 +	configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
    1.88 +}
    1.89 +
    1.90 +// ------------------------------------------------------------------------------------------------
    1.91 +// Count the number of nodes
    1.92 +unsigned int PretransformVertices::CountNodes( aiNode* pcNode )
    1.93 +{
    1.94 +	unsigned int iRet = 1;
    1.95 +	for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
    1.96 +	{
    1.97 +		iRet += CountNodes(pcNode->mChildren[i]);
    1.98 +	}
    1.99 +	return iRet;
   1.100 +}
   1.101 +
   1.102 +// ------------------------------------------------------------------------------------------------
   1.103 +// Get a bitwise combination identifying the vertex format of a mesh
   1.104 +unsigned int PretransformVertices::GetMeshVFormat(aiMesh* pcMesh)
   1.105 +{
   1.106 +	// the vertex format is stored in aiMesh::mBones for later retrieval.
   1.107 +	// there isn't a good reason to compute it a few hundred times
   1.108 +	// from scratch. The pointer is unused as animations are lost
   1.109 +	// during PretransformVertices.
   1.110 +	if (pcMesh->mBones)
   1.111 +		return (unsigned int)(uint64_t)pcMesh->mBones;
   1.112 +
   1.113 +
   1.114 +	const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
   1.115 +
   1.116 +	// store the value for later use
   1.117 +	pcMesh->mBones = (aiBone**)(uint64_t)iRet;
   1.118 +	return iRet;
   1.119 +}
   1.120 +
   1.121 +// ------------------------------------------------------------------------------------------------
   1.122 +// Count the number of vertices in the whole scene and a given
   1.123 +// material index
   1.124 +void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
   1.125 +	unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices)
   1.126 +{
   1.127 +	for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
   1.128 +	{
   1.129 +		aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; 
   1.130 +		if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
   1.131 +		{
   1.132 +			*piVertices += pcMesh->mNumVertices;
   1.133 +			*piFaces += pcMesh->mNumFaces;
   1.134 +		}
   1.135 +	}
   1.136 +	for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
   1.137 +	{
   1.138 +		CountVerticesAndFaces(pcScene,pcNode->mChildren[i],iMat,
   1.139 +			iVFormat,piFaces,piVertices);
   1.140 +	}
   1.141 +}
   1.142 +
   1.143 +// ------------------------------------------------------------------------------------------------
   1.144 +// Collect vertex/face data
   1.145 +void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
   1.146 +	unsigned int iVFormat, aiMesh* pcMeshOut, 
   1.147 +	unsigned int aiCurrent[2], unsigned int* num_refs)
   1.148 +{
   1.149 +	// No need to multiply if there's no transformation
   1.150 +	const bool identity = pcNode->mTransformation.IsIdentity();
   1.151 +	for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
   1.152 +	{
   1.153 +		aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; 
   1.154 +		if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
   1.155 +		{
   1.156 +			// Decrement mesh reference counter
   1.157 +			unsigned int& num_ref = num_refs[pcNode->mMeshes[i]];
   1.158 +			ai_assert(0 != num_ref);
   1.159 +			--num_ref;
   1.160 +
   1.161 +			if (identity)	{
   1.162 +				// copy positions without modifying them
   1.163 +				::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX],
   1.164 +					pcMesh->mVertices,
   1.165 +					pcMesh->mNumVertices * sizeof(aiVector3D));
   1.166 +
   1.167 +				if (iVFormat & 0x2) {
   1.168 +					// copy normals without modifying them
   1.169 +					::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX],
   1.170 +						pcMesh->mNormals,
   1.171 +						pcMesh->mNumVertices * sizeof(aiVector3D));
   1.172 +				}
   1.173 +				if (iVFormat & 0x4)
   1.174 +				{
   1.175 +					// copy tangents without modifying them
   1.176 +					::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX],
   1.177 +						pcMesh->mTangents,
   1.178 +						pcMesh->mNumVertices * sizeof(aiVector3D));
   1.179 +					// copy bitangents without modifying them
   1.180 +					::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX],
   1.181 +						pcMesh->mBitangents,
   1.182 +						pcMesh->mNumVertices * sizeof(aiVector3D));
   1.183 +				}
   1.184 +			}
   1.185 +			else
   1.186 +			{
   1.187 +				// copy positions, transform them to worldspace
   1.188 +				for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)	{
   1.189 +					pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n];
   1.190 +				}
   1.191 +				aiMatrix4x4 mWorldIT = pcNode->mTransformation;
   1.192 +				mWorldIT.Inverse().Transpose();
   1.193 +
   1.194 +				// TODO: implement Inverse() for aiMatrix3x3
   1.195 +				aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
   1.196 +
   1.197 +				if (iVFormat & 0x2)
   1.198 +				{
   1.199 +					// copy normals, transform them to worldspace
   1.200 +					for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)	{
   1.201 +						pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] = 
   1.202 +							(m * pcMesh->mNormals[n]).Normalize();
   1.203 +					}
   1.204 +				}
   1.205 +				if (iVFormat & 0x4)
   1.206 +				{
   1.207 +					// copy tangents and bitangents, transform them to worldspace
   1.208 +					for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)	{
   1.209 +						pcMeshOut->mTangents  [aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mTangents[n]).Normalize();
   1.210 +						pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize();
   1.211 +					}
   1.212 +				}
   1.213 +			}
   1.214 +			unsigned int p = 0;
   1.215 +			while (iVFormat & (0x100 << p))
   1.216 +			{
   1.217 +				// copy texture coordinates
   1.218 +				memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX],
   1.219 +					pcMesh->mTextureCoords[p],
   1.220 +					pcMesh->mNumVertices * sizeof(aiVector3D));
   1.221 +				++p;
   1.222 +			}
   1.223 +			p = 0;
   1.224 +			while (iVFormat & (0x1000000 << p))
   1.225 +			{
   1.226 +				// copy vertex colors
   1.227 +				memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX],
   1.228 +					pcMesh->mColors[p],
   1.229 +					pcMesh->mNumVertices * sizeof(aiColor4D));
   1.230 +				++p;
   1.231 +			}
   1.232 +			// now we need to copy all faces. since we will delete the source mesh afterwards,
   1.233 +			// we don't need to reallocate the array of indices except if this mesh is 
   1.234 +			// referenced multiple times.
   1.235 +			for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck)
   1.236 +			{
   1.237 +				aiFace& f_src = pcMesh->mFaces[planck];
   1.238 +				aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck];
   1.239 +
   1.240 +				const unsigned int num_idx = f_src.mNumIndices;
   1.241 +
   1.242 +				f_dst.mNumIndices = num_idx; 
   1.243 +
   1.244 +				unsigned int* pi;
   1.245 +				if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */
   1.246 +					pi = f_dst.mIndices = f_src.mIndices; 
   1.247 +
   1.248 +					// offset all vertex indices
   1.249 +					for (unsigned int hahn = 0; hahn < num_idx;++hahn){
   1.250 +						pi[hahn] += aiCurrent[AI_PTVS_VERTEX];
   1.251 +					}
   1.252 +				}
   1.253 +				else {
   1.254 +					pi = f_dst.mIndices = new unsigned int[num_idx];
   1.255 +					
   1.256 +					// copy and offset all vertex indices
   1.257 +					for (unsigned int hahn = 0; hahn < num_idx;++hahn){
   1.258 +						pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX];
   1.259 +					}
   1.260 +				}
   1.261 +
   1.262 +				// Update the mPrimitiveTypes member of the mesh
   1.263 +				switch (pcMesh->mFaces[planck].mNumIndices)
   1.264 +				{
   1.265 +				case 0x1:
   1.266 +					pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT;
   1.267 +					break;
   1.268 +				case 0x2:
   1.269 +					pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE;
   1.270 +					break;
   1.271 +				case 0x3:
   1.272 +					pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
   1.273 +					break;
   1.274 +				default:
   1.275 +					pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
   1.276 +					break;
   1.277 +				};
   1.278 +			}
   1.279 +			aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices;
   1.280 +			aiCurrent[AI_PTVS_FACE]   += pcMesh->mNumFaces;
   1.281 +		}
   1.282 +	}
   1.283 +
   1.284 +	// append all children of us
   1.285 +	for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
   1.286 +		CollectData(pcScene,pcNode->mChildren[i],iMat,
   1.287 +			iVFormat,pcMeshOut,aiCurrent,num_refs);
   1.288 +	}
   1.289 +}
   1.290 +
   1.291 +// ------------------------------------------------------------------------------------------------
   1.292 +// Get a list of all vertex formats that occur for a given material index
   1.293 +// The output list contains duplicate elements
   1.294 +void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat,
   1.295 +	std::list<unsigned int>& aiOut)
   1.296 +{
   1.297 +	for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
   1.298 +	{
   1.299 +		aiMesh* pcMesh = pcScene->mMeshes[ i ]; 
   1.300 +		if (iMat == pcMesh->mMaterialIndex)	{
   1.301 +			aiOut.push_back(GetMeshVFormat(pcMesh));
   1.302 +		}
   1.303 +	}
   1.304 +}
   1.305 +
   1.306 +// ------------------------------------------------------------------------------------------------
   1.307 +// Compute the absolute transformation matrices of each node
   1.308 +void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode )
   1.309 +{
   1.310 +	if (pcNode->mParent)	{
   1.311 +		pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation;
   1.312 +	}
   1.313 +
   1.314 +	for (unsigned int i = 0;i < pcNode->mNumChildren;++i)	{
   1.315 +		ComputeAbsoluteTransform(pcNode->mChildren[i]);
   1.316 +	}
   1.317 +}
   1.318 +
   1.319 +// ------------------------------------------------------------------------------------------------
   1.320 +// Apply the node transformation to a mesh
   1.321 +void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)
   1.322 +{
   1.323 +	// Check whether we need to transform the coordinates at all
   1.324 +	if (!mat.IsIdentity()) {
   1.325 +		
   1.326 +		if (mesh->HasPositions()) {
   1.327 +			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
   1.328 +				mesh->mVertices[i] = mat * mesh->mVertices[i];
   1.329 +			}
   1.330 +		}
   1.331 +		if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
   1.332 +			aiMatrix4x4 mWorldIT = mat;
   1.333 +			mWorldIT.Inverse().Transpose();
   1.334 +
   1.335 +			// TODO: implement Inverse() for aiMatrix3x3
   1.336 +			aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
   1.337 +
   1.338 +			if (mesh->HasNormals()) {
   1.339 +				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
   1.340 +					mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
   1.341 +				}
   1.342 +			}
   1.343 +			if (mesh->HasTangentsAndBitangents()) {
   1.344 +				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
   1.345 +					mesh->mTangents[i]   = (m * mesh->mTangents[i]).Normalize();
   1.346 +					mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
   1.347 +				}
   1.348 +			}
   1.349 +		}
   1.350 +	}
   1.351 +}
   1.352 +
   1.353 +// ------------------------------------------------------------------------------------------------
   1.354 +// Simple routine to build meshes in worldspace, no further optimization
   1.355 +void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in,
   1.356 +	unsigned int numIn, aiNode* node)
   1.357 +{
   1.358 +	// NOTE:
   1.359 +	//  aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy
   1.360 +	//  aiMesh::mBones store reference to abs. transform we multiplied with
   1.361 +
   1.362 +	// process meshes
   1.363 +	for (unsigned int i = 0; i < node->mNumMeshes;++i) {
   1.364 +		aiMesh* mesh = in[node->mMeshes[i]];
   1.365 +
   1.366 +		// check whether we can operate on this mesh
   1.367 +		if (!mesh->mBones || *reinterpret_cast<aiMatrix4x4*>(mesh->mBones) == node->mTransformation) {
   1.368 +			// yes, we can.
   1.369 +			mesh->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
   1.370 +			mesh->mNumBones = UINT_MAX;
   1.371 +		}
   1.372 +		else {
   1.373 +		
   1.374 +			// try to find us in the list of newly created meshes
   1.375 +			for (unsigned int n = 0; n < out.size(); ++n) {
   1.376 +				aiMesh* ctz = out[n];
   1.377 +				if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4*>(ctz->mBones) ==  node->mTransformation) {
   1.378 +					
   1.379 +					// ok, use this one. Update node mesh index
   1.380 +					node->mMeshes[i] = numIn + n;
   1.381 +				}
   1.382 +			}
   1.383 +			if (node->mMeshes[i] < numIn) {
   1.384 +				// Worst case. Need to operate on a full copy of the mesh
   1.385 +				DefaultLogger::get()->info("PretransformVertices: Copying mesh due to mismatching transforms");
   1.386 +				aiMesh* ntz;
   1.387 +
   1.388 +				const unsigned int tmp = mesh->mNumBones; //
   1.389 +				mesh->mNumBones = 0;
   1.390 +				SceneCombiner::Copy(&ntz,mesh);
   1.391 +				mesh->mNumBones = tmp;
   1.392 +
   1.393 +				ntz->mNumBones = node->mMeshes[i];
   1.394 +				ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
   1.395 +
   1.396 +				out.push_back(ntz);
   1.397 +			}
   1.398 +		}
   1.399 +	}
   1.400 +
   1.401 +	// call children
   1.402 +	for (unsigned int i = 0; i < node->mNumChildren;++i)
   1.403 +		BuildWCSMeshes(out,in,numIn,node->mChildren[i]);
   1.404 +}
   1.405 +
   1.406 +// ------------------------------------------------------------------------------------------------
   1.407 +// Reset transformation matrices to identity
   1.408 +void PretransformVertices::MakeIdentityTransform(aiNode* nd)
   1.409 +{
   1.410 +	nd->mTransformation = aiMatrix4x4();
   1.411 +
   1.412 +	// call children
   1.413 +	for (unsigned int i = 0; i < nd->mNumChildren;++i)
   1.414 +		MakeIdentityTransform(nd->mChildren[i]);
   1.415 +}
   1.416 +
   1.417 +// ------------------------------------------------------------------------------------------------
   1.418 +// Build reference counters for all meshes
   1.419 +void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs)
   1.420 +{
   1.421 +	for (unsigned int i = 0; i< nd->mNumMeshes;++i)
   1.422 +		refs[nd->mMeshes[i]]++;
   1.423 +
   1.424 +	// call children
   1.425 +	for (unsigned int i = 0; i < nd->mNumChildren;++i)
   1.426 +		BuildMeshRefCountArray(nd->mChildren[i],refs);
   1.427 +}
   1.428 +
   1.429 +// ------------------------------------------------------------------------------------------------
   1.430 +// Executes the post processing step on the given imported data.
   1.431 +void PretransformVertices::Execute( aiScene* pScene)
   1.432 +{
   1.433 +	DefaultLogger::get()->debug("PretransformVerticesProcess begin");
   1.434 +
   1.435 +	// Return immediately if we have no meshes
   1.436 +	if (!pScene->mNumMeshes)
   1.437 +		return;
   1.438 +
   1.439 +	const unsigned int iOldMeshes = pScene->mNumMeshes;
   1.440 +	const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
   1.441 +	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
   1.442 +
   1.443 +	// first compute absolute transformation matrices for all nodes
   1.444 +	ComputeAbsoluteTransform(pScene->mRootNode);
   1.445 +
   1.446 +	// Delete aiMesh::mBones for all meshes. The bones are
   1.447 +	// removed during this step and we need the pointer as
   1.448 +	// temporary storage
   1.449 +	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)	{
   1.450 +		aiMesh* mesh = pScene->mMeshes[i];
   1.451 +
   1.452 +		for (unsigned int a = 0; a < mesh->mNumBones;++a)
   1.453 +			delete mesh->mBones[a];
   1.454 +
   1.455 +		delete[] mesh->mBones;
   1.456 +		mesh->mBones = NULL;
   1.457 +	}
   1.458 +
   1.459 +	// now build a list of output meshes
   1.460 +	std::vector<aiMesh*> apcOutMeshes;
   1.461 +
   1.462 +	// Keep scene hierarchy? It's an easy job in this case ...
   1.463 +	// we go on and transform all meshes, if one is referenced by nodes
   1.464 +	// with different absolute transformations a depth copy of the mesh
   1.465 +	// is required.
   1.466 +	if( configKeepHierarchy ) {
   1.467 +
   1.468 +		// Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
   1.469 +		BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode);
   1.470 +
   1.471 +		// ... if new meshes have been generated, append them to the end of the scene
   1.472 +		if (apcOutMeshes.size() > 0) {
   1.473 +			aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()];
   1.474 +
   1.475 +			memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes);
   1.476 +			memcpy(npp+pScene->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size());
   1.477 +
   1.478 +			pScene->mNumMeshes  += apcOutMeshes.size();
   1.479 +			delete[] pScene->mMeshes; pScene->mMeshes = npp;
   1.480 +		}
   1.481 +
   1.482 +		// now iterate through all meshes and transform them to worldspace
   1.483 +		for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
   1.484 +			ApplyTransform(pScene->mMeshes[i],*reinterpret_cast<aiMatrix4x4*>( pScene->mMeshes[i]->mBones ));
   1.485 +
   1.486 +			// prevent improper destruction
   1.487 +			pScene->mMeshes[i]->mBones    = NULL;
   1.488 +			pScene->mMeshes[i]->mNumBones = 0;
   1.489 +		}
   1.490 +	}
   1.491 +	else {
   1.492 +
   1.493 +		apcOutMeshes.reserve(pScene->mNumMaterials<<1u);
   1.494 +		std::list<unsigned int> aiVFormats;
   1.495 +
   1.496 +		std::vector<unsigned int> s(pScene->mNumMeshes,0);
   1.497 +		BuildMeshRefCountArray(pScene->mRootNode,&s[0]);
   1.498 +
   1.499 +		for (unsigned int i = 0; i < pScene->mNumMaterials;++i)		{
   1.500 +			// get the list of all vertex formats for this material
   1.501 +			aiVFormats.clear();
   1.502 +			GetVFormatList(pScene,i,aiVFormats);
   1.503 +			aiVFormats.sort();
   1.504 +			aiVFormats.unique();
   1.505 +			for (std::list<unsigned int>::const_iterator j =  aiVFormats.begin();j != aiVFormats.end();++j)	{
   1.506 +				unsigned int iVertices = 0;
   1.507 +				unsigned int iFaces = 0; 
   1.508 +				CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices);
   1.509 +				if (0 != iFaces && 0 != iVertices)
   1.510 +				{
   1.511 +					apcOutMeshes.push_back(new aiMesh());
   1.512 +					aiMesh* pcMesh = apcOutMeshes.back();
   1.513 +					pcMesh->mNumFaces = iFaces;
   1.514 +					pcMesh->mNumVertices = iVertices;
   1.515 +					pcMesh->mFaces = new aiFace[iFaces];
   1.516 +					pcMesh->mVertices = new aiVector3D[iVertices];
   1.517 +					pcMesh->mMaterialIndex = i;
   1.518 +					if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices];
   1.519 +					if ((*j) & 0x4)
   1.520 +					{
   1.521 +						pcMesh->mTangents    = new aiVector3D[iVertices];
   1.522 +						pcMesh->mBitangents  = new aiVector3D[iVertices];
   1.523 +					}
   1.524 +					iFaces = 0;
   1.525 +					while ((*j) & (0x100 << iFaces))
   1.526 +					{
   1.527 +						pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
   1.528 +						if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3;
   1.529 +						else pcMesh->mNumUVComponents[iFaces] = 2;
   1.530 +						iFaces++;
   1.531 +					}
   1.532 +					iFaces = 0;
   1.533 +					while ((*j) & (0x1000000 << iFaces))
   1.534 +						pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
   1.535 +
   1.536 +					// fill the mesh ...
   1.537 +					unsigned int aiTemp[2] = {0,0};
   1.538 +					CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]);
   1.539 +				}
   1.540 +			}
   1.541 +		}
   1.542 +
   1.543 +		// If no meshes are referenced in the node graph it is possible that we get no output meshes. 
   1.544 +		if (apcOutMeshes.empty())	{		
   1.545 +			throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes");
   1.546 +		}
   1.547 +		else
   1.548 +		{
   1.549 +			// now delete all meshes in the scene and build a new mesh list
   1.550 +			for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
   1.551 +			{
   1.552 +				aiMesh* mesh = pScene->mMeshes[i];
   1.553 +				mesh->mNumBones = 0;
   1.554 +				mesh->mBones    = NULL;
   1.555 +
   1.556 +				// we're reusing the face index arrays. avoid destruction
   1.557 +				for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
   1.558 +					mesh->mFaces[a].mNumIndices = 0;
   1.559 +					mesh->mFaces[a].mIndices = NULL;
   1.560 +				}
   1.561 +
   1.562 +				delete mesh;
   1.563 +
   1.564 +				// Invalidate the contents of the old mesh array. We will most
   1.565 +				// likely have less output meshes now, so the last entries of 
   1.566 +				// the mesh array are not overridden. We set them to NULL to 
   1.567 +				// make sure the developer gets notified when his application
   1.568 +				// attempts to access these fields ...
   1.569 +				mesh = NULL;
   1.570 +			}
   1.571 +
   1.572 +			// It is impossible that we have more output meshes than 
   1.573 +			// input meshes, so we can easily reuse the old mesh array
   1.574 +			pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
   1.575 +			for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
   1.576 +				pScene->mMeshes[i] = apcOutMeshes[i];
   1.577 +			}
   1.578 +		}
   1.579 +	}
   1.580 +
   1.581 +	// remove all animations from the scene
   1.582 +	for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
   1.583 +		delete pScene->mAnimations[i];
   1.584 +	delete[] pScene->mAnimations;
   1.585 +
   1.586 +	pScene->mAnimations    = NULL;
   1.587 +	pScene->mNumAnimations = 0;
   1.588 +
   1.589 +	// --- we need to keep all cameras and lights 
   1.590 +	for (unsigned int i = 0; i < pScene->mNumCameras;++i)
   1.591 +	{
   1.592 +		aiCamera* cam = pScene->mCameras[i];
   1.593 +		const aiNode* nd = pScene->mRootNode->FindNode(cam->mName);
   1.594 +		ai_assert(NULL != nd);
   1.595 +
   1.596 +		// multiply all properties of the camera with the absolute
   1.597 +		// transformation of the corresponding node
   1.598 +		cam->mPosition = nd->mTransformation * cam->mPosition;
   1.599 +		cam->mLookAt   = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt;
   1.600 +		cam->mUp       = aiMatrix3x3( nd->mTransformation ) * cam->mUp;
   1.601 +	}
   1.602 +
   1.603 +	for (unsigned int i = 0; i < pScene->mNumLights;++i)
   1.604 +	{
   1.605 +		aiLight* l = pScene->mLights[i];
   1.606 +		const aiNode* nd = pScene->mRootNode->FindNode(l->mName);
   1.607 +		ai_assert(NULL != nd);
   1.608 +
   1.609 +		// multiply all properties of the camera with the absolute
   1.610 +		// transformation of the corresponding node
   1.611 +		l->mPosition   = nd->mTransformation * l->mPosition;
   1.612 +		l->mDirection  = aiMatrix3x3( nd->mTransformation ) * l->mDirection;
   1.613 +	}
   1.614 +
   1.615 +	if( !configKeepHierarchy ) {
   1.616 +
   1.617 +		// now delete all nodes in the scene and build a new
   1.618 +		// flat node graph with a root node and some level 1 children
   1.619 +		delete pScene->mRootNode;
   1.620 +		pScene->mRootNode = new aiNode();
   1.621 +		pScene->mRootNode->mName.Set("<dummy_root>");
   1.622 +
   1.623 +		if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras)
   1.624 +		{
   1.625 +			pScene->mRootNode->mNumMeshes = 1;
   1.626 +			pScene->mRootNode->mMeshes = new unsigned int[1];
   1.627 +			pScene->mRootNode->mMeshes[0] = 0;
   1.628 +		}
   1.629 +		else
   1.630 +		{
   1.631 +			pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras;
   1.632 +			aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
   1.633 +
   1.634 +			// generate mesh nodes
   1.635 +			for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
   1.636 +			{
   1.637 +				aiNode* pcNode = *nodes = new aiNode();
   1.638 +				pcNode->mParent = pScene->mRootNode;
   1.639 +				pcNode->mName.length = ::sprintf(pcNode->mName.data,"mesh_%i",i);
   1.640 +
   1.641 +				// setup mesh indices
   1.642 +				pcNode->mNumMeshes = 1;
   1.643 +				pcNode->mMeshes = new unsigned int[1];
   1.644 +				pcNode->mMeshes[0] = i;
   1.645 +			}
   1.646 +			// generate light nodes
   1.647 +			for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
   1.648 +			{
   1.649 +				aiNode* pcNode = *nodes = new aiNode();
   1.650 +				pcNode->mParent = pScene->mRootNode;
   1.651 +				pcNode->mName.length = ::sprintf(pcNode->mName.data,"light_%i",i);
   1.652 +				pScene->mLights[i]->mName = pcNode->mName;
   1.653 +			}
   1.654 +			// generate camera nodes
   1.655 +			for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
   1.656 +			{
   1.657 +				aiNode* pcNode = *nodes = new aiNode();
   1.658 +				pcNode->mParent = pScene->mRootNode;
   1.659 +				pcNode->mName.length = ::sprintf(pcNode->mName.data,"cam_%i",i);
   1.660 +				pScene->mCameras[i]->mName = pcNode->mName;
   1.661 +			}
   1.662 +		}
   1.663 +	}
   1.664 +	else {
   1.665 +		// ... and finally set the transformation matrix of all nodes to identity
   1.666 +		MakeIdentityTransform(pScene->mRootNode);
   1.667 +	}
   1.668 +
   1.669 +	if (configNormalize) {
   1.670 +		// compute the boundary of all meshes
   1.671 +		aiVector3D min,max;
   1.672 +		MinMaxChooser<aiVector3D> ()(min,max);
   1.673 +
   1.674 +		for (unsigned int a = 0; a <  pScene->mNumMeshes; ++a) {
   1.675 +			aiMesh* m = pScene->mMeshes[a];
   1.676 +			for (unsigned int i = 0; i < m->mNumVertices;++i) {
   1.677 +				min = std::min(m->mVertices[i],min);
   1.678 +				max = std::max(m->mVertices[i],max);
   1.679 +			}
   1.680 +		}
   1.681 +
   1.682 +		// find the dominant axis
   1.683 +		aiVector3D d = max-min;
   1.684 +		const float div = std::max(d.x,std::max(d.y,d.z))*0.5f;
   1.685 +	
   1.686 +		d = min+d*0.5f;
   1.687 +		for (unsigned int a = 0; a <  pScene->mNumMeshes; ++a) {
   1.688 +			aiMesh* m = pScene->mMeshes[a];
   1.689 +			for (unsigned int i = 0; i < m->mNumVertices;++i) {
   1.690 +				m->mVertices[i] = (m->mVertices[i]-d)/div;
   1.691 +			}
   1.692 +		}
   1.693 +	}
   1.694 +
   1.695 +	// print statistics
   1.696 +	if (!DefaultLogger::isNullLogger())
   1.697 +	{
   1.698 +		char buffer[4096];
   1.699 +
   1.700 +		DefaultLogger::get()->debug("PretransformVerticesProcess finished");
   1.701 +
   1.702 +		sprintf(buffer,"Removed %i nodes and %i animation channels (%i output nodes)",
   1.703 +			iOldNodes,iOldAnimationChannels,CountNodes(pScene->mRootNode));
   1.704 +		DefaultLogger::get()->info(buffer);
   1.705 +
   1.706 +		sprintf(buffer,"Kept %i lights and %i cameras",
   1.707 +			pScene->mNumLights,pScene->mNumCameras);
   1.708 +		DefaultLogger::get()->info(buffer);
   1.709 +
   1.710 +		sprintf(buffer,"Moved %i meshes to WCS (number of output meshes: %i)",
   1.711 +			iOldMeshes,pScene->mNumMeshes);
   1.712 +		DefaultLogger::get()->info(buffer);
   1.713 +	}
   1.714 +}
   1.715 +