[6455] | 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 | uint 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(uint 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(uint 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(uint 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, uint *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 | uint 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 | uint 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 | uint MinInputVert; |
---|
| 333 | uint 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, uint *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, uint 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, uint 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, uint *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, (uint*)&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 | uint 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, (uint*)&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, uint v1, uint v2, uint 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, uint *v1Return, uint *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, uint *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 | uint (*triangles)[3], int primTypes[], int primLengths[], uint vertices[], |
---|
| 1362 | int maxBatchSize) |
---|
| 1363 | { |
---|
| 1364 | int r; |
---|
| 1365 | int curTriangle; |
---|
| 1366 | int curPrimitive; |
---|
| 1367 | uint curVertex; |
---|
| 1368 | int prim; |
---|
| 1369 | uint 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 | */ |
---|