refactored skin plugin a bit; wrote xbox skin instance callback

This commit is contained in:
aap 2015-09-07 10:22:54 +02:00
parent f09a1ab99f
commit 0f135f2de6
6 changed files with 177 additions and 112 deletions

View File

@ -504,40 +504,19 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset)
assert(stream->readU32() == PLATFORM_OGL); assert(stream->readU32() == PLATFORM_OGL);
Skin *skin = new Skin; Skin *skin = new Skin;
*PLUGINOFFSET(Skin*, geometry, offset) = skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin;
skin->numBones = stream->readI32();
skin->numUsedBones = 0;
skin->maxIndex = 0;
int32 size = skin->numBones*64 + 15; int32 numBones = stream->readI32();
uint8 *data = new uint8[size]; skin->init(numBones, 0, 0);
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); stream->read(skin->inverseMatrices, skin->numBones*64);
} }
}
void void
writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset) writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset)
{ {
uint8 header[4];
writeChunkHeader(stream, ID_STRUCT, len-12); writeChunkHeader(stream, ID_STRUCT, len-12);
stream->writeU32(PLATFORM_OGL); stream->writeU32(PLATFORM_OGL);
Skin *skin = *PLUGINOFFSET(Skin*, object, offset); Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
header[0] = skin->numBones; stream->writeI32(skin->numBones);
header[1] = 0;
header[2] = 0;
header[3] = 0;
stream->write(header, 4);
stream->write(skin->inverseMatrices, skin->numBones*64); stream->write(skin->inverseMatrices, skin->numBones*64);
} }
@ -608,7 +587,11 @@ skinUninstanceCB(Geometry *geo)
if(skin == NULL) if(skin == NULL)
return; 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; uint8 *p;
float *weights = skin->weights; float *weights = skin->weights;
@ -637,6 +620,9 @@ skinUninstanceCB(Geometry *geo)
break; break;
} }
} }
skin->findNumWeights(geo->numVertices);
skin->findUsedBones(geo->numVertices);
} }
ObjPipeline* ObjPipeline*

View File

@ -362,8 +362,10 @@ static void*
destroySkin(void *object, int32 offset, int32) destroySkin(void *object, int32 offset, int32)
{ {
Skin *skin = *PLUGINOFFSET(Skin*, object, offset); Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
if(skin) if(skin){
delete[] skin->data; delete[] skin->data;
// delete[] skin->platformData;
}
delete skin; delete skin;
return object; return object;
} }
@ -381,10 +383,10 @@ copySkin(void *dst, void *src, int32 offset, int32)
*PLUGINOFFSET(Skin*, dst, offset) = dstskin; *PLUGINOFFSET(Skin*, dst, offset) = dstskin;
dstskin->numBones = srcskin->numBones; dstskin->numBones = srcskin->numBones;
dstskin->numUsedBones = srcskin->numUsedBones; dstskin->numUsedBones = srcskin->numUsedBones;
dstskin->maxIndex = srcskin->maxIndex; dstskin->numWeights = srcskin->numWeights;
assert(0 && "can't copy skin yet"); 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->usedBones, srcskin->usedBones, srcskin->numUsedBones);
memcpy(dstskin->inverseMatrices, srcskin->inverseMatrices, memcpy(dstskin->inverseMatrices, srcskin->inverseMatrices,
srcskin->numBones*64); srcskin->numBones*64);
@ -412,20 +414,22 @@ readSkin(Stream *stream, int32 len, void *object, int32 offset, int32)
return; return;
} }
stream->read(header, 4); stream->read(header, 4); // numBones, numUsedBones, numWeights, unused
Skin *skin = new Skin; Skin *skin = new Skin;
*PLUGINOFFSET(Skin*, geometry, offset) = skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin;
skin->numBones = header[0];
// both values unused in/before 33002, used in/after 34003 // numUsedBones and numWeights appear in/after 34003 but not in/before 33002
// probably rw::version >= 0x34000 // (probably rw::version >= 0x34000)
skin->numUsedBones = header[1]; bool oldFormat = header[1] == 0;
skin->maxIndex = header[2];
bool oldFormat = skin->numUsedBones == 0; // Use numBones for numUsedBones to allocate data, find out the correct value later
skin->allocateData(geometry->numVertices); 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); stream->read(skin->usedBones, skin->numUsedBones);
if(skin->indices) if(skin->indices)
stream->read(skin->indices, geometry->numVertices*4); 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); stream->read(&skin->inverseMatrices[i*16], 64);
} }
if(oldFormat){
skin->findNumWeights(geometry->numVertices);
skin->findUsedBones(geometry->numVertices);
}
// no split skins in GTA // no split skins in GTA
if(!oldFormat) if(!oldFormat)
stream->seek(12); stream->seek(12);
@ -461,15 +470,17 @@ writeSkin(Stream *stream, int32 len, void *object, int32 offset, int32)
} }
Skin *skin = *PLUGINOFFSET(Skin*, object, offset); 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[0] = skin->numBones;
header[1] = skin->numUsedBones;
header[2] = skin->maxIndex;
header[3] = 0;
if(oldFormat){ if(oldFormat){
header[1] = 0; header[1] = 0;
header[2] = 0; header[2] = 0;
}else{
header[1] = skin->numUsedBones;
header[2] = skin->numWeights;
} }
header[3] = 0;
stream->write(header, 4); stream->write(header, 4);
if(!oldFormat) if(!oldFormat)
stream->write(skin->usedBones, skin->numUsedBones); stream->write(skin->usedBones, skin->numUsedBones);
@ -512,7 +523,7 @@ getSizeSkin(void *object, int32 offset, int32)
int32 size = 4 + geometry->numVertices*(16+4) + int32 size = 4 + geometry->numVertices*(16+4) +
skin->numBones*64; skin->numBones*64;
// not sure which version introduced the new format // not sure which version introduced the new format
if(version < 0x34003) if(version < 0x34000)
size += skin->numBones*4; size += skin->numBones*4;
else else
size += skin->numUsedBones + 12; size += skin->numUsedBones + 12;
@ -522,7 +533,7 @@ getSizeSkin(void *object, int32 offset, int32)
static void static void
skinRights(void *object, int32, int32, uint32) skinRights(void *object, int32, int32, uint32)
{ {
((Atomic*)object)->pipeline = skinGlobals.pipelines[platformIdx[platform]]; ((Atomic*)object)->pipeline = skinGlobals.pipelines[platformIdx[rw::platform]];
} }
void void
@ -553,53 +564,78 @@ registerSkinPlugin(void)
} }
void void
Skin::allocateData(int32 numVerts) Skin::init(int32 numBones, int32 numUsedBones, int32 numVertices)
{ {
this->numBones = numBones;
this->numUsedBones = numUsedBones;
uint32 size = this->numUsedBones + uint32 size = this->numUsedBones +
this->numBones*64 + this->numBones*64 +
numVerts*(16+4) + 15; numVertices*(16+4) + 0xF;
this->data = new uint8[size]; this->data = new uint8[size];
uint8 *data = this->data; uint8 *p = this->data;
this->usedBones = NULL; this->usedBones = NULL;
if(this->numUsedBones){ if(this->numUsedBones){
this->usedBones = data; this->usedBones = p;
data += this->numUsedBones; p += this->numUsedBones;
} }
uintptr ptr = (uintptr)data + 15; p = (uint8*)(((uintptr)p + 0xF) & ~0xF);
ptr &= ~0xF;
data = (uint8*)ptr;
this->inverseMatrices = NULL; this->inverseMatrices = NULL;
if(this->numBones){ if(this->numBones){
this->inverseMatrices = (float*)data; this->inverseMatrices = (float*)p;
data += 64*this->numBones; p += 64*this->numBones;
} }
this->indices = NULL; this->indices = NULL;
if(numVerts){ if(numVertices){
this->indices = data; this->indices = p;
data += 4*numVerts; p += 4*numVertices;
} }
this->weights = NULL; this->weights = NULL;
if(numVerts) if(numVertices)
this->weights = (float*)data; this->weights = (float*)p;
this->platformData = NULL; this->platformData = NULL;
} }
void void
Skin::allocateVertexData(int32 numVerts) Skin::findNumWeights(int32 numVertices)
{ {
uint8 *usedBones = this->usedBones; this->numWeights = 1;
float *invMats = this->inverseMatrices; float *w = this->weights;
uint8 *data = this->data; while(numVertices--){
while(w[this->numWeights] != 0.0f){
this->numWeights++;
if(this->numWeights == 4)
return;
}
w += 4;
}
}
this->allocateData(numVerts); void
memcpy(this->usedBones, usedBones, this->numUsedBones); Skin::findUsedBones(int32 numVertices)
memcpy(this->inverseMatrices, invMats, this->numBones*64); {
delete[] data; 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;
} }
// //

View File

@ -689,37 +689,32 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset)
stream->read(header, 4); stream->read(header, 4);
Skin *skin = new Skin; Skin *skin = new Skin;
*PLUGINOFFSET(Skin*, geometry, offset) = skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin;
skin->numBones = header[0];
// both values unused in/before 33002, used in/after 34003 // numUsedBones and numWeights appear in/after 34003 but not in/before 33002
skin->numUsedBones = header[1]; // (probably rw::version >= 0x34000)
skin->maxIndex = header[2]; bool oldFormat = header[1] == 0;
bool oldFormat = skin->numUsedBones == 0; // Use numBones for numUsedBones to allocate data
int32 size = skin->numUsedBones + skin->numBones*64 + 15; if(oldFormat)
uint8 *data = new uint8[size]; skin->init(header[0], header[0], 0);
skin->data = data; else
skin->indices = NULL; skin->init(header[0], header[1], 0);
skin->weights = NULL; skin->numWeights = header[2];
skin->usedBones = NULL; if(!oldFormat)
if(skin->numUsedBones){ stream->read(skin->usedBones, skin->numUsedBones);
skin->usedBones = data; if(skin->numBones)
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;
stream->read(skin->inverseMatrices, skin->numBones*64); 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) 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? // TODO: what are the other 4?
stream->seek(7*4); stream->seek(7*4);
} }
@ -732,15 +727,17 @@ writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset)
writeChunkHeader(stream, ID_STRUCT, len-12); writeChunkHeader(stream, ID_STRUCT, len-12);
stream->writeU32(PLATFORM_PS2); stream->writeU32(PLATFORM_PS2);
Skin *skin = *PLUGINOFFSET(Skin*, object, offset); 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[0] = skin->numBones;
header[1] = skin->numUsedBones;
header[2] = skin->maxIndex;
header[3] = 0;
if(oldFormat){ if(oldFormat){
header[1] = 0; header[1] = 0;
header[2] = 0; header[2] = 0;
}else{
header[1] = skin->numUsedBones;
header[2] = skin->numWeights;
} }
header[3] = 0;
stream->write(header, 4); stream->write(header, 4);
if(!oldFormat) if(!oldFormat)
@ -760,7 +757,7 @@ getSizeNativeSkin(void *object, int32 offset)
return -1; return -1;
int32 size = 12 + 4 + 4 + skin->numBones*64; int32 size = 12 + 4 + 4 + skin->numBones*64;
// not sure which version introduced the new format // not sure which version introduced the new format
if(version >= 0x34003) if(version >= 0x34000)
size += skin->numUsedBones + 16 + 12; size += skin->numUsedBones + 16 + 12;
return size; return size;
} }

View File

@ -314,7 +314,7 @@ struct Skin
{ {
int32 numBones; int32 numBones;
int32 numUsedBones; int32 numUsedBones;
int32 maxIndex; int32 numWeights;
uint8 *usedBones; uint8 *usedBones;
float *inverseMatrices; float *inverseMatrices;
uint8 *indices; uint8 *indices;
@ -322,8 +322,9 @@ struct Skin
uint8 *data; // only used by delete uint8 *data; // only used by delete
void *platformData; // a place to store platform specific stuff void *platformData; // a place to store platform specific stuff
void allocateData(int32 numVerts); void init(int32 numBones, int32 numUsedBones, int32 numVertices);
void allocateVertexData(int32 numVerts); void findNumWeights(int32 numVertices);
void findUsedBones(int32 numVertices);
}; };
struct SkinGlobals struct SkinGlobals

View File

@ -16,11 +16,6 @@ using namespace std;
namespace rw { namespace rw {
namespace xbox { namespace xbox {
enum {
D3DPT_TRIANGLELIST = 5,
D3DPT_TRIANGLESTRIP = 6,
};
void* void*
destroyNativeData(void *object, int32, int32) destroyNativeData(void *object, int32, int32)
{ {
@ -149,6 +144,11 @@ ObjPipeline::ObjPipeline(uint32 platform)
void void
ObjPipeline::instance(Atomic *atomic) ObjPipeline::instance(Atomic *atomic)
{ {
enum {
D3DPT_TRIANGLELIST = 5,
D3DPT_TRIANGLESTRIP = 6,
};
Geometry *geo = atomic->geometry; Geometry *geo = atomic->geometry;
if(geo->geoflags & Geometry::NATIVE) if(geo->geoflags & Geometry::NATIVE)
return; return;
@ -281,18 +281,15 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset)
assert(stream->readU32() == PLATFORM_XBOX); assert(stream->readU32() == PLATFORM_XBOX);
Skin *skin = new Skin; Skin *skin = new Skin;
*PLUGINOFFSET(Skin*, geometry, offset) = skin; *PLUGINOFFSET(Skin*, geometry, offset) = skin;
skin->numBones = stream->readI32();
// only allocate matrices int32 numBones = stream->readI32();
skin->numUsedBones = 0; skin->init(numBones, 0, 0);
skin->allocateData(0);
NativeSkin *natskin = new NativeSkin; NativeSkin *natskin = new NativeSkin;
skin->platformData = natskin; skin->platformData = natskin;
stream->read(natskin->table1, 256*sizeof(int32)); stream->read(natskin->table1, 256*sizeof(int32));
stream->read(natskin->table2, 256*sizeof(int32)); stream->read(natskin->table2, 256*sizeof(int32));
// we use our own variable for this due to allocation
natskin->numUsedBones = stream->readI32(); natskin->numUsedBones = stream->readI32();
skin->maxIndex = stream->readI32(); skin->numWeights = stream->readI32();
stream->seek(4); // skip pointer to vertexBuffer stream->seek(4); // skip pointer to vertexBuffer
natskin->stride = stream->readI32(); natskin->stride = stream->readI32();
int32 size = geometry->numVertices*natskin->stride; 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->table1, 256*sizeof(int32));
stream->write(natskin->table2, 256*sizeof(int32)); stream->write(natskin->table2, 256*sizeof(int32));
stream->writeI32(natskin->numUsedBones); stream->writeI32(natskin->numUsedBones);
stream->writeI32(skin->maxIndex); stream->writeI32(skin->numWeights);
stream->writeU32(0xBADEAFFE); // pointer to vertexBuffer stream->writeU32(0xBADEAFFE); // pointer to vertexBuffer
stream->writeI32(natskin->stride); stream->writeI32(natskin->stride);
stream->write(natskin->vertexBuffer, stream->write(natskin->vertexBuffer,
@ -347,6 +344,54 @@ void
skinInstanceCB(Geometry *geo, InstanceDataHeader *header) skinInstanceCB(Geometry *geo, InstanceDataHeader *header)
{ {
defaultInstanceCB(geo, 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* ObjPipeline*

View File

@ -13,7 +13,6 @@ using namespace rw;
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
rw::version = 0x33002;
gta::registerEnvSpecPlugin(); gta::registerEnvSpecPlugin();
rw::registerMatFXPlugin(); rw::registerMatFXPlugin();
rw::registerMaterialRightsPlugin(); rw::registerMaterialRightsPlugin();
@ -30,6 +29,7 @@ main(int argc, char *argv[])
rw::registerMeshPlugin(); rw::registerMeshPlugin();
rw::Atomic::init(); rw::Atomic::init();
// rw::version = 0x33002;
// rw::platform = rw::PLATFORM_PS2; // rw::platform = rw::PLATFORM_PS2;
// rw::platform = rw::PLATFORM_OGL; // rw::platform = rw::PLATFORM_OGL;
rw::platform = rw::PLATFORM_XBOX; rw::platform = rw::PLATFORM_XBOX;