Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/lib/graphics/importer/tc.cc @ 7591

Last change on this file since 7591 was 6608, checked in by bensch, 19 years ago

trunk: copy the tc version from spaceshipcontrol

File size: 35.5 KB
Line 
1/*
2 * $Header: /home/grantham/cvsroot/projects/modules/tc/tc.c,v 1.27 2000/10/10 16:09:23 grantham Exp $
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <limits.h>
9#include "tc.h"
10
11/* SNIPPET "table.c" Inducted Wed Nov 22 09:36:55 2000 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#if !defined(MEM_CHART)
18#define chartedSetLabel(a)
19#endif
20
21#define LEVEL1COUNT 16384
22#define LEVEL2COUNT 1024
23#define LEVEL3COUNT 256
24
25typedef struct TableLevel3
26{
27    int EntryCount;
28    void *Table[LEVEL3COUNT];
29    char IsSet[LEVEL3COUNT];
30} TableLevel3;
31
32typedef struct TableLevel2
33{
34    int EntryCount;
35    TableLevel3 *Table[LEVEL2COUNT];
36} TableLevel2;
37
38typedef struct TableRoot
39{
40    size_t EntryCount;
41    size_t TotalEntryCount;
42    size_t TotalAllocatedBytes;
43    int EmptyEntryCount;
44    TableLevel2 *Table[LEVEL1COUNT];
45} TableRoot;
46
47typedef struct TableIterator {
48    int i1, i2, i3;
49    unsigned int i;
50    TableLevel3 *CurLevel3;
51    int CheckLevel1, CheckLevel2;
52} TableIterator;
53
54TableRoot *tableNew(void)
55{
56    TableRoot *tr;
57
58    chartedSetLabel("table root");
59    tr = (TableRoot *)calloc(sizeof(TableRoot), 1);
60    return tr;
61}
62
63TableIterator *tableNewIterator(void)
64{
65    TableIterator *ti;
66
67    chartedSetLabel("table iterator");
68    ti = (TableIterator *)malloc(sizeof(TableIterator));
69    return ti;
70}
71
72int tableRetrieve(unsigned int a, TableRoot *table, void **ref)
73{
74    int i1 = a / (LEVEL2COUNT * LEVEL3COUNT);
75    int i2 = (a / LEVEL3COUNT) % LEVEL2COUNT;
76    int i3 = a % LEVEL3COUNT;
77
78    if(table->Table[i1] == NULL)
79        return 0;
80    if(table->Table[i1]->Table[i2] == NULL)
81        return 0;
82    if(!table->Table[i1]->Table[i2]->IsSet[i3])
83        return 0;
84    if(ref != NULL)
85        *ref = table->Table[i1]->Table[i2]->Table[i3];
86    return 1;
87}
88
89int tableInsert(unsigned int a, TableRoot *table, void *ref)
90{
91    int i1 = a / (LEVEL2COUNT * LEVEL3COUNT);
92    int i2 = (a / LEVEL3COUNT) % LEVEL2COUNT;
93    int i3 = a % LEVEL3COUNT;
94
95    if(table->Table[i1] == NULL) {
96        chartedSetLabel("table level 2");
97        table->Table[i1] = (TableLevel2 *)calloc(1, sizeof(TableLevel2));
98        table->TotalAllocatedBytes += sizeof(TableLevel2);
99        if(table->Table[i1] == NULL)
100            return 0;
101    }
102    if(table->Table[i1]->Table[i2] == NULL) {
103        chartedSetLabel("table level 3");
104        table->Table[i1]->Table[i2] =
105            (TableLevel3 *)calloc(1, sizeof(TableLevel3));
106        table->TotalAllocatedBytes += sizeof(TableLevel3);
107        if(table->Table[i1]->Table[i2] == NULL)
108            return 0;
109        table->Table[i1]->EntryCount++;
110        table->TotalEntryCount += LEVEL3COUNT;
111        table->EmptyEntryCount += LEVEL3COUNT;
112    }
113    if(!table->Table[i1]->Table[i2]->IsSet[i3]) {
114        table->Table[i1]->Table[i2]->EntryCount++;
115        table->EmptyEntryCount --;
116        table->Table[i1]->Table[i2]->IsSet[i3] = 1;
117    }
118    table->Table[i1]->Table[i2]->Table[i3] = ref;
119    return 1;
120}
121
122int tableRemove(unsigned int a, TableRoot *table, void **wasref)
123{
124    int i1 = a / (LEVEL2COUNT * LEVEL3COUNT);
125    int i2 = (a / LEVEL3COUNT) % LEVEL2COUNT;
126    int i3 = a % LEVEL3COUNT;
127
128    if(table->Table[i1] == NULL)
129        return 0;
130    if(table->Table[i1]->Table[i2] == NULL)
131        return 0;
132    if(!table->Table[i1]->Table[i2]->IsSet[i3])
133        return 0;
134    if(wasref != NULL)
135        *wasref = table->Table[i1]->Table[i2]->Table[i3];
136    table->Table[i1]->Table[i2]->IsSet[i3] = 0;
137    table->EmptyEntryCount ++;
138    if(--table->Table[i1]->Table[i2]->EntryCount == 0) {
139        table->EmptyEntryCount -= LEVEL3COUNT;
140        table->TotalEntryCount -= LEVEL3COUNT;
141        free(table->Table[i1]->Table[i2]);
142        table->TotalAllocatedBytes -= sizeof(TableLevel3);
143        table->Table[i1]->Table[i2] = NULL;
144        if(--table->Table[i1]->EntryCount == 0) {
145            table->TotalAllocatedBytes -= sizeof(TableLevel2);
146            free(table->Table[i1]);
147            table->Table[i1] = NULL;
148        }
149    }
150    return 1;
151}
152
153void tableResetIterator(TableIterator *ti)
154{
155    ti->i1 = 0;
156    ti->i2 = 0;
157    ti->i3 = 0;
158    ti->i = 0;
159    ti->CheckLevel1 = 1;
160    ti->CheckLevel2 = 1;
161}
162
163int tableIterate(TableRoot *table, TableIterator *ti, unsigned int *i, void **ref)
164{
165    int done;
166
167    done = 0;
168    while(ti->i1 < LEVEL1COUNT) {
169        if(ti->CheckLevel1 && table->Table[ti->i1] == NULL) {
170            ti->i += LEVEL2COUNT * LEVEL3COUNT;
171            ti->i1++;
172            continue;
173        } else
174            ti->CheckLevel1 = 0;
175        if(ti->CheckLevel2 && table->Table[ti->i1]->Table[ti->i2] == NULL) {
176            ti->i += LEVEL3COUNT;
177            if(++ti->i2 >= LEVEL2COUNT) {
178                ti->i2 = 0;
179                ti->i1++;
180                ti->CheckLevel1 = 1;
181            }
182            continue;
183        } else
184            ti->CheckLevel2 = 0;
185        if(ti->i3 == 0)
186            ti->CurLevel3 = table->Table[ti->i1]->Table[ti->i2];
187        if(ti->CurLevel3->IsSet[ti->i3]) {
188            if(ref != NULL)
189                *ref = ti->CurLevel3->Table[ti->i3];
190            if(i != NULL)
191                *i = ti->i;
192            done = 1;
193        }
194        ti->i++;
195        if(++ti->i3 >= LEVEL3COUNT) {
196            ti->i3 = 0;
197            ti->CheckLevel2 = 1;
198            if(++ti->i2 >= LEVEL2COUNT) {
199                ti->i2 = 0;
200                ti->i1++;
201                ti->CheckLevel1 = 1;
202            }
203        }
204        if(done)
205            return 1;
206    }
207    return 0;
208}
209
210void tableDelete(TableRoot *table, void (*datumDelete)(void *datum))
211{
212    int i1, i2, i3;
213
214    for(i1 = 0; i1 < LEVEL1COUNT; i1++) {
215        if(table->Table[i1] != NULL) {
216            for(i2 = 0; i2 < LEVEL2COUNT; i2++) {
217                if(table->Table[i1]->Table[i2] != NULL) {
218                    for(i3 = 0; i3 < LEVEL3COUNT; i3++) {
219                        if(table->Table[i1]->Table[i2]->IsSet[i3])
220                            datumDelete(table->Table[i1]->Table[i2]->Table[i3]);
221                    }
222                    free(table->Table[i1]->Table[i2]);
223                }
224            }
225            free(table->Table[i1]);
226            table->Table[i1] = NULL;
227        }
228    }
229    table->TotalEntryCount = 0;
230    table->EmptyEntryCount = 0;
231    table->TotalAllocatedBytes = 0;
232}
233
234void tableGetStats(TableRoot *table, size_t *totalBytes, size_t *emptyCount,
235    size_t *totalCount)
236{
237    if(emptyCount != NULL)
238        *emptyCount = table->EmptyEntryCount;
239    if(totalCount != NULL)
240        *totalCount = table->TotalEntryCount;
241    if(totalBytes != NULL)
242        *totalBytes = table->TotalAllocatedBytes;
243}
244
245size_t tableGetIteratorSize(void)
246{
247    return sizeof(TableIterator);
248}
249
250/* "table.c" ENDSNIPPET */
251
252#if !defined(MEM_CHART)
253#define chartedSetLabel(a)
254#endif
255
256#if defined(DEBUG)
257#define ACTC_DEBUG(a) a
258#else
259#define ACTC_DEBUG(a)
260#endif
261
262#if defined(INFO)
263#define ACTC_INFO(a) a
264#else
265#define ACTC_INFO(a)
266#endif
267
268
269#define ACTC_CHECK(a) \
270    { \
271        int theErrorNow; \
272        theErrorNow = (a); \
273        if(theErrorNow < 0) \
274            return theErrorNow; \
275    }
276
277typedef struct {
278    struct ACTCVertex *FinalVert;
279} ACTCTriangle;
280
281typedef struct {
282    struct ACTCVertex *V2;
283    int Count;
284    int TriangleCount;
285    ACTCTriangle *Triangles;
286} ACTCEdge;
287
288typedef struct ACTCVertex {
289    unsigned int V;
290    int Count;
291    struct ACTCVertex **PointsToMe;
292    struct ACTCVertex *Next;
293    int EdgeCount;
294    ACTCEdge *Edges;
295} ACTCVertex;
296
297/* private tokens */
298#define ACTC_NO_MATCHING_VERT           -0x3000
299#define ACTC_FWD_ORDER                  0
300#define ACTC_REV_ORDER                  1
301
302#define MAX_STATIC_VERTS                10000000 /* buh? */
303
304struct _ACTCData {
305
306    /* vertex and edge database */
307    int VertexCount;
308    TableRoot *Vertices;
309    TableIterator *VertexIterator;
310    int CurMaxVertValence;
311    int CurMinVertValence;
312    ACTCVertex **VertexBins;
313
314    /* alternate vertex array if range small enough */
315    ACTCVertex *StaticVerts;
316    int UsingStaticVerts;
317    unsigned int VertRange;
318
319    /* During consolidation */
320    int CurWindOrder;
321    int PrimType;
322    ACTCVertex *V1;
323    ACTCVertex *V2;
324    int VerticesSoFar;
325
326    /* Error and state handling */
327    int IsInputting;
328    int IsOutputting;
329    int Error;
330
331    /* actcParam-settable parameters */
332    unsigned int MinInputVert;
333    unsigned int MaxInputVert;
334    int MaxVertShare;
335    int MaxEdgeShare;
336    int MinFanVerts;
337    int MaxPrimVerts;
338    int HonorWinding;
339};
340
341#if defined(DEBUG) || defined(INFO)
342
343static void dumpTriangles(ACTCEdge *e, FILE *fp)
344{
345    int i;
346    int c;
347    char v[12];
348
349    c = fprintf(fp, "      %d triangles: ");
350    for(i = 0; i < e->TriangleCount; i++) {
351        if(c + 1 + sprintf(v, "%u", e->Triangles[i].FinalVert) > 78) {
352            fputs("\n", fp);
353            c = fprintf(fp, "        ");
354        }
355        c += fprintf(fp, " %s", v);
356    }
357    fputs("\n", fp);
358}
359
360static void dumpEdges(ACTCVertex *vert, FILE *fp)
361{
362    int i;
363    int c;
364    char v[26]; /* two signed ints plus x plus NUL */
365
366    for(i = 0; i < vert->EdgeCount; i++) {
367        fprintf(fp, "    %u->%u (%d times)\n", vert->V, vert->Edges[i].V2->V,
368            vert->Edges[i].Count);
369        dumpTriangles(&vert->Edges[i], fp);
370    }
371    fputs("\n", fp);
372}
373
374static void dumpVertices(ACTCData *tc, FILE *fp)
375{
376    int i;
377    ACTCVertex *v;
378
379    if(!tc->UsingStaticVerts)
380        tableResetIterator(tc->VertexIterator);
381
382    fprintf(fp, "%d vertices in valences list\n", tc->VertexCount);
383    if(tc->UsingStaticVerts) {
384        for(i = 0; i < tc->VertRange; i++) {
385            v = &tc->StaticVerts[i];
386            if(v->Count > 0) {
387                fprintf(fp, "  vertex %u, valence %d, %d edges\n", v->V,
388                    v->Count, v->EdgeCount);
389                dumpEdges(v, fp);
390            }
391        }
392    } else {
393        for(i = 0; i < tc->VertexCount; i++) {
394            if(tableIterate(tc->Vertices, tc->VertexIterator, NULL,
395                (void **)&v) == 0) {
396                fprintf(fp, "ACTC::dumpVertices : fewer vertices in the table "
397                    "than we expected!\n");
398                fprintf(stderr, "ACTC::dumpVertices : fewer vertices in the table "
399                    "than we expected!\n");
400            }
401            if(v == NULL) {
402                fprintf(fp, "ACTC::dumpVertices : did not expect to get a NULL"
403                    "Vertex from the table iterator!\n");
404                fprintf(stderr, "ACTC::dumpVertices : did not expect to get a NULL"
405                    "Vertex from the table iterator!\n");
406            }
407            fprintf(fp, "  vertex %u, valence %d, %d edges\n", v->V, v->Count,
408                v->EdgeCount);
409            dumpEdges(v, fp);
410        }
411    }
412}
413
414static void dumpVertexBins(ACTCData *tc, FILE *fp)
415{
416    ACTCVertex *cur;
417    int i;
418    int c;
419    char v[26]; /* two signed ints plus x plus NUL */
420
421    fprintf(fp, "vertex bins:\n");
422    if(tc->VertexBins == NULL) {
423        fprintf(fp, "        empty.\n");
424        return;
425    }
426    for(i = 1; i <= tc->CurMaxVertValence; i++) {
427        cur = tc->VertexBins[i];
428        c = fprintf(fp, "        bin %d -> ", i);
429        while(cur != NULL) {
430            if(c + 1 + sprintf(v, "%ux%d", cur->V, cur->Count) > 78) {
431                fputs("\n", fp);
432                c = fprintf(fp, "          ");
433            }
434            c += fprintf(fp, " %s", v);
435            cur = cur->Next;
436        }
437        fputs("\n", fp);
438    }
439}
440
441void actcDumpState(ACTCData *tc, FILE *fp)
442{
443    dumpVertices(tc, fp);
444    dumpVertexBins(tc, fp);
445}
446
447#endif /* DEBUG || INFO */
448
449#if defined(DEBUG)
450
451static int abortWithOptionalDump(ACTCData *tc)
452{
453    ACTC_INFO(actcDumpState(tc, stderr));
454    abort();
455}
456
457#endif /* defined(DEBUG) */
458
459int actcGetError(ACTCData *tc)
460{
461    int error = tc->Error;
462    tc->Error = ACTC_NO_ERROR;
463    return error;
464}
465
466static void *reallocAndAppend(void **ptr, unsigned int *itemCount, size_t itemBytes,
467    void *append)
468{
469    void *t;
470
471    t = realloc(*ptr, itemBytes * (*itemCount + 1));
472    if(t == NULL)
473        return NULL;
474    *ptr = t;
475
476    memcpy((unsigned char *)*ptr + *itemCount * itemBytes, append, itemBytes);
477    (*itemCount) += 1;
478
479    return *ptr;
480}
481
482/*
483 * Call only during input; changes vertices' valences and does not
484 * fix the bins that are ordered by vertex valence.  (It's usually cheaper
485 * to traverse the vertex list once after all are added, since that's
486 * linear in the NUMBER OF UNIQUE VERTEX INDICES, which is almost always
487 * going to be less than the number of vertices.)
488 */
489static int incVertexValence(ACTCData *tc, unsigned int v, ACTCVertex **found)
490{
491    ACTCVertex *vertex;
492
493    if(tc->UsingStaticVerts) {
494        vertex = &tc->StaticVerts[v];
495        vertex->Count++;
496        if(vertex->Count == 1) {
497            vertex->V = v;
498            tc->VertexCount++;
499        }
500    } else {
501        if(tableRetrieve(v, tc->Vertices, (void **)&vertex) == 1) {
502            if(vertex->V != v) {
503                ACTC_DEBUG(
504                    fprintf(stderr, "ACTC::incVertexValence : Got vertex %d when "
505                        "looking for vertex %d?!?\n", vertex->V, v);
506                    abortWithOptionalDump(tc);
507                )
508                return tc->Error = ACTC_DATABASE_CORRUPT;
509            }
510            vertex->Count++;
511        } else {
512            chartedSetLabel("new Vertex");
513            vertex = (ACTCVertex *)malloc(sizeof(ACTCVertex));
514            vertex->V = v;
515            vertex->Count = 1;
516            vertex->Edges = NULL;
517            vertex->EdgeCount = 0;
518            if(tableInsert(v, tc->Vertices, vertex) == 0) {
519                ACTC_DEBUG(fprintf(stderr, "ACTC::incVertexValence : Failed "
520                    "to insert vertex into table\n");)
521                return tc->Error = ACTC_ALLOC_FAILED;
522            }
523            tc->VertexCount++;
524        }
525    }
526    if(vertex->Count > tc->CurMaxVertValence)
527        tc->CurMaxVertValence = vertex->Count;
528
529    *found = vertex;
530
531    return ACTC_NO_ERROR;
532}
533
534static int decVertexValence(ACTCData *tc, ACTCVertex **vptr)
535{
536    ACTCVertex *v = *vptr;
537
538    v->Count--;
539    if(v->Count < 0) {
540        ACTC_DEBUG(
541            fprintf(stderr, "ACTC::decVertexValence : Valence went "
542                "negative?!?\n");
543            abortWithOptionalDump(tc);
544        )
545        return tc->Error = ACTC_DATABASE_CORRUPT;
546    }
547
548    if(v->PointsToMe != NULL) {
549        *v->PointsToMe = v->Next;
550        if(v->Next != NULL)
551            v->Next->PointsToMe = v->PointsToMe;
552        v->Next = NULL;
553    }
554
555    if(v->Count == 0) {
556        tc->VertexCount--;
557        if(v->Edges != NULL)
558            free(v->Edges);
559        if(!tc->UsingStaticVerts) {
560            tableRemove(v->V, tc->Vertices, NULL);
561            free(v);
562        }
563        *vptr = NULL;
564    } else {
565        if(tc->VertexBins != NULL) {
566            v->Next = tc->VertexBins[v->Count];
567            v->PointsToMe = &tc->VertexBins[v->Count];
568            if(v->Next != NULL)
569                v->Next->PointsToMe = &v->Next;
570            tc->VertexBins[v->Count] = v;
571            if(v->Count < tc->CurMinVertValence)
572                tc->CurMinVertValence = v->Count;
573        }
574    }
575
576    return ACTC_NO_ERROR;
577}
578
579static int findNextFanVertex(ACTCData *tc, ACTCVertex **vert)
580{
581    if(tc->CurMaxVertValence < tc->MinFanVerts) {
582        return ACTC_NO_MATCHING_VERT;
583    }
584    while(tc->VertexBins[tc->CurMaxVertValence] == NULL) {
585        tc->CurMaxVertValence--;
586        if(tc->CurMaxVertValence < tc->CurMinVertValence) {
587            if(tc->VertexCount > 0) {
588                ACTC_DEBUG(fprintf(stderr, "tc::findNextFanVertex : no more "
589                    "vertices in bins but VertexCount > 0\n");)
590                return tc->Error = ACTC_DATABASE_CORRUPT;
591            }
592            return ACTC_NO_MATCHING_VERT;
593        }
594    }
595    *vert = tc->VertexBins[tc->CurMaxVertValence];
596    return ACTC_NO_ERROR;
597}
598
599static int findNextStripVertex(ACTCData *tc, ACTCVertex **vert)
600{
601    while(tc->VertexBins[tc->CurMinVertValence] == NULL) {
602        tc->CurMinVertValence++;
603        if(tc->CurMinVertValence > tc->CurMaxVertValence) {
604            if(tc->VertexCount > 0) {
605                ACTC_DEBUG(fprintf(stderr, "tc::findNextStripVertex : no more "
606                    "vertices in bins but VertexCount > 0\n");)
607                return tc->Error = ACTC_DATABASE_CORRUPT;
608            }
609            return ACTC_NO_MATCHING_VERT;
610        }
611    }
612    *vert = tc->VertexBins[tc->CurMinVertValence];
613    return ACTC_NO_ERROR;
614}
615
616int actcGetIsDuringInput(ACTCData *tc) {
617    return tc->IsInputting;
618}
619
620int actcBeginInput(ACTCData *tc)
621{
622    if(tc->IsOutputting) {
623        ACTC_DEBUG(fprintf(stderr, "actcBeginInput : called within "
624            "BeginOutput/EndOutput\n");)
625        return tc->Error = ACTC_DURING_INPUT;
626    }
627
628    if(tc->IsInputting) {
629        ACTC_DEBUG(fprintf(stderr, "actcBeginInput : called within "
630            "BeginInput/EndInput\n");)
631        return tc->Error = ACTC_DURING_INPUT;
632    }
633
634    tc->IsInputting = 1;
635    tc->CurMaxVertValence = 0;
636
637    if(tc->MaxInputVert < MAX_STATIC_VERTS - 1) {
638        size_t byteCount;
639        tc->UsingStaticVerts = 1;
640        tc->VertRange = tc->MaxInputVert + 1;
641        byteCount = sizeof(ACTCVertex) * tc->VertRange;
642        chartedSetLabel("static verts");
643        tc->StaticVerts = (ACTCVertex *)calloc(sizeof(ACTCVertex), tc->VertRange);
644        if(tc->StaticVerts == NULL) {
645            ACTC_INFO(printf("Couldn't allocate static %d vert block of %u "
646                "bytes\n", tc->VertRange, byteCount);)
647            tc->UsingStaticVerts = 0;
648        }
649    } else
650        tc->UsingStaticVerts = 0;
651
652    return ACTC_NO_ERROR;
653}
654
655int actcEndInput(ACTCData *tc)
656{
657    if(tc->IsOutputting) {
658        ACTC_DEBUG(fprintf(stderr, "actcEndInput : called within "
659            "BeginOutput/EndOutput\n");)
660        return tc->Error = ACTC_DURING_OUTPUT;
661    }
662
663    if(!tc->IsInputting) {
664        ACTC_DEBUG(fprintf(stderr, "actcEndInput : called outside "
665            "BeginInput/EndInput\n");)
666        return tc->Error = ACTC_IDLE;
667    }
668
669    tc->IsInputting = 0;
670
671    return ACTC_NO_ERROR;
672}
673
674int actcGetIsDuringOutput(ACTCData *tc) {
675    return tc->IsOutputting;
676}
677
678int actcBeginOutput(ACTCData *tc)
679{
680    ACTCVertex *v;
681    int i;
682
683    if(tc->IsInputting) {
684        ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : called within "
685            "BeginInput/EndInput\n");)
686        return tc->Error = ACTC_DURING_INPUT;
687    }
688
689    if(tc->IsOutputting) {
690        ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : called within "
691            "BeginOutput/EndOutput\n");)
692        return tc->Error = ACTC_DURING_OUTPUT;
693    }
694
695    tc->IsOutputting = 1;
696
697    tc->CurMinVertValence = INT_MAX;
698    chartedSetLabel("vertex bins");
699    tc->VertexBins = (ACTCVertex **)calloc(sizeof(ACTCVertex *), tc->CurMaxVertValence + 1);
700    if(tc->VertexBins == NULL) {
701        ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : couldn't allocate %d bytes "
702            "for Vertex Bins\n",
703            sizeof(ACTCVertex *) * tc->CurMaxVertValence);)
704        return tc->Error = ACTC_ALLOC_FAILED;
705    }
706
707    if(tc->UsingStaticVerts) {
708        double edgeTotal;
709        for(i = 0; i < tc->VertRange; i++) {
710            v = &tc->StaticVerts[i];
711            if(v->Count > 0) {
712                v->Next = tc->VertexBins[v->Count];
713                v->PointsToMe = &tc->VertexBins[v->Count];
714                tc->VertexBins[v->Count] = v;
715                if(v->Next != NULL)
716                    v->Next->PointsToMe = &v->Next;
717                if(v->Count < tc->CurMinVertValence)
718                    tc->CurMinVertValence = v->Count;
719                edgeTotal += v->EdgeCount;
720            }
721        }
722    } else {
723        tableResetIterator(tc->VertexIterator);
724        for(i = 0; i < tc->VertexCount; i++) {
725            if(tableIterate(tc->Vertices, tc->VertexIterator, NULL, (void **)&v)
726                == 0) {
727                ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : fewer vertices in "
728                    "the table than we expected!\n");)
729                return tc->Error = ACTC_DATABASE_CORRUPT;
730            }
731            v->Next = tc->VertexBins[v->Count];
732            v->PointsToMe = &tc->VertexBins[v->Count];
733            tc->VertexBins[v->Count] = v;
734            if(v->Next != NULL)
735                v->Next->PointsToMe = &v->Next;
736            if(v->Count < tc->CurMinVertValence)
737                tc->CurMinVertValence = v->Count;
738        }
739    }
740
741    return ACTC_NO_ERROR;
742}
743
744int actcEndOutput(ACTCData *tc)
745{
746    if(tc->IsInputting) {
747        ACTC_DEBUG(fprintf(stderr, "actcEndOutput : called within "
748            "BeginInput/EndInput\n");)
749        return tc->Error = ACTC_DURING_INPUT;
750    }
751
752    if(!tc->IsOutputting) {
753        ACTC_DEBUG(fprintf(stderr, "actcEndOutput : called outside "
754            "BeginOutput/EndOutput\n");)
755        return tc->Error = ACTC_IDLE;
756    }
757
758    tc->IsOutputting = 0;
759
760    if(tc->UsingStaticVerts) {
761        free(tc->StaticVerts);
762        tc->StaticVerts = NULL;
763        tc->UsingStaticVerts = 0;
764    }
765
766    free(tc->VertexBins);
767    tc->VertexBins = NULL;
768
769    return ACTC_NO_ERROR;
770}
771
772ACTCData *actcNew(void)
773{
774    ACTCData *tc;
775#if defined(DEBUG) || defined(INFO)
776    static int didPrintVersion = 0;
777
778    if(!didPrintVersion) {
779        int verMinor, verMajor;
780        didPrintVersion = 1;
781
782        actcGetParami(tc, ACTC_MAJOR_VERSION, &verMajor);
783        actcGetParami(tc, ACTC_MINOR_VERSION, &verMinor);
784        fprintf(stderr, "TC Version %d.%d\n", verMajor, verMinor);
785    }
786#endif /* defined(DEBUG) || defined(INFO) */
787
788    chartedSetLabel("the tc struct");
789    tc = (ACTCData *)calloc(sizeof(*tc), 1);
790
791    if(tc == NULL) {
792        ACTC_DEBUG(fprintf(stderr, "actcNew : couldn't allocate %d bytes "
793            "for new ACTCData\n", sizeof(*tc));)
794        return NULL;
795    }
796
797    tc->Vertices = tableNew();
798    tc->VertexIterator = tableNewIterator();
799
800    tc->MinFanVerts = INT_MAX;
801    tc->MaxPrimVerts = INT_MAX;
802    tc->MaxInputVert = INT_MAX;
803    tc->MaxEdgeShare = INT_MAX;
804    tc->MaxVertShare = INT_MAX;
805    tc->HonorWinding = 1;
806    /* seed = 0 handled by calloc */
807    /* XXX grantham 20000615 - seed ignored for now */
808
809    return tc;
810}
811
812static size_t allocatedForTriangles(ACTCEdge *e)
813{
814    return sizeof(ACTCTriangle) * e->TriangleCount;
815}
816
817static size_t allocatedForEdges(ACTCVertex *vert)
818{
819    int i;
820    size_t size;
821
822    size = sizeof(ACTCEdge) * vert->EdgeCount;
823    for(i = 0; i < vert->EdgeCount; i++) {
824        size += allocatedForTriangles(&vert->Edges[i]);
825    }
826    return size;
827}
828
829static size_t allocatedForVertices(ACTCData *tc)
830{
831    int i;
832    int size;
833    ACTCVertex *v;
834
835    if(!tc->UsingStaticVerts)
836        tableResetIterator(tc->VertexIterator);
837
838    if(tc->UsingStaticVerts) {
839        size = tc->VertRange * sizeof(ACTCVertex);
840        for(i = 0; i < tc->VertRange; i++) {
841            v = &tc->StaticVerts[i];
842            if(v->Count > 0)
843                size += allocatedForEdges(v);
844        }
845    } else {
846        for(i = 0; i < tc->VertexCount; i++) {
847            tableIterate(tc->Vertices, tc->VertexIterator, NULL, (void **)&v);
848            size += allocatedForEdges(v);
849        }
850    }
851    return size;
852}
853
854int actcGetMemoryAllocation(ACTCData *tc, size_t *bytesAllocated)
855{
856    size_t tableBytes;
857
858    tableGetStats(tc->Vertices, NULL, NULL, &tableBytes);
859    *bytesAllocated = sizeof(ACTCData);
860    *bytesAllocated += tableBytes;
861    *bytesAllocated += allocatedForVertices(tc); /* recurses */
862
863    return ACTC_NO_ERROR;
864}
865
866static void freeVertex(void *p)
867{
868    ACTCVertex *v = (ACTCVertex *)p;
869    int i;
870
871    for(i = 0; i < v->EdgeCount; i++)
872        free(v->Edges[i].Triangles);
873    free(v->Edges);
874    free(v);
875}
876
877int actcMakeEmpty(ACTCData *tc)
878{
879    tc->VertexCount = 0;
880    if(!tc->UsingStaticVerts)
881        tableDelete(tc->Vertices, freeVertex);
882    if(tc->VertexBins != NULL) {
883        free(tc->VertexBins);
884        tc->VertexBins = NULL;
885    }
886    tc->IsOutputting = 0;
887    tc->IsInputting = 0;
888    return ACTC_NO_ERROR;
889}
890
891void actcDelete(ACTCData *tc)
892{
893    actcMakeEmpty(tc);
894    free(tc->VertexIterator);
895    free(tc->Vertices);
896    free(tc);
897}
898
899int actcParami(ACTCData *tc, int param, int value)
900{
901    if(tc->IsInputting) {
902        ACTC_DEBUG(fprintf(stderr, "actcParami : within BeginInput/"
903            "EndInput\n");)
904        return tc->Error = ACTC_DURING_INPUT;
905    }
906    if(tc->IsOutputting) {
907        ACTC_DEBUG(fprintf(stderr, "actcParami : within BeginOutput/"
908            "EndOutput\n");)
909        return tc->Error = ACTC_DURING_OUTPUT;
910    }
911    switch(param) {
912        case ACTC_OUT_MIN_FAN_VERTS:
913            tc->MinFanVerts = value;
914            break;
915
916        case ACTC_IN_MAX_VERT:
917            if(value < tc->MinInputVert) {
918                ACTC_DEBUG(fprintf(stderr, "actcParami : tried to set "
919                    "MAX_INPUT_VERT to %d, less than MIN_INPUT_VERT (%d)\n",
920                    value, tc->MinInputVert);)
921                return tc->Error = ACTC_INVALID_VALUE;
922            }
923            tc->MaxInputVert = value;
924            break;
925
926        case ACTC_IN_MIN_VERT:
927            if(value > tc->MaxInputVert) {
928                ACTC_DEBUG(fprintf(stderr, "actcParami : tried to set "
929                    "MIN_INPUT_VERT to %d, greater than MAX_INPUT_VERT (%d)\n",
930                    value, tc->MaxInputVert);)
931                return tc->Error = ACTC_INVALID_VALUE;
932            }
933            tc->MinInputVert = value;
934            break;
935
936        case ACTC_IN_MAX_EDGE_SHARING:
937            tc->MaxEdgeShare = value;
938            break;
939
940        case ACTC_IN_MAX_VERT_SHARING:
941            tc->MaxVertShare = value;
942            break;
943
944        case ACTC_OUT_HONOR_WINDING:
945            tc->HonorWinding = value;
946            break;
947
948        case ACTC_OUT_MAX_PRIM_VERTS:
949            if(value < 3) {
950                ACTC_DEBUG(fprintf(stderr, "actcParami : tried to set "
951                    "MAX_PRIM_VERTS to %d (needed to be 3 or more)\n", value);)
952                return tc->Error = ACTC_INVALID_VALUE;
953            }
954            tc->MaxPrimVerts = value;
955            break;
956
957    }
958    return ACTC_NO_ERROR;
959}
960
961int actcParamu(ACTCData *tc, int param, unsigned int value)
962{
963    /*
964     * XXX - yes, this is questionable, but I consulted industry
965     * experts and we agreed that most common behavior is to copy the
966     * bits directly, which is what I want.
967     */
968    return actcParami(tc, param, (int)value);
969}
970
971int actcGetParami(ACTCData *tc, int param, int *value)
972{
973    switch(param) {
974        case ACTC_MAJOR_VERSION:
975            *value = 1;
976            break;
977
978        case ACTC_MINOR_VERSION:
979            *value = 1;
980            break;
981
982        case ACTC_IN_MAX_VERT:
983            *value = tc->MaxInputVert;
984            break;
985
986        case ACTC_IN_MIN_VERT:
987            *value = tc->MinInputVert;
988            break;
989
990        case ACTC_IN_MAX_EDGE_SHARING:
991            *value = tc->MaxEdgeShare;
992            break;
993
994        case ACTC_IN_MAX_VERT_SHARING:
995            *value = tc->MaxVertShare;
996            break;
997
998        case ACTC_OUT_MIN_FAN_VERTS:
999            *value = tc->MinFanVerts;
1000            break;
1001
1002        case ACTC_OUT_HONOR_WINDING:
1003            *value = tc->HonorWinding;
1004            break;
1005
1006        case ACTC_OUT_MAX_PRIM_VERTS:
1007            *value = tc->MaxPrimVerts;
1008            break;
1009
1010        default:
1011            *value = 0;
1012            return tc->Error = ACTC_INVALID_VALUE;
1013            /* break; */
1014    }
1015    return ACTC_NO_ERROR;
1016}
1017
1018int actcGetParamu(ACTCData *tc, int param, unsigned int *value)
1019{
1020    return actcGetParami(tc, param, (int *)value);
1021}
1022
1023static int mapEdgeTriangle(ACTCData *tc, ACTCEdge *edge, ACTCVertex *v3)
1024{
1025    ACTCTriangle tmp;
1026    void *r;
1027
1028    tmp.FinalVert = v3;
1029    chartedSetLabel("triangle list");
1030    r = reallocAndAppend((void **)&edge->Triangles, (unsigned int*)&edge->TriangleCount,
1031        sizeof(tmp), &tmp);
1032    if(r == NULL) {
1033        ACTC_DEBUG(fprintf(stderr, "ACTC::mapEdgeTriangle : Couldn't allocate "
1034            "%d bytes for triangles\n", sizeof(tmp) *
1035            (edge->TriangleCount + 1));)
1036        return tc->Error = ACTC_ALLOC_FAILED;
1037    }
1038
1039    return ACTC_NO_ERROR;
1040}
1041
1042static int unmapEdgeTriangle(ACTCData *tc, ACTCEdge *edge, ACTCVertex *v3)
1043{
1044    int i;
1045
1046    for(i = 0; i < edge->TriangleCount; i++)
1047        if(edge->Triangles[i].FinalVert == v3)
1048            break;
1049
1050    if(i == edge->TriangleCount) {
1051        ACTC_DEBUG(
1052            fprintf(stderr, "ACTC::unmapEdgeTriangle : Couldn't find third vertex"
1053                " from edge in order to delete it?!?\n");
1054            abortWithOptionalDump(tc);
1055        )
1056        return tc->Error = ACTC_DATABASE_CORRUPT;
1057    }
1058
1059    edge->Triangles[i] = edge->Triangles[edge->TriangleCount - 1];
1060    edge->TriangleCount --;
1061
1062    return ACTC_NO_ERROR;
1063}
1064
1065static int mapVertexEdge(ACTCData *tc, ACTCVertex *v1, ACTCVertex *v2, ACTCEdge **edge)
1066{
1067    unsigned int i;
1068    ACTCEdge tmp;
1069    void *r;
1070
1071    for(i = 0; i < v1->EdgeCount; i++)
1072        if(v1->Edges[i].V2 == v2) {
1073            v1->Edges[i].Count++;
1074            break;
1075        }
1076
1077    if(i == v1->EdgeCount) {
1078
1079        tmp.V2 = v2;
1080        tmp.Count = 1;
1081        tmp.Triangles = NULL;
1082        tmp.TriangleCount = 0;
1083
1084        chartedSetLabel("vert-to-edge mapping");
1085        r = reallocAndAppend((void **)&v1->Edges, (unsigned int*)&v1->EdgeCount,
1086            sizeof(tmp), &tmp);
1087        if(r == NULL) {
1088            ACTC_DEBUG(fprintf(stderr, "ACTC::mapVertexEdge : Couldn't reallocate "
1089                "to %d bytes for vertex's edge list\n", sizeof(tmp) *
1090                v1->EdgeCount);)
1091            return tc->Error = ACTC_ALLOC_FAILED;
1092        }
1093    }
1094    *edge = &v1->Edges[i];
1095
1096    return ACTC_NO_ERROR;
1097}
1098
1099static int unmapVertexEdge(ACTCData *tc, ACTCVertex *v1, ACTCVertex *v2)
1100{
1101    int i;
1102
1103    for(i = 0; i < v1->EdgeCount; i++)
1104        if(v1->Edges[i].V2 == v2)
1105            break;
1106
1107    if(i == v1->EdgeCount) {
1108        ACTC_DEBUG(
1109            fprintf(stderr, "ACTC::unmapVertexEdge : Couldn't find edge %d,%d"
1110                " from vertex in order to unmap it?!?\n", v1->V, v2->V);
1111            abortWithOptionalDump(tc);
1112        )
1113        return tc->Error = ACTC_DATABASE_CORRUPT;
1114    }
1115
1116    v1->Edges[i].Count --;
1117    if(v1->Edges[i].Count == 0) {
1118        if(v1->Edges[i].Triangles != NULL)
1119            free(v1->Edges[i].Triangles);
1120        v1->Edges[i] = v1->Edges[v1->EdgeCount - 1];
1121        v1->EdgeCount --;
1122    }
1123
1124    return ACTC_NO_ERROR;
1125}
1126
1127int actcAddTriangle(ACTCData *tc, unsigned int v1, unsigned int v2, unsigned int v3)
1128{
1129    ACTCVertex *vertexRec1;
1130    ACTCVertex *vertexRec2;
1131    ACTCVertex *vertexRec3;
1132
1133    ACTCEdge *edge12;
1134    ACTCEdge *edge23;
1135    ACTCEdge *edge31;
1136
1137    if(tc->IsOutputting) {
1138        ACTC_DEBUG(fprintf(stderr, "actcAddTriangle : inside "
1139            "BeginOutput/EndOutput\n");)
1140        return tc->Error = ACTC_IDLE;
1141    }
1142    if(!tc->IsInputting) {
1143        ACTC_DEBUG(fprintf(stderr, "actcAddTriangle : outside "
1144            "BeginInput/EndInput\n");)
1145        return tc->Error = ACTC_DURING_INPUT;
1146    }
1147
1148    if(incVertexValence(tc, v1, &vertexRec1) != ACTC_NO_ERROR) goto returnError1;
1149    if(incVertexValence(tc, v2, &vertexRec2) != ACTC_NO_ERROR) goto free1;
1150    if(incVertexValence(tc, v3, &vertexRec3) != ACTC_NO_ERROR) goto free2;
1151
1152    if(mapVertexEdge(tc, vertexRec1, vertexRec2, &edge12) != ACTC_NO_ERROR)
1153        goto free3;
1154    if(mapVertexEdge(tc, vertexRec2, vertexRec3, &edge23) != ACTC_NO_ERROR)
1155        goto free4;
1156    if(mapVertexEdge(tc, vertexRec3, vertexRec1, &edge31) != ACTC_NO_ERROR)
1157        goto free5;
1158
1159    if(mapEdgeTriangle(tc, edge12, vertexRec3) != ACTC_NO_ERROR) goto free6;
1160    if(mapEdgeTriangle(tc, edge23, vertexRec1) != ACTC_NO_ERROR) goto free7;
1161    if(mapEdgeTriangle(tc, edge31, vertexRec2) != ACTC_NO_ERROR) goto free8;
1162
1163    return ACTC_NO_ERROR;
1164
1165    /*
1166     * XXX Unfortunately, while backing out during the following
1167     * statements, we might encounter errors in the database which
1168     * will not get returned properly to the caller; I take heart in
1169     * the fact that if such an error occurs, TC is just a moment from
1170     * core dumping anyway. XXX grantham 20000615
1171     */
1172
1173free8:
1174    unmapEdgeTriangle(tc, edge23, vertexRec1);
1175free7:
1176    unmapEdgeTriangle(tc, edge12, vertexRec3);
1177free6:
1178    unmapVertexEdge(tc, vertexRec3, vertexRec1);
1179free5:
1180    unmapVertexEdge(tc, vertexRec2, vertexRec3);
1181free4:
1182    unmapVertexEdge(tc, vertexRec1, vertexRec2);
1183free3:
1184    decVertexValence(tc, &vertexRec3);
1185free2:
1186    decVertexValence(tc, &vertexRec2);
1187free1:
1188    decVertexValence(tc, &vertexRec1);
1189returnError1:
1190    return tc->Error;
1191}
1192
1193int actcStartNextPrim(ACTCData *tc, unsigned int *v1Return, unsigned int *v2Return)
1194{
1195    ACTCVertex *v1 = NULL;
1196    ACTCVertex *v2 = NULL;
1197    int findResult;
1198
1199    if(tc->IsInputting) {
1200        ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : within "
1201            "BeginInput/EndInput\n");)
1202        return tc->Error = ACTC_DURING_INPUT;
1203    }
1204    if(!tc->IsOutputting) {
1205        ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : outside "
1206            "BeginOutput/EndOutput\n");)
1207        return tc->Error = ACTC_IDLE;
1208    }
1209
1210    findResult = findNextFanVertex(tc, &v1);
1211    if(findResult == ACTC_NO_ERROR)
1212        tc->PrimType = ACTC_PRIM_FAN;
1213    else if(findResult != ACTC_NO_MATCHING_VERT) {
1214        ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : internal "
1215            "error finding next appropriate vertex\n");)
1216        return tc->Error = findResult;
1217    } else {
1218        findResult = findNextStripVertex(tc, &v1);
1219        if(findResult != ACTC_NO_ERROR && findResult != ACTC_NO_MATCHING_VERT) {
1220            ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : internal "
1221                "error finding next appropriate vertex\n");)
1222            return tc->Error = findResult;
1223        }
1224        tc->PrimType = ACTC_PRIM_STRIP;
1225    }
1226
1227    if(findResult == ACTC_NO_MATCHING_VERT) {
1228        *v1Return = -1;
1229        *v2Return = -1;
1230        return tc->Error = ACTC_DATABASE_EMPTY;
1231    }
1232
1233    v2 = v1->Edges[0].V2;
1234
1235    tc->CurWindOrder = ACTC_FWD_ORDER;
1236    tc->VerticesSoFar = 2;
1237
1238    tc->V1 = v1;
1239    tc->V2 = v2;
1240
1241    *v1Return = v1->V;
1242    *v2Return = v2->V;
1243
1244    ACTC_INFO(printf("starting with edge %u, %u\n", tc->V1->V, tc->V2->V);)
1245
1246    return tc->PrimType;
1247}
1248
1249static int findEdge(ACTCVertex *v1, ACTCVertex *v2, ACTCEdge **edge)
1250{
1251    int i;
1252
1253    for(i = 0; i < v1->EdgeCount; i++)
1254        if(v1->Edges[i].V2 == v2) {
1255            *edge = &v1->Edges[i];
1256            return 1;
1257        }
1258    return 0;
1259}
1260
1261int unmapEdgeTriangleByVerts(ACTCData *tc, ACTCVertex *v1, ACTCVertex *v2,
1262    ACTCVertex *v3)
1263{
1264    ACTCEdge *e;
1265
1266    ACTC_CHECK(findEdge(v1, v2, &e));
1267    unmapEdgeTriangle(tc, e, v3);
1268    return ACTC_NO_ERROR;
1269}
1270
1271int actcGetNextVert(ACTCData *tc, unsigned int *vertReturn)
1272{
1273    ACTCEdge *edge;
1274    int wasEdgeFound = 0;
1275    ACTCVertex *thirdVertex;
1276    int wasFoundReversed;
1277
1278    if(tc->IsInputting) {
1279        ACTC_DEBUG(fprintf(stderr, "actcGetNextVert : within BeginInput/"
1280            "EndInput\n");)
1281        return tc->Error = ACTC_DURING_INPUT;
1282    }
1283    if(!tc->IsOutputting) {
1284        ACTC_DEBUG(fprintf(stderr, "actcGetNextVert : outside BeginOutput/"
1285            "EndOutput\n");)
1286        return tc->Error = ACTC_IDLE;
1287    }
1288    if(tc->PrimType == -1) {
1289        ACTC_DEBUG(fprintf(stderr, "actcGetNextVert : Asked for next vertex "
1290            "without a primitive (got last\n    vertex already?)\n");)
1291        return tc->Error = ACTC_INVALID_VALUE;
1292    }
1293
1294    if(tc->VerticesSoFar >= tc->MaxPrimVerts) {
1295        tc->PrimType = -1;
1296        return tc->Error = ACTC_PRIM_COMPLETE;
1297    }
1298
1299    if(tc->V1 == NULL || tc->V2 == NULL) {
1300        tc->PrimType = -1;
1301        return tc->Error = ACTC_PRIM_COMPLETE;
1302    }
1303
1304    ACTC_INFO(printf("looking for edge %u, %u\n", tc->V1->V, tc->V2->V);)
1305
1306    wasFoundReversed = 0;
1307
1308    if(findEdge(tc->V1, tc->V2, &edge) != 0) {
1309        wasEdgeFound = 1;
1310    } else if(!tc->HonorWinding) {
1311        wasFoundReversed = 1;
1312        if(findEdge(tc->V2, tc->V1, &edge) != 0) {
1313            wasEdgeFound = 1;
1314        }
1315    }
1316
1317    if(!wasEdgeFound) {
1318        tc->PrimType = -1;
1319        return tc->Error = ACTC_PRIM_COMPLETE;
1320    }
1321
1322    thirdVertex = edge->Triangles[edge->TriangleCount - 1].FinalVert;
1323
1324    ACTC_INFO(printf("third vertex = %u\n", thirdVertex->V);)
1325    *vertReturn = thirdVertex->V;
1326
1327    if(wasFoundReversed) {
1328        ACTC_CHECK(unmapEdgeTriangle(tc, edge, thirdVertex));
1329        ACTC_CHECK(unmapEdgeTriangleByVerts(tc, tc->V1, thirdVertex, tc->V2));
1330        ACTC_CHECK(unmapEdgeTriangleByVerts(tc, thirdVertex, tc->V2, tc->V1));
1331        ACTC_CHECK(unmapVertexEdge(tc, tc->V2, tc->V1));
1332        ACTC_CHECK(unmapVertexEdge(tc, tc->V1, thirdVertex));
1333        ACTC_CHECK(unmapVertexEdge(tc, thirdVertex, tc->V2));
1334    } else {
1335        ACTC_CHECK(unmapEdgeTriangle(tc, edge, thirdVertex));
1336        ACTC_CHECK(unmapEdgeTriangleByVerts(tc, tc->V2, thirdVertex, tc->V1));
1337        ACTC_CHECK(unmapEdgeTriangleByVerts(tc, thirdVertex, tc->V1, tc->V2));
1338        ACTC_CHECK(unmapVertexEdge(tc, tc->V1, tc->V2));
1339        ACTC_CHECK(unmapVertexEdge(tc, tc->V2, thirdVertex));
1340        ACTC_CHECK(unmapVertexEdge(tc, thirdVertex, tc->V1));
1341    }
1342    ACTC_CHECK(decVertexValence(tc, &tc->V1));
1343    ACTC_CHECK(decVertexValence(tc, &tc->V2));
1344    ACTC_CHECK(decVertexValence(tc, &thirdVertex));
1345
1346    if(tc->PrimType == ACTC_PRIM_FAN) {
1347        tc->V2 = thirdVertex;
1348    } else /* PRIM_STRIP */ {
1349        if(tc->CurWindOrder == ACTC_FWD_ORDER)
1350            tc->V1 = thirdVertex;
1351        else
1352            tc->V2 = thirdVertex;
1353        tc->CurWindOrder = !tc->CurWindOrder;
1354    }
1355
1356    tc->VerticesSoFar++;
1357    return ACTC_NO_ERROR;
1358}
1359
1360int actcTrianglesToPrimitives(ACTCData *tc, int triangleCount,
1361    unsigned int (*triangles)[3], int primTypes[], int primLengths[], unsigned int vertices[],
1362    int maxBatchSize)
1363{
1364    int r;
1365    int curTriangle;
1366    int curPrimitive;
1367    unsigned int curVertex;
1368    int prim;
1369    unsigned int v1, v2, v3;
1370    int lastPrim;
1371    int passesWithoutPrims;
1372    int trisSoFar;
1373
1374    if(tc->IsInputting) {
1375        ACTC_DEBUG(fprintf(stderr, "actcTrianglesToPrimitives : within BeginInput/"
1376            "EndInput\n");)
1377        return tc->Error = ACTC_DURING_INPUT;
1378    }
1379    if(tc->IsOutputting) {
1380        ACTC_DEBUG(fprintf(stderr, "actcTrianglesToPrimitives : within"
1381            "BeginOutput/EndOutput\n");)
1382        return tc->Error = ACTC_DURING_OUTPUT;
1383    }
1384    curTriangle = 0;
1385    curPrimitive = 0;
1386    curVertex = 0;
1387    passesWithoutPrims = 0;
1388
1389    actcMakeEmpty(tc);
1390
1391    ACTC_CHECK(actcBeginInput(tc));
1392    trisSoFar = 0;
1393    while(curTriangle < triangleCount) {
1394        r = actcAddTriangle(tc, triangles[curTriangle][0],
1395            triangles[curTriangle][1], triangles[curTriangle][2]);
1396        trisSoFar++;
1397        curTriangle++;
1398        if((trisSoFar >= maxBatchSize) ||
1399            (r == ACTC_ALLOC_FAILED && curTriangle != triangleCount) ||
1400            (r == ACTC_NO_ERROR && curTriangle == triangleCount)) {
1401
1402            /* drain what we got */
1403            trisSoFar = 0;
1404            ACTC_CHECK(actcEndInput(tc));
1405            ACTC_CHECK(actcBeginOutput(tc));
1406            lastPrim = curPrimitive;
1407            while((prim = actcStartNextPrim(tc, &v1, &v2)) != ACTC_DATABASE_EMPTY) {
1408                ACTC_CHECK(prim);
1409                primTypes[curPrimitive] = prim;
1410                primLengths[curPrimitive] = 2;
1411                vertices[curVertex++] = v1;
1412                vertices[curVertex++] = v2;
1413                while((r = actcGetNextVert(tc, &v3)) != ACTC_PRIM_COMPLETE) {
1414                    ACTC_CHECK(r);
1415                    vertices[curVertex++] = v3;
1416                    primLengths[curPrimitive]++;
1417                }
1418                curPrimitive++;
1419            }
1420            ACTC_CHECK(actcEndOutput(tc));
1421            if(r == ACTC_ALLOC_FAILED && curPrimitive == lastPrim) {
1422                if(passesWithoutPrims == 0) {
1423                    /* not enough memory to add a triangle and */
1424                    /* nothing in the database, better free everything */
1425                    /* and try again */
1426                    actcMakeEmpty(tc);
1427                } else {
1428                    /* cleaned up and STILL couldn't get a triangle in; */
1429                    /* give up */
1430                    return tc->Error = ACTC_ALLOC_FAILED;
1431                }
1432                passesWithoutPrims++;
1433            }
1434            ACTC_CHECK(actcBeginInput(tc));
1435        } else
1436            ACTC_CHECK(r);
1437        if(r == ACTC_ALLOC_FAILED)
1438            curTriangle--;
1439    }
1440    ACTC_CHECK(actcEndInput(tc));
1441
1442    actcMakeEmpty(tc);
1443
1444    return curPrimitive;
1445}
1446
1447/* vi:tabstop=8
1448 */
Note: See TracBrowser for help on using the repository browser.