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 }
|