PVRTTriStrip.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /******************************************************************************
  2. @File PVRTTriStrip.cpp
  3. @Title PVRTTriStrip
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Strips a triangle list.
  8. ******************************************************************************/
  9. /****************************************************************************
  10. ** Includes
  11. ****************************************************************************/
  12. #include <stdlib.h>
  13. #include "PVRTGlobal.h"
  14. #include "PVRTContext.h"
  15. #include "PVRTTriStrip.h"
  16. /****************************************************************************
  17. ** Defines
  18. ****************************************************************************/
  19. #if !defined(__BADA__) // qsort is not supported by Bada
  20. #define RND_TRIS_ORDER
  21. #endif
  22. /****************************************************************************
  23. ** Structures
  24. ****************************************************************************/
  25. /****************************************************************************
  26. ** Class: CTri
  27. ****************************************************************************/
  28. class CTri;
  29. /*!***************************************************************************
  30. @Class CTriState
  31. @Description Stores a pointer to the triangles either side of itself,
  32. as well as it's winding.
  33. *****************************************************************************/
  34. class CTriState
  35. {
  36. public:
  37. CTri *pRev, *pFwd;
  38. bool bWindFwd;
  39. CTriState()
  40. {
  41. bWindFwd = true; // Initial value irrelevent
  42. pRev = NULL;
  43. pFwd = NULL;
  44. }
  45. };
  46. /*!***************************************************************************
  47. @Class CTri
  48. @Description Object used to store information about the triangle, such as
  49. the vertex indices it is made from, which triangles are
  50. adjacent to it, etc.
  51. *****************************************************************************/
  52. class CTri
  53. {
  54. public:
  55. CTriState sNew, sOld;
  56. CTri *pAdj[3];
  57. bool bInStrip;
  58. const unsigned int *pIdx; // three indices for the tri
  59. bool bOutput;
  60. public:
  61. CTri();
  62. int FindEdge(const unsigned int pw0, const unsigned int pw1) const;
  63. void Cement();
  64. void Undo();
  65. int EdgeFromAdjTri(const CTri &tri) const; // Find the index of the adjacent tri
  66. };
  67. /*!***************************************************************************
  68. @Class CStrip
  69. @Description Object used to store the triangles that a given strip is
  70. composed from.
  71. *****************************************************************************/
  72. class CStrip
  73. {
  74. protected:
  75. unsigned int m_nTriCnt;
  76. CTri *m_pTri;
  77. unsigned int m_nStrips;
  78. CTri **m_psStrip; // Working space for finding strips
  79. public:
  80. CStrip(
  81. const unsigned int * const pui32TriList,
  82. const unsigned int nTriCnt);
  83. ~CStrip();
  84. protected:
  85. bool StripGrow(
  86. CTri &triFrom,
  87. const unsigned int nEdgeFrom,
  88. const int nMaxChange);
  89. public:
  90. void StripFromEdges();
  91. void StripImprove();
  92. void Output(
  93. unsigned int **ppui32Strips,
  94. unsigned int **ppnStripLen,
  95. unsigned int *pnStripCnt);
  96. };
  97. /****************************************************************************
  98. ** Constants
  99. ****************************************************************************/
  100. /****************************************************************************
  101. ** Code: Class: CTri
  102. ****************************************************************************/
  103. CTri::CTri()
  104. {
  105. pAdj[0] = NULL;
  106. pAdj[1] = NULL;
  107. pAdj[2] = NULL;
  108. bInStrip = false;
  109. bOutput = false;
  110. }
  111. /*!***************************************************************************
  112. @Function FindEdge
  113. @Input pw0 The first index
  114. @Input pw1 The second index
  115. @Return The index of the edge
  116. @Description Finds the index of the edge that the current object shares
  117. with the two vertex index values that have been passed in
  118. (or returns -1 if they dont share an edge).
  119. *****************************************************************************/
  120. int CTri::FindEdge(const unsigned int pw0, const unsigned int pw1) const
  121. {
  122. if((pIdx[0] == pw0 && pIdx[1] == pw1))
  123. return 0;
  124. if((pIdx[1] == pw0 && pIdx[2] == pw1))
  125. return 1;
  126. if((pIdx[2] == pw0 && pIdx[0] == pw1))
  127. return 2;
  128. return -1;
  129. }
  130. /*!***************************************************************************
  131. @Function Cement
  132. @Description Assigns the new state as the old state.
  133. *****************************************************************************/
  134. void CTri::Cement()
  135. {
  136. sOld = sNew;
  137. }
  138. /*!***************************************************************************
  139. @Function Undo
  140. @Description Reverts the new state to the old state.
  141. *****************************************************************************/
  142. void CTri::Undo()
  143. {
  144. sNew = sOld;
  145. }
  146. /*!***************************************************************************
  147. @Function EdgeFromAdjTri
  148. @Input tri The triangle to compare
  149. @Return int Index of adjacent triangle (-1 if not adjacent)
  150. @Description If the input triangle is adjacent to the current triangle,
  151. it's index is returned.
  152. *****************************************************************************/
  153. int CTri::EdgeFromAdjTri(const CTri &tri) const
  154. {
  155. for(int i = 0; i < 3; ++i)
  156. {
  157. if(pAdj[i] == &tri)
  158. {
  159. return i;
  160. }
  161. }
  162. _ASSERT(false);
  163. return -1;
  164. }
  165. /****************************************************************************
  166. ** Local code
  167. ****************************************************************************/
  168. /*!***************************************************************************
  169. @Function OrphanTri
  170. @Input tri The triangle test
  171. @Return int Returns 1 if change was made
  172. @Description If the input triangle is not wound forward and is not the last
  173. triangle in the strip, the connection with the next triangle
  174. in the strip is removed.
  175. *****************************************************************************/
  176. static int OrphanTri(
  177. CTri * const pTri)
  178. {
  179. _ASSERT(!pTri->bInStrip);
  180. if(pTri->sNew.bWindFwd || !pTri->sNew.pFwd)
  181. return 0;
  182. pTri->sNew.pFwd->sNew.pRev = NULL;
  183. pTri->sNew.pFwd = NULL;
  184. return 1;
  185. }
  186. /*!***************************************************************************
  187. @Function TakeTri
  188. @Input pTri The triangle to take
  189. @Input pRevNew The triangle that is before pTri in the new strip
  190. @Return int Returns 1 if a new strip has been created
  191. @Description Removes the triangle from it's current strip
  192. and places it in a new one (following pRevNew in the new strip).
  193. *****************************************************************************/
  194. static int TakeTri(
  195. CTri * const pTri,
  196. CTri * const pRevNew,
  197. const bool bFwd)
  198. {
  199. int nRet;
  200. _ASSERT(!pTri->bInStrip);
  201. if(pTri->sNew.pFwd && pTri->sNew.pRev)
  202. {
  203. _ASSERT(pTri->sNew.pFwd->sNew.pRev == pTri);
  204. pTri->sNew.pFwd->sNew.pRev = NULL;
  205. _ASSERT(pTri->sNew.pRev->sNew.pFwd == pTri);
  206. pTri->sNew.pRev->sNew.pFwd = NULL;
  207. // If in the middle of a Strip, this will generate a new Strip
  208. nRet = 1;
  209. // The second tri in the strip may need to be orphaned, or it will have wrong winding order
  210. nRet += OrphanTri(pTri->sNew.pFwd);
  211. }
  212. else if(pTri->sNew.pFwd)
  213. {
  214. _ASSERT(pTri->sNew.pFwd->sNew.pRev == pTri);
  215. pTri->sNew.pFwd->sNew.pRev = NULL;
  216. // If at the beginning of a Strip, no change
  217. nRet = 0;
  218. // The second tri in the strip may need to be orphaned, or it will have wrong winding order
  219. nRet += OrphanTri(pTri->sNew.pFwd);
  220. }
  221. else if(pTri->sNew.pRev)
  222. {
  223. _ASSERT(pTri->sNew.pRev->sNew.pFwd == pTri);
  224. pTri->sNew.pRev->sNew.pFwd = NULL;
  225. // If at the end of a Strip, no change
  226. nRet = 0;
  227. }
  228. else
  229. {
  230. // Otherwise it's a lonesome triangle; one Strip removed!
  231. nRet = -1;
  232. }
  233. pTri->sNew.pFwd = NULL;
  234. pTri->sNew.pRev = pRevNew;
  235. pTri->bInStrip = true;
  236. pTri->sNew.bWindFwd = bFwd;
  237. if(pRevNew)
  238. {
  239. _ASSERT(!pRevNew->sNew.pFwd);
  240. pRevNew->sNew.pFwd = pTri;
  241. }
  242. return nRet;
  243. }
  244. /*!***************************************************************************
  245. @Function TryLinkEdge
  246. @Input src The source triangle
  247. @Input cmp The triangle to compare with
  248. @Input nSrcEdge The edge of souce triangle to compare
  249. @Input idx0 Vertex index 0 of the compare triangle
  250. @Input idx1 Vertex index 1 of the compare triangle
  251. @Description If the triangle to compare currently has no adjacent
  252. triangle along the specified edge, link the source triangle
  253. (along it's specified edge) with the compare triangle.
  254. *****************************************************************************/
  255. static bool TryLinkEdge(
  256. CTri &src,
  257. CTri &cmp,
  258. const int nSrcEdge,
  259. const unsigned int idx0,
  260. const unsigned int idx1)
  261. {
  262. int nCmpEdge;
  263. nCmpEdge = cmp.FindEdge(idx0, idx1);
  264. if(nCmpEdge != -1 && !cmp.pAdj[nCmpEdge])
  265. {
  266. cmp.pAdj[nCmpEdge] = &src;
  267. src.pAdj[nSrcEdge] = &cmp;
  268. return true;
  269. }
  270. return false;
  271. }
  272. /****************************************************************************
  273. ** Code: Class: CStrip
  274. ****************************************************************************/
  275. CStrip::CStrip(
  276. const unsigned int * const pui32TriList,
  277. const unsigned int nTriCnt)
  278. {
  279. unsigned int i, j;
  280. bool b0, b1, b2;
  281. m_nTriCnt = nTriCnt;
  282. /*
  283. Generate adjacency info
  284. */
  285. m_pTri = new CTri[nTriCnt];
  286. for(i = 0; i < nTriCnt; ++i)
  287. {
  288. // Set pointer to indices
  289. m_pTri[i].pIdx = &pui32TriList[3 * i];
  290. b0 = false;
  291. b1 = false;
  292. b2 = false;
  293. for(j = 0; j < i && !(b0 & b1 & b2); ++j)
  294. {
  295. if(!b0)
  296. b0 = TryLinkEdge(m_pTri[i], m_pTri[j], 0, m_pTri[i].pIdx[1], m_pTri[i].pIdx[0]);
  297. if(!b1)
  298. b1 = TryLinkEdge(m_pTri[i], m_pTri[j], 1, m_pTri[i].pIdx[2], m_pTri[i].pIdx[1]);
  299. if(!b2)
  300. b2 = TryLinkEdge(m_pTri[i], m_pTri[j], 2, m_pTri[i].pIdx[0], m_pTri[i].pIdx[2]);
  301. }
  302. }
  303. // Initially, every triangle is a strip.
  304. m_nStrips = m_nTriCnt;
  305. // Allocate working space for the strippers
  306. m_psStrip = new CTri*[m_nTriCnt];
  307. }
  308. CStrip::~CStrip()
  309. {
  310. delete [] m_pTri;
  311. delete [] m_psStrip;
  312. }
  313. /*!***************************************************************************
  314. @Function StripGrow
  315. @Input triFrom The triangle to begin from
  316. @Input nEdgeFrom The edge of the triangle to begin from
  317. @Input maxChange The maximum number of changes to be made
  318. @Description Takes triFrom as a starting point of triangles to add to
  319. the list and adds triangles sequentially by finding the next
  320. triangle that is adjacent to the current triangle.
  321. This is repeated until the maximum number of changes
  322. have been made.
  323. *****************************************************************************/
  324. bool CStrip::StripGrow(
  325. CTri &triFrom,
  326. const unsigned int nEdgeFrom,
  327. const int nMaxChange)
  328. {
  329. unsigned int i;
  330. bool bFwd;
  331. int nDiff, nDiffTot, nEdge;
  332. CTri *pTri, *pTriPrev, *pTmp;
  333. unsigned int nStripLen;
  334. // Start strip from this tri
  335. pTri = &triFrom;
  336. pTriPrev = NULL;
  337. nDiffTot = 0;
  338. nStripLen = 0;
  339. // Start strip from this edge
  340. nEdge = nEdgeFrom;
  341. bFwd = true;
  342. // Extend the strip until we run out, or we find an improvement
  343. nDiff = 1;
  344. while(nDiff > nMaxChange)
  345. {
  346. // Add pTri to the strip
  347. _ASSERT(pTri);
  348. nDiff += TakeTri(pTri, pTriPrev, bFwd);
  349. _ASSERT(nStripLen < m_nTriCnt);
  350. m_psStrip[nStripLen++] = pTri;
  351. // Jump to next tri
  352. pTriPrev = pTri;
  353. pTri = pTri->pAdj[nEdge];
  354. if(!pTri)
  355. break; // No more tris, gotta stop
  356. if(pTri->bInStrip)
  357. break; // No more tris, gotta stop
  358. // Find which edge we came over
  359. nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
  360. // Find the edge to leave over
  361. if(bFwd)
  362. {
  363. if(--nEdge < 0)
  364. nEdge = 2;
  365. }
  366. else
  367. {
  368. if(++nEdge > 2)
  369. nEdge = 0;
  370. }
  371. // Swap the winding order for the next tri
  372. bFwd = !bFwd;
  373. }
  374. _ASSERT(!pTriPrev->sNew.pFwd);
  375. /*
  376. Accept or reject this strip.
  377. Accepting changes which don't change the number of strips
  378. adds variety, which can help better strips to develop.
  379. */
  380. if(nDiff <= nMaxChange)
  381. {
  382. nDiffTot += nDiff;
  383. // Great, take the Strip
  384. for(i = 0; i < nStripLen; ++i)
  385. {
  386. pTri = m_psStrip[i];
  387. _ASSERT(pTri->bInStrip);
  388. // Cement affected tris
  389. pTmp = pTri->sOld.pFwd;
  390. if(pTmp && !pTmp->bInStrip)
  391. {
  392. if(pTmp->sOld.pFwd && !pTmp->sOld.pFwd->bInStrip)
  393. pTmp->sOld.pFwd->Cement();
  394. pTmp->Cement();
  395. }
  396. pTmp = pTri->sOld.pRev;
  397. if(pTmp && !pTmp->bInStrip)
  398. {
  399. pTmp->Cement();
  400. }
  401. // Cement this tris
  402. pTri->bInStrip = false;
  403. pTri->Cement();
  404. }
  405. }
  406. else
  407. {
  408. // Shame, undo the strip
  409. for(i = 0; i < nStripLen; ++i)
  410. {
  411. pTri = m_psStrip[i];
  412. _ASSERT(pTri->bInStrip);
  413. // Undo affected tris
  414. pTmp = pTri->sOld.pFwd;
  415. if(pTmp && !pTmp->bInStrip)
  416. {
  417. if(pTmp->sOld.pFwd && !pTmp->sOld.pFwd->bInStrip)
  418. pTmp->sOld.pFwd->Undo();
  419. pTmp->Undo();
  420. }
  421. pTmp = pTri->sOld.pRev;
  422. if(pTmp && !pTmp->bInStrip)
  423. {
  424. pTmp->Undo();
  425. }
  426. // Undo this tris
  427. pTri->bInStrip = false;
  428. pTri->Undo();
  429. }
  430. }
  431. #ifdef _DEBUG
  432. for(int nDbg = 0; nDbg < (int)m_nTriCnt; ++nDbg)
  433. {
  434. _ASSERT(m_pTri[nDbg].bInStrip == false);
  435. _ASSERT(m_pTri[nDbg].bOutput == false);
  436. _ASSERT(m_pTri[nDbg].sOld.pRev == m_pTri[nDbg].sNew.pRev);
  437. _ASSERT(m_pTri[nDbg].sOld.pFwd == m_pTri[nDbg].sNew.pFwd);
  438. if(m_pTri[nDbg].sNew.pRev)
  439. {
  440. _ASSERT(m_pTri[nDbg].sNew.pRev->sNew.pFwd == &m_pTri[nDbg]);
  441. }
  442. if(m_pTri[nDbg].sNew.pFwd)
  443. {
  444. _ASSERT(m_pTri[nDbg].sNew.pFwd->sNew.pRev == &m_pTri[nDbg]);
  445. }
  446. }
  447. #endif
  448. if(nDiffTot)
  449. {
  450. m_nStrips += nDiffTot;
  451. return true;
  452. }
  453. return false;
  454. }
  455. /*!***************************************************************************
  456. @Function StripFromEdges
  457. @Description Creates a strip from the object's edge information.
  458. *****************************************************************************/
  459. void CStrip::StripFromEdges()
  460. {
  461. unsigned int i, j, nTest;
  462. CTri *pTri, *pTriPrev;
  463. int nEdge = 0;
  464. /*
  465. Attempt to create grid-oriented strips.
  466. */
  467. for(i = 0; i < m_nTriCnt; ++i)
  468. {
  469. pTri = &m_pTri[i];
  470. // Count the number of empty edges
  471. nTest = 0;
  472. for(j = 0; j < 3; ++j)
  473. {
  474. if(!pTri->pAdj[j])
  475. {
  476. ++nTest;
  477. }
  478. else
  479. {
  480. nEdge = j;
  481. }
  482. }
  483. if(nTest != 2)
  484. continue;
  485. for(;;)
  486. {
  487. // A tri with two empty edges is a corner (there are other corners too, but this works so...)
  488. while(StripGrow(*pTri, nEdge, -1)) {};
  489. pTriPrev = pTri;
  490. pTri = pTri->pAdj[nEdge];
  491. if(!pTri)
  492. break;
  493. // Find the edge we came over
  494. nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
  495. // Step around to the next edge
  496. if(++nEdge > 2)
  497. nEdge = 0;
  498. pTriPrev = pTri;
  499. pTri = pTri->pAdj[nEdge];
  500. if(!pTri)
  501. break;
  502. // Find the edge we came over
  503. nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
  504. // Step around to the next edge
  505. if(--nEdge < 0)
  506. nEdge = 2;
  507. #if 0
  508. // If we're not tracking the edge, give up
  509. nTest = nEdge - 1;
  510. if(nTest < 0)
  511. nTest = 2;
  512. if(pTri->pAdj[nTest])
  513. break;
  514. else
  515. continue;
  516. #endif
  517. }
  518. }
  519. }
  520. #ifdef RND_TRIS_ORDER
  521. struct pair
  522. {
  523. unsigned int i, o;
  524. };
  525. static int compare(const void *arg1, const void *arg2)
  526. {
  527. return ((pair*)arg1)->i - ((pair*)arg2)->i;
  528. }
  529. #endif
  530. /*!***************************************************************************
  531. @Function StripImprove
  532. @Description Optimises the strip
  533. *****************************************************************************/
  534. void CStrip::StripImprove()
  535. {
  536. unsigned int i, j;
  537. bool bChanged;
  538. int nRepCnt, nChecks;
  539. int nMaxChange;
  540. #ifdef RND_TRIS_ORDER
  541. pair *pnOrder;
  542. /*
  543. Create a random order to process the tris
  544. */
  545. pnOrder = new pair[m_nTriCnt];
  546. #endif
  547. nRepCnt = 0;
  548. nChecks = 2;
  549. nMaxChange = 0;
  550. /*
  551. Reduce strip count by growing each of the three strips each tri can start.
  552. */
  553. while(nChecks)
  554. {
  555. --nChecks;
  556. bChanged = false;
  557. #ifdef RND_TRIS_ORDER
  558. /*
  559. Create a random order to process the tris
  560. */
  561. for(i = 0; i < m_nTriCnt; ++i)
  562. {
  563. pnOrder[i].i = rand() * rand();
  564. pnOrder[i].o = i;
  565. }
  566. qsort(pnOrder, m_nTriCnt, sizeof(*pnOrder), compare);
  567. #endif
  568. /*
  569. Process the tris
  570. */
  571. for(i = 0; i < m_nTriCnt; ++i)
  572. {
  573. for(j = 0; j < 3; ++j)
  574. {
  575. #ifdef RND_TRIS_ORDER
  576. bChanged |= StripGrow(m_pTri[pnOrder[i].o], j, nMaxChange);
  577. #else
  578. bChanged |= StripGrow(m_pTri[i], j, nMaxChange);
  579. #endif
  580. }
  581. }
  582. ++nRepCnt;
  583. // Check the results once or twice
  584. if(bChanged)
  585. nChecks = 2;
  586. nMaxChange = (nMaxChange == 0 ? -1 : 0);
  587. }
  588. #ifdef RND_TRIS_ORDER
  589. delete [] pnOrder;
  590. #endif
  591. _RPT1(_CRT_WARN, "Reps: %d\n", nRepCnt);
  592. }
  593. /*!***************************************************************************
  594. @Function Output
  595. @Output ppui32Strips
  596. @Output ppnStripLen The length of the strip
  597. @Output pnStripCnt
  598. @Description Outputs key information about the strip to the output
  599. parameters.
  600. *****************************************************************************/
  601. void CStrip::Output(
  602. unsigned int **ppui32Strips,
  603. unsigned int **ppnStripLen,
  604. unsigned int *pnStripCnt)
  605. {
  606. unsigned int *pui32Strips;
  607. unsigned int *pnStripLen;
  608. unsigned int i, j, nIdx, nStrip;
  609. CTri *pTri;
  610. /*
  611. Output Strips
  612. */
  613. pnStripLen = (unsigned int*)malloc(m_nStrips * sizeof(*pnStripLen));
  614. pui32Strips = (unsigned int*)malloc((m_nTriCnt + m_nStrips * 2) * sizeof(*pui32Strips));
  615. nStrip = 0;
  616. nIdx = 0;
  617. for(i = 0; i < m_nTriCnt; ++i)
  618. {
  619. pTri = &m_pTri[i];
  620. if(pTri->sNew.pRev)
  621. continue;
  622. _ASSERT(!pTri->sNew.pFwd || pTri->sNew.bWindFwd);
  623. _ASSERT(pTri->bOutput == false);
  624. if(!pTri->sNew.pFwd)
  625. {
  626. pui32Strips[nIdx++] = pTri->pIdx[0];
  627. pui32Strips[nIdx++] = pTri->pIdx[1];
  628. pui32Strips[nIdx++] = pTri->pIdx[2];
  629. pnStripLen[nStrip] = 1;
  630. pTri->bOutput = true;
  631. }
  632. else
  633. {
  634. if(pTri->sNew.pFwd == pTri->pAdj[0])
  635. {
  636. pui32Strips[nIdx++] = pTri->pIdx[2];
  637. pui32Strips[nIdx++] = pTri->pIdx[0];
  638. }
  639. else if(pTri->sNew.pFwd == pTri->pAdj[1])
  640. {
  641. pui32Strips[nIdx++] = pTri->pIdx[0];
  642. pui32Strips[nIdx++] = pTri->pIdx[1];
  643. }
  644. else
  645. {
  646. _ASSERT(pTri->sNew.pFwd == pTri->pAdj[2]);
  647. pui32Strips[nIdx++] = pTri->pIdx[1];
  648. pui32Strips[nIdx++] = pTri->pIdx[2];
  649. }
  650. pnStripLen[nStrip] = 0;
  651. do
  652. {
  653. _ASSERT(pTri->bOutput == false);
  654. // Increment tris-in-this-strip counter
  655. ++pnStripLen[nStrip];
  656. // Output the new vertex index
  657. for(j = 0; j < 3; ++j)
  658. {
  659. if(
  660. (pui32Strips[nIdx-2] != pTri->pIdx[j]) &&
  661. (pui32Strips[nIdx-1] != pTri->pIdx[j]))
  662. {
  663. break;
  664. }
  665. }
  666. _ASSERT(j != 3);
  667. pui32Strips[nIdx++] = pTri->pIdx[j];
  668. // Double-check that the previous three indices are the indices of this tris (in some order)
  669. _ASSERT(
  670. ((pui32Strips[nIdx-3] == pTri->pIdx[0]) && (pui32Strips[nIdx-2] == pTri->pIdx[1]) && (pui32Strips[nIdx-1] == pTri->pIdx[2])) ||
  671. ((pui32Strips[nIdx-3] == pTri->pIdx[1]) && (pui32Strips[nIdx-2] == pTri->pIdx[2]) && (pui32Strips[nIdx-1] == pTri->pIdx[0])) ||
  672. ((pui32Strips[nIdx-3] == pTri->pIdx[2]) && (pui32Strips[nIdx-2] == pTri->pIdx[0]) && (pui32Strips[nIdx-1] == pTri->pIdx[1])) ||
  673. ((pui32Strips[nIdx-3] == pTri->pIdx[2]) && (pui32Strips[nIdx-2] == pTri->pIdx[1]) && (pui32Strips[nIdx-1] == pTri->pIdx[0])) ||
  674. ((pui32Strips[nIdx-3] == pTri->pIdx[1]) && (pui32Strips[nIdx-2] == pTri->pIdx[0]) && (pui32Strips[nIdx-1] == pTri->pIdx[2])) ||
  675. ((pui32Strips[nIdx-3] == pTri->pIdx[0]) && (pui32Strips[nIdx-2] == pTri->pIdx[2]) && (pui32Strips[nIdx-1] == pTri->pIdx[1])));
  676. // Check that the latest three indices are not degenerate
  677. _ASSERT(pui32Strips[nIdx-1] != pui32Strips[nIdx-2]);
  678. _ASSERT(pui32Strips[nIdx-1] != pui32Strips[nIdx-3]);
  679. _ASSERT(pui32Strips[nIdx-2] != pui32Strips[nIdx-3]);
  680. pTri->bOutput = true;
  681. // Check that the next triangle is adjacent to this triangle
  682. _ASSERT(
  683. (pTri->sNew.pFwd == pTri->pAdj[0]) ||
  684. (pTri->sNew.pFwd == pTri->pAdj[1]) ||
  685. (pTri->sNew.pFwd == pTri->pAdj[2]) ||
  686. (!pTri->sNew.pFwd));
  687. // Check that this triangle is adjacent to the next triangle
  688. _ASSERT(
  689. (!pTri->sNew.pFwd) ||
  690. (pTri == pTri->sNew.pFwd->pAdj[0]) ||
  691. (pTri == pTri->sNew.pFwd->pAdj[1]) ||
  692. (pTri == pTri->sNew.pFwd->pAdj[2]));
  693. pTri = pTri->sNew.pFwd;
  694. } while(pTri);
  695. }
  696. ++nStrip;
  697. }
  698. _ASSERT(nIdx == m_nTriCnt + m_nStrips * 2);
  699. _ASSERT(nStrip == m_nStrips);
  700. // Check all triangles have been output
  701. for(i = 0; i < m_nTriCnt; ++i)
  702. {
  703. _ASSERT(m_pTri[i].bOutput == true);
  704. }
  705. // Check all triangles are present
  706. j = 0;
  707. for(i = 0; i < m_nStrips; ++i)
  708. {
  709. j += pnStripLen[i];
  710. }
  711. _ASSERT(j == m_nTriCnt);
  712. // Output data
  713. *pnStripCnt = m_nStrips;
  714. *ppui32Strips = pui32Strips;
  715. *ppnStripLen = pnStripLen;
  716. }
  717. /****************************************************************************
  718. ** Code
  719. ****************************************************************************/
  720. /*!***************************************************************************
  721. @Function PVRTTriStrip
  722. @Output ppui32Strips
  723. @Output ppnStripLen
  724. @Output pnStripCnt
  725. @Input pui32TriList
  726. @Input nTriCnt
  727. @Description Reads a triangle list and generates an optimised triangle strip.
  728. *****************************************************************************/
  729. void PVRTTriStrip(
  730. unsigned int **ppui32Strips,
  731. unsigned int **ppnStripLen,
  732. unsigned int *pnStripCnt,
  733. const unsigned int * const pui32TriList,
  734. const unsigned int nTriCnt)
  735. {
  736. unsigned int *pui32Strips;
  737. unsigned int *pnStripLen;
  738. unsigned int nStripCnt;
  739. /*
  740. If the order in which triangles are tested as strip roots is
  741. randomised, then several attempts can be made. Use the best result.
  742. */
  743. for(int i = 0; i <
  744. #ifdef RND_TRIS_ORDER
  745. 5
  746. #else
  747. 1
  748. #endif
  749. ; ++i)
  750. {
  751. CStrip stripper(pui32TriList, nTriCnt);
  752. #ifdef RND_TRIS_ORDER
  753. srand(i);
  754. #endif
  755. stripper.StripFromEdges();
  756. stripper.StripImprove();
  757. stripper.Output(&pui32Strips, &pnStripLen, &nStripCnt);
  758. if(!i || nStripCnt < *pnStripCnt)
  759. {
  760. if(i)
  761. {
  762. FREE(*ppui32Strips);
  763. FREE(*ppnStripLen);
  764. }
  765. *ppui32Strips = pui32Strips;
  766. *ppnStripLen = pnStripLen;
  767. *pnStripCnt = nStripCnt;
  768. }
  769. else
  770. {
  771. FREE(pui32Strips);
  772. FREE(pnStripLen);
  773. }
  774. }
  775. }
  776. /*!***************************************************************************
  777. @Function PVRTTriStripList
  778. @Modified pui32TriList
  779. @Input nTriCnt
  780. @Description Reads a triangle list and generates an optimised triangle strip.
  781. Result is converted back to a triangle list.
  782. *****************************************************************************/
  783. void PVRTTriStripList(unsigned int * const pui32TriList, const unsigned int nTriCnt)
  784. {
  785. unsigned int *pui32Strips;
  786. unsigned int *pnStripLength;
  787. unsigned int nNumStrips;
  788. unsigned int *pui32TriPtr, *pui32StripPtr;
  789. /*
  790. Strip the geometry
  791. */
  792. PVRTTriStrip(&pui32Strips, &pnStripLength, &nNumStrips, pui32TriList, nTriCnt);
  793. /*
  794. Convert back to a triangle list
  795. */
  796. pui32StripPtr = pui32Strips;
  797. pui32TriPtr = pui32TriList;
  798. for(unsigned int i = 0; i < nNumStrips; ++i)
  799. {
  800. *pui32TriPtr++ = *pui32StripPtr++;
  801. *pui32TriPtr++ = *pui32StripPtr++;
  802. *pui32TriPtr++ = *pui32StripPtr++;
  803. for(unsigned int j = 1; j < pnStripLength[i]; ++j)
  804. {
  805. // Use two indices from previous triangle, flipping tri order alternately.
  806. if(j & 0x01)
  807. {
  808. *pui32TriPtr++ = pui32StripPtr[-1];
  809. *pui32TriPtr++ = pui32StripPtr[-2];
  810. }
  811. else
  812. {
  813. *pui32TriPtr++ = pui32StripPtr[-2];
  814. *pui32TriPtr++ = pui32StripPtr[-1];
  815. }
  816. *pui32TriPtr++ = *pui32StripPtr++;
  817. }
  818. }
  819. free(pui32Strips);
  820. free(pnStripLength);
  821. }
  822. /*****************************************************************************
  823. End of file (PVRTTriStrip.cpp)
  824. *****************************************************************************/