From 6b36390bdc344af7c13619754f7043fb9d5f75d4 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 10 Jan 2019 10:17:53 +0100 Subject: [PATCH] implemented simple tri stripping --- src/ps2/ps2.cpp | 268 ++++++++++++++++++++++++++++++++++++++++----- src/ps2/rwps2.h | 5 +- src/rwobjects.h | 2 +- src/tristrip.cpp | 279 ++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 501 insertions(+), 53 deletions(-) diff --git a/src/ps2/ps2.cpp b/src/ps2/ps2.cpp index a6c097d..499b711 100644 --- a/src/ps2/ps2.cpp +++ b/src/ps2/ps2.cpp @@ -21,6 +21,8 @@ namespace rw { namespace ps2 { +#define ALIGNPTR(p,a) ((uint8*)(((uintptr)(p)+a-1) & ~(uintptr)(a-1))) + static void* driverOpen(void *o, int32, int32) { @@ -63,7 +65,7 @@ destroyNativeData(void *object, int32, int32) return object; InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData; for(uint32 i = 0; i < header->numMeshes; i++) - rwFree(header->instanceMeshes[i].data); + rwFree(header->instanceMeshes[i].dataRaw); rwFree(header->instanceMeshes); rwFree(header); geometry->instData = nil; @@ -96,8 +98,8 @@ readNativeData(Stream *stream, int32, void *object, int32, int32) uint32 buf[2]; stream->read(buf, 8); instance->dataSize = buf[0]; -// TODO: force alignment - instance->data = rwNewT(uint8, instance->dataSize, MEMDUR_EVENT | ID_GEOMETRY); + instance->dataRaw = rwNewT(uint8, instance->dataSize+0x7F, MEMDUR_EVENT | ID_GEOMETRY); + instance->data = ALIGNPTR(instance->dataRaw, 0x80); #ifdef RW_PS2 uint32 a = (uint32)instance->data; assert(a % 0x10 == 0); @@ -458,20 +460,24 @@ MatPipeline::dump(void) } void -MatPipeline::setTriBufferSizes(uint32 inputStride, uint32 stripCount) +MatPipeline::setTriBufferSizes(uint32 inputStride, uint32 bufferSize) { - this->inputStride = inputStride; - this->triListCount = stripCount/12*12; PipeAttribute *a; + + this->inputStride = inputStride; + uint32 numTLtris = bufferSize/3; + this->triListCount = (numTLtris & ~3) * 3; + this->triStripCount = bufferSize & ~3; for(uint i = 0; i < nelem(this->attribs); i++){ a = this->attribs[i]; - if(a && a->attrib & AT_RW) - goto brokenout; + if(a && a->attrib & AT_RW){ + // broken out attribs have different requirement + // because we have to be able to restart a strip + // at an aligned offset + this->triStripCount = ((bufferSize-2) & ~3)+2; + return; + } } - this->triStripCount = stripCount/4*4; - return; -brokenout: - this->triStripCount = (stripCount-2)/4*4+2; } // Instance format: @@ -514,14 +520,27 @@ enum { DMAret = 0x60000000, VIF_NOP = 0, - VIF_STCYCL = 0x01000100, // WL = 1 + VIF_STCYCL = 0x01000000, + VIF_STCYCL1 = 0x01000100, // WL = 1 + VIF_OFFSET = 0x02000000, + VIF_BASE = 0x03000000, VIF_ITOP = 0x04000000, VIF_STMOD = 0x05000000, VIF_MSKPATH3 = 0x06000000, VIF_MARK = 0x07000000, + VIF_FLUSHE = 0x10000000, VIF_FLUSH = 0x11000000, + VIF_FLUSHA = 0x13000000, + VIF_MSCAL = 0x14000000, VIF_MSCALF = 0x15000000, - VIF_MSCNT = 0x17000000 + VIF_MSCNT = 0x17000000, + VIF_STMASK = 0x20000000, + VIF_STROW = 0x30000000, + VIF_STCOL = 0x31000000, + VIF_MPG = 0x4A000000, + VIF_DIRECT = 0x50000000, + VIF_DIRECTHL = 0x51000000, + VIF_UNPACK = 0x60000000 // no mode encoded }; struct InstMeshInfo @@ -595,8 +614,10 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m) InstMeshInfo im = getInstMeshInfo(this, g, m); inst->dataSize = (im.size+im.size2)<<4; - // TODO: force alignment - inst->data = rwNewT(uint8, inst->dataSize, MEMDUR_EVENT | ID_GEOMETRY); + // TODO: do this properly, just a test right now + inst->dataSize += 0x7F; + inst->dataRaw = rwNewT(uint8, inst->dataSize, MEMDUR_EVENT | ID_GEOMETRY); + inst->data = ALIGNPTR(inst->dataRaw, 0x80); /* make array of addresses of broken out sections */ uint8 *datap[nelem(this->attribs)]; @@ -630,12 +651,17 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m) uint32 atsz = attribSize(a->attrib); *p++ = DMAref | QWC(nverts*atsz); *p++ = im.attribPos[i]; - *p++ = VIF_STCYCL | this->inputStride; + *p++ = VIF_STCYCL1 | this->inputStride; // Round up nverts so UNPACK will fit exactly into the DMA packet // (can't pad with zeroes in broken out sections). - // TODO: check for clash with vifOffset somewhere + int num = (QWC(nverts*atsz)<<4)/atsz; *p++ = (a->attrib&0xFF004000) - | 0x8000 | (QWC(nverts*atsz)<<4)/atsz << 16 | i; // UNPACK + | 0x8000 | num << 16 | i; // UNPACK + // This probably shouldn't happen. + if(num*this->inputStride > this->vifOffset) + fprintf(stderr, "WARNING: PS2 instance data over vifOffset %08X, %X-> %X %X\n", + p[-1], num, + num*this->inputStride, this->vifOffset); *p++ = DMAcnt; *p++ = 0x0; @@ -660,7 +686,7 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m) else *p++ = VIF_MARK | markcnt++; *p++ = VIF_STMOD; - *p++ = VIF_STCYCL | this->inputStride; + *p++ = VIF_STCYCL1 | this->inputStride; *p++ = (a->attrib&0xFF004000) | 0x8000 | nverts << 16 | i; // UNPACK @@ -846,6 +872,7 @@ objUninstance(rw::ObjPipeline *rwpipe, Atomic *atomic) (MatPipeline*)mesh->material->pipeline; if(m == nil) m = defaultMatPipe; + //printDMAVIF(instance); uint8 *data[nelem(m->attribs)] = { nil }; uint8 *raw = m->collectData(geo, instance, mesh, data); assert(m->uninstanceCB); @@ -1256,31 +1283,220 @@ registerADCPlugin(void) } // misc stuff -/* + +static uint32 +unpackSize(uint32 unpack) +{ + static uint32 size[] = { 32, 16, 8, 4 }; + return ((unpack>>26 & 3)+1)*size[unpack>>24 & 3]/8; +} + +/* A little dumb VIF interpreter */ +static void +sendVIF(uint32 w) +{ + enum VIFstate { + VST_cmd, + VST_stmask, + VST_strow, + VST_stcol, + VST_mpg, + VST_direct, + VST_unpack + }; +// static uint32 buf[256 * 16]; // maximum unpack size + static VIFstate state = VST_cmd; + static uint32 n; + static uint32 code; + uint32 imm, num; + + imm = w & 0xFFFF; + num = (w>>16) & 0xFF; + switch(state){ + case VST_cmd: + code = w; + if((code & 0x60000000) == VIF_UNPACK){ + printf("\t%08X VIF_UNPACK\n", code); + printf("\t...skipping...\n"); + state = VST_unpack; + n = (unpackSize(code)*num + 3) >> 2; + }else switch(code & 0x7F000000){ + case VIF_NOP: + printf("\t%08X VIF_NOP\n", code); + break; + case VIF_STCYCL: + printf("\t%08X VIF_STCYCL\n", code); + break; + case VIF_OFFSET: + printf("\t%08X VIF_OFFSET\n", code); + break; + case VIF_BASE: + printf("\t%08X VIF_BASE\n", code); + break; + case VIF_ITOP: + printf("\t%08X VIF_ITOP\n", code); + break; + case VIF_STMOD: + printf("\t%08X VIF_STMOD\n", code); + break; + case VIF_MSKPATH3: + printf("\t%08X VIF_MSKPATH3\n", code); + break; + case VIF_MARK: + printf("\t%08X VIF_MARK\n", code); + break; + case VIF_FLUSHE: + printf("\t%08X VIF_FLUSHE\n", code); + break; + case VIF_FLUSH: + printf("\t%08X VIF_FLUSH\n", code); + break; + case VIF_FLUSHA: + printf("\t%08X VIF_FLUSHA\n", code); + break; + case VIF_MSCAL: + printf("\t%08X VIF_MSCAL\n", code); + break; + case VIF_MSCALF: + printf("\t%08X VIF_MSCALF\n", code); + break; + case VIF_MSCNT: + printf("\t%08X VIF_MSCNT\n", code); + break; + case VIF_STMASK: + printf("\t%08X VIF_STMASK\n", code); + printf("\t...skipping...\n"); + state = VST_stmask; + n = 1; + break; + case VIF_STROW: + printf("\t%08X VIF_STROW\n", code); + printf("\t...skipping...\n"); + state = VST_strow; + n = 4; + break; + case VIF_STCOL: + printf("\t%08X VIF_STCOL\n", code); + printf("\t...skipping...\n"); + state = VST_stcol; + n = 4; + break; + case VIF_MPG: + printf("\t%08X VIF_MPG\n", code); + state = VST_mpg; + n = num*2; + break; + case VIF_DIRECT: + printf("\t%08X VIF_DIRECT\n", code); + printf("\t...skipping...\n"); + state = VST_direct; + n = imm*4; + break; + case VIF_DIRECTHL: + printf("\t%08X VIF_DIRECTHL\n", code); + printf("\t...skipping...\n"); + state = VST_direct; + n = imm*4; + break; + default: + printf("\tUnknown VIFcode %08X\n", code); + } + break; + /* TODO: actually do something here */ + case VST_stmask: + n--; + break; + case VST_strow: + n--; + break; + case VST_stcol: + n--; + break; + case VST_mpg: + n--; + break; + case VST_direct: + n--; + break; + case VST_unpack: + n--; + break; + } + if(n == 0) + state = VST_cmd; +} + +static void +dmaVIF(int32 qwc, uint32 *data) +{ + qwc *= 4; + while(qwc--) + sendVIF(*data++); +} void -printDMA(InstanceData *inst) +printDMAVIF(InstanceData *inst) { uint32 *tag = (uint32*)inst->data; + uint32 *base = (uint32*)inst->data; + uint32 qwc; + for(;;){ + qwc = tag[0]&0xFFFF; switch(tag[0]&0x70000000){ case DMAcnt: - printf("%08x %08x\n", tag[0], tag[1]); - tag += (1+(tag[0]&0xFFFF))*4; + printf("DMAcnt %04x %08x\n", qwc, tag[1]); + sendVIF(tag[2]); + sendVIF(tag[3]); + dmaVIF(qwc, tag+4); + tag += (1+qwc)*4; break; case DMAref: - printf("%08x %08x\n", tag[0], tag[1]); + printf("DMAref %04x %08x\n", qwc, tag[1]); + sendVIF(tag[2]); + sendVIF(tag[3]); + dmaVIF(qwc, base + tag[1]*4); tag += 4; break; case DMAret: - printf("%08x %08x\n", tag[0], tag[1]); + printf("DMAret %04x %08x\n", qwc, tag[1]); + sendVIF(tag[2]); + sendVIF(tag[3]); + dmaVIF(qwc, tag+4); + printf("\n"); return; } } } +void +printDMA(InstanceData *inst) +{ + uint32 *tag = (uint32*)inst->data; + uint32 qwc; + for(;;){ + qwc = tag[0]&0xFFFF; + switch(tag[0]&0x70000000){ + case DMAcnt: + printf("CNT %04x %08x\n", qwc, tag[1]); + tag += (1+qwc)*4; + break; + + case DMAref: + printf("REF %04x %08x\n", qwc, tag[1]); + tag += 4; + break; + + case DMAret: + printf("RET %04x %08x\n\n", qwc, tag[1]); + return; + } + } +} + +/* void sizedebug(InstanceData *inst) { diff --git a/src/ps2/rwps2.h b/src/ps2/rwps2.h index eee9e87..9e94e23 100644 --- a/src/ps2/rwps2.h +++ b/src/ps2/rwps2.h @@ -15,6 +15,7 @@ extern Device renderdevice; struct InstanceData { uint32 dataSize; + uint8 *dataRaw; uint8 *data; Material *material; }; @@ -59,6 +60,7 @@ int32 getSizeNativeData(void *object, int32, int32); void registerNativeDataPlugin(void); void printDMA(InstanceData *inst); +void printDMAVIF(InstanceData *inst); void sizedebug(InstanceData *inst); void fixDmaOffsets(InstanceData *inst); // only RW_PS2 @@ -83,6 +85,7 @@ class MatPipeline : public rw::Pipeline public: uint32 vifOffset; uint32 inputStride; + // number of vertices for tri strips and lists uint32 triStripCount, triListCount; PipeAttribute *attribs[10]; void (*instanceCB)(MatPipeline*, Geometry*, Mesh*, uint8**); @@ -104,7 +107,7 @@ public: MatPipeline(uint32 platform); void dump(void); - void setTriBufferSizes(uint32 inputStride, uint32 stripCount); + void setTriBufferSizes(uint32 inputStride, uint32 bufferSize); void instance(Geometry *g, InstanceData *inst, Mesh *m); uint8 *collectData(Geometry *g, InstanceData *inst, Mesh *m, uint8 *data[]); }; diff --git a/src/rwobjects.h b/src/rwobjects.h index a259e1a..7b6cbd1 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -402,7 +402,7 @@ struct Geometry MeshHeader *allocateMeshes(int32 numMeshes, uint32 numIndices, bool32 noIndices); void generateTriangles(int8 *adc = nil); void buildMeshes(void); - void buildTristrips(void); + void buildTristrips(void); // private, used by buildMeshes void correctTristripWinding(void); void removeUnusedMaterials(void); static Geometry *streamRead(Stream *stream); diff --git a/src/tristrip.cpp b/src/tristrip.cpp index a4c96d3..c0234ee 100644 --- a/src/tristrip.cpp +++ b/src/tristrip.cpp @@ -32,7 +32,6 @@ struct StripNode uint8 isEnd : 1; /* is in end list */ GraphEdge e[3]; int32 stripId; /* index of start node */ -// int asdf; LLLink inlist; }; @@ -44,10 +43,13 @@ struct StripMesh LinkList endNodes; /* strip start/end nodes */ }; +//#define trace(...) printf(__VA_ARGS__) +#define trace(...) + static void printNode(StripMesh *sm, StripNode *n) { - printf("%3ld: %3d %3d.%d %3d.%d %3d.%d || %3d %3d %3d\n", + trace("%3ld: %3d %3d.%d %3d.%d %3d.%d || %3d %3d %3d\n", n - sm->nodes, n->stripId, n->e[0].node, @@ -95,6 +97,9 @@ collectFaces(Geometry *geo, StripMesh *sm, uint16 m) n->v[0] = t->v[0]; n->v[1] = t->v[1]; n->v[2] = t->v[2]; + assert(t->v[0] < geo->numVertices); + assert(t->v[1] < geo->numVertices); + assert(t->v[2] < geo->numVertices); n->e[0].node = 0; n->e[1].node = 0; n->e[2].node = 0; @@ -114,7 +119,7 @@ collectFaces(Geometry *geo, StripMesh *sm, uint16 m) } } -/* Find Triangle that has edge e. */ +/* Find Triangle that has edge e that is not connected yet. */ static GraphEdge findEdge(StripMesh *sm, int32 e[2]) { @@ -128,6 +133,7 @@ findEdge(StripMesh *sm, int32 e[2]) if(e[0] == n->v[j] && e[1] == n->v[(j+1) % 3]){ ge.node = i; + // signal success ge.isConnected = 1; ge.otherEdge = j; return ge; @@ -139,7 +145,7 @@ findEdge(StripMesh *sm, int32 e[2]) /* Connect nodes sharing an edge, preserving winding */ static void -connectNodes(StripMesh *sm) +connectNodesPreserve(StripMesh *sm) { StripNode *n, *nn; int32 e[2]; @@ -154,8 +160,8 @@ connectNodes(StripMesh *sm) e[1] = n->v[j]; e[0] = n->v[(j+1) % 3]; ge = findEdge(sm, e); - /* found node, now connect */ if(ge.isConnected){ + /* found node, now connect */ n->e[j].node = ge.node; n->e[j].isConnected = 1; n->e[j].otherEdge = ge.otherEdge; @@ -188,6 +194,7 @@ numStripEdges(StripNode *n) #define IsEnd(n) (numConnections(n) > 0 && numStripEdges(n) < 2) +/* Complement the strip-ness of an edge */ static void complementEdge(StripMesh *sm, GraphEdge *e) { @@ -197,8 +204,9 @@ complementEdge(StripMesh *sm, GraphEdge *e) } /* While possible extend a strip from a starting node until - * we find a node already in a strip. N.B. this function does - * make no attempts to connect to an already existing strip. */ + * we find a node already in a strip. N.B. this function + * makes no attempts to connect to an already existing strip. + * It also doesn't try to alternate between left and right. */ static void extendStrip(StripMesh *sm, StripNode *start) { @@ -210,7 +218,7 @@ extendStrip(StripMesh *sm, StripNode *start) } sm->endNodes.append(&n->inlist); n->isEnd = 1; -tail: +loop: /* Find the next node to connect to on any of the three edges */ for(int32 i = 0; i < 3; i++){ if(!n->e[i].isConnected) @@ -221,9 +229,11 @@ tail: /* found one */ nn->stripId = n->stripId; + /* We know it's not a strip edge yet, + * so complementing it will make it one. */ complementEdge(sm, &n->e[i]); n = nn; - goto tail; + goto loop; } if(n != start){ sm->endNodes.append(&n->inlist); @@ -317,7 +327,7 @@ walkStrip(StripMesh *sm, StripNode *start) StripNode *n, *nn; int32 last; -//printf("stripend: "); +//trace("stripend: "); //printNode(sm, start); n = start; @@ -342,7 +352,7 @@ walkStrip(StripMesh *sm, StripNode *start) nn->stripId = n->stripId; break; } -//printf(" next: "); +//trace(" next: "); //printNode(sm, nn); if(nn == nil) return nil; @@ -356,15 +366,15 @@ applyTunnel(StripMesh *sm, StripNode *end, StripNode *start) StripNode *n, *nn; for(n = end; n != start; n = &sm->nodes[n->e[n->parent].node]){ -//printf(" "); +//trace(" "); //printNode(sm, n); complementEdge(sm, &n->e[n->parent]); } -//printf(" "); +//trace(" "); //printNode(sm, start); //printSmesh(sm); -//printf("-------\n"); +//trace("-------\n"); tmplist.init(); while(!sm->endNodes.isEmpty()){ n = LLLinkGetData(sm->endNodes.link.next, StripNode, inlist); @@ -399,9 +409,9 @@ tunnel(StripMesh *sm) again: FORLIST(lnk, sm->endNodes){ n = LLLinkGetData(lnk, StripNode, inlist); -// printf("searching %p %d\n", n, numStripEdges(n)); +// trace("searching %p %d\n", n, numStripEdges(n)); nn = findTunnel(sm, n); -// printf(" %p %p\n", n, nn); +// trace(" %p %p\n", n, nn); if(nn){ applyTunnel(sm, nn, n); @@ -412,9 +422,137 @@ again: } resetGraph(sm); } - printf("tunneling done!\n"); + trace("tunneling done!\n"); } +/* Get next edge in strip. + * Last is the edge index whence we came lest we go back. */ +static int +getNextEdge(StripNode *n, int32 last) +{ + int32 i; + for(i = 0; i < 3; i++) + if(n->e[i].isStrip && i != last) + return i; + return -1; +} + +#define NEXT(x) (((x)+1) % 3) +#define PREV(x) (((x)+2) % 3) +#define RIGHT(x) NEXT(x) +#define LEFT(x) PREV(x) + +/* Generate mesh indices for all strips in a StripMesh */ +static void +makeMesh(StripMesh *sm, Mesh *m) +{ + int32 i, j; + int32 rightturn, lastrightturn; + int32 seam; + int32 even; + StripNode *n; + + /* three indices + two for stitch per triangle must be enough */ + m->indices = rwNewT(uint16, sm->numNodes*5, MEMDUR_FUNCTION | ID_GEOMETRY); + memset(m->indices, 0xFF, sm->numNodes*5*sizeof(uint16)); + + even = 1; + FORLIST(lnk, sm->endNodes){ + n = LLLinkGetData(lnk, StripNode, inlist); + /* only interested in start nodes, not the ends */ + if(n->stripId != (n - sm->nodes)) + continue; + + /* i is the edge we enter this triangle from. + * j is the edge we exit. */ + j = getNextEdge(n, -1); + /* starting triangle must have connection */ + if(j < 0) + continue; + /* Space to stitch together strips */ + seam = m->numIndices; + if(seam) + m->numIndices += 2; + /* Start ccw for even tris */ + if(even){ + /* Start with a right turn */ + i = LEFT(j); + m->indices[m->numIndices++] = n->v[i]; + m->indices[m->numIndices++] = n->v[NEXT(i)]; + }else{ + /* Start with a left turn */ + i = RIGHT(j); + m->indices[m->numIndices++] = n->v[NEXT(i)]; + m->indices[m->numIndices++] = n->v[i]; + } +trace("\nstart %d %d\n", numStripEdges(n), m->numIndices-2); + lastrightturn = -1; + + while(j >= 0){ + rightturn = RIGHT(i) == j; + if(rightturn == lastrightturn){ + // insert a swap if we're not alternating + m->indices[m->numIndices] = m->indices[m->numIndices-2]; +trace("SWAP\n"); + m->numIndices++; + even = !even; + } +trace("%d:%d%c %d %d %d\n", n-sm->nodes, m->numIndices, even ? ' ' : '.', n->v[0], n->v[1], n->v[2]); + lastrightturn = rightturn; + if(rightturn) + m->indices[m->numIndices++] = n->v[NEXT(j)]; + else + m->indices[m->numIndices++] = n->v[j]; + even = !even; + + /* go to next triangle */ + i = n->e[j].otherEdge; + n = &sm->nodes[n->e[j].node]; + j = getNextEdge(n, i); + } + + /* finish strip */ +trace("%d:%d%c %d %d %d\nend\n", n-sm->nodes, m->numIndices, even ? ' ' : '.', n->v[0], n->v[1], n->v[2]); + m->indices[m->numIndices++] = n->v[LEFT(i)]; + even = !even; + if(seam){ + m->indices[seam] = m->indices[seam-1]; + m->indices[seam+1] = m->indices[seam+2]; +trace("STITCH %d: %d %d\n", seam, m->indices[seam], m->indices[seam+1]); + } + } + + /* Add all unconnected and lonely triangles */ + FORLIST(lnk, sm->endNodes){ + n = LLLinkGetData(lnk, StripNode, inlist); + if(numStripEdges(n) != 0) + continue; + if(m->numIndices != 0){ + m->indices[m->numIndices] = m->indices[m->numIndices-1]; + m->numIndices++; + m->indices[m->numIndices++] = n->v[!even]; + } + m->indices[m->numIndices++] = n->v[!even]; + m->indices[m->numIndices++] = n->v[even]; + m->indices[m->numIndices++] = n->v[2]; + even = !even; + } + FORLIST(lnk, sm->loneNodes){ + n = LLLinkGetData(lnk, StripNode, inlist); + if(m->numIndices != 0){ + m->indices[m->numIndices] = m->indices[m->numIndices-1]; + m->numIndices++; + m->indices[m->numIndices++] = n->v[!even]; + } + m->indices[m->numIndices++] = n->v[!even]; + m->indices[m->numIndices++] = n->v[even]; + m->indices[m->numIndices++] = n->v[2]; + even = !even; + } +} + +static void verifyMesh(Geometry *geo); + /* * For each material: * 1. build dual graph (collectFaces, connectNodes) @@ -424,30 +562,121 @@ again: void Geometry::buildTristrips(void) { + int32 i; + uint16 *indices; + MeshHeader *header; + Mesh *ms, *md; StripMesh smesh; - printf("%ld\n", sizeof(StripNode)); +// trace("%ld\n", sizeof(StripNode)); + + this->allocateMeshes(matList.numMaterials, 0, 1); smesh.nodes = rwNewT(StripNode, this->numTriangles, MEMDUR_FUNCTION | ID_GEOMETRY); + ms = this->meshHeader->getMeshes(); for(int32 i = 0; i < this->matList.numMaterials; i++){ smesh.loneNodes.init(); smesh.endNodes.init(); collectFaces(this, &smesh, i); - connectNodes(&smesh); + connectNodesPreserve(&smesh); buildStrips(&smesh); printSmesh(&smesh); -printf("-------\n"); +//trace("-------\n"); //printLone(&smesh); -//printf("-------\n"); +//trace("-------\n"); //printEnds(&smesh); -//printf("-------\n"); - tunnel(&smesh); -//printf("-------\n"); +//trace("-------\n"); + // TODO: make this work +// tunnel(&smesh); +//trace("-------\n"); //printEnds(&smesh); + + ms[i].material = this->matList.materials[i]; + makeMesh(&smesh, &ms[i]); + this->meshHeader->totalIndices += ms[i].numIndices; } rwFree(smesh.nodes); - exit(1); + /* Now re-allocate and copy data */ + header = this->meshHeader; + this->meshHeader = nil; + this->allocateMeshes(header->numMeshes, header->totalIndices, 0); + this->meshHeader->flags = MeshHeader::TRISTRIP; + md = this->meshHeader->getMeshes(); + indices = md->indices; + for(i = 0; i < header->numMeshes; i++){ + md[i].material = ms[i].material; + md[i].numIndices = ms[i].numIndices; + md[i].indices = indices; + indices += md[i].numIndices; + memcpy(md[i].indices, ms[i].indices, md[i].numIndices*sizeof(uint16)); + rwFree(ms[i].indices); + } + rwFree(header); + + verifyMesh(this); +} + +/* Check that tristripped mesh and geometry triangles are actually the same. */ +static void +verifyMesh(Geometry *geo) +{ + int32 i, k; + uint32 j; + int32 x; + int32 a, b, c, m; + Mesh *mesh; + Triangle *t; + uint8 *seen; + + seen = rwNewT(uint8, geo->numTriangles, MEMDUR_FUNCTION | ID_GEOMETRY); + memset(seen, 0, geo->numTriangles); + + mesh = geo->meshHeader->getMeshes(); + for(i = 0; i < geo->meshHeader->numMeshes; i++){ + m = geo->matList.findIndex(mesh->material); + x = 0; + for(j = 0; j < mesh->numIndices-2; j++){ + a = mesh->indices[j+x]; + x = !x; + b = mesh->indices[j+x]; + c = mesh->indices[j+2]; + if(a >= geo->numVertices || + b >= geo->numVertices || + c >= geo->numVertices){ + fprintf(stderr, "triangle %d %d %d out of range (%d)\n", a, b, c, geo->numVertices); + goto loss; + } + if(a == b || a == c || b == c) + continue; +trace("%d %d %d\n", a, b, c); + + /* now that we have a triangle, try to find it */ + for(k = 0; k < geo->numTriangles; k++){ + t = &geo->triangles[k]; + if(seen[k] || t->matId != m) continue; + if(t->v[0] == a && t->v[1] == b && t->v[2] == c || + t->v[1] == a && t->v[2] == b && t->v[0] == c || + t->v[2] == a && t->v[0] == b && t->v[1] == c){ + seen[k] = 1; + goto found; + } + } + goto loss; + found: ; + } + mesh++; + } + + /* Also check that all triangles are in the mesh */ + for(i = 0; i < geo->numTriangles; i++) + if(!seen[i]){ + loss: + fprintf(stderr, "TRISTRIP verify failed\n"); + exit(1); + } + + rwFree(seen); } }