stripoptimizer.cpp 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "stripoptimizer.h"
  19. #include "hashtemplate.h"
  20. #include "wwdebug.h"
  21. template <class T> inline void swap (T& a, T& b)
  22. {
  23. T t(a);
  24. a = b;
  25. b = t;
  26. }
  27. //------------------------------------------------------------------------
  28. // Prototypes for sort functions. Note that class T must have
  29. // operators =, > and < in order for the functions to compile.
  30. //------------------------------------------------------------------------
  31. template <class T> inline void Insertion_Sort (T* a, int N);
  32. template <class T> inline void Quick_Sort (T* a, int N);
  33. template <class T> inline void Insertion_Sort (T* a, int N)
  34. {
  35. for (int i = 1; i < N; i++)
  36. if (a[i-1] > a[i])
  37. {
  38. T v = a[i];
  39. int j = i;
  40. while (a[j-1]> v)
  41. {
  42. a[j] = a[j-1]; // copy data
  43. j--;
  44. if (!j)
  45. break;
  46. };
  47. a[j] = v;
  48. }
  49. }
  50. template <class T> inline void Quick_Sort (T* a, int l, int r)
  51. {
  52. if (r-l <= 16)
  53. {
  54. Insertion_Sort(a+l,r-l+1);
  55. return;
  56. }
  57. T v = a[r];
  58. int i = l-1;
  59. int j = r;
  60. do
  61. {
  62. do { i++; } while (i < r && a[i] < v);
  63. do { j--; } while (j > 0 && a[j] > v);
  64. swap(a[i],a[j]);
  65. } while (j > i);
  66. T t = a[j];
  67. a[j] = a[i];
  68. a[i] = a[r];
  69. a[r] = t;
  70. if ((i-1) > l)
  71. Quick_Sort (a,l,i-1);
  72. if (r > (i+1))
  73. Quick_Sort (a,i+1,r);
  74. }
  75. template <class T> inline void Quick_Sort (T* a, int N)
  76. {
  77. Quick_Sort(a,0,N-1);
  78. }
  79. //------------------------------------------------------------------------
  80. // Implementation
  81. //------------------------------------------------------------------------
  82. /*****************************************************************************
  83. *
  84. * Function: StripOptimizerClass::getStripIndexCount()
  85. *
  86. * Description: Returns number of indices in a set of strips
  87. *
  88. * Parameters:
  89. *
  90. *****************************************************************************/
  91. int StripOptimizerClass::Get_Strip_Index_Count (const int* strips, int strip_count)
  92. {
  93. int cnt = 0;
  94. for (int i = 0; i < strip_count; i++)
  95. {
  96. int len = *strips++; // read len
  97. cnt += len;
  98. strips += len; // skip data
  99. }
  100. return cnt;
  101. }
  102. /*****************************************************************************
  103. *
  104. * Function: StripOptimizerClass::optimizeStripOrder()
  105. *
  106. * Description:
  107. *
  108. * Parameters:
  109. *
  110. *****************************************************************************/
  111. // compares two strips and returns number of shared indices
  112. static inline int Get_Strip_Similarity (const int* A, const int* B)
  113. {
  114. int cnt = 0;
  115. int lenA = *A++;
  116. int lenB = *B++;
  117. for (int i = 0; i < lenA; i++)
  118. {
  119. int index = A[i]; // index of A
  120. for (int j = 0; j < lenB; j++)
  121. if (B[j] == index) // match
  122. {
  123. cnt++;
  124. break;
  125. }
  126. }
  127. return cnt;
  128. }
  129. // copies a strip, returns new destination pointer
  130. static inline int* Copy_Strip (int* d, const int* s)
  131. {
  132. int len = *s++;
  133. *d++ = len;
  134. for (int i = 0; i < len; i++)
  135. *d++ = *s++;
  136. return d;
  137. }
  138. void StripOptimizerClass::Optimize_Strip_Order (int* strips, int strip_count)
  139. {
  140. if (strip_count <= 0)
  141. return;
  142. // WWASSERT(strips);
  143. int** ss = new int*[strip_count]; // pointers to beginning of strips
  144. int* s = strips;
  145. for (int i = 0; i < strip_count; i++)
  146. {
  147. ss[i] = s;
  148. int len = *s++; // read len
  149. s+=len; // skip
  150. }
  151. int outSize = Get_Strip_Index_Count(strips, strip_count)+strip_count; // output memory alloc size
  152. int* out = new int[outSize];
  153. int* o = out; // output pointer
  154. const int* prev = ss[0]; // previous strip
  155. o = Copy_Strip (o, ss[0]); // output first strip
  156. ss[0] = 0;
  157. for (;;)
  158. {
  159. int bestIndex = -1;
  160. int bestSimilarity = -1;
  161. for (int j = 0; j < strip_count; j++)
  162. if (ss[j])
  163. {
  164. int sim = Get_Strip_Similarity (prev, ss[j]); // get similarity
  165. if (sim > bestSimilarity)
  166. {
  167. bestSimilarity = sim;
  168. bestIndex = j;
  169. }
  170. }
  171. if (bestIndex==-1) // we're done
  172. break;
  173. o = Copy_Strip(o, ss[bestIndex]); // copy the strip
  174. prev = ss[bestIndex]; // set to prev
  175. ss[bestIndex] = NULL; // mark as selected
  176. }
  177. // WWASSERT((out+outSize)==o); // HUH?
  178. for (i = 0; i < outSize; i++) // copy output
  179. strips[i] = out[i];
  180. delete[] out;
  181. delete[] ss;
  182. }
  183. /*****************************************************************************
  184. *
  185. * Function: StripOptimizerClass::optimizeTriangleOrder()
  186. *
  187. * Description:
  188. *
  189. * Parameters:
  190. *
  191. *****************************************************************************/
  192. struct Tri
  193. {
  194. public:
  195. int a,b,c;
  196. bool operator< (const Tri& s) const { return a < s.a; }
  197. bool operator> (const Tri& s) const { return a > s.a; }
  198. };
  199. static inline int Get_Similarity (const Tri& A, const Tri& B)
  200. {
  201. int sim = 0;
  202. if (A.a == B.a || A.a == B.b || A.a == B.c) sim++;
  203. if (A.b == B.a || A.b == B.b || A.b == B.c) sim++;
  204. if (A.c == B.a || A.c == B.b || A.c == B.c) sim++;
  205. return sim;
  206. }
  207. void StripOptimizerClass::Optimize_Triangle_Order (int *tris, int triangle_count)
  208. {
  209. if (triangle_count<=0)
  210. return;
  211. WWASSERT(tris);
  212. Tri** t = new Tri*[triangle_count];
  213. for (int i = 0; i < triangle_count; i++)
  214. {
  215. t[i] = (Tri*)(tris + i*3);
  216. }
  217. Tri* out = new Tri[triangle_count];
  218. Tri* o = out;
  219. Tri* prev = t[0];
  220. *o++ = *prev;
  221. t[0] = NULL;
  222. for (;;)
  223. {
  224. // match best
  225. int bestIndex = -1;
  226. int bestSim = -1;
  227. for (int j = 0; j < triangle_count; j++)
  228. if (t[j])
  229. {
  230. int sim = Get_Similarity (*prev, *t[j]);
  231. if (sim > bestSim)
  232. {
  233. bestSim = sim;
  234. bestIndex = j;
  235. if (sim >= 2) // that's the best we could get
  236. break;
  237. }
  238. }
  239. if (bestIndex == -1) // we're done
  240. break;
  241. *o++ = *t[bestIndex];
  242. prev = t[bestIndex];
  243. t[bestIndex] = NULL;
  244. }
  245. WWASSERT(o == (out+triangle_count));
  246. for (i = 0; i < triangle_count; i++)
  247. {
  248. Tri* d = (Tri*)(tris)+i;
  249. *d = out[i];
  250. }
  251. delete[] t;
  252. delete[] out;
  253. }
  254. /*****************************************************************************
  255. *
  256. * Function: StripOptimizerClass::combineStrips()
  257. *
  258. * Description: Combines a number of strips into one
  259. *
  260. * Parameters:
  261. *
  262. *****************************************************************************/
  263. int* StripOptimizerClass::Combine_Strips (const int* strips, int strip_count)
  264. {
  265. int check = Get_Strip_Index_Count(strips,strip_count) + (strip_count-1)*3;
  266. int* out = new int[check+1];
  267. int* o = out + 1;
  268. int* tmp = new int[check]; // DEBUG DEBUG
  269. bool prevEven = true;
  270. for (int i = 0; i < strip_count; i++)
  271. {
  272. int len = *strips++;
  273. if (i != 0)
  274. {
  275. *o++ = *strips; // duplicate first
  276. if (!prevEven)
  277. *o++ = *strips;
  278. }
  279. for (int j = 0; j < len; j++)
  280. *o++ = *strips++; // copy the strip
  281. if (i != (strip_count-1))
  282. *o++ = o[-1];
  283. prevEven = (!(len&1));
  284. }
  285. delete[] tmp;
  286. // WWASSERT(check == (o-out-1));
  287. *out = (o-out-1); // set length
  288. return out;
  289. }
  290. //------------------------------------------------------------------------
  291. // New striping code
  292. //------------------------------------------------------------------------
  293. namespace Strip
  294. {
  295. /*****************************************************************************
  296. *
  297. * Struct: Vector3i
  298. *
  299. * Description: Internal class for representing an edge
  300. *
  301. *****************************************************************************/
  302. struct Vector3i
  303. {
  304. int v[3];
  305. Vector3i () {}
  306. Vector3i (int a, int b, int c) { v[0]=a; v[1]=b; v[2]=c; }
  307. int& operator[](int i) { return v[i]; }
  308. const int& operator[](int i) const { return v[i]; }
  309. };
  310. /*****************************************************************************
  311. *
  312. * Struct: Edge
  313. *
  314. * Description: Internal class for representing an edge
  315. *
  316. *****************************************************************************/
  317. struct Edge
  318. {
  319. Edge (void) {}
  320. Edge (int v0, int v1) { v[0] = v0; v[1] = v1; }
  321. bool operator== (const Edge& s) const { return v[0]==s.v[0] && v[1] == s.v[1]; }
  322. void sort (void) { if (v[0]>v[1]) swap(v[0],v[1]); }
  323. int v[2]; // edge
  324. };
  325. /*****************************************************************************
  326. *
  327. * Struct: Triangle
  328. *
  329. * Description: Internal class for representing a triangle and
  330. * associated connectivity information
  331. *
  332. *****************************************************************************/
  333. struct Triangle
  334. {
  335. Triangle (void)
  336. {
  337. m_neighbors[0] = 0;
  338. m_neighbors[1] = 0;
  339. m_neighbors[2] = 0;
  340. m_vertices[0] = 0;
  341. m_vertices[1] = 0;
  342. m_vertices[2] = 0;
  343. m_prev = 0;
  344. m_next = 0;
  345. m_bin = -1;
  346. }
  347. Triangle* m_neighbors[3]; // pointers to neighbors of the triangle
  348. Vector3i m_vertices; // vertices of the triangle
  349. Triangle* m_prev; // previous triangle in same bin
  350. Triangle* m_next; // next triangle in same bin
  351. int m_bin; // current bin (-1 == not in any bin)
  352. int getConnectivity (void) const { int cnt = 0; if (m_neighbors[0]) cnt++; if (m_neighbors[1]) cnt++; if (m_neighbors[2]) cnt++; return cnt;}
  353. const Edge getEdge (int i) const { WWASSERT(i>=0 && i<3); return Edge(m_vertices[i],i==2?m_vertices[0]:m_vertices[i+1]); }
  354. };
  355. /*****************************************************************************
  356. *
  357. * Class: TriangleQueue
  358. *
  359. * Description: Internal class for maintaining triangles sorted by
  360. * connectivity
  361. *
  362. *****************************************************************************/
  363. class TriangleQueue
  364. {
  365. public:
  366. TriangleQueue (Triangle* tris, int N);
  367. ~TriangleQueue (void);
  368. void removeTriangle (Triangle* t);
  369. Triangle* getTop (void) const;
  370. int getVertexConnectivity (int i) const;
  371. private:
  372. TriangleQueue (const TriangleQueue&);
  373. TriangleQueue& operator= (const TriangleQueue&);
  374. void reinsert (Triangle* t);
  375. Triangle* m_bin[4]; // bins (0 = triangles with zero neighbors, etc.)
  376. int* m_nodeConnectivity; // node connectivity count
  377. int m_vertexCount;
  378. };
  379. /*****************************************************************************
  380. *
  381. * Class: Stripify
  382. *
  383. * Description: Class for performing stripification
  384. *
  385. *****************************************************************************/
  386. class Stripify
  387. {
  388. public:
  389. static int* stripify (const Vector3i* tris, int N);
  390. private:
  391. Stripify (void); // not permitted
  392. Stripify (const Stripify&);
  393. Stripify& operator= (const Stripify&);
  394. static Triangle* generateTriangleList (const Vector3i* tris, int N);
  395. static Vector3i getTriangleNodeConnectivityWeights (const TriangleQueue& queue, const Triangle& tri);
  396. static int getMod3 (int i) { WWASSERT(i>=0 && i<6); return s_mod[i]; }
  397. static int s_mod[6]; // small lookup table for mod3 operation (see getMod3())
  398. };
  399. int Stripify::s_mod[6] = {0,1,2,0,1,2};
  400. } // Strip
  401. template <> inline unsigned int HashTemplateKeyClass<Strip::Edge>::Get_Hash_Value(const Strip::Edge& s)
  402. {
  403. return (s.v[0]*139) + (s.v[1]*7);
  404. }
  405. namespace Strip
  406. {
  407. /*****************************************************************************
  408. *
  409. * Function: TriangleQueue::getTop()
  410. *
  411. * Description: Returns pointer to triangle with smallest connectivity
  412. *
  413. * Returns: pointer to triangle with smallest connectivity or NULL
  414. * if the queue is empty
  415. *
  416. *****************************************************************************/
  417. inline Triangle* TriangleQueue::getTop (void) const
  418. {
  419. for (int i = 0; i < 4; i++)
  420. if (m_bin[i])
  421. return m_bin[i]; // return head
  422. return 0; // end
  423. }
  424. /*****************************************************************************
  425. *
  426. * Function: TriangleQueue::getVertexConnectivity()
  427. *
  428. * Description: Returns current connectivity count of specified vertex
  429. *
  430. * Parameters: i = vertex index
  431. *
  432. * Returns: connectivity count
  433. *
  434. *****************************************************************************/
  435. inline int TriangleQueue::getVertexConnectivity (int i) const
  436. {
  437. WWASSERT(i>=0 && i< m_vertexCount);
  438. return m_nodeConnectivity[i];
  439. }
  440. /*****************************************************************************
  441. *
  442. * Function: TriangleQueue::~TriangleQueue()
  443. *
  444. * Description: Destructor
  445. *
  446. *****************************************************************************/
  447. inline TriangleQueue::~TriangleQueue ()
  448. {
  449. delete[] m_nodeConnectivity;
  450. }
  451. /*****************************************************************************
  452. *
  453. * Function: TriangleQueue::reinsert()
  454. *
  455. * Description: Internal function for recalculating a triangle's
  456. * connectivity
  457. *
  458. * Parameters: t = pointer to triangle (non-NULL)
  459. *
  460. *****************************************************************************/
  461. inline void TriangleQueue::reinsert (Triangle* t)
  462. {
  463. WWASSERT (t && t->m_bin!=-1); // must be in some bin
  464. int w = t->getConnectivity();
  465. // remove from bin
  466. if (t->m_prev)
  467. t->m_prev->m_next = t->m_next;
  468. else
  469. {
  470. WWASSERT(t->m_bin != -1);
  471. WWASSERT(t == m_bin[t->m_bin]); // must be head
  472. m_bin[t->m_bin] = t->m_next; // new head
  473. }
  474. if (t->m_next)
  475. t->m_next->m_prev = t->m_prev;
  476. t->m_prev = 0;
  477. t->m_next = m_bin[w];
  478. if (t->m_next)
  479. t->m_next->m_prev = t;
  480. m_bin[w] = t; // head of bin
  481. t->m_bin = w; // set bin
  482. }
  483. /*****************************************************************************
  484. *
  485. * Function: TriangleQueue::removeTriangle()
  486. *
  487. * Description: Removes a triangle from the queue
  488. *
  489. * Parameters: t = pointer to triangle (non-NULL)
  490. *
  491. *****************************************************************************/
  492. inline void TriangleQueue::removeTriangle (Triangle* t)
  493. {
  494. WWASSERT(t);
  495. if (t->m_prev)
  496. t->m_prev->m_next = t->m_next;
  497. else
  498. {
  499. WWASSERT(t->m_bin != -1);
  500. WWASSERT(t == m_bin[t->m_bin]); // must be head
  501. m_bin[t->m_bin] = t->m_next; // new head
  502. }
  503. if (t->m_next)
  504. t->m_next->m_prev = t->m_prev;
  505. t->m_bin = -1;
  506. // update connectivity of t's neighbors
  507. Triangle* update[3];
  508. int i;
  509. for (i = 0; i < 3; i++)
  510. {
  511. update[i] = 0;
  512. if (t->m_neighbors[i])
  513. {
  514. Triangle* n = t->m_neighbors[i];
  515. int k=0;
  516. for (k = 0; k < 3; k++)
  517. if (n->m_neighbors[k]==t)
  518. break;
  519. WWASSERT (k!=3); // WASS??
  520. n->m_neighbors[k] = 0; // reduce connection
  521. t->m_neighbors[i] = 0;
  522. update[i] = n;
  523. }
  524. }
  525. // update connectivity count of t's vertices
  526. for (i = 0; i < 3; i++)
  527. {
  528. m_nodeConnectivity[t->m_vertices[i]]--;
  529. WWASSERT(m_nodeConnectivity[t->m_vertices[i]] >= 0); // WASS?
  530. }
  531. for (i = 0; i < 3; i++) // perform reinsertions now...
  532. if (update[i])
  533. reinsert(update[i]);
  534. }
  535. /*****************************************************************************
  536. *
  537. * Function: TriangleQueue::TriangleQueue()
  538. *
  539. * Description: Constructor
  540. *
  541. * Parameters: tris = array of triangles
  542. * N = number of triangles in the array
  543. *
  544. *****************************************************************************/
  545. inline TriangleQueue::TriangleQueue (Triangle* tris, int N)
  546. {
  547. int i;
  548. for (i = 0; i < 4; i++)
  549. m_bin[i] = 0; // initialize to zero
  550. int largestIndex = 0;
  551. for (i = 0; i < N; i++)
  552. for (int j = 0; j < 3; j++)
  553. {
  554. WWASSERT(tris[i].m_vertices[j]>=0);
  555. if (tris[i].m_vertices[j] > largestIndex)
  556. largestIndex = tris[i].m_vertices[j];
  557. }
  558. m_vertexCount = largestIndex+1;
  559. m_nodeConnectivity = new int[m_vertexCount]; //
  560. for (i = 0; i < m_vertexCount; i++)
  561. m_nodeConnectivity[i] = 0;
  562. for (i = 0; i < N; i++)
  563. {
  564. Triangle* t = tris+i;
  565. int w = t->getConnectivity();
  566. WWASSERT(w>=0 && w <=3);
  567. WWASSERT(!t->m_prev && !t->m_next && t->m_bin==-1); // must not be in a bin
  568. t->m_prev = 0;
  569. t->m_next = m_bin[w];
  570. if (t->m_next)
  571. t->m_next->m_prev = t;
  572. m_bin[w] = t; // head of bin
  573. t->m_bin = w; // set bin
  574. for (int j = 0; j < 3; j++)
  575. m_nodeConnectivity[t->m_vertices[j]]++;
  576. }
  577. }
  578. /*****************************************************************************
  579. *
  580. * Function: Stripify::getTriangleConnectivityWeights()
  581. *
  582. * Description: Returns "node connectivity" weights for each triangle vertex
  583. *
  584. * Parameters: queue = reference to triangle queue
  585. * tri = reference to triangle
  586. *
  587. * Returns: Vector structure containing three weights
  588. *
  589. *****************************************************************************/
  590. inline Vector3i Stripify::getTriangleNodeConnectivityWeights (const TriangleQueue& queue, const Triangle& tri)
  591. {
  592. int weight[3];
  593. for (int i = 0; i < 3; i++)
  594. {
  595. weight[i] = queue.getVertexConnectivity(tri.m_vertices[i]);
  596. }
  597. int highestVal = weight[0];
  598. if (weight[1] > highestVal) highestVal = weight[1];
  599. if (weight[2] > highestVal) highestVal = weight[2];
  600. Vector3i v(-1,-1,-1);
  601. for (i = 0; i < 3; i++) {
  602. if (weight[0] == highestVal) v[i] = +1;
  603. }
  604. return v;
  605. }
  606. /*****************************************************************************
  607. *
  608. * Function: Stripify::generateTriangleList()
  609. *
  610. * Description: Converts input triangles into internal Triangle structure
  611. *
  612. * Parameters: inTris = input triangles
  613. * N = number of input triangles
  614. *
  615. * Returns: pointer to Triangle array
  616. *
  617. * Notes: The function sets up the initial connectivity information
  618. *
  619. *****************************************************************************/
  620. Triangle* Stripify::generateTriangleList (const Vector3i* inTris, int N)
  621. {
  622. WWASSERT (inTris && N>=0);
  623. Triangle* tris = new Triangle[N]; // allocate triangles
  624. int i;
  625. //--------------------------------------------------------------------
  626. // Copy triangle vertex data
  627. //--------------------------------------------------------------------
  628. for (i = 0; i < N; i++)
  629. {
  630. //--------------------------------------------------------------------
  631. // We could perform random rotation here (this way we don't need random
  632. // comparisons later in the algo in equality cases).
  633. //--------------------------------------------------------------------
  634. tris[i].m_vertices[0] = inTris[i][0];
  635. tris[i].m_vertices[1] = inTris[i][1];
  636. tris[i].m_vertices[2] = inTris[i][2];
  637. }
  638. //--------------------------------------------------------------------
  639. // Build connectivity information using a hash table
  640. //--------------------------------------------------------------------
  641. HashTemplateClass<Edge,Triangle*> hash;
  642. Triangle* t = tris;
  643. for (i = 0; i < N; i++, t++)
  644. {
  645. for (int j = 0; j < 3; j++)
  646. if (!t->m_neighbors[j]) // if neighbor not defined yet
  647. {
  648. Edge edge = tris[i].getEdge(j);
  649. Edge e = edge;
  650. e.sort(); // sort vertices (smaller first)
  651. Triangle* n = hash.Get(e);
  652. if (n) // if edge is already in the hash...
  653. {
  654. int k=0;
  655. for (k = 0; k < 3; k++) // find matching edge
  656. if (!n->m_neighbors[k]) // this neighbor not located yet
  657. {
  658. Edge ek = n->getEdge(k); // get edge
  659. if (ek.v[0] == edge.v[1] && ek.v[1] == edge.v[0]) // if matching edge (note that order must be different)
  660. break; // .. we found the edge
  661. }
  662. if (k < 3) // (k==3) -> no match
  663. {
  664. t->m_neighbors[j] = n; // set neighbor
  665. n->m_neighbors[k] = t; // set neighbor
  666. hash.Remove(e); // remove from hash (this speeds up the hash queries considerably)
  667. }
  668. } else
  669. hash.Insert(e, t); // insert triangle into hash
  670. }
  671. }
  672. return tris; // return pointer to output data
  673. }
  674. /*****************************************************************************
  675. *
  676. * Function: Stripify::stripify()
  677. *
  678. * Description: Builds a set of triangle strips out of a triangle array
  679. *
  680. * Parameters: inTris = input triangles (three vertices per triangle)
  681. * N = number of input triangles
  682. *
  683. * Returns: pointer to strip data array
  684. *
  685. * Notes: The strip data array layout is as follows:
  686. *
  687. * [int] number of strips
  688. * [int] length of first strip (in vertices)
  689. * [int,..] vertex indices of the first strip
  690. * [int] length of second strip
  691. * ...
  692. *
  693. * The routine assumes that degenerate triangles have been
  694. * remove and input vertices have been welded
  695. *
  696. *****************************************************************************/
  697. int* Stripify::stripify (const Vector3i* inTris, int N)
  698. {
  699. if (!inTris || N<=0) // boo!
  700. return 0;
  701. //--------------------------------------------------------------------
  702. // Initial setup
  703. //--------------------------------------------------------------------
  704. Triangle* tris = generateTriangleList(inTris,N); // build connectivity info
  705. int* out = new int[N*5]; // absolute worst case situation
  706. int* o = out; // internal ptr (save entry[0] for later use)
  707. int strip_count = 0; // number of output strips
  708. TriangleQueue queue (tris, N); // insert triangles into priority queue
  709. int nSwaps = 0;
  710. int nLen = 0;
  711. //--------------------------------------------------------------------
  712. // Main loop. Always select triangle with smallest weight.
  713. //--------------------------------------------------------------------
  714. for (;;)
  715. {
  716. Triangle* t = queue.getTop(); // get triangle with smallest weight
  717. if (!t) // ok, we ran out of triangles (we're done)
  718. break;
  719. //--------------------------------------------------------------------
  720. // Choose initial direction by selecting neighbor with smallest
  721. // weight
  722. //--------------------------------------------------------------------
  723. int* pLen = o; // get current pointer (as we need to take care of it later)
  724. int len = 3; // initial length
  725. int best = 0; // best edge
  726. int bestWeight = 0x7fffffff; // initialize to maximum width
  727. Vector3i nodeWeights = getTriangleNodeConnectivityWeights(queue, *t);
  728. for (int i = 0; i < 3; i++)
  729. if (t->m_neighbors[i]) // if triangle has a neighbor in this direction
  730. {
  731. int weight = t->m_neighbors[i]->getConnectivity(); // get connectivity of neighbor
  732. weight += nodeWeights[i]; // add node weights
  733. weight += nodeWeights[getMod3(i+1)];
  734. // DEBUG DEBUG ADD SWAP COST HERE?
  735. if (weight <= bestWeight)
  736. {
  737. bestWeight = weight;
  738. best = i;
  739. }
  740. }
  741. *o++ = len; // output the first three vertices
  742. *o++ = t->m_vertices[getMod3(best+2)];
  743. *o++ = t->m_vertices[getMod3(best+0)];
  744. *o++ = t->m_vertices[getMod3(best+1)];
  745. for (;;)
  746. {
  747. Triangle* next = 0; // find next triangle
  748. int i;
  749. for (i = 0; i < 3; i++)
  750. if (t->m_neighbors[i])
  751. {
  752. Triangle* n = t->m_neighbors[i];
  753. for (int j = 0; j < 3; j++)
  754. {
  755. Edge e = n->getEdge(j);
  756. if (!(len&1))
  757. swap(e.v[0],e.v[1]); // swap
  758. if (e.v[0] == o[-1] && e.v[1] == o[-2])
  759. {
  760. next = n;
  761. break;
  762. }
  763. }
  764. }
  765. queue.removeTriangle(t); // get rid of the old triangle
  766. if (!next) // we're done
  767. break;
  768. //--------------------------------------------------------------------
  769. // Find out where we want to continue...
  770. //--------------------------------------------------------------------
  771. int bestEdge = -1;
  772. int bestWeight = 0x7fffffff;
  773. bool bestSwap = false;
  774. Vector3i nodeWeights = getTriangleNodeConnectivityWeights(queue, *next);
  775. for (i = 0; i < 3; i++)
  776. if (next->m_neighbors[i]) // is there a neighbor?
  777. {
  778. Edge e = next->getEdge(i); // a swap happens if it contains the prevprev
  779. bool swap = (e.v[0] == o[-2] || e.v[1] == o[-2]);
  780. Triangle* n = next->m_neighbors[i]; // get pointer to neighbor
  781. int w = n->getConnectivity();
  782. w += nodeWeights[i]; // add vertex weight
  783. w += nodeWeights[getMod3(i+1)]; // add vertex weight
  784. w += (swap) ? 1 : -1; // add swap penalty
  785. if (w <= bestWeight)
  786. {
  787. bestWeight = w;
  788. bestEdge = i;
  789. bestSwap = swap;
  790. }
  791. }
  792. if (bestEdge != -1 && bestSwap) // if we're going to continue...
  793. {
  794. *o = o[-2]; // introduce swap vertex
  795. o++;
  796. len++; // adjust length
  797. nSwaps++; // update statistics
  798. }
  799. //--------------------------------------------------------------------
  800. // Find out which was the new vertex (store it to vIndex)
  801. //--------------------------------------------------------------------
  802. int vIndex = 0;
  803. if (next->m_vertices[1] != o[-1] && next->m_vertices[1] != o[-2]) vIndex = 1; else
  804. if (next->m_vertices[2] != o[-1] && next->m_vertices[2] != o[-2]) vIndex = 2; else
  805. WWASSERT (next->m_vertices[0] != o[-1] && next->m_vertices[0] != o[-2]);
  806. //--------------------------------------------------------------------
  807. // Output the vertex and move to next triangle
  808. //--------------------------------------------------------------------
  809. *o++ = next->m_vertices[vIndex]; // output the vertex
  810. len++; // increase strip length
  811. t = next; // move to next triangle
  812. }
  813. *pLen = len; // patch final length
  814. strip_count++; // increase strip count
  815. nLen += len;
  816. // printf ("strip len = %d\n",len);
  817. }
  818. //--------------------------------------------------------------------
  819. // Allocate new optimal-size array and copy output there. Then release
  820. // all temporary memory allocations.
  821. //--------------------------------------------------------------------
  822. // printf ("total indices = %d\n",nLen);
  823. // printf ("total swaps = %d\n",nSwaps);
  824. int len = o-out; // allocation length
  825. int* rOut = new int[len+1];
  826. *rOut = strip_count; // first entry is number of strips
  827. for (int i = 0; i < len; i++)
  828. {
  829. WWASSERT(out[i] >= 0); // would be nice to test for len as well
  830. rOut[i+1] = out[i];
  831. }
  832. delete[] out; // delete internal output
  833. delete[] tris; // delete internal triangle list
  834. return rOut;
  835. }
  836. } // Strip
  837. int* StripOptimizerClass::Stripify(const int* tris, int N)
  838. {
  839. return Strip::Stripify::stripify((const Strip::Vector3i*)tris,N);
  840. }
  841. //------------------------------------------------------------------------