Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

930 lines
28 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //-----------------------------------------------------------------------------
  9. // FILE: TRISTRIP.CPP
  10. //
  11. // Desc: Xbox tristripper
  12. //
  13. // Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
  14. //-----------------------------------------------------------------------------
  15. // identifier was truncated to '255' characters in the debug information
  16. #pragma warning(disable: 4786)
  17. // conversion from 'double' to 'float'
  18. #pragma warning(disable: 4244)
  19. #pragma warning(disable: 4530)
  20. #include <stdio.h>
  21. #include <stdarg.h>
  22. #include <algorithm>
  23. #include <list>
  24. #include <vector>
  25. #include <assert.h>
  26. #ifdef _DEBUG
  27. #include <crtdbg.h>
  28. #endif
  29. #include "mstristrip.h"
  30. using namespace std;
  31. //=========================================================================
  32. // structs
  33. //=========================================================================
  34. typedef vector<WORD> STRIPVERTS;
  35. typedef list<STRIPVERTS *> STRIPLIST;
  36. typedef WORD (*TRIANGLELIST)[3];
  37. struct TRIANGLEINFO
  38. {
  39. int neighbortri[3];
  40. int neighboredge[3];
  41. };
  42. // return true if strip starts clockwise
  43. inline bool FIsStripCW(const STRIPVERTS &stripvertices)
  44. {
  45. // last index should have cw/ccw bool
  46. return !!stripvertices[stripvertices.size() - 1];
  47. }
  48. // return length of strip
  49. inline int StripLen(const STRIPVERTS &stripvertices)
  50. {
  51. return (int)stripvertices.size() - 1;
  52. }
  53. // free all stripverts and clear the striplist
  54. inline void FreeStripListVerts(STRIPLIST *pstriplist)
  55. {
  56. STRIPLIST::iterator istriplist = pstriplist->begin();
  57. while(istriplist != pstriplist->end())
  58. {
  59. STRIPVERTS *pstripverts = *istriplist;
  60. delete pstripverts;
  61. pstriplist->erase(istriplist++);
  62. }
  63. }
  64. //=========================================================================
  65. // main stripper class
  66. //=========================================================================
  67. class CStripper
  68. {
  69. public:
  70. // ctors/dtors
  71. CStripper(int numtris, TRIANGLELIST ptriangles);
  72. ~CStripper();
  73. // initialize tri info
  74. void InitTriangleInfo(int tri, int vert);
  75. // get maximum length strip from tri/vert
  76. int CreateStrip(int tri, int vert, int maxlen, int *pswaps,
  77. bool flookahead, bool fstartcw, int *pstriptris, int *pstripverts);
  78. // stripify entire mesh
  79. void BuildStrips(STRIPLIST *pstriplist, int maxlen, bool flookahead);
  80. // blast strip indices to ppstripindices
  81. int CreateManyStrips(STRIPLIST *pstriplist, WORD **ppstripindices);
  82. int CreateLongStrip(STRIPLIST *pstriplist, WORD **ppstripindices);
  83. inline int GetNeighborCount(int tri)
  84. {
  85. int count = 0;
  86. for(int vert = 0; vert < 3; vert++)
  87. {
  88. int neighbortri = m_ptriinfo[tri].neighbortri[vert];
  89. count += (neighbortri != -1) && !m_pused[neighbortri];
  90. }
  91. return count;
  92. }
  93. // from callee
  94. int m_numtris; // # tris
  95. TRIANGLELIST m_ptriangles; // trilist
  96. TRIANGLEINFO *m_ptriinfo; // tri edge, neighbor info
  97. int *m_pused; // tri used flag
  98. };
  99. //=========================================================================
  100. // vertex cache class
  101. //=========================================================================
  102. class CVertCache
  103. {
  104. public:
  105. CVertCache()
  106. { Reset(); }
  107. ~CVertCache()
  108. {};
  109. // reset cache
  110. void Reset()
  111. {
  112. m_iCachePtr = 0;
  113. m_cachehits = 0;
  114. memset(m_rgCache, 0xff, sizeof(m_rgCache));
  115. }
  116. // add vertindex to cache
  117. bool Add(int strip, int vertindex);
  118. int NumCacheHits() const
  119. { return m_cachehits; }
  120. // enum { CACHE_SIZE = 10 };
  121. enum { CACHE_SIZE = 18 };
  122. private:
  123. int m_cachehits; // current # of cache hits
  124. WORD m_rgCache[CACHE_SIZE]; // vertex cache
  125. int m_rgCacheStrip[CACHE_SIZE]; // strip # which added vert
  126. int m_iCachePtr; // fifo ptr
  127. };
  128. //=========================================================================
  129. // Get maximum length of strip starting at tri/vert
  130. //=========================================================================
  131. int CStripper::CreateStrip(int tri, int vert, int maxlen, int *pswaps,
  132. bool flookahead, bool fstartcw, int *pstriptris, int *pstripverts)
  133. {
  134. *pswaps = 0;
  135. // this guy has already been used?
  136. if(m_pused[tri])
  137. return 0;
  138. // mark tri as used
  139. m_pused[tri] = 1;
  140. int swaps = 0;
  141. // add first tri info
  142. pstriptris[0] = tri;
  143. pstriptris[1] = tri;
  144. pstriptris[2] = tri;
  145. if(fstartcw)
  146. {
  147. pstripverts[0] = (vert) % 3;
  148. pstripverts[1] = (vert + 1) % 3;
  149. pstripverts[2] = (vert + 2) % 3;
  150. }
  151. else
  152. {
  153. pstripverts[0] = (vert + 1) % 3;
  154. pstripverts[1] = (vert + 0) % 3;
  155. pstripverts[2] = (vert + 2) % 3;
  156. }
  157. fstartcw = !fstartcw;
  158. // get next tri information
  159. int edge = (fstartcw ? vert + 2 : vert + 1) % 3;
  160. int nexttri = m_ptriinfo[tri].neighbortri[edge];
  161. int nextvert = m_ptriinfo[tri].neighboredge[edge];
  162. // start building the strip until we run out of room or indices
  163. int stripcount;
  164. for( stripcount = 3; stripcount < maxlen; stripcount++)
  165. {
  166. // dead end?
  167. if(nexttri == -1 || m_pused[nexttri])
  168. break;
  169. // move to next tri
  170. tri = nexttri;
  171. vert = nextvert;
  172. // toggle orientation
  173. fstartcw = !fstartcw;
  174. // find the next natural edge
  175. int edge = (fstartcw ? vert + 2 : vert + 1) % 3;
  176. nexttri = m_ptriinfo[tri].neighbortri[edge];
  177. nextvert = m_ptriinfo[tri].neighboredge[edge];
  178. bool fswap = false;
  179. if(nexttri == -1 || m_pused[nexttri])
  180. {
  181. // if the next tri is a dead end - try swapping orientation
  182. fswap = true;
  183. }
  184. else if(flookahead)
  185. {
  186. // try a swap and see who our new neighbor would be
  187. int edgeswap = (fstartcw ? vert + 1 : vert + 2) % 3;
  188. int nexttriswap = m_ptriinfo[tri].neighbortri[edgeswap];
  189. int nextvertswap = m_ptriinfo[tri].neighboredge[edgeswap];
  190. if(nexttriswap != -1 && !m_pused[nexttriswap])
  191. {
  192. assert(nexttri != -1);
  193. // if the swap neighbor has a lower count, change directions
  194. if(GetNeighborCount(nexttriswap) < GetNeighborCount(nexttri))
  195. {
  196. fswap = true;
  197. }
  198. else if(GetNeighborCount(nexttriswap) == GetNeighborCount(nexttri))
  199. {
  200. // if they have the same number of neighbors - check their neighbors
  201. edgeswap = (fstartcw ? nextvertswap + 2 : nextvertswap + 1) % 3;
  202. nexttriswap = m_ptriinfo[nexttriswap].neighbortri[edgeswap];
  203. int edge1 = (fstartcw ? nextvert + 1 : nextvert + 2) % 3;
  204. int nexttri1 = m_ptriinfo[nexttri].neighbortri[edge1];
  205. if(nexttri1 == -1 || m_pused[nexttri1])
  206. {
  207. // natural winding order leads us to a dead end so turn
  208. fswap = true;
  209. }
  210. else if(nexttriswap != -1 && !m_pused[nexttriswap])
  211. {
  212. // check neighbor counts on both directions and swap if it's better
  213. if(GetNeighborCount(nexttriswap) < GetNeighborCount(nexttri1))
  214. fswap = true;
  215. }
  216. }
  217. }
  218. }
  219. if(fswap)
  220. {
  221. // we've been told to change directions so make sure we actually can
  222. // and then add the swap vertex
  223. int edgeswap = (fstartcw ? vert + 1 : vert + 2) % 3;
  224. nexttri = m_ptriinfo[tri].neighbortri[edgeswap];
  225. nextvert = m_ptriinfo[tri].neighboredge[edgeswap];
  226. if(nexttri != -1 && !m_pused[nexttri])
  227. {
  228. pstriptris[stripcount] = pstriptris[stripcount - 2];
  229. pstripverts[stripcount] = pstripverts[stripcount - 2];
  230. stripcount++;
  231. swaps++;
  232. fstartcw = !fstartcw;
  233. }
  234. }
  235. // record index information
  236. pstriptris[stripcount] = tri;
  237. pstripverts[stripcount] = (vert + 2) % 3;
  238. // mark triangle as used
  239. m_pused[tri] = 1;
  240. }
  241. // clear the used flags
  242. for(int j = 2; j < stripcount; j++)
  243. m_pused[pstriptris[j]] = 0;
  244. // return swap count and striplen
  245. *pswaps = swaps;
  246. return stripcount;
  247. }
  248. //=========================================================================
  249. // Given a striplist and current cache state, pick the best next strip
  250. //=========================================================================
  251. STRIPLIST::iterator FindBestCachedStrip(STRIPLIST *pstriplist,
  252. const CVertCache &vertcachestate)
  253. {
  254. if(pstriplist->empty())
  255. return pstriplist->end();
  256. bool fFlipStrip = false;
  257. int maxcachehits = -1;
  258. STRIPLIST::iterator istriplistbest = pstriplist->begin();
  259. int striplen = StripLen(**istriplistbest);
  260. bool fstartcw = FIsStripCW(**istriplistbest);
  261. // go through all the other strips looking for the best caching
  262. for(STRIPLIST::iterator istriplist = pstriplist->begin();
  263. istriplist != pstriplist->end();
  264. ++istriplist)
  265. {
  266. bool fFlip = false;
  267. const STRIPVERTS &stripverts = **istriplist;
  268. int striplennew = StripLen(stripverts);
  269. // check cache if this strip is the same type as us (ie: cw/odd)
  270. if((FIsStripCW(stripverts) == fstartcw) &&
  271. ((striplen & 0x1) == (striplennew & 0x1)))
  272. {
  273. // copy current state of cache
  274. CVertCache vertcachenew = vertcachestate;
  275. // figure out what this guy would do to our cache
  276. for(int ivert = 0; ivert < striplennew; ivert++)
  277. vertcachenew.Add(2, stripverts[ivert]);
  278. // even length strip - see if better cache hits reversed
  279. if(!(striplennew & 0x1))
  280. {
  281. CVertCache vertcacheflipped = vertcachestate;
  282. for(int ivert = StripLen(stripverts) - 1; ivert >= 0; ivert--)
  283. vertcacheflipped.Add(2, stripverts[ivert]);
  284. if(vertcacheflipped.NumCacheHits() > vertcachenew.NumCacheHits())
  285. {
  286. vertcachenew = vertcacheflipped;
  287. fFlip = true;
  288. }
  289. }
  290. // record the best number of cache hits to date
  291. int numcachehits = vertcachenew.NumCacheHits() - vertcachestate.NumCacheHits();
  292. if(numcachehits > maxcachehits)
  293. {
  294. maxcachehits = numcachehits;
  295. istriplistbest = istriplist;
  296. fFlipStrip = fFlip;
  297. }
  298. }
  299. }
  300. if(fFlipStrip)
  301. {
  302. STRIPVERTS &stripverts = **istriplistbest;
  303. STRIPVERTS::iterator vend = stripverts.end();
  304. reverse(stripverts.begin(), --vend);
  305. }
  306. // make sure we keep the list in order and always pull off
  307. // the first dude.
  308. if(istriplistbest != pstriplist->begin())
  309. swap(*istriplistbest, *pstriplist->begin());
  310. return pstriplist->begin();
  311. }
  312. //=========================================================================
  313. // Don't merge the strips - just blast em into the stripbuffer one by one
  314. // (useful for debugging)
  315. //=========================================================================
  316. int CStripper::CreateManyStrips(STRIPLIST *pstriplist, WORD **ppstripindices)
  317. {
  318. // allow room for each of the strips size plus the final 0
  319. int indexcount = (int)pstriplist->size() + 1;
  320. // we're storing the strips in [size1 i1 i2 i3][size2 i4 i5 i6][0] format
  321. STRIPLIST::iterator istriplist;
  322. for( istriplist = pstriplist->begin(); istriplist != pstriplist->end(); ++istriplist)
  323. {
  324. // add striplength plus potential degenerate to swap ccw --> cw
  325. indexcount += StripLen(**istriplist) + 1;
  326. }
  327. // alloc the space for all this stuff
  328. WORD *pstripindices = new WORD [indexcount];
  329. assert(pstripindices);
  330. CVertCache vertcache;
  331. int numstripindices = 0;
  332. for(istriplist = pstriplist->begin();
  333. !pstriplist->empty();
  334. istriplist = FindBestCachedStrip(pstriplist, vertcache))
  335. {
  336. const STRIPVERTS &stripverts = **istriplist;
  337. if(!FIsStripCW(stripverts))
  338. {
  339. // add an extra index if it's ccw
  340. pstripindices[numstripindices++] = StripLen(stripverts) + 1;
  341. pstripindices[numstripindices++] = stripverts[0];
  342. }
  343. else
  344. {
  345. // add the strip length
  346. pstripindices[numstripindices++] = StripLen(stripverts);
  347. }
  348. // add all the strip indices
  349. for(int i = 0; i < StripLen(stripverts); i++)
  350. {
  351. pstripindices[numstripindices++] = stripverts[i];
  352. vertcache.Add(1, stripverts[i]);
  353. }
  354. // free this guy and pop him off the list
  355. delete &stripverts;
  356. pstriplist->pop_front();
  357. }
  358. // add terminating zero
  359. pstripindices[numstripindices++] = 0;
  360. *ppstripindices = pstripindices;
  361. return numstripindices;
  362. }
  363. //=========================================================================
  364. // Merge striplist into one big uberlist with (hopefully) optimal caching
  365. //=========================================================================
  366. int CStripper::CreateLongStrip(STRIPLIST *pstriplist, WORD **ppstripindices)
  367. {
  368. // allow room for one strip length plus a possible 3 extra indices per
  369. // concatenated strip list plus the final 0
  370. int indexcount = ((int)pstriplist->size() * 3) + 2;
  371. // we're storing the strips in [size1 i1 i2 i3][size2 i4 i5 i6][0] format
  372. STRIPLIST::iterator istriplist;
  373. for( istriplist = pstriplist->begin(); istriplist != pstriplist->end(); ++istriplist)
  374. {
  375. indexcount += StripLen(**istriplist);
  376. }
  377. // alloc the space for all this stuff
  378. WORD *pstripindices = new WORD [indexcount];
  379. assert(pstripindices);
  380. CVertCache vertcache;
  381. int numstripindices = 0;
  382. // add first strip
  383. istriplist = pstriplist->begin();
  384. const STRIPVERTS &stripverts = **istriplist;
  385. // first strip should be cw
  386. assert(FIsStripCW(stripverts));
  387. for(int ivert = 0; ivert < StripLen(stripverts); ivert++)
  388. {
  389. pstripindices[numstripindices++] = stripverts[ivert];
  390. vertcache.Add(1, stripverts[ivert]);
  391. }
  392. // kill first dude
  393. delete &stripverts;
  394. pstriplist->erase(istriplist);
  395. // add all the others
  396. while(pstriplist->size())
  397. {
  398. istriplist = FindBestCachedStrip(pstriplist, vertcache);
  399. STRIPVERTS &stripverts = **istriplist;
  400. short lastvert = pstripindices[numstripindices - 1];
  401. short firstvert = stripverts[0];
  402. if(firstvert != lastvert)
  403. {
  404. // add degenerate from last strip
  405. pstripindices[numstripindices++] = lastvert;
  406. // add degenerate from our strip
  407. pstripindices[numstripindices++] = firstvert;
  408. }
  409. // if we're not orientated correctly, we need to add a degenerate
  410. if(FIsStripCW(stripverts) != !(numstripindices & 0x1))
  411. {
  412. // This shouldn't happen - we're currently trying very hard
  413. // to keep everything oriented correctly.
  414. assert(false);
  415. pstripindices[numstripindices++] = firstvert;
  416. }
  417. // add these verts
  418. for(int ivert = 0; ivert < StripLen(stripverts); ivert++)
  419. {
  420. pstripindices[numstripindices++] = stripverts[ivert];
  421. vertcache.Add(1, stripverts[ivert]);
  422. }
  423. // free these guys
  424. delete &stripverts;
  425. pstriplist->erase(istriplist);
  426. }
  427. *ppstripindices = pstripindices;
  428. return numstripindices;
  429. }
  430. //=========================================================================
  431. // Build a (hopefully) optimal set of strips from a trilist
  432. //=========================================================================
  433. void CStripper::BuildStrips(STRIPLIST *pstriplist, int maxlen, bool flookahead)
  434. {
  435. // temp indices storage
  436. const int ctmpverts = 1024;
  437. int pstripverts[ctmpverts + 1];
  438. int pstriptris[ctmpverts + 1];
  439. assert(maxlen <= ctmpverts);
  440. // clear all the used flags for the tris
  441. memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
  442. bool fstartcw = true;
  443. for(;;)
  444. {
  445. int besttri = 0;
  446. int bestvert = 0;
  447. float bestratio = 2.0f;
  448. int bestneighborcount = INT_MAX;
  449. int tri;
  450. for( tri = 0; tri < m_numtris; tri++)
  451. {
  452. // if used the continue
  453. if(m_pused[tri])
  454. continue;
  455. // get the neighbor count
  456. int curneightborcount = GetNeighborCount(tri);
  457. assert(curneightborcount >= 0 && curneightborcount <= 3);
  458. // push all the singletons to the very end
  459. if(!curneightborcount)
  460. curneightborcount = 4;
  461. // if this guy has more neighbors than the current best - bail
  462. if(curneightborcount > bestneighborcount)
  463. continue;
  464. // try starting the strip with each of this tris verts
  465. for(int vert = 0; vert < 3; vert++)
  466. {
  467. int swaps;
  468. int len = CreateStrip(tri, vert, maxlen, &swaps, flookahead,
  469. fstartcw, pstriptris, pstripverts);
  470. assert(len);
  471. float ratio = (len == 3) ? 1.0f : (float)swaps / len;
  472. // check if this ratio is better than what we've already got for
  473. // this neighborcount
  474. if((curneightborcount < bestneighborcount) ||
  475. ((curneightborcount == bestneighborcount) && (ratio < bestratio)))
  476. {
  477. bestneighborcount = curneightborcount;
  478. besttri = tri;
  479. bestvert = vert;
  480. bestratio = ratio;
  481. }
  482. }
  483. }
  484. // no strips found?
  485. if(bestneighborcount == INT_MAX)
  486. break;
  487. // recreate this strip
  488. int swaps;
  489. int len = CreateStrip(besttri, bestvert, maxlen,
  490. &swaps, flookahead, fstartcw, pstriptris, pstripverts);
  491. assert(len);
  492. // mark the tris on the best strip as used
  493. for(tri = 0; tri < len; tri++)
  494. m_pused[pstriptris[tri]] = 1;
  495. // create a new STRIPVERTS and stuff in the indices
  496. STRIPVERTS *pstripvertices = new STRIPVERTS(len + 1);
  497. assert(pstripvertices);
  498. // store orientation in first entry
  499. for(tri = 0; tri < len; tri++)
  500. (*pstripvertices)[tri] = m_ptriangles[pstriptris[tri]][pstripverts[tri]];
  501. (*pstripvertices)[len] = fstartcw;
  502. // store the STRIPVERTS
  503. pstriplist->push_back(pstripvertices);
  504. // if strip was odd - swap orientation
  505. if((len & 0x1))
  506. fstartcw = !fstartcw;
  507. }
  508. #ifdef _DEBUG
  509. // make sure all tris are used
  510. for(int t = 0; t < m_numtris; t++)
  511. assert(m_pused[t]);
  512. #endif
  513. }
  514. //=========================================================================
  515. // Guesstimate on the total index count for this list of strips
  516. //=========================================================================
  517. int EstimateStripCost(STRIPLIST *pstriplist)
  518. {
  519. int count = 0;
  520. for(STRIPLIST::iterator istriplist = pstriplist->begin();
  521. istriplist != pstriplist->end();
  522. ++istriplist)
  523. {
  524. // add count of indices
  525. count += StripLen(**istriplist);
  526. }
  527. // assume 2 indices per strip to tack all these guys together
  528. return count + ((int)pstriplist->size() - 1) * 2;
  529. }
  530. //=========================================================================
  531. // Initialize triangle information (edges, #neighbors, etc.)
  532. //=========================================================================
  533. void CStripper::InitTriangleInfo(int tri, int vert)
  534. {
  535. WORD *ptriverts = &m_ptriangles[tri + 1][0];
  536. int vert1 = m_ptriangles[tri][(vert + 1) % 3];
  537. int vert2 = m_ptriangles[tri][vert];
  538. for(int itri = tri + 1; itri < m_numtris; itri++, ptriverts += 3)
  539. {
  540. if(m_pused[itri] != 0x7)
  541. {
  542. for(int ivert = 0; ivert < 3; ivert++)
  543. {
  544. if((ptriverts[ivert] == vert1) &&
  545. (ptriverts[(ivert + 1) % 3] == vert2))
  546. {
  547. // add the triangle info
  548. m_ptriinfo[tri].neighbortri[vert] = itri;
  549. m_ptriinfo[tri].neighboredge[vert] = ivert;
  550. m_pused[tri] |= (1 << vert);
  551. m_ptriinfo[itri].neighbortri[ivert] = tri;
  552. m_ptriinfo[itri].neighboredge[ivert] = vert;
  553. m_pused[itri] |= (1 << ivert);
  554. return;
  555. }
  556. }
  557. }
  558. }
  559. }
  560. //=========================================================================
  561. // CStripper ctor
  562. //=========================================================================
  563. CStripper::CStripper(int numtris, TRIANGLELIST ptriangles)
  564. {
  565. // store trilist info
  566. m_numtris = numtris;
  567. m_ptriangles = ptriangles;
  568. m_pused = new int[numtris];
  569. assert(m_pused);
  570. m_ptriinfo = new TRIANGLEINFO[numtris];
  571. assert(m_ptriinfo);
  572. // init triinfo
  573. int itri;
  574. for( itri = 0; itri < numtris; itri++)
  575. {
  576. m_ptriinfo[itri].neighbortri[0] = -1;
  577. m_ptriinfo[itri].neighbortri[1] = -1;
  578. m_ptriinfo[itri].neighbortri[2] = -1;
  579. }
  580. // clear the used flag
  581. memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
  582. // go through all the triangles and find edges, neighbor counts
  583. for(itri = 0; itri < numtris; itri++)
  584. {
  585. for(int ivert = 0; ivert < 3; ivert++)
  586. {
  587. if(!(m_pused[itri] & (1 << ivert)))
  588. InitTriangleInfo(itri, ivert);
  589. }
  590. }
  591. // clear the used flags from InitTriangleInfo
  592. memset(m_pused, 0, sizeof(m_pused[0]) * m_numtris);
  593. }
  594. //=========================================================================
  595. // CStripper dtor
  596. //=========================================================================
  597. CStripper::~CStripper()
  598. {
  599. // free stuff
  600. delete [] m_pused;
  601. m_pused = NULL;
  602. delete [] m_ptriinfo;
  603. m_ptriinfo = NULL;
  604. }
  605. //=========================================================================
  606. // Add an index to the cache - returns true if it was added, false otherwise
  607. //=========================================================================
  608. bool CVertCache::Add(int strip, int vertindex)
  609. {
  610. // find index in cache
  611. for(int iCache = 0; iCache < CACHE_SIZE; iCache++)
  612. {
  613. if(vertindex == m_rgCache[iCache])
  614. {
  615. // if it's in the cache and it's from a different strip
  616. // change the strip to the new one and count the cache hit
  617. if(strip != m_rgCacheStrip[iCache])
  618. {
  619. m_cachehits++;
  620. m_rgCacheStrip[iCache] = strip;
  621. return true;
  622. }
  623. // we added this item to the cache earlier - carry on
  624. return false;
  625. }
  626. }
  627. // not in cache, add vert and strip
  628. m_rgCache[m_iCachePtr] = vertindex;
  629. m_rgCacheStrip[m_iCachePtr] = strip;
  630. m_iCachePtr = (m_iCachePtr + 1) % CACHE_SIZE;
  631. return true;
  632. }
  633. #ifdef _DEBUG
  634. //=========================================================================
  635. // Turn on c runtime leak checking, etc.
  636. //=========================================================================
  637. void EnableLeakChecking()
  638. {
  639. int flCrtDbgFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
  640. flCrtDbgFlags &=
  641. ~(_CRTDBG_LEAK_CHECK_DF |
  642. _CRTDBG_CHECK_ALWAYS_DF |
  643. _CRTDBG_DELAY_FREE_MEM_DF);
  644. // always check for memory leaks
  645. flCrtDbgFlags |= _CRTDBG_LEAK_CHECK_DF;
  646. // others you may / may not want to set
  647. flCrtDbgFlags |= _CRTDBG_CHECK_ALWAYS_DF;
  648. flCrtDbgFlags |= _CRTDBG_DELAY_FREE_MEM_DF;
  649. _CrtSetDbgFlag(flCrtDbgFlags);
  650. // all types of reports go via OutputDebugString
  651. _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
  652. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
  653. _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
  654. // big errors and asserts get their own assert window
  655. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
  656. _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_WNDW);
  657. // _CrtSetBreakAlloc(0);
  658. }
  659. #endif
  660. //=========================================================================
  661. // Main Stripify routine
  662. //=========================================================================
  663. int Stripify(int numtris, WORD *ptriangles, int *pnumindices, WORD **ppstripindices)
  664. {
  665. if(!numtris || !ptriangles)
  666. return 0;
  667. #ifdef _DEBUG
  668. // EnableLeakChecking();
  669. #endif
  670. CStripper stripper(numtris, (TRIANGLELIST)ptriangles);
  671. // map of various args to try stripifying mesh with
  672. struct ARGMAP
  673. {
  674. int maxlen; // maximum length of strips
  675. bool flookahead; // use sgi greedy lookahead (or not)
  676. } rgargmap[] =
  677. {
  678. { 1024, true },
  679. { 1024, false },
  680. };
  681. static const int cargmaps = sizeof(rgargmap) / sizeof(rgargmap[0]);
  682. STRIPLIST striplistbest;
  683. int bestlistcost = 0;
  684. for(int imap = 0; imap < cargmaps; imap++)
  685. {
  686. STRIPLIST striplist;
  687. // build the strip with the various args
  688. stripper.BuildStrips(&striplist, rgargmap[imap].maxlen,
  689. rgargmap[imap].flookahead);
  690. // guesstimate the list cost and store it if it's good
  691. int listcost = EstimateStripCost(&striplist);
  692. if(!bestlistcost || (listcost < bestlistcost))
  693. {
  694. // free the old best list
  695. FreeStripListVerts(&striplistbest);
  696. // store the new best list
  697. striplistbest = striplist;
  698. bestlistcost = listcost;
  699. assert(bestlistcost > 0);
  700. }
  701. else
  702. {
  703. FreeStripListVerts(&striplist);
  704. }
  705. }
  706. #ifdef NEVER
  707. // Return the strips in [size1 i1 i2 i3][size2 i4 i5 i6]...[0] format
  708. // Very useful for debugging...
  709. return stripper.CreateManyStrips(&striplistbest, ppstripindices);
  710. #endif // NEVER
  711. // return one big long strip
  712. int numindices = stripper.CreateLongStrip(&striplistbest, ppstripindices);
  713. if(pnumindices)
  714. *pnumindices = numindices;
  715. return numindices;
  716. }
  717. //=========================================================================
  718. // Class used to vertices for locality of access.
  719. //=========================================================================
  720. struct SortEntry
  721. {
  722. public:
  723. int iFirstUsed;
  724. int iOrigIndex;
  725. bool operator<(const SortEntry& rhs)
  726. {
  727. return iFirstUsed < rhs.iFirstUsed;
  728. }
  729. };
  730. //=========================================================================
  731. // Reorder the vertices
  732. //=========================================================================
  733. void ComputeVertexPermutation(int numstripindices, WORD* pstripindices,
  734. int* pnumverts, WORD** ppvertexpermutation)
  735. {
  736. // Sort verts to maximize locality.
  737. SortEntry* pSortTable = new SortEntry[*pnumverts];
  738. // Fill in original index.
  739. int i;
  740. for( i = 0; i < *pnumverts; i++)
  741. {
  742. pSortTable[i].iOrigIndex = i;
  743. pSortTable[i].iFirstUsed = -1;
  744. }
  745. // Fill in first used flag.
  746. for(i = 0; i < numstripindices; i++)
  747. {
  748. int index = pstripindices[i];
  749. if(pSortTable[index].iFirstUsed == -1)
  750. pSortTable[index].iFirstUsed = i;
  751. }
  752. // Sort the table.
  753. sort(pSortTable, pSortTable + *pnumverts);
  754. // Copy re-mapped to orignal vertex permutaion into output array.
  755. *ppvertexpermutation = new WORD[*pnumverts];
  756. for(i = 0; i < *pnumverts; i++)
  757. {
  758. (*ppvertexpermutation)[i] = pSortTable[i].iOrigIndex;
  759. }
  760. // Build original to re-mapped permutation.
  761. WORD* pInversePermutation = new WORD[numstripindices];
  762. for(i = 0; i < *pnumverts; i++)
  763. {
  764. pInversePermutation[pSortTable[i].iOrigIndex] = i;
  765. }
  766. // We need to remap indices as well.
  767. for(i = 0; i < numstripindices; i++)
  768. {
  769. pstripindices[i] = pInversePermutation[pstripindices[i]];
  770. }
  771. delete[] pSortTable;
  772. delete[] pInversePermutation;
  773. }