OptimizeGraphProcess.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /*
  2. Open Asset Import Library (ASSIMP)
  3. ----------------------------------------------------------------------
  4. Copyright (c) 2006-2008, ASSIMP Development Team
  5. All rights reserved.
  6. Redistribution and use of this software in source and binary forms,
  7. with or without modification, are permitted provided that the
  8. following conditions are met:
  9. * Redistributions of source code must retain the above
  10. copyright notice, this list of conditions and the
  11. following disclaimer.
  12. * Redistributions in binary form must reproduce the above
  13. copyright notice, this list of conditions and the
  14. following disclaimer in the documentation and/or other
  15. materials provided with the distribution.
  16. * Neither the name of the ASSIMP team, nor the names of its
  17. contributors may be used to endorse or promote products
  18. derived from this software without specific prior
  19. written permission of the ASSIMP Development Team.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. ----------------------------------------------------------------------
  32. */
  33. /** Implementation of the OptimizeGraphProcess post-processing step*/
  34. #include "AssimpPCH.h"
  35. #include "OptimizeGraphProcess.h"
  36. #include "Hash.h"
  37. using namespace Assimp;
  38. // MSB for type unsigned int
  39. #define AI_OG_UINT_MSB (1u<<((sizeof(unsigned int)*8u)-1u))
  40. #define AI_OG_UINT_MSB_2 (AI_OG_UINT_MSB>>1)
  41. // check whether a node/a mesh is locked
  42. #define AI_OG_IS_NODE_LOCKED(nd) (nd->mNumChildren & AI_OG_UINT_MSB)
  43. #define AI_OG_IS_MESH_LOCKED(ms) (ms->mNumBones & AI_OG_UINT_MSB)
  44. // check whether a node has locked meshes in its list
  45. #define AI_OG_HAS_NODE_LOCKED_MESHES(nd) (nd->mNumChildren & AI_OG_UINT_MSB_2)
  46. // unmask the two upper bits of an unsigned int
  47. #define AI_OG_UNMASK(p) (p & (~(AI_OG_UINT_MSB|AI_OG_UINT_MSB_2)))
  48. // ------------------------------------------------------------------------------------------------
  49. // Constructor to be privately used by Importer
  50. OptimizeGraphProcess::OptimizeGraphProcess()
  51. {
  52. configMinNumFaces = AI_OG_MIN_NUM_FACES;
  53. configJoinInequalTransforms = AI_OG_JOIN_INEQUAL_TRANSFORMS;
  54. }
  55. // ------------------------------------------------------------------------------------------------
  56. // Destructor, private as well
  57. OptimizeGraphProcess::~OptimizeGraphProcess()
  58. {
  59. // nothing to do here
  60. }
  61. // ------------------------------------------------------------------------------------------------
  62. // Returns whether the processing step is present in the given flag field.
  63. bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const
  64. {
  65. return (pFlags & aiProcess_OptimizeGraph) != 0;
  66. }
  67. // ------------------------------------------------------------------------------------------------
  68. // Setup properties of the step
  69. void OptimizeGraphProcess::SetupProperties(const Importer* pImp)
  70. {
  71. // join nods with inequal transformations?
  72. configJoinInequalTransforms = pImp->GetPropertyInteger(AI_CONFIG_PP_OG_JOIN_INEQUAL_TRANSFORMS,
  73. AI_OG_JOIN_INEQUAL_TRANSFORMS) != 0 ? true : false;
  74. // minimum face number per node
  75. configMinNumFaces = pImp->GetPropertyInteger(AI_CONFIG_PP_OG_MIN_NUM_FACES,
  76. AI_OG_MIN_NUM_FACES);
  77. }
  78. // ------------------------------------------------------------------------------------------------
  79. void OptimizeGraphProcess::FindLockedNodes(aiNode* node)
  80. {
  81. ai_assert(NULL != node);
  82. // process animations
  83. for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
  84. {
  85. aiAnimation* pani = pScene->mAnimations[i];
  86. for (unsigned int a = 0; a < pani->mNumChannels;++a)
  87. {
  88. aiNodeAnim* pba = pani->mChannels[a];
  89. if (pba->mNodeName == node->mName)
  90. {
  91. // this node is locked, it is referenced by an animation channel
  92. node->mNumChildren |= AI_OG_UINT_MSB;
  93. }
  94. }
  95. }
  96. // process cameras
  97. for (unsigned int i = 0; i < pScene->mNumCameras;++i)
  98. {
  99. aiCamera* p = pScene->mCameras[i];
  100. if (p->mName == node->mName)
  101. {
  102. // this node is locked, it is referenced by a camera
  103. node->mNumChildren |= AI_OG_UINT_MSB;
  104. }
  105. }
  106. // process lights
  107. for (unsigned int i = 0; i < pScene->mNumLights;++i)
  108. {
  109. aiLight* p = pScene->mLights[i];
  110. if (p->mName == node->mName)
  111. {
  112. // this node is locked, it is referenced by a light
  113. node->mNumChildren |= AI_OG_UINT_MSB;
  114. }
  115. }
  116. // call all children
  117. for (unsigned int i = 0; i < node->mNumChildren;++i)
  118. FindLockedNodes(node->mChildren[i]);
  119. }
  120. // ------------------------------------------------------------------------------------------------
  121. void OptimizeGraphProcess::FindLockedMeshes(aiNode* node, MeshRefCount* pRefCount)
  122. {
  123. ai_assert(NULL != node && NULL != pRefCount);
  124. for (unsigned int i = 0;i < node->mNumMeshes;++i)
  125. {
  126. unsigned int m = node->mMeshes[i];
  127. if (pRefCount[m].first)
  128. {
  129. // we have already one reference - lock the first node
  130. // that had a referenced to this mesh too if it has only
  131. // one mesh assigned. If there are multiple meshes,
  132. // the others could still be used for optimizations.
  133. if (pRefCount[m].second)
  134. {
  135. pRefCount[m].second->mNumChildren |= (pRefCount[m].second->mNumMeshes <= 1
  136. ? AI_OG_UINT_MSB : AI_OG_UINT_MSB_2);
  137. pRefCount[m].second = NULL;
  138. }
  139. pScene->mMeshes[m]->mNumBones |= AI_OG_UINT_MSB;
  140. // lock this node
  141. node->mNumChildren |= (node->mNumMeshes <= 1
  142. ? AI_OG_UINT_MSB : AI_OG_UINT_MSB_2);
  143. }
  144. else pRefCount[m].second = node;
  145. ++pRefCount[m].first;
  146. }
  147. // call all children
  148. for (unsigned int i = 0; i < node->mNumChildren;++i)
  149. FindLockedMeshes(node->mChildren[i],pRefCount);
  150. }
  151. // ------------------------------------------------------------------------------------------------
  152. void OptimizeGraphProcess::FindLockedMeshes(aiNode* node)
  153. {
  154. ai_assert(NULL != node);
  155. MeshRefCount* pRefCount = new MeshRefCount[pScene->mNumMeshes];
  156. for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
  157. pRefCount[i] = MeshRefCount();
  158. // execute the algorithm
  159. FindLockedMeshes(node,pRefCount);
  160. delete[] pRefCount;
  161. }
  162. // ------------------------------------------------------------------------------------------------
  163. void OptimizeGraphProcess::UnlockNodes(aiNode* node)
  164. {
  165. ai_assert(NULL != node);
  166. node->mNumChildren &= ~(AI_OG_UINT_MSB|AI_OG_UINT_MSB_2);
  167. // call all children
  168. for (unsigned int i = 0; i < node->mNumChildren;++i)
  169. UnlockNodes(node->mChildren[i]);
  170. }
  171. // ------------------------------------------------------------------------------------------------
  172. void OptimizeGraphProcess::UnlockMeshes()
  173. {
  174. for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
  175. pScene->mMeshes[i]->mNumBones &= ~AI_OG_UINT_MSB;
  176. }
  177. // ------------------------------------------------------------------------------------------------
  178. void OptimizeGraphProcess::ComputeMeshHashes()
  179. {
  180. mMeshHashes.resize(pScene->mNumMeshes);
  181. for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
  182. {
  183. unsigned int iRet = 0;
  184. aiMesh* pcMesh = pScene->mMeshes[i];
  185. // normals
  186. if (pcMesh->HasNormals())iRet |= 0x1;
  187. // tangents and bitangents
  188. if (pcMesh->HasTangentsAndBitangents())iRet |= 0x2;
  189. // texture coordinates
  190. unsigned int p = 0;
  191. ai_assert(4 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
  192. while (pcMesh->HasTextureCoords(p))
  193. {
  194. iRet |= (0x100 << p++);
  195. // NOTE: meshes with numUVComp != 3 && != 2 aren't handled correctly here
  196. ai_assert(pcMesh->mNumUVComponents[p] == 3 || pcMesh->mNumUVComponents[p] == 2);
  197. if (3 == pcMesh->mNumUVComponents[p])
  198. iRet |= (0x1000 << p++);
  199. }
  200. // vertex colors
  201. p = 0;
  202. ai_assert(4 >= AI_MAX_NUMBER_OF_COLOR_SETS);
  203. while (pcMesh->HasVertexColors(p))iRet |= (0x10000 << p++);
  204. mMeshHashes[i] = iRet;
  205. // material index -store it in the upper 1 1/2 bytes, so
  206. // are able to encode 2^12 material indices.
  207. iRet |= (pcMesh->mMaterialIndex << 20u);
  208. }
  209. }
  210. // ------------------------------------------------------------------------------------------------
  211. inline unsigned int OptimizeGraphProcess::BinarySearch(NodeIndexList& sortedArray,
  212. unsigned int min, unsigned int& index, unsigned int iStart)
  213. {
  214. unsigned int first = iStart,last = (unsigned int)sortedArray.size()-1;
  215. while (first <= last)
  216. {
  217. unsigned int mid = (first + last) / 2;
  218. unsigned int id = sortedArray[mid].second;
  219. if (min > id)
  220. first = mid + 1;
  221. else if (min <= id)
  222. {
  223. last = mid - 1;
  224. if (!mid || min > sortedArray[last].second)
  225. {
  226. index = sortedArray[last].first;
  227. return mid;
  228. }
  229. }
  230. }
  231. return (unsigned int)sortedArray.size();
  232. }
  233. // ------------------------------------------------------------------------------------------------
  234. void OptimizeGraphProcess::ApplyNodeMeshesOptimization(aiNode* pNode)
  235. {
  236. ai_assert(NULL != pNode);
  237. // find all meshes which are compatible and could therefore be joined.
  238. // we can't join meshes that are locked
  239. std::vector<aiMesh*> apcMeshes(pNode->mNumMeshes);
  240. unsigned int iNumMeshes;
  241. for (unsigned int m = 0, ttt = 0; m < pNode->mNumMeshes;++m)
  242. {
  243. iNumMeshes = 0;
  244. unsigned int nm = pNode->mMeshes[m];
  245. if (0xffffffff == nm || AI_OG_IS_MESH_LOCKED(pScene->mMeshes[nm]))continue;
  246. for (unsigned int q = m+1; q < pNode->mNumMeshes;++q)
  247. {
  248. register unsigned int nq = pNode->mMeshes[q];
  249. // skip locked meshes
  250. if (AI_OG_IS_MESH_LOCKED(pScene->mMeshes[nq]))continue;
  251. // compare the mesh hashes
  252. if (mMeshHashes[nm] == mMeshHashes[nq])
  253. {
  254. apcMeshes[iNumMeshes++] = pScene->mMeshes[nq];
  255. pNode->mMeshes[q] = 0xffffffff;
  256. }
  257. }
  258. aiMesh* out;
  259. if (iNumMeshes > 0)
  260. {
  261. apcMeshes[iNumMeshes++] = pScene->mMeshes[nm];
  262. // JoinMeshes(apcMeshes,out,iNumMeshes);
  263. }
  264. else out = pScene->mMeshes[nm];
  265. pNode->mMeshes[ttt++] = (unsigned int)mOutputMeshes.size();
  266. mOutputMeshes.push_back(out);
  267. }
  268. }
  269. // ------------------------------------------------------------------------------------------------
  270. void OptimizeGraphProcess::TransformMeshes(aiNode* quak,aiNode* pNode)
  271. {
  272. for (unsigned int pl = 0; pl < quak->mNumMeshes;++pl)
  273. {
  274. aiMesh* mariusIsHot = pScene->mMeshes[quak->mMeshes[pl]];
  275. aiMatrix4x4 mMatTransform = pNode->mTransformation;
  276. // transformation: first back to the parent's local space,
  277. // later into the local space of the destination child node
  278. mMatTransform.Inverse();
  279. mMatTransform = quak->mTransformation * mMatTransform;
  280. // transform all vertices
  281. for (unsigned int oo =0; oo < mariusIsHot->mNumVertices;++oo)
  282. mariusIsHot->mVertices[oo] = mMatTransform * mariusIsHot->mVertices[oo];
  283. // transform all normal vectors
  284. if (mariusIsHot->HasNormals())
  285. {
  286. mMatTransform.Inverse().Transpose();
  287. for (unsigned int oo =0; oo < mariusIsHot->mNumVertices;++oo)
  288. mariusIsHot->mNormals[oo] = mMatTransform * mariusIsHot->mNormals[oo];
  289. }
  290. }
  291. }
  292. // ------------------------------------------------------------------------------------------------
  293. void OptimizeGraphProcess::ApplyOptimizations(aiNode* node)
  294. {
  295. ai_assert(NULL != node);
  296. unsigned int iJoinedIndex = 0;
  297. // first: node index; second: number of faces in node
  298. NodeIndexList aiBelowTreshold;
  299. aiBelowTreshold.reserve(node->mNumChildren);
  300. for (unsigned int i = 0; i < node->mNumChildren;++i)
  301. {
  302. aiNode* pChild = node->mChildren[i];
  303. if (AI_OG_IS_NODE_LOCKED(pChild) || !pChild->mNumMeshes)continue;
  304. // find out how many faces this node is referencing
  305. unsigned int iFaceCnt = 0;
  306. for (unsigned int a = 0; a < pChild->mNumMeshes;++a)
  307. iFaceCnt += pScene->mMeshes[pChild->mMeshes[a]]->mNumFaces;
  308. // are we below the treshold?
  309. if (iFaceCnt < configMinNumFaces)
  310. {
  311. aiBelowTreshold.push_back(NodeIndexEntry());
  312. NodeIndexEntry& p = aiBelowTreshold.back();
  313. p.first = i;
  314. p.second = iFaceCnt;
  315. p.pNode = pChild;
  316. }
  317. }
  318. if (!aiBelowTreshold.empty())
  319. {
  320. // some typedefs for the data structures we'll need
  321. typedef std::pair<unsigned int, unsigned int> JoinListEntry;
  322. std::vector<JoinListEntry> aiJoinList(aiBelowTreshold.size());
  323. std::vector<unsigned int> aiTempList(aiBelowTreshold.size());
  324. unsigned int iNumJoins, iNumTemp;
  325. // sort the list by size
  326. std::sort(aiBelowTreshold.begin(),aiBelowTreshold.end());
  327. unsigned int iStart = 0;
  328. for (NodeIndexList::const_iterator it = aiBelowTreshold.begin(),end = aiBelowTreshold.end();
  329. it != end; /*++it */++iStart)
  330. {
  331. aiNode* pNode = node->mChildren[(*it).first];
  332. // get the hash of the mesh
  333. const unsigned int iMeshVFormat = mMeshHashes[pNode->mMeshes[0]];
  334. // we search for a node with more faces than this ... find
  335. // the one that fits best and continue until we've reached
  336. // treshold size.
  337. int iDiff = configMinNumFaces-(*it).second;
  338. for (;;)
  339. {
  340. // do a binary search and start the iteration there
  341. unsigned int index;
  342. unsigned int start = BinarySearch(aiBelowTreshold,iDiff,index,iStart);
  343. if (index == (*it).first)start++;
  344. if (start >= aiBelowTreshold.size())
  345. {
  346. // there is no node with enough faces. take the first
  347. start = 0;
  348. }
  349. // todo: implement algorithm to find the best possible combination ...
  350. iNumTemp = 0;
  351. while( start < aiBelowTreshold.size())
  352. {
  353. // check whether the node has akready been processed before
  354. const NodeIndexEntry& entry = aiBelowTreshold[start];
  355. if (!entry.pNode)continue;
  356. const aiNode* pip = node->mChildren[entry.first];
  357. if (configJoinInequalTransforms )
  358. {
  359. // we need to check whether this node has locked meshes
  360. // in this case we can't add it here - the meshes will
  361. // be transformed from one to another coordinate space
  362. if (!AI_OG_HAS_NODE_LOCKED_MESHES(pip) || pip->mTransformation == pNode->mTransformation)
  363. aiTempList[iNumTemp++] = start;
  364. }
  365. else if (node->mChildren[entry.first]->mTransformation == pNode->mTransformation)
  366. {
  367. aiTempList[iNumTemp++] = start;
  368. break;
  369. }
  370. ++start;
  371. }
  372. if (iNumTemp)
  373. {
  374. // search for a node which has a mesh with
  375. // - the same material index
  376. // - the same vertex layout
  377. unsigned int d = iNumJoins = 0;
  378. for (unsigned int m = 0; m < iNumTemp;++m)
  379. {
  380. register unsigned int mn = aiTempList[m];
  381. aiNode* pip = aiBelowTreshold[mn].pNode;
  382. for (unsigned int tt = 0; tt < pip->mNumMeshes;++tt)
  383. {
  384. register unsigned int mm = pip->mMeshes[tt];
  385. if (mMeshHashes [ mm ] == iMeshVFormat)
  386. {
  387. d = mn;
  388. goto break_out;
  389. }
  390. }
  391. }
  392. break_out:
  393. aiJoinList[iNumJoins++] = JoinListEntry( aiBelowTreshold[d].first, d );
  394. iDiff -= aiBelowTreshold[d].second;
  395. }
  396. // did we reach the target treshold?
  397. if (iDiff <= 0)break;
  398. }
  399. // did we found any nodes to be joined with *this* one?
  400. if (iNumJoins)
  401. {
  402. unsigned int iNumTotalChilds = pNode->mNumChildren;
  403. unsigned int iNumTotalMeshes = pNode->mNumMeshes;
  404. std::vector<JoinListEntry>::const_iterator wend = aiJoinList.begin()+iNumJoins;
  405. // get output array bounds
  406. for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
  407. wit != wend;++wit )
  408. {
  409. aiNode*& quak = node->mChildren[(*wit).first];
  410. iNumTotalChilds += AI_OG_UNMASK( quak->mNumChildren );
  411. iNumTotalMeshes += quak->mNumMeshes;
  412. }
  413. // build the output child list
  414. if (iNumTotalChilds != pNode->mNumChildren)
  415. {
  416. aiNode** ppc = pNode->mChildren;
  417. delete[] pNode->mChildren;
  418. pNode->mChildren = new aiNode*[iNumTotalChilds];
  419. ::memcpy(pNode->mChildren,ppc, sizeof(void*)* AI_OG_UNMASK( pNode->mNumChildren ));
  420. for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
  421. wit != wend;++wit )
  422. {
  423. aiNode*& quak = node->mChildren[(*wit).first];
  424. ::memcpy(pNode->mChildren+pNode->mNumChildren,
  425. quak->mChildren, sizeof(void*)*quak->mNumChildren);
  426. pNode->mNumChildren += AI_OG_UNMASK( quak->mNumChildren );
  427. }
  428. }
  429. // build the output mesh list
  430. unsigned int* ppc = pNode->mMeshes;
  431. delete[] pNode->mMeshes;
  432. pNode->mMeshes = new unsigned int[iNumTotalMeshes];
  433. ::memcpy(pNode->mMeshes,ppc, sizeof(void*)*pNode->mNumMeshes);
  434. for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
  435. wit != wend;++wit )
  436. {
  437. aiNode*& quak = node->mChildren[(*wit).first];
  438. ::memcpy(pNode->mMeshes+pNode->mNumMeshes,
  439. quak->mMeshes, sizeof(unsigned int)*quak->mNumMeshes);
  440. // if the node has a transformation matrix that is not equal to ours,
  441. // we'll need to transform all vertices of the mesh into our
  442. // local coordinate space.
  443. if (configJoinInequalTransforms && quak->mTransformation != pNode->mTransformation)
  444. TransformMeshes(quak,pNode);
  445. pNode->mNumMeshes += quak->mNumMeshes;
  446. // remove the joined nodes from all lists.
  447. aiBelowTreshold[(*wit).second].pNode = NULL;
  448. if ((*wit).second == iStart+1)++iStart;
  449. }
  450. // now generate an output name for the joined nodes
  451. if (1 == iNumTotalChilds)
  452. {
  453. pNode->mName.length = ::sprintf( pNode->mName.data, "<Joined_%i_%i>",
  454. iJoinedIndex++,iNumJoins+1);
  455. }
  456. }
  457. // now optimize the meshes in this node
  458. ApplyNodeMeshesOptimization(pNode);
  459. // note - this has been optimized away. The search in the binary
  460. // list starts with iStart, which is incremented each iteration
  461. ++it; // = aiBelowTreshold.erase(it);
  462. }
  463. }
  464. // call all children recursively
  465. for (unsigned int i = 0; i < node->mNumChildren;++i)
  466. ApplyOptimizations(node->mChildren[i]);
  467. }
  468. // ------------------------------------------------------------------------------------------------
  469. void OptimizeGraphProcess::BuildOutputMeshList()
  470. {
  471. // all meshes should have been deleted before if they are
  472. // not contained in the new mesh list
  473. if (pScene->mNumMeshes < mOutputMeshes.size())
  474. {
  475. delete[] pScene->mMeshes;
  476. pScene->mMeshes = new aiMesh*[mOutputMeshes.size()];
  477. }
  478. pScene->mNumMeshes = (unsigned int)mOutputMeshes.size();
  479. ::memcpy(pScene->mMeshes,&mOutputMeshes[0],pScene->mNumMeshes*sizeof(void*));
  480. }
  481. // ------------------------------------------------------------------------------------------------
  482. // Executes the post processing step on the given imported data.
  483. void OptimizeGraphProcess::Execute( aiScene* pScene)
  484. {
  485. throw new ImportErrorException("This step is disabled in this beta");
  486. this->pScene = pScene;
  487. /*
  488. a) the term "mesh node" stands for a node with numMeshes > 0
  489. b) the term "animation node" stands for a node with numMeshes == 0,
  490. regardless whether the node is referenced by animation channels,
  491. lights or cameras
  492. Algorithm:
  493. 1. Compute hashes for all meshes that we're able to check whether
  494. two meshes are compatible.
  495. 3. Find out which nodes may not be moved, so to speak are "locked" - a
  496. locked node will never be joined with neighbors.
  497. - A node lock is indicated by a set MSB in the aiNode::mNumChildren member
  498. 4. Find out which meshes are locked - they are referenced by
  499. more than one node. They will never be joined. Mark all
  500. nodes referencing such a mesh as "locked", too.
  501. - A mesh lock is indicated by a set MSB in the aiMesh::mNumBones member
  502. 5. For each unlocked node count the face numbers of all assigned meshes
  503. - if it is below the pre-defined treshold add the node to a list.
  504. For each node in the list - try to find enough joinable nodes to
  505. have enough faces all together.
  506. Two nodes are joined if:
  507. - none of them is locked
  508. - (optional) their world matrices are identical
  509. - nodes whose meshes share the same material indices are prefered
  510. Two meshes in one node are joined if:
  511. - their material indices are identical
  512. - none of them is locked
  513. - they share the same vertex format
  514. 6. Build the final mesh list
  515. 7. For all meshes and all nodes - remove locks.
  516. */
  517. throw new ImportErrorException("OG step is still undeer development and not yet finished");
  518. // STEP 1
  519. ComputeMeshHashes();
  520. // STEP 2
  521. FindLockedNodes(pScene->mRootNode);
  522. // STEP 3
  523. FindLockedMeshes(pScene->mRootNode);
  524. // STEP 4
  525. ApplyOptimizations(pScene->mRootNode);
  526. // STEP 5
  527. BuildOutputMeshList();
  528. // STEP 6
  529. UnlockNodes(pScene->mRootNode);
  530. UnlockMeshes();
  531. }