PVRTBoneBatch.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /******************************************************************************
  2. @File PVRTBoneBatch.cpp
  3. @Title PVRTBoneBatch
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform ANSI compatible
  7. @Description Utility functions which process vertices.
  8. ******************************************************************************/
  9. /****************************************************************************
  10. ** Includes
  11. ****************************************************************************/
  12. #include "PVRTGlobal.h"
  13. #include "PVRTContext.h"
  14. #include <vector>
  15. #include <list>
  16. #include "PVRTMatrix.h"
  17. #include "PVRTVertex.h"
  18. #include "PVRTBoneBatch.h"
  19. /****************************************************************************
  20. ** Defines
  21. ****************************************************************************/
  22. /****************************************************************************
  23. ** Macros
  24. ****************************************************************************/
  25. /****************************************************************************
  26. ** Structures
  27. ****************************************************************************/
  28. /*!***************************************************************************
  29. @Class CBatch
  30. @Brief Class to contain and manage batch information.
  31. *****************************************************************************/
  32. class CBatch
  33. {
  34. protected:
  35. int m_nCapacity, // Maximum size of the batch
  36. m_nCnt, // Number of elements currently contained in the batch
  37. *m_pnPalette; // Array of palette indices
  38. public:
  39. /*!***************************************************************************
  40. @Function CBatch
  41. @Description The default constructor
  42. *****************************************************************************/
  43. CBatch()
  44. {
  45. m_pnPalette = NULL;
  46. }
  47. /*!***************************************************************************
  48. @Function CBatch
  49. @Input src CBatch to copy
  50. @Description Copy constructor
  51. *****************************************************************************/
  52. CBatch(const CBatch &src)
  53. {
  54. m_pnPalette = NULL;
  55. SetSize(src.m_nCapacity);
  56. *this = src;
  57. }
  58. /*!***************************************************************************
  59. @Function ~CBatch
  60. @Description Destructor
  61. *****************************************************************************/
  62. ~CBatch()
  63. {
  64. FREE(m_pnPalette);
  65. }
  66. /*!***************************************************************************
  67. @Function operator=
  68. @Description Operator overload for the '=' operand
  69. *****************************************************************************/
  70. void operator= (const CBatch &src)
  71. {
  72. _ASSERT(m_nCapacity == src.m_nCapacity);
  73. m_nCnt = src.m_nCnt;
  74. memcpy(m_pnPalette, src.m_pnPalette, m_nCnt * sizeof(*m_pnPalette));
  75. }
  76. /*!***************************************************************************
  77. @Function SetSize
  78. @Input nSize The new size of the batch
  79. @Description Delete all current information and resizes the batch
  80. to the value that has been passed in.
  81. *****************************************************************************/
  82. void SetSize(const int nSize)
  83. {
  84. FREE(m_pnPalette);
  85. m_nCapacity = nSize;
  86. m_nCnt = 0;
  87. m_pnPalette = (int*)malloc(m_nCapacity * sizeof(*m_pnPalette));
  88. }
  89. /*!***************************************************************************
  90. @Function Clear
  91. @Description Resets the count
  92. *****************************************************************************/
  93. void Clear()
  94. {
  95. m_nCnt = 0;
  96. }
  97. /*!***************************************************************************
  98. @Function Clear
  99. @Input n The index of the new item
  100. Return bool Returns true if the item already exists or has been added.
  101. @Description Adds a new item to the batch, providing it has not already
  102. been added to the batch and the count doesn't exceed the
  103. maximum number of bones the batch can hold.
  104. *****************************************************************************/
  105. bool Add(const int n)
  106. {
  107. int i;
  108. if(n < 0)
  109. return false;
  110. // If we already have this item, do nothing
  111. for(i = 0; i < m_nCnt; ++i)
  112. {
  113. if(m_pnPalette[i] == n)
  114. return true;
  115. }
  116. // Add the new item
  117. if(m_nCnt < m_nCapacity)
  118. {
  119. m_pnPalette[m_nCnt] = n;
  120. ++m_nCnt;
  121. return true;
  122. }
  123. else
  124. {
  125. return false;
  126. }
  127. }
  128. /*!***************************************************************************
  129. @Function Merge
  130. @Input src The batch to merge with
  131. @Description Merges the input batch with the current batch.
  132. *****************************************************************************/
  133. void Merge(const CBatch &src)
  134. {
  135. int i;
  136. for(i = 0; i < src.m_nCnt; ++i)
  137. Add(src.m_pnPalette[i]);
  138. }
  139. /*!***************************************************************************
  140. @Function TestMerge
  141. @Input src The batch to merge with
  142. @Return int The number of items that are not already
  143. present in the batch. -1 if the merge will
  144. exceed the capacity of the batch
  145. @Description Tests how many of the items of the input batch are not
  146. already contained in the batch. This returns the number of
  147. items that would need to be added, or -1 if the number
  148. of additional items would exceed the capacity of the batch.
  149. *****************************************************************************/
  150. int TestMerge(const CBatch &src)
  151. {
  152. int i, nCnt;
  153. nCnt = 0;
  154. for(i = 0; i < src.m_nCnt; ++i)
  155. if(!Contains(src.m_pnPalette[i]))
  156. ++nCnt;
  157. return m_nCnt+nCnt > m_nCapacity ? -1 : nCnt;
  158. }
  159. /*!***************************************************************************
  160. @Function Contains
  161. @Input src The batch to compare
  162. @Return bool Returns true if the batch and the input batch
  163. have at least one item in common
  164. @Description Returns true if the batch's have at least one item in common
  165. *****************************************************************************/
  166. bool Contains(const CBatch &batch) const
  167. {
  168. int i;
  169. for(i = 0; i < batch.m_nCnt; ++i)
  170. if(!Contains(batch.m_pnPalette[i]))
  171. return false;
  172. return true;
  173. }
  174. /*!***************************************************************************
  175. @Function Contains
  176. @Input n The index of the new item
  177. @Return bool Returns true if the batch contains the item
  178. @Description Returns true if the batch contains the item.
  179. *****************************************************************************/
  180. bool Contains(const int n) const
  181. {
  182. int i;
  183. for(i = 0; i < m_nCnt; ++i)
  184. if(m_pnPalette[i] == n)
  185. return true;
  186. return false;
  187. }
  188. /*!***************************************************************************
  189. @Function Write
  190. @Output pn The array of items to overwrite
  191. @Output pnCnt The number of items in the array
  192. @Description Writes the array of items and the number of items to the output
  193. parameters.
  194. *****************************************************************************/
  195. void Write(
  196. int * const pn,
  197. int * const pnCnt) const
  198. {
  199. memcpy(pn, m_pnPalette, m_nCnt * sizeof(*pn));
  200. *pnCnt = m_nCnt;
  201. }
  202. /*!***************************************************************************
  203. @Function GetVertexBoneIndices
  204. @Modified pfI Returned index
  205. @Input pfW Weight?
  206. @Input n Length of index array
  207. @Description For each element of the input array, the index value is compared
  208. with the palette's index value. If the values are equal, the
  209. value of the current input array element is replaced with the
  210. palette index, otherwise the value is set to zero.
  211. *****************************************************************************/
  212. void GetVertexBoneIndices(
  213. float * const pfI,
  214. const float * const pfW,
  215. const int n)
  216. {
  217. int i, j;
  218. for(i = 0; i < n; ++i)
  219. {
  220. if(pfW[i] != 0)
  221. {
  222. for(j = 0; j < m_nCnt; ++j)
  223. {
  224. if(pfI[i] != m_pnPalette[j])
  225. continue;
  226. pfI[i] = (float)j;
  227. break;
  228. }
  229. // This batch *must* contain this vertex
  230. _ASSERT(j != m_nCnt);
  231. }
  232. else
  233. {
  234. pfI[i] = 0;
  235. }
  236. }
  237. }
  238. };
  239. /*!***************************************************************************
  240. @Class CGrowableArray
  241. @Brief Class that provides an array structure that can change its size dynamically.
  242. *****************************************************************************/
  243. class CGrowableArray
  244. {
  245. protected:
  246. char *m_p;
  247. int m_nSize;
  248. int m_nCnt;
  249. public:
  250. /*!***************************************************************************
  251. @Function CGrowableArray
  252. @Input nSize The size of the data (in bytes) that the array will contain
  253. @Description Initialises the size of the data the array will contain to the
  254. value that has been passed in and initialises the remaining
  255. data members with default values.
  256. *****************************************************************************/
  257. CGrowableArray(const int nSize)
  258. {
  259. m_p = NULL;
  260. m_nSize = nSize;
  261. m_nCnt = 0;
  262. }
  263. /*!***************************************************************************
  264. @Function ~CGrowableArray
  265. @Description The destructor
  266. *****************************************************************************/
  267. ~CGrowableArray()
  268. {
  269. FREE(m_p);
  270. }
  271. /*!***************************************************************************
  272. @Function Append
  273. @Input pData The data to append
  274. @Input nCnt The amount of data elements to append
  275. @Description Resizes the array and appends the new data that has been passed in.
  276. *****************************************************************************/
  277. void Append(const void * const pData, const int nCnt)
  278. {
  279. m_p = (char*)realloc(m_p, (m_nCnt + nCnt) * m_nSize);
  280. _ASSERT(m_p);
  281. memcpy(&m_p[m_nCnt * m_nSize], pData, nCnt * m_nSize);
  282. m_nCnt += nCnt;
  283. }
  284. /*!***************************************************************************
  285. @Function last
  286. @Return char* The last element of the array
  287. @Description Returns a pointer to the last element of the array.
  288. *****************************************************************************/
  289. char *last()
  290. {
  291. return at(m_nCnt-1);
  292. }
  293. /*!***************************************************************************
  294. @Function at
  295. @Input nIdx The index of the requested element
  296. @Return char* The element at the specified index of the array
  297. @Description Returns a pointer to the data at the specified index of the array.
  298. *****************************************************************************/
  299. char *at(const int nIdx)
  300. {
  301. return &m_p[nIdx * m_nSize];
  302. }
  303. /*!***************************************************************************
  304. @Function size
  305. @Return int The number of elements contained in the array
  306. @Description Returns the number of elements contained in the array.
  307. *****************************************************************************/
  308. int size() const
  309. {
  310. return m_nCnt;
  311. }
  312. /*!***************************************************************************
  313. @Function Surrender
  314. @Output pData The pointer to surrender the data to
  315. @Description Assigns the memory address of the data to the pointer that has
  316. been passed in. Sets the class's number of elements and
  317. data pointer back to their default values.
  318. *****************************************************************************/
  319. int Surrender(
  320. char ** const pData)
  321. {
  322. int nCnt;
  323. *pData = m_p;
  324. nCnt = m_nCnt;
  325. m_p = NULL;
  326. m_nCnt = 0;
  327. return nCnt;
  328. }
  329. };
  330. /****************************************************************************
  331. ** Constants
  332. ****************************************************************************/
  333. /****************************************************************************
  334. ** Local function definitions
  335. ****************************************************************************/
  336. static bool FillBatch(
  337. CBatch &batch,
  338. const unsigned int * const pui32Idx, // input AND output; index array for triangle list
  339. const char * const pVtx, // Input vertices
  340. const int nStride, // Size of a vertex (in bytes)
  341. const int nOffsetWeight, // Offset in bytes to the vertex bone-weights
  342. EPVRTDataType eTypeWeight, // Data type of the vertex bone-weights
  343. const int nOffsetIdx, // Offset in bytes to the vertex bone-indices
  344. EPVRTDataType eTypeIdx, // Data type of the vertex bone-indices
  345. const int nVertexBones); // Number of bones affecting each vertex
  346. static bool BonesMatch(
  347. const float * const pfIdx0,
  348. const float * const pfIdx1);
  349. /*****************************************************************************
  350. ** Functions
  351. *****************************************************************************/
  352. /*!***************************************************************************
  353. @Function Create
  354. @Output pnVtxNumOut vertex count
  355. @Output pVtxOut Output vertices (program must free() this)
  356. @Modified pui32Idx index array for triangle list
  357. @Input nVtxNum vertex count
  358. @Input pVtx vertices
  359. @Input nStride Size of a vertex (in bytes)
  360. @Input nOffsetWeight Offset in bytes to the vertex bone-weights
  361. @Input eTypeWeight Data type of the vertex bone-weights
  362. @Input nOffsetIdx Offset in bytes to the vertex bone-indices
  363. @Input eTypeIdx Data type of the vertex bone-indices
  364. @Input nTriNum Number of triangles
  365. @Input nBatchBoneMax Number of bones a batch can reference
  366. @Input nVertexBones Number of bones affecting each vertex
  367. @Returns PVR_SUCCESS if successful
  368. @Description Fills the bone batch structure
  369. *****************************************************************************/
  370. EPVRTError CPVRTBoneBatches::Create(
  371. int * const pnVtxNumOut,
  372. char ** const pVtxOut,
  373. unsigned int * const pui32Idx,
  374. const int nVtxNum,
  375. const char * const pVtx,
  376. const int nStride,
  377. const int nOffsetWeight,
  378. const EPVRTDataType eTypeWeight,
  379. const int nOffsetIdx,
  380. const EPVRTDataType eTypeIdx,
  381. const int nTriNum,
  382. const int nBatchBoneMax,
  383. const int nVertexBones)
  384. {
  385. int i, j, k, nTriCnt;
  386. CBatch batch;
  387. std::list<CBatch> lBatch;
  388. std::list<CBatch>::iterator iBatch, iBatch2;
  389. CBatch **ppBatch;
  390. unsigned int *pui32IdxNew;
  391. const char *pV, *pV2;
  392. PVRTVECTOR4 vWeight, vIdx;
  393. PVRTVECTOR4 vWeight2, vIdx2;
  394. std::vector<int> *pvDup;
  395. CGrowableArray *pVtxBuf;
  396. unsigned int ui32SrcIdx;
  397. memset(this, 0, sizeof(*this));
  398. if(nVertexBones <= 0 || nVertexBones > 4)
  399. {
  400. _RPT0(_CRT_WARN, "CPVRTBoneBatching() will only handle 1..4 bones per vertex.\n");
  401. return PVR_FAIL;
  402. }
  403. memset(&vWeight, 0, sizeof(vWeight));
  404. memset(&vWeight2, 0, sizeof(vWeight2));
  405. memset(&vIdx, 0, sizeof(vIdx));
  406. memset(&vIdx2, 0, sizeof(vIdx2));
  407. batch.SetSize(nBatchBoneMax);
  408. // Allocate some working space
  409. ppBatch = (CBatch**)malloc(nTriNum * sizeof(*ppBatch));
  410. pui32IdxNew = (unsigned int*)malloc(nTriNum * 3 * sizeof(*pui32IdxNew));
  411. pvDup = new std::vector<int>[nVtxNum];
  412. pVtxBuf = new CGrowableArray(nStride);
  413. // Check what batches are necessary
  414. for(i = 0; i < nTriNum; ++i)
  415. {
  416. // Build the batch
  417. if(!FillBatch(batch, &pui32Idx[i * 3], pVtx, nStride, nOffsetWeight, eTypeWeight, nOffsetIdx, eTypeIdx, nVertexBones))
  418. return PVR_FAIL;
  419. // Update the batch list
  420. for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
  421. {
  422. // Do nothing if an existing batch is a superset of this new batch
  423. if(iBatch->Contains(batch))
  424. {
  425. break;
  426. }
  427. // If this new batch is a superset of an existing batch, replace the old with the new
  428. if(batch.Contains(*iBatch))
  429. {
  430. *iBatch = batch;
  431. break;
  432. }
  433. }
  434. // If no suitable batch exists, create a new one
  435. if(iBatch == lBatch.end())
  436. {
  437. lBatch.push_back(batch);
  438. }
  439. }
  440. // Group batches into fewer batches. This simple greedy algorithm could be improved.
  441. int nCurrent, nShortest;
  442. std::list<CBatch>::iterator iShortest;
  443. for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
  444. {
  445. for(;;)
  446. {
  447. nShortest = nBatchBoneMax;
  448. iBatch2 = iBatch;
  449. ++iBatch2;
  450. for(; iBatch2 != lBatch.end(); ++iBatch2)
  451. {
  452. nCurrent = iBatch->TestMerge(*iBatch2);
  453. if(nCurrent >= 0 && nCurrent < nShortest)
  454. {
  455. nShortest = nCurrent;
  456. iShortest = iBatch2;
  457. }
  458. }
  459. if(nShortest < nBatchBoneMax)
  460. {
  461. iBatch->Merge(*iShortest);
  462. lBatch.erase(iShortest);
  463. }
  464. else
  465. {
  466. break;
  467. }
  468. }
  469. }
  470. // Place each triangle in a batch.
  471. for(i = 0; i < nTriNum; ++i)
  472. {
  473. if(!FillBatch(batch, &pui32Idx[i * 3], pVtx, nStride, nOffsetWeight, eTypeWeight, nOffsetIdx, eTypeIdx, nVertexBones))
  474. return PVR_FAIL;
  475. for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
  476. {
  477. if(iBatch->Contains(batch))
  478. {
  479. ppBatch[i] = &*iBatch;
  480. break;
  481. }
  482. }
  483. _ASSERT(iBatch != lBatch.end());
  484. }
  485. // Now that we know how many batches there are, we can allocate the output arrays
  486. CPVRTBoneBatches::nBatchBoneMax = nBatchBoneMax;
  487. pnBatches = new int[lBatch.size() * nBatchBoneMax];
  488. pnBatchBoneCnt = new int[lBatch.size()];
  489. pnBatchOffset = new int[lBatch.size()];
  490. memset(pnBatches, 0, lBatch.size() * nBatchBoneMax * sizeof(int));
  491. memset(pnBatchBoneCnt, 0, lBatch.size() * sizeof(int));
  492. memset(pnBatchOffset, 0, lBatch.size() * sizeof(int));
  493. // Create the new triangle index list, the new vertex list, and the batch information.
  494. nTriCnt = 0;
  495. nBatchCnt = 0;
  496. for(iBatch = lBatch.begin(); iBatch != lBatch.end(); ++iBatch)
  497. {
  498. // Write pnBatches, pnBatchBoneCnt and pnBatchOffset for this batch.
  499. iBatch->Write(&pnBatches[nBatchCnt * nBatchBoneMax], &pnBatchBoneCnt[nBatchCnt]);
  500. pnBatchOffset[nBatchCnt] = nTriCnt;
  501. ++nBatchCnt;
  502. // Copy any triangle indices for this batch
  503. for(i = 0; i < nTriNum; ++i)
  504. {
  505. if(ppBatch[i] != &*iBatch)
  506. continue;
  507. for(j = 0; j < 3; ++j)
  508. {
  509. ui32SrcIdx = pui32Idx[3 * i + j];
  510. // Get desired bone indices for this vertex/tri
  511. pV = &pVtx[ui32SrcIdx * nStride];
  512. PVRTVertexRead(&vWeight, &pV[nOffsetWeight], eTypeWeight, nVertexBones);
  513. PVRTVertexRead(&vIdx, &pV[nOffsetIdx], eTypeIdx, nVertexBones);
  514. iBatch->GetVertexBoneIndices(&vIdx.x, &vWeight.x, nVertexBones);
  515. _ASSERT(vIdx.x == 0 || vIdx.x != vIdx.y);
  516. // Check the list of copies of this vertex for one with suitable bone indices
  517. for(k = 0; k < (int)pvDup[ui32SrcIdx].size(); ++k)
  518. {
  519. pV2 = pVtxBuf->at(pvDup[ui32SrcIdx][k]);
  520. PVRTVertexRead(&vWeight2, &pV2[nOffsetWeight], eTypeWeight, nVertexBones);
  521. PVRTVertexRead(&vIdx2, &pV2[nOffsetIdx], eTypeIdx, nVertexBones);
  522. if(BonesMatch(&vIdx2.x, &vIdx.x))
  523. {
  524. pui32IdxNew[3 * nTriCnt + j] = pvDup[ui32SrcIdx][k];
  525. break;
  526. }
  527. }
  528. if(k != (int)pvDup[ui32SrcIdx].size())
  529. continue;
  530. // Did not find a suitable duplicate of the vertex, so create one
  531. pVtxBuf->Append(pV, 1);
  532. pvDup[ui32SrcIdx].push_back(pVtxBuf->size() - 1);
  533. PVRTVertexWrite(&pVtxBuf->last()[nOffsetIdx], eTypeIdx, nVertexBones, &vIdx);
  534. pui32IdxNew[3 * nTriCnt + j] = pVtxBuf->size() - 1;
  535. }
  536. ++nTriCnt;
  537. }
  538. }
  539. _ASSERTE(nTriCnt == nTriNum);
  540. _ASSERTE(nBatchCnt == (int)lBatch.size());
  541. // Copy indices to output
  542. memcpy(pui32Idx, pui32IdxNew, nTriNum * 3 * sizeof(*pui32IdxNew));
  543. // Move vertices to output
  544. *pnVtxNumOut = pVtxBuf->Surrender(pVtxOut);
  545. // Free working memory
  546. delete [] pvDup;
  547. delete pVtxBuf;
  548. FREE(ppBatch);
  549. FREE(pui32IdxNew);
  550. return PVR_SUCCESS;
  551. }
  552. /****************************************************************************
  553. ** Local functions
  554. ****************************************************************************/
  555. /*!***********************************************************************
  556. @Function FillBatch
  557. @Modified batch The batch to fill
  558. @Input pui32Idx Input index array for triangle list
  559. @Input pVtx Input vertices
  560. @Input nStride Size of a vertex (in bytes)
  561. @Input nOffsetWeight Offset in bytes to the vertex bone-weights
  562. @Input eTypeWeight Data type of the vertex bone-weights
  563. @Input nOffsetIdx Offset in bytes to the vertex bone-indices
  564. @Input eTypeIdx Data type of the vertex bone-indices
  565. @Input nVertexBones Number of bones affecting each vertex
  566. @Returns True if successful
  567. @Description Creates a bone batch from a triangle.
  568. *************************************************************************/
  569. static bool FillBatch(
  570. CBatch &batch,
  571. const unsigned int * const pui32Idx,
  572. const char * const pVtx,
  573. const int nStride,
  574. const int nOffsetWeight,
  575. EPVRTDataType eTypeWeight,
  576. const int nOffsetIdx,
  577. EPVRTDataType eTypeIdx,
  578. const int nVertexBones)
  579. {
  580. PVRTVECTOR4 vWeight, vIdx;
  581. const char *pV;
  582. int i;
  583. bool bOk;
  584. bOk = true;
  585. batch.Clear();
  586. for(i = 0; i < 3; ++i)
  587. {
  588. pV = &pVtx[pui32Idx[i] * nStride];
  589. memset(&vWeight, 0, sizeof(vWeight));
  590. PVRTVertexRead(&vWeight, &pV[nOffsetWeight], eTypeWeight, nVertexBones);
  591. PVRTVertexRead(&vIdx, &pV[nOffsetIdx], eTypeIdx, nVertexBones);
  592. if(nVertexBones >= 1 && vWeight.x != 0) bOk &= batch.Add((int)vIdx.x);
  593. if(nVertexBones >= 2 && vWeight.y != 0) bOk &= batch.Add((int)vIdx.y);
  594. if(nVertexBones >= 3 && vWeight.z != 0) bOk &= batch.Add((int)vIdx.z);
  595. if(nVertexBones >= 4 && vWeight.w != 0) bOk &= batch.Add((int)vIdx.w);
  596. }
  597. return bOk;
  598. }
  599. /*!***********************************************************************
  600. @Function BonesMatch
  601. @Input pfIdx0 A float 4 array
  602. @Input pfIdx1 A float 4 array
  603. @Returns True if the two float4 arraus are identical
  604. @Description Checks if the two float4 arrays are identical.
  605. *************************************************************************/
  606. static bool BonesMatch(
  607. const float * const pfIdx0,
  608. const float * const pfIdx1)
  609. {
  610. int i;
  611. for(i = 0; i < 4; ++i)
  612. {
  613. if(pfIdx0[i] != pfIdx1[i])
  614. return false;
  615. }
  616. return true;
  617. }
  618. /*****************************************************************************
  619. End of file (PVRTBoneBatch.cpp)
  620. *****************************************************************************/