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