mirror of
https://github.com/aap/librw.git
synced 2024-11-25 05:05:42 +00:00
implemented simple tri stripping
This commit is contained in:
parent
0b968c9866
commit
6b36390bdc
268
src/ps2/ps2.cpp
268
src/ps2/ps2.cpp
@ -21,6 +21,8 @@
|
|||||||
namespace rw {
|
namespace rw {
|
||||||
namespace ps2 {
|
namespace ps2 {
|
||||||
|
|
||||||
|
#define ALIGNPTR(p,a) ((uint8*)(((uintptr)(p)+a-1) & ~(uintptr)(a-1)))
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
driverOpen(void *o, int32, int32)
|
driverOpen(void *o, int32, int32)
|
||||||
{
|
{
|
||||||
@ -63,7 +65,7 @@ destroyNativeData(void *object, int32, int32)
|
|||||||
return object;
|
return object;
|
||||||
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
||||||
for(uint32 i = 0; i < header->numMeshes; i++)
|
for(uint32 i = 0; i < header->numMeshes; i++)
|
||||||
rwFree(header->instanceMeshes[i].data);
|
rwFree(header->instanceMeshes[i].dataRaw);
|
||||||
rwFree(header->instanceMeshes);
|
rwFree(header->instanceMeshes);
|
||||||
rwFree(header);
|
rwFree(header);
|
||||||
geometry->instData = nil;
|
geometry->instData = nil;
|
||||||
@ -96,8 +98,8 @@ readNativeData(Stream *stream, int32, void *object, int32, int32)
|
|||||||
uint32 buf[2];
|
uint32 buf[2];
|
||||||
stream->read(buf, 8);
|
stream->read(buf, 8);
|
||||||
instance->dataSize = buf[0];
|
instance->dataSize = buf[0];
|
||||||
// TODO: force alignment
|
instance->dataRaw = rwNewT(uint8, instance->dataSize+0x7F, MEMDUR_EVENT | ID_GEOMETRY);
|
||||||
instance->data = rwNewT(uint8, instance->dataSize, MEMDUR_EVENT | ID_GEOMETRY);
|
instance->data = ALIGNPTR(instance->dataRaw, 0x80);
|
||||||
#ifdef RW_PS2
|
#ifdef RW_PS2
|
||||||
uint32 a = (uint32)instance->data;
|
uint32 a = (uint32)instance->data;
|
||||||
assert(a % 0x10 == 0);
|
assert(a % 0x10 == 0);
|
||||||
@ -458,20 +460,24 @@ MatPipeline::dump(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MatPipeline::setTriBufferSizes(uint32 inputStride, uint32 stripCount)
|
MatPipeline::setTriBufferSizes(uint32 inputStride, uint32 bufferSize)
|
||||||
{
|
{
|
||||||
this->inputStride = inputStride;
|
|
||||||
this->triListCount = stripCount/12*12;
|
|
||||||
PipeAttribute *a;
|
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++){
|
for(uint i = 0; i < nelem(this->attribs); i++){
|
||||||
a = this->attribs[i];
|
a = this->attribs[i];
|
||||||
if(a && a->attrib & AT_RW)
|
if(a && a->attrib & AT_RW){
|
||||||
goto brokenout;
|
// 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:
|
// Instance format:
|
||||||
@ -514,14 +520,27 @@ enum {
|
|||||||
DMAret = 0x60000000,
|
DMAret = 0x60000000,
|
||||||
|
|
||||||
VIF_NOP = 0,
|
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_ITOP = 0x04000000,
|
||||||
VIF_STMOD = 0x05000000,
|
VIF_STMOD = 0x05000000,
|
||||||
VIF_MSKPATH3 = 0x06000000,
|
VIF_MSKPATH3 = 0x06000000,
|
||||||
VIF_MARK = 0x07000000,
|
VIF_MARK = 0x07000000,
|
||||||
|
VIF_FLUSHE = 0x10000000,
|
||||||
VIF_FLUSH = 0x11000000,
|
VIF_FLUSH = 0x11000000,
|
||||||
|
VIF_FLUSHA = 0x13000000,
|
||||||
|
VIF_MSCAL = 0x14000000,
|
||||||
VIF_MSCALF = 0x15000000,
|
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
|
struct InstMeshInfo
|
||||||
@ -595,8 +614,10 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m)
|
|||||||
InstMeshInfo im = getInstMeshInfo(this, g, m);
|
InstMeshInfo im = getInstMeshInfo(this, g, m);
|
||||||
|
|
||||||
inst->dataSize = (im.size+im.size2)<<4;
|
inst->dataSize = (im.size+im.size2)<<4;
|
||||||
// TODO: force alignment
|
// TODO: do this properly, just a test right now
|
||||||
inst->data = rwNewT(uint8, inst->dataSize, MEMDUR_EVENT | ID_GEOMETRY);
|
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 */
|
/* make array of addresses of broken out sections */
|
||||||
uint8 *datap[nelem(this->attribs)];
|
uint8 *datap[nelem(this->attribs)];
|
||||||
@ -630,12 +651,17 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m)
|
|||||||
uint32 atsz = attribSize(a->attrib);
|
uint32 atsz = attribSize(a->attrib);
|
||||||
*p++ = DMAref | QWC(nverts*atsz);
|
*p++ = DMAref | QWC(nverts*atsz);
|
||||||
*p++ = im.attribPos[i];
|
*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
|
// Round up nverts so UNPACK will fit exactly into the DMA packet
|
||||||
// (can't pad with zeroes in broken out sections).
|
// (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)
|
*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++ = DMAcnt;
|
||||||
*p++ = 0x0;
|
*p++ = 0x0;
|
||||||
@ -660,7 +686,7 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m)
|
|||||||
else
|
else
|
||||||
*p++ = VIF_MARK | markcnt++;
|
*p++ = VIF_MARK | markcnt++;
|
||||||
*p++ = VIF_STMOD;
|
*p++ = VIF_STMOD;
|
||||||
*p++ = VIF_STCYCL | this->inputStride;
|
*p++ = VIF_STCYCL1 | this->inputStride;
|
||||||
*p++ = (a->attrib&0xFF004000)
|
*p++ = (a->attrib&0xFF004000)
|
||||||
| 0x8000 | nverts << 16 | i; // UNPACK
|
| 0x8000 | nverts << 16 | i; // UNPACK
|
||||||
|
|
||||||
@ -846,6 +872,7 @@ objUninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
|
|||||||
(MatPipeline*)mesh->material->pipeline;
|
(MatPipeline*)mesh->material->pipeline;
|
||||||
if(m == nil) m = defaultMatPipe;
|
if(m == nil) m = defaultMatPipe;
|
||||||
|
|
||||||
|
//printDMAVIF(instance);
|
||||||
uint8 *data[nelem(m->attribs)] = { nil };
|
uint8 *data[nelem(m->attribs)] = { nil };
|
||||||
uint8 *raw = m->collectData(geo, instance, mesh, data);
|
uint8 *raw = m->collectData(geo, instance, mesh, data);
|
||||||
assert(m->uninstanceCB);
|
assert(m->uninstanceCB);
|
||||||
@ -1256,31 +1283,220 @@ registerADCPlugin(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// misc stuff
|
// 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
|
void
|
||||||
printDMA(InstanceData *inst)
|
printDMAVIF(InstanceData *inst)
|
||||||
{
|
{
|
||||||
uint32 *tag = (uint32*)inst->data;
|
uint32 *tag = (uint32*)inst->data;
|
||||||
|
uint32 *base = (uint32*)inst->data;
|
||||||
|
uint32 qwc;
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
|
qwc = tag[0]&0xFFFF;
|
||||||
switch(tag[0]&0x70000000){
|
switch(tag[0]&0x70000000){
|
||||||
case DMAcnt:
|
case DMAcnt:
|
||||||
printf("%08x %08x\n", tag[0], tag[1]);
|
printf("DMAcnt %04x %08x\n", qwc, tag[1]);
|
||||||
tag += (1+(tag[0]&0xFFFF))*4;
|
sendVIF(tag[2]);
|
||||||
|
sendVIF(tag[3]);
|
||||||
|
dmaVIF(qwc, tag+4);
|
||||||
|
tag += (1+qwc)*4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DMAref:
|
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;
|
tag += 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DMAret:
|
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;
|
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
|
void
|
||||||
sizedebug(InstanceData *inst)
|
sizedebug(InstanceData *inst)
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,7 @@ extern Device renderdevice;
|
|||||||
struct InstanceData
|
struct InstanceData
|
||||||
{
|
{
|
||||||
uint32 dataSize;
|
uint32 dataSize;
|
||||||
|
uint8 *dataRaw;
|
||||||
uint8 *data;
|
uint8 *data;
|
||||||
Material *material;
|
Material *material;
|
||||||
};
|
};
|
||||||
@ -59,6 +60,7 @@ int32 getSizeNativeData(void *object, int32, int32);
|
|||||||
void registerNativeDataPlugin(void);
|
void registerNativeDataPlugin(void);
|
||||||
|
|
||||||
void printDMA(InstanceData *inst);
|
void printDMA(InstanceData *inst);
|
||||||
|
void printDMAVIF(InstanceData *inst);
|
||||||
void sizedebug(InstanceData *inst);
|
void sizedebug(InstanceData *inst);
|
||||||
|
|
||||||
void fixDmaOffsets(InstanceData *inst); // only RW_PS2
|
void fixDmaOffsets(InstanceData *inst); // only RW_PS2
|
||||||
@ -83,6 +85,7 @@ class MatPipeline : public rw::Pipeline
|
|||||||
public:
|
public:
|
||||||
uint32 vifOffset;
|
uint32 vifOffset;
|
||||||
uint32 inputStride;
|
uint32 inputStride;
|
||||||
|
// number of vertices for tri strips and lists
|
||||||
uint32 triStripCount, triListCount;
|
uint32 triStripCount, triListCount;
|
||||||
PipeAttribute *attribs[10];
|
PipeAttribute *attribs[10];
|
||||||
void (*instanceCB)(MatPipeline*, Geometry*, Mesh*, uint8**);
|
void (*instanceCB)(MatPipeline*, Geometry*, Mesh*, uint8**);
|
||||||
@ -104,7 +107,7 @@ public:
|
|||||||
|
|
||||||
MatPipeline(uint32 platform);
|
MatPipeline(uint32 platform);
|
||||||
void dump(void);
|
void dump(void);
|
||||||
void setTriBufferSizes(uint32 inputStride, uint32 stripCount);
|
void setTriBufferSizes(uint32 inputStride, uint32 bufferSize);
|
||||||
void instance(Geometry *g, InstanceData *inst, Mesh *m);
|
void instance(Geometry *g, InstanceData *inst, Mesh *m);
|
||||||
uint8 *collectData(Geometry *g, InstanceData *inst, Mesh *m, uint8 *data[]);
|
uint8 *collectData(Geometry *g, InstanceData *inst, Mesh *m, uint8 *data[]);
|
||||||
};
|
};
|
||||||
|
@ -402,7 +402,7 @@ struct Geometry
|
|||||||
MeshHeader *allocateMeshes(int32 numMeshes, uint32 numIndices, bool32 noIndices);
|
MeshHeader *allocateMeshes(int32 numMeshes, uint32 numIndices, bool32 noIndices);
|
||||||
void generateTriangles(int8 *adc = nil);
|
void generateTriangles(int8 *adc = nil);
|
||||||
void buildMeshes(void);
|
void buildMeshes(void);
|
||||||
void buildTristrips(void);
|
void buildTristrips(void); // private, used by buildMeshes
|
||||||
void correctTristripWinding(void);
|
void correctTristripWinding(void);
|
||||||
void removeUnusedMaterials(void);
|
void removeUnusedMaterials(void);
|
||||||
static Geometry *streamRead(Stream *stream);
|
static Geometry *streamRead(Stream *stream);
|
||||||
|
279
src/tristrip.cpp
279
src/tristrip.cpp
@ -32,7 +32,6 @@ struct StripNode
|
|||||||
uint8 isEnd : 1; /* is in end list */
|
uint8 isEnd : 1; /* is in end list */
|
||||||
GraphEdge e[3];
|
GraphEdge e[3];
|
||||||
int32 stripId; /* index of start node */
|
int32 stripId; /* index of start node */
|
||||||
// int asdf;
|
|
||||||
LLLink inlist;
|
LLLink inlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,10 +43,13 @@ struct StripMesh
|
|||||||
LinkList endNodes; /* strip start/end nodes */
|
LinkList endNodes; /* strip start/end nodes */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//#define trace(...) printf(__VA_ARGS__)
|
||||||
|
#define trace(...)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
printNode(StripMesh *sm, StripNode *n)
|
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 - sm->nodes,
|
||||||
n->stripId,
|
n->stripId,
|
||||||
n->e[0].node,
|
n->e[0].node,
|
||||||
@ -95,6 +97,9 @@ collectFaces(Geometry *geo, StripMesh *sm, uint16 m)
|
|||||||
n->v[0] = t->v[0];
|
n->v[0] = t->v[0];
|
||||||
n->v[1] = t->v[1];
|
n->v[1] = t->v[1];
|
||||||
n->v[2] = t->v[2];
|
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[0].node = 0;
|
||||||
n->e[1].node = 0;
|
n->e[1].node = 0;
|
||||||
n->e[2].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
|
static GraphEdge
|
||||||
findEdge(StripMesh *sm, int32 e[2])
|
findEdge(StripMesh *sm, int32 e[2])
|
||||||
{
|
{
|
||||||
@ -128,6 +133,7 @@ findEdge(StripMesh *sm, int32 e[2])
|
|||||||
if(e[0] == n->v[j] &&
|
if(e[0] == n->v[j] &&
|
||||||
e[1] == n->v[(j+1) % 3]){
|
e[1] == n->v[(j+1) % 3]){
|
||||||
ge.node = i;
|
ge.node = i;
|
||||||
|
// signal success
|
||||||
ge.isConnected = 1;
|
ge.isConnected = 1;
|
||||||
ge.otherEdge = j;
|
ge.otherEdge = j;
|
||||||
return ge;
|
return ge;
|
||||||
@ -139,7 +145,7 @@ findEdge(StripMesh *sm, int32 e[2])
|
|||||||
|
|
||||||
/* Connect nodes sharing an edge, preserving winding */
|
/* Connect nodes sharing an edge, preserving winding */
|
||||||
static void
|
static void
|
||||||
connectNodes(StripMesh *sm)
|
connectNodesPreserve(StripMesh *sm)
|
||||||
{
|
{
|
||||||
StripNode *n, *nn;
|
StripNode *n, *nn;
|
||||||
int32 e[2];
|
int32 e[2];
|
||||||
@ -154,8 +160,8 @@ connectNodes(StripMesh *sm)
|
|||||||
e[1] = n->v[j];
|
e[1] = n->v[j];
|
||||||
e[0] = n->v[(j+1) % 3];
|
e[0] = n->v[(j+1) % 3];
|
||||||
ge = findEdge(sm, e);
|
ge = findEdge(sm, e);
|
||||||
/* found node, now connect */
|
|
||||||
if(ge.isConnected){
|
if(ge.isConnected){
|
||||||
|
/* found node, now connect */
|
||||||
n->e[j].node = ge.node;
|
n->e[j].node = ge.node;
|
||||||
n->e[j].isConnected = 1;
|
n->e[j].isConnected = 1;
|
||||||
n->e[j].otherEdge = ge.otherEdge;
|
n->e[j].otherEdge = ge.otherEdge;
|
||||||
@ -188,6 +194,7 @@ numStripEdges(StripNode *n)
|
|||||||
|
|
||||||
#define IsEnd(n) (numConnections(n) > 0 && numStripEdges(n) < 2)
|
#define IsEnd(n) (numConnections(n) > 0 && numStripEdges(n) < 2)
|
||||||
|
|
||||||
|
/* Complement the strip-ness of an edge */
|
||||||
static void
|
static void
|
||||||
complementEdge(StripMesh *sm, GraphEdge *e)
|
complementEdge(StripMesh *sm, GraphEdge *e)
|
||||||
{
|
{
|
||||||
@ -197,8 +204,9 @@ complementEdge(StripMesh *sm, GraphEdge *e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* While possible extend a strip from a starting node until
|
/* While possible extend a strip from a starting node until
|
||||||
* we find a node already in a strip. N.B. this function does
|
* we find a node already in a strip. N.B. this function
|
||||||
* make no attempts to connect to an already existing strip. */
|
* makes no attempts to connect to an already existing strip.
|
||||||
|
* It also doesn't try to alternate between left and right. */
|
||||||
static void
|
static void
|
||||||
extendStrip(StripMesh *sm, StripNode *start)
|
extendStrip(StripMesh *sm, StripNode *start)
|
||||||
{
|
{
|
||||||
@ -210,7 +218,7 @@ extendStrip(StripMesh *sm, StripNode *start)
|
|||||||
}
|
}
|
||||||
sm->endNodes.append(&n->inlist);
|
sm->endNodes.append(&n->inlist);
|
||||||
n->isEnd = 1;
|
n->isEnd = 1;
|
||||||
tail:
|
loop:
|
||||||
/* Find the next node to connect to on any of the three edges */
|
/* Find the next node to connect to on any of the three edges */
|
||||||
for(int32 i = 0; i < 3; i++){
|
for(int32 i = 0; i < 3; i++){
|
||||||
if(!n->e[i].isConnected)
|
if(!n->e[i].isConnected)
|
||||||
@ -221,9 +229,11 @@ tail:
|
|||||||
|
|
||||||
/* found one */
|
/* found one */
|
||||||
nn->stripId = n->stripId;
|
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]);
|
complementEdge(sm, &n->e[i]);
|
||||||
n = nn;
|
n = nn;
|
||||||
goto tail;
|
goto loop;
|
||||||
}
|
}
|
||||||
if(n != start){
|
if(n != start){
|
||||||
sm->endNodes.append(&n->inlist);
|
sm->endNodes.append(&n->inlist);
|
||||||
@ -317,7 +327,7 @@ walkStrip(StripMesh *sm, StripNode *start)
|
|||||||
StripNode *n, *nn;
|
StripNode *n, *nn;
|
||||||
int32 last;
|
int32 last;
|
||||||
|
|
||||||
//printf("stripend: ");
|
//trace("stripend: ");
|
||||||
//printNode(sm, start);
|
//printNode(sm, start);
|
||||||
|
|
||||||
n = start;
|
n = start;
|
||||||
@ -342,7 +352,7 @@ walkStrip(StripMesh *sm, StripNode *start)
|
|||||||
nn->stripId = n->stripId;
|
nn->stripId = n->stripId;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//printf(" next: ");
|
//trace(" next: ");
|
||||||
//printNode(sm, nn);
|
//printNode(sm, nn);
|
||||||
if(nn == nil)
|
if(nn == nil)
|
||||||
return nil;
|
return nil;
|
||||||
@ -356,15 +366,15 @@ applyTunnel(StripMesh *sm, StripNode *end, StripNode *start)
|
|||||||
StripNode *n, *nn;
|
StripNode *n, *nn;
|
||||||
|
|
||||||
for(n = end; n != start; n = &sm->nodes[n->e[n->parent].node]){
|
for(n = end; n != start; n = &sm->nodes[n->e[n->parent].node]){
|
||||||
//printf(" ");
|
//trace(" ");
|
||||||
//printNode(sm, n);
|
//printNode(sm, n);
|
||||||
complementEdge(sm, &n->e[n->parent]);
|
complementEdge(sm, &n->e[n->parent]);
|
||||||
}
|
}
|
||||||
//printf(" ");
|
//trace(" ");
|
||||||
//printNode(sm, start);
|
//printNode(sm, start);
|
||||||
|
|
||||||
//printSmesh(sm);
|
//printSmesh(sm);
|
||||||
//printf("-------\n");
|
//trace("-------\n");
|
||||||
tmplist.init();
|
tmplist.init();
|
||||||
while(!sm->endNodes.isEmpty()){
|
while(!sm->endNodes.isEmpty()){
|
||||||
n = LLLinkGetData(sm->endNodes.link.next, StripNode, inlist);
|
n = LLLinkGetData(sm->endNodes.link.next, StripNode, inlist);
|
||||||
@ -399,9 +409,9 @@ tunnel(StripMesh *sm)
|
|||||||
again:
|
again:
|
||||||
FORLIST(lnk, sm->endNodes){
|
FORLIST(lnk, sm->endNodes){
|
||||||
n = LLLinkGetData(lnk, StripNode, inlist);
|
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);
|
nn = findTunnel(sm, n);
|
||||||
// printf(" %p %p\n", n, nn);
|
// trace(" %p %p\n", n, nn);
|
||||||
|
|
||||||
if(nn){
|
if(nn){
|
||||||
applyTunnel(sm, nn, n);
|
applyTunnel(sm, nn, n);
|
||||||
@ -412,9 +422,137 @@ again:
|
|||||||
}
|
}
|
||||||
resetGraph(sm);
|
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:
|
* For each material:
|
||||||
* 1. build dual graph (collectFaces, connectNodes)
|
* 1. build dual graph (collectFaces, connectNodes)
|
||||||
@ -424,30 +562,121 @@ again:
|
|||||||
void
|
void
|
||||||
Geometry::buildTristrips(void)
|
Geometry::buildTristrips(void)
|
||||||
{
|
{
|
||||||
|
int32 i;
|
||||||
|
uint16 *indices;
|
||||||
|
MeshHeader *header;
|
||||||
|
Mesh *ms, *md;
|
||||||
StripMesh smesh;
|
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);
|
smesh.nodes = rwNewT(StripNode, this->numTriangles, MEMDUR_FUNCTION | ID_GEOMETRY);
|
||||||
|
ms = this->meshHeader->getMeshes();
|
||||||
for(int32 i = 0; i < this->matList.numMaterials; i++){
|
for(int32 i = 0; i < this->matList.numMaterials; i++){
|
||||||
smesh.loneNodes.init();
|
smesh.loneNodes.init();
|
||||||
smesh.endNodes.init();
|
smesh.endNodes.init();
|
||||||
collectFaces(this, &smesh, i);
|
collectFaces(this, &smesh, i);
|
||||||
connectNodes(&smesh);
|
connectNodesPreserve(&smesh);
|
||||||
buildStrips(&smesh);
|
buildStrips(&smesh);
|
||||||
printSmesh(&smesh);
|
printSmesh(&smesh);
|
||||||
printf("-------\n");
|
//trace("-------\n");
|
||||||
//printLone(&smesh);
|
//printLone(&smesh);
|
||||||
//printf("-------\n");
|
//trace("-------\n");
|
||||||
//printEnds(&smesh);
|
//printEnds(&smesh);
|
||||||
//printf("-------\n");
|
//trace("-------\n");
|
||||||
tunnel(&smesh);
|
// TODO: make this work
|
||||||
//printf("-------\n");
|
// tunnel(&smesh);
|
||||||
|
//trace("-------\n");
|
||||||
//printEnds(&smesh);
|
//printEnds(&smesh);
|
||||||
|
|
||||||
|
ms[i].material = this->matList.materials[i];
|
||||||
|
makeMesh(&smesh, &ms[i]);
|
||||||
|
this->meshHeader->totalIndices += ms[i].numIndices;
|
||||||
}
|
}
|
||||||
rwFree(smesh.nodes);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user