mirror of https://github.com/aap/librw.git
First commit.
This commit is contained in:
parent
1f9e16abc0
commit
42b3520f7b
|
@ -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.
|
||||
|
|
|
@ -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