mirror of
https://github.com/aap/librw.git
synced 2024-11-25 05:05:42 +00:00
Implemented generic and most of PS2 skin plugin.
This commit is contained in:
parent
811c045326
commit
e373b47041
@ -16,10 +16,13 @@ main(int argc, char *argv[])
|
|||||||
// Rw::Version = 0x31000;
|
// Rw::Version = 0x31000;
|
||||||
// Rw::Build = 0;
|
// Rw::Build = 0;
|
||||||
|
|
||||||
|
// Rw::Version = 0x33002;
|
||||||
|
|
||||||
Rw::RegisterNodeNamePlugin();
|
Rw::RegisterNodeNamePlugin();
|
||||||
Rw::RegisterBreakableModelPlugin();
|
Rw::RegisterBreakableModelPlugin();
|
||||||
Rw::RegisterExtraVertColorPlugin();
|
Rw::RegisterExtraVertColorPlugin();
|
||||||
Rw::Ps2::RegisterADCPlugin();
|
Rw::Ps2::RegisterADCPlugin();
|
||||||
|
Rw::RegisterSkinPlugin();
|
||||||
Rw::RegisterNativeDataPlugin();
|
Rw::RegisterNativeDataPlugin();
|
||||||
// Rw::Ps2::RegisterNativeDataPlugin();
|
// Rw::Ps2::RegisterNativeDataPlugin();
|
||||||
Rw::RegisterMeshPlugin();
|
Rw::RegisterMeshPlugin();
|
||||||
|
421
src/geometryplg.cpp
Normal file
421
src/geometryplg.cpp
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
//#include <iostream>
|
||||||
|
//#include <fstream>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
265
src/gtaplg.cpp
Normal file
265
src/gtaplg.cpp
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
//#include <iostream>
|
||||||
|
//#include <fstream>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
src/gtaplg.h
Normal file
40
src/gtaplg.h
Normal file
@ -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);
|
||||||
|
|
||||||
|
}
|
91
src/ps2.cpp
91
src/ps2.cpp
@ -181,6 +181,95 @@ unfixDmaOffsets(InstanceData *inst)
|
|||||||
#endif
|
#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
|
// ADC
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
@ -200,6 +289,8 @@ copyADC(void *dst, void *src, int32 offset, int32)
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: look at PC SA rccam.dff bloodrb.dff
|
||||||
|
|
||||||
static void
|
static void
|
||||||
readADC(Stream *stream, int32, void *object, int32 offset, int32)
|
readADC(Stream *stream, int32, void *object, int32 offset, int32)
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,11 @@ typedef float float32;
|
|||||||
typedef int32 bool32;
|
typedef int32 bool32;
|
||||||
typedef uint8 byte;
|
typedef uint8 byte;
|
||||||
typedef uint32 uint;
|
typedef uint32 uint;
|
||||||
|
#if __WORDSIZE == 64
|
||||||
|
typedef uint64 uintptr;
|
||||||
|
#else
|
||||||
|
typedef uint32 uintptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
class Stream
|
class Stream
|
||||||
{
|
{
|
||||||
@ -104,6 +109,7 @@ enum PluginID
|
|||||||
ID_RIGHTTORENDER = 0x1F,
|
ID_RIGHTTORENDER = 0x1F,
|
||||||
ID_UVANIMDICT = 0x2B,
|
ID_UVANIMDICT = 0x2B,
|
||||||
|
|
||||||
|
ID_SKIN = 0x116,
|
||||||
ID_ADC = 0x134,
|
ID_ADC = 0x134,
|
||||||
ID_NATIVEDATA = 0x510,
|
ID_NATIVEDATA = 0x510,
|
||||||
};
|
};
|
||||||
|
@ -148,6 +148,18 @@ struct Geometry : PluginBase<Geometry>, 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<Frame>, Object
|
struct Frame : PluginBase<Frame>, Object
|
||||||
{
|
{
|
||||||
typedef Frame *(*Callback)(Frame *f, void *data);
|
typedef Frame *(*Callback)(Frame *f, void *data);
|
||||||
@ -227,5 +239,6 @@ private:
|
|||||||
|
|
||||||
void RegisterMeshPlugin(void);
|
void RegisterMeshPlugin(void);
|
||||||
void RegisterNativeDataPlugin(void);
|
void RegisterNativeDataPlugin(void);
|
||||||
|
void RegisterSkinPlugin(void);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,12 @@ void sizedebug(InstanceData *inst);
|
|||||||
void fixDmaOffsets(InstanceData *inst);
|
void fixDmaOffsets(InstanceData *inst);
|
||||||
void unfixDmaOffsets(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
|
// ADC plugin
|
||||||
|
|
||||||
// The plugin is a little crippled due to lack of documentation
|
// The plugin is a little crippled due to lack of documentation
|
||||||
|
Loading…
Reference in New Issue
Block a user