First commit.

This commit is contained in:
Angelo Papenhoff 2014-12-18 17:26:57 +01:00
parent 1f9e16abc0
commit 42b3520f7b
8 changed files with 1609 additions and 1 deletions

View File

@ -1,4 +1,5 @@
librw
=====
New implementation of some parts of Renderware
This still very much work in progress.
The basics of DFFs are implemented, no plugins yet.

495
clump.cpp Normal file
View File

@ -0,0 +1,495 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <fstream>
#include "rwbase.h"
#include "rwplugin.h"
#include "rw.h"
using namespace std;
namespace Rw {
static int32
findFrame(Frame *f, Frame **frameList, int32 numFrames)
{
int frm;
for(frm = 0; frm < numFrames; frm++)
if(frameList[frm] == f)
goto foundfrm;
return -1;
foundfrm:
return frm;
}
Frame::Frame(void)
{
this->child = NULL;
this->next = NULL;
this->root = NULL;
constructPlugins();
}
Frame::Frame(Frame *f)
{
// TODO
copyPlugins(f);
}
Frame::~Frame(void)
{
destructPlugins();
}
Frame*
Frame::addChild(Frame *child)
{
if(this->child == NULL)
this->child = child;
else{
Frame *f;
for(f = this->child; f->next; f = f->next);
f->next = child;
}
child->next = NULL;
child->parent = this;
child->root = this->root;
return this;
}
Frame*
Frame::forAllChildren(Callback cb, void *data)
{
for(Frame *f = this->child; f; f = f->next)
cb(f, data);
return this;
}
static Frame*
countCB(Frame *f, void *count)
{
(*(int32*)count)++;
f->forAllChildren(countCB, count);
return f;
}
int32
Frame::count(void)
{
int32 count = 1;
this->forAllChildren(countCB, (void*)&count);
return count;
}
static Frame*
sizeCB(Frame *f, void *size)
{
*(int32*)size += f->streamGetPluginSize();
f->forAllChildren(sizeCB, size);
return f;
}
static Frame**
makeFrameList(Frame *frame, Frame **flist)
{
*flist++ = frame;
if(frame->next)
flist = makeFrameList(frame->next, flist);
if(frame->child)
flist = makeFrameList(frame->child, flist);
return flist;
}
Clump::Clump(void)
{
this->numAtomics = 0;
this->numLights = 0;
this->numCameras = 0;
constructPlugins();
}
Clump::Clump(Clump *c)
{
this->numAtomics = c->numAtomics;
this->numLights = c->numLights;
this->numCameras = c->numCameras;
copyPlugins(c);
}
Clump::~Clump(void)
{
destructPlugins();
}
Clump*
Clump::streamRead(istream &stream)
{
uint32 length, version;
int32 buf[3];
Clump *clump;
if(!FindChunk(stream, ID_STRUCT, &length, &version))
return NULL;
clump = new Clump;
stream.read((char*)buf, length);
clump->numAtomics = buf[0];
clump->numLights = 0;
clump->numCameras = 0;
if(version >= 0x33000){
clump->numLights = buf[1];
clump->numCameras = buf[2];
}
// Frame list
Frame **frameList;
int32 numFrames;
clump->frameListStreamRead(stream, &frameList, &numFrames);
clump->parent = (void*)frameList[0];
// Geometry list
int32 numGeometries = 0;
if(!FindChunk(stream, ID_GEOMETRYLIST, NULL, NULL))
return NULL;
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return NULL;
numGeometries = readInt32(stream);
Geometry **geometryList = new Geometry*[numGeometries];
for(int32 i = 0; i < numGeometries; i++){
if(!FindChunk(stream, ID_GEOMETRY, NULL, NULL))
return NULL;
geometryList[i] = Geometry::streamRead(stream);
}
// Atomics
clump->atomicList = new Atomic*[clump->numAtomics];
for(int32 i = 0; i < clump->numAtomics; i++){
if(!FindChunk(stream, ID_ATOMIC, NULL, NULL))
return NULL;
clump->atomicList[i] = Atomic::streamReadClump(stream,
frameList, geometryList);
clump->atomicList[i]->clump = clump;
}
// Lights
clump->lightList = new Light*[clump->numLights];
for(int32 i = 0; i < clump->numLights; i++){
int32 frm;
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return NULL;
frm = readInt32(stream);
if(!FindChunk(stream, ID_LIGHT, NULL, NULL))
return NULL;
clump->lightList[i] = Light::streamRead(stream);
clump->lightList[i]->frame = frameList[frm];
clump->lightList[i]->clump = clump;
}
delete[] frameList;
clump->streamReadPlugins(stream);
return clump;
}
bool
Clump::streamWrite(ostream &stream)
{
int size = this->streamGetSize();
WriteChunkHeader(stream, ID_CLUMP, size);
int buf[3] = { this->numAtomics, this->numLights, this->numCameras };
size = Version >= 0x33000 ? 12 : 4;
WriteChunkHeader(stream, ID_STRUCT, size);
stream.write((char*)buf, size);
int32 numFrames = ((Frame*)this->parent)->count();
Frame **flist = new Frame*[numFrames];
makeFrameList((Frame*)this->parent, flist);
this->frameListStreamWrite(stream, flist, numFrames);
size = 12+4;
for(int32 i = 0; i < this->numAtomics; i++)
size += 12 + this->atomicList[i]->geometry->streamGetSize();
WriteChunkHeader(stream, ID_GEOMETRYLIST, size);
WriteChunkHeader(stream, ID_STRUCT, 4);
writeInt32(this->numAtomics, stream); // same as numGeometries
for(int32 i = 0; i < this->numAtomics; i++)
this->atomicList[i]->geometry->streamWrite(stream);
for(int32 i = 0; i < this->numAtomics; i++)
this->atomicList[i]->streamWriteClump(stream, flist, numFrames);
for(int32 i = 0; i < this->numLights; i++){
Light *l = this->lightList[i];
int frm = findFrame(l->frame, flist, numFrames);
if(frm < 0)
return false;
WriteChunkHeader(stream, ID_STRUCT, 4);
writeInt32(frm, stream);
l->streamWrite(stream);
}
delete[] flist;
this->streamWritePlugins(stream);
return true;
}
struct FrameStreamData
{
float32 mat[9];
float32 pos[3];
int32 parent;
int32 matflag;
};
uint32
Clump::streamGetSize(void)
{
uint32 size = 0;
size += 12; // Struct
size += 4; // numAtomics
if(Version >= 0x33000)
size += 8; // numLights, numCameras
// frame list
int32 numFrames = ((Frame*)this->parent)->count();
size += 12 + 12 + 4 + numFrames*(sizeof(FrameStreamData)+12);
sizeCB((Frame*)this->parent, (void*)&size);
// geometry list
size += 12 + 12 + 4;
for(int32 i = 0; i < this->numAtomics; i++)
size += 12 + this->atomicList[i]->geometry->streamGetSize();
// atomics
for(int32 i = 0; i < this->numAtomics; i++)
size += 12 + this->atomicList[i]->streamGetSize();
// light
for(int32 i = 0; i < this->numAtomics; i++)
size += 16 + 12 + this->lightList[i]->streamGetSize();
size += 12 + this->streamGetPluginSize();
return size;
}
void
Clump::frameListStreamRead(istream &stream, Frame ***flp, int32 *nf)
{
FrameStreamData buf;
int32 numFrames = 0;
if(!FindChunk(stream, ID_FRAMELIST, NULL, NULL))
return;
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return;
numFrames = readInt32(stream);
Frame **frameList = new Frame*[numFrames];
for(int32 i = 0; i < numFrames; i++){
Frame *f;
frameList[i] = f = new Frame;
stream.read((char*)&buf, sizeof(buf));
f->matrix[0] = buf.mat[0];
f->matrix[1] = buf.mat[1];
f->matrix[2] = buf.mat[2];
f->matrix[3] = 0.0f;
f->matrix[4] = buf.mat[3];
f->matrix[5] = buf.mat[4];
f->matrix[6] = buf.mat[5];
f->matrix[7] = 0.0f;
f->matrix[8] = buf.mat[6];
f->matrix[9] = buf.mat[7];
f->matrix[10] = buf.mat[8];
f->matrix[11] = 0.0f;
f->matrix[12] = buf.pos[0];
f->matrix[13] = buf.pos[1];
f->matrix[14] = buf.pos[2];
f->matrix[15] = 1.0f;
if(buf.parent >= 0)
frameList[buf.parent]->addChild(f);
f->matflag = buf.matflag;
}
for(int32 i = 0; i < numFrames; i++)
frameList[i]->streamReadPlugins(stream);
*nf = numFrames;
*flp = frameList;
}
void
Clump::frameListStreamWrite(ostream &stream, Frame **frameList, int32 numFrames)
{
FrameStreamData buf;
int size = 0, structsize = 0;
structsize = 4 + numFrames*sizeof(FrameStreamData);
size += 12 + structsize;
for(int32 i = 0; i < numFrames; i++)
size += 12 + frameList[i]->streamGetPluginSize();
WriteChunkHeader(stream, ID_FRAMELIST, size);
WriteChunkHeader(stream, ID_STRUCT, structsize);
writeUInt32(numFrames, stream);
for(int32 i = 0; i < numFrames; i++){
Frame *f = frameList[i];
buf.mat[0] = f->matrix[0];
buf.mat[1] = f->matrix[1];
buf.mat[2] = f->matrix[2];
buf.mat[3] = f->matrix[4];
buf.mat[4] = f->matrix[5];
buf.mat[5] = f->matrix[6];
buf.mat[6] = f->matrix[8];
buf.mat[7] = f->matrix[9];
buf.mat[8] = f->matrix[10];
buf.pos[0] = f->matrix[12];
buf.pos[1] = f->matrix[13];
buf.pos[2] = f->matrix[14];
buf.parent = findFrame(f, frameList, numFrames);
buf.matflag = f->matflag;
stream.write((char*)&buf, sizeof(buf));
}
for(int32 i = 0; i < numFrames; i++)
frameList[i]->streamWritePlugins(stream);
}
Atomic::Atomic(void)
{
this->frame = NULL;
this->geometry = NULL;
constructPlugins();
}
Atomic::Atomic(Atomic *a)
{
//TODO
copyPlugins(a);
}
Atomic::~Atomic(void)
{
//TODO
destructPlugins();
}
Atomic*
Atomic::streamReadClump(istream &stream,
Frame **frameList, Geometry **geometryList)
{
int32 buf[4];
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return NULL;
stream.read((char*)buf, 16);
Atomic *atomic = new Atomic;
atomic->frame = frameList[buf[0]];
atomic->geometry = geometryList[buf[1]];
atomic->streamReadPlugins(stream);
return atomic;
}
bool
Atomic::streamWriteClump(ostream &stream, Frame **frameList, int32 numFrames)
{
int32 buf[4] = { 0, 0, 5, 0 };
Clump *c = this->clump;
if(c == NULL)
return false;
WriteChunkHeader(stream, ID_ATOMIC, this->streamGetSize());
WriteChunkHeader(stream, ID_STRUCT, 16);
buf[0] = findFrame(this->frame, frameList, numFrames);
// TODO
for(buf[1] = 0; buf[1] < c->numAtomics; buf[1]++)
if(c->atomicList[buf[1]]->geometry == this->geometry)
goto foundgeo;
return false;
foundgeo:
stream.write((char*)buf, sizeof(buf));
this->streamWritePlugins(stream);
return true;
}
uint32
Atomic::streamGetSize(void)
{
return 12 + 16 + 12 + this->streamGetPluginSize();
}
Light::Light(void)
{
this->frame = NULL;
constructPlugins();
}
Light::Light(Light *l)
{
// TODO
copyPlugins(l);
}
Light::~Light(void)
{
destructPlugins();
}
struct LightChunkData
{
float32 radius;
float32 red, green, blue;
float32 minusCosAngle;
uint16 flags;
uint16 type;
};
Light*
Light::streamRead(istream &stream)
{
LightChunkData buf;
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return NULL;
Light *light = new Light;
stream.read((char*)&buf, sizeof(LightChunkData));
light->radius = buf.radius;
light->color[0] = buf.red;
light->color[1] = buf.green;
light->color[2] = buf.blue;
light->color[3] = 1.0f;
light->minusCosAngle = buf.minusCosAngle;
light->flags = (uint8)buf.flags;
light->subType = (uint8)buf.type;
light->streamReadPlugins(stream);
return light;
}
bool
Light::streamWrite(ostream &stream)
{
LightChunkData buf;
WriteChunkHeader(stream, ID_LIGHT, this->streamGetSize());
WriteChunkHeader(stream, ID_STRUCT, sizeof(LightChunkData));
buf.radius = this->radius;
buf.red = this->color[0];
buf.green = this->color[1];
buf.blue = this->color[2];
buf.minusCosAngle = this->minusCosAngle;
buf.flags = this->flags;
buf.type = this->subType;
stream.write((char*)&buf, sizeof(LightChunkData));
this->streamWritePlugins(stream);
return true;
}
uint32
Light::streamGetSize(void)
{
return 12 + sizeof(LightChunkData) + 12 + this->streamGetPluginSize();
}
}

407
geometry.cpp Normal file
View File

@ -0,0 +1,407 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <fstream>
#include "rwbase.h"
#include "rwplugin.h"
#include "rw.h"
using namespace std;
namespace Rw {
Geometry::Geometry(void)
{
geoflags = 0;
numTriangles = 0;
numVertices = 0;
numMorphTargets = 0;
numTexCoordSets = 0;
triangles = 0;
colors = 0;
for(int i = 0; i < 8; i++)
texCoords[i] = 0;
morphTargets = NULL;
constructPlugins();
}
Geometry::Geometry(Geometry *g)
{
// TODO
geoflags = g->geoflags;
numTriangles = g->numTriangles;
numVertices = g->numVertices;
numMorphTargets = g->numMorphTargets;
numTexCoordSets = g->numTexCoordSets;
copyPlugins(g);
}
Geometry::~Geometry(void)
{
destructPlugins();
}
struct GeoStreamData
{
uint32 flags;
int32 numTriangles;
int32 numVertices;
int32 numMorphTargets;
};
Geometry*
Geometry::streamRead(istream &stream)
{
uint32 version;
GeoStreamData buf;
if(!FindChunk(stream, ID_STRUCT, NULL, &version))
return NULL;
Geometry *geo = new Geometry;
stream.read((char*)&buf, sizeof(buf));
geo->geoflags = buf.flags & 0xFF00FFFF;
geo->numTexCoordSets = (buf.flags & 0xFF0000) >> 16;
if(geo->numTexCoordSets == 0 && (geo->geoflags & TEXTURED))
geo->numTexCoordSets = 1;
geo->numTriangles = buf.numTriangles;
geo->numVertices = buf.numVertices;
geo->numMorphTargets = buf.numMorphTargets;
// skip surface properties
if(version < 0x34000)
stream.seekg(12, ios::cur);
if(!(geo->geoflags & 0xFF000000)){
if(geo->geoflags & PRELIT){
geo->colors = new uint8[4*geo->numVertices];
stream.read((char*)geo->colors, 4*geo->numVertices);
}
if((geo->geoflags & TEXTURED) || (geo->geoflags & TEXTURED2))
for(int32 i = 0; i < geo->numTexCoordSets; i++){
geo->texCoords[i] =
new float32[2*geo->numVertices];
stream.read((char*)geo->texCoords[i],
2*geo->numVertices*4);
}
geo->triangles = new uint16[4*geo->numTriangles];
stream.read((char*)geo->triangles, 4*geo->numTriangles*2);
}
geo->morphTargets = new MorphTarget[geo->numMorphTargets];
for(int32 i = 0; i < geo->numMorphTargets; i++){
MorphTarget *m = &geo->morphTargets[i];
stream.read((char*)m->boundingSphere, 4*4);
int32 hasVertices = readInt32(stream);
int32 hasNormals = readInt32(stream);
if(hasVertices){
m->vertices = new float32[3*geo->numVertices];
stream.read((char*)m->vertices, 3*geo->numVertices*4);
}
if(hasNormals){
m->normals = new float32[3*geo->numVertices];
stream.read((char*)m->normals, 3*geo->numVertices*4);
}
}
if(!FindChunk(stream, ID_MATLIST, NULL, NULL))
return geo;
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return geo;
geo->numMaterials = readInt32(stream);
geo->materialList = new Material*[geo->numMaterials];
stream.seekg(geo->numMaterials*4, ios::cur); // unused (-1)
for(int32 i = 0; i < geo->numMaterials; i++){
if(!FindChunk(stream, ID_MATERIAL, NULL, NULL))
return geo;
geo->materialList[i] = Material::streamRead(stream);
}
geo->streamReadPlugins(stream);
return geo;
}
static uint32
geoStructSize(Geometry *geo)
{
uint32 size = 0;
size += sizeof(GeoStreamData);
if(Version < 0x34000)
size += 12; // surface properties
if(!(geo->geoflags & 0xFF000000)){
if(geo->geoflags&geo->PRELIT)
size += 4*geo->numVertices;
if((geo->geoflags & geo->TEXTURED) ||
(geo->geoflags & geo->TEXTURED2))
for(int32 i = 0; i < geo->numTexCoordSets; i++)
size += 2*geo->numVertices*4;
size += 4*geo->numTriangles*2;
}
for(int32 i = 0; i < geo->numMorphTargets; i++){
MorphTarget *m = &geo->morphTargets[i];
size += 4*4 + 2*4; // bounding sphere and bools
if(m->vertices)
size += 3*geo->numVertices*4;
if(m->normals)
size += 3*geo->numVertices*4;
}
return size;
}
bool
Geometry::streamWrite(ostream &stream)
{
GeoStreamData buf;
uint32 size;
static float32 fbuf[3] = { 1.0f, 1.0f, 1.0f };
WriteChunkHeader(stream, ID_GEOMETRY, this->streamGetSize());
WriteChunkHeader(stream, ID_STRUCT, geoStructSize(this));
buf.flags = this->geoflags | this->numTexCoordSets << 16;
buf.numTriangles = this->numTriangles;
buf.numVertices = this->numVertices;
buf.numMorphTargets = this->numMorphTargets;
stream.write((char*)&buf, sizeof(buf));
if(Version < 0x34000)
stream.write((char*)fbuf, sizeof(fbuf));
if(!(this->geoflags & 0xFF000000)){
if(this->geoflags & PRELIT)
stream.write((char*)this->colors, 4*this->numVertices);
if((this->geoflags & TEXTURED) || (this->geoflags & TEXTURED2))
for(int32 i = 0; i < this->numTexCoordSets; i++)
stream.write((char*)this->texCoords[i],
2*this->numVertices*4);
stream.write((char*)this->triangles, 4*this->numTriangles*2);
}
for(int32 i = 0; i < this->numMorphTargets; i++){
MorphTarget *m = &this->morphTargets[i];
stream.write((char*)m->boundingSphere, 4*4);
writeInt32(m->vertices != NULL, stream);
writeInt32(m->normals != NULL, stream);
if(m->vertices)
stream.write((char*)m->vertices, 3*this->numVertices*4);
if(m->normals)
stream.write((char*)m->normals, 3*this->numVertices*4);
}
size = 12 + 4;
for(int32 i = 0; i < this->numMaterials; i++)
size += 4 + 12 + this->materialList[i]->streamGetSize();
WriteChunkHeader(stream, ID_MATLIST, size);
WriteChunkHeader(stream, ID_STRUCT, 4 + this->numMaterials*4);
writeInt32(this->numMaterials, stream);
for(int32 i = 0; i < this->numMaterials; i++)
writeInt32(-1, stream);
for(int32 i = 0; i < this->numMaterials; i++)
this->materialList[i]->streamWrite(stream);
this->streamWritePlugins(stream);
return true;
}
uint32
Geometry::streamGetSize(void)
{
uint32 size = 0;
size += 12 + geoStructSize(this);
size += 12 + 12 + 4;
for(int32 i = 0; i < this->numMaterials; i++)
size += 4 + 12 + this->materialList[i]->streamGetSize();
size += 12 + this->streamGetPluginSize();
return size;
}
Material::Material(void)
{
this->texture = NULL;
color[0] = color[1] = color[2] = color[3] = 0xFF;
surfaceProps[0] = surfaceProps[1] = surfaceProps[2] = 1.0f;
constructPlugins();
}
Material::Material(Material *m)
{
m->color[0] = this->color[0];
m->color[1] = this->color[1];
m->color[2] = this->color[2];
m->color[3] = this->color[3];
m->surfaceProps[0] = this->surfaceProps[0];
m->surfaceProps[1] = this->surfaceProps[1];
m->surfaceProps[2] = this->surfaceProps[2];
copyPlugins(m);
}
Material::~Material(void)
{
destructPlugins();
}
struct MatStreamData
{
int32 flags; // unused according to RW
uint8 color[4];
int32 unused;
int32 textured;
float32 surfaceProps[3];
};
Material*
Material::streamRead(istream &stream)
{
uint32 length;
MatStreamData buf;
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return NULL;
stream.read((char*)&buf, sizeof(buf));
Material *mat = new Material;
mat->color[0] = buf.color[0];
mat->color[1] = buf.color[1];
mat->color[2] = buf.color[2];
mat->color[3] = buf.color[3];
mat->surfaceProps[0] = buf.surfaceProps[0];
mat->surfaceProps[1] = buf.surfaceProps[1];
mat->surfaceProps[2] = buf.surfaceProps[2];
if(buf.textured){
if(!FindChunk(stream, ID_TEXTURE, &length, NULL))
return NULL;
mat->texture = Texture::streamRead(stream);
}
mat->streamReadPlugins(stream);
return mat;
}
bool
Material::streamWrite(ostream &stream)
{
MatStreamData buf;
WriteChunkHeader(stream, ID_MATERIAL, this->streamGetSize());
WriteChunkHeader(stream, ID_STRUCT, sizeof(MatStreamData));
buf.color[0] = this->color[0];
buf.color[1] = this->color[1];
buf.color[2] = this->color[2];
buf.color[3] = this->color[3];
buf.surfaceProps[0] = this->surfaceProps[0];
buf.surfaceProps[1] = this->surfaceProps[1];
buf.surfaceProps[2] = this->surfaceProps[2];
buf.flags = 0;
buf.unused = 0;
buf.textured = this->texture != NULL;
stream.write((char*)&buf, sizeof(buf));
if(this->texture)
this->texture->streamWrite(stream);
this->streamWritePlugins(stream);
return true;
}
uint32
Material::streamGetSize(void)
{
uint32 size = 0;
size += 12 + sizeof(MatStreamData);
if(this->texture)
size += 12 + this->texture->streamGetSize();
size += 12 + this->streamGetPluginSize();
return size;
}
Texture::Texture(void)
{
memset(this->name, 0, 32);
memset(this->mask, 0, 32);
this->filterAddressing = 0;
constructPlugins();
}
Texture::Texture(Texture *t)
{
memcpy(this->name, t->name, 32);
memcpy(this->mask, t->name, 32);
this->filterAddressing = t->filterAddressing;
copyPlugins(t);
}
Texture::~Texture(void)
{
destructPlugins();
}
Texture*
Texture::streamRead(istream &stream)
{
uint32 length;
if(!FindChunk(stream, ID_STRUCT, NULL, NULL))
return NULL;
Texture *tex = new Texture;
tex->filterAddressing = readUInt16(stream);
stream.seekg(2, ios::cur);
if(!FindChunk(stream, ID_STRING, &length, NULL))
return NULL;
stream.read(tex->name, length);
if(!FindChunk(stream, ID_STRING, &length, NULL))
return NULL;
stream.read(tex->mask, length);
tex->streamReadPlugins(stream);
return tex;
}
bool
Texture::streamWrite(ostream &stream)
{
int size;
WriteChunkHeader(stream, ID_TEXTURE, this->streamGetSize());
WriteChunkHeader(stream, ID_STRUCT, 4);
writeUInt32(this->filterAddressing, stream);
size = strnlen(this->name, 32)+3 & ~3;
if(size < 4)
size = 4;
WriteChunkHeader(stream, ID_STRING, size);
stream.write(this->name, size);
size = strnlen(this->mask, 32)+3 & ~3;
if(size < 4)
size = 4;
WriteChunkHeader(stream, ID_STRING, size);
stream.write(this->mask, size);
this->streamWritePlugins(stream);
return true;
}
uint32
Texture::streamGetSize(void)
{
uint32 size = 0;
int strsize;
size += 12 + 4;
size += 12 + 12;
strsize = strnlen(this->name, 32)+3 & ~3;
size += strsize < 4 ? 4 : strsize;
strsize = strnlen(this->mask, 32)+3 & ~3;
size += strsize < 4 ? 4 : strsize;
size += 12 + this->streamGetPluginSize();
return size;
}
}

95
main.cpp Normal file
View File

@ -0,0 +1,95 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <fstream>
#include <list>
#include "rwbase.h"
#include "rwplugin.h"
#include "rw.h"
using namespace std;
//
// X - Plugin of Clump
//
struct X
{
Rw::int32 a;
Rw::int32 b;
};
void*
ctorX(void *object, int offset, int)
{
X *x = PLUGINOFFSET(X, object, offset);
x->a = 123;
x->b = 789;
return object;
}
void*
dtorX(void *object, int, int)
{
return object;
}
void*
cctorX(void *dst, void *src, int offset, int)
{
X *srcx = PLUGINOFFSET(X, src, offset);
X *dstx = PLUGINOFFSET(X, dst, offset);
dstx->a = srcx->a;
dstx->b = srcx->b;
return dst;
}
Rw::int32
getSizeX(void *, int, int)
{
return 8;
}
void
writeX(ostream &stream, Rw::int32, void *object, int offset, int)
{
X *x = PLUGINOFFSET(X, object, offset);
Rw::writeInt32(x->a, stream);
Rw::writeInt32(x->b, stream);
}
void
readX(istream &stream, Rw::int32, void *object, int offset, int)
{
X *x = PLUGINOFFSET(X, object, offset);
x->a = Rw::readInt32(stream);
x->b = Rw::readInt32(stream);
}
int
main(int argc, char *argv[])
{
// Rw::Version = 0x31000;
// Rw::Build = 0;
// int Xoff = Rw::Clump::registerPlugin(8, 0x123, ctorX, dtorX, cctorX);
// Xoff = Rw::Clump::registerPluginStream(0x123, readX, writeX, getSizeX);
Rw::Clump *c;
// X *x;
ifstream in(argv[1], ios::binary);
Rw::FindChunk(in, Rw::ID_CLUMP, NULL, NULL);
c = Rw::Clump::streamRead(in);
in.close();
ofstream out("out.dff", ios::binary);
c->streamWrite(out);
out.close();
delete c;
return 0;
}

161
rw.h Normal file
View File

@ -0,0 +1,161 @@
namespace Rw {
struct Object
{
uint8 type;
uint8 subType;
uint8 flags;
void *parent;
};
struct Texture : PluginBase<Texture>
{
char name[32];
char mask[32];
uint32 filterAddressing;
Texture(void);
Texture(Texture *t);
~Texture(void);
static Texture *streamRead(std::istream &stream);
bool streamWrite(std::ostream &stream);
uint32 streamGetSize(void);
};
struct Material : PluginBase<Material>
{
Texture *texture;
uint8 color[4];
float32 surfaceProps[3];
Material(void);
Material(Material *m);
~Material(void);
static Material *streamRead(std::istream &stream);
bool streamWrite(std::ostream &stream);
uint32 streamGetSize(void);
};
struct MorphTarget
{
float32 boundingSphere[4];
float32 *vertices;
float32 *normals;
};
struct Geometry : PluginBase<Geometry>, Object
{
uint32 geoflags;
int32 numTriangles;
int32 numVertices;
int32 numMorphTargets;
int32 numTexCoordSets;
uint16 *triangles;
uint8 *colors;
float32 *texCoords[8];
MorphTarget *morphTargets;
int32 numMaterials;
Material **materialList;
Geometry(void);
Geometry(Geometry *g);
~Geometry(void);
static Geometry *streamRead(std::istream &stream);
bool streamWrite(std::ostream &stream);
uint32 streamGetSize(void);
enum Flags
{
TRISTRIP = 0x01,
POSITIONS = 0x02,
TEXTURED = 0x04,
PRELIT = 0x08,
NORMALS = 0x10,
LIGHT = 0x20,
MODULATE = 0x40,
TEXTURED2 = 0x80,
NATIVE = 0x01000000,
NATIVEINSTANCE = 0x02000000
};
};
struct Frame : PluginBase<Frame>, Object
{
typedef Frame *(*Callback)(Frame *f, void *data);
float32 matrix[16];
float32 ltm[16];
Frame *child;
Frame *next;
Frame *root;
// temporary
int32 matflag;
Frame(void);
Frame(Frame *f);
~Frame(void);
Frame *addChild(Frame *f);
Frame *forAllChildren(Callback cb, void *data);
int32 count(void);
};
struct Clump;
struct Light : PluginBase<Light>, Object
{
Frame *frame;
float32 radius;
float32 color[4];
float32 minusCosAngle;
Clump *clump;
Light(void);
Light(Light *l);
~Light(void);
static Light *streamRead(std::istream &stream);
bool streamWrite(std::ostream &stream);
uint32 streamGetSize(void);
};
struct Atomic : PluginBase<Atomic>, Object
{
Frame *frame;
Geometry *geometry;
Clump *clump;
Atomic(void);
Atomic(Atomic *a);
~Atomic(void);
static Atomic *streamReadClump(std::istream &stream,
Frame **frameList, Geometry **geometryList);
bool streamWriteClump(std::ostream &stream,
Frame **frameList, int32 numFrames);
uint32 streamGetSize(void);
};
struct Clump : PluginBase<Clump>, Object
{
int32 numAtomics;
Atomic **atomicList;
int32 numLights;
Light **lightList;
int32 numCameras;
// cameras not implemented
Clump(void);
Clump(Clump *c);
~Clump(void);
static Clump *streamRead(std::istream &stream);
bool streamWrite(std::ostream &stream);
uint32 streamGetSize(void);
private:
void frameListStreamRead(std::istream &stream, Frame ***flp, int32 *nf);
void frameListStreamWrite(std::ostream &stream, Frame **flp, int32 nf);
};
}

163
rwbase.cpp Normal file
View File

@ -0,0 +1,163 @@
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <fstream>
#include "rwbase.h"
#include "rwplugin.h"
using namespace std;
namespace Rw {
int Version = 0x36003;
int Build = 0xFFFF;
uint32
writeInt8(int8 tmp, ostream &rw)
{
rw.write((char*)&tmp, sizeof(int8));
return sizeof(int8);
}
uint32
writeUInt8(uint8 tmp, ostream &rw)
{
rw.write((char*)&tmp, sizeof(uint8));
return sizeof(uint8);
}
uint32
writeInt16(int16 tmp, ostream &rw)
{
rw.write((char*)&tmp, sizeof(int16));
return sizeof(int16);
}
uint32
writeUInt16(uint16 tmp, ostream &rw)
{
rw.write((char*)&tmp, sizeof(uint16));
return sizeof(uint16);
}
uint32
writeInt32(int32 tmp, ostream &rw)
{
rw.write((char*)&tmp, sizeof(int32));
return sizeof(int32);
}
uint32
writeUInt32(uint32 tmp, ostream &rw)
{
rw.write((char*)&tmp, sizeof(uint32));
return sizeof(uint32);
}
uint32
writeFloat32(float32 tmp, ostream &rw)
{
rw.write((char*)&tmp, sizeof(float32));
return sizeof(float32);
}
uint8
readUInt8(istream &rw)
{
uint8 tmp;
rw.read((char*)&tmp, sizeof(uint8));
return tmp;
}
int16
readInt16(istream &rw)
{
int16 tmp;
rw.read((char*)&tmp, sizeof(int16));
return tmp;
}
uint16
readUInt16(istream &rw)
{
uint16 tmp;
rw.read((char*)&tmp, sizeof(uint16));
return tmp;
}
int32
readInt32(istream &rw)
{
int32 tmp;
rw.read((char*)&tmp, sizeof(int32));
return tmp;
}
uint32
readUInt32(istream &rw)
{
uint32 tmp;
rw.read((char*)&tmp, sizeof(uint32));
return tmp;
}
float32
readFloat32(istream &rw)
{
float32 tmp;
rw.read((char*)&tmp, sizeof(float32));
return tmp;
}
bool
WriteChunkHeader(ostream &s, int32 type, int32 size)
{
struct {
int32 type, size;
uint32 id;
} buf = { type, size, LibraryIDPack(Version, Build) };
s.write((char*)&buf, 12);
return true;
}
bool
ReadChunkHeaderInfo(istream &s, ChunkHeaderInfo *header)
{
struct {
int32 type, size;
uint32 id;
} buf;
s.read((char*)&buf, 12);
if(s.eof())
return false;
assert(header != NULL);
header->type = buf.type;
header->length = buf.size;
header->version = LibraryIDUnpackVersion(buf.id);
header->build = LibraryIDUnpackBuild(buf.id);
return true;
}
bool
FindChunk(istream &s, uint32 type, uint32 *length, uint32 *version)
{
ChunkHeaderInfo header;
while(ReadChunkHeaderInfo(s, &header)){
if(header.type == ID_NAOBJECT)
return false;
if(header.type == type){
if(length)
*length = header.length;
if(version)
*version = header.version;
return true;
}
s.seekg(header.length, ios::cur);
}
return false;
}
}

100
rwbase.h Normal file
View File

@ -0,0 +1,100 @@
namespace Rw {
typedef char int8;
typedef short int16;
typedef int int32;
typedef long long int64;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
typedef float float32;
typedef uint8 byte;
typedef uint32 uint;
uint32 writeInt8(int8 tmp, std::ostream &rw);
uint32 writeUInt8(uint8 tmp, std::ostream &rw);
uint32 writeInt16(int16 tmp, std::ostream &rw);
uint32 writeUInt16(uint16 tmp, std::ostream &rw);
uint32 writeInt32(int32 tmp, std::ostream &rw);
uint32 writeUInt32(uint32 tmp, std::ostream &rw);
uint32 writeFloat32(float32 tmp, std::ostream &rw);
int8 readInt8(std::istream &rw);
uint8 readUInt8(std::istream &rw);
int16 readInt16(std::istream &rw);
uint16 readUInt16(std::istream &rw);
int32 readInt32(std::istream &rw);
uint32 readUInt32(std::istream &rw);
float32 readFloat32(std::istream &rw);
enum PluginID
{
// Core
ID_NAOBJECT = 0x0,
ID_STRUCT = 0x1,
ID_STRING = 0x2,
ID_EXTENSION = 0x3,
ID_CAMERA = 0x5,
ID_TEXTURE = 0x6,
ID_MATERIAL = 0x7,
ID_MATLIST = 0x8,
ID_FRAMELIST = 0xE,
ID_GEOMETRY = 0xF,
ID_CLUMP = 0x10,
ID_LIGHT = 0x12,
ID_ATOMIC = 0x14,
ID_TEXTURENATIVE = 0x15,
ID_TEXDICTIONARY = 0x16,
ID_GEOMETRYLIST = 0x1A,
ID_ANIMANIMATION = 0x1B,
ID_RIGHTTORENDER = 0x1F,
ID_UVANIMDICT = 0x2B,
};
extern int Version;
extern int Build;
inline uint32
LibraryIDPack(int version, int build)
{
if(build){
version -= 0x30000;
return (version&0xFFC0) << 14 | (version&0x3F) << 16 |
(build & 0xFFFF);
}
return version>>8;
}
inline int
LibraryIDUnpackVersion(uint32 libid)
{
if(libid & 0xFFFF0000)
return (libid>>14 & 0x3FF00) |
(libid>>16 & 0x3F) |
0x30000;
else
return libid<<8;
}
inline int
LibraryIDUnpackBuild(uint32 libid)
{
if(libid & 0xFFFF0000)
return libid & 0xFFFF;
else
return 0;
}
struct ChunkHeaderInfo
{
uint32 type;
uint32 length;
uint32 version, build;
};
// TODO?: make these methods of ChunkHeaderInfo?
bool WriteChunkHeader(std::ostream &s, int32 type, int32 size);
bool ReadChunkHeaderInfo(std::istream &s, ChunkHeaderInfo *header);
bool FindChunk(std::istream &s, uint32 type, uint32 *length, uint32 *version);
}

186
rwplugin.h Normal file
View File

@ -0,0 +1,186 @@
namespace Rw {
#define PLUGINOFFSET(type, base, offset) \
((type*)((char*)(base) + (offset)))
typedef void *(*Constructor)(void *object, int offset, int size);
typedef void *(*Destructor)(void *object, int offset, int size);
typedef void *(*CopyConstructor)(void *dst, void *src, int offset, int size);
typedef void (*StreamRead)(std::istream &stream, int length, void *object, int offset, int size);
typedef void (*StreamWrite)(std::ostream &stream, int length, void *object, int offset, int size);
typedef int32 (*StreamGetSize)(void *object, int offset, int size);
struct Plugin
{
int offset;
int size;
uint id;
Constructor constructor;
Destructor destructor;
CopyConstructor copy;
StreamRead read;
StreamWrite write;
StreamGetSize getSize;
Plugin *next;
};
template <typename T>
struct PluginBase
{
static int s_defaultSize;
static int s_size;
static Plugin *s_plugins;
void constructPlugins(void);
void destructPlugins(void);
void copyPlugins(T *t);
void streamReadPlugins(std::istream &stream);
void streamWritePlugins(std::ostream &stream);
int streamGetPluginSize(void);
static int registerPlugin(int size, uint id,
Constructor, Destructor, CopyConstructor);
static int registerPluginStream(uint id,
StreamRead, StreamWrite, StreamGetSize);
static int getPluginOffset(uint id);
static void *operator new(size_t size);
static void operator delete(void *p);
};
template <typename T>
int PluginBase<T>::s_defaultSize = sizeof(T);
template <typename T>
int PluginBase<T>::s_size = sizeof(T);
template <typename T>
Plugin *PluginBase<T>::s_plugins = 0;
template <typename T> void
PluginBase<T>::constructPlugins(void)
{
for(Plugin *p = this->s_plugins; p; p = p->next)
if(p->constructor)
p->constructor((void*)this, p->offset, p->size);
}
template <typename T> void
PluginBase<T>::destructPlugins(void)
{
for(Plugin *p = this->s_plugins; p; p = p->next)
if(p->destructor)
p->destructor((void*)this, p->offset, p->size);
}
template <typename T> void
PluginBase<T>::copyPlugins(T *t)
{
for(Plugin *p = this->s_plugins; p; p = p->next)
if(p->copy)
p->copy((void*)this, (void*)t, p->offset, p->size);
}
template <typename T> void
PluginBase<T>::streamReadPlugins(std::istream &stream)
{
uint32 length;
Rw::ChunkHeaderInfo header;
if(!Rw::FindChunk(stream, Rw::ID_EXTENSION, &length, NULL))
return;
while(length){
Rw::ReadChunkHeaderInfo(stream, &header);
length -= 12;
for(Plugin *p = this->s_plugins; p; p = p->next)
if(p->id == header.type){
p->read(stream, header.length,
(void*)this, p->offset, p->size);
goto cont;
}
stream.seekg(header.length, std::ios::cur);
cont:
length -= header.length;
}
}
template <typename T> void
PluginBase<T>::streamWritePlugins(std::ostream &stream)
{
int size = this->streamGetPluginSize();
Rw::WriteChunkHeader(stream, Rw::ID_EXTENSION, size);
for(Plugin *p = this->s_plugins; p; p = p->next){
if((size = p->getSize(this, p->offset, p->size)) < 0)
continue;
Rw::WriteChunkHeader(stream, p->id, size);
p->write(stream, size, this, p->offset, p->size);
}
}
template <typename T> int
PluginBase<T>::streamGetPluginSize(void)
{
int size = 0;
int plgsize;
for(Plugin *p = this->s_plugins; p; p = p->next)
if(p->getSize &&
(plgsize = p->getSize(this, p->offset, p->size)) >= 0)
size += 12 + plgsize;
return size;
}
template <typename T> int
PluginBase<T>::registerPlugin(int size, uint id,
Constructor ctor, Destructor dtor, CopyConstructor cctor)
{
Plugin *p = new Plugin;
p->offset = s_size;
s_size += size;
p->size = size;
p->id = id;
p->constructor = ctor;
p->copy = cctor;
p->destructor = dtor;
p->read = NULL;
p->write = NULL;
p->getSize = NULL;
p->next = s_plugins;
s_plugins = p;
return p->offset;
}
template <typename T> int
PluginBase<T>::registerPluginStream(uint id,
StreamRead read, StreamWrite write, StreamGetSize getSize)
{
for(Plugin *p = PluginBase<T>::s_plugins; p; p = p->next)
if(p->id == id){
p->read = read;
p->write = write;
p->getSize = getSize;
return p->offset;
}
return -1;
}
template <typename T> int
PluginBase<T>::getPluginOffset(uint id)
{
for(Plugin *p = PluginBase<T>::s_plugins; p; p = p->next)
if(p->id == id)
return p->offset;
return -1;
}
template <typename T> void*
PluginBase<T>::operator new(size_t)
{
void *m = malloc(T::s_size);
if(!m)
throw std::bad_alloc();
return m;
}
template <typename T> void
PluginBase<T>::operator delete(void *p)
{
free(p);
}
}