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