vrshoot

annotate libs/assimp/PretransformVertices.cpp @ 1:e7ca128b8713

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