From 0f135f2de6148f7926388628bc248929218d5e6e Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 7 Sep 2015 10:22:54 +0200 Subject: [PATCH] refactored skin plugin a bit; wrote xbox skin instance callback --- src/ogl.cpp | 38 ++++-------- src/plugins.cpp | 118 +++++++++++++++++++++++------------- src/ps2.cpp | 55 ++++++++--------- src/rwobjects.h | 7 ++- src/xbox.cpp | 69 +++++++++++++++++---- tools/insttest/insttest.cpp | 2 +- 6 files changed, 177 insertions(+), 112 deletions(-) diff --git a/src/ogl.cpp b/src/ogl.cpp index 2a1f7fd..8d4e499 100644 --- a/src/ogl.cpp +++ b/src/ogl.cpp @@ -504,40 +504,19 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset) assert(stream->readU32() == PLATFORM_OGL); Skin *skin = new Skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin; - skin->numBones = stream->readI32(); - skin->numUsedBones = 0; - skin->maxIndex = 0; - int32 size = skin->numBones*64 + 15; - uint8 *data = new uint8[size]; - skin->data = data; - skin->indices = NULL; - skin->weights = NULL; - skin->usedBones = NULL; - - uintptr ptr = (uintptr)data + 15; - ptr &= ~0xF; - data = (uint8*)ptr; - skin->inverseMatrices = NULL; - if(skin->numBones){ - skin->inverseMatrices = (float*)data; - stream->read(skin->inverseMatrices, skin->numBones*64); - } + int32 numBones = stream->readI32(); + skin->init(numBones, 0, 0); + stream->read(skin->inverseMatrices, skin->numBones*64); } void writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset) { - uint8 header[4]; - writeChunkHeader(stream, ID_STRUCT, len-12); stream->writeU32(PLATFORM_OGL); Skin *skin = *PLUGINOFFSET(Skin*, object, offset); - header[0] = skin->numBones; - header[1] = 0; - header[2] = 0; - header[3] = 0; - stream->write(header, 4); + stream->writeI32(skin->numBones); stream->write(skin->inverseMatrices, skin->numBones*64); } @@ -608,7 +587,11 @@ skinUninstanceCB(Geometry *geo) if(skin == NULL) return; - skin->allocateVertexData(geo->numVertices); + uint8 *data = skin->data; + float *invMats = skin->inverseMatrices; + skin->init(skin->numBones, skin->numBones, geo->numVertices); + memcpy(skin->inverseMatrices, invMats, skin->numBones*64); + delete[] data; uint8 *p; float *weights = skin->weights; @@ -637,6 +620,9 @@ skinUninstanceCB(Geometry *geo) break; } } + + skin->findNumWeights(geo->numVertices); + skin->findUsedBones(geo->numVertices); } ObjPipeline* diff --git a/src/plugins.cpp b/src/plugins.cpp index 8f1f576..68f6d5e 100644 --- a/src/plugins.cpp +++ b/src/plugins.cpp @@ -362,8 +362,10 @@ static void* destroySkin(void *object, int32 offset, int32) { Skin *skin = *PLUGINOFFSET(Skin*, object, offset); - if(skin) + if(skin){ delete[] skin->data; +// delete[] skin->platformData; + } delete skin; return object; } @@ -381,10 +383,10 @@ copySkin(void *dst, void *src, int32 offset, int32) *PLUGINOFFSET(Skin*, dst, offset) = dstskin; dstskin->numBones = srcskin->numBones; dstskin->numUsedBones = srcskin->numUsedBones; - dstskin->maxIndex = srcskin->maxIndex; + dstskin->numWeights = srcskin->numWeights; assert(0 && "can't copy skin yet"); - dstskin->allocateData(geometry->numVertices); + dstskin->init(srcskin->numBones, srcskin->numUsedBones, geometry->numVertices); memcpy(dstskin->usedBones, srcskin->usedBones, srcskin->numUsedBones); memcpy(dstskin->inverseMatrices, srcskin->inverseMatrices, srcskin->numBones*64); @@ -412,20 +414,22 @@ readSkin(Stream *stream, int32 len, void *object, int32 offset, int32) return; } - stream->read(header, 4); + stream->read(header, 4); // numBones, numUsedBones, numWeights, unused Skin *skin = new Skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin; - skin->numBones = header[0]; - // both values unused in/before 33002, used in/after 34003 - // probably rw::version >= 0x34000 - skin->numUsedBones = header[1]; - skin->maxIndex = header[2]; + // numUsedBones and numWeights appear in/after 34003 but not in/before 33002 + // (probably rw::version >= 0x34000) + bool oldFormat = header[1] == 0; - bool oldFormat = skin->numUsedBones == 0; - skin->allocateData(geometry->numVertices); + // Use numBones for numUsedBones to allocate data, find out the correct value later + if(oldFormat) + skin->init(header[0], header[0], geometry->numVertices); + else + skin->init(header[0], header[1], geometry->numVertices); + skin->numWeights = header[2]; - if(skin->usedBones) + if(!oldFormat) stream->read(skin->usedBones, skin->numUsedBones); if(skin->indices) stream->read(skin->indices, geometry->numVertices*4); @@ -437,6 +441,11 @@ readSkin(Stream *stream, int32 len, void *object, int32 offset, int32) stream->read(&skin->inverseMatrices[i*16], 64); } + if(oldFormat){ + skin->findNumWeights(geometry->numVertices); + skin->findUsedBones(geometry->numVertices); + } + // no split skins in GTA if(!oldFormat) stream->seek(12); @@ -461,15 +470,17 @@ writeSkin(Stream *stream, int32 len, void *object, int32 offset, int32) } Skin *skin = *PLUGINOFFSET(Skin*, object, offset); - bool oldFormat = version < 0x34003; + // not sure which version introduced the new format + bool oldFormat = version < 0x34000; header[0] = skin->numBones; - header[1] = skin->numUsedBones; - header[2] = skin->maxIndex; - header[3] = 0; if(oldFormat){ header[1] = 0; header[2] = 0; + }else{ + header[1] = skin->numUsedBones; + header[2] = skin->numWeights; } + header[3] = 0; stream->write(header, 4); if(!oldFormat) stream->write(skin->usedBones, skin->numUsedBones); @@ -512,7 +523,7 @@ getSizeSkin(void *object, int32 offset, int32) int32 size = 4 + geometry->numVertices*(16+4) + skin->numBones*64; // not sure which version introduced the new format - if(version < 0x34003) + if(version < 0x34000) size += skin->numBones*4; else size += skin->numUsedBones + 12; @@ -522,7 +533,7 @@ getSizeSkin(void *object, int32 offset, int32) static void skinRights(void *object, int32, int32, uint32) { - ((Atomic*)object)->pipeline = skinGlobals.pipelines[platformIdx[platform]]; + ((Atomic*)object)->pipeline = skinGlobals.pipelines[platformIdx[rw::platform]]; } void @@ -553,53 +564,78 @@ registerSkinPlugin(void) } void -Skin::allocateData(int32 numVerts) +Skin::init(int32 numBones, int32 numUsedBones, int32 numVertices) { + this->numBones = numBones; + this->numUsedBones = numUsedBones; uint32 size = this->numUsedBones + this->numBones*64 + - numVerts*(16+4) + 15; + numVertices*(16+4) + 0xF; this->data = new uint8[size]; - uint8 *data = this->data; + uint8 *p = this->data; this->usedBones = NULL; if(this->numUsedBones){ - this->usedBones = data; - data += this->numUsedBones; + this->usedBones = p; + p += this->numUsedBones; } - uintptr ptr = (uintptr)data + 15; - ptr &= ~0xF; - data = (uint8*)ptr; + p = (uint8*)(((uintptr)p + 0xF) & ~0xF); this->inverseMatrices = NULL; if(this->numBones){ - this->inverseMatrices = (float*)data; - data += 64*this->numBones; + this->inverseMatrices = (float*)p; + p += 64*this->numBones; } this->indices = NULL; - if(numVerts){ - this->indices = data; - data += 4*numVerts; + if(numVertices){ + this->indices = p; + p += 4*numVertices; } this->weights = NULL; - if(numVerts) - this->weights = (float*)data; + if(numVertices) + this->weights = (float*)p; this->platformData = NULL; } void -Skin::allocateVertexData(int32 numVerts) +Skin::findNumWeights(int32 numVertices) { - uint8 *usedBones = this->usedBones; - float *invMats = this->inverseMatrices; - uint8 *data = this->data; + this->numWeights = 1; + float *w = this->weights; + while(numVertices--){ + while(w[this->numWeights] != 0.0f){ + this->numWeights++; + if(this->numWeights == 4) + return; + } + w += 4; + } +} - this->allocateData(numVerts); - memcpy(this->usedBones, usedBones, this->numUsedBones); - memcpy(this->inverseMatrices, invMats, this->numBones*64); - delete[] data; +void +Skin::findUsedBones(int32 numVertices) +{ + uint8 usedTab[256]; + uint8 *indices = this->indices; + float *weights = this->weights; + memset(usedTab, 0, 256); + while(numVertices--){ + for(int32 i = 0; i < this->numWeights; i++){ + if(weights[i] == 0.0f) + continue; // TODO: this could probably be optimized + if(usedTab[indices[i]] == 0) + usedTab[indices[i]]++; + } + indices += 4; + weights += 4; + } + this->numUsedBones = 0; + for(int32 i = 0; i < 256; i++) + if(usedTab[i]) + this->usedBones[this->numUsedBones++] = i; } // diff --git a/src/ps2.cpp b/src/ps2.cpp index f659c77..5e02cc3 100644 --- a/src/ps2.cpp +++ b/src/ps2.cpp @@ -689,37 +689,32 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset) stream->read(header, 4); Skin *skin = new Skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin; - skin->numBones = header[0]; - // both values unused in/before 33002, used in/after 34003 - skin->numUsedBones = header[1]; - skin->maxIndex = header[2]; + // numUsedBones and numWeights appear in/after 34003 but not in/before 33002 + // (probably rw::version >= 0x34000) + bool oldFormat = header[1] == 0; - bool oldFormat = skin->numUsedBones == 0; - int32 size = skin->numUsedBones + skin->numBones*64 + 15; - uint8 *data = new uint8[size]; - skin->data = data; - skin->indices = NULL; - skin->weights = NULL; + // Use numBones for numUsedBones to allocate data + if(oldFormat) + skin->init(header[0], header[0], 0); + else + skin->init(header[0], header[1], 0); + skin->numWeights = header[2]; - skin->usedBones = NULL; - if(skin->numUsedBones){ - skin->usedBones = data; - data += skin->numUsedBones; - stream->read(skin->data, skin->numUsedBones); - } - - uintptr ptr = (uintptr)data + 15; - ptr &= ~0xF; - data = (uint8*)ptr; - skin->inverseMatrices = NULL; - if(skin->numBones){ - skin->inverseMatrices = (float*)data; + if(!oldFormat) + stream->read(skin->usedBones, skin->numUsedBones); + if(skin->numBones) stream->read(skin->inverseMatrices, skin->numBones*64); + + // dummy data in case we need to write data in the new format + if(oldFormat){ + skin->numWeights = 4; + for(int32 i = 0; i < skin->numUsedBones; i++) + skin->usedBones[i] = i; } if(!oldFormat) - // last 3 ints are probably the same as in generic format + // last 3 ints are split data as in the other formats // TODO: what are the other 4? stream->seek(7*4); } @@ -732,15 +727,17 @@ writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset) writeChunkHeader(stream, ID_STRUCT, len-12); stream->writeU32(PLATFORM_PS2); Skin *skin = *PLUGINOFFSET(Skin*, object, offset); - bool oldFormat = version < 0x34003; + // not sure which version introduced the new format + bool oldFormat = version < 0x34000; header[0] = skin->numBones; - header[1] = skin->numUsedBones; - header[2] = skin->maxIndex; - header[3] = 0; if(oldFormat){ header[1] = 0; header[2] = 0; + }else{ + header[1] = skin->numUsedBones; + header[2] = skin->numWeights; } + header[3] = 0; stream->write(header, 4); if(!oldFormat) @@ -760,7 +757,7 @@ getSizeNativeSkin(void *object, int32 offset) return -1; int32 size = 12 + 4 + 4 + skin->numBones*64; // not sure which version introduced the new format - if(version >= 0x34003) + if(version >= 0x34000) size += skin->numUsedBones + 16 + 12; return size; } diff --git a/src/rwobjects.h b/src/rwobjects.h index eebf616..55642dc 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -314,7 +314,7 @@ struct Skin { int32 numBones; int32 numUsedBones; - int32 maxIndex; + int32 numWeights; uint8 *usedBones; float *inverseMatrices; uint8 *indices; @@ -322,8 +322,9 @@ struct Skin uint8 *data; // only used by delete void *platformData; // a place to store platform specific stuff - void allocateData(int32 numVerts); - void allocateVertexData(int32 numVerts); + void init(int32 numBones, int32 numUsedBones, int32 numVertices); + void findNumWeights(int32 numVertices); + void findUsedBones(int32 numVertices); }; struct SkinGlobals diff --git a/src/xbox.cpp b/src/xbox.cpp index 27b20aa..e91591e 100644 --- a/src/xbox.cpp +++ b/src/xbox.cpp @@ -16,11 +16,6 @@ using namespace std; namespace rw { namespace xbox { -enum { - D3DPT_TRIANGLELIST = 5, - D3DPT_TRIANGLESTRIP = 6, -}; - void* destroyNativeData(void *object, int32, int32) { @@ -149,6 +144,11 @@ ObjPipeline::ObjPipeline(uint32 platform) void ObjPipeline::instance(Atomic *atomic) { + enum { + D3DPT_TRIANGLELIST = 5, + D3DPT_TRIANGLESTRIP = 6, + }; + Geometry *geo = atomic->geometry; if(geo->geoflags & Geometry::NATIVE) return; @@ -281,18 +281,15 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset) assert(stream->readU32() == PLATFORM_XBOX); Skin *skin = new Skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin; - skin->numBones = stream->readI32(); - // only allocate matrices - skin->numUsedBones = 0; - skin->allocateData(0); + int32 numBones = stream->readI32(); + skin->init(numBones, 0, 0); NativeSkin *natskin = new NativeSkin; skin->platformData = natskin; stream->read(natskin->table1, 256*sizeof(int32)); stream->read(natskin->table2, 256*sizeof(int32)); - // we use our own variable for this due to allocation natskin->numUsedBones = stream->readI32(); - skin->maxIndex = stream->readI32(); + skin->numWeights = stream->readI32(); stream->seek(4); // skip pointer to vertexBuffer natskin->stride = stream->readI32(); int32 size = geometry->numVertices*natskin->stride; @@ -319,7 +316,7 @@ writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset) stream->write(natskin->table1, 256*sizeof(int32)); stream->write(natskin->table2, 256*sizeof(int32)); stream->writeI32(natskin->numUsedBones); - stream->writeI32(skin->maxIndex); + stream->writeI32(skin->numWeights); stream->writeU32(0xBADEAFFE); // pointer to vertexBuffer stream->writeI32(natskin->stride); stream->write(natskin->vertexBuffer, @@ -347,6 +344,54 @@ void skinInstanceCB(Geometry *geo, InstanceDataHeader *header) { defaultInstanceCB(geo, header); + + Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset); + if(skin == NULL) + return; + NativeSkin *natskin = new NativeSkin; + skin->platformData = natskin; + + natskin->numUsedBones = skin->numUsedBones; + memset(natskin->table1, 0xFF, sizeof(natskin->table1)); + memset(natskin->table2, 0x00, sizeof(natskin->table2)); + for(int32 i = 0; i < skin->numUsedBones; i++){ + natskin->table1[i] = skin->usedBones[i]; + natskin->table2[skin->usedBones[i]] = i; + } + + natskin->stride = 3*skin->numWeights; + uint8 *vbuf = new uint8[header->numVertices*natskin->stride]; + natskin->vertexBuffer = vbuf; + + int32 w[4]; + int sum; + float *weights = skin->weights; + uint8 *p = vbuf; + int32 numVertices = header->numVertices; + while(numVertices--){ + sum = 0; + for(int i = 1; i < skin->numWeights; i++){ + w[i] = weights[i]*255.0f + 0.5f; + sum += w[i]; + } + w[0] = 255 - sum; + for(int i = 0; i < skin->numWeights; i++) + p[i] = w[i]; + p += natskin->stride; + weights += 4; + } + + numVertices = header->numVertices; + p = vbuf + skin->numWeights; + uint8 *indices = skin->indices; + uint16 *idx; + while(numVertices--){ + idx = (uint16*)p; + for(int i = 0; i < skin->numWeights; i++) + idx[i] = 3*natskin->table2[indices[i]]; + p += natskin->stride; + indices += 4; + } } ObjPipeline* diff --git a/tools/insttest/insttest.cpp b/tools/insttest/insttest.cpp index 880b8b9..f693f52 100644 --- a/tools/insttest/insttest.cpp +++ b/tools/insttest/insttest.cpp @@ -13,7 +13,6 @@ using namespace rw; int main(int argc, char *argv[]) { - rw::version = 0x33002; gta::registerEnvSpecPlugin(); rw::registerMatFXPlugin(); rw::registerMaterialRightsPlugin(); @@ -30,6 +29,7 @@ main(int argc, char *argv[]) rw::registerMeshPlugin(); rw::Atomic::init(); +// rw::version = 0x33002; // rw::platform = rw::PLATFORM_PS2; // rw::platform = rw::PLATFORM_OGL; rw::platform = rw::PLATFORM_XBOX;