1/*
2Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE SOFTWARE.
21*/
22
23#pragma once
24#ifndef O3DGC_TRIANGLE_LIST_ENCODER_INL
25#define O3DGC_TRIANGLE_LIST_ENCODER_INL
26
27namespace o3dgc
28{
29    // extract opposite edge
30    template <class T>
31    inline void CompueOppositeEdge(const long focusVertex,
32                                   const T * triangle,
33                                   long & a, long & b)
34    {
35        if ((long) triangle[0] == focusVertex)
36        {
37            a = triangle[1];
38            b = triangle[2];
39        }
40        else if ((long) triangle[1] == focusVertex)
41        {
42            a = triangle[2];
43            b = triangle[0];
44        }
45        else
46        {
47            a = triangle[0];
48            b = triangle[1];
49        }
50    }
51    inline bool IsCase0(long degree, long numIndices, const long * const ops, const long * const indices)
52    {
53        // ops: 1000001 vertices: -1 -2
54        if ((numIndices != 2) || (degree < 2)) {
55            return false;
56        }
57        if ((indices[0] != -1) ||(indices[1] != -2) ||
58            (ops[0] != 1)       ||(ops[degree-1] != 1)  ) return false;
59        for (long u = 1; u < degree-1; u++) {
60            if (ops[u] != 0) return false;
61        }
62        return true;
63    }
64    inline bool IsCase1(long degree, long numIndices, const long * const ops, const long * const indices)
65    {
66        // ops: 1xxxxxx1 indices: -1 x x x x x -2
67        if ((degree < 2) || (numIndices < 1))
68        {
69            return false;
70        }
71        if ((indices[0] != -1) ||(indices[numIndices-1] != -2) ||
72            (ops[0] != 1)       ||(ops[degree-1] != 1)  ) return false;
73        return true;
74    }
75    inline bool IsCase2(long degree, long numIndices, const long * const ops, const long * const indices)
76    {
77        // ops: 00000001 indices: -1
78        if ((degree < 2) || (numIndices!= 1))
79        {
80            return false;
81        }
82        if ((indices[0] != -1) || (ops[degree-1] != 1)  ) return false;
83        for (long u = 0; u < degree-1; u++) {
84            if (ops[u] != 0) return false;
85        }
86        return true;
87    }
88    inline bool IsCase3(long degree, long numIndices, const long * const ops, const long * const indices)
89    {
90        // ops: 00000001 indices: -2
91        if ((degree < 2) || (numIndices!= 1))
92        {
93            return false;
94        }
95        if ((indices[0] != -2) || (ops[degree-1] != 1)  ) return false;
96        for (long u = 0; u < degree-1; u++) {
97            if (ops[u] != 0) return false;
98        }
99        return true;
100    }
101    inline bool IsCase4(long degree, long numIndices, const long * const ops, const long * const indices)
102    {
103        // ops: 10000000 indices: -1
104        if ((degree < 2) || (numIndices!= 1))
105        {
106            return false;
107        }
108        if ((indices[0] != -1) || (ops[0] != 1)  ) return false;
109        for (long u = 1; u < degree; u++)
110        {
111            if (ops[u] != 0) return false;
112        }
113        return true;
114    }
115    inline bool IsCase5(long degree, long numIndices, const long * const ops, const long * const indices)
116    {
117        // ops: 10000000 indices: -2
118        if ((degree < 2) || (numIndices!= 1))
119        {
120            return false;
121        }
122        if ((indices[0] != -2) || (ops[0] != 1)  ) return false;
123        for (long u = 1; u < degree; u++) {
124            if (ops[u] != 0) return false;
125        }
126        return true;
127    }
128    inline bool IsCase6(long degree, long numIndices, const long * const ops, const long * const /*indices*/)
129    {
130        // ops: 0000000 indices:
131        if (numIndices!= 0)
132        {
133            return false;
134        }
135        for (long u = 0; u < degree; u++)
136        {
137            if (ops[u] != 0) return false;
138        }
139        return true;
140    }
141    inline bool IsCase7(long degree, long numIndices, const long * const ops, const long * const indices)
142    {
143        // ops: 1000001 indices: -2 -1
144        if ((numIndices!= 2) || (degree < 2))
145        {
146            return false;
147        }
148        if ((indices[0] != -2) ||(indices[1] != -1) ||
149            (ops[0] != 1)      ||(ops[degree-1] != 1)  ) return false;
150        for (long u = 1; u < degree-1; u++)
151        {
152            if (ops[u] != 0) return false;
153        }
154        return true;
155    }
156    inline bool IsCase8(long degree, long numIndices, const long * const ops, const long * const indices)
157    {
158        // ops: 1xxxxxx1 indices: -1 x x x x x -2
159        if ((degree < 2) || (numIndices < 1))
160        {
161            return false;
162        }
163        if ((indices[0] != -2) ||(indices[numIndices-1] != -1) ||
164            (ops[0] != 1)      ||(ops[degree-1] != 1)  ) return false;
165        return true;
166    }
167    template <class T>
168    TriangleListEncoder<T>::TriangleListEncoder(void)
169    {
170        m_vtags                   = 0;
171        m_ttags                   = 0;
172        m_tmap                    = 0;
173        m_vmap                    = 0;
174        m_count                   = 0;
175        m_invVMap                 = 0;
176        m_invTMap                 = 0;
177        m_nonConqueredTriangles   = 0;
178        m_nonConqueredEdges       = 0;
179        m_visitedVertices         = 0;
180        m_visitedVerticesValence  = 0;
181        m_vertexCount             = 0;
182        m_triangleCount           = 0;
183        m_maxNumVertices          = 0;
184        m_maxNumTriangles         = 0;
185        m_numTriangles            = 0;
186        m_numVertices             = 0;
187        m_triangles               = 0;
188        m_maxSizeVertexToTriangle = 0;
189        m_streamType              = O3DGC_STREAM_TYPE_UNKOWN;
190    }
191    template <class T>
192    TriangleListEncoder<T>::~TriangleListEncoder()
193    {
194        delete [] m_vtags;
195        delete [] m_vmap;
196        delete [] m_invVMap;
197        delete [] m_invTMap;
198        delete [] m_visitedVerticesValence;
199        delete [] m_visitedVertices;
200        delete [] m_ttags;
201        delete [] m_tmap;
202        delete [] m_count;
203        delete [] m_nonConqueredTriangles;
204        delete [] m_nonConqueredEdges;
205    }
206    template <class T>
207    O3DGCErrorCode TriangleListEncoder<T>::Init(const T * const triangles,
208                                             long numTriangles,
209                                             long numVertices)
210    {
211        assert(numVertices  > 0);
212        assert(numTriangles > 0);
213
214        m_numTriangles  = numTriangles;
215        m_numVertices   = numVertices;
216        m_triangles     = triangles;
217        m_vertexCount   = 0;
218        m_triangleCount = 0;
219
220        if  (m_numVertices > m_maxNumVertices)
221        {
222            delete [] m_vtags;
223            delete [] m_vmap;
224            delete [] m_invVMap;
225            delete [] m_visitedVerticesValence;
226            delete [] m_visitedVertices;
227            m_maxNumVertices         = m_numVertices;
228            m_vtags                  = new long [m_numVertices];
229            m_vmap                   = new long [m_numVertices];
230            m_invVMap                = new long [m_numVertices];
231            m_visitedVerticesValence = new long [m_numVertices];
232            m_visitedVertices        = new long [m_numVertices];
233        }
234
235        if  (m_numTriangles > m_maxNumTriangles)
236        {
237            delete [] m_ttags;
238            delete [] m_tmap;
239            delete [] m_invTMap;
240            delete [] m_nonConqueredTriangles;
241            delete [] m_nonConqueredEdges;
242            delete [] m_count;
243            m_maxNumTriangles       = m_numTriangles;
244            m_ttags                 = new long [m_numTriangles];
245            m_tmap                  = new long [m_numTriangles];
246            m_invTMap               = new long [m_numTriangles];
247            m_count                 = new long [m_numTriangles+1];
248            m_nonConqueredTriangles = new long [m_numTriangles];
249            m_nonConqueredEdges     = new long [2*m_numTriangles];
250        }
251
252        memset(m_vtags  , 0x00, sizeof(long) * m_numVertices );
253        memset(m_vmap   , 0xFF, sizeof(long) * m_numVertices );
254        memset(m_invVMap, 0xFF, sizeof(long) * m_numVertices );
255        memset(m_ttags  , 0x00, sizeof(long) * m_numTriangles);
256        memset(m_tmap   , 0xFF, sizeof(long) * m_numTriangles);
257        memset(m_invTMap, 0xFF, sizeof(long) * m_numTriangles);
258        memset(m_count  , 0x00, sizeof(long) * (m_numTriangles+1));
259
260        m_vfifo.Allocate(m_numVertices);
261        m_ctfans.SetStreamType(m_streamType);
262        m_ctfans.Allocate(m_numVertices, m_numTriangles);
263
264        // compute vertex-to-triangle adjacency information
265        m_vertexToTriangle.AllocateNumNeighborsArray(numVertices);
266        m_vertexToTriangle.ClearNumNeighborsArray();
267        long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer();
268        for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3)
269        {
270            ++numNeighbors[ triangles[t  ] ];
271            ++numNeighbors[ triangles[t+1] ];
272            ++numNeighbors[ triangles[t+2] ];
273        }
274        m_maxSizeVertexToTriangle = 0;
275        for(long i = 0; i < numVertices; ++i)
276        {
277            if (m_maxSizeVertexToTriangle < numNeighbors[i])
278            {
279                m_maxSizeVertexToTriangle = numNeighbors[i];
280            }
281        }
282        m_vertexToTriangle.AllocateNeighborsArray();
283        m_vertexToTriangle.ClearNeighborsArray();
284        for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3)
285        {
286            m_vertexToTriangle.AddNeighbor(triangles[t  ], i);
287            m_vertexToTriangle.AddNeighbor(triangles[t+1], i);
288            m_vertexToTriangle.AddNeighbor(triangles[t+2], i);
289        }
290        return O3DGC_OK;
291    }
292    template <class T>
293    O3DGCErrorCode TriangleListEncoder<T>::Encode(const T * const triangles,
294                                                  const unsigned long * const indexBufferIDs,
295                                                  const long numTriangles,
296                                                  const long numVertices,
297                                                  BinaryStream & bstream)
298    {
299        assert(numVertices > 0);
300        assert(numTriangles > 0);
301
302        Init(triangles, numTriangles, numVertices);
303        unsigned char mask = 0;
304        bool encodeTrianglesOrder = (indexBufferIDs != 0);
305
306
307        if (encodeTrianglesOrder)
308        {
309            long numBufferIDs = 0;
310            for (long t = 0; t < numTriangles; t++)
311            {
312                if (numBufferIDs <= (long) indexBufferIDs[t])
313                {
314                    ++numBufferIDs;
315                    assert(numBufferIDs <= numTriangles);
316                }
317                ++m_count[indexBufferIDs[t]+1];
318            }
319            for (long i = 2; i <= numBufferIDs; i++)
320            {
321                m_count[i] += m_count[i-1];
322            }
323            mask += 2; // preserved triangles order
324        }
325        bstream.WriteUChar(mask, m_streamType);
326        bstream.WriteUInt32(m_maxSizeVertexToTriangle, m_streamType);
327
328        long v0;
329        for (long v = 0; v < m_numVertices; v++)
330        {
331            if (!m_vtags[v])
332            {
333                m_vfifo.PushBack(v);
334                m_vtags[v] = 1;
335                m_vmap[v] = m_vertexCount++;
336                m_invVMap[m_vmap[v]] = v;
337                while (m_vfifo.GetSize() > 0 )
338                {
339                    v0 = m_vfifo.PopFirst();
340                    ProcessVertex(v0);
341                }
342            }
343        }
344        if (encodeTrianglesOrder)
345        {
346            long t, prev = 0;
347            long pred;
348            for (long i = 0; i < numTriangles; ++i)
349            {
350                t = m_invTMap[i];
351                m_tmap[t] = m_count[ indexBufferIDs[t] ]++;
352                pred = m_tmap[t] - prev;
353                m_ctfans.PushTriangleIndex(pred);
354                prev = m_tmap[t] + 1;
355            }
356            for (long tt = 0; tt < numTriangles; ++tt)
357            {
358                m_invTMap[m_tmap[tt]] = tt;
359            }
360        }
361        m_ctfans.Save(bstream, encodeTrianglesOrder, m_streamType);
362        return O3DGC_OK;
363    }
364    template <class T>
365    O3DGCErrorCode TriangleListEncoder<T>::CompueLocalConnectivityInfo(const long focusVertex)
366    {
367        long t, v, p;
368        m_numNonConqueredTriangles = 0;
369        m_numConqueredTriangles    = 0;
370        m_numVisitedVertices       = 0;
371        for(long i = m_vertexToTriangle.Begin(focusVertex); i < m_vertexToTriangle.End(focusVertex); ++i)
372        {
373            t = m_vertexToTriangle.GetNeighbor(i);
374
375            if ( m_ttags[t] == 0) // non-processed triangle
376            {
377                m_nonConqueredTriangles[m_numNonConqueredTriangles] = t;
378                CompueOppositeEdge( focusVertex,
379                                    m_triangles + (3*t),
380                                    m_nonConqueredEdges[m_numNonConqueredTriangles*2],
381                                    m_nonConqueredEdges[m_numNonConqueredTriangles*2+1]);
382                ++m_numNonConqueredTriangles;
383            }
384            else                // triangle already processed
385            {
386                m_numConqueredTriangles++;
387                p = 3*t;
388                // extract visited vertices
389                for(long k = 0; k < 3; ++k)
390                {
391                    v = m_triangles[p+k];
392                    if (m_vmap[v] > m_vmap[focusVertex]) // vertices are insertices by increasing traversal order
393                    {
394                        bool foundOrInserted = false;
395                        for (long j = 0; j < m_numVisitedVertices; ++j)
396                        {
397
398                            if (m_vmap[v] == m_visitedVertices[j])
399                            {
400                                m_visitedVerticesValence[j]++;
401                                foundOrInserted = true;
402                                break;
403                            }
404                            else if (m_vmap[v] < m_visitedVertices[j])
405                            {
406                                ++m_numVisitedVertices;
407                                for (long h = m_numVisitedVertices-1; h > j; --h)
408                                {
409                                    m_visitedVertices[h]        = m_visitedVertices[h-1];
410                                    m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1];
411                                }
412                                m_visitedVertices[j]        = m_vmap[v];
413                                m_visitedVerticesValence[j] = 1;
414                                foundOrInserted = true;
415                                break;
416                            }
417                        }
418                        if (!foundOrInserted)
419                        {
420                            m_visitedVertices[m_numVisitedVertices] = m_vmap[v];
421                            m_visitedVerticesValence[m_numVisitedVertices] = 1;
422                            m_numVisitedVertices++;
423                        }
424                    }
425                }
426            }
427        }
428        // re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex)
429        // in order to avoid config. 9
430        if (m_numVisitedVertices > 2)
431        {
432            long y;
433            for(long x = 1; x < m_numVisitedVertices; ++x)
434            {
435
436                if (m_visitedVerticesValence[x] == 1)
437                {
438                    y = x;
439                    while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) )
440                    {
441                        swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]);
442                        swap(m_visitedVertices[y], m_visitedVertices[y-1]);
443                        --y;
444                    }
445                }
446            }
447        }
448        if (m_numNonConqueredTriangles > 0)
449        {
450            // compute triangle-to-triangle adjacency information
451            m_triangleToTriangle.AllocateNumNeighborsArray(m_numNonConqueredTriangles);
452            m_triangleToTriangle.ClearNumNeighborsArray();
453            m_triangleToTriangleInv.AllocateNumNeighborsArray(m_numNonConqueredTriangles);
454            m_triangleToTriangleInv.ClearNumNeighborsArray();
455            long * const numNeighbors    = m_triangleToTriangle.GetNumNeighborsBuffer();
456            long * const invNumNeighbors = m_triangleToTriangleInv.GetNumNeighborsBuffer();
457            for(long i = 0; i < m_numNonConqueredTriangles; ++i)
458            {
459                for(long j = i+1; j < m_numNonConqueredTriangles; ++j)
460                {
461                    if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j
462                    {
463                        ++numNeighbors[i];
464                        ++invNumNeighbors[j];
465                    }
466                    if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j
467                    {
468                        ++numNeighbors[j];
469                        ++invNumNeighbors[i];
470                    }
471                }
472            }
473            m_triangleToTriangle.AllocateNeighborsArray();
474            m_triangleToTriangle.ClearNeighborsArray();
475            m_triangleToTriangleInv.AllocateNeighborsArray();
476            m_triangleToTriangleInv.ClearNeighborsArray();
477            for(long i = 0; i < m_numNonConqueredTriangles; ++i)
478            {
479                for(long j = 1; j < m_numNonConqueredTriangles; ++j)
480                {
481                    if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j
482                    {
483                        m_triangleToTriangle.AddNeighbor(i, j);
484                        m_triangleToTriangleInv.AddNeighbor(j, i);
485                    }
486                    if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j
487                    {
488                        m_triangleToTriangle.AddNeighbor(j, i);
489                        m_triangleToTriangleInv.AddNeighbor(i, j);
490                    }
491                }
492            }
493        }
494        return O3DGC_OK;
495    }
496    template <class T>
497    O3DGCErrorCode TriangleListEncoder<T>::ComputeTFANDecomposition(const long focusVertex)
498    {
499        long processedTriangles = 0;
500        long minNumInputEdges;
501        long numInputEdges;
502        long indexSeedTriangle;
503        long seedTriangle;
504        long currentIndex;
505        long currentTriangle;
506        long i0, i1, index;
507
508        m_tfans.Clear();
509        while (processedTriangles != m_numNonConqueredTriangles)
510        {
511            // find non processed triangle with lowest number of inputs
512            minNumInputEdges   = m_numTriangles;
513            indexSeedTriangle = -1;
514            for(long i = 0; i < m_numNonConqueredTriangles; ++i)
515            {
516                numInputEdges = m_triangleToTriangleInv.GetNumNeighbors(i);
517                if ( !m_ttags[m_nonConqueredTriangles[i]] &&
518                      numInputEdges < minNumInputEdges            )
519                {
520                    minNumInputEdges  = numInputEdges;
521                    indexSeedTriangle = i;
522                    if (minNumInputEdges == 0) // found boundary triangle
523                    {
524                        break;
525                    }
526                }
527            }
528            assert(indexSeedTriangle >= 0);
529            seedTriangle = m_nonConqueredTriangles[indexSeedTriangle];
530            m_tfans.AddTFAN();
531            m_tfans.AddVertex( focusVertex );
532            m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2] );
533            m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2 + 1] );
534            m_ttags[ seedTriangle ]         = 1; // mark triangle as processed
535            m_tmap[seedTriangle]            = m_triangleCount++;
536            m_invTMap[m_tmap[seedTriangle]] = seedTriangle;
537            ++processedTriangles;
538            currentIndex                    = indexSeedTriangle;
539            currentTriangle                 = seedTriangle;
540            do
541            {
542                // find next triangle
543                i0 = m_triangleToTriangle.Begin(currentIndex);
544                i1 = m_triangleToTriangle.End(currentIndex);
545                currentIndex = -1;
546                for(long i = i0; i < i1; ++i)
547                {
548                    index           = m_triangleToTriangle.GetNeighbor(i);
549                    currentTriangle = m_nonConqueredTriangles[index];
550                    if ( !m_ttags[currentTriangle] )
551                    {
552                        currentIndex = index;
553                        m_tfans.AddVertex( m_nonConqueredEdges[currentIndex*2+1] );
554                        m_ttags[currentTriangle]            = 1; // mark triangle as processed
555                        m_tmap [currentTriangle]            = m_triangleCount++;
556                        m_invTMap[m_tmap [currentTriangle]] = currentTriangle;
557                        ++processedTriangles;
558                        break;
559                    }
560                }
561            } while (currentIndex != -1);
562        }
563
564        return O3DGC_OK;
565    }
566    template <class T>
567    O3DGCErrorCode TriangleListEncoder<T>::CompressTFAN(const long focusVertex)
568    {
569        m_ctfans.PushNumTFans(m_tfans.GetNumTFANs());
570
571        const long ntfans = m_tfans.GetNumTFANs();
572        long degree;
573        long k0, k1;
574        long v0;
575        long ops[O3DGC_MAX_TFAN_SIZE];
576        long indices[O3DGC_MAX_TFAN_SIZE];
577
578        long numOps;
579        long numIndices;
580        long pos;
581        long found;
582
583        if (m_tfans.GetNumTFANs() > 0)
584        {
585            for(long f = 0; f != ntfans; f++)
586            {
587                degree = m_tfans.GetTFANSize(f) - 1;
588                m_ctfans.PushDegree(degree-2+ m_numConqueredTriangles);
589                numOps     = 0;
590                numIndices = 0;
591                k0 = 1 + m_tfans.Begin(f);
592                k1 = m_tfans.End(f);
593                for(long k = k0; k < k1; k++)
594                {
595                    v0 = m_tfans.GetVertex(k);
596                    if (m_vtags[v0] == 0)
597                    {
598                        ops[numOps++] = 0;
599                        m_vtags[v0] = 1;
600                        m_vmap[v0] = m_vertexCount++;
601                        m_invVMap[m_vmap[v0]] = v0;
602                        m_vfifo.PushBack(v0);
603                        m_visitedVertices[m_numVisitedVertices++] = m_vmap[v0];
604                    }
605                    else
606                    {
607                        ops[numOps++] = 1;
608                        pos = 0;
609                        found = 0;
610                        for(long u=0; u < m_numVisitedVertices; ++u)
611                        {
612                            pos++;
613                            if (m_visitedVertices[u] == m_vmap[v0])
614                            {
615                                found = 1;
616                                break;
617                            }
618                        }
619                        if (found == 1)
620                        {
621                            indices[numIndices++] = -pos;
622                        }
623                        else
624                        {
625                            indices[numIndices++] = m_vmap[v0] - m_vmap[focusVertex];
626                        }
627                    }
628                }
629                //-----------------------------------------------
630                if (IsCase0(degree, numIndices, ops, indices))
631                {
632                    // ops: 1000001 vertices: -1 -2
633                    m_ctfans.PushConfig(0);
634                }
635                else if (IsCase1(degree, numIndices, ops, indices))
636                {
637                    // ops: 1xxxxxx1 vertices: -1 x x x x x -2
638                    long u = 1;
639                    for(u = 1; u < degree-1; u++)
640                    {
641                        m_ctfans.PushOperation(ops[u]);
642                    }
643                    for(u =1; u < numIndices-1; u++)
644                    {
645                        m_ctfans.PushIndex(indices[u]);
646                    }
647                    m_ctfans.PushConfig(1);
648                }
649                else if (IsCase2(degree, numIndices, ops, indices))
650                {
651                    // ops: 00000001 vertices: -1
652                    m_ctfans.PushConfig(2);
653                }
654                else if (IsCase3(degree, numIndices, ops, indices))
655                {
656                    // ops: 00000001 vertices: -2
657                    m_ctfans.PushConfig(3);
658                }
659                else if (IsCase4(degree, numIndices, ops, indices))
660                {
661                    // ops: 10000000 vertices: -1
662                    m_ctfans.PushConfig(4);
663                }
664                else if (IsCase5(degree, numIndices, ops, indices))
665                {
666                    // ops: 10000000 vertices: -2
667                    m_ctfans.PushConfig(5);
668                }
669                else if (IsCase6(degree, numIndices, ops, indices))
670                {
671                    // ops: 00000000 vertices:
672                    m_ctfans.PushConfig(6);
673                }
674                else if (IsCase7(degree, numIndices, ops, indices))
675                {
676                    // ops: 1000001 vertices: -1 -2
677                    m_ctfans.PushConfig(7);
678                }
679                else if (IsCase8(degree, numIndices, ops, indices))
680                {
681                    // ops: 1xxxxxx1 vertices: -2 x x x x x -1
682                    long u = 1;
683                    for(u =1; u < degree-1; u++)
684                    {
685                        m_ctfans.PushOperation(ops[u]);
686                    }
687                    for(u =1; u < numIndices-1; u++)
688                    {
689                        m_ctfans.PushIndex(indices[u]);
690                    }
691                    m_ctfans.PushConfig(8);
692                }
693                else
694                {
695                    long u = 0;
696                    for(u =0; u < degree; u++)
697                    {
698                        m_ctfans.PushOperation(ops[u]);
699                    }
700                    for(u =0; u < numIndices; u++)
701                    {
702                        m_ctfans.PushIndex(indices[u]);
703                    }
704                    m_ctfans.PushConfig(9);
705                }
706            }
707        }
708        return O3DGC_OK;
709    }
710    template <class T>
711    O3DGCErrorCode TriangleListEncoder<T>::ProcessVertex(const long focusVertex)
712    {
713        CompueLocalConnectivityInfo(focusVertex);
714        ComputeTFANDecomposition(focusVertex);
715        CompressTFAN(focusVertex);
716        return O3DGC_OK;
717    }
718}
719#endif //O3DGC_TRIANGLE_LIST_ENCODER_INL
720