mirror of https://github.com/aap/librw.git
First commit.
This commit is contained in:
parent
1f9e16abc0
commit
42b3520f7b
|
@ -1,4 +1,5 @@
|
||||||
librw
|
librw
|
||||||
=====
|
=====
|
||||||
|
|
||||||
New implementation of some parts of Renderware
|
This still very much work in progress.
|
||||||
|
The basics of DFFs are implemented, no plugins yet.
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue