vrshoot

diff libs/assimp/SceneCombiner.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/SceneCombiner.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,1146 @@
     1.4 +/*
     1.5 +Open Asset Import Library (assimp)
     1.6 +----------------------------------------------------------------------
     1.7 +
     1.8 +Copyright (c) 2006-2012, assimp team
     1.9 +All rights reserved.
    1.10 +
    1.11 +Redistribution and use of this software in source and binary forms, 
    1.12 +with or without modification, are permitted provided that the 
    1.13 +following conditions are met:
    1.14 +
    1.15 +* Redistributions of source code must retain the above
    1.16 +  copyright notice, this list of conditions and the
    1.17 +  following disclaimer.
    1.18 +
    1.19 +* Redistributions in binary form must reproduce the above
    1.20 +  copyright notice, this list of conditions and the
    1.21 +  following disclaimer in the documentation and/or other
    1.22 +  materials provided with the distribution.
    1.23 +
    1.24 +* Neither the name of the assimp team, nor the names of its
    1.25 +  contributors may be used to endorse or promote products
    1.26 +  derived from this software without specific prior
    1.27 +  written permission of the assimp team.
    1.28 +
    1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
    1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.40 +
    1.41 +----------------------------------------------------------------------
    1.42 +*/
    1.43 +
    1.44 +
    1.45 +// ----------------------------------------------------------------------------
    1.46 +/** @file Implements Assimp::SceneCombiner. This is a smart utility
    1.47 + *    class that combines multiple scenes, meshes, ... into one. Currently 
    1.48 + *    these utilities are used by the IRR and LWS loaders and the
    1.49 + *    OptimizeGraph step.
    1.50 + */
    1.51 +// ----------------------------------------------------------------------------
    1.52 +#include "AssimpPCH.h"
    1.53 +#include "SceneCombiner.h"
    1.54 +#include "fast_atof.h"
    1.55 +#include "Hash.h"
    1.56 +#include "time.h"
    1.57 +
    1.58 +namespace Assimp	{
    1.59 +
    1.60 +// ------------------------------------------------------------------------------------------------
    1.61 +// Add a prefix to a string
    1.62 +inline void PrefixString(aiString& string,const char* prefix, unsigned int len)
    1.63 +{
    1.64 +	// If the string is already prefixed, we won't prefix it a second time
    1.65 +	if (string.length >= 1 && string.data[0] == '$')
    1.66 +		return;
    1.67 +
    1.68 +	if (len+string.length>=MAXLEN-1) {
    1.69 +		DefaultLogger::get()->debug("Can't add an unique prefix because the string is too long");
    1.70 +		ai_assert(false);
    1.71 +		return;
    1.72 +	}
    1.73 +
    1.74 +	// Add the prefix
    1.75 +	::memmove(string.data+len,string.data,string.length+1);
    1.76 +	::memcpy (string.data, prefix, len);
    1.77 +
    1.78 +	// And update the string's length
    1.79 +	string.length += len;
    1.80 +}
    1.81 +
    1.82 +// ------------------------------------------------------------------------------------------------
    1.83 +// Add node identifiers to a hashing set
    1.84 +void SceneCombiner::AddNodeHashes(aiNode* node, std::set<unsigned int>& hashes)
    1.85 +{
    1.86 +	// Add node name to hashing set if it is non-empty - empty nodes are allowed 
    1.87 +	// and they can't have any anims assigned so its absolutely safe to duplicate them.
    1.88 +	if (node->mName.length) {
    1.89 +		hashes.insert( SuperFastHash(node->mName.data,node->mName.length) );
    1.90 +	}
    1.91 +
    1.92 +	// Process all children recursively
    1.93 +	for (unsigned int i = 0; i < node->mNumChildren;++i)
    1.94 +		AddNodeHashes(node->mChildren[i],hashes);
    1.95 +}
    1.96 +
    1.97 +// ------------------------------------------------------------------------------------------------
    1.98 +// Add a name prefix to all nodes in a hierarchy
    1.99 +void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len)
   1.100 +{
   1.101 +	ai_assert(NULL != prefix);
   1.102 +	PrefixString(node->mName,prefix,len);
   1.103 +
   1.104 +	// Process all children recursively
   1.105 +	for (unsigned int i = 0; i < node->mNumChildren;++i)
   1.106 +		AddNodePrefixes(node->mChildren[i],prefix,len);
   1.107 +}
   1.108 +
   1.109 +// ------------------------------------------------------------------------------------------------
   1.110 +// Search for matching names
   1.111 +bool SceneCombiner::FindNameMatch(const aiString& name, std::vector<SceneHelper>& input, unsigned int cur)
   1.112 +{
   1.113 +	const unsigned int hash = SuperFastHash(name.data, name.length);
   1.114 +
   1.115 +	// Check whether we find a positive match in one of the given sets
   1.116 +	for (unsigned int i = 0; i < input.size(); ++i) {
   1.117 +
   1.118 +		if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) {
   1.119 +			return true;
   1.120 +		}
   1.121 +	}
   1.122 +	return false;
   1.123 +}
   1.124 +
   1.125 +// ------------------------------------------------------------------------------------------------
   1.126 +// Add a name prefix to all nodes in a hierarchy if a hash match is found
   1.127 +void SceneCombiner::AddNodePrefixesChecked(aiNode* node, const char* prefix, unsigned int len,
   1.128 +	std::vector<SceneHelper>& input, unsigned int cur)
   1.129 +{
   1.130 +	ai_assert(NULL != prefix);
   1.131 +	const unsigned int hash = SuperFastHash(node->mName.data,node->mName.length);
   1.132 +
   1.133 +	// Check whether we find a positive match in one of the given sets
   1.134 +	for (unsigned int i = 0; i < input.size(); ++i) {
   1.135 +
   1.136 +		if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) {
   1.137 +			PrefixString(node->mName,prefix,len);
   1.138 +			break;
   1.139 +		}
   1.140 +	}
   1.141 +
   1.142 +	// Process all children recursively
   1.143 +	for (unsigned int i = 0; i < node->mNumChildren;++i)
   1.144 +		AddNodePrefixesChecked(node->mChildren[i],prefix,len,input,cur);
   1.145 +}
   1.146 +
   1.147 +// ------------------------------------------------------------------------------------------------
   1.148 +// Add an offset to all mesh indices in a node graph
   1.149 +void SceneCombiner::OffsetNodeMeshIndices (aiNode* node, unsigned int offset)
   1.150 +{
   1.151 +	for (unsigned int i = 0; i < node->mNumMeshes;++i)
   1.152 +		node->mMeshes[i] += offset;
   1.153 +
   1.154 +	for (unsigned int i = 0; i < node->mNumChildren;++i)
   1.155 +		OffsetNodeMeshIndices(node->mChildren[i],offset);
   1.156 +}
   1.157 +
   1.158 +// ------------------------------------------------------------------------------------------------
   1.159 +// Merges two scenes. Currently only used by the LWS loader.
   1.160 +void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src,
   1.161 +	unsigned int flags)
   1.162 +{
   1.163 +	ai_assert(NULL != _dest);
   1.164 +
   1.165 +	// if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
   1.166 +	if (src.empty())
   1.167 +	{
   1.168 +		if (*_dest)
   1.169 +		{
   1.170 +			(*_dest)->~aiScene();
   1.171 +			SceneCombiner::CopySceneFlat(_dest,src[0]);
   1.172 +		}
   1.173 +		else *_dest = src[0];
   1.174 +		return;
   1.175 +	}
   1.176 +	if (*_dest)(*_dest)->~aiScene();
   1.177 +	else *_dest = new aiScene();
   1.178 +
   1.179 +	// Create a dummy scene to serve as master for the others
   1.180 +	aiScene* master = new aiScene();
   1.181 +	master->mRootNode = new aiNode();
   1.182 +	master->mRootNode->mName.Set("<MergeRoot>");
   1.183 +
   1.184 +	std::vector<AttachmentInfo> srcList (src.size());
   1.185 +	for (unsigned int i = 0; i < srcList.size();++i)	{
   1.186 +		srcList[i] = AttachmentInfo(src[i],master->mRootNode);
   1.187 +	}
   1.188 +
   1.189 +	// 'master' will be deleted afterwards
   1.190 +	MergeScenes (_dest, master, srcList, flags);
   1.191 +}
   1.192 +
   1.193 +// ------------------------------------------------------------------------------------------------
   1.194 +void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInfo>& srcList)
   1.195 +{
   1.196 +	unsigned int cnt;
   1.197 +	for (cnt = 0; cnt < attach->mNumChildren;++cnt)
   1.198 +		AttachToGraph(attach->mChildren[cnt],srcList);
   1.199 +
   1.200 +	cnt = 0;
   1.201 +	for (std::vector<NodeAttachmentInfo>::iterator it = srcList.begin();
   1.202 +		 it != srcList.end(); ++it)
   1.203 +	{
   1.204 +		if ((*it).attachToNode == attach && !(*it).resolved)
   1.205 +			++cnt;
   1.206 +	}
   1.207 +
   1.208 +	if (cnt)	{
   1.209 +		aiNode** n = new aiNode*[cnt+attach->mNumChildren];
   1.210 +		if (attach->mNumChildren)	{
   1.211 +			::memcpy(n,attach->mChildren,sizeof(void*)*attach->mNumChildren);
   1.212 +			delete[] attach->mChildren;
   1.213 +		}
   1.214 +		attach->mChildren = n;
   1.215 +
   1.216 +		n += attach->mNumChildren;
   1.217 +		attach->mNumChildren += cnt;
   1.218 +
   1.219 +		for (unsigned int i = 0; i < srcList.size();++i)	{
   1.220 +			NodeAttachmentInfo& att = srcList[i];
   1.221 +			if (att.attachToNode == attach && !att.resolved)	{
   1.222 +				*n = att.node;
   1.223 +				(**n).mParent = attach;
   1.224 +				++n;
   1.225 +
   1.226 +				// mark this attachment as resolved
   1.227 +				att.resolved = true;
   1.228 +			}
   1.229 +		}
   1.230 +	}
   1.231 +}
   1.232 +
   1.233 +// ------------------------------------------------------------------------------------------------
   1.234 +void SceneCombiner::AttachToGraph ( aiScene* master, 
   1.235 +	std::vector<NodeAttachmentInfo>& src)
   1.236 +{
   1.237 +	ai_assert(NULL != master);
   1.238 +	AttachToGraph(master->mRootNode,src);
   1.239 +}
   1.240 +
   1.241 +// ------------------------------------------------------------------------------------------------
   1.242 +void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, 
   1.243 +	std::vector<AttachmentInfo>& srcList,
   1.244 +	unsigned int flags)
   1.245 +{
   1.246 +	ai_assert(NULL != _dest);
   1.247 +
   1.248 +	// if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
   1.249 +	if (srcList.empty())	{
   1.250 +		if (*_dest)	{
   1.251 +			SceneCombiner::CopySceneFlat(_dest,master);
   1.252 +		}
   1.253 +		else *_dest = master;
   1.254 +		return;
   1.255 +	}
   1.256 +	if (*_dest) {
   1.257 +		(*_dest)->~aiScene();
   1.258 +		new (*_dest) aiScene();
   1.259 +	}
   1.260 +	else *_dest = new aiScene();
   1.261 +
   1.262 +	aiScene* dest = *_dest;
   1.263 +
   1.264 +	std::vector<SceneHelper> src (srcList.size()+1);
   1.265 +	src[0].scene = master;
   1.266 +	for (unsigned int i = 0; i < srcList.size();++i)	{
   1.267 +		src[i+1] = SceneHelper( srcList[i].scene );
   1.268 +	}
   1.269 +
   1.270 +	// this helper array specifies which scenes are duplicates of others
   1.271 +	std::vector<unsigned int> duplicates(src.size(),UINT_MAX);
   1.272 +
   1.273 +	// this helper array is used as lookup table several times
   1.274 +	std::vector<unsigned int> offset(src.size());
   1.275 +
   1.276 +	// Find duplicate scenes
   1.277 +	for (unsigned int i = 0; i < src.size();++i) {
   1.278 +		if (duplicates[i] != i && duplicates[i] != UINT_MAX) {
   1.279 +			continue;
   1.280 +		}
   1.281 +			
   1.282 +		duplicates[i] = i;
   1.283 +		for ( unsigned int a = i+1; a < src.size(); ++a)	{
   1.284 +			if (src[i].scene == src[a].scene) {
   1.285 +				duplicates[a] = i;
   1.286 +			}
   1.287 +		}
   1.288 +	}
   1.289 +
   1.290 +	// Generate unique names for all named stuff?
   1.291 +	if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES)
   1.292 +	{
   1.293 +#if 0
   1.294 +		// Construct a proper random number generator
   1.295 +		boost::mt19937 rng(  );
   1.296 +		boost::uniform_int<> dist(1u,1 << 24u);
   1.297 +		boost::variate_generator<boost::mt19937&, boost::uniform_int<> > rndGen(rng, dist);   
   1.298 +#endif
   1.299 +		for (unsigned int i = 1; i < src.size();++i)
   1.300 +		{
   1.301 +			//if (i != duplicates[i]) 
   1.302 +			//{
   1.303 +			//	// duplicate scenes share the same UID
   1.304 +			//	::strcpy( src[i].id, src[duplicates[i]].id );
   1.305 +			//	src[i].idlen = src[duplicates[i]].idlen;
   1.306 +
   1.307 +			//	continue;
   1.308 +			//}
   1.309 +
   1.310 +			src[i].idlen = ::sprintf(src[i].id,"$%.6X$_",i);
   1.311 +
   1.312 +			if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
   1.313 +				
   1.314 +				// Compute hashes for all identifiers in this scene and store them
   1.315 +				// in a sorted table (for convenience I'm using std::set). We hash
   1.316 +				// just the node and animation channel names, all identifiers except
   1.317 +				// the material names should be caught by doing this.
   1.318 +				AddNodeHashes(src[i]->mRootNode,src[i].hashes);
   1.319 +
   1.320 +				for (unsigned int a = 0; a < src[i]->mNumAnimations;++a) {
   1.321 +					aiAnimation* anim = src[i]->mAnimations[a];
   1.322 +					src[i].hashes.insert(SuperFastHash(anim->mName.data,anim->mName.length));
   1.323 +				}
   1.324 +			}
   1.325 +		}
   1.326 +	}
   1.327 +	
   1.328 +	unsigned int cnt;
   1.329 +
   1.330 +	// First find out how large the respective output arrays must be
   1.331 +	for ( unsigned int n = 0; n < src.size();++n )
   1.332 +	{
   1.333 +		SceneHelper* cur = &src[n];
   1.334 +
   1.335 +		if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)	{
   1.336 +			dest->mNumTextures   += (*cur)->mNumTextures;
   1.337 +			dest->mNumMaterials  += (*cur)->mNumMaterials;
   1.338 +			dest->mNumMeshes     += (*cur)->mNumMeshes;
   1.339 +		}
   1.340 +
   1.341 +		dest->mNumLights     += (*cur)->mNumLights;
   1.342 +		dest->mNumCameras    += (*cur)->mNumCameras;
   1.343 +		dest->mNumAnimations += (*cur)->mNumAnimations;
   1.344 +
   1.345 +		// Combine the flags of all scenes
   1.346 +		// We need to process them flag-by-flag here to get correct results
   1.347 +		// dest->mFlags ; //|= (*cur)->mFlags;
   1.348 +		if ((*cur)->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
   1.349 +			dest->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
   1.350 +		}
   1.351 +	}
   1.352 +
   1.353 +	// generate the output texture list + an offset table for all texture indices
   1.354 +	if (dest->mNumTextures)
   1.355 +	{
   1.356 +		aiTexture** pip = dest->mTextures = new aiTexture*[dest->mNumMaterials];
   1.357 +		cnt = 0;
   1.358 +		for ( unsigned int n = 0; n < src.size();++n )
   1.359 +		{
   1.360 +			SceneHelper* cur = &src[n];
   1.361 +			for (unsigned int i = 0; i < (*cur)->mNumTextures;++i)
   1.362 +			{
   1.363 +				if (n != duplicates[n])
   1.364 +				{
   1.365 +					if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
   1.366 +						Copy(pip,(*cur)->mTextures[i]);
   1.367 +
   1.368 +					else continue;
   1.369 +				}
   1.370 +				else *pip = (*cur)->mTextures[i];
   1.371 +				++pip;
   1.372 +			}
   1.373 +
   1.374 +			offset[n] = cnt;
   1.375 +			cnt = (unsigned int)(pip - dest->mTextures);
   1.376 +		}
   1.377 +	}
   1.378 +
   1.379 +	// generate the output material list + an offset table for all material indices
   1.380 +	if (dest->mNumMaterials)
   1.381 +	{ 
   1.382 +		aiMaterial** pip = dest->mMaterials = new aiMaterial*[dest->mNumMaterials];
   1.383 +		cnt = 0;
   1.384 +		for ( unsigned int n = 0; n < src.size();++n )	{
   1.385 +			SceneHelper* cur = &src[n];
   1.386 +			for (unsigned int i = 0; i < (*cur)->mNumMaterials;++i)
   1.387 +			{
   1.388 +				if (n != duplicates[n])
   1.389 +				{
   1.390 +					if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
   1.391 +						Copy(pip,(*cur)->mMaterials[i]);
   1.392 +
   1.393 +					else continue;
   1.394 +				}
   1.395 +				else *pip = (*cur)->mMaterials[i];
   1.396 +
   1.397 +				if ((*cur)->mNumTextures != dest->mNumTextures)		{
   1.398 +					// We need to update all texture indices of the mesh. So we need to search for
   1.399 +					// a material property called '$tex.file'
   1.400 +
   1.401 +					for (unsigned int a = 0; a < (*pip)->mNumProperties;++a)
   1.402 +					{
   1.403 +						aiMaterialProperty* prop = (*pip)->mProperties[a];
   1.404 +						if (!strncmp(prop->mKey.data,"$tex.file",9))
   1.405 +						{
   1.406 +							// Check whether this texture is an embedded texture.
   1.407 +							// In this case the property looks like this: *<n>,
   1.408 +							// where n is the index of the texture.
   1.409 +							aiString& s = *((aiString*)prop->mData);
   1.410 +							if ('*' == s.data[0])	{
   1.411 +								// Offset the index and write it back ..
   1.412 +								const unsigned int idx = strtoul10(&s.data[1]) + offset[n];
   1.413 +								ASSIMP_itoa10(&s.data[1],sizeof(s.data)-1,idx);
   1.414 +							}
   1.415 +						}
   1.416 +
   1.417 +						// Need to generate new, unique material names?
   1.418 +						else if (!::strcmp( prop->mKey.data,"$mat.name" ) && flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES)
   1.419 +						{
   1.420 +							aiString* pcSrc = (aiString*) prop->mData; 
   1.421 +							PrefixString(*pcSrc, (*cur).id, (*cur).idlen);
   1.422 +						}
   1.423 +					}
   1.424 +				}
   1.425 +				++pip;
   1.426 +			}
   1.427 +
   1.428 +			offset[n] = cnt;
   1.429 +			cnt = (unsigned int)(pip - dest->mMaterials);
   1.430 +		}
   1.431 +	}
   1.432 +
   1.433 +	// generate the output mesh list + again an offset table for all mesh indices
   1.434 +	if (dest->mNumMeshes)
   1.435 +	{
   1.436 +		aiMesh** pip = dest->mMeshes = new aiMesh*[dest->mNumMeshes];
   1.437 +		cnt = 0;
   1.438 +		for ( unsigned int n = 0; n < src.size();++n )
   1.439 +		{
   1.440 +			SceneHelper* cur = &src[n];
   1.441 +			for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i)
   1.442 +			{
   1.443 +				if (n != duplicates[n])	{
   1.444 +					if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
   1.445 +						Copy(pip, (*cur)->mMeshes[i]);
   1.446 +
   1.447 +					else continue;
   1.448 +				}
   1.449 +				else *pip = (*cur)->mMeshes[i];
   1.450 +
   1.451 +				// update the material index of the mesh
   1.452 +				(*pip)->mMaterialIndex +=  offset[n];
   1.453 +				++pip;
   1.454 +			}
   1.455 +
   1.456 +			// reuse the offset array - store now the mesh offset in it
   1.457 +			offset[n] = cnt;
   1.458 +			cnt = (unsigned int)(pip - dest->mMeshes);
   1.459 +		}
   1.460 +	}
   1.461 +
   1.462 +	std::vector <NodeAttachmentInfo> nodes;
   1.463 +	nodes.reserve(srcList.size());
   1.464 +
   1.465 +	// ----------------------------------------------------------------------------
   1.466 +	// Now generate the output node graph. We need to make those
   1.467 +	// names in the graph that are referenced by anims or lights
   1.468 +	// or cameras unique. So we add a prefix to them ... $<rand>_
   1.469 +	// We could also use a counter, but using a random value allows us to
   1.470 +	// use just one prefix if we are joining multiple scene hierarchies recursively.
   1.471 +	// Chances are quite good we don't collide, so we try that ...
   1.472 +	// ----------------------------------------------------------------------------
   1.473 +
   1.474 +	// Allocate space for light sources, cameras and animations
   1.475 +	aiLight** ppLights = dest->mLights = (dest->mNumLights 
   1.476 +		? new aiLight*[dest->mNumLights] : NULL);
   1.477 +
   1.478 +	aiCamera** ppCameras = dest->mCameras = (dest->mNumCameras 
   1.479 +		? new aiCamera*[dest->mNumCameras] : NULL);
   1.480 +
   1.481 +	aiAnimation** ppAnims = dest->mAnimations = (dest->mNumAnimations 
   1.482 +		? new aiAnimation*[dest->mNumAnimations] : NULL);
   1.483 +
   1.484 +	for ( int n = src.size()-1; n >= 0 ;--n ) /* !!! important !!! */
   1.485 +	{
   1.486 +		SceneHelper* cur = &src[n];
   1.487 +		aiNode* node;
   1.488 +
   1.489 +		// To offset or not to offset, this is the question
   1.490 +		if (n != (int)duplicates[n])
   1.491 +		{
   1.492 +			// Get full scenegraph copy
   1.493 +			Copy( &node, (*cur)->mRootNode );
   1.494 +			OffsetNodeMeshIndices(node,offset[duplicates[n]]);
   1.495 +
   1.496 +			if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)	{
   1.497 +				// (note:) they are already 'offseted' by offset[duplicates[n]] 
   1.498 +				OffsetNodeMeshIndices(node,offset[n] - offset[duplicates[n]]);
   1.499 +			}
   1.500 +		}
   1.501 +		else // if (n == duplicates[n])
   1.502 +		{
   1.503 +			node = (*cur)->mRootNode;
   1.504 +			OffsetNodeMeshIndices(node,offset[n]);
   1.505 +		}
   1.506 +		if (n) // src[0] is the master node
   1.507 +			nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode,n ));
   1.508 +
   1.509 +		// add name prefixes?
   1.510 +		if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
   1.511 +
   1.512 +			// or the whole scenegraph
   1.513 +			if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
   1.514 +				AddNodePrefixesChecked(node,(*cur).id,(*cur).idlen,src,n);
   1.515 +			}
   1.516 +			else AddNodePrefixes(node,(*cur).id,(*cur).idlen);
   1.517 +
   1.518 +			// meshes
   1.519 +			for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i)	{
   1.520 +				aiMesh* mesh = (*cur)->mMeshes[i]; 
   1.521 +
   1.522 +				// rename all bones
   1.523 +				for (unsigned int a = 0; a < mesh->mNumBones;++a)	{
   1.524 +					if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
   1.525 +						if (!FindNameMatch(mesh->mBones[a]->mName,src,n))
   1.526 +							continue;
   1.527 +					}
   1.528 +					PrefixString(mesh->mBones[a]->mName,(*cur).id,(*cur).idlen);
   1.529 +				}
   1.530 +			}
   1.531 +		}
   1.532 +
   1.533 +		// --------------------------------------------------------------------
   1.534 +		// Copy light sources
   1.535 +		for (unsigned int i = 0; i < (*cur)->mNumLights;++i,++ppLights)
   1.536 +		{
   1.537 +			if (n != (int)duplicates[n]) // duplicate scene? 
   1.538 +			{
   1.539 +				Copy(ppLights, (*cur)->mLights[i]);
   1.540 +			}
   1.541 +			else *ppLights = (*cur)->mLights[i];
   1.542 +
   1.543 +
   1.544 +			// Add name prefixes?
   1.545 +			if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
   1.546 +				if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
   1.547 +					if (!FindNameMatch((*ppLights)->mName,src,n))
   1.548 +						continue;
   1.549 +				}
   1.550 +
   1.551 +				PrefixString((*ppLights)->mName,(*cur).id,(*cur).idlen);
   1.552 +			}
   1.553 +		}
   1.554 +
   1.555 +		// --------------------------------------------------------------------
   1.556 +		// Copy cameras
   1.557 +		for (unsigned int i = 0; i < (*cur)->mNumCameras;++i,++ppCameras)	{
   1.558 +			if (n != (int)duplicates[n]) // duplicate scene? 
   1.559 +			{
   1.560 +				Copy(ppCameras, (*cur)->mCameras[i]);
   1.561 +			}
   1.562 +			else *ppCameras = (*cur)->mCameras[i];
   1.563 +
   1.564 +			// Add name prefixes?
   1.565 +			if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
   1.566 +				if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
   1.567 +					if (!FindNameMatch((*ppCameras)->mName,src,n))
   1.568 +						continue;
   1.569 +				}
   1.570 +
   1.571 +				PrefixString((*ppCameras)->mName,(*cur).id,(*cur).idlen);
   1.572 +			}
   1.573 +		}
   1.574 +
   1.575 +		// --------------------------------------------------------------------
   1.576 +		// Copy animations
   1.577 +		for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i,++ppAnims)	{
   1.578 +			if (n != (int)duplicates[n]) // duplicate scene? 
   1.579 +			{
   1.580 +				Copy(ppAnims, (*cur)->mAnimations[i]);
   1.581 +			}
   1.582 +			else *ppAnims = (*cur)->mAnimations[i];
   1.583 +
   1.584 +			// Add name prefixes?
   1.585 +			if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
   1.586 +				if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
   1.587 +					if (!FindNameMatch((*ppAnims)->mName,src,n))
   1.588 +						continue;
   1.589 +				}
   1.590 +
   1.591 +				PrefixString((*ppAnims)->mName,(*cur).id,(*cur).idlen);
   1.592 +
   1.593 +				// don't forget to update all node animation channels
   1.594 +				for (unsigned int a = 0; a < (*ppAnims)->mNumChannels;++a) {
   1.595 +					if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
   1.596 +						if (!FindNameMatch((*ppAnims)->mChannels[a]->mNodeName,src,n))
   1.597 +							continue;
   1.598 +					}
   1.599 +
   1.600 +					PrefixString((*ppAnims)->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen);
   1.601 +				}
   1.602 +			}
   1.603 +		}
   1.604 +	}
   1.605 +
   1.606 +	// Now build the output graph
   1.607 +	AttachToGraph ( master, nodes);
   1.608 +	dest->mRootNode = master->mRootNode;
   1.609 +
   1.610 +	// Check whether we succeeded at building the output graph
   1.611 +	for (std::vector <NodeAttachmentInfo> ::iterator it = nodes.begin(); 
   1.612 +		it != nodes.end(); ++it)
   1.613 +	{
   1.614 +		if (!(*it).resolved) {
   1.615 +			if (flags & AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS) {
   1.616 +				// search for this attachment point in all other imported scenes, too.
   1.617 +				for ( unsigned int n = 0; n < src.size();++n ) {
   1.618 +					if (n != (*it).src_idx) {
   1.619 +						AttachToGraph(src[n].scene,nodes);
   1.620 +						if ((*it).resolved)
   1.621 +							break;
   1.622 +					}
   1.623 +				}
   1.624 +			}
   1.625 +			if (!(*it).resolved) {
   1.626 +				DefaultLogger::get()->error(std::string("SceneCombiner: Failed to resolve attachment ") 
   1.627 +					+ (*it).node->mName.data + " " + (*it).attachToNode->mName.data);
   1.628 +			}
   1.629 +		}
   1.630 +	}
   1.631 +
   1.632 +	// now delete all input scenes. Make sure duplicate scenes aren't
   1.633 +	// deleted more than one time
   1.634 +	for ( unsigned int n = 0; n < src.size();++n )	{
   1.635 +		if (n != duplicates[n]) // duplicate scene?
   1.636 +			continue;
   1.637 +
   1.638 +		aiScene* deleteMe = src[n].scene;
   1.639 +
   1.640 +		// We need to delete the arrays before the destructor is called -
   1.641 +		// we are reusing the array members
   1.642 +		delete[] deleteMe->mMeshes;     deleteMe->mMeshes     = NULL;
   1.643 +		delete[] deleteMe->mCameras;    deleteMe->mCameras    = NULL;
   1.644 +		delete[] deleteMe->mLights;     deleteMe->mLights     = NULL;
   1.645 +		delete[] deleteMe->mMaterials;  deleteMe->mMaterials  = NULL;
   1.646 +		delete[] deleteMe->mAnimations; deleteMe->mAnimations = NULL;
   1.647 +
   1.648 +		deleteMe->mRootNode = NULL;
   1.649 +
   1.650 +		// Now we can safely delete the scene
   1.651 +		delete deleteMe;
   1.652 +	}
   1.653 +
   1.654 +	// Check flags
   1.655 +	if (!dest->mNumMeshes || !dest->mNumMaterials) {
   1.656 +		dest->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
   1.657 +	}
   1.658 +
   1.659 +	// We're finished
   1.660 +}
   1.661 +
   1.662 +// ------------------------------------------------------------------------------------------------
   1.663 +// Build a list of unique bones
   1.664 +void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
   1.665 +	std::vector<aiMesh*>::const_iterator it,
   1.666 +	std::vector<aiMesh*>::const_iterator end)
   1.667 +{
   1.668 +	unsigned int iOffset = 0;
   1.669 +	for (; it != end;++it)	{
   1.670 +		for (unsigned int l = 0; l < (*it)->mNumBones;++l)	{
   1.671 +			aiBone* p = (*it)->mBones[l];
   1.672 +			uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length);
   1.673 +
   1.674 +			std::list<BoneWithHash>::iterator it2  = asBones.begin();
   1.675 +			std::list<BoneWithHash>::iterator end2 = asBones.end();
   1.676 +
   1.677 +			for (;it2 != end2;++it2)	{
   1.678 +				if ((*it2).first == itml)	{
   1.679 +					(*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset));
   1.680 +					break;
   1.681 +				}
   1.682 +			}
   1.683 +			if (end2 == it2)	{
   1.684 +				// need to begin a new bone entry
   1.685 +				asBones.push_back(BoneWithHash());
   1.686 +				BoneWithHash& btz = asBones.back();
   1.687 +
   1.688 +				// setup members
   1.689 +				btz.first = itml;
   1.690 +				btz.second = &p->mName;
   1.691 +				btz.pSrcBones.push_back(BoneSrcIndex(p,iOffset));
   1.692 +			}
   1.693 +		}
   1.694 +		iOffset += (*it)->mNumVertices;
   1.695 +	}
   1.696 +}
   1.697 +
   1.698 +// ------------------------------------------------------------------------------------------------
   1.699 +// Merge a list of bones
   1.700 +void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
   1.701 +	std::vector<aiMesh*>::const_iterator end)
   1.702 +{
   1.703 +	ai_assert(NULL != out && !out->mNumBones);
   1.704 +
   1.705 +	// find we need to build an unique list of all bones.
   1.706 +	// we work with hashes to make the comparisons MUCH faster,
   1.707 +	// at least if we have many bones.
   1.708 +	std::list<BoneWithHash> asBones;
   1.709 +	BuildUniqueBoneList(asBones, it,end);
   1.710 +	
   1.711 +	// now create the output bones
   1.712 +	out->mNumBones = 0;
   1.713 +	out->mBones = new aiBone*[asBones.size()];
   1.714 +
   1.715 +	for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),end = asBones.end(); it != end;++it)	{
   1.716 +		// Allocate a bone and setup it's name
   1.717 +		aiBone* pc = out->mBones[out->mNumBones++] = new aiBone();
   1.718 +		pc->mName = aiString( *((*it).second ));
   1.719 +
   1.720 +		std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end();
   1.721 +
   1.722 +		// Loop through all bones to be joined for this bone
   1.723 +		for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)	{
   1.724 +			pc->mNumWeights += (*wmit).first->mNumWeights;
   1.725 +
   1.726 +			// NOTE: different offset matrices for bones with equal names
   1.727 +			// are - at the moment - not handled correctly. 
   1.728 +			if (wmit != (*it).pSrcBones.begin() && pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix)	{
   1.729 +				DefaultLogger::get()->warn("Bones with equal names but different offset matrices can't be joined at the moment");
   1.730 +				continue;
   1.731 +			}
   1.732 +			pc->mOffsetMatrix = (*wmit).first->mOffsetMatrix;
   1.733 +		}
   1.734 +
   1.735 +		// Allocate the vertex weight array
   1.736 +		aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights];
   1.737 +
   1.738 +		// And copy the final weights - adjust the vertex IDs by the 
   1.739 +		// face index offset of the coresponding mesh.
   1.740 +		for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)	{
   1.741 +			aiBone* pip = (*wmit).first;
   1.742 +			for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw)	{
   1.743 +				const aiVertexWeight& vfi = pip->mWeights[mp];
   1.744 +				avw->mWeight = vfi.mWeight;
   1.745 +				avw->mVertexId = vfi.mVertexId + (*wmit).second;
   1.746 +			}
   1.747 +		}
   1.748 +	}
   1.749 +}
   1.750 +
   1.751 +// ------------------------------------------------------------------------------------------------
   1.752 +// Merge a list of meshes
   1.753 +void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/,
   1.754 +	std::vector<aiMesh*>::const_iterator begin,
   1.755 +	std::vector<aiMesh*>::const_iterator end)
   1.756 +{
   1.757 +	ai_assert(NULL != _out);
   1.758 +
   1.759 +	if (begin == end)	{
   1.760 +		*_out = NULL; // no meshes ...
   1.761 +		return;
   1.762 +	}
   1.763 +
   1.764 +	// Allocate the output mesh
   1.765 +	aiMesh* out = *_out = new aiMesh();
   1.766 +	out->mMaterialIndex = (*begin)->mMaterialIndex;
   1.767 +
   1.768 +	// Find out how much output storage we'll need
   1.769 +	for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
   1.770 +		out->mNumVertices	+= (*it)->mNumVertices;
   1.771 +		out->mNumFaces		+= (*it)->mNumFaces;
   1.772 +		out->mNumBones		+= (*it)->mNumBones;
   1.773 +
   1.774 +		// combine primitive type flags
   1.775 +		out->mPrimitiveTypes |= (*it)->mPrimitiveTypes;
   1.776 +	}
   1.777 +
   1.778 +	if (out->mNumVertices) {
   1.779 +		aiVector3D* pv2;
   1.780 +
   1.781 +		// copy vertex positions
   1.782 +		if ((**begin).HasPositions())	{
   1.783 +
   1.784 +			pv2 = out->mVertices = new aiVector3D[out->mNumVertices];
   1.785 +			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
   1.786 +				if ((*it)->mVertices)	{
   1.787 +					::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D));
   1.788 +				}
   1.789 +				else DefaultLogger::get()->warn("JoinMeshes: Positions expected but input mesh contains no positions");
   1.790 +				pv2 += (*it)->mNumVertices;
   1.791 +			}
   1.792 +		}
   1.793 +		// copy normals
   1.794 +		if ((**begin).HasNormals())	{
   1.795 +
   1.796 +			pv2 = out->mNormals = new aiVector3D[out->mNumVertices];
   1.797 +			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
   1.798 +				if ((*it)->mNormals)	{
   1.799 +					::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
   1.800 +				}
   1.801 +				else DefaultLogger::get()->warn("JoinMeshes: Normals expected but input mesh contains no normals");
   1.802 +				pv2 += (*it)->mNumVertices;
   1.803 +			}
   1.804 +		}
   1.805 +		// copy tangents and bitangents
   1.806 +		if ((**begin).HasTangentsAndBitangents())	{
   1.807 +
   1.808 +			pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
   1.809 +			aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
   1.810 +
   1.811 +			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
   1.812 +				if ((*it)->mTangents)	{
   1.813 +					::memcpy(pv2, (*it)->mTangents,	 (*it)->mNumVertices*sizeof(aiVector3D));
   1.814 +					::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
   1.815 +				}
   1.816 +				else DefaultLogger::get()->warn("JoinMeshes: Tangents expected but input mesh contains no tangents");
   1.817 +				pv2  += (*it)->mNumVertices;
   1.818 +				pv2b += (*it)->mNumVertices;
   1.819 +			}
   1.820 +		}
   1.821 +		// copy texture coordinates
   1.822 +		unsigned int n = 0;
   1.823 +		while ((**begin).HasTextureCoords(n))	{
   1.824 +			out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
   1.825 +
   1.826 +			pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
   1.827 +			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
   1.828 +
   1.829 +				if ((*it)->mTextureCoords[n])	{
   1.830 +					::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
   1.831 +				}
   1.832 +				else DefaultLogger::get()->warn("JoinMeshes: UVs expected but input mesh contains no UVs");
   1.833 +				pv2 += (*it)->mNumVertices;
   1.834 +			}
   1.835 +			++n;
   1.836 +		}
   1.837 +		// copy vertex colors
   1.838 +		n = 0;
   1.839 +		while ((**begin).HasVertexColors(n))	{
   1.840 +			aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
   1.841 +			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
   1.842 +
   1.843 +				if ((*it)->mColors[n])	{
   1.844 +					::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
   1.845 +				}
   1.846 +				else DefaultLogger::get()->warn("JoinMeshes: VCs expected but input mesh contains no VCs");
   1.847 +				pv2 += (*it)->mNumVertices;
   1.848 +			}
   1.849 +			++n;
   1.850 +		}
   1.851 +	}
   1.852 +
   1.853 +	if (out->mNumFaces) // just for safety
   1.854 +	{
   1.855 +		// copy faces
   1.856 +		out->mFaces = new aiFace[out->mNumFaces];
   1.857 +		aiFace* pf2 = out->mFaces;
   1.858 +
   1.859 +		unsigned int ofs = 0;
   1.860 +		for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
   1.861 +			for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2)	{
   1.862 +				aiFace& face = (*it)->mFaces[m];
   1.863 +				pf2->mNumIndices = face.mNumIndices;
   1.864 +				pf2->mIndices = face.mIndices;
   1.865 +
   1.866 +				if (ofs)	{
   1.867 +					// add the offset to the vertex
   1.868 +					for (unsigned int q = 0; q < face.mNumIndices; ++q)
   1.869 +						face.mIndices[q] += ofs;	
   1.870 +				}
   1.871 +				face.mIndices = NULL;
   1.872 +			}
   1.873 +			ofs += (*it)->mNumVertices;
   1.874 +		}
   1.875 +	}
   1.876 +
   1.877 +	// bones - as this is quite lengthy, I moved the code to a separate function
   1.878 +	if (out->mNumBones)
   1.879 +		MergeBones(out,begin,end);
   1.880 +
   1.881 +	// delete all source meshes
   1.882 +	for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
   1.883 +		delete *it;
   1.884 +}
   1.885 +
   1.886 +// ------------------------------------------------------------------------------------------------
   1.887 +template <typename Type>
   1.888 +inline void CopyPtrArray (Type**& dest, const Type* const * src, unsigned int num)
   1.889 +{
   1.890 +	if (!num)
   1.891 +	{
   1.892 +		dest = NULL;
   1.893 +		return;
   1.894 +	}
   1.895 +	dest = new Type*[num];
   1.896 +	for (unsigned int i = 0; i < num;++i) {
   1.897 +		SceneCombiner::Copy(&dest[i],src[i]);
   1.898 +	}
   1.899 +}
   1.900 +
   1.901 +// ------------------------------------------------------------------------------------------------
   1.902 +template <typename Type>
   1.903 +inline void GetArrayCopy (Type*& dest, unsigned int num )
   1.904 +{
   1.905 +	if (!dest)return;
   1.906 +	Type* old = dest;
   1.907 +
   1.908 +	dest = new Type[num];
   1.909 +	::memcpy(dest, old, sizeof(Type) * num);
   1.910 +}
   1.911 +
   1.912 +// ------------------------------------------------------------------------------------------------
   1.913 +void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src)
   1.914 +{
   1.915 +	// reuse the old scene or allocate a new?
   1.916 +	if (*_dest) {
   1.917 +		(*_dest)->~aiScene();
   1.918 +		new (*_dest) aiScene();
   1.919 +	}
   1.920 +	else *_dest = new aiScene();
   1.921 +
   1.922 +	::memcpy(*_dest,src,sizeof(aiScene));
   1.923 +}
   1.924 +
   1.925 +// ------------------------------------------------------------------------------------------------
   1.926 +void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
   1.927 +{
   1.928 +	ai_assert(NULL != _dest && NULL != src);
   1.929 +
   1.930 +	if (allocate) {
   1.931 +		*_dest = new aiScene();
   1.932 +	}
   1.933 +	aiScene* dest = *_dest; 
   1.934 +	ai_assert(dest);
   1.935 +
   1.936 +	// copy animations
   1.937 +	dest->mNumAnimations = src->mNumAnimations;
   1.938 +	CopyPtrArray(dest->mAnimations,src->mAnimations,
   1.939 +		dest->mNumAnimations);
   1.940 +
   1.941 +	// copy textures
   1.942 +	dest->mNumTextures = src->mNumTextures;
   1.943 +	CopyPtrArray(dest->mTextures,src->mTextures,
   1.944 +		dest->mNumTextures);
   1.945 +
   1.946 +	// copy materials
   1.947 +	dest->mNumMaterials = src->mNumMaterials;
   1.948 +	CopyPtrArray(dest->mMaterials,src->mMaterials,
   1.949 +		dest->mNumMaterials);
   1.950 +
   1.951 +	// copy lights
   1.952 +	dest->mNumLights = src->mNumLights;
   1.953 +	CopyPtrArray(dest->mLights,src->mLights,
   1.954 +		dest->mNumLights);
   1.955 +
   1.956 +	// copy cameras
   1.957 +	dest->mNumCameras = src->mNumCameras;
   1.958 +	CopyPtrArray(dest->mCameras,src->mCameras,
   1.959 +		dest->mNumCameras);
   1.960 +
   1.961 +	// copy meshes
   1.962 +	dest->mNumMeshes = src->mNumMeshes;
   1.963 +	CopyPtrArray(dest->mMeshes,src->mMeshes,
   1.964 +		dest->mNumMeshes);
   1.965 +
   1.966 +	// now - copy the root node of the scene (deep copy, too)
   1.967 +	Copy( &dest->mRootNode, src->mRootNode);
   1.968 +
   1.969 +	// and keep the flags ...
   1.970 +	dest->mFlags = src->mFlags;
   1.971 +
   1.972 +	// source private data might be NULL if the scene is user-allocated (i.e. for use with the export API)
   1.973 +	ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : 0;
   1.974 +}
   1.975 +
   1.976 +// ------------------------------------------------------------------------------------------------
   1.977 +void SceneCombiner::Copy     (aiMesh** _dest, const aiMesh* src)
   1.978 +{
   1.979 +	ai_assert(NULL != _dest && NULL != src);
   1.980 +
   1.981 +	aiMesh* dest = *_dest = new aiMesh();
   1.982 +
   1.983 +	// get a flat copy
   1.984 +	::memcpy(dest,src,sizeof(aiMesh));
   1.985 +
   1.986 +	// and reallocate all arrays
   1.987 +	GetArrayCopy( dest->mVertices,   dest->mNumVertices );
   1.988 +	GetArrayCopy( dest->mNormals ,   dest->mNumVertices );
   1.989 +	GetArrayCopy( dest->mTangents,   dest->mNumVertices );
   1.990 +	GetArrayCopy( dest->mBitangents, dest->mNumVertices );
   1.991 +
   1.992 +	unsigned int n = 0;
   1.993 +	while (dest->HasTextureCoords(n))
   1.994 +		GetArrayCopy( dest->mTextureCoords[n++],   dest->mNumVertices );
   1.995 +
   1.996 +	n = 0;
   1.997 +	while (dest->HasVertexColors(n))
   1.998 +		GetArrayCopy( dest->mColors[n++],   dest->mNumVertices );
   1.999 +
  1.1000 +	// make a deep copy of all bones
  1.1001 +	CopyPtrArray(dest->mBones,dest->mBones,dest->mNumBones);
  1.1002 +
  1.1003 +	// make a deep copy of all faces
  1.1004 +	GetArrayCopy(dest->mFaces,dest->mNumFaces);
  1.1005 +	for (unsigned int i = 0; i < dest->mNumFaces;++i)
  1.1006 +	{
  1.1007 +		aiFace& f = dest->mFaces[i];
  1.1008 +		GetArrayCopy(f.mIndices,f.mNumIndices);
  1.1009 +	}
  1.1010 +}
  1.1011 +
  1.1012 +// ------------------------------------------------------------------------------------------------
  1.1013 +void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src)
  1.1014 +{
  1.1015 +	ai_assert(NULL != _dest && NULL != src);
  1.1016 +
  1.1017 +	aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
  1.1018 +	dest->mNumAllocated  =  src->mNumAllocated;
  1.1019 +	dest->mNumProperties =  src->mNumProperties;
  1.1020 +	dest->mProperties    =  new aiMaterialProperty* [dest->mNumAllocated];
  1.1021 +
  1.1022 +	for (unsigned int i = 0; i < dest->mNumProperties;++i)
  1.1023 +	{
  1.1024 +		aiMaterialProperty* prop  = dest->mProperties[i] = new aiMaterialProperty();
  1.1025 +		aiMaterialProperty* sprop = src->mProperties[i];
  1.1026 +
  1.1027 +		prop->mDataLength = sprop->mDataLength;
  1.1028 +		prop->mData = new char[prop->mDataLength];
  1.1029 +		::memcpy(prop->mData,sprop->mData,prop->mDataLength);
  1.1030 +
  1.1031 +		prop->mIndex    = sprop->mIndex;
  1.1032 +		prop->mSemantic = sprop->mSemantic;
  1.1033 +		prop->mKey      = sprop->mKey;
  1.1034 +		prop->mType		= sprop->mType;
  1.1035 +	}
  1.1036 +}
  1.1037 +	
  1.1038 +// ------------------------------------------------------------------------------------------------
  1.1039 +void SceneCombiner::Copy  (aiTexture** _dest, const aiTexture* src)
  1.1040 +{
  1.1041 +	ai_assert(NULL != _dest && NULL != src);
  1.1042 +
  1.1043 +	aiTexture* dest = *_dest = new aiTexture();
  1.1044 +
  1.1045 +	// get a flat copy
  1.1046 +	::memcpy(dest,src,sizeof(aiTexture));
  1.1047 +
  1.1048 +	// and reallocate all arrays. We must do it manually here
  1.1049 +	const char* old = (const char*)dest->pcData;
  1.1050 +	if (old)
  1.1051 +	{
  1.1052 +		unsigned int cpy;
  1.1053 +		if (!dest->mHeight)cpy = dest->mWidth;
  1.1054 +		else cpy = dest->mHeight * dest->mWidth * sizeof(aiTexel);
  1.1055 +
  1.1056 +		if (!cpy)
  1.1057 +		{
  1.1058 +			dest->pcData = NULL;
  1.1059 +			return;
  1.1060 +		}
  1.1061 +		// the cast is legal, the aiTexel c'tor does nothing important
  1.1062 +		dest->pcData = (aiTexel*) new char[cpy];
  1.1063 +		::memcpy(dest->pcData, old, cpy);
  1.1064 +	}
  1.1065 +}
  1.1066 +	
  1.1067 +// ------------------------------------------------------------------------------------------------
  1.1068 +void SceneCombiner::Copy     (aiAnimation** _dest, const aiAnimation* src)
  1.1069 +{
  1.1070 +	ai_assert(NULL != _dest && NULL != src);
  1.1071 +
  1.1072 +	aiAnimation* dest = *_dest = new aiAnimation();
  1.1073 +
  1.1074 +	// get a flat copy
  1.1075 +	::memcpy(dest,src,sizeof(aiAnimation));
  1.1076 +
  1.1077 +	// and reallocate all arrays
  1.1078 +	CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels );
  1.1079 +}
  1.1080 +
  1.1081 +// ------------------------------------------------------------------------------------------------
  1.1082 +void SceneCombiner::Copy     (aiNodeAnim** _dest, const aiNodeAnim* src)
  1.1083 +{
  1.1084 +	ai_assert(NULL != _dest && NULL != src);
  1.1085 +
  1.1086 +	aiNodeAnim* dest = *_dest = new aiNodeAnim();
  1.1087 +
  1.1088 +	// get a flat copy
  1.1089 +	::memcpy(dest,src,sizeof(aiNodeAnim));
  1.1090 +
  1.1091 +	// and reallocate all arrays
  1.1092 +	GetArrayCopy( dest->mPositionKeys, dest->mNumPositionKeys );
  1.1093 +	GetArrayCopy( dest->mScalingKeys,  dest->mNumScalingKeys );
  1.1094 +	GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys );
  1.1095 +}
  1.1096 +
  1.1097 +// ------------------------------------------------------------------------------------------------
  1.1098 +void SceneCombiner::Copy   (aiCamera** _dest,const  aiCamera* src)
  1.1099 +{
  1.1100 +	ai_assert(NULL != _dest && NULL != src);
  1.1101 +
  1.1102 +	aiCamera* dest = *_dest = new aiCamera();
  1.1103 +
  1.1104 +	// get a flat copy, that's already OK
  1.1105 +	::memcpy(dest,src,sizeof(aiCamera));
  1.1106 +}
  1.1107 +
  1.1108 +// ------------------------------------------------------------------------------------------------
  1.1109 +void SceneCombiner::Copy   (aiLight** _dest, const aiLight* src)
  1.1110 +{
  1.1111 +	ai_assert(NULL != _dest && NULL != src);
  1.1112 +
  1.1113 +	aiLight* dest = *_dest = new aiLight();
  1.1114 +
  1.1115 +	// get a flat copy, that's already OK
  1.1116 +	::memcpy(dest,src,sizeof(aiLight));
  1.1117 +}
  1.1118 +
  1.1119 +// ------------------------------------------------------------------------------------------------
  1.1120 +void SceneCombiner::Copy     (aiBone** _dest, const aiBone* src)
  1.1121 +{
  1.1122 +	ai_assert(NULL != _dest && NULL != src);
  1.1123 +
  1.1124 +	aiBone* dest = *_dest = new aiBone();
  1.1125 +
  1.1126 +	// get a flat copy
  1.1127 +	::memcpy(dest,src,sizeof(aiBone));
  1.1128 +
  1.1129 +	// and reallocate all arrays
  1.1130 +	GetArrayCopy( dest->mWeights, dest->mNumWeights );
  1.1131 +}
  1.1132 +
  1.1133 +// ------------------------------------------------------------------------------------------------
  1.1134 +void SceneCombiner::Copy     (aiNode** _dest, const aiNode* src)
  1.1135 +{
  1.1136 +	ai_assert(NULL != _dest && NULL != src);
  1.1137 +
  1.1138 +	aiNode* dest = *_dest = new aiNode();
  1.1139 +
  1.1140 +	// get a flat copy
  1.1141 +	::memcpy(dest,src,sizeof(aiNode));
  1.1142 +
  1.1143 +	// and reallocate all arrays
  1.1144 +	GetArrayCopy( dest->mMeshes, dest->mNumMeshes );
  1.1145 +	CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren);
  1.1146 +}
  1.1147 +
  1.1148 +
  1.1149 +}