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 | |
---|
25 | typedef struct TableLevel3 |
---|
26 | { |
---|
27 | int EntryCount; |
---|
28 | void *Table[LEVEL3COUNT]; |
---|
29 | char IsSet[LEVEL3COUNT]; |
---|
30 | } TableLevel3; |
---|
31 | |
---|
32 | typedef struct TableLevel2 |
---|
33 | { |
---|
34 | int EntryCount; |
---|
35 | TableLevel3 *Table[LEVEL2COUNT]; |
---|
36 | } TableLevel2; |
---|
37 | |
---|
38 | typedef 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 | |
---|
47 | typedef struct TableIterator { |
---|
48 | int i1, i2, i3; |
---|
49 | unsigned int i; |
---|
50 | TableLevel3 *CurLevel3; |
---|
51 | int CheckLevel1, CheckLevel2; |
---|
52 | } TableIterator; |
---|
53 | |
---|
54 | TableRoot *tableNew(void) |
---|
55 | { |
---|
56 | TableRoot *tr; |
---|
57 | |
---|
58 | chartedSetLabel("table root"); |
---|
59 | tr = (TableRoot *)calloc(sizeof(TableRoot), 1); |
---|
60 | return tr; |
---|
61 | } |
---|
62 | |
---|
63 | TableIterator *tableNewIterator(void) |
---|
64 | { |
---|
65 | TableIterator *ti; |
---|
66 | |
---|
67 | chartedSetLabel("table iterator"); |
---|
68 | ti = (TableIterator *)malloc(sizeof(TableIterator)); |
---|
69 | return ti; |
---|
70 | } |
---|
71 | |
---|
72 | int 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 | |
---|
89 | int 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 | |
---|
122 | int 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 | |
---|
153 | void 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 | |
---|
163 | int 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 | |
---|
210 | void 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 | |
---|
234 | void 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 | |
---|
245 | size_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 | |
---|
277 | typedef struct { |
---|
278 | struct ACTCVertex *FinalVert; |
---|
279 | } ACTCTriangle; |
---|
280 | |
---|
281 | typedef struct { |
---|
282 | struct ACTCVertex *V2; |
---|
283 | int Count; |
---|
284 | int TriangleCount; |
---|
285 | ACTCTriangle *Triangles; |
---|
286 | } ACTCEdge; |
---|
287 | |
---|
288 | typedef 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 | |
---|
304 | struct _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 | |
---|
343 | static 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 | |
---|
360 | static 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 | |
---|
374 | static 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 | |
---|
414 | static 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 | |
---|
441 | void 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 | |
---|
451 | static int abortWithOptionalDump(ACTCData *tc) |
---|
452 | { |
---|
453 | ACTC_INFO(actcDumpState(tc, stderr)); |
---|
454 | abort(); |
---|
455 | } |
---|
456 | |
---|
457 | #endif /* defined(DEBUG) */ |
---|
458 | |
---|
459 | int actcGetError(ACTCData *tc) |
---|
460 | { |
---|
461 | int error = tc->Error; |
---|
462 | tc->Error = ACTC_NO_ERROR; |
---|
463 | return error; |
---|
464 | } |
---|
465 | |
---|
466 | static 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 | */ |
---|
489 | static 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 | |
---|
534 | static 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 | |
---|
579 | static 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 | |
---|
599 | static 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 | |
---|
616 | int actcGetIsDuringInput(ACTCData *tc) { |
---|
617 | return tc->IsInputting; |
---|
618 | } |
---|
619 | |
---|
620 | int 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 | |
---|
655 | int 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 | |
---|
674 | int actcGetIsDuringOutput(ACTCData *tc) { |
---|
675 | return tc->IsOutputting; |
---|
676 | } |
---|
677 | |
---|
678 | int 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 | |
---|
744 | int 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 | |
---|
772 | ACTCData *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 | |
---|
812 | static size_t allocatedForTriangles(ACTCEdge *e) |
---|
813 | { |
---|
814 | return sizeof(ACTCTriangle) * e->TriangleCount; |
---|
815 | } |
---|
816 | |
---|
817 | static 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 | |
---|
829 | static 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 | |
---|
854 | int 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 | |
---|
866 | static 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 | |
---|
877 | int 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 | |
---|
891 | void actcDelete(ACTCData *tc) |
---|
892 | { |
---|
893 | actcMakeEmpty(tc); |
---|
894 | free(tc->VertexIterator); |
---|
895 | free(tc->Vertices); |
---|
896 | free(tc); |
---|
897 | } |
---|
898 | |
---|
899 | int 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 | |
---|
961 | int 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 | |
---|
971 | int 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 | |
---|
1018 | int actcGetParamu(ACTCData *tc, int param, unsigned int *value) |
---|
1019 | { |
---|
1020 | return actcGetParami(tc, param, (int *)value); |
---|
1021 | } |
---|
1022 | |
---|
1023 | static 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, &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 | |
---|
1042 | static 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 | |
---|
1065 | static 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, &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 | |
---|
1099 | static 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 | |
---|
1127 | int 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 | |
---|
1173 | free8: |
---|
1174 | unmapEdgeTriangle(tc, edge23, vertexRec1); |
---|
1175 | free7: |
---|
1176 | unmapEdgeTriangle(tc, edge12, vertexRec3); |
---|
1177 | free6: |
---|
1178 | unmapVertexEdge(tc, vertexRec3, vertexRec1); |
---|
1179 | free5: |
---|
1180 | unmapVertexEdge(tc, vertexRec2, vertexRec3); |
---|
1181 | free4: |
---|
1182 | unmapVertexEdge(tc, vertexRec1, vertexRec2); |
---|
1183 | free3: |
---|
1184 | decVertexValence(tc, &vertexRec3); |
---|
1185 | free2: |
---|
1186 | decVertexValence(tc, &vertexRec2); |
---|
1187 | free1: |
---|
1188 | decVertexValence(tc, &vertexRec1); |
---|
1189 | returnError1: |
---|
1190 | return tc->Error; |
---|
1191 | } |
---|
1192 | |
---|
1193 | int 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 | |
---|
1249 | static 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 | |
---|
1261 | int 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 | |
---|
1271 | int 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 | |
---|
1360 | int 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 | */ |
---|