librw/src/clump.cpp

682 lines
14 KiB
C++
Raw Normal View History

2014-12-18 17:26:57 +01:00
#include <cstdio>
#include <cstdlib>
#include <cstring>
2014-12-19 22:58:10 +01:00
#include <cassert>
2014-12-18 17:26:57 +01:00
#include <new>
2014-12-18 17:26:57 +01:00
#include "rwbase.h"
#include "rwplugin.h"
2015-07-11 23:48:11 +02:00
#include "rwpipeline.h"
2014-12-23 15:59:14 +01:00
#include "rwobjects.h"
2015-08-03 18:30:10 +02:00
#include "rwps2.h"
#include "rwogl.h"
#include "rwxbox.h"
#include "rwd3d8.h"
#include "rwd3d9.h"
2014-12-18 17:26:57 +01:00
using namespace std;
namespace rw {
2014-12-18 17:26:57 +01:00
Frame*
Frame::create(void)
{
Frame *f = (Frame*)malloc(PluginBase::s_size);
f->object.init(0, 0);
f->objectList.init();
f->child = NULL;
f->next = NULL;
f->root = NULL;
2014-12-24 11:38:25 +01:00
for(int i = 0; i < 16; i++)
f->matrix[i] = 0.0f;
f->matrix[0] = 1.0f;
f->matrix[5] = 1.0f;
f->matrix[10] = 1.0f;
f->matrix[15] = 1.0f;
f->matflag = 0;
f->dirty = true;
f->constructPlugins();
return f;
2014-12-18 17:26:57 +01:00
}
void
Frame::destroy(void)
2014-12-18 17:26:57 +01:00
{
this->destructPlugins();
free(this);
2014-12-18 17:26:57 +01:00
}
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;
2016-01-11 11:23:26 +01:00
child->object.parent = this;
2014-12-18 17:26:57 +01:00
child->root = this->root;
return this;
}
2014-12-19 22:58:10 +01:00
Frame*
Frame::removeChild(void)
{
2016-01-11 11:23:26 +01:00
Frame *parent = (Frame*)this->object.parent;
2014-12-19 22:58:10 +01:00
if(parent->child == this)
parent->child = this->next;
else{
Frame *f;
for(f = parent->child; f; f = f->next)
if(f->next == this)
goto found;
// not found
found:
f->next = f->next->next;
}
2016-01-11 11:23:26 +01:00
this->object.parent = NULL;
2014-12-19 22:58:10 +01:00
this->next = this->root = NULL;
return this;
}
2014-12-18 17:26:57 +01:00
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;
}
void
Frame::updateLTM(void)
{
if(!this->dirty)
return;
2016-01-11 11:23:26 +01:00
Frame *parent = (Frame*)this->object.parent;
if(parent){
parent->updateLTM();
matrixMult(this->ltm, parent->ltm, this->matrix);
this->dirty = false;
}else{
memcpy(this->ltm, this->matrix, 16*4);
this->dirty = false;
}
}
2015-01-17 15:15:03 +01:00
static Frame*
dirtyCB(Frame *f, void *)
{
f->dirty = true;
f->forAllChildren(dirtyCB, NULL);
return f;
}
void
Frame::setDirty(void)
{
this->dirty = true;
this->forAllChildren(dirtyCB, NULL);
}
2014-12-18 17:26:57 +01:00
static Frame*
sizeCB(Frame *f, void *size)
{
*(int32*)size += f->streamGetPluginSize();
f->forAllChildren(sizeCB, size);
return f;
}
2015-12-18 01:10:42 +01:00
Frame**
2014-12-18 17:26:57 +01:00
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;
}
2015-01-09 20:17:32 +01:00
//
// Clump
//
2014-12-18 17:26:57 +01:00
Clump*
Clump::create(void)
2014-12-18 17:26:57 +01:00
{
Clump *clump = (Clump*)malloc(PluginBase::s_size);
clump->object.init(2, 0);
clump->atomics.init();
clump->lights.init();
clump->constructPlugins();
return clump;
2014-12-18 17:26:57 +01:00
}
Clump*
Clump::clone(void)
2014-12-18 17:26:57 +01:00
{
Clump *clump = Clump::create();
// TODO actually clone
clump->copyPlugins(this);
return clump;
2014-12-18 17:26:57 +01:00
}
void
Clump::destroy(void)
2014-12-18 17:26:57 +01:00
{
this->destructPlugins();
free(this);
}
int32
Clump::countAtomics(void)
{
int32 n = 0;
FORLIST(l, this->atomics)
n++;
return n;
}
int32
Clump::countLights(void)
{
int32 n = 0;
FORLIST(l, this->lights)
n++;
return n;
2014-12-18 17:26:57 +01:00
}
Clump*
Clump::streamRead(Stream *stream)
2014-12-18 17:26:57 +01:00
{
uint32 length, version;
int32 buf[3];
Clump *clump;
assert(findChunk(stream, ID_STRUCT, &length, &version));
clump = Clump::create();
stream->read(buf, length);
int32 numAtomics = buf[0];
int32 numLights = 0;
if(version > 0x33000)
numLights = buf[1];
// ignore cameras
2014-12-18 17:26:57 +01:00
// Frame list
Frame **frameList;
int32 numFrames;
clump->frameListStreamRead(stream, &frameList, &numFrames);
2016-01-11 11:23:26 +01:00
clump->object.parent = (void*)frameList[0];
2014-12-18 17:26:57 +01:00
Geometry **geometryList = 0;
2015-08-16 23:23:41 +02:00
if(version >= 0x30400){
// Geometry list
int32 numGeometries = 0;
assert(findChunk(stream, ID_GEOMETRYLIST, NULL, NULL));
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
numGeometries = stream->readI32();
if(numGeometries)
geometryList = new Geometry*[numGeometries];
for(int32 i = 0; i < numGeometries; i++){
assert(findChunk(stream, ID_GEOMETRY, NULL, NULL));
geometryList[i] = Geometry::streamRead(stream);
}
2014-12-18 17:26:57 +01:00
}
// Atomics
for(int32 i = 0; i < numAtomics; i++){
assert(findChunk(stream, ID_ATOMIC, NULL, NULL));
Atomic *a = Atomic::streamReadClump(stream, frameList, geometryList);
clump->addAtomic(a);
2014-12-18 17:26:57 +01:00
}
// Lights
for(int32 i = 0; i < numLights; i++){
2014-12-18 17:26:57 +01:00
int32 frm;
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
frm = stream->readI32();
assert(findChunk(stream, ID_LIGHT, NULL, NULL));
Light *l = Light::streamRead(stream);
l->setFrame(frameList[frm]);
clump->addLight(l);
2014-12-18 17:26:57 +01:00
}
delete[] frameList;
clump->streamReadPlugins(stream);
return clump;
}
bool
Clump::streamWrite(Stream *stream)
2014-12-18 17:26:57 +01:00
{
int size = this->streamGetSize();
writeChunkHeader(stream, ID_CLUMP, size);
int32 numAtomics = this->countAtomics();
int32 numLights = this->countLights();
int buf[3] = { numAtomics, numLights, 0 };
size = version > 0x33000 ? 12 : 4;
writeChunkHeader(stream, ID_STRUCT, size);
stream->write(buf, size);
2014-12-18 17:26:57 +01:00
2016-01-11 11:23:26 +01:00
int32 numFrames = ((Frame*)this->object.parent)->count();
2014-12-18 17:26:57 +01:00
Frame **flist = new Frame*[numFrames];
2016-01-11 11:23:26 +01:00
makeFrameList((Frame*)this->object.parent, flist);
2014-12-18 17:26:57 +01:00
this->frameListStreamWrite(stream, flist, numFrames);
2015-08-16 23:23:41 +02:00
if(rw::version >= 0x30400){
size = 12+4;
FORLIST(lnk, this->atomics)
size += 12 + Atomic::fromClump(lnk)->geometry->streamGetSize();
2015-08-16 23:23:41 +02:00
writeChunkHeader(stream, ID_GEOMETRYLIST, size);
writeChunkHeader(stream, ID_STRUCT, 4);
stream->writeI32(numAtomics); // same as numGeometries
FORLIST(lnk, this->atomics)
Atomic::fromClump(lnk)->geometry->streamWrite(stream);
2015-08-16 23:23:41 +02:00
}
2014-12-18 17:26:57 +01:00
FORLIST(lnk, this->atomics)
Atomic::fromClump(lnk)->streamWriteClump(stream, flist, numFrames);
2014-12-18 17:26:57 +01:00
FORLIST(lnk, this->lights){
Light *l = Light::fromClump(lnk);
int frm = findPointer((void*)l->object.parent, (void**)flist, numFrames);
2014-12-18 17:26:57 +01:00
if(frm < 0)
return false;
writeChunkHeader(stream, ID_STRUCT, 4);
stream->writeI32(frm);
2014-12-18 17:26:57 +01:00
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)
2014-12-18 17:26:57 +01:00
size += 8; // numLights, numCameras
// frame list
2016-01-11 11:23:26 +01:00
int32 numFrames = ((Frame*)this->object.parent)->count();
2014-12-18 17:26:57 +01:00
size += 12 + 12 + 4 + numFrames*(sizeof(FrameStreamData)+12);
2016-01-11 11:23:26 +01:00
sizeCB((Frame*)this->object.parent, (void*)&size);
2014-12-18 17:26:57 +01:00
2015-08-16 23:23:41 +02:00
if(rw::version >= 0x30400){
// geometry list
size += 12 + 12 + 4;
FORLIST(lnk, this->atomics)
size += 12 + Atomic::fromClump(lnk)->geometry->streamGetSize();
2015-08-16 23:23:41 +02:00
}
2014-12-18 17:26:57 +01:00
// atomics
FORLIST(lnk, this->atomics)
size += 12 + Atomic::fromClump(lnk)->streamGetSize();
2014-12-18 17:26:57 +01:00
// light
FORLIST(lnk, this->lights)
size += 16 + 12 + Light::fromClump(lnk)->streamGetSize();
2014-12-18 17:26:57 +01:00
size += 12 + this->streamGetPluginSize();
return size;
}
void
Clump::frameListStreamRead(Stream *stream, Frame ***flp, int32 *nf)
2014-12-18 17:26:57 +01:00
{
FrameStreamData buf;
int32 numFrames = 0;
assert(findChunk(stream, ID_FRAMELIST, NULL, NULL));
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
numFrames = stream->readI32();
2014-12-18 17:26:57 +01:00
Frame **frameList = new Frame*[numFrames];
for(int32 i = 0; i < numFrames; i++){
Frame *f;
frameList[i] = f = Frame::create();
stream->read(&buf, sizeof(buf));
2014-12-18 17:26:57 +01:00
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;
f->matflag = buf.matflag;
2014-12-18 17:26:57 +01:00
if(buf.parent >= 0)
frameList[buf.parent]->addChild(f);
}
for(int32 i = 0; i < numFrames; i++)
frameList[i]->streamReadPlugins(stream);
*nf = numFrames;
*flp = frameList;
}
void
Clump::frameListStreamWrite(Stream *stream, Frame **frameList, int32 numFrames)
2014-12-18 17:26:57 +01:00
{
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);
stream->writeU32(numFrames);
2014-12-18 17:26:57 +01:00
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];
2016-01-11 11:23:26 +01:00
buf.parent = findPointer((void*)f->object.parent, (void**)frameList,
2015-08-11 21:48:23 +02:00
numFrames);
2014-12-18 17:26:57 +01:00
buf.matflag = f->matflag;
stream->write(&buf, sizeof(buf));
2014-12-18 17:26:57 +01:00
}
for(int32 i = 0; i < numFrames; i++)
frameList[i]->streamWritePlugins(stream);
}
2015-01-09 20:17:32 +01:00
//
// Atomic
//
2014-12-18 17:26:57 +01:00
Atomic*
Atomic::create(void)
2014-12-18 17:26:57 +01:00
{
Atomic *atomic = (Atomic*)malloc(PluginBase::s_size);
atomic->object.init(1, 0);
atomic->geometry = NULL;
atomic->pipeline = NULL;
atomic->constructPlugins();
return atomic;
2014-12-18 17:26:57 +01:00
}
Atomic*
Atomic::clone()
2014-12-18 17:26:57 +01:00
{
Atomic *atomic = Atomic::create();
2014-12-18 17:26:57 +01:00
//TODO
atomic->copyPlugins(this);
return atomic;
2014-12-18 17:26:57 +01:00
}
void
Atomic::destroy(void)
2014-12-18 17:26:57 +01:00
{
//TODO
this->destructPlugins();
free(this);
2014-12-18 17:26:57 +01:00
}
2015-01-10 22:13:27 +01:00
static uint32 atomicRights[2];
2014-12-18 17:26:57 +01:00
Atomic*
Atomic::streamReadClump(Stream *stream,
2014-12-18 17:26:57 +01:00
Frame **frameList, Geometry **geometryList)
{
int32 buf[4];
2015-08-16 23:23:41 +02:00
uint32 version;
assert(findChunk(stream, ID_STRUCT, NULL, &version));
stream->read(buf, version < 0x30400 ? 12 : 16);
Atomic *atomic = Atomic::create();
2016-01-11 11:23:26 +01:00
atomic->setFrame(frameList[buf[0]]);
2015-08-16 23:23:41 +02:00
if(version < 0x30400){
assert(findChunk(stream, ID_GEOMETRY, NULL, NULL));
atomic->geometry = Geometry::streamRead(stream);
}else
atomic->geometry = geometryList[buf[1]];
2015-01-10 22:13:27 +01:00
atomicRights[0] = 0;
2014-12-18 17:26:57 +01:00
atomic->streamReadPlugins(stream);
2015-01-10 22:13:27 +01:00
if(atomicRights[0])
atomic->assertRights(atomicRights[0], atomicRights[1]);
2014-12-18 17:26:57 +01:00
return atomic;
}
bool
Atomic::streamWriteClump(Stream *stream, Frame **frameList, int32 numFrames)
2014-12-18 17:26:57 +01:00
{
int32 buf[4] = { 0, 0, 5, 0 };
Clump *c = this->clump;
if(c == NULL)
return false;
writeChunkHeader(stream, ID_ATOMIC, this->streamGetSize());
2015-08-16 23:23:41 +02:00
writeChunkHeader(stream, ID_STRUCT, rw::version < 0x30400 ? 12 : 16);
2016-01-11 11:23:26 +01:00
buf[0] = findPointer((void*)this->object.parent, (void**)frameList, numFrames);
2014-12-18 17:26:57 +01:00
2015-08-16 23:23:41 +02:00
if(version < 0x30400){
stream->write(buf, sizeof(int[3]));
this->geometry->streamWrite(stream);
}else{
buf[1] = 0;
FORLIST(lnk, c->atomics){
if(Atomic::fromClump(lnk)->geometry == this->geometry)
2015-08-16 23:23:41 +02:00
goto foundgeo;
buf[1]++;
}
2015-08-16 23:23:41 +02:00
return false;
foundgeo:
stream->write(buf, sizeof(buf));
}
2014-12-18 17:26:57 +01:00
this->streamWritePlugins(stream);
return true;
}
uint32
Atomic::streamGetSize(void)
{
2015-08-16 23:23:41 +02:00
uint32 size = 12 + 12 + 12 + this->streamGetPluginSize();
if(rw::version < 0x30400)
size += 12 + this->geometry->streamGetSize();
else
size += 4;
return size;
2014-12-18 17:26:57 +01:00
}
2015-08-03 18:30:10 +02:00
ObjPipeline *defaultPipelines[NUM_PLATFORMS];
ObjPipeline*
Atomic::getPipeline(void)
{
return this->pipeline ?
this->pipeline :
2015-09-19 19:28:23 +02:00
defaultPipelines[platform];
2015-08-03 18:30:10 +02:00
}
void
Atomic::init(void)
{
ObjPipeline *defpipe = new ObjPipeline(PLATFORM_NULL);
for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++)
defaultPipelines[i] = defpipe;
2015-09-19 19:28:23 +02:00
defaultPipelines[PLATFORM_PS2] =
2015-08-03 18:30:10 +02:00
ps2::makeDefaultPipeline();
2015-09-19 19:28:23 +02:00
defaultPipelines[PLATFORM_OGL] =
2015-08-03 18:30:10 +02:00
gl::makeDefaultPipeline();
2015-09-19 19:28:23 +02:00
defaultPipelines[PLATFORM_XBOX] =
xbox::makeDefaultPipeline();
2015-09-19 19:28:23 +02:00
defaultPipelines[PLATFORM_D3D8] =
d3d8::makeDefaultPipeline();
2015-09-19 19:28:23 +02:00
defaultPipelines[PLATFORM_D3D9] =
d3d9::makeDefaultPipeline();
2015-08-03 18:30:10 +02:00
}
2015-01-09 20:17:32 +01:00
// Atomic Rights plugin
static void
readAtomicRights(Stream *stream, int32, void *, int32, int32)
{
2015-01-10 22:13:27 +01:00
stream->read(atomicRights, 8);
}
static void
writeAtomicRights(Stream *stream, int32, void *object, int32, int32)
{
Atomic *atomic = (Atomic*)object;
uint32 buffer[2];
buffer[0] = atomic->pipeline->pluginID;
buffer[1] = atomic->pipeline->pluginData;
stream->write(buffer, 8);
}
static int32
getSizeAtomicRights(void *object, int32, int32)
{
Atomic *atomic = (Atomic*)object;
if(atomic->pipeline == NULL || atomic->pipeline->pluginID == 0)
return -1;
return 8;
2015-01-09 20:17:32 +01:00
}
void
registerAtomicRightsPlugin(void)
2015-01-09 20:17:32 +01:00
{
Atomic::registerPlugin(0, ID_RIGHTTORENDER, NULL, NULL, NULL);
Atomic::registerPluginStream(ID_RIGHTTORENDER,
2015-01-10 22:13:27 +01:00
readAtomicRights,
writeAtomicRights,
getSizeAtomicRights);
2015-01-09 20:17:32 +01:00
}
//
// Light
//
2014-12-18 17:26:57 +01:00
Light*
Light::create(int32 type)
{
Light *light = (Light*)malloc(PluginBase::s_size);
light->object.init(3, type);
light->radius = 0.0f;
light->color[0] = 1.0f;
light->color[1] = 1.0f;
light->color[2] = 1.0f;
light->color[3] = 1.0f;
light->minusCosAngle = 1.0f;
light->object.privateFlags = 1;
light->object.flags = 1 | 2;
light->inClump.init();
light->constructPlugins();
return light;
2014-12-18 17:26:57 +01:00
}
void
Light::destroy(void)
2014-12-18 17:26:57 +01:00
{
this->destructPlugins();
free(this);
2014-12-18 17:26:57 +01:00
}
struct LightChunkData
{
float32 radius;
float32 red, green, blue;
float32 minusCosAngle;
uint16 flags;
uint16 type;
};
Light*
Light::streamRead(Stream *stream)
2014-12-18 17:26:57 +01:00
{
LightChunkData buf;
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
stream->read(&buf, sizeof(LightChunkData));
Light *light = Light::create(buf.type);
2014-12-18 17:26:57 +01:00
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;
2016-01-11 11:23:26 +01:00
light->object.flags = (uint8)buf.flags;
2014-12-18 17:26:57 +01:00
light->streamReadPlugins(stream);
return light;
}
bool
Light::streamWrite(Stream *stream)
2014-12-18 17:26:57 +01:00
{
LightChunkData buf;
writeChunkHeader(stream, ID_LIGHT, this->streamGetSize());
writeChunkHeader(stream, ID_STRUCT, sizeof(LightChunkData));
2014-12-18 17:26:57 +01:00
buf.radius = this->radius;
buf.red = this->color[0];
buf.green = this->color[1];
buf.blue = this->color[2];
buf.minusCosAngle = this->minusCosAngle;
2016-01-11 11:23:26 +01:00
buf.flags = this->object.flags;
buf.type = this->object.subType;
stream->write(&buf, sizeof(LightChunkData));
2014-12-18 17:26:57 +01:00
this->streamWritePlugins(stream);
return true;
}
uint32
Light::streamGetSize(void)
{
return 12 + sizeof(LightChunkData) + 12 + this->streamGetPluginSize();
}
}