From e373b47041ff5bf2053ca5fbb0df6ade57619dc0 Mon Sep 17 00:00:00 2001 From: Angelo Papenhoff Date: Wed, 7 Jan 2015 23:06:44 +0100 Subject: [PATCH] Implemented generic and most of PS2 skin plugin. --- dffwrite.cpp | 3 + src/geometryplg.cpp | 421 ++++++++++++++++++++++++++++++++++++++++++++ src/gtaplg.cpp | 265 ++++++++++++++++++++++++++++ src/gtaplg.h | 40 +++++ src/ps2.cpp | 91 ++++++++++ src/rwbase.h | 6 + src/rwobjects.h | 13 ++ src/rwps2.h | 6 + 8 files changed, 845 insertions(+) create mode 100644 src/geometryplg.cpp create mode 100644 src/gtaplg.cpp create mode 100644 src/gtaplg.h diff --git a/dffwrite.cpp b/dffwrite.cpp index dbb424e..9e689fa 100644 --- a/dffwrite.cpp +++ b/dffwrite.cpp @@ -16,10 +16,13 @@ main(int argc, char *argv[]) // Rw::Version = 0x31000; // Rw::Build = 0; +// Rw::Version = 0x33002; + Rw::RegisterNodeNamePlugin(); Rw::RegisterBreakableModelPlugin(); Rw::RegisterExtraVertColorPlugin(); Rw::Ps2::RegisterADCPlugin(); + Rw::RegisterSkinPlugin(); Rw::RegisterNativeDataPlugin(); // Rw::Ps2::RegisterNativeDataPlugin(); Rw::RegisterMeshPlugin(); diff --git a/src/geometryplg.cpp b/src/geometryplg.cpp new file mode 100644 index 0000000..28fa01f --- /dev/null +++ b/src/geometryplg.cpp @@ -0,0 +1,421 @@ +#include +#include +#include +#include + +//#include +//#include +#include + +#include "rwbase.h" +#include "rwplugin.h" +#include "rwobjects.h" +#include "rwps2.h" +#include "rwogl.h" + +using namespace std; + +namespace Rw { + +// +// Geometry +// + +// Mesh + +static void +readMesh(Stream *stream, int32 len, void *object, int32, int32) +{ + Geometry *geo = (Geometry*)object; + int32 indbuf[256]; + uint32 buf[3]; + stream->read(buf, 12); + geo->meshHeader = new MeshHeader; + geo->meshHeader->flags = buf[0]; + geo->meshHeader->numMeshes = buf[1]; + geo->meshHeader->totalIndices = buf[2]; + geo->meshHeader->mesh = new Mesh[geo->meshHeader->numMeshes]; + Mesh *mesh = geo->meshHeader->mesh; + bool hasData = len > 12+geo->meshHeader->numMeshes*8; + for(uint32 i = 0; i < geo->meshHeader->numMeshes; i++){ + stream->read(buf, 8); + mesh->numIndices = buf[0]; + mesh->material = geo->materialList[buf[1]]; + mesh->indices = NULL; + if(geo->geoflags & Geometry::NATIVE){ + // OpenGL stores uint16 indices here + if(hasData){ + mesh->indices = new uint16[mesh->numIndices]; + stream->read(mesh->indices, + mesh->numIndices*2); + } + }else{ + mesh->indices = new uint16[mesh->numIndices]; + uint16 *ind = mesh->indices; + int32 numIndices = mesh->numIndices; + for(; numIndices > 0; numIndices -= 256){ + int32 n = numIndices < 256 ? numIndices : 256; + stream->read(indbuf, n*4); + for(int32 j = 0; j < n; j++) + ind[j] = indbuf[j]; + ind += n; + } + } + mesh++; + } +} + +static void +writeMesh(Stream *stream, int32, void *object, int32, int32) +{ + Geometry *geo = (Geometry*)object; + int32 indbuf[256]; + uint32 buf[3]; + buf[0] = geo->meshHeader->flags; + buf[1] = geo->meshHeader->numMeshes; + buf[2] = geo->meshHeader->totalIndices; + stream->write(buf, 12); + Mesh *mesh = geo->meshHeader->mesh; + for(uint32 i = 0; i < geo->meshHeader->numMeshes; i++){ + buf[0] = mesh->numIndices; + buf[1] = findPointer((void*)mesh->material, + (void**)geo->materialList, + geo->numMaterials); + stream->write(buf, 8); + if(geo->geoflags & Geometry::NATIVE){ + assert(geo->instData != NULL); + if(geo->instData->platform == PLATFORM_OGL) + stream->write(mesh->indices, + mesh->numIndices*2); + }else{ + uint16 *ind = mesh->indices; + int32 numIndices = mesh->numIndices; + for(; numIndices > 0; numIndices -= 256){ + int32 n = numIndices < 256 ? numIndices : 256; + for(int32 j = 0; j < n; j++) + indbuf[j] = ind[j]; + stream->write(indbuf, n*4); + ind += n; + } + } + mesh++; + } +} + +static int32 +getSizeMesh(void *object, int32) +{ + Geometry *geo = (Geometry*)object; + if(geo->meshHeader == NULL) + return -1; + int32 size = 12 + geo->meshHeader->numMeshes*8; + if(geo->geoflags & Geometry::NATIVE){ + assert(geo->instData != NULL); + if(geo->instData->platform == PLATFORM_OGL) + size += geo->meshHeader->totalIndices*2; + }else{ + size += geo->meshHeader->totalIndices*4; + } + return size; +} + + +void +RegisterMeshPlugin(void) +{ + Geometry::registerPlugin(0, 0x50E, NULL, NULL, NULL); + Geometry::registerPluginStream(0x50E, (StreamRead)readMesh, + (StreamWrite)writeMesh, + (StreamGetSize)getSizeMesh); +} + +// Native Data + +static void* +destroyNativeData(void *object, int32 offset, int32 size) +{ + Geometry *geometry = (Geometry*)object; + if(geometry->instData == NULL) + return object; + if(geometry->instData->platform == PLATFORM_PS2) + return Ps2::DestroyNativeData(object, offset, size); + if(geometry->instData->platform == PLATFORM_OGL) + return Gl::DestroyNativeData(object, offset, size); + return object; +} + +static void +readNativeData(Stream *stream, int32 len, void *object, int32 o, int32 s) +{ + ChunkHeaderInfo header; + uint32 libid; + uint32 platform; + // ugly hack to find out platform + stream->seek(-4); + libid = stream->readU32(); + ReadChunkHeaderInfo(stream, &header); + if(header.type == ID_STRUCT && + LibraryIDPack(header.version, header.build) == libid){ + // must be PS2 or Xbox + platform = stream->readU32(); + stream->seek(-16); + if(platform == PLATFORM_PS2) + Ps2::ReadNativeData(stream, len, object, o, s); + else if(platform == PLATFORM_XBOX) + stream->seek(len); + }else{ + stream->seek(-12); + Gl::ReadNativeData(stream, len, object, o, s); + } +} + +static void +writeNativeData(Stream *stream, int32 len, void *object, int32 o, int32 s) +{ + Geometry *geometry = (Geometry*)object; + if(geometry->instData == NULL) + return; + if(geometry->instData->platform == PLATFORM_PS2) + Ps2::WriteNativeData(stream, len, object, o, s); + else if(geometry->instData->platform == PLATFORM_OGL) + Gl::WriteNativeData(stream, len, object, o, s); +} + +static int32 +getSizeNativeData(void *object, int32 offset, int32 size) +{ + Geometry *geometry = (Geometry*)object; + if(geometry->instData == NULL) + return -1; + if(geometry->instData->platform == PLATFORM_PS2) + return Ps2::GetSizeNativeData(object, offset, size); + else if(geometry->instData->platform == PLATFORM_XBOX) + return -1; + else if(geometry->instData->platform == PLATFORM_OGL) + return Gl::GetSizeNativeData(object, offset, size); + return -1; +} + +void +RegisterNativeDataPlugin(void) +{ + Geometry::registerPlugin(0, ID_NATIVEDATA, + NULL, destroyNativeData, NULL); + Geometry::registerPluginStream(ID_NATIVEDATA, + (StreamRead)readNativeData, + (StreamWrite)writeNativeData, + (StreamGetSize)getSizeNativeData); +} + +// Skin + +static void* +createSkin(void *object, int32 offset, int32) +{ + *PLUGINOFFSET(Skin*, object, offset) = NULL; + return object; +} + +static void* +destroySkin(void *object, int32 offset, int32) +{ + Skin *skin = *PLUGINOFFSET(Skin*, object, offset); + if(skin) + delete[] skin->data; + delete skin; + return object; +} + +static void* +copySkin(void *dst, void *src, int32 offset, int32) +{ + Geometry *geometry = (Geometry*)src; + assert(geometry->instData == NULL); + assert(((Geometry*)src)->numVertices == ((Geometry*)dst)->numVertices); + Skin *srcskin = *PLUGINOFFSET(Skin*, src, offset); + if(srcskin == NULL) + return dst; + Skin *dstskin = new Skin; + *PLUGINOFFSET(Skin*, dst, offset) = dstskin; + dstskin->numBones = srcskin->numBones; + dstskin->numUsedBones = srcskin->numUsedBones; + dstskin->maxIndex = srcskin->maxIndex; + uint32 size = srcskin->numUsedBones + + srcskin->numBones*64 + + geometry->numVertices*(16+4) + 15; + uint8 *data = new uint8[size]; + dstskin->data = data; + memcpy(dstskin->data, srcskin->data, size); + + dstskin->usedBones = NULL; + if(srcskin->usedBones){ + dstskin->usedBones = data; + data += dstskin->numUsedBones; + } + + uintptr ptr = (uintptr)data + 15; + ptr &= ~0xF; + data = (uint8*)ptr; + dstskin->inverseMatrices = NULL; + if(srcskin->inverseMatrices){ + dstskin->inverseMatrices = (float*)data; + data += 64*dstskin->numBones; + } + + dstskin->indices = NULL; + if(srcskin->indices){ + dstskin->indices = data; + data += 4*geometry->numVertices; + } + + dstskin->weights = NULL; + if(srcskin->weights) + dstskin->weights = (float*)data; + + return dst; +} + +static void +readSkin(Stream *stream, int32 len, void *object, int32 offset, int32) +{ + uint8 header[4]; + Geometry *geometry = (Geometry*)object; + + if(geometry->instData){ + assert(geometry->instData->platform == PLATFORM_PS2); + Ps2::ReadNativeSkin(stream, len, object, offset); + return; + } + + 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]; + + bool oldFormat = skin->numUsedBones == 0; + uint32 size = skin->numUsedBones + + skin->numBones*64 + + geometry->numVertices*(16+4) + 15; + uint8 *data = new uint8[size]; + skin->data = data; + + skin->usedBones = NULL; + if(skin->numUsedBones){ + skin->usedBones = data; + data += skin->numUsedBones; + } + + uintptr ptr = (uintptr)data + 15; + ptr &= ~0xF; + data = (uint8*)ptr; + skin->inverseMatrices = NULL; + if(skin->numBones){ + skin->inverseMatrices = (float*)data; + data += 64*skin->numBones; + } + + skin->indices = NULL; + if(geometry->numVertices){ + skin->indices = data; + data += 4*geometry->numVertices; + } + + skin->weights = NULL; + if(geometry->numVertices) + skin->weights = (float*)data; + + if(skin->usedBones) + stream->read(skin->usedBones, skin->numUsedBones); + if(skin->indices) + stream->read(skin->indices, geometry->numVertices*4); + if(skin->weights) + stream->read(skin->weights, geometry->numVertices*16); + for(int32 i = 0; i < skin->numBones; i++){ + if(oldFormat) + stream->seek(4); // skip 0xdeaddead + stream->read(&skin->inverseMatrices[i*16], 64); + } + // TODO: find out what this is (related to skin splitting) + // always 0 in GTA files + if(!oldFormat) + stream->seek(12); +} + +static void +writeSkin(Stream *stream, int32 len, void *object, int32 offset, int32) +{ + uint8 header[4]; + Geometry *geometry = (Geometry*)object; + + if(geometry->instData){ + assert(geometry->instData->platform == PLATFORM_PS2); + Ps2::WriteNativeSkin(stream, len, object, offset); + return; + } + + Skin *skin = *PLUGINOFFSET(Skin*, object, offset); + bool oldFormat = Version < 0x34003; + header[0] = skin->numBones; + header[1] = skin->numUsedBones; + header[2] = skin->maxIndex; + header[3] = 0; + if(oldFormat){ + header[1] = 0; + header[2] = 0; + } + stream->write(header, 4); + if(!oldFormat) + stream->write(skin->usedBones, skin->numUsedBones); + stream->write(skin->indices, geometry->numVertices*4); + stream->write(skin->weights, geometry->numVertices*16); + for(int32 i = 0; i < skin->numBones; i++){ + if(oldFormat) + stream->writeU32(0xdeaddead); + stream->write(&skin->inverseMatrices[i*16], 64); + } + if(!oldFormat){ + uint32 buffer[3] = { 0, 0, 0}; + stream->write(buffer, 12); + } +} + +static int32 +getSizeSkin(void *object, int32 offset, int32) +{ + Geometry *geometry = (Geometry*)object; + + if(geometry->instData){ + assert(geometry->instData->platform == PLATFORM_PS2); + return Ps2::GetSizeNativeSkin(object, offset); + } + + Skin *skin = *PLUGINOFFSET(Skin*, object, offset); + if(skin == NULL) + return -1; + + int32 size = 4 + geometry->numVertices*(16+4) + + skin->numBones*64; + // not sure which version introduced the new format + if(Version < 0x34003) + size += skin->numBones*4; + else + size += skin->numUsedBones + 12; + return size; +} + +void +RegisterSkinPlugin(void) +{ + Geometry::registerPlugin(sizeof(Skin*), ID_SKIN, + createSkin, destroySkin, copySkin); + Geometry::registerPluginStream(ID_SKIN, + (StreamRead)readSkin, + (StreamWrite)writeSkin, + (StreamGetSize)getSizeSkin); +} + +} diff --git a/src/gtaplg.cpp b/src/gtaplg.cpp new file mode 100644 index 0000000..4980cd1 --- /dev/null +++ b/src/gtaplg.cpp @@ -0,0 +1,265 @@ +#include +#include +#include +#include + +//#include +//#include +#include + +#include "rwbase.h" +#include "rwplugin.h" +#include "rwobjects.h" +#include "gtaplg.h" + +using namespace std; + +namespace Rw { + +// +// Frame +// + +// Node Name + +static void* +createNodeName(void *object, int32 offset, int32) +{ + char *name = PLUGINOFFSET(char, object, offset); + name[0] = '\0'; + return object; +} + +static void* +copyNodeName(void *dst, void *src, int32 offset, int32) +{ + char *dstname = PLUGINOFFSET(char, dst, offset); + char *srcname = PLUGINOFFSET(char, src, offset); + strncpy(dstname, srcname, 17); + return dst; +} + +static void* +destroyNodeName(void *object, int32, int32) +{ + return object; +} + +static void +readNodeName(Stream *stream, int32 len, void *object, int32 offset, int32) +{ + char *name = PLUGINOFFSET(char, object, offset); + stream->read(name, len); + name[len] = '\0'; +} + +static void +writeNodeName(Stream *stream, int32 len, void *object, int32 offset, int32) +{ + char *name = PLUGINOFFSET(char, object, offset); + stream->write(name, len); +} + +static int32 +getSizeNodeName(void *object, int32 offset) +{ + char *name = PLUGINOFFSET(char, object, offset); + int32 len = strlen(name); + return len > 0 ? len : -1; +} + + +void +RegisterNodeNamePlugin(void) +{ + Frame::registerPlugin(18, ID_NODENAME, + (Constructor)createNodeName, + (Destructor)destroyNodeName, + (CopyConstructor)copyNodeName); + Frame::registerPluginStream(0x253f2fe, (StreamRead)readNodeName, + (StreamWrite)writeNodeName, + (StreamGetSize)getSizeNodeName); +} + +// +// Geometry +// + +// Breakable Model + +static void* +createBreakableModel(void *object, int32 offset, int32) +{ + *PLUGINOFFSET(uint8*, object, offset) = 0; + return object; +} + +static void* +destroyBreakableModel(void *object, int32 offset, int32) +{ + uint8 *p = *PLUGINOFFSET(uint8*, object, offset); + delete[] p; + return object; +} + +static void +readBreakableModel(Stream *stream, int32, void *object, int32 o, int32) +{ + uint32 header[13]; + uint32 hasBreakable = stream->readU32(); + if(hasBreakable == 0) + return; + stream->read(header, 13*4); + uint32 size = header[1]*(12+8+4) + header[5]*(6+2) + + header[8]*(32+32+12); + uint8 *p = new uint8[sizeof(Breakable)+size]; + Breakable *breakable = (Breakable*)p; + *PLUGINOFFSET(Breakable*, object, o) = breakable; + breakable->position = header[0]; + breakable->numVertices = header[1]; + breakable->numFaces = header[5]; + breakable->numMaterials = header[8]; + p += sizeof(Breakable); + stream->read(p, size); + breakable->vertices = (float*)p; + p += breakable->numVertices*12; + breakable->texCoords = (float*)p; + p += breakable->numVertices*8; + breakable->colors = (uint8*)p; + p += breakable->numVertices*4; + breakable->faces = (uint16*)p; + p += breakable->numFaces*6; + breakable->matIDs = (uint16*)p; + p += breakable->numFaces*2; + breakable->texNames = (char(*)[32])p; + p += breakable->numMaterials*32; + breakable->maskNames = (char(*)[32])p; + p += breakable->numMaterials*32; + breakable->surfaceProps = (float32(*)[3])p; +} + +static void +writeBreakableModel(Stream *stream, int32, void *object, int32 o, int32) +{ + uint32 header[13]; + Breakable *breakable = *PLUGINOFFSET(Breakable*, object, o); + uint8 *p = (uint8*)breakable; + if(breakable == NULL){ + stream->writeU32(0); + return; + } + stream->writeU32(1); + memset((char*)header, 0, 13*4); + header[0] = breakable->position; + header[1] = breakable->numVertices; + header[5] = breakable->numFaces; + header[8] = breakable->numMaterials; + stream->write(header, 13*4); + p += sizeof(Breakable); + stream->write(p, breakable->numVertices*(12+8+4) + + breakable->numFaces*(6+2) + + breakable->numMaterials*(32+32+12)); +} + +static int32 +getSizeBreakableModel(void *object, int32 offset, int32) +{ + Breakable *breakable = *PLUGINOFFSET(Breakable*, object, offset); + if(breakable == NULL) + return 4; + return 56 + breakable->numVertices*(12+8+4) + + breakable->numFaces*(6+2) + + breakable->numMaterials*(32+32+12); +} + +void +RegisterBreakableModelPlugin(void) +{ + Geometry::registerPlugin(sizeof(Breakable*), ID_BREAKABLE, + createBreakableModel, + destroyBreakableModel, NULL); + Geometry::registerPluginStream(ID_BREAKABLE, + (StreamRead)readBreakableModel, + (StreamWrite)writeBreakableModel, + (StreamGetSize)getSizeBreakableModel); +} + +// Extra colors + + +static void* +createExtraVertColors(void *object, int32 offset, int32) +{ + ExtraVertColors *colordata = + PLUGINOFFSET(ExtraVertColors, object, offset); + colordata->nightColors = NULL; + colordata->dayColors = NULL; + colordata->balance = 0.0f; + return object; +} + +static void* +destroyExtraVertColors(void *object, int32 offset, int32) +{ + ExtraVertColors *colordata = + PLUGINOFFSET(ExtraVertColors, object, offset); + delete[] colordata->nightColors; + delete[] colordata->dayColors; + return object; +} + +static void +readExtraVertColors(Stream *stream, int32, void *object, int32 offset, int32) +{ + uint32 hasData; + ExtraVertColors *colordata = + PLUGINOFFSET(ExtraVertColors, object, offset); + hasData = stream->readU32(); + if(!hasData) + return; + Geometry *geometry = (Geometry*)object; + colordata->nightColors = new uint8[geometry->numVertices*4]; + colordata->dayColors = new uint8[geometry->numVertices*4]; + colordata->balance = 1.0f; + stream->read(colordata->nightColors, geometry->numVertices*4); + if(geometry->colors) + memcpy(colordata->dayColors, geometry->colors, + geometry->numVertices*4); +} + +static void +writeExtraVertColors(Stream *stream, int32, void *object, int32 offset, int32) +{ + ExtraVertColors *colordata = + PLUGINOFFSET(ExtraVertColors, object, offset); + stream->writeU32(colordata->nightColors != NULL); + if(colordata->nightColors){ + Geometry *geometry = (Geometry*)object; + stream->write(colordata->nightColors, geometry->numVertices*4); + } +} + +static int32 +getSizeExtraVertColors(void *object, int32 offset, int32) +{ + ExtraVertColors *colordata = + PLUGINOFFSET(ExtraVertColors, object, offset); + Geometry *geometry = (Geometry*)object; + if(colordata->nightColors) + return 4 + geometry->numVertices*4; + return -1; +} + +void +RegisterExtraVertColorPlugin(void) +{ + Geometry::registerPlugin(sizeof(ExtraVertColors), ID_EXTRAVERTCOLORS, + createExtraVertColors, + destroyExtraVertColors, NULL); + Geometry::registerPluginStream(ID_EXTRAVERTCOLORS, + (StreamRead)readExtraVertColors, + (StreamWrite)writeExtraVertColors, + (StreamGetSize)getSizeExtraVertColors); +} + +} diff --git a/src/gtaplg.h b/src/gtaplg.h new file mode 100644 index 0000000..dd5a1ca --- /dev/null +++ b/src/gtaplg.h @@ -0,0 +1,40 @@ +namespace Rw { + +enum +{ + ID_EXTRAVERTCOLORS = 0x253f2f9, + ID_BREAKABLE = 0x253f2fd, + ID_NODENAME = 0x253f2fe +}; + +void RegisterNodeNamePlugin(void); + +struct Breakable +{ + uint32 position; + uint32 numVertices; + uint32 numFaces; + uint32 numMaterials; + + float32 *vertices; + float32 *texCoords; + uint8 *colors; + uint16 *faces; + uint16 *matIDs; + char (*texNames)[32]; + char (*maskNames)[32]; + float32 (*surfaceProps)[3]; +}; + +void RegisterBreakableModelPlugin(void); + +struct ExtraVertColors +{ + uint8 *nightColors; + uint8 *dayColors; + float balance; +}; + +void RegisterExtraVertColorPlugin(void); + +} diff --git a/src/ps2.cpp b/src/ps2.cpp index 9e959fa..122f169 100644 --- a/src/ps2.cpp +++ b/src/ps2.cpp @@ -181,6 +181,95 @@ unfixDmaOffsets(InstanceData *inst) #endif } +// Skin + +void +ReadNativeSkin(Stream *stream, int32, void *object, int32 offset) +{ + uint8 header[4]; + uint32 vers; + Geometry *geometry = (Geometry*)object; + assert(FindChunk(stream, ID_STRUCT, NULL, &vers)); + assert(stream->readU32() == PLATFORM_PS2); + 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]; + + 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; + + 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; + stream->read(skin->inverseMatrices, skin->numBones*64); + } + + if(!oldFormat) + // last 3 ints are probably the same as in generic format + // TODO: what are the other 4? + stream->seek(7*4); +} + +void +WriteNativeSkin(Stream *stream, int32 len, void *object, int32 offset) +{ + uint8 header[4]; + + WriteChunkHeader(stream, ID_STRUCT, len-12); + stream->writeU32(PLATFORM_PS2); + Skin *skin = *PLUGINOFFSET(Skin*, object, offset); + bool oldFormat = Version < 0x34003; + header[0] = skin->numBones; + header[1] = skin->numUsedBones; + header[2] = skin->maxIndex; + header[3] = 0; + if(oldFormat){ + header[1] = 0; + header[2] = 0; + } + stream->write(header, 4); + + if(!oldFormat) + stream->write(skin->usedBones, skin->numUsedBones); + stream->write(skin->inverseMatrices, skin->numBones*64); + if(!oldFormat){ + uint32 buffer[7] = { 0, 0, 0, 0, 0, 0, 0 }; + stream->write(buffer, 7*4); + } +} + +int32 +GetSizeNativeSkin(void *object, int32 offset) +{ + Skin *skin = *PLUGINOFFSET(Skin*, object, offset); + if(skin == NULL) + return -1; + int32 size = 12 + 4 + 4 + skin->numBones*64; + // not sure which version introduced the new format + if(Version >= 0x34003) + size += skin->numUsedBones + 16 + 12; + return size; +} + // ADC static void* @@ -200,6 +289,8 @@ copyADC(void *dst, void *src, int32 offset, int32) return dst; } +// TODO: look at PC SA rccam.dff bloodrb.dff + static void readADC(Stream *stream, int32, void *object, int32 offset, int32) { diff --git a/src/rwbase.h b/src/rwbase.h index e77bb3e..21fa2e2 100644 --- a/src/rwbase.h +++ b/src/rwbase.h @@ -12,6 +12,11 @@ typedef float float32; typedef int32 bool32; typedef uint8 byte; typedef uint32 uint; +#if __WORDSIZE == 64 +typedef uint64 uintptr; +#else +typedef uint32 uintptr; +#endif class Stream { @@ -104,6 +109,7 @@ enum PluginID ID_RIGHTTORENDER = 0x1F, ID_UVANIMDICT = 0x2B, + ID_SKIN = 0x116, ID_ADC = 0x134, ID_NATIVEDATA = 0x510, }; diff --git a/src/rwobjects.h b/src/rwobjects.h index 35ac4ca..374ab0c 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -148,6 +148,18 @@ struct Geometry : PluginBase, Object }; }; +struct Skin +{ + int32 numBones; + int32 numUsedBones; + int32 maxIndex; + uint8 *usedBones; + float *inverseMatrices; + uint8 *indices; + float *weights; + uint8 *data; // only used by delete +}; + struct Frame : PluginBase, Object { typedef Frame *(*Callback)(Frame *f, void *data); @@ -227,5 +239,6 @@ private: void RegisterMeshPlugin(void); void RegisterNativeDataPlugin(void); +void RegisterSkinPlugin(void); } diff --git a/src/rwps2.h b/src/rwps2.h index 59f8cc0..d5295aa 100644 --- a/src/rwps2.h +++ b/src/rwps2.h @@ -32,6 +32,12 @@ void sizedebug(InstanceData *inst); void fixDmaOffsets(InstanceData *inst); void unfixDmaOffsets(InstanceData *inst); +// Skin plugin + +void ReadNativeSkin(Stream *stream, int32, void *object, int32 offset); +void WriteNativeSkin(Stream *stream, int32 len, void *object, int32 offset); +int32 GetSizeNativeSkin(void *object, int32 offset); + // ADC plugin // The plugin is a little crippled due to lack of documentation