Index: /trunk/src/lib/graphics/importer/Makefile.am
===================================================================
--- /trunk/src/lib/graphics/importer/Makefile.am	(revision 6307)
+++ /trunk/src/lib/graphics/importer/Makefile.am	(revision 6308)
@@ -5,4 +5,5 @@
 
 libORXimporter_a_SOURCES = model.cc \
+			   tc.c \
                            vertex_array_model.cc \
                            static_model.cc \
@@ -18,4 +19,5 @@
 
 noinst_HEADERS = model.h \
+		 tc.h \
                  vertex_array_model.h \
                  static_model.h \
@@ -28,3 +30,3 @@
                  height_map.h \
                  anorms.h \
-                 anormtab.h
+                 anormtab.h 
Index: /trunk/src/lib/graphics/importer/model.h
===================================================================
--- /trunk/src/lib/graphics/importer/model.h	(revision 6307)
+++ /trunk/src/lib/graphics/importer/model.h	(revision 6308)
@@ -32,5 +32,5 @@
 typedef struct
 {
-  unsigned int   indexToVertices[3];   //!< index to the verteces of the triangle
+  unsigned int   indexToVertices[3];   //!< index to the vertices of the triangle
   unsigned int   indexToNormals[3];    //!< index to the normals of the triangle
   unsigned int   indexToTexCoor[3];    //!< index to the texture coordinates
@@ -83,5 +83,5 @@
     inline sTriangleExt* getTriangles() const { return this->pModelInfo.pTriangles; };
     /** @returns the Count of Faces of this Model */
-    inline unsigned int getFaceCount() const { return this->pModelInfo.numTriangles; };
+    inline unsigned int getTriangleCount() const { return this->pModelInfo.numTriangles; };
 
 
Index: /trunk/src/lib/graphics/importer/tc.COPYRIGHT
===================================================================
--- /trunk/src/lib/graphics/importer/tc.COPYRIGHT	(revision 6308)
+++ /trunk/src/lib/graphics/importer/tc.COPYRIGHT	(revision 6308)
@@ -0,0 +1,25 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. All advertising materials mentioning features or use of this software
+     must display the following acknowledgement:
+       This product includes software developed by Brad Grantham and
+       Applied Conjecture.
+  4. Neither the name Brad Grantham nor Applied Conjecture 
+     may be used to endorse or promote products derived from this software
+     without specific prior written permission.
+  5. Notification must be made to Brad Grantham about inclusion of this
+     software in a product including the author of the product and the name
+     and purpose of the product.  Notification can be made using email
+     to Brad Grantham's current address (grantham@plunk.org as of September
+     20th, 2000) or current U.S. mail address.
+
+$Header: /home/grantham/cvsroot/projects/modules/tc/COPYRIGHT,v 1.1 2000/09/21 19:36:56 grantham Exp $
+
+# vi:tabstop=8
+#
Index: /trunk/src/lib/graphics/importer/tc.c
===================================================================
--- /trunk/src/lib/graphics/importer/tc.c	(revision 6308)
+++ /trunk/src/lib/graphics/importer/tc.c	(revision 6308)
@@ -0,0 +1,1448 @@
+/*
+ * $Header: /home/grantham/cvsroot/projects/modules/tc/tc.c,v 1.27 2000/10/10 16:09:23 grantham Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "tc.h"
+
+/* SNIPPET "table.c" Inducted Wed Nov 22 09:36:55 2000 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(MEM_CHART)
+#define chartedSetLabel(a)
+#endif
+
+#define LEVEL1COUNT 16384
+#define LEVEL2COUNT 1024
+#define LEVEL3COUNT 256
+
+typedef struct TableLevel3
+{
+    int EntryCount;
+    void *Table[LEVEL3COUNT];
+    char IsSet[LEVEL3COUNT];
+} TableLevel3;
+
+typedef struct TableLevel2
+{
+    int EntryCount;
+    TableLevel3 *Table[LEVEL2COUNT];
+} TableLevel2;
+
+typedef struct TableRoot
+{
+    size_t EntryCount;
+    size_t TotalEntryCount;
+    size_t TotalAllocatedBytes;
+    int EmptyEntryCount;
+    TableLevel2 *Table[LEVEL1COUNT];
+} TableRoot;
+
+typedef struct TableIterator {
+    int i1, i2, i3;
+    uint i;
+    TableLevel3 *CurLevel3;
+    int CheckLevel1, CheckLevel2;
+} TableIterator;
+
+TableRoot *tableNew(void)
+{
+    TableRoot *tr;
+
+    chartedSetLabel("table root");
+    tr = (TableRoot *)calloc(sizeof(TableRoot), 1);
+    return tr;
+}
+
+TableIterator *tableNewIterator(void)
+{
+    TableIterator *ti;
+
+    chartedSetLabel("table iterator");
+    ti = (TableIterator *)malloc(sizeof(TableIterator));
+    return ti;
+}
+
+int tableRetrieve(uint a, TableRoot *table, void **ref)
+{
+    int i1 = a / (LEVEL2COUNT * LEVEL3COUNT);
+    int i2 = (a / LEVEL3COUNT) % LEVEL2COUNT;
+    int i3 = a % LEVEL3COUNT;
+
+    if(table->Table[i1] == NULL)
+        return 0;
+    if(table->Table[i1]->Table[i2] == NULL)
+        return 0;
+    if(!table->Table[i1]->Table[i2]->IsSet[i3])
+        return 0;
+    if(ref != NULL) 
+        *ref = table->Table[i1]->Table[i2]->Table[i3];
+    return 1;
+}
+
+int tableInsert(uint a, TableRoot *table, void *ref)
+{
+    int i1 = a / (LEVEL2COUNT * LEVEL3COUNT);
+    int i2 = (a / LEVEL3COUNT) % LEVEL2COUNT;
+    int i3 = a % LEVEL3COUNT;
+
+    if(table->Table[i1] == NULL) {
+	chartedSetLabel("table level 2");
+        table->Table[i1] = (TableLevel2 *)calloc(1, sizeof(TableLevel2));
+	table->TotalAllocatedBytes += sizeof(TableLevel2);
+        if(table->Table[i1] == NULL)
+            return 0;
+    }
+    if(table->Table[i1]->Table[i2] == NULL) {
+	chartedSetLabel("table level 3");
+        table->Table[i1]->Table[i2] =
+	    (TableLevel3 *)calloc(1, sizeof(TableLevel3));
+	table->TotalAllocatedBytes += sizeof(TableLevel3);
+        if(table->Table[i1]->Table[i2] == NULL)
+            return 0;
+	table->Table[i1]->EntryCount++;
+	table->TotalEntryCount += LEVEL3COUNT;
+	table->EmptyEntryCount += LEVEL3COUNT;
+    }
+    if(!table->Table[i1]->Table[i2]->IsSet[i3]) {
+	table->Table[i1]->Table[i2]->EntryCount++;
+	table->EmptyEntryCount --;
+	table->Table[i1]->Table[i2]->IsSet[i3] = 1;
+    }
+    table->Table[i1]->Table[i2]->Table[i3] = ref;
+    return 1;
+}
+
+int tableRemove(uint a, TableRoot *table, void **wasref)
+{
+    int i1 = a / (LEVEL2COUNT * LEVEL3COUNT);
+    int i2 = (a / LEVEL3COUNT) % LEVEL2COUNT;
+    int i3 = a % LEVEL3COUNT;
+
+    if(table->Table[i1] == NULL)
+	return 0;
+    if(table->Table[i1]->Table[i2] == NULL)
+	return 0;
+    if(!table->Table[i1]->Table[i2]->IsSet[i3])
+        return 0;
+    if(wasref != NULL)
+        *wasref = table->Table[i1]->Table[i2]->Table[i3];
+    table->Table[i1]->Table[i2]->IsSet[i3] = 0;
+    table->EmptyEntryCount ++;
+    if(--table->Table[i1]->Table[i2]->EntryCount == 0) {
+	table->EmptyEntryCount -= LEVEL3COUNT;
+	table->TotalEntryCount -= LEVEL3COUNT;
+	free(table->Table[i1]->Table[i2]);
+	table->TotalAllocatedBytes -= sizeof(TableLevel3);
+	table->Table[i1]->Table[i2] = NULL;
+	if(--table->Table[i1]->EntryCount == 0) {
+	    table->TotalAllocatedBytes -= sizeof(TableLevel2);
+	    free(table->Table[i1]);
+	    table->Table[i1] = NULL;
+	}
+    }
+    return 1;
+}
+
+void tableResetIterator(TableIterator *ti)
+{
+    ti->i1 = 0;
+    ti->i2 = 0;
+    ti->i3 = 0;
+    ti->i = 0;
+    ti->CheckLevel1 = 1;
+    ti->CheckLevel2 = 1;
+}
+
+int tableIterate(TableRoot *table, TableIterator *ti, uint *i, void **ref)
+{
+    int done;
+
+    done = 0;
+    while(ti->i1 < LEVEL1COUNT) {
+        if(ti->CheckLevel1 && table->Table[ti->i1] == NULL) {
+	    ti->i += LEVEL2COUNT * LEVEL3COUNT;
+	    ti->i1++;
+	    continue;
+	} else
+	    ti->CheckLevel1 = 0;
+        if(ti->CheckLevel2 && table->Table[ti->i1]->Table[ti->i2] == NULL) {
+	    ti->i += LEVEL3COUNT;
+	    if(++ti->i2 >= LEVEL2COUNT) {
+		ti->i2 = 0;
+		ti->i1++;
+		ti->CheckLevel1 = 1;
+	    }
+	    continue;
+	} else 
+	    ti->CheckLevel2 = 0;
+	if(ti->i3 == 0)
+	    ti->CurLevel3 = table->Table[ti->i1]->Table[ti->i2];
+	if(ti->CurLevel3->IsSet[ti->i3]) {
+	    if(ref != NULL)
+		*ref = ti->CurLevel3->Table[ti->i3];
+	    if(i != NULL)
+		*i = ti->i;
+	    done = 1;
+	}
+	ti->i++;
+	if(++ti->i3 >= LEVEL3COUNT) {
+	    ti->i3 = 0;
+	    ti->CheckLevel2 = 1;
+	    if(++ti->i2 >= LEVEL2COUNT) {
+		ti->i2 = 0;
+		ti->i1++;
+		ti->CheckLevel1 = 1;
+	    }
+	}
+	if(done)
+	    return 1;
+    }
+    return 0;
+}
+
+void tableDelete(TableRoot *table, void (*datumDelete)(void *datum))
+{
+    int i1, i2, i3;
+
+    for(i1 = 0; i1 < LEVEL1COUNT; i1++) {
+        if(table->Table[i1] != NULL) {
+	    for(i2 = 0; i2 < LEVEL2COUNT; i2++) {
+		if(table->Table[i1]->Table[i2] != NULL) {
+		    for(i3 = 0; i3 < LEVEL3COUNT; i3++) {
+			if(table->Table[i1]->Table[i2]->IsSet[i3])
+			    datumDelete(table->Table[i1]->Table[i2]->Table[i3]);
+		    }
+		    free(table->Table[i1]->Table[i2]);
+		}
+	    }
+	    free(table->Table[i1]);
+	    table->Table[i1] = NULL;
+	}
+    }
+    table->TotalEntryCount = 0;
+    table->EmptyEntryCount = 0;
+    table->TotalAllocatedBytes = 0;
+}
+
+void tableGetStats(TableRoot *table, size_t *totalBytes, size_t *emptyCount,
+    size_t *totalCount)
+{
+    if(emptyCount != NULL)
+        *emptyCount = table->EmptyEntryCount;
+    if(totalCount != NULL)
+        *totalCount = table->TotalEntryCount;
+    if(totalBytes != NULL)
+        *totalBytes = table->TotalAllocatedBytes;
+}
+
+size_t tableGetIteratorSize(void)
+{
+    return sizeof(TableIterator);
+}
+
+/* "table.c" ENDSNIPPET */
+
+#if !defined(MEM_CHART)
+#define chartedSetLabel(a)
+#endif
+
+#if defined(DEBUG)
+#define ACTC_DEBUG(a) a
+#else
+#define ACTC_DEBUG(a)
+#endif
+
+#if defined(INFO)
+#define ACTC_INFO(a) a
+#else
+#define ACTC_INFO(a)
+#endif
+
+
+#define ACTC_CHECK(a) \
+    { \
+        int theErrorNow; \
+	theErrorNow = (a); \
+	if(theErrorNow < 0) \
+	    return theErrorNow; \
+    }
+
+typedef struct {
+    struct ACTCVertex *FinalVert;
+} ACTCTriangle;
+
+typedef struct {
+    struct ACTCVertex *V2;
+    int Count;
+    int TriangleCount;
+    ACTCTriangle *Triangles;
+} ACTCEdge;
+
+typedef struct ACTCVertex {
+    uint V;
+    int Count;
+    struct ACTCVertex **PointsToMe;
+    struct ACTCVertex *Next;
+    int EdgeCount;
+    ACTCEdge *Edges;	
+} ACTCVertex;
+
+/* private tokens */
+#define ACTC_NO_MATCHING_VERT		-0x3000
+#define ACTC_FWD_ORDER			0
+#define ACTC_REV_ORDER			1
+
+#define MAX_STATIC_VERTS		10000000 /* buh? */
+
+struct _ACTCData {
+
+    /* vertex and edge database */
+    int VertexCount;
+    TableRoot *Vertices;
+    TableIterator *VertexIterator;
+    int CurMaxVertValence;
+    int CurMinVertValence;
+    ACTCVertex **VertexBins;
+
+    /* alternate vertex array if range small enough */
+    ACTCVertex *StaticVerts;
+    int UsingStaticVerts;
+    uint VertRange;
+
+    /* During consolidation */
+    int CurWindOrder;
+    int PrimType;
+    ACTCVertex *V1;
+    ACTCVertex *V2;
+    int VerticesSoFar;
+
+    /* Error and state handling */
+    int IsInputting;
+    int IsOutputting;
+    int Error;
+
+    /* actcParam-settable parameters */
+    uint MinInputVert;
+    uint MaxInputVert;
+    int MaxVertShare;
+    int MaxEdgeShare;
+    int MinFanVerts;
+    int MaxPrimVerts;
+    int HonorWinding;
+};
+
+#if defined(DEBUG) || defined(INFO)
+
+static void dumpTriangles(ACTCEdge *e, FILE *fp)
+{
+    int i;
+    int c;
+    char v[12];
+
+    c = fprintf(fp, "      %d triangles: ");
+    for(i = 0; i < e->TriangleCount; i++) {
+	if(c + 1 + sprintf(v, "%u", e->Triangles[i].FinalVert) > 78) {
+	    fputs("\n", fp);
+	    c = fprintf(fp, "        ");
+	}
+	c += fprintf(fp, " %s", v);
+    }
+    fputs("\n", fp);
+}
+
+static void dumpEdges(ACTCVertex *vert, FILE *fp)
+{
+    int i;
+    int c;
+    char v[26]; /* two signed ints plus x plus NUL */
+
+    for(i = 0; i < vert->EdgeCount; i++) {
+	fprintf(fp, "    %u->%u (%d times)\n", vert->V, vert->Edges[i].V2->V,
+	    vert->Edges[i].Count);
+	dumpTriangles(&vert->Edges[i], fp);
+    }
+    fputs("\n", fp);
+}
+
+static void dumpVertices(ACTCData *tc, FILE *fp)
+{
+    int i;
+    ACTCVertex *v;
+
+    if(!tc->UsingStaticVerts)
+        tableResetIterator(tc->VertexIterator);
+
+    fprintf(fp, "%d vertices in valences list\n", tc->VertexCount);
+    if(tc->UsingStaticVerts) {
+        for(i = 0; i < tc->VertRange; i++) {
+	    v = &tc->StaticVerts[i];
+	    if(v->Count > 0) {
+		fprintf(fp, "  vertex %u, valence %d, %d edges\n", v->V,
+		    v->Count, v->EdgeCount);
+		dumpEdges(v, fp);
+	    }
+	}
+    } else {
+	for(i = 0; i < tc->VertexCount; i++) {
+	    if(tableIterate(tc->Vertices, tc->VertexIterator, NULL,
+		(void **)&v) == 0) {
+		fprintf(fp, "ACTC::dumpVertices : fewer vertices in the table "
+		    "than we expected!\n");
+		fprintf(stderr, "ACTC::dumpVertices : fewer vertices in the table "
+		    "than we expected!\n");
+	    }
+	    if(v == NULL) {
+		fprintf(fp, "ACTC::dumpVertices : did not expect to get a NULL"
+		    "Vertex from the table iterator!\n");
+		fprintf(stderr, "ACTC::dumpVertices : did not expect to get a NULL"
+		    "Vertex from the table iterator!\n");
+	    }
+	    fprintf(fp, "  vertex %u, valence %d, %d edges\n", v->V, v->Count,
+		v->EdgeCount);
+	    dumpEdges(v, fp);
+	}
+    }
+}
+
+static void dumpVertexBins(ACTCData *tc, FILE *fp)
+{
+    ACTCVertex *cur;
+    int i;
+    int c;
+    char v[26]; /* two signed ints plus x plus NUL */
+
+    fprintf(fp, "vertex bins:\n");
+    if(tc->VertexBins == NULL) {
+        fprintf(fp, "        empty.\n");
+	return;
+    }
+    for(i = 1; i <= tc->CurMaxVertValence; i++) {
+        cur = tc->VertexBins[i];
+	c = fprintf(fp, "        bin %d -> ", i);
+	while(cur != NULL) {
+	    if(c + 1 + sprintf(v, "%ux%d", cur->V, cur->Count) > 78) {
+		fputs("\n", fp);
+		c = fprintf(fp, "          ");
+	    }
+	    c += fprintf(fp, " %s", v);
+	    cur = cur->Next;
+	}
+	fputs("\n", fp);
+    }
+}
+
+void actcDumpState(ACTCData *tc, FILE *fp)
+{
+    dumpVertices(tc, fp);
+    dumpVertexBins(tc, fp);
+}
+
+#endif /* DEBUG || INFO */
+
+#if defined(DEBUG)
+
+static int abortWithOptionalDump(ACTCData *tc)
+{
+    ACTC_INFO(actcDumpState(tc, stderr));
+    abort();
+}
+
+#endif /* defined(DEBUG) */
+
+int actcGetError(ACTCData *tc)
+{
+    int error = tc->Error;
+    tc->Error = ACTC_NO_ERROR;
+    return error;
+}
+
+static void *reallocAndAppend(void **ptr, uint *itemCount, size_t itemBytes,
+    void *append)
+{
+    void *t;
+
+    t = realloc(*ptr, itemBytes * (*itemCount + 1));
+    if(t == NULL)
+	return NULL;
+    *ptr = t;
+
+    memcpy((unsigned char *)*ptr + *itemCount * itemBytes, append, itemBytes);
+    (*itemCount) += 1;
+
+    return *ptr;
+}
+
+/*
+ * Call only during input; changes vertices' valences and does not
+ * fix the bins that are ordered by vertex valence.  (It's usually cheaper
+ * to traverse the vertex list once after all are added, since that's
+ * linear in the NUMBER OF UNIQUE VERTEX INDICES, which is almost always
+ * going to be less than the number of vertices.)
+ */
+static int incVertexValence(ACTCData *tc, uint v, ACTCVertex **found)
+{
+    ACTCVertex *vertex;
+
+    if(tc->UsingStaticVerts) {
+        vertex = &tc->StaticVerts[v];
+	vertex->Count++;
+	if(vertex->Count == 1) {
+	    vertex->V = v;
+	    tc->VertexCount++;
+	}
+    } else {
+	if(tableRetrieve(v, tc->Vertices, (void **)&vertex) == 1) {
+	    if(vertex->V != v) {
+		ACTC_DEBUG(
+		    fprintf(stderr, "ACTC::incVertexValence : Got vertex %d when "
+			"looking for vertex %d?!?\n", vertex->V, v);
+		    abortWithOptionalDump(tc);
+		)
+		return tc->Error = ACTC_DATABASE_CORRUPT;
+	    }
+	    vertex->Count++;
+	} else {
+	    chartedSetLabel("new Vertex");
+	    vertex = (ACTCVertex *)malloc(sizeof(ACTCVertex));
+	    vertex->V = v;
+	    vertex->Count = 1;
+	    vertex->Edges = NULL;
+	    vertex->EdgeCount = 0;
+	    if(tableInsert(v, tc->Vertices, vertex) == 0) {
+		ACTC_DEBUG(fprintf(stderr, "ACTC::incVertexValence : Failed "
+		    "to insert vertex into table\n");)
+		return tc->Error = ACTC_ALLOC_FAILED;
+	    }
+	    tc->VertexCount++;
+	}
+    }
+    if(vertex->Count > tc->CurMaxVertValence)
+	tc->CurMaxVertValence = vertex->Count;
+
+    *found = vertex;
+
+    return ACTC_NO_ERROR;
+}
+
+static int decVertexValence(ACTCData *tc, ACTCVertex **vptr)
+{
+    ACTCVertex *v = *vptr;
+
+    v->Count--;
+    if(v->Count < 0) {
+	ACTC_DEBUG(
+	    fprintf(stderr, "ACTC::decVertexValence : Valence went "
+		"negative?!?\n");
+	    abortWithOptionalDump(tc);
+	)
+	return tc->Error = ACTC_DATABASE_CORRUPT;
+    }
+    
+    if(v->PointsToMe != NULL) {
+	*v->PointsToMe = v->Next;
+	if(v->Next != NULL)
+	    v->Next->PointsToMe = v->PointsToMe;
+	v->Next = NULL;
+    }
+
+    if(v->Count == 0) {
+	tc->VertexCount--;
+	if(v->Edges != NULL)
+	    free(v->Edges);
+        if(!tc->UsingStaticVerts) {
+	    tableRemove(v->V, tc->Vertices, NULL);
+	    free(v);
+	}
+	*vptr = NULL;
+    } else {
+	if(tc->VertexBins != NULL) {
+	    v->Next = tc->VertexBins[v->Count];
+	    v->PointsToMe = &tc->VertexBins[v->Count];
+	    if(v->Next != NULL)
+		v->Next->PointsToMe = &v->Next;
+	    tc->VertexBins[v->Count] = v;
+	    if(v->Count < tc->CurMinVertValence)
+		tc->CurMinVertValence = v->Count;
+	}
+    }
+
+    return ACTC_NO_ERROR;
+}
+
+static int findNextFanVertex(ACTCData *tc, ACTCVertex **vert)
+{
+    if(tc->CurMaxVertValence < tc->MinFanVerts) {
+	return ACTC_NO_MATCHING_VERT;
+    }
+    while(tc->VertexBins[tc->CurMaxVertValence] == NULL) {
+	tc->CurMaxVertValence--;
+	if(tc->CurMaxVertValence < tc->CurMinVertValence) {
+	    if(tc->VertexCount > 0) {
+		ACTC_DEBUG(fprintf(stderr, "tc::findNextFanVertex : no more "
+		    "vertices in bins but VertexCount > 0\n");)
+		return tc->Error = ACTC_DATABASE_CORRUPT;
+	    }
+	    return ACTC_NO_MATCHING_VERT;
+	}
+    }
+    *vert = tc->VertexBins[tc->CurMaxVertValence];
+    return ACTC_NO_ERROR;
+}
+
+static int findNextStripVertex(ACTCData *tc, ACTCVertex **vert)
+{
+    while(tc->VertexBins[tc->CurMinVertValence] == NULL) {
+	tc->CurMinVertValence++;
+	if(tc->CurMinVertValence > tc->CurMaxVertValence) {
+	    if(tc->VertexCount > 0) {
+		ACTC_DEBUG(fprintf(stderr, "tc::findNextStripVertex : no more "
+		    "vertices in bins but VertexCount > 0\n");)
+		return tc->Error = ACTC_DATABASE_CORRUPT;
+	    }
+	    return ACTC_NO_MATCHING_VERT;
+	}
+    }
+    *vert = tc->VertexBins[tc->CurMinVertValence];
+    return ACTC_NO_ERROR;
+}
+
+int actcGetIsDuringInput(ACTCData *tc) {
+    return tc->IsInputting;
+}
+
+int actcBeginInput(ACTCData *tc)
+{
+    if(tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcBeginInput : called within "
+	    "BeginOutput/EndOutput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+
+    if(tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcBeginInput : called within "
+	    "BeginInput/EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+
+    tc->IsInputting = 1;
+    tc->CurMaxVertValence = 0;
+
+    if(tc->MaxInputVert < MAX_STATIC_VERTS - 1) {
+	size_t byteCount;
+	tc->UsingStaticVerts = 1;
+	tc->VertRange = tc->MaxInputVert + 1;
+	byteCount = sizeof(ACTCVertex) * tc->VertRange;
+	chartedSetLabel("static verts");
+	tc->StaticVerts = (ACTCVertex *)calloc(sizeof(ACTCVertex), tc->VertRange);
+	if(tc->StaticVerts == NULL) {
+	    ACTC_INFO(printf("Couldn't allocate static %d vert block of %u "
+		"bytes\n", tc->VertRange, byteCount);)
+	    tc->UsingStaticVerts = 0;
+	}
+    } else
+	tc->UsingStaticVerts = 0;
+
+    return ACTC_NO_ERROR;
+}
+
+int actcEndInput(ACTCData *tc)
+{
+    if(tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcEndInput : called within "
+	    "BeginOutput/EndOutput\n");)
+	return tc->Error = ACTC_DURING_OUTPUT;
+    }
+
+    if(!tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcEndInput : called outside "
+	    "BeginInput/EndInput\n");)
+	return tc->Error = ACTC_IDLE;
+    }
+
+    tc->IsInputting = 0;
+
+    return ACTC_NO_ERROR;
+}
+
+int actcGetIsDuringOutput(ACTCData *tc) {
+    return tc->IsOutputting;
+}
+
+int actcBeginOutput(ACTCData *tc)
+{
+    ACTCVertex *v;
+    int i;
+
+    if(tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : called within "
+	    "BeginInput/EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+
+    if(tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : called within "
+	    "BeginOutput/EndOutput\n");)
+	return tc->Error = ACTC_DURING_OUTPUT;
+    }
+
+    tc->IsOutputting = 1;
+
+    tc->CurMinVertValence = INT_MAX;
+    chartedSetLabel("vertex bins");
+    tc->VertexBins = (ACTCVertex **)calloc(sizeof(ACTCVertex *), tc->CurMaxVertValence + 1);
+    if(tc->VertexBins == NULL) {
+	ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : couldn't allocate %d bytes "
+	    "for Vertex Bins\n",
+	    sizeof(ACTCVertex *) * tc->CurMaxVertValence);)
+	return tc->Error = ACTC_ALLOC_FAILED;
+    }
+
+    if(tc->UsingStaticVerts) {
+        double edgeTotal;
+	for(i = 0; i < tc->VertRange; i++) {
+	    v = &tc->StaticVerts[i];
+	    if(v->Count > 0) {
+		v->Next = tc->VertexBins[v->Count];
+		v->PointsToMe = &tc->VertexBins[v->Count];
+		tc->VertexBins[v->Count] = v;
+		if(v->Next != NULL)
+		    v->Next->PointsToMe = &v->Next;
+		if(v->Count < tc->CurMinVertValence)
+		    tc->CurMinVertValence = v->Count;
+		edgeTotal += v->EdgeCount;
+	    }
+	}
+    } else {
+	tableResetIterator(tc->VertexIterator);
+	for(i = 0; i < tc->VertexCount; i++) {
+	    if(tableIterate(tc->Vertices, tc->VertexIterator, NULL, (void **)&v)
+		== 0) {
+		ACTC_DEBUG(fprintf(stderr, "actcBeginOutput : fewer vertices in "
+		    "the table than we expected!\n");)
+		return tc->Error = ACTC_DATABASE_CORRUPT;
+	    }
+	    v->Next = tc->VertexBins[v->Count];
+	    v->PointsToMe = &tc->VertexBins[v->Count];
+	    tc->VertexBins[v->Count] = v;
+	    if(v->Next != NULL)
+		v->Next->PointsToMe = &v->Next;
+	    if(v->Count < tc->CurMinVertValence)
+		tc->CurMinVertValence = v->Count;
+	}
+    }
+
+    return ACTC_NO_ERROR;
+}
+
+int actcEndOutput(ACTCData *tc)
+{
+    if(tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcEndOutput : called within "
+	    "BeginInput/EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+
+    if(!tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcEndOutput : called outside "
+	    "BeginOutput/EndOutput\n");)
+	return tc->Error = ACTC_IDLE;
+    }
+
+    tc->IsOutputting = 0;
+
+    if(tc->UsingStaticVerts) {
+	free(tc->StaticVerts);
+	tc->StaticVerts = NULL;
+	tc->UsingStaticVerts = 0;
+    }
+
+    free(tc->VertexBins);
+    tc->VertexBins = NULL;
+
+    return ACTC_NO_ERROR;
+}
+
+ACTCData *actcNew(void)
+{
+    ACTCData *tc;
+#if defined(DEBUG) || defined(INFO)
+    static int didPrintVersion = 0;
+
+    if(!didPrintVersion) {
+	int verMinor, verMajor;
+	didPrintVersion = 1;
+
+        actcGetParami(tc, ACTC_MAJOR_VERSION, &verMajor);
+        actcGetParami(tc, ACTC_MINOR_VERSION, &verMinor);
+	fprintf(stderr, "TC Version %d.%d\n", verMajor, verMinor);
+    }
+#endif /* defined(DEBUG) || defined(INFO) */
+
+    chartedSetLabel("the tc struct");
+    tc = (ACTCData *)calloc(sizeof(*tc), 1);
+
+    if(tc == NULL) {
+	ACTC_DEBUG(fprintf(stderr, "actcNew : couldn't allocate %d bytes "
+	    "for new ACTCData\n", sizeof(*tc));)
+	return NULL;
+    }
+
+    tc->Vertices = tableNew();
+    tc->VertexIterator = tableNewIterator();
+
+    tc->MinFanVerts = INT_MAX;
+    tc->MaxPrimVerts = INT_MAX;
+    tc->MaxInputVert = INT_MAX;
+    tc->MaxEdgeShare = INT_MAX;
+    tc->MaxVertShare = INT_MAX;
+    tc->HonorWinding = 1;
+    /* seed = 0 handled by calloc */
+    /* XXX grantham 20000615 - seed ignored for now */
+
+    return tc;
+}
+
+static size_t allocatedForTriangles(ACTCEdge *e)
+{
+    return sizeof(ACTCTriangle) * e->TriangleCount;
+}
+
+static size_t allocatedForEdges(ACTCVertex *vert)
+{
+    int i;
+    size_t size;
+
+    size = sizeof(ACTCEdge) * vert->EdgeCount;
+    for(i = 0; i < vert->EdgeCount; i++) {
+	size += allocatedForTriangles(&vert->Edges[i]);
+    }
+    return size;
+}
+
+static size_t allocatedForVertices(ACTCData *tc)
+{
+    int i;
+    int size;
+    ACTCVertex *v;
+
+    if(!tc->UsingStaticVerts)
+        tableResetIterator(tc->VertexIterator);
+
+    if(tc->UsingStaticVerts) {
+        size = tc->VertRange * sizeof(ACTCVertex);
+        for(i = 0; i < tc->VertRange; i++) {
+	    v = &tc->StaticVerts[i];
+	    if(v->Count > 0)
+	        size += allocatedForEdges(v);
+	}
+    } else {
+	for(i = 0; i < tc->VertexCount; i++) {
+	    tableIterate(tc->Vertices, tc->VertexIterator, NULL, (void **)&v);
+	    size += allocatedForEdges(v);
+	}
+    }
+    return size;
+}
+
+int actcGetMemoryAllocation(ACTCData *tc, size_t *bytesAllocated)
+{
+    size_t tableBytes;
+
+    tableGetStats(tc->Vertices, NULL, NULL, &tableBytes);
+    *bytesAllocated = sizeof(ACTCData);
+    *bytesAllocated += tableBytes;
+    *bytesAllocated += allocatedForVertices(tc); /* recurses */
+
+    return ACTC_NO_ERROR;
+}
+
+static void freeVertex(void *p)
+{
+    ACTCVertex *v = (ACTCVertex *)p;
+    int i;
+
+    for(i = 0; i < v->EdgeCount; i++)
+        free(v->Edges[i].Triangles);
+    free(v->Edges);
+    free(v);
+}
+
+int actcMakeEmpty(ACTCData *tc)
+{
+    tc->VertexCount = 0;
+    if(!tc->UsingStaticVerts)
+        tableDelete(tc->Vertices, freeVertex);
+    if(tc->VertexBins != NULL) {
+        free(tc->VertexBins);
+	tc->VertexBins = NULL;
+    }
+    tc->IsOutputting = 0;
+    tc->IsInputting = 0;
+    return ACTC_NO_ERROR;
+}
+
+void actcDelete(ACTCData *tc)
+{
+    actcMakeEmpty(tc);
+    free(tc->VertexIterator);
+    free(tc->Vertices);
+    free(tc);
+}
+
+int actcParami(ACTCData *tc, int param, int value)
+{
+    if(tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcParami : within BeginInput/"
+	    "EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+    if(tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcParami : within BeginOutput/"
+	    "EndOutput\n");)
+	return tc->Error = ACTC_DURING_OUTPUT;
+    }
+    switch(param) {
+	case ACTC_OUT_MIN_FAN_VERTS:
+	    tc->MinFanVerts = value;
+	    break;
+
+	case ACTC_IN_MAX_VERT:
+	    if(value < tc->MinInputVert) {
+		ACTC_DEBUG(fprintf(stderr, "actcParami : tried to set "
+		    "MAX_INPUT_VERT to %d, less than MIN_INPUT_VERT (%d)\n",
+		    value, tc->MinInputVert);)
+		return tc->Error = ACTC_INVALID_VALUE;
+	    }
+	    tc->MaxInputVert = value;
+	    break;
+
+	case ACTC_IN_MIN_VERT:
+	    if(value > tc->MaxInputVert) {
+		ACTC_DEBUG(fprintf(stderr, "actcParami : tried to set "
+		    "MIN_INPUT_VERT to %d, greater than MAX_INPUT_VERT (%d)\n",
+		    value, tc->MaxInputVert);)
+		return tc->Error = ACTC_INVALID_VALUE;
+	    }
+	    tc->MinInputVert = value;
+	    break;
+
+	case ACTC_IN_MAX_EDGE_SHARING:
+	    tc->MaxEdgeShare = value;
+	    break;
+
+	case ACTC_IN_MAX_VERT_SHARING:
+	    tc->MaxVertShare = value;
+	    break;
+
+	case ACTC_OUT_HONOR_WINDING:
+	    tc->HonorWinding = value;
+	    break;
+
+	case ACTC_OUT_MAX_PRIM_VERTS:
+	    if(value < 3) {
+		ACTC_DEBUG(fprintf(stderr, "actcParami : tried to set "
+		    "MAX_PRIM_VERTS to %d (needed to be 3 or more)\n", value);)
+		return tc->Error = ACTC_INVALID_VALUE;
+	    }
+	    tc->MaxPrimVerts = value;
+	    break;
+
+    }
+    return ACTC_NO_ERROR;
+}
+
+int actcParamu(ACTCData *tc, int param, uint value)
+{
+    /*
+     * XXX - yes, this is questionable, but I consulted industry
+     * experts and we agreed that most common behavior is to copy the
+     * bits directly, which is what I want.
+     */
+    return actcParami(tc, param, (int)value);
+}
+
+int actcGetParami(ACTCData *tc, int param, int *value)
+{
+    switch(param) {
+	case ACTC_MAJOR_VERSION:
+	    *value = 1;
+	    break;
+
+	case ACTC_MINOR_VERSION:
+	    *value = 1;
+	    break;
+
+	case ACTC_IN_MAX_VERT:
+	    *value = tc->MaxInputVert;
+	    break;
+
+	case ACTC_IN_MIN_VERT:
+	    *value = tc->MinInputVert;
+	    break;
+
+	case ACTC_IN_MAX_EDGE_SHARING:
+	    *value = tc->MaxEdgeShare;
+	    break;
+
+	case ACTC_IN_MAX_VERT_SHARING:
+	    *value = tc->MaxVertShare;
+	    break;
+
+	case ACTC_OUT_MIN_FAN_VERTS:
+	    *value = tc->MinFanVerts;
+	    break;
+
+	case ACTC_OUT_HONOR_WINDING:
+	    *value = tc->HonorWinding;
+	    break;
+
+	case ACTC_OUT_MAX_PRIM_VERTS:
+	    *value = tc->MaxPrimVerts;
+	    break;
+
+	default:
+	    *value = 0;
+	    return tc->Error = ACTC_INVALID_VALUE;
+	    /* break; */
+    }
+    return ACTC_NO_ERROR;
+}
+
+int actcGetParamu(ACTCData *tc, int param, uint *value)
+{
+    return actcGetParami(tc, param, (int *)value);
+}
+
+static int mapEdgeTriangle(ACTCData *tc, ACTCEdge *edge, ACTCVertex *v3)
+{
+    ACTCTriangle tmp;
+    void *r;
+
+    tmp.FinalVert = v3;
+    chartedSetLabel("triangle list");
+    r = reallocAndAppend((void **)&edge->Triangles, &edge->TriangleCount,
+        sizeof(tmp), &tmp);
+    if(r == NULL) {
+	ACTC_DEBUG(fprintf(stderr, "ACTC::mapEdgeTriangle : Couldn't allocate "
+	    "%d bytes for triangles\n", sizeof(tmp) *
+	    (edge->TriangleCount + 1));)
+	return tc->Error = ACTC_ALLOC_FAILED;
+    }
+
+    return ACTC_NO_ERROR;
+}
+
+static int unmapEdgeTriangle(ACTCData *tc, ACTCEdge *edge, ACTCVertex *v3)
+{
+    int i;
+
+    for(i = 0; i < edge->TriangleCount; i++)
+	if(edge->Triangles[i].FinalVert == v3)
+	    break;
+
+    if(i == edge->TriangleCount) {
+	ACTC_DEBUG(
+	    fprintf(stderr, "ACTC::unmapEdgeTriangle : Couldn't find third vertex"
+	        " from edge in order to delete it?!?\n");
+	    abortWithOptionalDump(tc);
+	)
+	return tc->Error = ACTC_DATABASE_CORRUPT;
+    }
+
+    edge->Triangles[i] = edge->Triangles[edge->TriangleCount - 1];
+    edge->TriangleCount --;
+
+    return ACTC_NO_ERROR;
+}
+
+static int mapVertexEdge(ACTCData *tc, ACTCVertex *v1, ACTCVertex *v2, ACTCEdge **edge)
+{
+    uint i;
+    ACTCEdge tmp;
+    void *r;
+
+    for(i = 0; i < v1->EdgeCount; i++)
+        if(v1->Edges[i].V2 == v2) {
+	    v1->Edges[i].Count++;
+	    break;
+	}
+
+    if(i == v1->EdgeCount) {
+
+	tmp.V2 = v2;
+	tmp.Count = 1;
+	tmp.Triangles = NULL;
+	tmp.TriangleCount = 0;
+
+	chartedSetLabel("vert-to-edge mapping");
+	r = reallocAndAppend((void **)&v1->Edges, &v1->EdgeCount,
+	    sizeof(tmp), &tmp);
+	if(r == NULL) {
+	    ACTC_DEBUG(fprintf(stderr, "ACTC::mapVertexEdge : Couldn't reallocate "
+	        "to %d bytes for vertex's edge list\n", sizeof(tmp) *
+		v1->EdgeCount);)
+	    return tc->Error = ACTC_ALLOC_FAILED;
+	}
+    }
+    *edge = &v1->Edges[i];
+
+    return ACTC_NO_ERROR;
+}
+
+static int unmapVertexEdge(ACTCData *tc, ACTCVertex *v1, ACTCVertex *v2)
+{
+    int i;
+
+    for(i = 0; i < v1->EdgeCount; i++)
+	if(v1->Edges[i].V2 == v2)
+	    break;
+
+    if(i == v1->EdgeCount) {
+	ACTC_DEBUG(
+	    fprintf(stderr, "ACTC::unmapVertexEdge : Couldn't find edge %d,%d"
+	        " from vertex in order to unmap it?!?\n", v1->V, v2->V);
+	    abortWithOptionalDump(tc);
+	)
+	return tc->Error = ACTC_DATABASE_CORRUPT;
+    }
+
+    v1->Edges[i].Count --;
+    if(v1->Edges[i].Count == 0) {
+        if(v1->Edges[i].Triangles != NULL)
+	    free(v1->Edges[i].Triangles);
+	v1->Edges[i] = v1->Edges[v1->EdgeCount - 1];
+	v1->EdgeCount --;
+    }
+
+    return ACTC_NO_ERROR;
+}
+
+int actcAddTriangle(ACTCData *tc, uint v1, uint v2, uint v3)
+{
+    ACTCVertex *vertexRec1;
+    ACTCVertex *vertexRec2;
+    ACTCVertex *vertexRec3;
+
+    ACTCEdge *edge12;
+    ACTCEdge *edge23;
+    ACTCEdge *edge31;
+
+    if(tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcAddTriangle : inside "
+	    "BeginOutput/EndOutput\n");)
+	return tc->Error = ACTC_IDLE;
+    }
+    if(!tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcAddTriangle : outside "
+	    "BeginInput/EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+
+    if(incVertexValence(tc, v1, &vertexRec1) != ACTC_NO_ERROR) goto returnError1;
+    if(incVertexValence(tc, v2, &vertexRec2) != ACTC_NO_ERROR) goto free1;
+    if(incVertexValence(tc, v3, &vertexRec3) != ACTC_NO_ERROR) goto free2;
+
+    if(mapVertexEdge(tc, vertexRec1, vertexRec2, &edge12) != ACTC_NO_ERROR)
+        goto free3;
+    if(mapVertexEdge(tc, vertexRec2, vertexRec3, &edge23) != ACTC_NO_ERROR)
+        goto free4;
+    if(mapVertexEdge(tc, vertexRec3, vertexRec1, &edge31) != ACTC_NO_ERROR)
+        goto free5;
+
+    if(mapEdgeTriangle(tc, edge12, vertexRec3) != ACTC_NO_ERROR) goto free6;
+    if(mapEdgeTriangle(tc, edge23, vertexRec1) != ACTC_NO_ERROR) goto free7;
+    if(mapEdgeTriangle(tc, edge31, vertexRec2) != ACTC_NO_ERROR) goto free8;
+
+    return ACTC_NO_ERROR;
+
+    /*
+     * XXX Unfortunately, while backing out during the following
+     * statements, we might encounter errors in the database which
+     * will not get returned properly to the caller; I take heart in
+     * the fact that if such an error occurs, TC is just a moment from
+     * core dumping anyway. XXX grantham 20000615
+     */
+
+free8:
+    unmapEdgeTriangle(tc, edge23, vertexRec1);
+free7:
+    unmapEdgeTriangle(tc, edge12, vertexRec3);
+free6:
+    unmapVertexEdge(tc, vertexRec3, vertexRec1);
+free5:
+    unmapVertexEdge(tc, vertexRec2, vertexRec3);
+free4:
+    unmapVertexEdge(tc, vertexRec1, vertexRec2);
+free3:
+    decVertexValence(tc, &vertexRec3);
+free2:
+    decVertexValence(tc, &vertexRec2);
+free1:
+    decVertexValence(tc, &vertexRec1);
+returnError1:
+    return tc->Error;
+}
+
+int actcStartNextPrim(ACTCData *tc, uint *v1Return, uint *v2Return)
+{
+    ACTCVertex *v1 = NULL;
+    ACTCVertex *v2 = NULL;
+    int findResult;
+
+    if(tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : within "
+	    "BeginInput/EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+    if(!tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : outside "
+	    "BeginOutput/EndOutput\n");)
+	return tc->Error = ACTC_IDLE;
+    }
+
+    findResult = findNextFanVertex(tc, &v1);
+    if(findResult == ACTC_NO_ERROR)
+	tc->PrimType = ACTC_PRIM_FAN;
+    else if(findResult != ACTC_NO_MATCHING_VERT) {
+	ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : internal "
+	    "error finding next appropriate vertex\n");)
+	return tc->Error = findResult;
+    } else {
+	findResult = findNextStripVertex(tc, &v1);
+	if(findResult != ACTC_NO_ERROR && findResult != ACTC_NO_MATCHING_VERT) {
+	    ACTC_DEBUG(fprintf(stderr, "actcStartNextPrim : internal "
+		"error finding next appropriate vertex\n");)
+	    return tc->Error = findResult;
+	}
+	tc->PrimType = ACTC_PRIM_STRIP;
+    }
+
+    if(findResult == ACTC_NO_MATCHING_VERT) {
+	*v1Return = -1;
+	*v2Return = -1;
+	return tc->Error = ACTC_DATABASE_EMPTY;
+    }
+
+    v2 = v1->Edges[0].V2;
+
+    tc->CurWindOrder = ACTC_FWD_ORDER;
+    tc->VerticesSoFar = 2;
+
+    tc->V1 = v1;
+    tc->V2 = v2;
+
+    *v1Return = v1->V;
+    *v2Return = v2->V;
+
+    ACTC_INFO(printf("starting with edge %u, %u\n", tc->V1->V, tc->V2->V);)
+
+    return tc->PrimType;
+}
+
+static int findEdge(ACTCVertex *v1, ACTCVertex *v2, ACTCEdge **edge)
+{
+    int i;
+
+    for(i = 0; i < v1->EdgeCount; i++)
+        if(v1->Edges[i].V2 == v2) {
+	    *edge = &v1->Edges[i];
+	    return 1;
+	}
+    return 0;
+}
+
+int unmapEdgeTriangleByVerts(ACTCData *tc, ACTCVertex *v1, ACTCVertex *v2,
+    ACTCVertex *v3)
+{
+    ACTCEdge *e;
+
+    ACTC_CHECK(findEdge(v1, v2, &e));
+    unmapEdgeTriangle(tc, e, v3);
+    return ACTC_NO_ERROR;
+}
+
+int actcGetNextVert(ACTCData *tc, uint *vertReturn)
+{
+    ACTCEdge *edge;
+    int wasEdgeFound = 0;
+    ACTCVertex *thirdVertex;
+    int wasFoundReversed;
+
+    if(tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcGetNextVert : within BeginInput/"
+	    "EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+    if(!tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcGetNextVert : outside BeginOutput/"
+	    "EndOutput\n");)
+	return tc->Error = ACTC_IDLE;
+    }
+    if(tc->PrimType == -1) {
+	ACTC_DEBUG(fprintf(stderr, "actcGetNextVert : Asked for next vertex "
+	    "without a primitive (got last\n    vertex already?)\n");)
+	return tc->Error = ACTC_INVALID_VALUE;
+    }
+
+    if(tc->VerticesSoFar >= tc->MaxPrimVerts) {
+	tc->PrimType = -1;
+	return tc->Error = ACTC_PRIM_COMPLETE;
+    }
+
+    if(tc->V1 == NULL || tc->V2 == NULL) {
+	tc->PrimType = -1;
+	return tc->Error = ACTC_PRIM_COMPLETE;
+    }
+
+    ACTC_INFO(printf("looking for edge %u, %u\n", tc->V1->V, tc->V2->V);)
+
+    wasFoundReversed = 0;
+
+    if(findEdge(tc->V1, tc->V2, &edge) != 0) {
+	wasEdgeFound = 1;
+    } else if(!tc->HonorWinding) {
+	wasFoundReversed = 1;
+	if(findEdge(tc->V2, tc->V1, &edge) != 0) {
+	    wasEdgeFound = 1;
+	}
+    }
+
+    if(!wasEdgeFound) {
+	tc->PrimType = -1;
+	return tc->Error = ACTC_PRIM_COMPLETE;
+    }
+
+    thirdVertex = edge->Triangles[edge->TriangleCount - 1].FinalVert;
+
+    ACTC_INFO(printf("third vertex = %u\n", thirdVertex->V);)
+    *vertReturn = thirdVertex->V;
+
+    if(wasFoundReversed) {
+	ACTC_CHECK(unmapEdgeTriangle(tc, edge, thirdVertex));
+	ACTC_CHECK(unmapEdgeTriangleByVerts(tc, tc->V1, thirdVertex, tc->V2));
+	ACTC_CHECK(unmapEdgeTriangleByVerts(tc, thirdVertex, tc->V2, tc->V1));
+	ACTC_CHECK(unmapVertexEdge(tc, tc->V2, tc->V1));
+	ACTC_CHECK(unmapVertexEdge(tc, tc->V1, thirdVertex));
+	ACTC_CHECK(unmapVertexEdge(tc, thirdVertex, tc->V2));
+    } else {
+	ACTC_CHECK(unmapEdgeTriangle(tc, edge, thirdVertex));
+	ACTC_CHECK(unmapEdgeTriangleByVerts(tc, tc->V2, thirdVertex, tc->V1));
+	ACTC_CHECK(unmapEdgeTriangleByVerts(tc, thirdVertex, tc->V1, tc->V2));
+	ACTC_CHECK(unmapVertexEdge(tc, tc->V1, tc->V2));
+	ACTC_CHECK(unmapVertexEdge(tc, tc->V2, thirdVertex));
+	ACTC_CHECK(unmapVertexEdge(tc, thirdVertex, tc->V1));
+    }
+    ACTC_CHECK(decVertexValence(tc, &tc->V1));
+    ACTC_CHECK(decVertexValence(tc, &tc->V2));
+    ACTC_CHECK(decVertexValence(tc, &thirdVertex));
+
+    if(tc->PrimType == ACTC_PRIM_FAN) {
+        tc->V2 = thirdVertex;
+    } else /* PRIM_STRIP */ {
+	if(tc->CurWindOrder == ACTC_FWD_ORDER)
+	    tc->V1 = thirdVertex;
+	else
+	    tc->V2 = thirdVertex;
+	tc->CurWindOrder = !tc->CurWindOrder;
+    }
+
+    tc->VerticesSoFar++;
+    return ACTC_NO_ERROR;
+}
+
+int actcTrianglesToPrimitives(ACTCData *tc, int triangleCount,
+    uint (*triangles)[3], int primTypes[], int primLengths[], uint vertices[],
+    int maxBatchSize)
+{
+    int r;
+    int curTriangle;
+    int curPrimitive;
+    uint curVertex;
+    int prim;
+    uint v1, v2, v3;
+    int lastPrim;
+    int passesWithoutPrims;
+    int trisSoFar;
+
+    if(tc->IsInputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcTrianglesToPrimitives : within BeginInput/"
+	    "EndInput\n");)
+	return tc->Error = ACTC_DURING_INPUT;
+    }
+    if(tc->IsOutputting) {
+	ACTC_DEBUG(fprintf(stderr, "actcTrianglesToPrimitives : within"
+	    "BeginOutput/EndOutput\n");)
+	return tc->Error = ACTC_DURING_OUTPUT;
+    }
+    curTriangle = 0;
+    curPrimitive = 0;
+    curVertex = 0;
+    passesWithoutPrims = 0;
+
+    actcMakeEmpty(tc);
+
+    ACTC_CHECK(actcBeginInput(tc));
+    trisSoFar = 0;
+    while(curTriangle < triangleCount) {
+	r = actcAddTriangle(tc, triangles[curTriangle][0],
+	    triangles[curTriangle][1], triangles[curTriangle][2]);
+	trisSoFar++;
+	curTriangle++;
+	if((trisSoFar >= maxBatchSize) ||
+	    (r == ACTC_ALLOC_FAILED && curTriangle != triangleCount) ||
+	    (r == ACTC_NO_ERROR && curTriangle == triangleCount)) {
+
+	    /* drain what we got */
+	    trisSoFar = 0;
+	    ACTC_CHECK(actcEndInput(tc));
+	    ACTC_CHECK(actcBeginOutput(tc));
+	    lastPrim = curPrimitive;
+	    while((prim = actcStartNextPrim(tc, &v1, &v2)) != ACTC_DATABASE_EMPTY) {
+		ACTC_CHECK(prim);
+		primTypes[curPrimitive] = prim;
+		primLengths[curPrimitive] = 2;
+		vertices[curVertex++] = v1;
+		vertices[curVertex++] = v2;
+		while((r = actcGetNextVert(tc, &v3)) != ACTC_PRIM_COMPLETE) {
+		    ACTC_CHECK(r);
+		    vertices[curVertex++] = v3;
+		    primLengths[curPrimitive]++;
+		}
+		curPrimitive++;
+	    }
+	    ACTC_CHECK(actcEndOutput(tc));
+	    if(r == ACTC_ALLOC_FAILED && curPrimitive == lastPrim) {
+	        if(passesWithoutPrims == 0) {
+		    /* not enough memory to add a triangle and */
+		    /* nothing in the database, better free everything */
+		    /* and try again */
+		    actcMakeEmpty(tc);
+		} else {
+		    /* cleaned up and STILL couldn't get a triangle in; */
+		    /* give up */
+		    return tc->Error = ACTC_ALLOC_FAILED;
+		}
+		passesWithoutPrims++;
+	    }
+	    ACTC_CHECK(actcBeginInput(tc));
+	} else
+	    ACTC_CHECK(r);
+	if(r == ACTC_ALLOC_FAILED)
+	    curTriangle--;
+    }
+    ACTC_CHECK(actcEndInput(tc));
+
+    actcMakeEmpty(tc);
+
+    return curPrimitive;
+}
+
+/* vi:tabstop=8
+ */
Index: /trunk/src/lib/graphics/importer/tc.h
===================================================================
--- /trunk/src/lib/graphics/importer/tc.h	(revision 6308)
+++ /trunk/src/lib/graphics/importer/tc.h	(revision 6308)
@@ -0,0 +1,77 @@
+/*
+ * $Header: /home/grantham/cvsroot/projects/modules/tc/tc.h,v 1.14 2000/10/03 07:19:20 grantham Exp $
+ */
+
+#if !defined(_ACTC_H_)
+#define _ACTC_H_
+
+#include <sys/types.h>
+
+typedef struct _ACTCData ACTCData;
+
+/*
+    Abbreviated:
+    	vertex		vert
+	primitive	prim
+	maximum		max
+	minimum		min
+	parameter	param
+ */
+
+#define ACTC_NO_ERROR			0
+#define ACTC_ALLOC_FAILED		-0x2000
+#define ACTC_DURING_INPUT		-0x2001
+#define ACTC_DURING_OUTPUT		-0x2002
+#define ACTC_IDLE			-0x2003
+#define ACTC_INVALID_VALUE		-0x2004
+#define ACTC_DATABASE_EMPTY		-0x2005
+#define ACTC_DATABASE_CORRUPT		-0x2006
+#define ACTC_PRIM_COMPLETE		-0x2007
+
+#define ACTC_OUT_MIN_FAN_VERTS		0x1000
+#define ACTC_OUT_HONOR_WINDING		0x1001
+#define ACTC_OUT_MAX_PRIM_VERTS		0x1004
+#define ACTC_IN_MIN_VERT		0x1005
+#define ACTC_IN_MAX_VERT		0x1006
+#define ACTC_IN_MAX_VERT_SHARING	0x1007
+#define ACTC_IN_MAX_EDGE_SHARING	0x1008
+#define ACTC_MINOR_VERSION		0x1009
+#define ACTC_MAJOR_VERSION		0x1010
+
+#define ACTC_PRIM_FAN			0x2000
+#define ACTC_PRIM_STRIP			0x2001
+
+#define ACTC_TRUE			1
+#define ACTC_FALSE			0
+
+ACTCData *actcNew(void);
+int actcParami(ACTCData *tc, int param, int value);
+int actcGetParami(ACTCData *tc, int param, int *value);
+int actcParamu(ACTCData *tc, int param, uint value);
+int actcGetParamu(ACTCData *tc, int param, uint *value);
+int actcGetError(ACTCData *tc);
+int actcMakeEmpty(ACTCData *tc);
+void actcDelete(ACTCData *tc);
+void actcDumpState(ACTCData *tc, FILE *fp);
+
+int actcBeginInput(ACTCData *tc);
+int actcGetIsDuringInput(ACTCData *tc);
+int actcAddTriangle(ACTCData *tc, uint v1, uint v2, uint v3);
+int actcEndInput(ACTCData *tc);
+
+int actcBeginOutput(ACTCData *tc);
+int actcGetIsDuringOutput(ACTCData *tc);
+int actcStartNextPrim(ACTCData *tc, uint *v1Return, uint *v2Return);
+int actcGetNextVert(ACTCData *tc, uint *vReturn);
+int actcEndOutput(ACTCData *tc);
+
+int actcGetMemoryAllocation(ACTCData *tc, size_t *bytesAllocated);
+
+int actcTrianglesToPrimitives(ACTCData *tc, int triangleCount,
+    uint (*triangles)[3], int primTypes[], int primLengths[], uint vertices[],
+    int maxBatchSize);
+
+#endif /* _ACTC_H_ */
+
+/* vi:tabstop=8
+ */
Index: /trunk/src/lib/graphics/importer/vertex_array_model.cc
===================================================================
--- /trunk/src/lib/graphics/importer/vertex_array_model.cc	(revision 6307)
+++ /trunk/src/lib/graphics/importer/vertex_array_model.cc	(revision 6308)
@@ -21,4 +21,6 @@
 #include <stdarg.h>
 
+#include "tc.h"
+
 using namespace std;
 
@@ -39,7 +41,62 @@
 }
 
-
-/**
- * @brief deletes an VertexArrayModel.
+/**
+ * @brief special copy constructor for converting Models to VertexArray-Stripes
+ * @param model the Model to produce a VertexArray model from.
+ *
+ * Code that uses Brad Granthams
+ * excelent TC-code for generating stripes out of a mix of ModelCoordinates.
+ */
+VertexArrayModel::VertexArrayModel(const Model& model)
+{
+  this->setClassID(CL_MODEL, "VertexArrayModel");
+  this->bFinalized = false;
+  this->newStripe();
+
+  for (unsigned int i = 0; i < model.getVertexCount(); i+=3)
+    this->addVertex(model.getVertexArray()[i], model.getVertexArray()[i+1], model.getVertexArray()[i+2]);
+  for (unsigned int i = 0; i < model.getNormalsCount(); i+=3)
+    this->addNormal(model.getNormalsArray()[i], model.getNormalsArray()[i+1], model.getNormalsArray()[i+2]);
+  for (unsigned int i = 0; i < model.getTexCoordCount(); i+=2)
+    this->addTexCoor(model.getTexCoordArray()[i], model.getTexCoordArray()[i+1]);
+
+  // The acTC object generating this Model. //
+  ACTCData *tc;
+  tc = actcNew();
+  if(tc == NULL) {
+    /* memory allocation failed */
+    /* print error here and exit or whatever */
+  }
+
+  // inputing the data of model to the tc
+  actcBeginInput(tc);
+  for(unsigned int i = 0; i < model.getTriangleCount(); i++)
+      actcAddTriangle(tc, model.getTriangles()[i].indexToVertices[0], model.getTriangles()[i].indexToVertices[1], model.getTriangles()[i].indexToVertices[2]);
+  actcEndInput(tc);
+
+  // importing the data to the new Model.
+  int prim;
+  unsigned int v1, v2, v3;
+
+  actcBeginOutput(tc);
+  while((prim = actcStartNextPrim(tc, &v1, &v2) != ACTC_DATABASE_EMPTY))
+  {
+    this->addIndice(v1);
+    this->addIndice(v2);
+    /* start a primitive of type "prim" with v1 and v2 */
+    while(actcGetNextVert(tc, &v3) != ACTC_PRIM_COMPLETE)
+    {
+      /* continue primitive using v3 */
+      this->addIndice(v3);
+    }
+    this->newStripe();
+  }
+  actcEndOutput(tc);
+
+  this->finalize();
+}
+
+/**
+ * @brief deletes a VertexArrayModel.
  *
  * Looks if any from model allocated space is still in use, and if so deleted it.
@@ -75,5 +132,5 @@
   glVertexPointer(3, GL_FLOAT, 0, this->vertices.getArray());
   glNormalPointer(GL_FLOAT, 0, this->normals.getArray());
-  glTexCoordPointer(2, GL_FLOAT, 0, this->texCoords.getArray());  
+  glTexCoordPointer(2, GL_FLOAT, 0, this->texCoords.getArray());
 
   for (GLuint i = 1; i < this->stripes.size(); ++i)
Index: /trunk/src/lib/graphics/importer/vertex_array_model.h
===================================================================
--- /trunk/src/lib/graphics/importer/vertex_array_model.h	(revision 6307)
+++ /trunk/src/lib/graphics/importer/vertex_array_model.h	(revision 6308)
@@ -29,4 +29,5 @@
  public:
   VertexArrayModel();
+  VertexArrayModel(const Model& model);
   virtual ~VertexArrayModel();
 
@@ -43,5 +44,5 @@
   void finalize();
 
-  // 
+  //
   void planeModel();
 
Index: /trunk/src/lib/particles/particle_system.cc
===================================================================
--- /trunk/src/lib/particles/particle_system.cc	(revision 6307)
+++ /trunk/src/lib/particles/particle_system.cc	(revision 6308)
@@ -386,5 +386,5 @@
     case PARTICLE_MODEL:
       if (this->getModel(0))
-        return this->count * this->getModel()->getFaceCount();
+        return this->count * this->getModel()->getTriangleCount();
       break;
   }
