vrshoot

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