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);
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*

View File

@ -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;
}
//

View File

@ -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;
}

View File

@ -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

View File

@ -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*

View File

@ -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;