vrshoot

annotate 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
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41
nuclear@0 42 // ----------------------------------------------------------------------------
nuclear@0 43 /** @file Implements Assimp::SceneCombiner. This is a smart utility
nuclear@0 44 * class that combines multiple scenes, meshes, ... into one. Currently
nuclear@0 45 * these utilities are used by the IRR and LWS loaders and the
nuclear@0 46 * OptimizeGraph step.
nuclear@0 47 */
nuclear@0 48 // ----------------------------------------------------------------------------
nuclear@0 49 #include "AssimpPCH.h"
nuclear@0 50 #include "SceneCombiner.h"
nuclear@0 51 #include "fast_atof.h"
nuclear@0 52 #include "Hash.h"
nuclear@0 53 #include "time.h"
nuclear@0 54
nuclear@0 55 namespace Assimp {
nuclear@0 56
nuclear@0 57 // ------------------------------------------------------------------------------------------------
nuclear@0 58 // Add a prefix to a string
nuclear@0 59 inline void PrefixString(aiString& string,const char* prefix, unsigned int len)
nuclear@0 60 {
nuclear@0 61 // If the string is already prefixed, we won't prefix it a second time
nuclear@0 62 if (string.length >= 1 && string.data[0] == '$')
nuclear@0 63 return;
nuclear@0 64
nuclear@0 65 if (len+string.length>=MAXLEN-1) {
nuclear@0 66 DefaultLogger::get()->debug("Can't add an unique prefix because the string is too long");
nuclear@0 67 ai_assert(false);
nuclear@0 68 return;
nuclear@0 69 }
nuclear@0 70
nuclear@0 71 // Add the prefix
nuclear@0 72 ::memmove(string.data+len,string.data,string.length+1);
nuclear@0 73 ::memcpy (string.data, prefix, len);
nuclear@0 74
nuclear@0 75 // And update the string's length
nuclear@0 76 string.length += len;
nuclear@0 77 }
nuclear@0 78
nuclear@0 79 // ------------------------------------------------------------------------------------------------
nuclear@0 80 // Add node identifiers to a hashing set
nuclear@0 81 void SceneCombiner::AddNodeHashes(aiNode* node, std::set<unsigned int>& hashes)
nuclear@0 82 {
nuclear@0 83 // Add node name to hashing set if it is non-empty - empty nodes are allowed
nuclear@0 84 // and they can't have any anims assigned so its absolutely safe to duplicate them.
nuclear@0 85 if (node->mName.length) {
nuclear@0 86 hashes.insert( SuperFastHash(node->mName.data,node->mName.length) );
nuclear@0 87 }
nuclear@0 88
nuclear@0 89 // Process all children recursively
nuclear@0 90 for (unsigned int i = 0; i < node->mNumChildren;++i)
nuclear@0 91 AddNodeHashes(node->mChildren[i],hashes);
nuclear@0 92 }
nuclear@0 93
nuclear@0 94 // ------------------------------------------------------------------------------------------------
nuclear@0 95 // Add a name prefix to all nodes in a hierarchy
nuclear@0 96 void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len)
nuclear@0 97 {
nuclear@0 98 ai_assert(NULL != prefix);
nuclear@0 99 PrefixString(node->mName,prefix,len);
nuclear@0 100
nuclear@0 101 // Process all children recursively
nuclear@0 102 for (unsigned int i = 0; i < node->mNumChildren;++i)
nuclear@0 103 AddNodePrefixes(node->mChildren[i],prefix,len);
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 // ------------------------------------------------------------------------------------------------
nuclear@0 107 // Search for matching names
nuclear@0 108 bool SceneCombiner::FindNameMatch(const aiString& name, std::vector<SceneHelper>& input, unsigned int cur)
nuclear@0 109 {
nuclear@0 110 const unsigned int hash = SuperFastHash(name.data, name.length);
nuclear@0 111
nuclear@0 112 // Check whether we find a positive match in one of the given sets
nuclear@0 113 for (unsigned int i = 0; i < input.size(); ++i) {
nuclear@0 114
nuclear@0 115 if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) {
nuclear@0 116 return true;
nuclear@0 117 }
nuclear@0 118 }
nuclear@0 119 return false;
nuclear@0 120 }
nuclear@0 121
nuclear@0 122 // ------------------------------------------------------------------------------------------------
nuclear@0 123 // Add a name prefix to all nodes in a hierarchy if a hash match is found
nuclear@0 124 void SceneCombiner::AddNodePrefixesChecked(aiNode* node, const char* prefix, unsigned int len,
nuclear@0 125 std::vector<SceneHelper>& input, unsigned int cur)
nuclear@0 126 {
nuclear@0 127 ai_assert(NULL != prefix);
nuclear@0 128 const unsigned int hash = SuperFastHash(node->mName.data,node->mName.length);
nuclear@0 129
nuclear@0 130 // Check whether we find a positive match in one of the given sets
nuclear@0 131 for (unsigned int i = 0; i < input.size(); ++i) {
nuclear@0 132
nuclear@0 133 if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) {
nuclear@0 134 PrefixString(node->mName,prefix,len);
nuclear@0 135 break;
nuclear@0 136 }
nuclear@0 137 }
nuclear@0 138
nuclear@0 139 // Process all children recursively
nuclear@0 140 for (unsigned int i = 0; i < node->mNumChildren;++i)
nuclear@0 141 AddNodePrefixesChecked(node->mChildren[i],prefix,len,input,cur);
nuclear@0 142 }
nuclear@0 143
nuclear@0 144 // ------------------------------------------------------------------------------------------------
nuclear@0 145 // Add an offset to all mesh indices in a node graph
nuclear@0 146 void SceneCombiner::OffsetNodeMeshIndices (aiNode* node, unsigned int offset)
nuclear@0 147 {
nuclear@0 148 for (unsigned int i = 0; i < node->mNumMeshes;++i)
nuclear@0 149 node->mMeshes[i] += offset;
nuclear@0 150
nuclear@0 151 for (unsigned int i = 0; i < node->mNumChildren;++i)
nuclear@0 152 OffsetNodeMeshIndices(node->mChildren[i],offset);
nuclear@0 153 }
nuclear@0 154
nuclear@0 155 // ------------------------------------------------------------------------------------------------
nuclear@0 156 // Merges two scenes. Currently only used by the LWS loader.
nuclear@0 157 void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src,
nuclear@0 158 unsigned int flags)
nuclear@0 159 {
nuclear@0 160 ai_assert(NULL != _dest);
nuclear@0 161
nuclear@0 162 // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
nuclear@0 163 if (src.empty())
nuclear@0 164 {
nuclear@0 165 if (*_dest)
nuclear@0 166 {
nuclear@0 167 (*_dest)->~aiScene();
nuclear@0 168 SceneCombiner::CopySceneFlat(_dest,src[0]);
nuclear@0 169 }
nuclear@0 170 else *_dest = src[0];
nuclear@0 171 return;
nuclear@0 172 }
nuclear@0 173 if (*_dest)(*_dest)->~aiScene();
nuclear@0 174 else *_dest = new aiScene();
nuclear@0 175
nuclear@0 176 // Create a dummy scene to serve as master for the others
nuclear@0 177 aiScene* master = new aiScene();
nuclear@0 178 master->mRootNode = new aiNode();
nuclear@0 179 master->mRootNode->mName.Set("<MergeRoot>");
nuclear@0 180
nuclear@0 181 std::vector<AttachmentInfo> srcList (src.size());
nuclear@0 182 for (unsigned int i = 0; i < srcList.size();++i) {
nuclear@0 183 srcList[i] = AttachmentInfo(src[i],master->mRootNode);
nuclear@0 184 }
nuclear@0 185
nuclear@0 186 // 'master' will be deleted afterwards
nuclear@0 187 MergeScenes (_dest, master, srcList, flags);
nuclear@0 188 }
nuclear@0 189
nuclear@0 190 // ------------------------------------------------------------------------------------------------
nuclear@0 191 void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInfo>& srcList)
nuclear@0 192 {
nuclear@0 193 unsigned int cnt;
nuclear@0 194 for (cnt = 0; cnt < attach->mNumChildren;++cnt)
nuclear@0 195 AttachToGraph(attach->mChildren[cnt],srcList);
nuclear@0 196
nuclear@0 197 cnt = 0;
nuclear@0 198 for (std::vector<NodeAttachmentInfo>::iterator it = srcList.begin();
nuclear@0 199 it != srcList.end(); ++it)
nuclear@0 200 {
nuclear@0 201 if ((*it).attachToNode == attach && !(*it).resolved)
nuclear@0 202 ++cnt;
nuclear@0 203 }
nuclear@0 204
nuclear@0 205 if (cnt) {
nuclear@0 206 aiNode** n = new aiNode*[cnt+attach->mNumChildren];
nuclear@0 207 if (attach->mNumChildren) {
nuclear@0 208 ::memcpy(n,attach->mChildren,sizeof(void*)*attach->mNumChildren);
nuclear@0 209 delete[] attach->mChildren;
nuclear@0 210 }
nuclear@0 211 attach->mChildren = n;
nuclear@0 212
nuclear@0 213 n += attach->mNumChildren;
nuclear@0 214 attach->mNumChildren += cnt;
nuclear@0 215
nuclear@0 216 for (unsigned int i = 0; i < srcList.size();++i) {
nuclear@0 217 NodeAttachmentInfo& att = srcList[i];
nuclear@0 218 if (att.attachToNode == attach && !att.resolved) {
nuclear@0 219 *n = att.node;
nuclear@0 220 (**n).mParent = attach;
nuclear@0 221 ++n;
nuclear@0 222
nuclear@0 223 // mark this attachment as resolved
nuclear@0 224 att.resolved = true;
nuclear@0 225 }
nuclear@0 226 }
nuclear@0 227 }
nuclear@0 228 }
nuclear@0 229
nuclear@0 230 // ------------------------------------------------------------------------------------------------
nuclear@0 231 void SceneCombiner::AttachToGraph ( aiScene* master,
nuclear@0 232 std::vector<NodeAttachmentInfo>& src)
nuclear@0 233 {
nuclear@0 234 ai_assert(NULL != master);
nuclear@0 235 AttachToGraph(master->mRootNode,src);
nuclear@0 236 }
nuclear@0 237
nuclear@0 238 // ------------------------------------------------------------------------------------------------
nuclear@0 239 void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
nuclear@0 240 std::vector<AttachmentInfo>& srcList,
nuclear@0 241 unsigned int flags)
nuclear@0 242 {
nuclear@0 243 ai_assert(NULL != _dest);
nuclear@0 244
nuclear@0 245 // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
nuclear@0 246 if (srcList.empty()) {
nuclear@0 247 if (*_dest) {
nuclear@0 248 SceneCombiner::CopySceneFlat(_dest,master);
nuclear@0 249 }
nuclear@0 250 else *_dest = master;
nuclear@0 251 return;
nuclear@0 252 }
nuclear@0 253 if (*_dest) {
nuclear@0 254 (*_dest)->~aiScene();
nuclear@0 255 new (*_dest) aiScene();
nuclear@0 256 }
nuclear@0 257 else *_dest = new aiScene();
nuclear@0 258
nuclear@0 259 aiScene* dest = *_dest;
nuclear@0 260
nuclear@0 261 std::vector<SceneHelper> src (srcList.size()+1);
nuclear@0 262 src[0].scene = master;
nuclear@0 263 for (unsigned int i = 0; i < srcList.size();++i) {
nuclear@0 264 src[i+1] = SceneHelper( srcList[i].scene );
nuclear@0 265 }
nuclear@0 266
nuclear@0 267 // this helper array specifies which scenes are duplicates of others
nuclear@0 268 std::vector<unsigned int> duplicates(src.size(),UINT_MAX);
nuclear@0 269
nuclear@0 270 // this helper array is used as lookup table several times
nuclear@0 271 std::vector<unsigned int> offset(src.size());
nuclear@0 272
nuclear@0 273 // Find duplicate scenes
nuclear@0 274 for (unsigned int i = 0; i < src.size();++i) {
nuclear@0 275 if (duplicates[i] != i && duplicates[i] != UINT_MAX) {
nuclear@0 276 continue;
nuclear@0 277 }
nuclear@0 278
nuclear@0 279 duplicates[i] = i;
nuclear@0 280 for ( unsigned int a = i+1; a < src.size(); ++a) {
nuclear@0 281 if (src[i].scene == src[a].scene) {
nuclear@0 282 duplicates[a] = i;
nuclear@0 283 }
nuclear@0 284 }
nuclear@0 285 }
nuclear@0 286
nuclear@0 287 // Generate unique names for all named stuff?
nuclear@0 288 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES)
nuclear@0 289 {
nuclear@0 290 #if 0
nuclear@0 291 // Construct a proper random number generator
nuclear@0 292 boost::mt19937 rng( );
nuclear@0 293 boost::uniform_int<> dist(1u,1 << 24u);
nuclear@0 294 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > rndGen(rng, dist);
nuclear@0 295 #endif
nuclear@0 296 for (unsigned int i = 1; i < src.size();++i)
nuclear@0 297 {
nuclear@0 298 //if (i != duplicates[i])
nuclear@0 299 //{
nuclear@0 300 // // duplicate scenes share the same UID
nuclear@0 301 // ::strcpy( src[i].id, src[duplicates[i]].id );
nuclear@0 302 // src[i].idlen = src[duplicates[i]].idlen;
nuclear@0 303
nuclear@0 304 // continue;
nuclear@0 305 //}
nuclear@0 306
nuclear@0 307 src[i].idlen = ::sprintf(src[i].id,"$%.6X$_",i);
nuclear@0 308
nuclear@0 309 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
nuclear@0 310
nuclear@0 311 // Compute hashes for all identifiers in this scene and store them
nuclear@0 312 // in a sorted table (for convenience I'm using std::set). We hash
nuclear@0 313 // just the node and animation channel names, all identifiers except
nuclear@0 314 // the material names should be caught by doing this.
nuclear@0 315 AddNodeHashes(src[i]->mRootNode,src[i].hashes);
nuclear@0 316
nuclear@0 317 for (unsigned int a = 0; a < src[i]->mNumAnimations;++a) {
nuclear@0 318 aiAnimation* anim = src[i]->mAnimations[a];
nuclear@0 319 src[i].hashes.insert(SuperFastHash(anim->mName.data,anim->mName.length));
nuclear@0 320 }
nuclear@0 321 }
nuclear@0 322 }
nuclear@0 323 }
nuclear@0 324
nuclear@0 325 unsigned int cnt;
nuclear@0 326
nuclear@0 327 // First find out how large the respective output arrays must be
nuclear@0 328 for ( unsigned int n = 0; n < src.size();++n )
nuclear@0 329 {
nuclear@0 330 SceneHelper* cur = &src[n];
nuclear@0 331
nuclear@0 332 if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) {
nuclear@0 333 dest->mNumTextures += (*cur)->mNumTextures;
nuclear@0 334 dest->mNumMaterials += (*cur)->mNumMaterials;
nuclear@0 335 dest->mNumMeshes += (*cur)->mNumMeshes;
nuclear@0 336 }
nuclear@0 337
nuclear@0 338 dest->mNumLights += (*cur)->mNumLights;
nuclear@0 339 dest->mNumCameras += (*cur)->mNumCameras;
nuclear@0 340 dest->mNumAnimations += (*cur)->mNumAnimations;
nuclear@0 341
nuclear@0 342 // Combine the flags of all scenes
nuclear@0 343 // We need to process them flag-by-flag here to get correct results
nuclear@0 344 // dest->mFlags ; //|= (*cur)->mFlags;
nuclear@0 345 if ((*cur)->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
nuclear@0 346 dest->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
nuclear@0 347 }
nuclear@0 348 }
nuclear@0 349
nuclear@0 350 // generate the output texture list + an offset table for all texture indices
nuclear@0 351 if (dest->mNumTextures)
nuclear@0 352 {
nuclear@0 353 aiTexture** pip = dest->mTextures = new aiTexture*[dest->mNumMaterials];
nuclear@0 354 cnt = 0;
nuclear@0 355 for ( unsigned int n = 0; n < src.size();++n )
nuclear@0 356 {
nuclear@0 357 SceneHelper* cur = &src[n];
nuclear@0 358 for (unsigned int i = 0; i < (*cur)->mNumTextures;++i)
nuclear@0 359 {
nuclear@0 360 if (n != duplicates[n])
nuclear@0 361 {
nuclear@0 362 if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
nuclear@0 363 Copy(pip,(*cur)->mTextures[i]);
nuclear@0 364
nuclear@0 365 else continue;
nuclear@0 366 }
nuclear@0 367 else *pip = (*cur)->mTextures[i];
nuclear@0 368 ++pip;
nuclear@0 369 }
nuclear@0 370
nuclear@0 371 offset[n] = cnt;
nuclear@0 372 cnt = (unsigned int)(pip - dest->mTextures);
nuclear@0 373 }
nuclear@0 374 }
nuclear@0 375
nuclear@0 376 // generate the output material list + an offset table for all material indices
nuclear@0 377 if (dest->mNumMaterials)
nuclear@0 378 {
nuclear@0 379 aiMaterial** pip = dest->mMaterials = new aiMaterial*[dest->mNumMaterials];
nuclear@0 380 cnt = 0;
nuclear@0 381 for ( unsigned int n = 0; n < src.size();++n ) {
nuclear@0 382 SceneHelper* cur = &src[n];
nuclear@0 383 for (unsigned int i = 0; i < (*cur)->mNumMaterials;++i)
nuclear@0 384 {
nuclear@0 385 if (n != duplicates[n])
nuclear@0 386 {
nuclear@0 387 if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
nuclear@0 388 Copy(pip,(*cur)->mMaterials[i]);
nuclear@0 389
nuclear@0 390 else continue;
nuclear@0 391 }
nuclear@0 392 else *pip = (*cur)->mMaterials[i];
nuclear@0 393
nuclear@0 394 if ((*cur)->mNumTextures != dest->mNumTextures) {
nuclear@0 395 // We need to update all texture indices of the mesh. So we need to search for
nuclear@0 396 // a material property called '$tex.file'
nuclear@0 397
nuclear@0 398 for (unsigned int a = 0; a < (*pip)->mNumProperties;++a)
nuclear@0 399 {
nuclear@0 400 aiMaterialProperty* prop = (*pip)->mProperties[a];
nuclear@0 401 if (!strncmp(prop->mKey.data,"$tex.file",9))
nuclear@0 402 {
nuclear@0 403 // Check whether this texture is an embedded texture.
nuclear@0 404 // In this case the property looks like this: *<n>,
nuclear@0 405 // where n is the index of the texture.
nuclear@0 406 aiString& s = *((aiString*)prop->mData);
nuclear@0 407 if ('*' == s.data[0]) {
nuclear@0 408 // Offset the index and write it back ..
nuclear@0 409 const unsigned int idx = strtoul10(&s.data[1]) + offset[n];
nuclear@0 410 ASSIMP_itoa10(&s.data[1],sizeof(s.data)-1,idx);
nuclear@0 411 }
nuclear@0 412 }
nuclear@0 413
nuclear@0 414 // Need to generate new, unique material names?
nuclear@0 415 else if (!::strcmp( prop->mKey.data,"$mat.name" ) && flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES)
nuclear@0 416 {
nuclear@0 417 aiString* pcSrc = (aiString*) prop->mData;
nuclear@0 418 PrefixString(*pcSrc, (*cur).id, (*cur).idlen);
nuclear@0 419 }
nuclear@0 420 }
nuclear@0 421 }
nuclear@0 422 ++pip;
nuclear@0 423 }
nuclear@0 424
nuclear@0 425 offset[n] = cnt;
nuclear@0 426 cnt = (unsigned int)(pip - dest->mMaterials);
nuclear@0 427 }
nuclear@0 428 }
nuclear@0 429
nuclear@0 430 // generate the output mesh list + again an offset table for all mesh indices
nuclear@0 431 if (dest->mNumMeshes)
nuclear@0 432 {
nuclear@0 433 aiMesh** pip = dest->mMeshes = new aiMesh*[dest->mNumMeshes];
nuclear@0 434 cnt = 0;
nuclear@0 435 for ( unsigned int n = 0; n < src.size();++n )
nuclear@0 436 {
nuclear@0 437 SceneHelper* cur = &src[n];
nuclear@0 438 for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i)
nuclear@0 439 {
nuclear@0 440 if (n != duplicates[n]) {
nuclear@0 441 if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
nuclear@0 442 Copy(pip, (*cur)->mMeshes[i]);
nuclear@0 443
nuclear@0 444 else continue;
nuclear@0 445 }
nuclear@0 446 else *pip = (*cur)->mMeshes[i];
nuclear@0 447
nuclear@0 448 // update the material index of the mesh
nuclear@0 449 (*pip)->mMaterialIndex += offset[n];
nuclear@0 450 ++pip;
nuclear@0 451 }
nuclear@0 452
nuclear@0 453 // reuse the offset array - store now the mesh offset in it
nuclear@0 454 offset[n] = cnt;
nuclear@0 455 cnt = (unsigned int)(pip - dest->mMeshes);
nuclear@0 456 }
nuclear@0 457 }
nuclear@0 458
nuclear@0 459 std::vector <NodeAttachmentInfo> nodes;
nuclear@0 460 nodes.reserve(srcList.size());
nuclear@0 461
nuclear@0 462 // ----------------------------------------------------------------------------
nuclear@0 463 // Now generate the output node graph. We need to make those
nuclear@0 464 // names in the graph that are referenced by anims or lights
nuclear@0 465 // or cameras unique. So we add a prefix to them ... $<rand>_
nuclear@0 466 // We could also use a counter, but using a random value allows us to
nuclear@0 467 // use just one prefix if we are joining multiple scene hierarchies recursively.
nuclear@0 468 // Chances are quite good we don't collide, so we try that ...
nuclear@0 469 // ----------------------------------------------------------------------------
nuclear@0 470
nuclear@0 471 // Allocate space for light sources, cameras and animations
nuclear@0 472 aiLight** ppLights = dest->mLights = (dest->mNumLights
nuclear@0 473 ? new aiLight*[dest->mNumLights] : NULL);
nuclear@0 474
nuclear@0 475 aiCamera** ppCameras = dest->mCameras = (dest->mNumCameras
nuclear@0 476 ? new aiCamera*[dest->mNumCameras] : NULL);
nuclear@0 477
nuclear@0 478 aiAnimation** ppAnims = dest->mAnimations = (dest->mNumAnimations
nuclear@0 479 ? new aiAnimation*[dest->mNumAnimations] : NULL);
nuclear@0 480
nuclear@0 481 for ( int n = src.size()-1; n >= 0 ;--n ) /* !!! important !!! */
nuclear@0 482 {
nuclear@0 483 SceneHelper* cur = &src[n];
nuclear@0 484 aiNode* node;
nuclear@0 485
nuclear@0 486 // To offset or not to offset, this is the question
nuclear@0 487 if (n != (int)duplicates[n])
nuclear@0 488 {
nuclear@0 489 // Get full scenegraph copy
nuclear@0 490 Copy( &node, (*cur)->mRootNode );
nuclear@0 491 OffsetNodeMeshIndices(node,offset[duplicates[n]]);
nuclear@0 492
nuclear@0 493 if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) {
nuclear@0 494 // (note:) they are already 'offseted' by offset[duplicates[n]]
nuclear@0 495 OffsetNodeMeshIndices(node,offset[n] - offset[duplicates[n]]);
nuclear@0 496 }
nuclear@0 497 }
nuclear@0 498 else // if (n == duplicates[n])
nuclear@0 499 {
nuclear@0 500 node = (*cur)->mRootNode;
nuclear@0 501 OffsetNodeMeshIndices(node,offset[n]);
nuclear@0 502 }
nuclear@0 503 if (n) // src[0] is the master node
nuclear@0 504 nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode,n ));
nuclear@0 505
nuclear@0 506 // add name prefixes?
nuclear@0 507 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
nuclear@0 508
nuclear@0 509 // or the whole scenegraph
nuclear@0 510 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
nuclear@0 511 AddNodePrefixesChecked(node,(*cur).id,(*cur).idlen,src,n);
nuclear@0 512 }
nuclear@0 513 else AddNodePrefixes(node,(*cur).id,(*cur).idlen);
nuclear@0 514
nuclear@0 515 // meshes
nuclear@0 516 for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) {
nuclear@0 517 aiMesh* mesh = (*cur)->mMeshes[i];
nuclear@0 518
nuclear@0 519 // rename all bones
nuclear@0 520 for (unsigned int a = 0; a < mesh->mNumBones;++a) {
nuclear@0 521 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
nuclear@0 522 if (!FindNameMatch(mesh->mBones[a]->mName,src,n))
nuclear@0 523 continue;
nuclear@0 524 }
nuclear@0 525 PrefixString(mesh->mBones[a]->mName,(*cur).id,(*cur).idlen);
nuclear@0 526 }
nuclear@0 527 }
nuclear@0 528 }
nuclear@0 529
nuclear@0 530 // --------------------------------------------------------------------
nuclear@0 531 // Copy light sources
nuclear@0 532 for (unsigned int i = 0; i < (*cur)->mNumLights;++i,++ppLights)
nuclear@0 533 {
nuclear@0 534 if (n != (int)duplicates[n]) // duplicate scene?
nuclear@0 535 {
nuclear@0 536 Copy(ppLights, (*cur)->mLights[i]);
nuclear@0 537 }
nuclear@0 538 else *ppLights = (*cur)->mLights[i];
nuclear@0 539
nuclear@0 540
nuclear@0 541 // Add name prefixes?
nuclear@0 542 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
nuclear@0 543 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
nuclear@0 544 if (!FindNameMatch((*ppLights)->mName,src,n))
nuclear@0 545 continue;
nuclear@0 546 }
nuclear@0 547
nuclear@0 548 PrefixString((*ppLights)->mName,(*cur).id,(*cur).idlen);
nuclear@0 549 }
nuclear@0 550 }
nuclear@0 551
nuclear@0 552 // --------------------------------------------------------------------
nuclear@0 553 // Copy cameras
nuclear@0 554 for (unsigned int i = 0; i < (*cur)->mNumCameras;++i,++ppCameras) {
nuclear@0 555 if (n != (int)duplicates[n]) // duplicate scene?
nuclear@0 556 {
nuclear@0 557 Copy(ppCameras, (*cur)->mCameras[i]);
nuclear@0 558 }
nuclear@0 559 else *ppCameras = (*cur)->mCameras[i];
nuclear@0 560
nuclear@0 561 // Add name prefixes?
nuclear@0 562 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
nuclear@0 563 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
nuclear@0 564 if (!FindNameMatch((*ppCameras)->mName,src,n))
nuclear@0 565 continue;
nuclear@0 566 }
nuclear@0 567
nuclear@0 568 PrefixString((*ppCameras)->mName,(*cur).id,(*cur).idlen);
nuclear@0 569 }
nuclear@0 570 }
nuclear@0 571
nuclear@0 572 // --------------------------------------------------------------------
nuclear@0 573 // Copy animations
nuclear@0 574 for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i,++ppAnims) {
nuclear@0 575 if (n != (int)duplicates[n]) // duplicate scene?
nuclear@0 576 {
nuclear@0 577 Copy(ppAnims, (*cur)->mAnimations[i]);
nuclear@0 578 }
nuclear@0 579 else *ppAnims = (*cur)->mAnimations[i];
nuclear@0 580
nuclear@0 581 // Add name prefixes?
nuclear@0 582 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) {
nuclear@0 583 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
nuclear@0 584 if (!FindNameMatch((*ppAnims)->mName,src,n))
nuclear@0 585 continue;
nuclear@0 586 }
nuclear@0 587
nuclear@0 588 PrefixString((*ppAnims)->mName,(*cur).id,(*cur).idlen);
nuclear@0 589
nuclear@0 590 // don't forget to update all node animation channels
nuclear@0 591 for (unsigned int a = 0; a < (*ppAnims)->mNumChannels;++a) {
nuclear@0 592 if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) {
nuclear@0 593 if (!FindNameMatch((*ppAnims)->mChannels[a]->mNodeName,src,n))
nuclear@0 594 continue;
nuclear@0 595 }
nuclear@0 596
nuclear@0 597 PrefixString((*ppAnims)->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen);
nuclear@0 598 }
nuclear@0 599 }
nuclear@0 600 }
nuclear@0 601 }
nuclear@0 602
nuclear@0 603 // Now build the output graph
nuclear@0 604 AttachToGraph ( master, nodes);
nuclear@0 605 dest->mRootNode = master->mRootNode;
nuclear@0 606
nuclear@0 607 // Check whether we succeeded at building the output graph
nuclear@0 608 for (std::vector <NodeAttachmentInfo> ::iterator it = nodes.begin();
nuclear@0 609 it != nodes.end(); ++it)
nuclear@0 610 {
nuclear@0 611 if (!(*it).resolved) {
nuclear@0 612 if (flags & AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS) {
nuclear@0 613 // search for this attachment point in all other imported scenes, too.
nuclear@0 614 for ( unsigned int n = 0; n < src.size();++n ) {
nuclear@0 615 if (n != (*it).src_idx) {
nuclear@0 616 AttachToGraph(src[n].scene,nodes);
nuclear@0 617 if ((*it).resolved)
nuclear@0 618 break;
nuclear@0 619 }
nuclear@0 620 }
nuclear@0 621 }
nuclear@0 622 if (!(*it).resolved) {
nuclear@0 623 DefaultLogger::get()->error(std::string("SceneCombiner: Failed to resolve attachment ")
nuclear@0 624 + (*it).node->mName.data + " " + (*it).attachToNode->mName.data);
nuclear@0 625 }
nuclear@0 626 }
nuclear@0 627 }
nuclear@0 628
nuclear@0 629 // now delete all input scenes. Make sure duplicate scenes aren't
nuclear@0 630 // deleted more than one time
nuclear@0 631 for ( unsigned int n = 0; n < src.size();++n ) {
nuclear@0 632 if (n != duplicates[n]) // duplicate scene?
nuclear@0 633 continue;
nuclear@0 634
nuclear@0 635 aiScene* deleteMe = src[n].scene;
nuclear@0 636
nuclear@0 637 // We need to delete the arrays before the destructor is called -
nuclear@0 638 // we are reusing the array members
nuclear@0 639 delete[] deleteMe->mMeshes; deleteMe->mMeshes = NULL;
nuclear@0 640 delete[] deleteMe->mCameras; deleteMe->mCameras = NULL;
nuclear@0 641 delete[] deleteMe->mLights; deleteMe->mLights = NULL;
nuclear@0 642 delete[] deleteMe->mMaterials; deleteMe->mMaterials = NULL;
nuclear@0 643 delete[] deleteMe->mAnimations; deleteMe->mAnimations = NULL;
nuclear@0 644
nuclear@0 645 deleteMe->mRootNode = NULL;
nuclear@0 646
nuclear@0 647 // Now we can safely delete the scene
nuclear@0 648 delete deleteMe;
nuclear@0 649 }
nuclear@0 650
nuclear@0 651 // Check flags
nuclear@0 652 if (!dest->mNumMeshes || !dest->mNumMaterials) {
nuclear@0 653 dest->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
nuclear@0 654 }
nuclear@0 655
nuclear@0 656 // We're finished
nuclear@0 657 }
nuclear@0 658
nuclear@0 659 // ------------------------------------------------------------------------------------------------
nuclear@0 660 // Build a list of unique bones
nuclear@0 661 void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
nuclear@0 662 std::vector<aiMesh*>::const_iterator it,
nuclear@0 663 std::vector<aiMesh*>::const_iterator end)
nuclear@0 664 {
nuclear@0 665 unsigned int iOffset = 0;
nuclear@0 666 for (; it != end;++it) {
nuclear@0 667 for (unsigned int l = 0; l < (*it)->mNumBones;++l) {
nuclear@0 668 aiBone* p = (*it)->mBones[l];
nuclear@0 669 uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length);
nuclear@0 670
nuclear@0 671 std::list<BoneWithHash>::iterator it2 = asBones.begin();
nuclear@0 672 std::list<BoneWithHash>::iterator end2 = asBones.end();
nuclear@0 673
nuclear@0 674 for (;it2 != end2;++it2) {
nuclear@0 675 if ((*it2).first == itml) {
nuclear@0 676 (*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset));
nuclear@0 677 break;
nuclear@0 678 }
nuclear@0 679 }
nuclear@0 680 if (end2 == it2) {
nuclear@0 681 // need to begin a new bone entry
nuclear@0 682 asBones.push_back(BoneWithHash());
nuclear@0 683 BoneWithHash& btz = asBones.back();
nuclear@0 684
nuclear@0 685 // setup members
nuclear@0 686 btz.first = itml;
nuclear@0 687 btz.second = &p->mName;
nuclear@0 688 btz.pSrcBones.push_back(BoneSrcIndex(p,iOffset));
nuclear@0 689 }
nuclear@0 690 }
nuclear@0 691 iOffset += (*it)->mNumVertices;
nuclear@0 692 }
nuclear@0 693 }
nuclear@0 694
nuclear@0 695 // ------------------------------------------------------------------------------------------------
nuclear@0 696 // Merge a list of bones
nuclear@0 697 void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
nuclear@0 698 std::vector<aiMesh*>::const_iterator end)
nuclear@0 699 {
nuclear@0 700 ai_assert(NULL != out && !out->mNumBones);
nuclear@0 701
nuclear@0 702 // find we need to build an unique list of all bones.
nuclear@0 703 // we work with hashes to make the comparisons MUCH faster,
nuclear@0 704 // at least if we have many bones.
nuclear@0 705 std::list<BoneWithHash> asBones;
nuclear@0 706 BuildUniqueBoneList(asBones, it,end);
nuclear@0 707
nuclear@0 708 // now create the output bones
nuclear@0 709 out->mNumBones = 0;
nuclear@0 710 out->mBones = new aiBone*[asBones.size()];
nuclear@0 711
nuclear@0 712 for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),end = asBones.end(); it != end;++it) {
nuclear@0 713 // Allocate a bone and setup it's name
nuclear@0 714 aiBone* pc = out->mBones[out->mNumBones++] = new aiBone();
nuclear@0 715 pc->mName = aiString( *((*it).second ));
nuclear@0 716
nuclear@0 717 std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end();
nuclear@0 718
nuclear@0 719 // Loop through all bones to be joined for this bone
nuclear@0 720 for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit) {
nuclear@0 721 pc->mNumWeights += (*wmit).first->mNumWeights;
nuclear@0 722
nuclear@0 723 // NOTE: different offset matrices for bones with equal names
nuclear@0 724 // are - at the moment - not handled correctly.
nuclear@0 725 if (wmit != (*it).pSrcBones.begin() && pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix) {
nuclear@0 726 DefaultLogger::get()->warn("Bones with equal names but different offset matrices can't be joined at the moment");
nuclear@0 727 continue;
nuclear@0 728 }
nuclear@0 729 pc->mOffsetMatrix = (*wmit).first->mOffsetMatrix;
nuclear@0 730 }
nuclear@0 731
nuclear@0 732 // Allocate the vertex weight array
nuclear@0 733 aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights];
nuclear@0 734
nuclear@0 735 // And copy the final weights - adjust the vertex IDs by the
nuclear@0 736 // face index offset of the coresponding mesh.
nuclear@0 737 for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit) {
nuclear@0 738 aiBone* pip = (*wmit).first;
nuclear@0 739 for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw) {
nuclear@0 740 const aiVertexWeight& vfi = pip->mWeights[mp];
nuclear@0 741 avw->mWeight = vfi.mWeight;
nuclear@0 742 avw->mVertexId = vfi.mVertexId + (*wmit).second;
nuclear@0 743 }
nuclear@0 744 }
nuclear@0 745 }
nuclear@0 746 }
nuclear@0 747
nuclear@0 748 // ------------------------------------------------------------------------------------------------
nuclear@0 749 // Merge a list of meshes
nuclear@0 750 void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/,
nuclear@0 751 std::vector<aiMesh*>::const_iterator begin,
nuclear@0 752 std::vector<aiMesh*>::const_iterator end)
nuclear@0 753 {
nuclear@0 754 ai_assert(NULL != _out);
nuclear@0 755
nuclear@0 756 if (begin == end) {
nuclear@0 757 *_out = NULL; // no meshes ...
nuclear@0 758 return;
nuclear@0 759 }
nuclear@0 760
nuclear@0 761 // Allocate the output mesh
nuclear@0 762 aiMesh* out = *_out = new aiMesh();
nuclear@0 763 out->mMaterialIndex = (*begin)->mMaterialIndex;
nuclear@0 764
nuclear@0 765 // Find out how much output storage we'll need
nuclear@0 766 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
nuclear@0 767 out->mNumVertices += (*it)->mNumVertices;
nuclear@0 768 out->mNumFaces += (*it)->mNumFaces;
nuclear@0 769 out->mNumBones += (*it)->mNumBones;
nuclear@0 770
nuclear@0 771 // combine primitive type flags
nuclear@0 772 out->mPrimitiveTypes |= (*it)->mPrimitiveTypes;
nuclear@0 773 }
nuclear@0 774
nuclear@0 775 if (out->mNumVertices) {
nuclear@0 776 aiVector3D* pv2;
nuclear@0 777
nuclear@0 778 // copy vertex positions
nuclear@0 779 if ((**begin).HasPositions()) {
nuclear@0 780
nuclear@0 781 pv2 = out->mVertices = new aiVector3D[out->mNumVertices];
nuclear@0 782 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
nuclear@0 783 if ((*it)->mVertices) {
nuclear@0 784 ::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D));
nuclear@0 785 }
nuclear@0 786 else DefaultLogger::get()->warn("JoinMeshes: Positions expected but input mesh contains no positions");
nuclear@0 787 pv2 += (*it)->mNumVertices;
nuclear@0 788 }
nuclear@0 789 }
nuclear@0 790 // copy normals
nuclear@0 791 if ((**begin).HasNormals()) {
nuclear@0 792
nuclear@0 793 pv2 = out->mNormals = new aiVector3D[out->mNumVertices];
nuclear@0 794 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
nuclear@0 795 if ((*it)->mNormals) {
nuclear@0 796 ::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
nuclear@0 797 }
nuclear@0 798 else DefaultLogger::get()->warn("JoinMeshes: Normals expected but input mesh contains no normals");
nuclear@0 799 pv2 += (*it)->mNumVertices;
nuclear@0 800 }
nuclear@0 801 }
nuclear@0 802 // copy tangents and bitangents
nuclear@0 803 if ((**begin).HasTangentsAndBitangents()) {
nuclear@0 804
nuclear@0 805 pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
nuclear@0 806 aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
nuclear@0 807
nuclear@0 808 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
nuclear@0 809 if ((*it)->mTangents) {
nuclear@0 810 ::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D));
nuclear@0 811 ::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
nuclear@0 812 }
nuclear@0 813 else DefaultLogger::get()->warn("JoinMeshes: Tangents expected but input mesh contains no tangents");
nuclear@0 814 pv2 += (*it)->mNumVertices;
nuclear@0 815 pv2b += (*it)->mNumVertices;
nuclear@0 816 }
nuclear@0 817 }
nuclear@0 818 // copy texture coordinates
nuclear@0 819 unsigned int n = 0;
nuclear@0 820 while ((**begin).HasTextureCoords(n)) {
nuclear@0 821 out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
nuclear@0 822
nuclear@0 823 pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
nuclear@0 824 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
nuclear@0 825
nuclear@0 826 if ((*it)->mTextureCoords[n]) {
nuclear@0 827 ::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
nuclear@0 828 }
nuclear@0 829 else DefaultLogger::get()->warn("JoinMeshes: UVs expected but input mesh contains no UVs");
nuclear@0 830 pv2 += (*it)->mNumVertices;
nuclear@0 831 }
nuclear@0 832 ++n;
nuclear@0 833 }
nuclear@0 834 // copy vertex colors
nuclear@0 835 n = 0;
nuclear@0 836 while ((**begin).HasVertexColors(n)) {
nuclear@0 837 aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
nuclear@0 838 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
nuclear@0 839
nuclear@0 840 if ((*it)->mColors[n]) {
nuclear@0 841 ::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
nuclear@0 842 }
nuclear@0 843 else DefaultLogger::get()->warn("JoinMeshes: VCs expected but input mesh contains no VCs");
nuclear@0 844 pv2 += (*it)->mNumVertices;
nuclear@0 845 }
nuclear@0 846 ++n;
nuclear@0 847 }
nuclear@0 848 }
nuclear@0 849
nuclear@0 850 if (out->mNumFaces) // just for safety
nuclear@0 851 {
nuclear@0 852 // copy faces
nuclear@0 853 out->mFaces = new aiFace[out->mNumFaces];
nuclear@0 854 aiFace* pf2 = out->mFaces;
nuclear@0 855
nuclear@0 856 unsigned int ofs = 0;
nuclear@0 857 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
nuclear@0 858 for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2) {
nuclear@0 859 aiFace& face = (*it)->mFaces[m];
nuclear@0 860 pf2->mNumIndices = face.mNumIndices;
nuclear@0 861 pf2->mIndices = face.mIndices;
nuclear@0 862
nuclear@0 863 if (ofs) {
nuclear@0 864 // add the offset to the vertex
nuclear@0 865 for (unsigned int q = 0; q < face.mNumIndices; ++q)
nuclear@0 866 face.mIndices[q] += ofs;
nuclear@0 867 }
nuclear@0 868 face.mIndices = NULL;
nuclear@0 869 }
nuclear@0 870 ofs += (*it)->mNumVertices;
nuclear@0 871 }
nuclear@0 872 }
nuclear@0 873
nuclear@0 874 // bones - as this is quite lengthy, I moved the code to a separate function
nuclear@0 875 if (out->mNumBones)
nuclear@0 876 MergeBones(out,begin,end);
nuclear@0 877
nuclear@0 878 // delete all source meshes
nuclear@0 879 for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
nuclear@0 880 delete *it;
nuclear@0 881 }
nuclear@0 882
nuclear@0 883 // ------------------------------------------------------------------------------------------------
nuclear@0 884 template <typename Type>
nuclear@0 885 inline void CopyPtrArray (Type**& dest, const Type* const * src, unsigned int num)
nuclear@0 886 {
nuclear@0 887 if (!num)
nuclear@0 888 {
nuclear@0 889 dest = NULL;
nuclear@0 890 return;
nuclear@0 891 }
nuclear@0 892 dest = new Type*[num];
nuclear@0 893 for (unsigned int i = 0; i < num;++i) {
nuclear@0 894 SceneCombiner::Copy(&dest[i],src[i]);
nuclear@0 895 }
nuclear@0 896 }
nuclear@0 897
nuclear@0 898 // ------------------------------------------------------------------------------------------------
nuclear@0 899 template <typename Type>
nuclear@0 900 inline void GetArrayCopy (Type*& dest, unsigned int num )
nuclear@0 901 {
nuclear@0 902 if (!dest)return;
nuclear@0 903 Type* old = dest;
nuclear@0 904
nuclear@0 905 dest = new Type[num];
nuclear@0 906 ::memcpy(dest, old, sizeof(Type) * num);
nuclear@0 907 }
nuclear@0 908
nuclear@0 909 // ------------------------------------------------------------------------------------------------
nuclear@0 910 void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src)
nuclear@0 911 {
nuclear@0 912 // reuse the old scene or allocate a new?
nuclear@0 913 if (*_dest) {
nuclear@0 914 (*_dest)->~aiScene();
nuclear@0 915 new (*_dest) aiScene();
nuclear@0 916 }
nuclear@0 917 else *_dest = new aiScene();
nuclear@0 918
nuclear@0 919 ::memcpy(*_dest,src,sizeof(aiScene));
nuclear@0 920 }
nuclear@0 921
nuclear@0 922 // ------------------------------------------------------------------------------------------------
nuclear@0 923 void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
nuclear@0 924 {
nuclear@0 925 ai_assert(NULL != _dest && NULL != src);
nuclear@0 926
nuclear@0 927 if (allocate) {
nuclear@0 928 *_dest = new aiScene();
nuclear@0 929 }
nuclear@0 930 aiScene* dest = *_dest;
nuclear@0 931 ai_assert(dest);
nuclear@0 932
nuclear@0 933 // copy animations
nuclear@0 934 dest->mNumAnimations = src->mNumAnimations;
nuclear@0 935 CopyPtrArray(dest->mAnimations,src->mAnimations,
nuclear@0 936 dest->mNumAnimations);
nuclear@0 937
nuclear@0 938 // copy textures
nuclear@0 939 dest->mNumTextures = src->mNumTextures;
nuclear@0 940 CopyPtrArray(dest->mTextures,src->mTextures,
nuclear@0 941 dest->mNumTextures);
nuclear@0 942
nuclear@0 943 // copy materials
nuclear@0 944 dest->mNumMaterials = src->mNumMaterials;
nuclear@0 945 CopyPtrArray(dest->mMaterials,src->mMaterials,
nuclear@0 946 dest->mNumMaterials);
nuclear@0 947
nuclear@0 948 // copy lights
nuclear@0 949 dest->mNumLights = src->mNumLights;
nuclear@0 950 CopyPtrArray(dest->mLights,src->mLights,
nuclear@0 951 dest->mNumLights);
nuclear@0 952
nuclear@0 953 // copy cameras
nuclear@0 954 dest->mNumCameras = src->mNumCameras;
nuclear@0 955 CopyPtrArray(dest->mCameras,src->mCameras,
nuclear@0 956 dest->mNumCameras);
nuclear@0 957
nuclear@0 958 // copy meshes
nuclear@0 959 dest->mNumMeshes = src->mNumMeshes;
nuclear@0 960 CopyPtrArray(dest->mMeshes,src->mMeshes,
nuclear@0 961 dest->mNumMeshes);
nuclear@0 962
nuclear@0 963 // now - copy the root node of the scene (deep copy, too)
nuclear@0 964 Copy( &dest->mRootNode, src->mRootNode);
nuclear@0 965
nuclear@0 966 // and keep the flags ...
nuclear@0 967 dest->mFlags = src->mFlags;
nuclear@0 968
nuclear@0 969 // source private data might be NULL if the scene is user-allocated (i.e. for use with the export API)
nuclear@0 970 ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : 0;
nuclear@0 971 }
nuclear@0 972
nuclear@0 973 // ------------------------------------------------------------------------------------------------
nuclear@0 974 void SceneCombiner::Copy (aiMesh** _dest, const aiMesh* src)
nuclear@0 975 {
nuclear@0 976 ai_assert(NULL != _dest && NULL != src);
nuclear@0 977
nuclear@0 978 aiMesh* dest = *_dest = new aiMesh();
nuclear@0 979
nuclear@0 980 // get a flat copy
nuclear@0 981 ::memcpy(dest,src,sizeof(aiMesh));
nuclear@0 982
nuclear@0 983 // and reallocate all arrays
nuclear@0 984 GetArrayCopy( dest->mVertices, dest->mNumVertices );
nuclear@0 985 GetArrayCopy( dest->mNormals , dest->mNumVertices );
nuclear@0 986 GetArrayCopy( dest->mTangents, dest->mNumVertices );
nuclear@0 987 GetArrayCopy( dest->mBitangents, dest->mNumVertices );
nuclear@0 988
nuclear@0 989 unsigned int n = 0;
nuclear@0 990 while (dest->HasTextureCoords(n))
nuclear@0 991 GetArrayCopy( dest->mTextureCoords[n++], dest->mNumVertices );
nuclear@0 992
nuclear@0 993 n = 0;
nuclear@0 994 while (dest->HasVertexColors(n))
nuclear@0 995 GetArrayCopy( dest->mColors[n++], dest->mNumVertices );
nuclear@0 996
nuclear@0 997 // make a deep copy of all bones
nuclear@0 998 CopyPtrArray(dest->mBones,dest->mBones,dest->mNumBones);
nuclear@0 999
nuclear@0 1000 // make a deep copy of all faces
nuclear@0 1001 GetArrayCopy(dest->mFaces,dest->mNumFaces);
nuclear@0 1002 for (unsigned int i = 0; i < dest->mNumFaces;++i)
nuclear@0 1003 {
nuclear@0 1004 aiFace& f = dest->mFaces[i];
nuclear@0 1005 GetArrayCopy(f.mIndices,f.mNumIndices);
nuclear@0 1006 }
nuclear@0 1007 }
nuclear@0 1008
nuclear@0 1009 // ------------------------------------------------------------------------------------------------
nuclear@0 1010 void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src)
nuclear@0 1011 {
nuclear@0 1012 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1013
nuclear@0 1014 aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
nuclear@0 1015 dest->mNumAllocated = src->mNumAllocated;
nuclear@0 1016 dest->mNumProperties = src->mNumProperties;
nuclear@0 1017 dest->mProperties = new aiMaterialProperty* [dest->mNumAllocated];
nuclear@0 1018
nuclear@0 1019 for (unsigned int i = 0; i < dest->mNumProperties;++i)
nuclear@0 1020 {
nuclear@0 1021 aiMaterialProperty* prop = dest->mProperties[i] = new aiMaterialProperty();
nuclear@0 1022 aiMaterialProperty* sprop = src->mProperties[i];
nuclear@0 1023
nuclear@0 1024 prop->mDataLength = sprop->mDataLength;
nuclear@0 1025 prop->mData = new char[prop->mDataLength];
nuclear@0 1026 ::memcpy(prop->mData,sprop->mData,prop->mDataLength);
nuclear@0 1027
nuclear@0 1028 prop->mIndex = sprop->mIndex;
nuclear@0 1029 prop->mSemantic = sprop->mSemantic;
nuclear@0 1030 prop->mKey = sprop->mKey;
nuclear@0 1031 prop->mType = sprop->mType;
nuclear@0 1032 }
nuclear@0 1033 }
nuclear@0 1034
nuclear@0 1035 // ------------------------------------------------------------------------------------------------
nuclear@0 1036 void SceneCombiner::Copy (aiTexture** _dest, const aiTexture* src)
nuclear@0 1037 {
nuclear@0 1038 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1039
nuclear@0 1040 aiTexture* dest = *_dest = new aiTexture();
nuclear@0 1041
nuclear@0 1042 // get a flat copy
nuclear@0 1043 ::memcpy(dest,src,sizeof(aiTexture));
nuclear@0 1044
nuclear@0 1045 // and reallocate all arrays. We must do it manually here
nuclear@0 1046 const char* old = (const char*)dest->pcData;
nuclear@0 1047 if (old)
nuclear@0 1048 {
nuclear@0 1049 unsigned int cpy;
nuclear@0 1050 if (!dest->mHeight)cpy = dest->mWidth;
nuclear@0 1051 else cpy = dest->mHeight * dest->mWidth * sizeof(aiTexel);
nuclear@0 1052
nuclear@0 1053 if (!cpy)
nuclear@0 1054 {
nuclear@0 1055 dest->pcData = NULL;
nuclear@0 1056 return;
nuclear@0 1057 }
nuclear@0 1058 // the cast is legal, the aiTexel c'tor does nothing important
nuclear@0 1059 dest->pcData = (aiTexel*) new char[cpy];
nuclear@0 1060 ::memcpy(dest->pcData, old, cpy);
nuclear@0 1061 }
nuclear@0 1062 }
nuclear@0 1063
nuclear@0 1064 // ------------------------------------------------------------------------------------------------
nuclear@0 1065 void SceneCombiner::Copy (aiAnimation** _dest, const aiAnimation* src)
nuclear@0 1066 {
nuclear@0 1067 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1068
nuclear@0 1069 aiAnimation* dest = *_dest = new aiAnimation();
nuclear@0 1070
nuclear@0 1071 // get a flat copy
nuclear@0 1072 ::memcpy(dest,src,sizeof(aiAnimation));
nuclear@0 1073
nuclear@0 1074 // and reallocate all arrays
nuclear@0 1075 CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels );
nuclear@0 1076 }
nuclear@0 1077
nuclear@0 1078 // ------------------------------------------------------------------------------------------------
nuclear@0 1079 void SceneCombiner::Copy (aiNodeAnim** _dest, const aiNodeAnim* src)
nuclear@0 1080 {
nuclear@0 1081 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1082
nuclear@0 1083 aiNodeAnim* dest = *_dest = new aiNodeAnim();
nuclear@0 1084
nuclear@0 1085 // get a flat copy
nuclear@0 1086 ::memcpy(dest,src,sizeof(aiNodeAnim));
nuclear@0 1087
nuclear@0 1088 // and reallocate all arrays
nuclear@0 1089 GetArrayCopy( dest->mPositionKeys, dest->mNumPositionKeys );
nuclear@0 1090 GetArrayCopy( dest->mScalingKeys, dest->mNumScalingKeys );
nuclear@0 1091 GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys );
nuclear@0 1092 }
nuclear@0 1093
nuclear@0 1094 // ------------------------------------------------------------------------------------------------
nuclear@0 1095 void SceneCombiner::Copy (aiCamera** _dest,const aiCamera* src)
nuclear@0 1096 {
nuclear@0 1097 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1098
nuclear@0 1099 aiCamera* dest = *_dest = new aiCamera();
nuclear@0 1100
nuclear@0 1101 // get a flat copy, that's already OK
nuclear@0 1102 ::memcpy(dest,src,sizeof(aiCamera));
nuclear@0 1103 }
nuclear@0 1104
nuclear@0 1105 // ------------------------------------------------------------------------------------------------
nuclear@0 1106 void SceneCombiner::Copy (aiLight** _dest, const aiLight* src)
nuclear@0 1107 {
nuclear@0 1108 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1109
nuclear@0 1110 aiLight* dest = *_dest = new aiLight();
nuclear@0 1111
nuclear@0 1112 // get a flat copy, that's already OK
nuclear@0 1113 ::memcpy(dest,src,sizeof(aiLight));
nuclear@0 1114 }
nuclear@0 1115
nuclear@0 1116 // ------------------------------------------------------------------------------------------------
nuclear@0 1117 void SceneCombiner::Copy (aiBone** _dest, const aiBone* src)
nuclear@0 1118 {
nuclear@0 1119 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1120
nuclear@0 1121 aiBone* dest = *_dest = new aiBone();
nuclear@0 1122
nuclear@0 1123 // get a flat copy
nuclear@0 1124 ::memcpy(dest,src,sizeof(aiBone));
nuclear@0 1125
nuclear@0 1126 // and reallocate all arrays
nuclear@0 1127 GetArrayCopy( dest->mWeights, dest->mNumWeights );
nuclear@0 1128 }
nuclear@0 1129
nuclear@0 1130 // ------------------------------------------------------------------------------------------------
nuclear@0 1131 void SceneCombiner::Copy (aiNode** _dest, const aiNode* src)
nuclear@0 1132 {
nuclear@0 1133 ai_assert(NULL != _dest && NULL != src);
nuclear@0 1134
nuclear@0 1135 aiNode* dest = *_dest = new aiNode();
nuclear@0 1136
nuclear@0 1137 // get a flat copy
nuclear@0 1138 ::memcpy(dest,src,sizeof(aiNode));
nuclear@0 1139
nuclear@0 1140 // and reallocate all arrays
nuclear@0 1141 GetArrayCopy( dest->mMeshes, dest->mNumMeshes );
nuclear@0 1142 CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren);
nuclear@0 1143 }
nuclear@0 1144
nuclear@0 1145
nuclear@0 1146 }