| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "stripoptimizer.h"
- #include "hashtemplate.h"
- #include "wwdebug.h"
- template <class T> inline void swap (T& a, T& b)
- {
- T t(a);
- a = b;
- b = t;
- }
- //------------------------------------------------------------------------
- // Prototypes for sort functions. Note that class T must have
- // operators =, > and < in order for the functions to compile.
- //------------------------------------------------------------------------
- template <class T> inline void Insertion_Sort (T* a, int N);
- template <class T> inline void Quick_Sort (T* a, int N);
- template <class T> inline void Insertion_Sort (T* a, int N)
- {
- for (int i = 1; i < N; i++)
- if (a[i-1] > a[i])
- {
- T v = a[i];
- int j = i;
- while (a[j-1]> v)
- {
- a[j] = a[j-1]; // copy data
- j--;
- if (!j)
- break;
- };
- a[j] = v;
- }
- }
- template <class T> inline void Quick_Sort (T* a, int l, int r)
- {
- if (r-l <= 16)
- {
- Insertion_Sort(a+l,r-l+1);
- return;
- }
- T v = a[r];
- int i = l-1;
- int j = r;
- do
- {
- do { i++; } while (i < r && a[i] < v);
- do { j--; } while (j > 0 && a[j] > v);
- swap(a[i],a[j]);
- } while (j > i);
-
- T t = a[j];
- a[j] = a[i];
- a[i] = a[r];
- a[r] = t;
- if ((i-1) > l)
- Quick_Sort (a,l,i-1);
- if (r > (i+1))
- Quick_Sort (a,i+1,r);
- }
- template <class T> inline void Quick_Sort (T* a, int N)
- {
- Quick_Sort(a,0,N-1);
- }
- //------------------------------------------------------------------------
- // Implementation
- //------------------------------------------------------------------------
- /*****************************************************************************
- *
- * Function: StripOptimizerClass::getStripIndexCount()
- *
- * Description: Returns number of indices in a set of strips
- *
- * Parameters:
- *
- *****************************************************************************/
- int StripOptimizerClass::Get_Strip_Index_Count (const int* strips, int strip_count)
- {
- int cnt = 0;
- for (int i = 0; i < strip_count; i++)
- {
- int len = *strips++; // read len
- cnt += len;
- strips += len; // skip data
- }
- return cnt;
- }
- /*****************************************************************************
- *
- * Function: StripOptimizerClass::optimizeStripOrder()
- *
- * Description:
- *
- * Parameters:
- *
- *****************************************************************************/
- // compares two strips and returns number of shared indices
- static inline int Get_Strip_Similarity (const int* A, const int* B)
- {
- int cnt = 0;
- int lenA = *A++;
- int lenB = *B++;
- for (int i = 0; i < lenA; i++)
- {
- int index = A[i]; // index of A
- for (int j = 0; j < lenB; j++)
- if (B[j] == index) // match
- {
- cnt++;
- break;
- }
- }
- return cnt;
- }
- // copies a strip, returns new destination pointer
- static inline int* Copy_Strip (int* d, const int* s)
- {
- int len = *s++;
- *d++ = len;
- for (int i = 0; i < len; i++)
- *d++ = *s++;
- return d;
- }
- void StripOptimizerClass::Optimize_Strip_Order (int* strips, int strip_count)
- {
- if (strip_count <= 0)
- return;
- // WWASSERT(strips);
-
- int** ss = W3DNEWARRAY int*[strip_count]; // pointers to beginning of strips
- int* s = strips;
- for (int i = 0; i < strip_count; i++)
- {
- ss[i] = s;
- int len = *s++; // read len
- s+=len; // skip
- }
- int outSize = Get_Strip_Index_Count(strips, strip_count)+strip_count; // output memory alloc size
- int* out = W3DNEWARRAY int[outSize];
- int* o = out; // output pointer
- const int* prev = ss[0]; // previous strip
- o = Copy_Strip (o, ss[0]); // output first strip
- ss[0] = 0;
- for (;;)
- {
- int bestIndex = -1;
- int bestSimilarity = -1;
- for (int j = 0; j < strip_count; j++)
- if (ss[j])
- {
- int sim = Get_Strip_Similarity (prev, ss[j]); // get similarity
- if (sim > bestSimilarity)
- {
- bestSimilarity = sim;
- bestIndex = j;
- }
- }
- if (bestIndex==-1) // we're done
- break;
- o = Copy_Strip(o, ss[bestIndex]); // copy the strip
- prev = ss[bestIndex]; // set to prev
- ss[bestIndex] = NULL; // mark as selected
- }
- // WWASSERT((out+outSize)==o); // HUH?
- for (i = 0; i < outSize; i++) // copy output
- strips[i] = out[i];
- delete[] out;
- delete[] ss;
- }
- /*****************************************************************************
- *
- * Function: StripOptimizerClass::optimizeTriangleOrder()
- *
- * Description:
- *
- * Parameters:
- *
- *****************************************************************************/
- struct Tri
- {
- public:
- int a,b,c;
- bool operator< (const Tri& s) const { return a < s.a; }
- bool operator> (const Tri& s) const { return a > s.a; }
- };
- static inline int Get_Similarity (const Tri& A, const Tri& B)
- {
- int sim = 0;
- if (A.a == B.a || A.a == B.b || A.a == B.c) sim++;
- if (A.b == B.a || A.b == B.b || A.b == B.c) sim++;
- if (A.c == B.a || A.c == B.b || A.c == B.c) sim++;
- return sim;
- }
- void StripOptimizerClass::Optimize_Triangle_Order (int *tris, int triangle_count)
- {
- if (triangle_count<=0)
- return;
- WWASSERT(tris);
- Tri** t = W3DNEWARRAY Tri*[triangle_count];
- for (int i = 0; i < triangle_count; i++)
- {
- t[i] = (Tri*)(tris + i*3);
- }
- Tri* out = W3DNEWARRAY Tri[triangle_count];
- Tri* o = out;
- Tri* prev = t[0];
- *o++ = *prev;
- t[0] = NULL;
- for (;;)
- {
- // match best
- int bestIndex = -1;
- int bestSim = -1;
- for (int j = 0; j < triangle_count; j++)
- if (t[j])
- {
- int sim = Get_Similarity (*prev, *t[j]);
- if (sim > bestSim)
- {
- bestSim = sim;
- bestIndex = j;
- if (sim >= 2) // that's the best we could get
- break;
- }
- }
- if (bestIndex == -1) // we're done
- break;
- *o++ = *t[bestIndex];
- prev = t[bestIndex];
- t[bestIndex] = NULL;
- }
- WWASSERT(o == (out+triangle_count));
- for (i = 0; i < triangle_count; i++)
- {
- Tri* d = (Tri*)(tris)+i;
- *d = out[i];
- }
- delete[] t;
- delete[] out;
- }
- /*****************************************************************************
- *
- * Function: StripOptimizerClass::combineStrips()
- *
- * Description: Combines a number of strips into one
- *
- * Parameters:
- *
- *****************************************************************************/
- int* StripOptimizerClass::Combine_Strips (const int* strips, int strip_count)
- {
- int check = Get_Strip_Index_Count(strips,strip_count) + (strip_count-1)*3;
- int* out = W3DNEWARRAY int[check+1];
- int* o = out + 1;
- int* tmp = W3DNEWARRAY int[check]; // DEBUG DEBUG
- bool prevEven = true;
- for (int i = 0; i < strip_count; i++)
- {
- int len = *strips++;
- if (i != 0)
- {
- *o++ = *strips; // duplicate first
-
- if (!prevEven)
- *o++ = *strips;
- }
- for (int j = 0; j < len; j++)
- *o++ = *strips++; // copy the strip
- if (i != (strip_count-1))
- *o++ = o[-1];
- prevEven = (!(len&1));
- }
- delete[] tmp;
- // WWASSERT(check == (o-out-1));
- *out = (o-out-1); // set length
- return out;
- }
- //------------------------------------------------------------------------
- // New striping code
- //------------------------------------------------------------------------
- namespace Strip
- {
- /*****************************************************************************
- *
- * Struct: Vector3i
- *
- * Description: Internal class for representing an edge
- *
- *****************************************************************************/
- struct Vector3i
- {
- int v[3];
- Vector3i () {}
- Vector3i (int a, int b, int c) { v[0]=a; v[1]=b; v[2]=c; }
- int& operator[](int i) { return v[i]; }
- const int& operator[](int i) const { return v[i]; }
- };
- /*****************************************************************************
- *
- * Struct: Edge
- *
- * Description: Internal class for representing an edge
- *
- *****************************************************************************/
- struct Edge
- {
- Edge (void) {}
- Edge (int v0, int v1) { v[0] = v0; v[1] = v1; }
- bool operator== (const Edge& s) const { return v[0]==s.v[0] && v[1] == s.v[1]; }
- void sort (void) { if (v[0]>v[1]) swap(v[0],v[1]); }
- int v[2]; // edge
- };
- /*****************************************************************************
- *
- * Struct: Triangle
- *
- * Description: Internal class for representing a triangle and
- * associated connectivity information
- *
- *****************************************************************************/
- struct Triangle
- {
- Triangle (void)
- {
- m_neighbors[0] = 0;
- m_neighbors[1] = 0;
- m_neighbors[2] = 0;
- m_vertices[0] = 0;
- m_vertices[1] = 0;
- m_vertices[2] = 0;
- m_prev = 0;
- m_next = 0;
- m_bin = -1;
- }
- Triangle* m_neighbors[3]; // pointers to neighbors of the triangle
- Vector3i m_vertices; // vertices of the triangle
- Triangle* m_prev; // previous triangle in same bin
- Triangle* m_next; // next triangle in same bin
- int m_bin; // current bin (-1 == not in any bin)
- int getConnectivity (void) const { int cnt = 0; if (m_neighbors[0]) cnt++; if (m_neighbors[1]) cnt++; if (m_neighbors[2]) cnt++; return cnt;}
- 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]); }
- };
- /*****************************************************************************
- *
- * Class: TriangleQueue
- *
- * Description: Internal class for maintaining triangles sorted by
- * connectivity
- *
- *****************************************************************************/
- class TriangleQueue
- {
- public:
- TriangleQueue (Triangle* tris, int N);
- ~TriangleQueue (void);
- void removeTriangle (Triangle* t);
- Triangle* getTop (void) const;
- int getVertexConnectivity (int i) const;
- private:
- TriangleQueue (const TriangleQueue&);
- TriangleQueue& operator= (const TriangleQueue&);
- void reinsert (Triangle* t);
- Triangle* m_bin[4]; // bins (0 = triangles with zero neighbors, etc.)
- int* m_nodeConnectivity; // node connectivity count
- int m_vertexCount;
- };
- /*****************************************************************************
- *
- * Class: Stripify
- *
- * Description: Class for performing stripification
- *
- *****************************************************************************/
- class Stripify
- {
- public:
- static int* stripify (const Vector3i* tris, int N);
- private:
- Stripify (void); // not permitted
- Stripify (const Stripify&);
- Stripify& operator= (const Stripify&);
- static Triangle* generateTriangleList (const Vector3i* tris, int N);
- static Vector3i getTriangleNodeConnectivityWeights (const TriangleQueue& queue, const Triangle& tri);
- static int getMod3 (int i) { WWASSERT(i>=0 && i<6); return s_mod[i]; }
- static int s_mod[6]; // small lookup table for mod3 operation (see getMod3())
- };
- int Stripify::s_mod[6] = {0,1,2,0,1,2};
- } // Strip
- template <> inline unsigned int HashTemplateKeyClass<Strip::Edge>::Get_Hash_Value(const Strip::Edge& s)
- {
- return (s.v[0]*139) + (s.v[1]*7);
- }
- namespace Strip
- {
- /*****************************************************************************
- *
- * Function: TriangleQueue::getTop()
- *
- * Description: Returns pointer to triangle with smallest connectivity
- *
- * Returns: pointer to triangle with smallest connectivity or NULL
- * if the queue is empty
- *
- *****************************************************************************/
- inline Triangle* TriangleQueue::getTop (void) const
- {
- for (int i = 0; i < 4; i++)
- if (m_bin[i])
- return m_bin[i]; // return head
- return 0; // end
- }
- /*****************************************************************************
- *
- * Function: TriangleQueue::getVertexConnectivity()
- *
- * Description: Returns current connectivity count of specified vertex
- *
- * Parameters: i = vertex index
- *
- * Returns: connectivity count
- *
- *****************************************************************************/
- inline int TriangleQueue::getVertexConnectivity (int i) const
- {
- WWASSERT(i>=0 && i< m_vertexCount);
- return m_nodeConnectivity[i];
- }
- /*****************************************************************************
- *
- * Function: TriangleQueue::~TriangleQueue()
- *
- * Description: Destructor
- *
- *****************************************************************************/
- inline TriangleQueue::~TriangleQueue ()
- {
- delete[] m_nodeConnectivity;
- }
- /*****************************************************************************
- *
- * Function: TriangleQueue::reinsert()
- *
- * Description: Internal function for recalculating a triangle's
- * connectivity
- *
- * Parameters: t = pointer to triangle (non-NULL)
- *
- *****************************************************************************/
- inline void TriangleQueue::reinsert (Triangle* t)
- {
- WWASSERT (t && t->m_bin!=-1); // must be in some bin
- int w = t->getConnectivity();
- // remove from bin
- if (t->m_prev)
- t->m_prev->m_next = t->m_next;
- else
- {
- WWASSERT(t->m_bin != -1);
- WWASSERT(t == m_bin[t->m_bin]); // must be head
- m_bin[t->m_bin] = t->m_next; // new head
- }
- if (t->m_next)
- t->m_next->m_prev = t->m_prev;
- t->m_prev = 0;
- t->m_next = m_bin[w];
- if (t->m_next)
- t->m_next->m_prev = t;
- m_bin[w] = t; // head of bin
- t->m_bin = w; // set bin
- }
- /*****************************************************************************
- *
- * Function: TriangleQueue::removeTriangle()
- *
- * Description: Removes a triangle from the queue
- *
- * Parameters: t = pointer to triangle (non-NULL)
- *
- *****************************************************************************/
- inline void TriangleQueue::removeTriangle (Triangle* t)
- {
- WWASSERT(t);
- if (t->m_prev)
- t->m_prev->m_next = t->m_next;
- else
- {
- WWASSERT(t->m_bin != -1);
- WWASSERT(t == m_bin[t->m_bin]); // must be head
- m_bin[t->m_bin] = t->m_next; // new head
- }
- if (t->m_next)
- t->m_next->m_prev = t->m_prev;
- t->m_bin = -1;
- // update connectivity of t's neighbors
- Triangle* update[3];
- int i;
- for (i = 0; i < 3; i++)
- {
- update[i] = 0;
- if (t->m_neighbors[i])
- {
- Triangle* n = t->m_neighbors[i];
- int k=0;
- for (k = 0; k < 3; k++)
- if (n->m_neighbors[k]==t)
- break;
- WWASSERT (k!=3); // WASS??
- n->m_neighbors[k] = 0; // reduce connection
- t->m_neighbors[i] = 0;
- update[i] = n;
- }
- }
- // update connectivity count of t's vertices
- for (i = 0; i < 3; i++)
- {
- m_nodeConnectivity[t->m_vertices[i]]--;
- WWASSERT(m_nodeConnectivity[t->m_vertices[i]] >= 0); // WASS?
- }
- for (i = 0; i < 3; i++) // perform reinsertions now...
- if (update[i])
- reinsert(update[i]);
- }
- /*****************************************************************************
- *
- * Function: TriangleQueue::TriangleQueue()
- *
- * Description: Constructor
- *
- * Parameters: tris = array of triangles
- * N = number of triangles in the array
- *
- *****************************************************************************/
- inline TriangleQueue::TriangleQueue (Triangle* tris, int N)
- {
- int i;
- for (i = 0; i < 4; i++)
- m_bin[i] = 0; // initialize to zero
- int largestIndex = 0;
- for (i = 0; i < N; i++)
- for (int j = 0; j < 3; j++)
- {
- WWASSERT(tris[i].m_vertices[j]>=0);
- if (tris[i].m_vertices[j] > largestIndex)
- largestIndex = tris[i].m_vertices[j];
- }
- m_vertexCount = largestIndex+1;
- m_nodeConnectivity = W3DNEWARRAY int[m_vertexCount]; //
- for (i = 0; i < m_vertexCount; i++)
- m_nodeConnectivity[i] = 0;
- for (i = 0; i < N; i++)
- {
- Triangle* t = tris+i;
- int w = t->getConnectivity();
- WWASSERT(w>=0 && w <=3);
- WWASSERT(!t->m_prev && !t->m_next && t->m_bin==-1); // must not be in a bin
- t->m_prev = 0;
- t->m_next = m_bin[w];
- if (t->m_next)
- t->m_next->m_prev = t;
- m_bin[w] = t; // head of bin
- t->m_bin = w; // set bin
- for (int j = 0; j < 3; j++)
- m_nodeConnectivity[t->m_vertices[j]]++;
- }
- }
- /*****************************************************************************
- *
- * Function: Stripify::getTriangleConnectivityWeights()
- *
- * Description: Returns "node connectivity" weights for each triangle vertex
- *
- * Parameters: queue = reference to triangle queue
- * tri = reference to triangle
- *
- * Returns: Vector structure containing three weights
- *
- *****************************************************************************/
- inline Vector3i Stripify::getTriangleNodeConnectivityWeights (const TriangleQueue& queue, const Triangle& tri)
- {
- int weight[3];
- for (int i = 0; i < 3; i++)
- {
- weight[i] = queue.getVertexConnectivity(tri.m_vertices[i]);
- }
- int highestVal = weight[0];
- if (weight[1] > highestVal) highestVal = weight[1];
- if (weight[2] > highestVal) highestVal = weight[2];
- Vector3i v(-1,-1,-1);
- for (i = 0; i < 3; i++) {
- if (weight[0] == highestVal) v[i] = +1;
- }
-
- return v;
- }
- /*****************************************************************************
- *
- * Function: Stripify::generateTriangleList()
- *
- * Description: Converts input triangles into internal Triangle structure
- *
- * Parameters: inTris = input triangles
- * N = number of input triangles
- *
- * Returns: pointer to Triangle array
- *
- * Notes: The function sets up the initial connectivity information
- *
- *****************************************************************************/
- Triangle* Stripify::generateTriangleList (const Vector3i* inTris, int N)
- {
- WWASSERT (inTris && N>=0);
- Triangle* tris = W3DNEWARRAY Triangle[N]; // allocate triangles
- int i;
- //--------------------------------------------------------------------
- // Copy triangle vertex data
- //--------------------------------------------------------------------
- for (i = 0; i < N; i++)
- {
- //--------------------------------------------------------------------
- // We could perform random rotation here (this way we don't need random
- // comparisons later in the algo in equality cases).
- //--------------------------------------------------------------------
- tris[i].m_vertices[0] = inTris[i][0];
- tris[i].m_vertices[1] = inTris[i][1];
- tris[i].m_vertices[2] = inTris[i][2];
- }
- //--------------------------------------------------------------------
- // Build connectivity information using a hash table
- //--------------------------------------------------------------------
- HashTemplateClass<Edge,Triangle*> hash;
- Triangle* t = tris;
- for (i = 0; i < N; i++, t++)
- {
- for (int j = 0; j < 3; j++)
- if (!t->m_neighbors[j]) // if neighbor not defined yet
- {
- Edge edge = tris[i].getEdge(j);
- Edge e = edge;
- e.sort(); // sort vertices (smaller first)
-
- Triangle* n = hash.Get(e);
- if (n) // if edge is already in the hash...
- {
- int k=0;
- for (k = 0; k < 3; k++) // find matching edge
- if (!n->m_neighbors[k]) // this neighbor not located yet
- {
- Edge ek = n->getEdge(k); // get edge
- if (ek.v[0] == edge.v[1] && ek.v[1] == edge.v[0]) // if matching edge (note that order must be different)
- break; // .. we found the edge
- }
- if (k < 3) // (k==3) -> no match
- {
- t->m_neighbors[j] = n; // set neighbor
- n->m_neighbors[k] = t; // set neighbor
- hash.Remove(e); // remove from hash (this speeds up the hash queries considerably)
- }
- } else
- hash.Insert(e, t); // insert triangle into hash
- }
- }
- return tris; // return pointer to output data
- }
- /*****************************************************************************
- *
- * Function: Stripify::stripify()
- *
- * Description: Builds a set of triangle strips out of a triangle array
- *
- * Parameters: inTris = input triangles (three vertices per triangle)
- * N = number of input triangles
- *
- * Returns: pointer to strip data array
- *
- * Notes: The strip data array layout is as follows:
- *
- * [int] number of strips
- * [int] length of first strip (in vertices)
- * [int,..] vertex indices of the first strip
- * [int] length of second strip
- * ...
- *
- * The routine assumes that degenerate triangles have been
- * remove and input vertices have been welded
- *
- *****************************************************************************/
- int* Stripify::stripify (const Vector3i* inTris, int N)
- {
- if (!inTris || N<=0) // boo!
- return 0;
- //--------------------------------------------------------------------
- // Initial setup
- //--------------------------------------------------------------------
- Triangle* tris = generateTriangleList(inTris,N); // build connectivity info
- int* out = W3DNEWARRAY int[N*5]; // absolute worst case situation
- int* o = out; // internal ptr (save entry[0] for later use)
- int strip_count = 0; // number of output strips
- TriangleQueue queue (tris, N); // insert triangles into priority queue
- int nSwaps = 0;
- int nLen = 0;
- //--------------------------------------------------------------------
- // Main loop. Always select triangle with smallest weight.
- //--------------------------------------------------------------------
- for (;;)
- {
- Triangle* t = queue.getTop(); // get triangle with smallest weight
- if (!t) // ok, we ran out of triangles (we're done)
- break;
- //--------------------------------------------------------------------
- // Choose initial direction by selecting neighbor with smallest
- // weight
- //--------------------------------------------------------------------
- int* pLen = o; // get current pointer (as we need to take care of it later)
- int len = 3; // initial length
- int best = 0; // best edge
- int bestWeight = 0x7fffffff; // initialize to maximum width
- Vector3i nodeWeights = getTriangleNodeConnectivityWeights(queue, *t);
-
- for (int i = 0; i < 3; i++)
- if (t->m_neighbors[i]) // if triangle has a neighbor in this direction
- {
- int weight = t->m_neighbors[i]->getConnectivity(); // get connectivity of neighbor
- weight += nodeWeights[i]; // add node weights
- weight += nodeWeights[getMod3(i+1)];
- // DEBUG DEBUG ADD SWAP COST HERE?
- if (weight <= bestWeight)
- {
- bestWeight = weight;
- best = i;
- }
- }
- *o++ = len; // output the first three vertices
- *o++ = t->m_vertices[getMod3(best+2)];
- *o++ = t->m_vertices[getMod3(best+0)];
- *o++ = t->m_vertices[getMod3(best+1)];
- for (;;)
- {
- Triangle* next = 0; // find next triangle
-
- int i;
- for (i = 0; i < 3; i++)
- if (t->m_neighbors[i])
- {
- Triangle* n = t->m_neighbors[i];
- for (int j = 0; j < 3; j++)
- {
- Edge e = n->getEdge(j);
- if (!(len&1))
- swap(e.v[0],e.v[1]); // swap
- if (e.v[0] == o[-1] && e.v[1] == o[-2])
- {
- next = n;
- break;
- }
- }
- }
- queue.removeTriangle(t); // get rid of the old triangle
- if (!next) // we're done
- break;
- //--------------------------------------------------------------------
- // Find out where we want to continue...
- //--------------------------------------------------------------------
-
- int bestEdge = -1;
- int bestWeight = 0x7fffffff;
- bool bestSwap = false;
- Vector3i nodeWeights = getTriangleNodeConnectivityWeights(queue, *next);
-
- for (i = 0; i < 3; i++)
- if (next->m_neighbors[i]) // is there a neighbor?
- {
- Edge e = next->getEdge(i); // a swap happens if it contains the prevprev
- bool swap = (e.v[0] == o[-2] || e.v[1] == o[-2]);
- Triangle* n = next->m_neighbors[i]; // get pointer to neighbor
- int w = n->getConnectivity();
- w += nodeWeights[i]; // add vertex weight
- w += nodeWeights[getMod3(i+1)]; // add vertex weight
- w += (swap) ? 1 : -1; // add swap penalty
-
- if (w <= bestWeight)
- {
- bestWeight = w;
- bestEdge = i;
- bestSwap = swap;
- }
- }
- if (bestEdge != -1 && bestSwap) // if we're going to continue...
- {
- *o = o[-2]; // introduce swap vertex
- o++;
- len++; // adjust length
- nSwaps++; // update statistics
- }
- //--------------------------------------------------------------------
- // Find out which was the new vertex (store it to vIndex)
- //--------------------------------------------------------------------
- int vIndex = 0;
- if (next->m_vertices[1] != o[-1] && next->m_vertices[1] != o[-2]) vIndex = 1; else
- if (next->m_vertices[2] != o[-1] && next->m_vertices[2] != o[-2]) vIndex = 2; else
- WWASSERT (next->m_vertices[0] != o[-1] && next->m_vertices[0] != o[-2]);
- //--------------------------------------------------------------------
- // Output the vertex and move to next triangle
- //--------------------------------------------------------------------
- *o++ = next->m_vertices[vIndex]; // output the vertex
- len++; // increase strip length
- t = next; // move to next triangle
- }
-
- *pLen = len; // patch final length
- strip_count++; // increase strip count
- nLen += len;
- // printf ("strip len = %d\n",len);
- }
- //--------------------------------------------------------------------
- // Allocate new optimal-size array and copy output there. Then release
- // all temporary memory allocations.
- //--------------------------------------------------------------------
- // printf ("total indices = %d\n",nLen);
- // printf ("total swaps = %d\n",nSwaps);
- int len = o-out; // allocation length
- int* rOut = W3DNEWARRAY int[len+1];
- *rOut = strip_count; // first entry is number of strips
- for (int i = 0; i < len; i++)
- {
- WWASSERT(out[i] >= 0); // would be nice to test for len as well
- rOut[i+1] = out[i];
- }
- delete[] out; // delete internal output
- delete[] tris; // delete internal triangle list
- return rOut;
- }
- } // Strip
- int* StripOptimizerClass::Stripify(const int* tris, int N)
- {
- return Strip::Stripify::stripify((const Strip::Vector3i*)tris,N);
- }
- //------------------------------------------------------------------------
|