1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2016, assimp team
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41
42 /** @file PretransformVertices.cpp
43 * @brief Implementation of the "PretransformVertices" post processing step
44 */
45
46
47 #include "PretransformVertices.h"
48 #include "ProcessHelper.h"
49 #include "SceneCombiner.h"
50 #include "Exceptional.h"
51
52 using namespace Assimp;
53
54 // some array offsets
55 #define AI_PTVS_VERTEX 0x0
56 #define AI_PTVS_FACE 0x1
57
58 // ------------------------------------------------------------------------------------------------
59 // Constructor to be privately used by Importer
PretransformVertices()60 PretransformVertices::PretransformVertices()
61 : configKeepHierarchy (false), configNormalize(false), configTransform(false), configTransformation()
62 {
63 }
64
65 // ------------------------------------------------------------------------------------------------
66 // Destructor, private as well
~PretransformVertices()67 PretransformVertices::~PretransformVertices()
68 {
69 // nothing to do here
70 }
71
72 // ------------------------------------------------------------------------------------------------
73 // Returns whether the processing step is present in the given flag field.
IsActive(unsigned int pFlags) const74 bool PretransformVertices::IsActive( unsigned int pFlags) const
75 {
76 return (pFlags & aiProcess_PreTransformVertices) != 0;
77 }
78
79 // ------------------------------------------------------------------------------------------------
80 // Setup import configuration
SetupProperties(const Importer * pImp)81 void PretransformVertices::SetupProperties(const Importer* pImp)
82 {
83 // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE,
84 // AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION
85 configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0));
86 configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
87 configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0));
88
89 configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
90 }
91
92 // ------------------------------------------------------------------------------------------------
93 // Count the number of nodes
CountNodes(aiNode * pcNode)94 unsigned int PretransformVertices::CountNodes( aiNode* pcNode )
95 {
96 unsigned int iRet = 1;
97 for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
98 {
99 iRet += CountNodes(pcNode->mChildren[i]);
100 }
101 return iRet;
102 }
103
104 // ------------------------------------------------------------------------------------------------
105 // Get a bitwise combination identifying the vertex format of a mesh
GetMeshVFormat(aiMesh * pcMesh)106 unsigned int PretransformVertices::GetMeshVFormat(aiMesh* pcMesh)
107 {
108 // the vertex format is stored in aiMesh::mBones for later retrieval.
109 // there isn't a good reason to compute it a few hundred times
110 // from scratch. The pointer is unused as animations are lost
111 // during PretransformVertices.
112 if (pcMesh->mBones)
113 return (unsigned int)(uint64_t)pcMesh->mBones;
114
115
116 const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
117
118 // store the value for later use
119 pcMesh->mBones = (aiBone**)(uint64_t)iRet;
120 return iRet;
121 }
122
123 // ------------------------------------------------------------------------------------------------
124 // Count the number of vertices in the whole scene and a given
125 // material index
CountVerticesAndFaces(aiScene * pcScene,aiNode * pcNode,unsigned int iMat,unsigned int iVFormat,unsigned int * piFaces,unsigned int * piVertices)126 void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
127 unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices)
128 {
129 for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
130 {
131 aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ];
132 if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
133 {
134 *piVertices += pcMesh->mNumVertices;
135 *piFaces += pcMesh->mNumFaces;
136 }
137 }
138 for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
139 {
140 CountVerticesAndFaces(pcScene,pcNode->mChildren[i],iMat,
141 iVFormat,piFaces,piVertices);
142 }
143 }
144
145 // ------------------------------------------------------------------------------------------------
146 // Collect vertex/face data
CollectData(aiScene * pcScene,aiNode * pcNode,unsigned int iMat,unsigned int iVFormat,aiMesh * pcMeshOut,unsigned int aiCurrent[2],unsigned int * num_refs)147 void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
148 unsigned int iVFormat, aiMesh* pcMeshOut,
149 unsigned int aiCurrent[2], unsigned int* num_refs)
150 {
151 // No need to multiply if there's no transformation
152 const bool identity = pcNode->mTransformation.IsIdentity();
153 for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
154 {
155 aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ];
156 if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
157 {
158 // Decrement mesh reference counter
159 unsigned int& num_ref = num_refs[pcNode->mMeshes[i]];
160 ai_assert(0 != num_ref);
161 --num_ref;
162
163 if (identity) {
164 // copy positions without modifying them
165 ::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX],
166 pcMesh->mVertices,
167 pcMesh->mNumVertices * sizeof(aiVector3D));
168
169 if (iVFormat & 0x2) {
170 // copy normals without modifying them
171 ::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX],
172 pcMesh->mNormals,
173 pcMesh->mNumVertices * sizeof(aiVector3D));
174 }
175 if (iVFormat & 0x4)
176 {
177 // copy tangents without modifying them
178 ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX],
179 pcMesh->mTangents,
180 pcMesh->mNumVertices * sizeof(aiVector3D));
181 // copy bitangents without modifying them
182 ::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX],
183 pcMesh->mBitangents,
184 pcMesh->mNumVertices * sizeof(aiVector3D));
185 }
186 }
187 else
188 {
189 // copy positions, transform them to worldspace
190 for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
191 pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n];
192 }
193 aiMatrix4x4 mWorldIT = pcNode->mTransformation;
194 mWorldIT.Inverse().Transpose();
195
196 // TODO: implement Inverse() for aiMatrix3x3
197 aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
198
199 if (iVFormat & 0x2)
200 {
201 // copy normals, transform them to worldspace
202 for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
203 pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] =
204 (m * pcMesh->mNormals[n]).Normalize();
205 }
206 }
207 if (iVFormat & 0x4)
208 {
209 // copy tangents and bitangents, transform them to worldspace
210 for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
211 pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mTangents[n]).Normalize();
212 pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize();
213 }
214 }
215 }
216 unsigned int p = 0;
217 while (iVFormat & (0x100 << p))
218 {
219 // copy texture coordinates
220 memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX],
221 pcMesh->mTextureCoords[p],
222 pcMesh->mNumVertices * sizeof(aiVector3D));
223 ++p;
224 }
225 p = 0;
226 while (iVFormat & (0x1000000 << p))
227 {
228 // copy vertex colors
229 memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX],
230 pcMesh->mColors[p],
231 pcMesh->mNumVertices * sizeof(aiColor4D));
232 ++p;
233 }
234 // now we need to copy all faces. since we will delete the source mesh afterwards,
235 // we don't need to reallocate the array of indices except if this mesh is
236 // referenced multiple times.
237 for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck)
238 {
239 aiFace& f_src = pcMesh->mFaces[planck];
240 aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck];
241
242 const unsigned int num_idx = f_src.mNumIndices;
243
244 f_dst.mNumIndices = num_idx;
245
246 unsigned int* pi;
247 if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */
248 pi = f_dst.mIndices = f_src.mIndices;
249
250 // offset all vertex indices
251 for (unsigned int hahn = 0; hahn < num_idx;++hahn){
252 pi[hahn] += aiCurrent[AI_PTVS_VERTEX];
253 }
254 }
255 else {
256 pi = f_dst.mIndices = new unsigned int[num_idx];
257
258 // copy and offset all vertex indices
259 for (unsigned int hahn = 0; hahn < num_idx;++hahn){
260 pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX];
261 }
262 }
263
264 // Update the mPrimitiveTypes member of the mesh
265 switch (pcMesh->mFaces[planck].mNumIndices)
266 {
267 case 0x1:
268 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT;
269 break;
270 case 0x2:
271 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE;
272 break;
273 case 0x3:
274 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
275 break;
276 default:
277 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
278 break;
279 };
280 }
281 aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices;
282 aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces;
283 }
284 }
285
286 // append all children of us
287 for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
288 CollectData(pcScene,pcNode->mChildren[i],iMat,
289 iVFormat,pcMeshOut,aiCurrent,num_refs);
290 }
291 }
292
293 // ------------------------------------------------------------------------------------------------
294 // Get a list of all vertex formats that occur for a given material index
295 // The output list contains duplicate elements
GetVFormatList(aiScene * pcScene,unsigned int iMat,std::list<unsigned int> & aiOut)296 void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat,
297 std::list<unsigned int>& aiOut)
298 {
299 for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
300 {
301 aiMesh* pcMesh = pcScene->mMeshes[ i ];
302 if (iMat == pcMesh->mMaterialIndex) {
303 aiOut.push_back(GetMeshVFormat(pcMesh));
304 }
305 }
306 }
307
308 // ------------------------------------------------------------------------------------------------
309 // Compute the absolute transformation matrices of each node
ComputeAbsoluteTransform(aiNode * pcNode)310 void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode )
311 {
312 if (pcNode->mParent) {
313 pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation;
314 }
315
316 for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
317 ComputeAbsoluteTransform(pcNode->mChildren[i]);
318 }
319 }
320
321 // ------------------------------------------------------------------------------------------------
322 // Apply the node transformation to a mesh
ApplyTransform(aiMesh * mesh,const aiMatrix4x4 & mat)323 void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)
324 {
325 // Check whether we need to transform the coordinates at all
326 if (!mat.IsIdentity()) {
327
328 if (mesh->HasPositions()) {
329 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
330 mesh->mVertices[i] = mat * mesh->mVertices[i];
331 }
332 }
333 if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
334 aiMatrix4x4 mWorldIT = mat;
335 mWorldIT.Inverse().Transpose();
336
337 // TODO: implement Inverse() for aiMatrix3x3
338 aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
339
340 if (mesh->HasNormals()) {
341 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
342 mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
343 }
344 }
345 if (mesh->HasTangentsAndBitangents()) {
346 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
347 mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
348 mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
349 }
350 }
351 }
352 }
353 }
354
355 // ------------------------------------------------------------------------------------------------
356 // Simple routine to build meshes in worldspace, no further optimization
BuildWCSMeshes(std::vector<aiMesh * > & out,aiMesh ** in,unsigned int numIn,aiNode * node)357 void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in,
358 unsigned int numIn, aiNode* node)
359 {
360 // NOTE:
361 // aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy
362 // aiMesh::mBones store reference to abs. transform we multiplied with
363
364 // process meshes
365 for (unsigned int i = 0; i < node->mNumMeshes;++i) {
366 aiMesh* mesh = in[node->mMeshes[i]];
367
368 // check whether we can operate on this mesh
369 if (!mesh->mBones || *reinterpret_cast<aiMatrix4x4*>(mesh->mBones) == node->mTransformation) {
370 // yes, we can.
371 mesh->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
372 mesh->mNumBones = UINT_MAX;
373 }
374 else {
375
376 // try to find us in the list of newly created meshes
377 for (unsigned int n = 0; n < out.size(); ++n) {
378 aiMesh* ctz = out[n];
379 if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4*>(ctz->mBones) == node->mTransformation) {
380
381 // ok, use this one. Update node mesh index
382 node->mMeshes[i] = numIn + n;
383 }
384 }
385 if (node->mMeshes[i] < numIn) {
386 // Worst case. Need to operate on a full copy of the mesh
387 DefaultLogger::get()->info("PretransformVertices: Copying mesh due to mismatching transforms");
388 aiMesh* ntz;
389
390 const unsigned int tmp = mesh->mNumBones; //
391 mesh->mNumBones = 0;
392 SceneCombiner::Copy(&ntz,mesh);
393 mesh->mNumBones = tmp;
394
395 ntz->mNumBones = node->mMeshes[i];
396 ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
397
398 out.push_back(ntz);
399
400 node->mMeshes[i] = numIn + out.size() - 1;
401 }
402 }
403 }
404
405 // call children
406 for (unsigned int i = 0; i < node->mNumChildren;++i)
407 BuildWCSMeshes(out,in,numIn,node->mChildren[i]);
408 }
409
410 // ------------------------------------------------------------------------------------------------
411 // Reset transformation matrices to identity
MakeIdentityTransform(aiNode * nd)412 void PretransformVertices::MakeIdentityTransform(aiNode* nd)
413 {
414 nd->mTransformation = aiMatrix4x4();
415
416 // call children
417 for (unsigned int i = 0; i < nd->mNumChildren;++i)
418 MakeIdentityTransform(nd->mChildren[i]);
419 }
420
421 // ------------------------------------------------------------------------------------------------
422 // Build reference counters for all meshes
BuildMeshRefCountArray(aiNode * nd,unsigned int * refs)423 void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs)
424 {
425 for (unsigned int i = 0; i< nd->mNumMeshes;++i)
426 refs[nd->mMeshes[i]]++;
427
428 // call children
429 for (unsigned int i = 0; i < nd->mNumChildren;++i)
430 BuildMeshRefCountArray(nd->mChildren[i],refs);
431 }
432
433 // ------------------------------------------------------------------------------------------------
434 // Executes the post processing step on the given imported data.
Execute(aiScene * pScene)435 void PretransformVertices::Execute( aiScene* pScene)
436 {
437 DefaultLogger::get()->debug("PretransformVerticesProcess begin");
438
439 // Return immediately if we have no meshes
440 if (!pScene->mNumMeshes)
441 return;
442
443 const unsigned int iOldMeshes = pScene->mNumMeshes;
444 const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
445 const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
446
447 if(configTransform) {
448 pScene->mRootNode->mTransformation = configTransformation;
449 }
450
451 // first compute absolute transformation matrices for all nodes
452 ComputeAbsoluteTransform(pScene->mRootNode);
453
454 // Delete aiMesh::mBones for all meshes. The bones are
455 // removed during this step and we need the pointer as
456 // temporary storage
457 for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
458 aiMesh* mesh = pScene->mMeshes[i];
459
460 for (unsigned int a = 0; a < mesh->mNumBones;++a)
461 delete mesh->mBones[a];
462
463 delete[] mesh->mBones;
464 mesh->mBones = NULL;
465 }
466
467 // now build a list of output meshes
468 std::vector<aiMesh*> apcOutMeshes;
469
470 // Keep scene hierarchy? It's an easy job in this case ...
471 // we go on and transform all meshes, if one is referenced by nodes
472 // with different absolute transformations a depth copy of the mesh
473 // is required.
474 if( configKeepHierarchy ) {
475
476 // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
477 BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode);
478
479 // ... if new meshes have been generated, append them to the end of the scene
480 if (apcOutMeshes.size() > 0) {
481 aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()];
482
483 memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes);
484 memcpy(npp+pScene->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size());
485
486 pScene->mNumMeshes += apcOutMeshes.size();
487 delete[] pScene->mMeshes; pScene->mMeshes = npp;
488 }
489
490 // now iterate through all meshes and transform them to worldspace
491 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
492 ApplyTransform(pScene->mMeshes[i],*reinterpret_cast<aiMatrix4x4*>( pScene->mMeshes[i]->mBones ));
493
494 // prevent improper destruction
495 pScene->mMeshes[i]->mBones = NULL;
496 pScene->mMeshes[i]->mNumBones = 0;
497 }
498 }
499 else {
500
501 apcOutMeshes.reserve(pScene->mNumMaterials<<1u);
502 std::list<unsigned int> aiVFormats;
503
504 std::vector<unsigned int> s(pScene->mNumMeshes,0);
505 BuildMeshRefCountArray(pScene->mRootNode,&s[0]);
506
507 for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
508 // get the list of all vertex formats for this material
509 aiVFormats.clear();
510 GetVFormatList(pScene,i,aiVFormats);
511 aiVFormats.sort();
512 aiVFormats.unique();
513 for (std::list<unsigned int>::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) {
514 unsigned int iVertices = 0;
515 unsigned int iFaces = 0;
516 CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices);
517 if (0 != iFaces && 0 != iVertices)
518 {
519 apcOutMeshes.push_back(new aiMesh());
520 aiMesh* pcMesh = apcOutMeshes.back();
521 pcMesh->mNumFaces = iFaces;
522 pcMesh->mNumVertices = iVertices;
523 pcMesh->mFaces = new aiFace[iFaces];
524 pcMesh->mVertices = new aiVector3D[iVertices];
525 pcMesh->mMaterialIndex = i;
526 if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices];
527 if ((*j) & 0x4)
528 {
529 pcMesh->mTangents = new aiVector3D[iVertices];
530 pcMesh->mBitangents = new aiVector3D[iVertices];
531 }
532 iFaces = 0;
533 while ((*j) & (0x100 << iFaces))
534 {
535 pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
536 if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3;
537 else pcMesh->mNumUVComponents[iFaces] = 2;
538 iFaces++;
539 }
540 iFaces = 0;
541 while ((*j) & (0x1000000 << iFaces))
542 pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
543
544 // fill the mesh ...
545 unsigned int aiTemp[2] = {0,0};
546 CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]);
547 }
548 }
549 }
550
551 // If no meshes are referenced in the node graph it is possible that we get no output meshes.
552 if (apcOutMeshes.empty()) {
553 throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes");
554 }
555 else
556 {
557 // now delete all meshes in the scene and build a new mesh list
558 for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
559 {
560 aiMesh* mesh = pScene->mMeshes[i];
561 mesh->mNumBones = 0;
562 mesh->mBones = NULL;
563
564 // we're reusing the face index arrays. avoid destruction
565 for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
566 mesh->mFaces[a].mNumIndices = 0;
567 mesh->mFaces[a].mIndices = NULL;
568 }
569
570 delete mesh;
571
572 // Invalidate the contents of the old mesh array. We will most
573 // likely have less output meshes now, so the last entries of
574 // the mesh array are not overridden. We set them to NULL to
575 // make sure the developer gets notified when his application
576 // attempts to access these fields ...
577 mesh = NULL;
578 }
579
580 // It is impossible that we have more output meshes than
581 // input meshes, so we can easily reuse the old mesh array
582 pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
583 for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
584 pScene->mMeshes[i] = apcOutMeshes[i];
585 }
586 }
587 }
588
589 // remove all animations from the scene
590 for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
591 delete pScene->mAnimations[i];
592 delete[] pScene->mAnimations;
593
594 pScene->mAnimations = NULL;
595 pScene->mNumAnimations = 0;
596
597 // --- we need to keep all cameras and lights
598 for (unsigned int i = 0; i < pScene->mNumCameras;++i)
599 {
600 aiCamera* cam = pScene->mCameras[i];
601 const aiNode* nd = pScene->mRootNode->FindNode(cam->mName);
602 ai_assert(NULL != nd);
603
604 // multiply all properties of the camera with the absolute
605 // transformation of the corresponding node
606 cam->mPosition = nd->mTransformation * cam->mPosition;
607 cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt;
608 cam->mUp = aiMatrix3x3( nd->mTransformation ) * cam->mUp;
609 }
610
611 for (unsigned int i = 0; i < pScene->mNumLights;++i)
612 {
613 aiLight* l = pScene->mLights[i];
614 const aiNode* nd = pScene->mRootNode->FindNode(l->mName);
615 ai_assert(NULL != nd);
616
617 // multiply all properties of the camera with the absolute
618 // transformation of the corresponding node
619 l->mPosition = nd->mTransformation * l->mPosition;
620 l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection;
621 l->mUp = aiMatrix3x3( nd->mTransformation ) * l->mUp;
622 }
623
624 if( !configKeepHierarchy ) {
625
626 // now delete all nodes in the scene and build a new
627 // flat node graph with a root node and some level 1 children
628 delete pScene->mRootNode;
629 pScene->mRootNode = new aiNode();
630 pScene->mRootNode->mName.Set("<dummy_root>");
631
632 if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras)
633 {
634 pScene->mRootNode->mNumMeshes = 1;
635 pScene->mRootNode->mMeshes = new unsigned int[1];
636 pScene->mRootNode->mMeshes[0] = 0;
637 }
638 else
639 {
640 pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras;
641 aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
642
643 // generate mesh nodes
644 for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
645 {
646 aiNode* pcNode = *nodes = new aiNode();
647 pcNode->mParent = pScene->mRootNode;
648 pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"mesh_%u",i);
649
650 // setup mesh indices
651 pcNode->mNumMeshes = 1;
652 pcNode->mMeshes = new unsigned int[1];
653 pcNode->mMeshes[0] = i;
654 }
655 // generate light nodes
656 for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
657 {
658 aiNode* pcNode = *nodes = new aiNode();
659 pcNode->mParent = pScene->mRootNode;
660 pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i);
661 pScene->mLights[i]->mName = pcNode->mName;
662 }
663 // generate camera nodes
664 for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
665 {
666 aiNode* pcNode = *nodes = new aiNode();
667 pcNode->mParent = pScene->mRootNode;
668 pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i);
669 pScene->mCameras[i]->mName = pcNode->mName;
670 }
671 }
672 }
673 else {
674 // ... and finally set the transformation matrix of all nodes to identity
675 MakeIdentityTransform(pScene->mRootNode);
676 }
677
678 if (configNormalize) {
679 // compute the boundary of all meshes
680 aiVector3D min,max;
681 MinMaxChooser<aiVector3D> ()(min,max);
682
683 for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
684 aiMesh* m = pScene->mMeshes[a];
685 for (unsigned int i = 0; i < m->mNumVertices;++i) {
686 min = std::min(m->mVertices[i],min);
687 max = std::max(m->mVertices[i],max);
688 }
689 }
690
691 // find the dominant axis
692 aiVector3D d = max-min;
693 const float div = std::max(d.x,std::max(d.y,d.z))*0.5f;
694
695 d = min+d*0.5f;
696 for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
697 aiMesh* m = pScene->mMeshes[a];
698 for (unsigned int i = 0; i < m->mNumVertices;++i) {
699 m->mVertices[i] = (m->mVertices[i]-d)/div;
700 }
701 }
702 }
703
704 // print statistics
705 if (!DefaultLogger::isNullLogger())
706 {
707 char buffer[4096];
708
709 DefaultLogger::get()->debug("PretransformVerticesProcess finished");
710
711 ::ai_snprintf(buffer,4096,"Removed %u nodes and %u animation channels (%u output nodes)",
712 iOldNodes,iOldAnimationChannels,CountNodes(pScene->mRootNode));
713 DefaultLogger::get()->info(buffer);
714
715 ai_snprintf(buffer, 4096,"Kept %u lights and %u cameras",
716 pScene->mNumLights,pScene->mNumCameras);
717 DefaultLogger::get()->info(buffer);
718
719 ai_snprintf(buffer, 4096,"Moved %u meshes to WCS (number of output meshes: %u)",
720 iOldMeshes,pScene->mNumMeshes);
721 DefaultLogger::get()->info(buffer);
722 }
723 }
724
725