mirror of https://github.com/aap/librw.git
implemented basic error system; restructured some files; replaced a few asserts
This commit is contained in:
parent
416ee91bb7
commit
6e71e34933
1
rw.h
1
rw.h
|
@ -2,6 +2,7 @@
|
|||
#include <cmath>
|
||||
|
||||
#include "src/rwbase.h"
|
||||
#include "src/rwerror.h"
|
||||
#include "src/rwplg.h"
|
||||
#include "src/rwpipeline.h"
|
||||
#include "src/rwobjects.h"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
ECODE(ERR_GENERAL,
|
||||
"General Error")
|
||||
ECODE(ERR_ALLOC,
|
||||
"Couldn't allocate 0x%X bytes")
|
||||
ECODE(ERR_FILE,
|
||||
"Couldn't open file %s")
|
||||
ECODE(ERR_CHUNK,
|
||||
"Couldn't find chunk %s")
|
|
@ -0,0 +1,167 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwerror.h"
|
||||
#include "rwplg.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
|
||||
#define PLUGIN_ID 0
|
||||
|
||||
namespace rw {
|
||||
|
||||
Camera*
|
||||
Camera::create(void)
|
||||
{
|
||||
Camera *cam = (Camera*)malloc(PluginBase::s_size);
|
||||
if(cam == NULL){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return NULL;
|
||||
}
|
||||
cam->object.object.init(Camera::ID, 0);
|
||||
cam->viewWindow.set(1.0f, 1.0f);
|
||||
cam->viewOffset.set(0.0f, 0.0f);
|
||||
cam->nearPlane = 0.05f;
|
||||
cam->farPlane = 10.0f;
|
||||
cam->fogPlane = 5.0f;
|
||||
cam->projection = Camera::PERSPECTIVE;
|
||||
cam->clump = NULL;
|
||||
cam->inClump.init();
|
||||
cam->constructPlugins();
|
||||
return cam;
|
||||
}
|
||||
|
||||
Camera*
|
||||
Camera::clone(void)
|
||||
{
|
||||
Camera *cam = Camera::create();
|
||||
if(cam == NULL)
|
||||
return NULL;
|
||||
cam->object.object.copy(&this->object.object);
|
||||
cam->setFrame(this->getFrame());
|
||||
cam->viewWindow = this->viewWindow;
|
||||
cam->viewOffset = this->viewOffset;
|
||||
cam->nearPlane = this->nearPlane;
|
||||
cam->farPlane = this->farPlane;
|
||||
cam->fogPlane = this->fogPlane;
|
||||
cam->projection = this->projection;
|
||||
cam->copyPlugins(this);
|
||||
return cam;
|
||||
}
|
||||
|
||||
void
|
||||
Camera::destroy(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
if(this->clump)
|
||||
this->inClump.remove();
|
||||
free(this);
|
||||
}
|
||||
|
||||
struct CameraChunkData
|
||||
{
|
||||
V2d viewWindow;
|
||||
V2d viewOffset;
|
||||
float32 nearPlane, farPlane;
|
||||
float32 fogPlane;
|
||||
int32 projection;
|
||||
};
|
||||
|
||||
Camera*
|
||||
Camera::streamRead(Stream *stream)
|
||||
{
|
||||
CameraChunkData buf;
|
||||
if(!findChunk(stream, ID_STRUCT, NULL, NULL)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return NULL;
|
||||
}
|
||||
stream->read(&buf, sizeof(CameraChunkData));
|
||||
Camera *cam = Camera::create();
|
||||
cam->viewWindow = buf.viewWindow;
|
||||
cam->viewOffset = buf.viewOffset;
|
||||
cam->nearPlane = buf.nearPlane;
|
||||
cam->farPlane = buf.farPlane;
|
||||
cam->fogPlane = buf.fogPlane;
|
||||
cam->projection = buf.projection;
|
||||
cam->streamReadPlugins(stream);
|
||||
return cam;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
Camera::streamWrite(Stream *stream)
|
||||
{
|
||||
CameraChunkData buf;
|
||||
writeChunkHeader(stream, ID_CAMERA, this->streamGetSize());
|
||||
writeChunkHeader(stream, ID_STRUCT, sizeof(CameraChunkData));
|
||||
buf.viewWindow = this->viewWindow;
|
||||
buf.viewOffset = this->viewOffset;
|
||||
buf.nearPlane = this->nearPlane;
|
||||
buf.farPlane = this->farPlane;
|
||||
buf.fogPlane = this->fogPlane;
|
||||
buf.projection = this->projection;
|
||||
stream->write(&buf, sizeof(CameraChunkData));
|
||||
this->streamWritePlugins(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
Camera::streamGetSize(void)
|
||||
{
|
||||
return 12 + sizeof(CameraChunkData) + 12 + this->streamGetPluginSize();
|
||||
}
|
||||
|
||||
void
|
||||
Camera::updateProjectionMatrix(void)
|
||||
{
|
||||
float32 invwx = 1.0f/this->viewWindow.x;
|
||||
float32 invwy = 1.0f/this->viewWindow.y;
|
||||
float32 invz = 1.0f/(this->farPlane-this->nearPlane);
|
||||
if(rw::platform == PLATFORM_D3D8 || rw::platform == PLATFORM_D3D9 ||
|
||||
rw::platform == PLATFORM_XBOX){
|
||||
// is this all really correct?
|
||||
this->projMat[0] = invwx;
|
||||
this->projMat[1] = 0.0f;
|
||||
this->projMat[2] = 0.0f;
|
||||
this->projMat[3] = 0.0f;
|
||||
|
||||
this->projMat[4] = 0.0f;
|
||||
this->projMat[5] = invwy;
|
||||
this->projMat[6] = 0.0f;
|
||||
this->projMat[7] = 0.0f;
|
||||
|
||||
if(this->projection == PERSPECTIVE){
|
||||
this->projMat[8] = this->viewOffset.x*invwx;
|
||||
this->projMat[9] = this->viewOffset.y*invwy;
|
||||
this->projMat[10] = this->farPlane*invz;
|
||||
this->projMat[11] = 1.0f;
|
||||
|
||||
this->projMat[12] = 0.0f;
|
||||
this->projMat[13] = 0.0f;
|
||||
this->projMat[14] = -this->nearPlane*this->projMat[10];
|
||||
this->projMat[15] = 0.0f;
|
||||
}else{
|
||||
this->projMat[8] = 0.0f;
|
||||
this->projMat[9] = 0.0f;
|
||||
this->projMat[10] = invz;
|
||||
this->projMat[11] = 0.0f;
|
||||
|
||||
this->projMat[12] = this->viewOffset.x*invwx;
|
||||
this->projMat[13] = this->viewOffset.y*invwy;
|
||||
this->projMat[14] = -this->nearPlane*this->projMat[10];
|
||||
this->projMat[15] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Camera::setFOV(float32 fov, float32 ratio)
|
||||
{
|
||||
float32 a = tan(fov*3.14159f/360.0f);
|
||||
this->viewWindow.x = a;
|
||||
this->viewWindow.y = a/ratio;
|
||||
this->viewOffset.set(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
}
|
656
src/clump.cpp
656
src/clump.cpp
|
@ -1,267 +1,19 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwerror.h"
|
||||
#include "rwplg.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
#include "rwengine.h"
|
||||
#include "rwps2.h"
|
||||
#include "rwxbox.h"
|
||||
#include "rwd3d8.h"
|
||||
#include "rwd3d9.h"
|
||||
#include "rwwdgl.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define PLUGIN_ID 2
|
||||
|
||||
namespace rw {
|
||||
|
||||
LinkList Frame::dirtyList;
|
||||
|
||||
Frame*
|
||||
Frame::create(void)
|
||||
{
|
||||
Frame *f = (Frame*)malloc(PluginBase::s_size);
|
||||
assert(f != NULL);
|
||||
f->object.init(Frame::ID, 0);
|
||||
f->objectList.init();
|
||||
f->child = NULL;
|
||||
f->next = NULL;
|
||||
f->root = f;
|
||||
f->matrix.setIdentity();
|
||||
f->ltm.setIdentity();
|
||||
f->constructPlugins();
|
||||
return f;
|
||||
}
|
||||
|
||||
Frame*
|
||||
Frame::cloneHierarchy(void)
|
||||
{
|
||||
Frame *frame = this->cloneAndLink(NULL);
|
||||
frame->purgeClone();
|
||||
return frame;
|
||||
}
|
||||
|
||||
void
|
||||
Frame::destroy(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
Frame *parent = this->getParent();
|
||||
Frame *child;
|
||||
if(parent){
|
||||
// remove from child list
|
||||
child = parent->child;
|
||||
if(child == this)
|
||||
parent->child = this->next;
|
||||
else{
|
||||
for(child = child->next; child != this; child = child->next)
|
||||
;
|
||||
child->next = this->next;
|
||||
}
|
||||
this->object.parent = NULL;
|
||||
// Doesn't seem to make much sense, blame criterion.
|
||||
this->setHierarchyRoot(this);
|
||||
}
|
||||
for(Frame *f = this->child; f; f = f->next)
|
||||
f->object.parent = NULL;
|
||||
free(this);
|
||||
}
|
||||
|
||||
void
|
||||
Frame::destroyHierarchy(void)
|
||||
{
|
||||
Frame *next;
|
||||
for(Frame *child = this->child; child; child = next){
|
||||
next = child->next;
|
||||
child->destroyHierarchy();
|
||||
}
|
||||
this->destructPlugins();
|
||||
free(this);
|
||||
}
|
||||
|
||||
Frame*
|
||||
Frame::addChild(Frame *child, bool32 append)
|
||||
{
|
||||
Frame *c;
|
||||
if(child->getParent())
|
||||
child->removeChild();
|
||||
if(append){
|
||||
if(this->child == NULL)
|
||||
this->child = child;
|
||||
else{
|
||||
for(c = this->child; c->next; c = c->next);
|
||||
c->next = child;
|
||||
}
|
||||
child->next = NULL;
|
||||
}else{
|
||||
child->next = this->child;
|
||||
this->child = child;
|
||||
}
|
||||
child->object.parent = this;
|
||||
child->root = this->root;
|
||||
for(c = child->child; c; c = c->next)
|
||||
c->setHierarchyRoot(this);
|
||||
if(child->object.privateFlags & Frame::HIERARCHYSYNC){
|
||||
child->inDirtyList.remove();
|
||||
child->object.privateFlags &= ~Frame::HIERARCHYSYNC;
|
||||
}
|
||||
this->updateObjects();
|
||||
return this;
|
||||
}
|
||||
|
||||
Frame*
|
||||
Frame::removeChild(void)
|
||||
{
|
||||
Frame *parent = this->getParent();
|
||||
Frame *child = parent->child;
|
||||
if(child == this)
|
||||
parent->child = this->next;
|
||||
else{
|
||||
while(child->next != this)
|
||||
child = child->next;
|
||||
child->next = this->next;
|
||||
}
|
||||
this->object.parent = this->next = NULL;
|
||||
this->root = this;
|
||||
for(child = this->child; child; child = child->next)
|
||||
child->setHierarchyRoot(this);
|
||||
this->updateObjects();
|
||||
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 void
|
||||
syncRecurse(Frame *frame, uint8 flags)
|
||||
{
|
||||
uint8 flg;
|
||||
for(; frame; frame = frame->next){
|
||||
flg = flags | frame->object.privateFlags;
|
||||
if(flg & Frame::SUBTREESYNCLTM){
|
||||
Matrix::mult(&frame->ltm, &frame->getParent()->ltm, &frame->matrix);
|
||||
frame->object.privateFlags &= ~Frame::SUBTREESYNCLTM;
|
||||
}
|
||||
syncRecurse(frame->child, flg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Frame::syncHierarchyLTM(void)
|
||||
{
|
||||
Frame *child;
|
||||
uint8 flg;
|
||||
if(this->object.privateFlags & Frame::SUBTREESYNCLTM)
|
||||
this->ltm = this->matrix;
|
||||
for(child = this->child; child; child = child->next){
|
||||
flg = this->object.privateFlags | child->object.privateFlags;
|
||||
if(flg & Frame::SUBTREESYNCLTM){
|
||||
Matrix::mult(&child->ltm, &this->ltm, &child->matrix);
|
||||
child->object.privateFlags &= ~Frame::SUBTREESYNCLTM;
|
||||
}
|
||||
syncRecurse(child, flg);
|
||||
}
|
||||
this->object.privateFlags &= ~Frame::SYNCLTM;
|
||||
}
|
||||
|
||||
Matrix*
|
||||
Frame::getLTM(void)
|
||||
{
|
||||
if(this->root->object.privateFlags & Frame::HIERARCHYSYNCLTM)
|
||||
this->root->syncHierarchyLTM();
|
||||
return &this->ltm;
|
||||
}
|
||||
|
||||
void
|
||||
Frame::updateObjects(void)
|
||||
{
|
||||
if((this->root->object.privateFlags & HIERARCHYSYNC) == 0)
|
||||
Frame::dirtyList.add(&this->inDirtyList);
|
||||
this->root->object.privateFlags |= HIERARCHYSYNC;
|
||||
this->object.privateFlags |= SUBTREESYNC;
|
||||
}
|
||||
|
||||
void
|
||||
Frame::setHierarchyRoot(Frame *root)
|
||||
{
|
||||
this->root = root;
|
||||
for(Frame *child = this->child; child; child = child->next)
|
||||
child->setHierarchyRoot(root);
|
||||
}
|
||||
|
||||
// Clone a frame hierarchy. Link cloned frames into Frame::root of the originals.
|
||||
Frame*
|
||||
Frame::cloneAndLink(Frame *clonedroot)
|
||||
{
|
||||
Frame *frame = Frame::create();
|
||||
if(clonedroot == NULL)
|
||||
clonedroot = frame;
|
||||
frame->object.copy(&this->object);
|
||||
frame->matrix = this->matrix;
|
||||
//memcpy(frame->matrix, this->matrix, sizeof(this->matrix));
|
||||
frame->root = clonedroot;
|
||||
this->root = frame; // Remember cloned frame
|
||||
for(Frame *child = this->child; child; child = child->next){
|
||||
Frame *clonedchild = child->cloneAndLink(clonedroot);
|
||||
clonedchild->next = frame->child;
|
||||
frame->child = clonedchild;
|
||||
clonedchild->object.parent = frame;
|
||||
}
|
||||
frame->copyPlugins(this);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Remove links to cloned frames from hierarchy.
|
||||
void
|
||||
Frame::purgeClone(void)
|
||||
{
|
||||
Frame *parent = this->getParent();
|
||||
this->setHierarchyRoot(parent ? parent->root : this);
|
||||
}
|
||||
|
||||
static Frame*
|
||||
sizeCB(Frame *f, void *size)
|
||||
{
|
||||
*(int32*)size += f->streamGetPluginSize();
|
||||
f->forAllChildren(sizeCB, size);
|
||||
return f;
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
|
@ -270,7 +22,10 @@ Clump*
|
|||
Clump::create(void)
|
||||
{
|
||||
Clump *clump = (Clump*)malloc(PluginBase::s_size);
|
||||
assert(clump != NULL);
|
||||
if(clump == nil){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return nil;
|
||||
}
|
||||
clump->object.init(Clump::ID, 0);
|
||||
clump->atomics.init();
|
||||
clump->lights.init();
|
||||
|
@ -318,8 +73,14 @@ Clump::streamRead(Stream *stream)
|
|||
uint32 length, version;
|
||||
int32 buf[3];
|
||||
Clump *clump;
|
||||
assert(findChunk(stream, ID_STRUCT, &length, &version));
|
||||
|
||||
if(!findChunk(stream, ID_STRUCT, &length, &version)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return nil;
|
||||
}
|
||||
clump = Clump::create();
|
||||
if(clump == nil)
|
||||
return nil;
|
||||
stream->read(buf, length);
|
||||
int32 numAtomics = buf[0];
|
||||
int32 numLights = 0;
|
||||
|
@ -339,31 +100,68 @@ Clump::streamRead(Stream *stream)
|
|||
if(version >= 0x30400){
|
||||
// Geometry list
|
||||
int32 numGeometries = 0;
|
||||
assert(findChunk(stream, ID_GEOMETRYLIST, NULL, NULL));
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
if(!findChunk(stream, ID_GEOMETRYLIST, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "GEOMETRYLIST"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
numGeometries = stream->readI32();
|
||||
if(numGeometries)
|
||||
geometryList = new Geometry*[numGeometries];
|
||||
for(int32 i = 0; i < numGeometries; i++){
|
||||
assert(findChunk(stream, ID_GEOMETRY, NULL, NULL));
|
||||
if(!findChunk(stream, ID_GEOMETRY, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "GEOMETRY"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
geometryList[i] = Geometry::streamRead(stream);
|
||||
if(geometryList[i] == nil){
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atomics
|
||||
Atomic *a;
|
||||
for(int32 i = 0; i < numAtomics; i++){
|
||||
assert(findChunk(stream, ID_ATOMIC, NULL, NULL));
|
||||
Atomic *a = Atomic::streamReadClump(stream, frameList, geometryList);
|
||||
if(!findChunk(stream, ID_ATOMIC, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "ATOMIC"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
a = Atomic::streamReadClump(stream, frameList, geometryList);
|
||||
if(a == nil){
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
clump->addAtomic(a);
|
||||
}
|
||||
|
||||
// Lights
|
||||
for(int32 i = 0; i < numLights; i++){
|
||||
int32 frm;
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
frm = stream->readI32();
|
||||
assert(findChunk(stream, ID_LIGHT, NULL, NULL));
|
||||
if(!findChunk(stream, ID_LIGHT, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "LIGHT"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
Light *l = Light::streamRead(stream);
|
||||
if(l == nil){
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
l->setFrame(frameList[frm]);
|
||||
clump->addLight(l);
|
||||
}
|
||||
|
@ -371,10 +169,22 @@ Clump::streamRead(Stream *stream)
|
|||
// Cameras
|
||||
for(int32 i = 0; i < numCameras; i++){
|
||||
int32 frm;
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
frm = stream->readI32();
|
||||
assert(findChunk(stream, ID_CAMERA, NULL, NULL));
|
||||
if(!findChunk(stream, ID_CAMERA, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "CAMERA"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
Camera *cam = Camera::streamRead(stream);
|
||||
if(cam == nil){
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
cam->setFrame(frameList[frm]);
|
||||
clump->addCamera(cam);
|
||||
}
|
||||
|
@ -450,6 +260,14 @@ struct FrameStreamData
|
|||
int32 matflag;
|
||||
};
|
||||
|
||||
static Frame*
|
||||
sizeCB(Frame *f, void *size)
|
||||
{
|
||||
*(int32*)size += f->streamGetPluginSize();
|
||||
f->forAllChildren(sizeCB, size);
|
||||
return f;
|
||||
}
|
||||
|
||||
uint32
|
||||
Clump::streamGetSize(void)
|
||||
{
|
||||
|
@ -498,13 +316,19 @@ Clump::render(void)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
Clump::frameListStreamRead(Stream *stream, Frame ***flp, int32 *nf)
|
||||
{
|
||||
FrameStreamData buf;
|
||||
int32 numFrames = 0;
|
||||
assert(findChunk(stream, ID_FRAMELIST, NULL, NULL));
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
if(!findChunk(stream, ID_FRAMELIST, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "FRAMELIST"));
|
||||
return 0;
|
||||
}
|
||||
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return 0;
|
||||
}
|
||||
numFrames = stream->readI32();
|
||||
Frame **frameList = new Frame*[numFrames];
|
||||
for(int32 i = 0; i < numFrames; i++){
|
||||
|
@ -527,6 +351,7 @@ Clump::frameListStreamRead(Stream *stream, Frame ***flp, int32 *nf)
|
|||
frameList[i]->streamReadPlugins(stream);
|
||||
*nf = numFrames;
|
||||
*flp = frameList;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -566,14 +391,17 @@ Atomic*
|
|||
Atomic::create(void)
|
||||
{
|
||||
Atomic *atomic = (Atomic*)malloc(PluginBase::s_size);
|
||||
assert(atomic != NULL);
|
||||
if(atomic == nil){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return nil;
|
||||
}
|
||||
atomic->object.object.init(Atomic::ID, 0);
|
||||
atomic->geometry = NULL;
|
||||
atomic->geometry = nil;
|
||||
atomic->worldBoundingSphere.center.set(0.0f, 0.0f, 0.0f);
|
||||
atomic->worldBoundingSphere.radius = 0.0f;
|
||||
atomic->setFrame(NULL);
|
||||
atomic->clump = NULL;
|
||||
atomic->pipeline = NULL;
|
||||
atomic->setFrame(nil);
|
||||
atomic->clump = nil;
|
||||
atomic->pipeline = nil;
|
||||
atomic->renderCB = Atomic::defaultRenderCB;
|
||||
atomic->object.object.flags = Atomic::COLLISIONTEST | Atomic::RENDER;
|
||||
atomic->constructPlugins();
|
||||
|
@ -603,7 +431,7 @@ Atomic::destroy(void)
|
|||
this->geometry->destroy();
|
||||
if(this->clump)
|
||||
this->inClump.remove();
|
||||
this->setFrame(NULL);
|
||||
this->setFrame(nil);
|
||||
free(this);
|
||||
}
|
||||
|
||||
|
@ -612,7 +440,7 @@ Atomic::removeFromClump(void)
|
|||
{
|
||||
if(this->clump){
|
||||
this->inClump.remove();
|
||||
this->clump = NULL;
|
||||
this->clump = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -640,13 +468,26 @@ Atomic::streamReadClump(Stream *stream,
|
|||
{
|
||||
int32 buf[4];
|
||||
uint32 version;
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, &version));
|
||||
if(!findChunk(stream, ID_STRUCT, nil, &version)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return nil;
|
||||
}
|
||||
stream->read(buf, version < 0x30400 ? 12 : 16);
|
||||
Atomic *atomic = Atomic::create();
|
||||
if(atomic == nil)
|
||||
return nil;
|
||||
atomic->setFrame(frameList[buf[0]]);
|
||||
if(version < 0x30400){
|
||||
assert(findChunk(stream, ID_GEOMETRY, NULL, NULL));
|
||||
if(!findChunk(stream, ID_GEOMETRY, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
atomic->geometry = Geometry::streamRead(stream);
|
||||
if(atomic->geometry == nil){
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
}else
|
||||
atomic->geometry = geometryList[buf[1]];
|
||||
atomic->object.object.flags = buf[2];
|
||||
|
@ -663,7 +504,7 @@ Atomic::streamWriteClump(Stream *stream, Frame **frameList, int32 numFrames)
|
|||
{
|
||||
int32 buf[4] = { 0, 0, 0, 0 };
|
||||
Clump *c = this->clump;
|
||||
if(c == NULL)
|
||||
if(c == nil)
|
||||
return false;
|
||||
writeChunkHeader(stream, ID_ATOMIC, this->streamGetSize());
|
||||
writeChunkHeader(stream, ID_STRUCT, rw::version < 0x30400 ? 12 : 16);
|
||||
|
@ -737,7 +578,7 @@ static int32
|
|||
getSizeAtomicRights(void *object, int32, int32)
|
||||
{
|
||||
Atomic *atomic = (Atomic*)object;
|
||||
if(atomic->pipeline == NULL || atomic->pipeline->pluginID == 0)
|
||||
if(atomic->pipeline == nil || atomic->pipeline->pluginID == 0)
|
||||
return -1;
|
||||
return 8;
|
||||
}
|
||||
|
@ -745,272 +586,11 @@ getSizeAtomicRights(void *object, int32, int32)
|
|||
void
|
||||
registerAtomicRightsPlugin(void)
|
||||
{
|
||||
Atomic::registerPlugin(0, ID_RIGHTTORENDER, NULL, NULL, NULL);
|
||||
Atomic::registerPlugin(0, ID_RIGHTTORENDER, nil, nil, nil);
|
||||
Atomic::registerPluginStream(ID_RIGHTTORENDER,
|
||||
readAtomicRights,
|
||||
writeAtomicRights,
|
||||
getSizeAtomicRights);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Light
|
||||
//
|
||||
|
||||
Light*
|
||||
Light::create(int32 type)
|
||||
{
|
||||
Light *light = (Light*)malloc(PluginBase::s_size);
|
||||
assert(light != NULL);
|
||||
light->object.object.init(Light::ID, type);
|
||||
light->radius = 0.0f;
|
||||
light->color.red = 1.0f;
|
||||
light->color.green = 1.0f;
|
||||
light->color.blue = 1.0f;
|
||||
light->color.alpha = 1.0f;
|
||||
light->minusCosAngle = 1.0f;
|
||||
light->object.object.privateFlags = 1;
|
||||
light->object.object.flags = LIGHTATOMICS | LIGHTWORLD;
|
||||
light->clump = NULL;
|
||||
light->inClump.init();
|
||||
light->constructPlugins();
|
||||
return light;
|
||||
}
|
||||
|
||||
void
|
||||
Light::destroy(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
if(this->clump)
|
||||
this->inClump.remove();
|
||||
free(this);
|
||||
}
|
||||
|
||||
void
|
||||
Light::setAngle(float32 angle)
|
||||
{
|
||||
this->minusCosAngle = -cos(angle);
|
||||
}
|
||||
|
||||
float32
|
||||
Light::getAngle(void)
|
||||
{
|
||||
return acos(-this->minusCosAngle);
|
||||
}
|
||||
|
||||
void
|
||||
Light::setColor(float32 r, float32 g, float32 b)
|
||||
{
|
||||
this->color.red = r;
|
||||
this->color.green = g;
|
||||
this->color.blue = b;
|
||||
this->object.object.privateFlags = r == g && r == b;
|
||||
}
|
||||
|
||||
struct LightChunkData
|
||||
{
|
||||
float32 radius;
|
||||
float32 red, green, blue;
|
||||
float32 minusCosAngle;
|
||||
uint16 flags;
|
||||
uint16 type;
|
||||
};
|
||||
|
||||
Light*
|
||||
Light::streamRead(Stream *stream)
|
||||
{
|
||||
uint32 version;
|
||||
LightChunkData buf;
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, &version));
|
||||
stream->read(&buf, sizeof(LightChunkData));
|
||||
Light *light = Light::create(buf.type);
|
||||
light->radius = buf.radius;
|
||||
light->setColor(buf.red, buf.green, buf.blue);
|
||||
float32 a = buf.minusCosAngle;
|
||||
if(version >= 0x30300)
|
||||
light->minusCosAngle = a;
|
||||
else
|
||||
// tan -> -cos
|
||||
light->minusCosAngle = -1.0f/sqrt(a*a+1.0f);
|
||||
light->object.object.flags = (uint8)buf.flags;
|
||||
light->streamReadPlugins(stream);
|
||||
return light;
|
||||
}
|
||||
|
||||
bool
|
||||
Light::streamWrite(Stream *stream)
|
||||
{
|
||||
LightChunkData buf;
|
||||
writeChunkHeader(stream, ID_LIGHT, this->streamGetSize());
|
||||
writeChunkHeader(stream, ID_STRUCT, sizeof(LightChunkData));
|
||||
buf.radius = this->radius;
|
||||
buf.red = this->color.red;
|
||||
buf.green = this->color.green;
|
||||
buf.blue = this->color.blue;
|
||||
if(version >= 0x30300)
|
||||
buf.minusCosAngle = this->minusCosAngle;
|
||||
else
|
||||
buf.minusCosAngle = tan(acos(-this->minusCosAngle));
|
||||
buf.flags = this->object.object.flags;
|
||||
buf.type = this->object.object.subType;
|
||||
stream->write(&buf, sizeof(LightChunkData));
|
||||
|
||||
this->streamWritePlugins(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
Light::streamGetSize(void)
|
||||
{
|
||||
return 12 + sizeof(LightChunkData) + 12 + this->streamGetPluginSize();
|
||||
}
|
||||
|
||||
//
|
||||
// Camera
|
||||
//
|
||||
|
||||
Camera*
|
||||
Camera::create(void)
|
||||
{
|
||||
Camera *cam = (Camera*)malloc(PluginBase::s_size);
|
||||
cam->object.object.init(Camera::ID, 0);
|
||||
cam->viewWindow.set(1.0f, 1.0f);
|
||||
cam->viewOffset.set(0.0f, 0.0f);
|
||||
cam->nearPlane = 0.05f;
|
||||
cam->farPlane = 10.0f;
|
||||
cam->fogPlane = 5.0f;
|
||||
cam->projection = Camera::PERSPECTIVE;
|
||||
cam->clump = NULL;
|
||||
cam->inClump.init();
|
||||
cam->constructPlugins();
|
||||
return cam;
|
||||
}
|
||||
|
||||
Camera*
|
||||
Camera::clone(void)
|
||||
{
|
||||
Camera *cam = Camera::create();
|
||||
cam->object.object.copy(&this->object.object);
|
||||
cam->setFrame(this->getFrame());
|
||||
cam->viewWindow = this->viewWindow;
|
||||
cam->viewOffset = this->viewOffset;
|
||||
cam->nearPlane = this->nearPlane;
|
||||
cam->farPlane = this->farPlane;
|
||||
cam->fogPlane = this->fogPlane;
|
||||
cam->projection = this->projection;
|
||||
cam->copyPlugins(this);
|
||||
return cam;
|
||||
}
|
||||
|
||||
void
|
||||
Camera::destroy(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
if(this->clump)
|
||||
this->inClump.remove();
|
||||
free(this);
|
||||
}
|
||||
|
||||
struct CameraChunkData
|
||||
{
|
||||
V2d viewWindow;
|
||||
V2d viewOffset;
|
||||
float32 nearPlane, farPlane;
|
||||
float32 fogPlane;
|
||||
int32 projection;
|
||||
};
|
||||
|
||||
Camera*
|
||||
Camera::streamRead(Stream *stream)
|
||||
{
|
||||
CameraChunkData buf;
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
stream->read(&buf, sizeof(CameraChunkData));
|
||||
Camera *cam = Camera::create();
|
||||
cam->viewWindow = buf.viewWindow;
|
||||
cam->viewOffset = buf.viewOffset;
|
||||
cam->nearPlane = buf.nearPlane;
|
||||
cam->farPlane = buf.farPlane;
|
||||
cam->fogPlane = buf.fogPlane;
|
||||
cam->projection = buf.projection;
|
||||
cam->streamReadPlugins(stream);
|
||||
return cam;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
Camera::streamWrite(Stream *stream)
|
||||
{
|
||||
CameraChunkData buf;
|
||||
writeChunkHeader(stream, ID_CAMERA, this->streamGetSize());
|
||||
writeChunkHeader(stream, ID_STRUCT, sizeof(CameraChunkData));
|
||||
buf.viewWindow = this->viewWindow;
|
||||
buf.viewOffset = this->viewOffset;
|
||||
buf.nearPlane = this->nearPlane;
|
||||
buf.farPlane = this->farPlane;
|
||||
buf.fogPlane = this->fogPlane;
|
||||
buf.projection = this->projection;
|
||||
stream->write(&buf, sizeof(CameraChunkData));
|
||||
this->streamWritePlugins(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
Camera::streamGetSize(void)
|
||||
{
|
||||
return 12 + sizeof(CameraChunkData) + 12 + this->streamGetPluginSize();
|
||||
}
|
||||
|
||||
void
|
||||
Camera::updateProjectionMatrix(void)
|
||||
{
|
||||
float32 invwx = 1.0f/this->viewWindow.x;
|
||||
float32 invwy = 1.0f/this->viewWindow.y;
|
||||
float32 invz = 1.0f/(this->farPlane-this->nearPlane);
|
||||
if(rw::platform == PLATFORM_D3D8 || rw::platform == PLATFORM_D3D9 ||
|
||||
rw::platform == PLATFORM_XBOX){
|
||||
// is this all really correct?
|
||||
this->projMat[0] = invwx;
|
||||
this->projMat[1] = 0.0f;
|
||||
this->projMat[2] = 0.0f;
|
||||
this->projMat[3] = 0.0f;
|
||||
|
||||
this->projMat[4] = 0.0f;
|
||||
this->projMat[5] = invwy;
|
||||
this->projMat[6] = 0.0f;
|
||||
this->projMat[7] = 0.0f;
|
||||
|
||||
if(this->projection == PERSPECTIVE){
|
||||
this->projMat[8] = this->viewOffset.x*invwx;
|
||||
this->projMat[9] = this->viewOffset.y*invwy;
|
||||
this->projMat[10] = this->farPlane*invz;
|
||||
this->projMat[11] = 1.0f;
|
||||
|
||||
this->projMat[12] = 0.0f;
|
||||
this->projMat[13] = 0.0f;
|
||||
this->projMat[14] = -this->nearPlane*this->projMat[10];
|
||||
this->projMat[15] = 0.0f;
|
||||
}else{
|
||||
this->projMat[8] = 0.0f;
|
||||
this->projMat[9] = 0.0f;
|
||||
this->projMat[10] = invz;
|
||||
this->projMat[11] = 0.0f;
|
||||
|
||||
this->projMat[12] = this->viewOffset.x*invwx;
|
||||
this->projMat[13] = this->viewOffset.y*invwy;
|
||||
this->projMat[14] = -this->nearPlane*this->projMat[10];
|
||||
this->projMat[15] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Camera::setFOV(float32 fov, float32 ratio)
|
||||
{
|
||||
float32 a = tan(fov*3.14159f/360.0f);
|
||||
this->viewWindow.x = a;
|
||||
this->viewWindow.y = a/ratio;
|
||||
this->viewOffset.set(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <cstdio>
|
||||
#include <assert.h>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwplg.h"
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#include <cstdio>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwerror.h"
|
||||
|
||||
namespace rw {
|
||||
|
||||
static Error error;
|
||||
|
||||
void
|
||||
setError(Error *e)
|
||||
{
|
||||
error = *e;
|
||||
}
|
||||
|
||||
Error*
|
||||
getError(Error *e)
|
||||
{
|
||||
*e = error;
|
||||
error.plugin = 0;
|
||||
error.code = 0;
|
||||
return e;
|
||||
}
|
||||
|
||||
#define ECODE(c, s) s,
|
||||
|
||||
const char *errstrs[] = {
|
||||
"No error",
|
||||
#include "base.err"
|
||||
};
|
||||
|
||||
#undef ECODE
|
||||
|
||||
char*
|
||||
dbgsprint(int32 code, ...)
|
||||
{
|
||||
va_list ap;
|
||||
static char strbuf[512];
|
||||
|
||||
if(code & 0x80000000)
|
||||
code &= ~0x80000000;
|
||||
va_start(ap, code);
|
||||
vsprintf(strbuf, errstrs[code], ap);
|
||||
va_end(ap);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwerror.h"
|
||||
#include "rwplg.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
#include "rwengine.h"
|
||||
#include "rwps2.h"
|
||||
#include "rwxbox.h"
|
||||
#include "rwd3d8.h"
|
||||
#include "rwd3d9.h"
|
||||
#include "rwwdgl.h"
|
||||
|
||||
#define PLUGIN_ID 0
|
||||
|
||||
namespace rw {
|
||||
|
||||
LinkList Frame::dirtyList;
|
||||
|
||||
Frame*
|
||||
Frame::create(void)
|
||||
{
|
||||
Frame *f = (Frame*)malloc(PluginBase::s_size);
|
||||
if(f == NULL){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return NULL;
|
||||
}
|
||||
f->object.init(Frame::ID, 0);
|
||||
f->objectList.init();
|
||||
f->child = NULL;
|
||||
f->next = NULL;
|
||||
f->root = f;
|
||||
f->matrix.setIdentity();
|
||||
f->ltm.setIdentity();
|
||||
f->constructPlugins();
|
||||
return f;
|
||||
}
|
||||
|
||||
Frame*
|
||||
Frame::cloneHierarchy(void)
|
||||
{
|
||||
Frame *frame = this->cloneAndLink(NULL);
|
||||
frame->purgeClone();
|
||||
return frame;
|
||||
}
|
||||
|
||||
void
|
||||
Frame::destroy(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
Frame *parent = this->getParent();
|
||||
Frame *child;
|
||||
if(parent){
|
||||
// remove from child list
|
||||
child = parent->child;
|
||||
if(child == this)
|
||||
parent->child = this->next;
|
||||
else{
|
||||
for(child = child->next; child != this; child = child->next)
|
||||
;
|
||||
child->next = this->next;
|
||||
}
|
||||
this->object.parent = NULL;
|
||||
// Doesn't seem to make much sense, blame criterion.
|
||||
this->setHierarchyRoot(this);
|
||||
}
|
||||
for(Frame *f = this->child; f; f = f->next)
|
||||
f->object.parent = NULL;
|
||||
free(this);
|
||||
}
|
||||
|
||||
void
|
||||
Frame::destroyHierarchy(void)
|
||||
{
|
||||
Frame *next;
|
||||
for(Frame *child = this->child; child; child = next){
|
||||
next = child->next;
|
||||
child->destroyHierarchy();
|
||||
}
|
||||
this->destructPlugins();
|
||||
free(this);
|
||||
}
|
||||
|
||||
Frame*
|
||||
Frame::addChild(Frame *child, bool32 append)
|
||||
{
|
||||
Frame *c;
|
||||
if(child->getParent())
|
||||
child->removeChild();
|
||||
if(append){
|
||||
if(this->child == NULL)
|
||||
this->child = child;
|
||||
else{
|
||||
for(c = this->child; c->next; c = c->next);
|
||||
c->next = child;
|
||||
}
|
||||
child->next = NULL;
|
||||
}else{
|
||||
child->next = this->child;
|
||||
this->child = child;
|
||||
}
|
||||
child->object.parent = this;
|
||||
child->root = this->root;
|
||||
for(c = child->child; c; c = c->next)
|
||||
c->setHierarchyRoot(this);
|
||||
if(child->object.privateFlags & Frame::HIERARCHYSYNC){
|
||||
child->inDirtyList.remove();
|
||||
child->object.privateFlags &= ~Frame::HIERARCHYSYNC;
|
||||
}
|
||||
this->updateObjects();
|
||||
return this;
|
||||
}
|
||||
|
||||
Frame*
|
||||
Frame::removeChild(void)
|
||||
{
|
||||
Frame *parent = this->getParent();
|
||||
Frame *child = parent->child;
|
||||
if(child == this)
|
||||
parent->child = this->next;
|
||||
else{
|
||||
while(child->next != this)
|
||||
child = child->next;
|
||||
child->next = this->next;
|
||||
}
|
||||
this->object.parent = this->next = NULL;
|
||||
this->root = this;
|
||||
for(child = this->child; child; child = child->next)
|
||||
child->setHierarchyRoot(this);
|
||||
this->updateObjects();
|
||||
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 void
|
||||
syncRecurse(Frame *frame, uint8 flags)
|
||||
{
|
||||
uint8 flg;
|
||||
for(; frame; frame = frame->next){
|
||||
flg = flags | frame->object.privateFlags;
|
||||
if(flg & Frame::SUBTREESYNCLTM){
|
||||
Matrix::mult(&frame->ltm, &frame->getParent()->ltm,
|
||||
&frame->matrix);
|
||||
frame->object.privateFlags &= ~Frame::SUBTREESYNCLTM;
|
||||
}
|
||||
syncRecurse(frame->child, flg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Frame::syncHierarchyLTM(void)
|
||||
{
|
||||
Frame *child;
|
||||
uint8 flg;
|
||||
if(this->object.privateFlags & Frame::SUBTREESYNCLTM)
|
||||
this->ltm = this->matrix;
|
||||
for(child = this->child; child; child = child->next){
|
||||
flg = this->object.privateFlags | child->object.privateFlags;
|
||||
if(flg & Frame::SUBTREESYNCLTM){
|
||||
Matrix::mult(&child->ltm, &this->ltm, &child->matrix);
|
||||
child->object.privateFlags &= ~Frame::SUBTREESYNCLTM;
|
||||
}
|
||||
syncRecurse(child, flg);
|
||||
}
|
||||
this->object.privateFlags &= ~Frame::SYNCLTM;
|
||||
}
|
||||
|
||||
Matrix*
|
||||
Frame::getLTM(void)
|
||||
{
|
||||
if(this->root->object.privateFlags & Frame::HIERARCHYSYNCLTM)
|
||||
this->root->syncHierarchyLTM();
|
||||
return &this->ltm;
|
||||
}
|
||||
|
||||
void
|
||||
Frame::updateObjects(void)
|
||||
{
|
||||
if((this->root->object.privateFlags & HIERARCHYSYNC) == 0)
|
||||
Frame::dirtyList.add(&this->inDirtyList);
|
||||
this->root->object.privateFlags |= HIERARCHYSYNC;
|
||||
this->object.privateFlags |= SUBTREESYNC;
|
||||
}
|
||||
|
||||
void
|
||||
Frame::setHierarchyRoot(Frame *root)
|
||||
{
|
||||
this->root = root;
|
||||
for(Frame *child = this->child; child; child = child->next)
|
||||
child->setHierarchyRoot(root);
|
||||
}
|
||||
|
||||
// Clone a frame hierarchy. Link cloned frames into Frame::root of the originals.
|
||||
Frame*
|
||||
Frame::cloneAndLink(Frame *clonedroot)
|
||||
{
|
||||
Frame *frame = Frame::create();
|
||||
if(clonedroot == NULL)
|
||||
clonedroot = frame;
|
||||
frame->object.copy(&this->object);
|
||||
frame->matrix = this->matrix;
|
||||
//memcpy(frame->matrix, this->matrix, sizeof(this->matrix));
|
||||
frame->root = clonedroot;
|
||||
this->root = frame; // Remember cloned frame
|
||||
for(Frame *child = this->child; child; child = child->next){
|
||||
Frame *clonedchild = child->cloneAndLink(clonedroot);
|
||||
clonedchild->next = frame->child;
|
||||
frame->child = clonedchild;
|
||||
clonedchild->object.parent = frame;
|
||||
}
|
||||
frame->copyPlugins(this);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Remove links to cloned frames from hierarchy.
|
||||
void
|
||||
Frame::purgeClone(void)
|
||||
{
|
||||
Frame *parent = this->getParent();
|
||||
this->setHierarchyRoot(parent ? parent->root : this);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -5,10 +5,13 @@
|
|||
#include <cmath>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwerror.h"
|
||||
#include "rwplg.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
|
||||
#define PLUGIN_ID 2
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace rw {
|
||||
|
@ -17,7 +20,10 @@ Geometry*
|
|||
Geometry::create(int32 numVerts, int32 numTris, uint32 flags)
|
||||
{
|
||||
Geometry *geo = (Geometry*)malloc(PluginBase::s_size);
|
||||
assert(geo != NULL);
|
||||
if(geo == nil){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return nil;
|
||||
}
|
||||
geo->object.init(Geometry::ID, 0);
|
||||
geo->geoflags = flags & 0xFF00FFFF;
|
||||
geo->numTexCoordSets = (flags & 0xFF0000) >> 16;
|
||||
|
@ -28,10 +34,10 @@ Geometry::create(int32 numVerts, int32 numTris, uint32 flags)
|
|||
geo->numVertices = numVerts;
|
||||
geo->numMorphTargets = 1;
|
||||
|
||||
geo->colors = NULL;
|
||||
geo->colors = nil;
|
||||
for(int32 i = 0; i < geo->numTexCoordSets; i++)
|
||||
geo->texCoords[i] = NULL;
|
||||
geo->triangles = NULL;
|
||||
geo->texCoords[i] = nil;
|
||||
geo->triangles = nil;
|
||||
if(!(geo->geoflags & NATIVE) && geo->numVertices){
|
||||
if(geo->geoflags & PRELIT)
|
||||
geo->colors = new uint8[4*geo->numVertices];
|
||||
|
@ -45,24 +51,23 @@ Geometry::create(int32 numVerts, int32 numTris, uint32 flags)
|
|||
MorphTarget *m = geo->morphTargets;
|
||||
m->boundingSphere.center.set(0.0f, 0.0f, 0.0f);
|
||||
m->boundingSphere.radius = 0.0f;
|
||||
m->vertices = NULL;
|
||||
m->normals = NULL;
|
||||
m->vertices = nil;
|
||||
m->normals = nil;
|
||||
if(!(geo->geoflags & NATIVE) && geo->numVertices){
|
||||
m->vertices = new float32[3*geo->numVertices];
|
||||
if(geo->geoflags & NORMALS)
|
||||
m->normals = new float32[3*geo->numVertices];
|
||||
}
|
||||
geo->numMaterials = 0;
|
||||
geo->materialList = NULL;
|
||||
geo->meshHeader = NULL;
|
||||
geo->instData = NULL;
|
||||
geo->materialList = nil;
|
||||
geo->meshHeader = nil;
|
||||
geo->instData = nil;
|
||||
geo->refCount = 1;
|
||||
|
||||
geo->constructPlugins();
|
||||
return geo;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Geometry::destroy(void)
|
||||
{
|
||||
|
@ -101,10 +106,15 @@ Geometry::streamRead(Stream *stream)
|
|||
{
|
||||
uint32 version;
|
||||
GeoStreamData buf;
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, &version));
|
||||
if(!findChunk(stream, ID_STRUCT, nil, &version)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return nil;
|
||||
}
|
||||
stream->read(&buf, sizeof(buf));
|
||||
Geometry *geo = Geometry::create(buf.numVertices,
|
||||
buf.numTriangles, buf.flags);
|
||||
if(geo == nil)
|
||||
return nil;
|
||||
geo->addMorphTargets(buf.numMorphTargets-1);
|
||||
// skip surface properties
|
||||
if(version < 0x34000)
|
||||
|
@ -137,13 +147,25 @@ Geometry::streamRead(Stream *stream)
|
|||
stream->read(m->normals, 3*geo->numVertices*4);
|
||||
}
|
||||
|
||||
assert(findChunk(stream, ID_MATLIST, NULL, NULL));
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
if(!findChunk(stream, ID_MATLIST, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "MATLIST"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
geo->numMaterials = stream->readI32();
|
||||
geo->materialList = new Material*[geo->numMaterials];
|
||||
stream->seek(geo->numMaterials*4); // unused (-1)
|
||||
for(int32 i = 0; i < geo->numMaterials; i++){
|
||||
assert(findChunk(stream, ID_MATERIAL, NULL, NULL));
|
||||
if(!findChunk(stream, ID_MATERIAL, nil, nil)){
|
||||
RWERROR((ERR_CHUNK, "MATERIAL"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
geo->materialList[i] = Material::streamRead(stream);
|
||||
}
|
||||
|
||||
|
@ -217,8 +239,8 @@ Geometry::streamWrite(Stream *stream)
|
|||
MorphTarget *m = &this->morphTargets[i];
|
||||
stream->write(&m->boundingSphere, 4*4);
|
||||
if(!(this->geoflags & NATIVE)){
|
||||
stream->writeI32(m->vertices != NULL);
|
||||
stream->writeI32(m->normals != NULL);
|
||||
stream->writeI32(m->vertices != nil);
|
||||
stream->writeI32(m->normals != nil);
|
||||
if(m->vertices)
|
||||
stream->write(m->vertices,
|
||||
3*this->numVertices*4);
|
||||
|
@ -270,8 +292,8 @@ Geometry::addMorphTargets(int32 n)
|
|||
this->morphTargets = morphTargets;
|
||||
for(int32 i = this->numMorphTargets; i < n; i++){
|
||||
MorphTarget *m = &morphTargets[i];
|
||||
m->vertices = NULL;
|
||||
m->normals = NULL;
|
||||
m->vertices = nil;
|
||||
m->normals = nil;
|
||||
if(!(this->geoflags & NATIVE)){
|
||||
m->vertices = new float32[3*this->numVertices];
|
||||
if(this->geoflags & NORMALS)
|
||||
|
@ -344,7 +366,7 @@ void
|
|||
Geometry::generateTriangles(int8 *adc)
|
||||
{
|
||||
MeshHeader *header = this->meshHeader;
|
||||
assert(header != NULL);
|
||||
assert(header != nil);
|
||||
|
||||
this->numTriangles = 0;
|
||||
Mesh *m = header->mesh;
|
||||
|
@ -452,7 +474,7 @@ Geometry::buildMeshes(void)
|
|||
void
|
||||
Geometry::removeUnusedMaterials(void)
|
||||
{
|
||||
if(this->meshHeader == NULL)
|
||||
if(this->meshHeader == nil)
|
||||
return;
|
||||
MeshHeader *mh = this->meshHeader;
|
||||
int32 *map = new int32[this->numMaterials];
|
||||
|
@ -515,13 +537,16 @@ Material*
|
|||
Material::create(void)
|
||||
{
|
||||
Material *mat = (Material*)malloc(PluginBase::s_size);
|
||||
assert(mat != NULL);
|
||||
mat->texture = NULL;
|
||||
if(mat == nil){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return nil;
|
||||
}
|
||||
mat->texture = nil;
|
||||
memset(&mat->color, 0xFF, 4);
|
||||
mat->surfaceProps.ambient = 1.0f;
|
||||
mat->surfaceProps.specular = 1.0f;
|
||||
mat->surfaceProps.diffuse = 1.0f;
|
||||
mat->pipeline = NULL;
|
||||
mat->pipeline = nil;
|
||||
mat->refCount = 1;
|
||||
mat->constructPlugins();
|
||||
return mat;
|
||||
|
@ -531,6 +556,10 @@ Material*
|
|||
Material::clone(void)
|
||||
{
|
||||
Material *mat = Material::create();
|
||||
if(mat == nil){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return nil;
|
||||
}
|
||||
mat->color = this->color;
|
||||
mat->surfaceProps = this->surfaceProps;
|
||||
if(this->texture){
|
||||
|
@ -570,9 +599,14 @@ Material::streamRead(Stream *stream)
|
|||
uint32 length, version;
|
||||
MatStreamData buf;
|
||||
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, &version));
|
||||
if(!findChunk(stream, ID_STRUCT, nil, &version)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return nil;
|
||||
}
|
||||
stream->read(&buf, sizeof(buf));
|
||||
Material *mat = Material::create();
|
||||
if(mat == nil)
|
||||
return nil;
|
||||
mat->color = buf.color;
|
||||
if(version < 0x30400){
|
||||
mat->surfaceProps.ambient = 1.0f;
|
||||
|
@ -586,8 +620,16 @@ Material::streamRead(Stream *stream)
|
|||
mat->surfaceProps.diffuse = surfaceProps[2];
|
||||
}
|
||||
if(buf.textured){
|
||||
assert(findChunk(stream, ID_TEXTURE, &length, NULL));
|
||||
if(!findChunk(stream, ID_TEXTURE, &length, nil)){
|
||||
RWERROR((ERR_CHUNK, "TEXTURE"));
|
||||
// TODO: free
|
||||
return nil;
|
||||
}
|
||||
mat->texture = Texture::streamRead(stream);
|
||||
if(mat->texture == nil){
|
||||
// TODO: fre
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
materialRights[0] = 0;
|
||||
|
@ -609,7 +651,7 @@ Material::streamWrite(Stream *stream)
|
|||
buf.color = this->color;
|
||||
buf.flags = 0;
|
||||
buf.unused = 0;
|
||||
buf.textured = this->texture != NULL;
|
||||
buf.textured = this->texture != nil;
|
||||
stream->write(&buf, sizeof(buf));
|
||||
|
||||
if(rw::version >= 0x30400){
|
||||
|
@ -663,7 +705,7 @@ static int32
|
|||
getSizeMaterialRights(void *object, int32, int32)
|
||||
{
|
||||
Material *material = (Material*)object;
|
||||
if(material->pipeline == NULL || material->pipeline->pluginID == 0)
|
||||
if(material->pipeline == nil || material->pipeline->pluginID == 0)
|
||||
return -1;
|
||||
return 8;
|
||||
}
|
||||
|
@ -671,7 +713,7 @@ getSizeMaterialRights(void *object, int32, int32)
|
|||
void
|
||||
registerMaterialRightsPlugin(void)
|
||||
{
|
||||
Material::registerPlugin(0, ID_RIGHTTORENDER, NULL, NULL, NULL);
|
||||
Material::registerPlugin(0, ID_RIGHTTORENDER, nil, nil, nil);
|
||||
Material::registerPluginStream(ID_RIGHTTORENDER,
|
||||
readMaterialRights,
|
||||
writeMaterialRights,
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwerror.h"
|
||||
#include "rwplg.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
|
||||
#define PLUGIN_ID 2
|
||||
|
||||
namespace rw {
|
||||
|
||||
Light*
|
||||
Light::create(int32 type)
|
||||
{
|
||||
Light *light = (Light*)malloc(PluginBase::s_size);
|
||||
if(light == NULL){
|
||||
RWERROR((ERR_ALLOC, PluginBase::s_size));
|
||||
return NULL;
|
||||
}
|
||||
light->object.object.init(Light::ID, type);
|
||||
light->radius = 0.0f;
|
||||
light->color.red = 1.0f;
|
||||
light->color.green = 1.0f;
|
||||
light->color.blue = 1.0f;
|
||||
light->color.alpha = 1.0f;
|
||||
light->minusCosAngle = 1.0f;
|
||||
light->object.object.privateFlags = 1;
|
||||
light->object.object.flags = LIGHTATOMICS | LIGHTWORLD;
|
||||
light->clump = NULL;
|
||||
light->inClump.init();
|
||||
light->constructPlugins();
|
||||
return light;
|
||||
}
|
||||
|
||||
void
|
||||
Light::destroy(void)
|
||||
{
|
||||
this->destructPlugins();
|
||||
if(this->clump)
|
||||
this->inClump.remove();
|
||||
free(this);
|
||||
}
|
||||
|
||||
void
|
||||
Light::setAngle(float32 angle)
|
||||
{
|
||||
this->minusCosAngle = -cos(angle);
|
||||
}
|
||||
|
||||
float32
|
||||
Light::getAngle(void)
|
||||
{
|
||||
return acos(-this->minusCosAngle);
|
||||
}
|
||||
|
||||
void
|
||||
Light::setColor(float32 r, float32 g, float32 b)
|
||||
{
|
||||
this->color.red = r;
|
||||
this->color.green = g;
|
||||
this->color.blue = b;
|
||||
this->object.object.privateFlags = r == g && r == b;
|
||||
}
|
||||
|
||||
struct LightChunkData
|
||||
{
|
||||
float32 radius;
|
||||
float32 red, green, blue;
|
||||
float32 minusCosAngle;
|
||||
uint16 flags;
|
||||
uint16 type;
|
||||
};
|
||||
|
||||
Light*
|
||||
Light::streamRead(Stream *stream)
|
||||
{
|
||||
uint32 version;
|
||||
LightChunkData buf;
|
||||
|
||||
if(!findChunk(stream, ID_STRUCT, NULL, &version)){
|
||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
||||
return NULL;
|
||||
}
|
||||
stream->read(&buf, sizeof(LightChunkData));
|
||||
Light *light = Light::create(buf.type);
|
||||
if(light == NULL)
|
||||
return NULL;
|
||||
light->radius = buf.radius;
|
||||
light->setColor(buf.red, buf.green, buf.blue);
|
||||
float32 a = buf.minusCosAngle;
|
||||
if(version >= 0x30300)
|
||||
light->minusCosAngle = a;
|
||||
else
|
||||
// tan -> -cos
|
||||
light->minusCosAngle = -1.0f/sqrt(a*a+1.0f);
|
||||
light->object.object.flags = (uint8)buf.flags;
|
||||
light->streamReadPlugins(stream);
|
||||
return light;
|
||||
}
|
||||
|
||||
bool
|
||||
Light::streamWrite(Stream *stream)
|
||||
{
|
||||
LightChunkData buf;
|
||||
writeChunkHeader(stream, ID_LIGHT, this->streamGetSize());
|
||||
writeChunkHeader(stream, ID_STRUCT, sizeof(LightChunkData));
|
||||
buf.radius = this->radius;
|
||||
buf.red = this->color.red;
|
||||
buf.green = this->color.green;
|
||||
buf.blue = this->color.blue;
|
||||
if(version >= 0x30300)
|
||||
buf.minusCosAngle = this->minusCosAngle;
|
||||
else
|
||||
buf.minusCosAngle = tan(acos(-this->minusCosAngle));
|
||||
buf.flags = this->object.object.flags;
|
||||
buf.type = this->object.object.subType;
|
||||
stream->write(&buf, sizeof(LightChunkData));
|
||||
|
||||
this->streamWritePlugins(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
Light::streamGetSize(void)
|
||||
{
|
||||
return 12 + sizeof(LightChunkData) + 12 + this->streamGetPluginSize();
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include <cctype>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwerror.h"
|
||||
#include "rwplg.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
|
@ -21,6 +22,8 @@ using namespace std;
|
|||
|
||||
namespace rw {
|
||||
|
||||
#define PLUGIN_ID 0
|
||||
|
||||
int32 version = 0x36003;
|
||||
int32 build = 0xFFFF;
|
||||
#ifdef RW_PS2
|
||||
|
@ -665,7 +668,11 @@ StreamFile*
|
|||
StreamFile::open(const char *path, const char *mode)
|
||||
{
|
||||
this->file = fopen(path, mode);
|
||||
return this->file ? this : NULL;
|
||||
if(this->file == NULL){
|
||||
RWERROR((ERR_FILE, path));
|
||||
return NULL;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -758,10 +765,8 @@ findPointer(void *p, void **list, int32 num)
|
|||
int i;
|
||||
for(i = 0; i < num; i++)
|
||||
if(list[i] == p)
|
||||
goto found;
|
||||
return -1;
|
||||
found:
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8*
|
||||
|
|
12
src/rwbase.h
12
src/rwbase.h
|
@ -33,6 +33,8 @@ typedef int32 bool32;
|
|||
typedef uint8 byte;
|
||||
typedef uint32 uint;
|
||||
|
||||
#define nil NULL
|
||||
|
||||
#define nelem(A) (sizeof(A) / sizeof A[0])
|
||||
|
||||
struct RGBA
|
||||
|
@ -284,6 +286,16 @@ enum PluginID
|
|||
ID_VERTEXFMT = 0x511,
|
||||
};
|
||||
|
||||
#define ECODE(c, s) c,
|
||||
|
||||
enum Errors
|
||||
{
|
||||
ERR_NONE = 0x80000000,
|
||||
#include "base.err"
|
||||
};
|
||||
|
||||
#undef ECODE
|
||||
|
||||
extern int version;
|
||||
extern int build;
|
||||
extern int platform;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
namespace rw {
|
||||
|
||||
struct Error
|
||||
{
|
||||
uint32 plugin;
|
||||
uint32 code;
|
||||
};
|
||||
|
||||
void setError(Error *e);
|
||||
Error *getError(Error *e);
|
||||
|
||||
#define _ERRORCODE(code, ...) code
|
||||
char *dbgsprint(int32 code, ...);
|
||||
|
||||
/* ecode is supposed to be in format "(errorcode, printf-arguments..)" */
|
||||
#define RWERROR(ecode) do{ \
|
||||
rw::Error _e; \
|
||||
_e.plugin = PLUGIN_ID; \
|
||||
_e.code = _ERRORCODE ecode; \
|
||||
fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \
|
||||
fprintf(stderr, "%s\n", rw::dbgsprint ecode); \
|
||||
rw::setError(&_e); \
|
||||
}while(0);
|
||||
|
||||
}
|
|
@ -544,7 +544,7 @@ struct Clump : PluginBase<Clump>
|
|||
uint32 streamGetSize(void);
|
||||
void render(void);
|
||||
|
||||
void frameListStreamRead(Stream *stream, Frame ***flp, int32 *nf);
|
||||
bool frameListStreamRead(Stream *stream, Frame ***flp, int32 *nf);
|
||||
void frameListStreamWrite(Stream *stream, Frame **flp, int32 nf);
|
||||
};
|
||||
|
||||
|
|
|
@ -205,13 +205,13 @@ PluginBase<T>::getPluginOffset(uint32 id)
|
|||
template <typename T> void*
|
||||
PluginBase<T>::operator new(size_t)
|
||||
{
|
||||
assert(0);
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename T> void
|
||||
PluginBase<T>::operator delete(void *p)
|
||||
{
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue