got animation, hanim and skinning basically working

This commit is contained in:
aap 2016-07-11 20:27:21 +02:00
parent b1e55a7784
commit 5dff69431e
31 changed files with 1175 additions and 482 deletions

1
rw.h
View File

@ -6,6 +6,7 @@
#include "src/rwplg.h"
#include "src/rwpipeline.h"
#include "src/rwobjects.h"
#include "src/rwanim.h"
#include "src/rwengine.h"
#include "src/rwplugins.h"
#include "src/ps2/rwps2.h"

View File

@ -8,18 +8,23 @@
#include "rwplg.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwanim.h"
#include "rwplugins.h"
#define PLUGIN_ID 2 // ?
#define PLUGIN_ID 0
namespace rw {
//
// AnimInterpolatorInfo
//
#define MAXINTERPINFO 10
static AnimInterpolatorInfo *interpInfoList[MAXINTERPINFO];
void
registerAnimInterpolatorInfo(AnimInterpolatorInfo *interpInfo)
AnimInterpolatorInfo::registerInterp(AnimInterpolatorInfo *interpInfo)
{
for(int32 i = 0; i < MAXINTERPINFO; i++)
if(interpInfoList[i] == nil){
@ -30,7 +35,7 @@ registerAnimInterpolatorInfo(AnimInterpolatorInfo *interpInfo)
}
AnimInterpolatorInfo*
findAnimInterpolatorInfo(int32 id)
AnimInterpolatorInfo::find(int32 id)
{
for(int32 i = 0; i < MAXINTERPINFO; i++){
if(interpInfoList[i] && interpInfoList[i]->id == id)
@ -39,17 +44,30 @@ findAnimInterpolatorInfo(int32 id)
return nil;
}
//
// Animation
//
Animation*
Animation::create(AnimInterpolatorInfo *interpInfo, int32 numFrames, int32 flags, float duration)
Animation::create(AnimInterpolatorInfo *interpInfo, int32 numFrames,
int32 flags, float duration)
{
Animation *anim = (Animation*)malloc(sizeof(*anim));
int32 sz = sizeof(Animation) +
numFrames*interpInfo->animKeyFrameSize +
interpInfo->customDataSize;
uint8 *data = (uint8*)malloc(sz);
if(data == nil){
RWERROR((ERR_ALLOC, sz));
return nil;
}
Animation *anim = (Animation*)data;
data += sizeof(Animation);
anim->interpInfo = interpInfo;
anim->numFrames = numFrames;
anim->flags = flags;
anim->duration = duration;
uint8 *data = new uint8[anim->numFrames*interpInfo->keyFrameSize + interpInfo->customDataSize];
anim->keyframes = data;
data += anim->numFrames*interpInfo->keyFrameSize;
data += anim->numFrames*interpInfo->animKeyFrameSize;
anim->customData = data;
return anim;
}
@ -57,11 +75,20 @@ Animation::create(AnimInterpolatorInfo *interpInfo, int32 numFrames, int32 flags
void
Animation::destroy(void)
{
uint8 *c = (uint8*)this->keyframes;
delete[] c;
free(this);
}
int32
Animation::getNumNodes(void)
{
int32 sz = this->interpInfo->animKeyFrameSize;
KeyFrameHeader *first = (KeyFrameHeader*)this->keyframes;
int32 n = 0;
for(KeyFrameHeader *f = first; f->prev != first; f = f->next(sz))
n++;
return n;
}
Animation*
Animation::streamRead(Stream *stream)
{
@ -69,7 +96,7 @@ Animation::streamRead(Stream *stream)
if(stream->readI32() != 0x100)
return nil;
int32 typeID = stream->readI32();
AnimInterpolatorInfo *interpInfo = findAnimInterpolatorInfo(typeID);
AnimInterpolatorInfo *interpInfo = AnimInterpolatorInfo::find(typeID);
int32 numFrames = stream->readI32();
int32 flags = stream->readI32();
float duration = stream->readF32();
@ -82,15 +109,15 @@ Animation*
Animation::streamReadLegacy(Stream *stream)
{
Animation *anim;
AnimInterpolatorInfo *interpInfo = findAnimInterpolatorInfo(1);
AnimInterpolatorInfo *interpInfo = AnimInterpolatorInfo::find(1);
int32 numFrames = stream->readI32();
int32 flags = stream->readI32();
float duration = stream->readF32();
anim = Animation::create(interpInfo, numFrames, flags, duration);
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
for(int32 i = 0; i < anim->numFrames; i++){
stream->read(frames[i].q, 4*4);
stream->read(frames[i].t, 3*4);
stream->read(&frames[i].q, 4*4);
stream->read(&frames[i].t, 3*4);
frames[i].time = stream->readF32();
int32 prev = stream->readI32();
frames[i].prev = &frames[prev];
@ -120,8 +147,8 @@ Animation::streamWriteLegacy(Stream *stream)
assert(interpInfo->id == 1);
HAnimKeyFrame *frames = (HAnimKeyFrame*)this->keyframes;
for(int32 i = 0; i < this->numFrames; i++){
stream->write(frames[i].q, 4*4);
stream->write(frames[i].t, 3*4);
stream->write(&frames[i].q, 4*4);
stream->write(&frames[i].t, 3*4);
stream->writeF32(frames[i].time);
stream->writeI32(frames[i].prev - frames);
}
@ -136,321 +163,114 @@ Animation::streamGetSize(void)
return size;
}
AnimInterpolator::AnimInterpolator(Animation *anim)
{
this->anim = anim;
}
//
// UVAnim
// AnimInterpolator
//
void
UVAnimCustomData::destroy(Animation *anim)
AnimInterpolator*
AnimInterpolator::create(int32 numNodes, int32 maxFrameSize)
{
this->refCount--;
if(this->refCount <= 0)
anim->destroy();
}
AnimInterpolator *interp;
int32 sz;
int32 realsz = maxFrameSize;
UVAnimDictionary *currentUVAnimDictionary;
UVAnimDictionary*
UVAnimDictionary::create(void)
{
UVAnimDictionary *dict = (UVAnimDictionary*)malloc(sizeof(UVAnimDictionary));
if(dict == nil){
RWERROR((ERR_ALLOC, sizeof(UVAnimDictionary)));
// Add some space for pointers and padding, hopefully this will
// enough. Don't change maxFrameSize not to mess up streaming.
if(sizeof(void*) > 4)
realsz += 16;
sz = sizeof(AnimInterpolator) + numNodes*realsz;
interp = (AnimInterpolator*)malloc(sz);
if(interp == nil){
RWERROR((ERR_ALLOC, sz));
return nil;
}
dict->animations.init();
return dict;
interp->currentAnim = nil;
interp->currentTime = 0.0f;
interp->nextFrame = nil;
interp->maxInterpKeyFrameSize = maxFrameSize;
interp->currentInterpKeyFrameSize = maxFrameSize;
interp->currentAnimKeyFrameSize = -1;
interp->numNodes = numNodes;;
return interp;
}
void
UVAnimDictionary::destroy(void)
AnimInterpolator::destroy(void)
{
FORLIST(lnk, this->animations){
UVAnimDictEntry *de = UVAnimDictEntry::fromDict(lnk);
UVAnimCustomData *cust = (UVAnimCustomData*)de->anim->customData;
cust->destroy(de->anim);
delete de;
}
free(this);
}
void
UVAnimDictionary::add(Animation *anim)
bool32
AnimInterpolator::setCurrentAnim(Animation *anim)
{
UVAnimDictEntry *de = new UVAnimDictEntry;
de->anim = anim;
this->animations.append(&de->inDict);
}
UVAnimDictionary*
UVAnimDictionary::streamRead(Stream *stream)
{
if(!findChunk(stream, ID_STRUCT, nil, nil)){
RWERROR((ERR_CHUNK, "STRUCT"));
return nil;
int32 i;
AnimInterpolatorInfo *interpInfo = anim->interpInfo;
this->currentAnim = anim;
this->currentTime = 0.0f;
int32 maxkf = this->maxInterpKeyFrameSize;
if(sizeof(void*) > 4) // see above in create()
maxkf += 16;
if(interpInfo->interpKeyFrameSize > maxkf){
RWERROR((ERR_GENERAL, "interpolation frame too big"));
return 0;
}
UVAnimDictionary *dict = UVAnimDictionary::create();
if(dict == nil)
return nil;
int32 numAnims = stream->readI32();
Animation *anim;
for(int32 i = 0; i < numAnims; i++){
if(!findChunk(stream, ID_ANIMANIMATION, nil, nil)){
RWERROR((ERR_CHUNK, "ANIMANIMATION"));
goto fail;
}
anim = Animation::streamRead(stream);
if(anim == nil)
goto fail;
dict->add(anim);
this->currentInterpKeyFrameSize = interpInfo->interpKeyFrameSize;
this->currentAnimKeyFrameSize = interpInfo->animKeyFrameSize;
this->applyCB = interpInfo->applyCB;
this->blendCB = interpInfo->blendCB;
this->interpCB = interpInfo->interpCB;
this->addCB = interpInfo->addCB;
for(i = 0; i < numNodes; i++){
InterpFrameHeader *intf;
KeyFrameHeader *kf1, *kf2;
intf = this->getInterpFrame(i);
kf1 = this->getAnimFrame(i);
kf2 = this->getAnimFrame(i+numNodes);
intf->keyFrame1 = kf1;
intf->keyFrame2 = kf2;
this->interpCB(intf, kf1, kf2, 0.0f, anim->customData);
}
return dict;
fail:
dict->destroy();
return nil;
this->nextFrame = this->getAnimFrame(numNodes*2);
return 1;
}
bool
UVAnimDictionary::streamWrite(Stream *stream)
{
uint32 size = this->streamGetSize();
writeChunkHeader(stream, ID_UVANIMDICT, size);
writeChunkHeader(stream, ID_STRUCT, 4);
int32 numAnims = this->count();
stream->writeI32(numAnims);
FORLIST(lnk, this->animations){
UVAnimDictEntry *de = UVAnimDictEntry::fromDict(lnk);
de->anim->streamWrite(stream);
}
return true;
}
uint32
UVAnimDictionary::streamGetSize(void)
{
uint32 size = 12 + 4;
FORLIST(lnk, this->animations){
UVAnimDictEntry *de = UVAnimDictEntry::fromDict(lnk);
size += 12 + de->anim->streamGetSize();
}
return size;
}
Animation*
UVAnimDictionary::find(const char *name)
{
FORLIST(lnk, this->animations){
Animation *anim = UVAnimDictEntry::fromDict(lnk)->anim;
UVAnimCustomData *custom = (UVAnimCustomData*)anim->customData;
if(strncmp_ci(custom->name, name, 32) == 0)
return anim;
}
return nil;
}
static void
uvAnimStreamRead(Stream *stream, Animation *anim)
{
UVAnimCustomData *custom = (UVAnimCustomData*)anim->customData;
UVAnimKeyFrame *frames = (UVAnimKeyFrame*)anim->keyframes;
stream->readI32();
stream->read(custom->name, 32);
stream->read(custom->nodeToUVChannel, 8*4);
custom->refCount = 1;
for(int32 i = 0; i < anim->numFrames; i++){
frames[i].time = stream->readF32();
stream->read(frames[i].uv, 6*4);
int32 prev = stream->readI32();
frames[i].prev = &frames[prev];
}
}
static void
uvAnimStreamWrite(Stream *stream, Animation *anim)
{
UVAnimCustomData *custom = (UVAnimCustomData*)anim->customData;
UVAnimKeyFrame *frames = (UVAnimKeyFrame*)anim->keyframes;
stream->writeI32(0);
stream->write(custom->name, 32);
stream->write(custom->nodeToUVChannel, 8*4);
for(int32 i = 0; i < anim->numFrames; i++){
stream->writeF32(frames[i].time);
stream->write(frames[i].uv, 6*4);
stream->writeI32(frames[i].prev - frames);
}
}
static uint32
uvAnimStreamGetSize(Animation *anim)
{
return 4 + 32 + 8*4 + anim->numFrames*(4 + 6*4 + 4);
}
static void
registerUVAnimInterpolator(void)
{
// Linear
AnimInterpolatorInfo *info = new AnimInterpolatorInfo;
info->id = 0x1C0;
info->keyFrameSize = sizeof(UVAnimKeyFrame);
info->customDataSize = sizeof(UVAnimCustomData);
info->streamRead = uvAnimStreamRead;
info->streamWrite = uvAnimStreamWrite;
info->streamGetSize = uvAnimStreamGetSize;
registerAnimInterpolatorInfo(info);
// Param
info = new AnimInterpolatorInfo;
info->id = 0x1C1;
info->keyFrameSize = sizeof(UVAnimKeyFrame);
info->customDataSize = sizeof(UVAnimCustomData);
info->streamRead = uvAnimStreamRead;
info->streamWrite = uvAnimStreamWrite;
info->streamGetSize = uvAnimStreamGetSize;
registerAnimInterpolatorInfo(info);
}
int32 uvAnimOffset;
static void*
createUVAnim(void *object, int32 offset, int32)
{
UVAnim *uvanim;
uvanim = PLUGINOFFSET(UVAnim, object, offset);
memset(uvanim, 0, sizeof(*uvanim));
return object;
}
static void*
destroyUVAnim(void *object, int32 offset, int32)
{
UVAnim *uvanim;
uvanim = PLUGINOFFSET(UVAnim, object, offset);
for(int32 i = 0; i < 8; i++){
AnimInterpolator *ip = uvanim->interp[i];
if(ip){
UVAnimCustomData *custom = (UVAnimCustomData*)ip->anim->customData;
custom->destroy(ip->anim);
delete ip;
}
}
return object;
}
static void*
copyUVAnim(void *dst, void *src, int32 offset, int32)
{
UVAnim *srcuvanim, *dstuvanim;
dstuvanim = PLUGINOFFSET(UVAnim, dst, offset);
srcuvanim = PLUGINOFFSET(UVAnim, src, offset);
for(int32 i = 0; i < 8; i++){
AnimInterpolator *srcip = srcuvanim->interp[i];
AnimInterpolator *dstip;
if(srcip){
UVAnimCustomData *custom = (UVAnimCustomData*)srcip->anim->customData;
dstip = new AnimInterpolator(srcip->anim);
custom->refCount++;
dstuvanim->interp[i] = dstip;
}
}
return dst;
}
Animation*
makeDummyAnimation(const char *name)
{
AnimInterpolatorInfo *interpInfo = findAnimInterpolatorInfo(0x1C0);
Animation *anim = Animation::create(interpInfo, 2, 0, 1.0f);
UVAnimCustomData *custom = (UVAnimCustomData*)anim->customData;
strncpy(custom->name, name, 32);
memset(custom->nodeToUVChannel, 0, sizeof(custom->nodeToUVChannel));
custom->refCount = 1;
// TODO: init the frames
// UVAnimKeyFrame *frames = (UVAnimKeyFrame*)anim->keyframes;
return anim;
}
static Stream*
readUVAnim(Stream *stream, int32, void *object, int32 offset, int32)
{
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
if(!findChunk(stream, ID_STRUCT, nil, nil)){
RWERROR((ERR_CHUNK, "STRUCT"));
return nil;
}
char name[32];
uint32 mask = stream->readI32();
uint32 bit = 1;
for(int32 i = 0; i < 8; i++){
if(mask & bit){
stream->read(name, 32);
Animation *anim = nil;
if(currentUVAnimDictionary)
anim = currentUVAnimDictionary->find(name);
if(anim == nil){
anim = makeDummyAnimation(name);
if(currentUVAnimDictionary)
currentUVAnimDictionary->add(anim);
}
UVAnimCustomData *custom = (UVAnimCustomData*)anim->customData;
AnimInterpolator *interp = new AnimInterpolator(anim);
custom->refCount++;
uvanim->interp[i] = interp;
}
bit <<= 1;
}
return stream;
}
static Stream*
writeUVAnim(Stream *stream, int32 size, void *object, int32 offset, int32)
{
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
writeChunkHeader(stream, ID_STRUCT, size-12);
uint32 mask = 0;
uint32 bit = 1;
for(int32 i = 0; i < 8; i++){
if(uvanim->interp[i])
mask |= bit;
bit <<= 1;
}
stream->writeI32(mask);
for(int32 i = 0; i < 8; i++){
if(uvanim->interp[i]){
UVAnimCustomData *custom =
(UVAnimCustomData*)uvanim->interp[i]->anim->customData;
stream->write(custom->name, 32);
}
}
return stream;
}
static int32
getSizeUVAnim(void *object, int32 offset, int32)
{
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
int32 size = 0;
for(int32 i = 0; i < 8; i++)
if(uvanim->interp[i])
size += 32;
return size ? size + 12 + 4 : 0;
}
void
registerUVAnimPlugin(void)
AnimInterpolator::addTime(float32 t)
{
registerUVAnimInterpolator();
uvAnimOffset = Material::registerPlugin(sizeof(UVAnim), ID_UVANIMATION,
createUVAnim, destroyUVAnim, copyUVAnim);
Material::registerPluginStream(ID_UVANIMATION, readUVAnim, writeUVAnim, getSizeUVAnim);
int32 i;
if(t <= 0.0f)
return;
this->currentTime += t;
// reset animation
if(this->currentTime > this->currentAnim->duration){
this->setCurrentAnim(this->currentAnim);
return;
}
KeyFrameHeader *last = this->getAnimFrame(this->currentAnim->numFrames);
KeyFrameHeader *next = (KeyFrameHeader*)this->nextFrame;
InterpFrameHeader *ifrm;
while(next < last && next->prev->time <= this->currentTime){
// find next interpolation frame to expire
for(i = 0; i < this->numNodes; i++){
ifrm = this->getInterpFrame(i);
if(ifrm->keyFrame2 == next->prev)
break;
}
// advance interpolation frame
ifrm->keyFrame1 = ifrm->keyFrame2;
ifrm->keyFrame2 = next;
// ... and next frame
next = (KeyFrameHeader*)((uint8*)this->nextFrame +
currentAnimKeyFrameSize);
this->nextFrame = next;
}
for(i = 0; i < this->numNodes; i++){
ifrm = this->getInterpFrame(i);
this->interpCB(ifrm, ifrm->keyFrame1, ifrm->keyFrame2,
this->currentTime,
this->currentAnim->customData);
}
}
}

View File

@ -10,7 +10,6 @@
#include "rwplg.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwplugins.h"
#include "rwengine.h"
namespace rw {
@ -74,6 +73,41 @@ mult(const Quat &q, const Quat &p)
q.w*p.z + q.z*p.w + q.x*p.y - q.y*p.x);
}
Quat
lerp(const Quat &q, const Quat &p, float32 r)
{
float32 c;
Quat q1 = q;
c = dot(q1, p);
if(c < 0.0f){
c = -c;
q1 = negate(q1);
}
return Quat(q1.w + r*(p.w - q1.w),
q1.x + r*(p.x - q1.x),
q1.y + r*(p.y - q1.y),
q1.z + r*(p.z - q1.z));
};
Quat
slerp(const Quat &q, const Quat &p, float32 a)
{
float32 c;
Quat q1 = q;
c = dot(q1, p);
if(c < 0.0f){
c = -c;
q1 = negate(q1);
}
float32 phi = acos(c);
if(phi > 0.00001f){
float32 s = sin(phi);
return add(scale(q1, sin((1.0f-a)*phi)/s),
scale(p, sin(a*phi)/s));
}
return q1;
}
V3d
cross(const V3d &a, const V3d &b)
{
@ -82,19 +116,35 @@ cross(const V3d &a, const V3d &b)
a.x*b.y - a.y*b.x);
}
/* q must be normalized */
Matrix
Matrix::makeRotation(const Quat &q)
{
Matrix res;
res.right.x = q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z;
res.right.y = 2*q.w*q.z + 2*q.x*q.y;
res.right.z = 2*q.x*q.z - 2*q.w*q.y;
res.up.x = 2*q.x*q.y - 2*q.w*q.z;
res.up.y = q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z;
res.up.z = 2*q.w*q.x + 2*q.y*q.z;
res.at.x = 2*q.w*q.y + 2*q.x*q.z;
res.at.y = 2*q.y*q.z - 2*q.w*q.x;
res.at.z = q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z;
float xx = q.x*q.x;
float yy = q.y*q.y;
float zz = q.z*q.z;
float yz = q.y*q.z;
float zx = q.z*q.x;
float xy = q.x*q.y;
float wx = q.w*q.x;
float wy = q.w*q.y;
float wz = q.w*q.z;
res.right.x = 1.0f - 2.0f*(yy + zz);
res.right.y = 2.0f*(xy + wz);
res.right.z = 2.0f*(zx - wy);
res.up.x = 2.0f*(xy - wz);
res.up.y = 1.0f - 2.0f*(xx + zz);
res.up.z = 2.0f*(yz + wx);
res.at.x = 2.0f*(zx + wy);
res.at.y = 2.0f*(yz - wx);
res.at.z = 1.0f - 2.0f*(xx + yy);
res.pos.x = res.pos.y = res.pos.z = 0.0f;
res.rightw = res.upw = res.atw = 0.0f;
res.posw = 1.0f;
return res;

View File

@ -1,5 +1,5 @@
ECODE(ERR_GENERAL,
"General Error")
"Error: %s")
ECODE(ERR_ALLOC,
"Couldn't allocate 0x%X bytes")
ECODE(ERR_FILE,

View File

@ -8,6 +8,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#include "rwd3d.h"

View File

@ -8,6 +8,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#include "rwd3d.h"

View File

@ -9,7 +9,6 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#include "rwxbox.h"
#include "rwxboximpl.h"

View File

@ -8,6 +8,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#include "rwxbox.h"
@ -115,7 +116,7 @@ skinInstanceCB(Geometry *geo, InstanceDataHeader *header)
{
defaultInstanceCB(geo, header);
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
Skin *skin = Skin::get(geo);
if(skin == nil)
return;
NativeSkin *natskin = new NativeSkin;
@ -169,7 +170,7 @@ skinUninstanceCB(Geometry *geo, InstanceDataHeader *header)
{
defaultUninstanceCB(geo, header);
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
Skin *skin = Skin::get(geo);
if(skin == nil)
return;
NativeSkin *natskin = (NativeSkin*)skin->platformData;

View File

@ -8,6 +8,7 @@
#include "rwplg.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwanim.h"
#include "rwplugins.h"
#include "ps2/rwps2.h"
#include "ps2/rwps2plg.h"

View File

@ -9,7 +9,6 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
#endif

View File

@ -8,7 +8,6 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
#include "rwgl3.h"

View File

@ -9,7 +9,6 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
#endif

View File

@ -8,6 +8,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#ifdef RW_OPENGL
@ -229,10 +230,13 @@ makeMatFXPipeline(void)
// Skin
Shader *skinShader;
static void*
skinOpen(void *o, int32, int32)
{
skinGlobals.pipelines[PLATFORM_GL3] = makeSkinPipeline();
skinShader = Shader::fromFiles("skin.vert", "simple.frag");
return o;
}
@ -247,15 +251,250 @@ initSkin(void)
{
Driver::registerPlugin(PLATFORM_GL3, 0, ID_SKIN,
skinOpen, skinClose);
registerUniform("u_boneMatrices");
}
enum
{
ATTRIB_WEIGHTS = ATTRIB_TEXCOORDS7+1,
ATTRIB_INDICES
};
void
skinInstanceCB(Geometry *geo, InstanceDataHeader *header)
{
AttribDesc attribs[14], *a;
uint32 stride;
//
// Create attribute descriptions
//
a = attribs;
stride = 0;
// Positions
a->index = ATTRIB_POS;
a->size = 3;
a->type = GL_FLOAT;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 12;
a++;
// Normals
// TODO: compress
bool hasNormals = !!(geo->geoflags & Geometry::NORMALS);
if(hasNormals){
a->index = ATTRIB_NORMAL;
a->size = 3;
a->type = GL_FLOAT;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 12;
a++;
}
// Prelighting
bool isPrelit = !!(geo->geoflags & Geometry::PRELIT);
if(isPrelit){
a->index = ATTRIB_COLOR;
a->size = 4;
a->type = GL_UNSIGNED_BYTE;
a->normalized = GL_TRUE;
a->offset = stride;
stride += 4;
a++;
}
// Texture coordinates
for(int32 n = 0; n < geo->numTexCoordSets; n++){
a->index = ATTRIB_TEXCOORDS0+n;
a->size = 2;
a->type = GL_FLOAT;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 8;
a++;
}
// Weights
a->index = ATTRIB_WEIGHTS;
a->size = 4;
a->type = GL_FLOAT;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 16;
a++;
// Indices
a->index = ATTRIB_INDICES;
a->size = 4;
a->type = GL_UNSIGNED_BYTE;
a->normalized = GL_FALSE;
a->offset = stride;
stride += 4;
a++;
header->numAttribs = a - attribs;
for(a = attribs; a != &attribs[header->numAttribs]; a++)
a->stride = stride;
header->attribDesc = new AttribDesc[header->numAttribs];
memcpy(header->attribDesc, attribs,
header->numAttribs*sizeof(AttribDesc));
//
// Allocate and fill vertex buffer
//
Skin *skin = Skin::get(geo);
uint8 *verts = new uint8[header->totalNumVertex*stride];
header->vertexBuffer = verts;
// Positions
for(a = attribs; a->index != ATTRIB_POS; a++)
;
instV3d(VERT_FLOAT3, verts + a->offset,
geo->morphTargets[0].vertices,
header->totalNumVertex, a->stride);
// Normals
if(hasNormals){
for(a = attribs; a->index != ATTRIB_NORMAL; a++)
;
instV3d(VERT_FLOAT3, verts + a->offset,
geo->morphTargets[0].normals,
header->totalNumVertex, a->stride);
}
// Prelighting
if(isPrelit){
for(a = attribs; a->index != ATTRIB_COLOR; a++)
;
instColor(VERT_RGBA, verts + a->offset,
geo->colors,
header->totalNumVertex, a->stride);
}
// Texture coordinates
for(int32 n = 0; n < geo->numTexCoordSets; n++){
for(a = attribs; a->index != ATTRIB_TEXCOORDS0+n; a++)
;
instV2d(VERT_FLOAT2, verts + a->offset,
geo->texCoords[n],
header->totalNumVertex, a->stride);
}
// Weights
for(a = attribs; a->index != ATTRIB_WEIGHTS; a++)
;
instV4d(VERT_FLOAT4, verts + a->offset,
skin->weights,
header->totalNumVertex, a->stride);
// Indices
for(a = attribs; a->index != ATTRIB_INDICES; a++)
;
// not really colors of course but what the heck
instColor(VERT_RGBA, verts + a->offset,
skin->indices,
header->totalNumVertex, a->stride);
glGenBuffers(1, &header->vbo);
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
glBufferData(GL_ARRAY_BUFFER, header->totalNumVertex*stride,
header->vertexBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void
skinUninstanceCB(Geometry *geo, InstanceDataHeader *header)
{
assert(0 && "can't uninstance");
}
#define U(s) currentShader->uniformLocations[findUniform(s)]
static float skinMatrices[64*16];
void
updateSkinMatrices(Atomic *a)
{
Skin *skin = Skin::get(a->geometry);
HAnimHierarchy *hier = Skin::getHierarchy(a);
Matrix *invMats = (Matrix*)skin->inverseMatrices;
float *m;
m = (float*)skinMatrices;
for(int i = 0; i < hier->numNodes; i++){
invMats[i].rightw = 0.0f;
invMats[i].upw = 0.0f;
invMats[i].atw = 0.0f;
invMats[i].posw = 1.0f;
Matrix::mult((Matrix*)m, &hier->matrices[i], &invMats[i]);
m[3] = 0.0f;
m[7] = 0.0f;
m[11] = 0.0f;
m[15] = 1.0f;
m += 16;
}
}
void
skinRenderCB(Atomic *atomic, InstanceDataHeader *header)
{
Material *m;
RGBAf col;
GLfloat surfProps[4];
int id;
setWorldMatrix(atomic->getFrame()->getLTM());
lightingCB();
glBindBuffer(GL_ARRAY_BUFFER, header->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, header->ibo);
setAttribPointers(header);
InstanceData *inst = header->inst;
int32 n = header->numMeshes;
rw::setRenderState(ALPHATESTFUNC, 1);
rw::setRenderState(ALPHATESTREF, 50);
skinShader->use();
updateSkinMatrices(atomic);
glUniformMatrix4fv(U("u_boneMatrices"), 64, GL_FALSE,
(GLfloat*)skinMatrices);
while(n--){
m = inst->material;
convColor(&col, &m->color);
glUniform4fv(U("u_matColor"), 1, (GLfloat*)&col);
surfProps[0] = m->surfaceProps.ambient;
surfProps[1] = m->surfaceProps.specular;
surfProps[2] = m->surfaceProps.diffuse;
surfProps[3] = 0.0f;
glUniform4fv(U("u_surfaceProps"), 1, surfProps);
setTexture(0, m->texture);
rw::setRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF);
flushCache();
glDrawElements(header->primType, inst->numIndex,
GL_UNSIGNED_SHORT, (void*)(uintptr)inst->offset);
inst++;
}
}
ObjPipeline*
makeSkinPipeline(void)
{
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
pipe->instanceCB = defaultInstanceCB;
pipe->uninstanceCB = defaultUninstanceCB;
pipe->renderCB = defaultRenderCB;
pipe->instanceCB = skinInstanceCB;
pipe->uninstanceCB = skinUninstanceCB;
pipe->renderCB = skinRenderCB;
pipe->pluginID = ID_SKIN;
pipe->pluginData = 1;
return pipe;

View File

@ -9,7 +9,6 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
#endif

View File

@ -8,7 +8,6 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
#include "rwgl3.h"

View File

@ -8,7 +8,6 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#ifdef RW_OPENGL
#include <GL/glew.h>
#include "rwgl3.h"

View File

@ -8,6 +8,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#include "rwwdgl.h"
@ -603,7 +604,7 @@ skinInstanceCB(Geometry *g, int32 i, uint32 offset)
header->dataSize = offset*g->numVertices;
header->data = new uint8[header->dataSize];
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
Skin *skin = Skin::get(g);
if(skin == nil)
return 8;
@ -631,7 +632,7 @@ skinUninstanceCB(Geometry *geo)
{
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
Skin *skin = Skin::get(geo);
if(skin == nil)
return;

View File

@ -8,6 +8,7 @@
#include "rwplg.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwanim.h"
#include "rwplugins.h"
#include "ps2/rwps2.h"
#include "ps2/rwps2plg.h"
@ -25,22 +26,24 @@ int32 hAnimOffset;
bool32 hAnimDoStream = 1;
HAnimHierarchy*
HAnimHierarchy::create(int32 numNodes, int32 *nodeFlags, int32 *nodeIDs, int32 flags, int32 maxKeySize)
HAnimHierarchy::create(int32 numNodes, int32 *nodeFlags, int32 *nodeIDs,
int32 flags, int32 maxKeySize)
{
HAnimHierarchy *hier = (HAnimHierarchy*)malloc(sizeof(*hier));
hier->currentAnim = AnimInterpolator::create(numNodes, maxKeySize);
hier->numNodes = numNodes;
hier->flags = flags;
hier->maxInterpKeyFrameSize = maxKeySize;
hier->parentFrame = nil;
hier->parentHierarchy = hier;
if(hier->flags & 2)
hier->matrices = hier->matricesUnaligned = nil;
else{
if(hier->flags & NOMATRICES){
hier->matrices = nil;
hier->matricesUnaligned = nil;
}else{
hier->matricesUnaligned =
(float*) new uint8[hier->numNodes*64 + 15];
(void*) new uint8[hier->numNodes*64 + 15];
hier->matrices =
(float*)((uintptr)hier->matricesUnaligned & ~0xF);
(Matrix*)((uintptr)hier->matricesUnaligned & ~0xF);
}
hier->nodeInfo = new HAnimNodeInfo[hier->numNodes];
for(int32 i = 0; i < hier->numNodes; i++){
@ -112,6 +115,43 @@ HAnimHierarchy::find(Frame *f)
return HAnimHierarchy::find(f->child);
}
void
HAnimHierarchy::updateMatrices(void)
{
// TODO: handle more (all!) cases
Matrix rootMat, animMat;
Matrix *curMat, *parentMat;
Matrix **sp, *stack[64];
Frame *frm, *parfrm;
int32 i;
AnimInterpolator *anim = this->currentAnim;
sp = stack;
curMat = this->matrices;
frm = this->parentFrame;
if(frm && (parfrm = frm->getParent()))
rootMat = *parfrm->getLTM();
else
rootMat.setIdentity();
parentMat = &rootMat;
HAnimNodeInfo *node = this->nodeInfo;
for(i = 0; i < this->numNodes; i++){
anim->applyCB(&animMat, anim->getInterpFrame(i));
Matrix::mult(curMat, parentMat, &animMat);
if(node->flags & PUSH)
*sp++ = parentMat;
parentMat = curMat;
if(node->flags & POP)
parentMat = *--sp;
node++;
curMat++;
}
}
HAnimData*
HAnimData::get(Frame *f)
{
@ -161,6 +201,8 @@ readHAnim(Stream *stream, int32, void *object, int32 offset, int32)
if(numNodes != 0){
int32 flags = stream->readI32();
int32 maxKeySize = stream->readI32();
// Sizes are fucked for 64 bit pointers but
// AnimInterpolator::create() will take care of that
int32 *nodeFlags = new int32[numNodes];
int32 *nodeIDs = new int32[numNodes];
for(int32 i = 0; i < numNodes; i++){
@ -190,7 +232,7 @@ writeHAnim(Stream *stream, int32, void *object, int32 offset, int32)
HAnimHierarchy *hier = hanim->hierarchy;
stream->writeI32(hier->numNodes);
stream->writeI32(hier->flags);
stream->writeI32(hier->maxInterpKeyFrameSize);
stream->writeI32(hier->currentAnim->maxInterpKeyFrameSize);
for(int32 i = 0; i < hier->numNodes; i++){
stream->writeI32(hier->nodeInfo[i].id);
stream->writeI32(hier->nodeInfo[i].index);
@ -217,9 +259,9 @@ hAnimFrameRead(Stream *stream, Animation *anim)
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
for(int32 i = 0; i < anim->numFrames; i++){
frames[i].time = stream->readF32();
stream->read(frames[i].q, 4*4);
stream->read(frames[i].t, 3*4);
int32 prev = stream->readI32();
stream->read(&frames[i].q, 4*4);
stream->read(&frames[i].t, 3*4);
int32 prev = stream->readI32()/0x24;
frames[i].prev = &frames[prev];
}
}
@ -230,9 +272,9 @@ hAnimFrameWrite(Stream *stream, Animation *anim)
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
for(int32 i = 0; i < anim->numFrames; i++){
stream->writeF32(frames[i].time);
stream->write(frames[i].q, 4*4);
stream->write(frames[i].t, 3*4);
stream->writeI32(frames[i].prev - frames);
stream->write(&frames[i].q, 4*4);
stream->write(&frames[i].t, 3*4);
stream->writeI32((frames[i].prev - frames)*0x24);
}
}
@ -242,6 +284,31 @@ hAnimFrameGetSize(Animation *anim)
return anim->numFrames*(4 + 4*4 + 3*4 + 4);
}
//void hanimBlendCB(void *out, void *in1, void *in2, float32 a);
//void hanimAddCB(void *out, void *in1, void *in2);
//void hanimMulRecipCB(void *frame, void *start);
static void
hanimApplyCB(void *result, void *frame)
{
Matrix *m = (Matrix*)result;
HAnimInterpFrame *f = (HAnimInterpFrame*)frame;
*m = Matrix::makeRotation(f->q);
m->pos = f->t;
}
static void
hanimInterpCB(void *vout, void *vin1, void *vin2, float32 t, void*)
{
HAnimInterpFrame *out = (HAnimInterpFrame*)vout;
HAnimKeyFrame *in1 = (HAnimKeyFrame*)vin1;
HAnimKeyFrame *in2 = (HAnimKeyFrame*)vin2;
assert(t >= in1->time && t <= in2->time);
float32 a = (t - in1->time)/(in2->time - in1->time);
out->t = lerp(in1->t, in2->t, a);
out->q = slerp(in1->q, in2->q, a);
}
void
registerHAnimPlugin(void)
{
@ -255,12 +322,18 @@ registerHAnimPlugin(void)
AnimInterpolatorInfo *info = new AnimInterpolatorInfo;
info->id = 1;
info->keyFrameSize = sizeof(HAnimKeyFrame);
info->customDataSize = sizeof(HAnimKeyFrame);
info->interpKeyFrameSize = sizeof(HAnimInterpFrame);
info->animKeyFrameSize = sizeof(HAnimKeyFrame);
info->customDataSize = 0;
info->applyCB = hanimApplyCB;
info->blendCB = nil;
info->interpCB = hanimInterpCB;
info->addCB = nil;
info->mulRecipCB = nil;
info->streamRead = hAnimFrameRead;
info->streamWrite = hAnimFrameWrite;
info->streamGetSize = hAnimFrameGetSize;
registerAnimInterpolatorInfo(info);
AnimInterpolatorInfo::registerInterp(info);
}
}

View File

@ -9,6 +9,7 @@
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwengine.h"
#include "rwanim.h"
#include "rwplugins.h"
#include "ps2/rwps2.h"
#include "ps2/rwps2plg.h"

View File

@ -51,6 +51,19 @@ findMinVertAndNumVertices(uint16 *indices, uint32 numIndices, uint32 *minVert, i
*numVertices = max - min + 1;
}
void
instV4d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride)
{
if(type == VERT_FLOAT4)
for(uint32 i = 0; i < numVertices; i++){
memcpy(dst, src, 16);
dst += stride;
src += 4;
}
else
assert(0 && "unsupported instV3d type");
}
void
instV3d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride)
{

View File

@ -7,6 +7,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwplugins.h"
#include "rwps2.h"
#include "rwps2plg.h"

View File

@ -9,6 +9,7 @@
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#include "../rwanim.h"
#include "../rwplugins.h"
#include "rwps2.h"
#include "rwps2plg.h"
@ -947,8 +948,8 @@ genericUninstanceCB(MatPipeline *pipe, Geometry *geo, uint32 flags[], Mesh *mesh
uint32 *weights = nil;
int8 *adc = nil;
Skin *skin = nil;
if(skinGlobals.offset)
skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
if(skinGlobals.geoOffset)
skin = Skin::get(geo);
PipeAttribute *a;
for(int32 i = 0; i < nelem(pipe->attribs); i++)

View File

@ -8,6 +8,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#include "rwps2.h"

View File

@ -8,6 +8,7 @@
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwanim.h"
#include "../rwengine.h"
#include "../rwplugins.h"
#include "rwps2.h"
@ -183,7 +184,7 @@ instanceSkinData(Geometry*, Mesh *m, Skin *skin, uint32 *data)
void
skinInstanceCB(MatPipeline *, Geometry *g, Mesh *m, uint8 **data)
{
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
Skin *skin = Skin::get(g);
if(skin == nil)
return;
instanceSkinData(g, m, skin, (uint32*)data[4]);
@ -193,7 +194,7 @@ skinInstanceCB(MatPipeline *, Geometry *g, Mesh *m, uint8 **data)
int32
findVertexSkin(Geometry *g, uint32 flags[], uint32 mask, Vertex *v)
{
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
Skin *skin = Skin::get(g);
float32 *wghts = nil;
uint8 *inds = nil;
if(skin){
@ -245,7 +246,7 @@ findVertexSkin(Geometry *g, uint32 flags[], uint32 mask, Vertex *v)
void
insertVertexSkin(Geometry *geo, int32 i, uint32 mask, Vertex *v)
{
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
Skin *skin = Skin::get(geo);
insertVertex(geo, i, mask, v);
if(mask & 0x10000){
memcpy(&skin->weights[i*4], v->w, 16);
@ -308,7 +309,7 @@ skinUninstanceCB(MatPipeline*, Geometry *geo, uint32 flags[], Mesh *mesh, uint8
void
skinPreCB(MatPipeline*, Geometry *geo)
{
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
Skin *skin = Skin::get(geo);
if(skin == nil)
return;
uint8 *data = skin->data;
@ -322,7 +323,7 @@ skinPreCB(MatPipeline*, Geometry *geo)
void
skinPostCB(MatPipeline*, Geometry *geo)
{
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
Skin *skin = Skin::get(geo);
if(skin){
skin->findNumWeights(geo->numVertices);
skin->findUsedBones(geo->numVertices);

174
src/rwanim.h Normal file
View File

@ -0,0 +1,174 @@
#include <stddef.h>
namespace rw {
struct Animation;
// These sizes of these are sadly not platform independent
// because pointer sizes can vary.
struct KeyFrameHeader
{
KeyFrameHeader *prev;
float32 time;
KeyFrameHeader *next(int32 sz){
return (KeyFrameHeader*)((uint8*)this + sz); }
};
struct InterpFrameHeader
{
KeyFrameHeader *keyFrame1;
KeyFrameHeader *keyFrame2;
};
struct AnimInterpolatorInfo
{
typedef void (*ApplyCB)(void *result, void *frame);
typedef void (*BlendCB)(void *out, void *in1, void *in2, float32 a);
typedef void (*InterpCB)(void *out, void *in1, void *in2, float32 t,
void *custom);
typedef void (*AddCB)(void *out, void *in1, void *in2);
typedef void (*MulRecipCB)(void *frame, void *start);
int32 id;
int32 interpKeyFrameSize;
int32 animKeyFrameSize;
int32 customDataSize;
ApplyCB applyCB;
BlendCB blendCB;
InterpCB interpCB;
AddCB addCB;
MulRecipCB mulRecipCB;
void (*streamRead)(Stream *stream, Animation *anim);
void (*streamWrite)(Stream *stream, Animation *anim);
uint32 (*streamGetSize)(Animation *anim);
static void registerInterp(AnimInterpolatorInfo *interpInfo);
static AnimInterpolatorInfo *find(int32 id);
};
struct Animation
{
AnimInterpolatorInfo *interpInfo;
int32 numFrames;
int32 flags;
float32 duration;
void *keyframes;
void *customData;
static Animation *create(AnimInterpolatorInfo*, int32 numFrames,
int32 flags, float duration);
void destroy(void);
int32 getNumNodes(void);
static Animation *streamRead(Stream *stream);
static Animation *streamReadLegacy(Stream *stream);
bool streamWrite(Stream *stream);
bool streamWriteLegacy(Stream *stream);
uint32 streamGetSize(void);
};
struct AnimInterpolator
{
Animation *currentAnim;
float32 currentTime;
void *nextFrame;
int32 maxInterpKeyFrameSize;
int32 currentInterpKeyFrameSize;
int32 currentAnimKeyFrameSize;
int32 numNodes;
// TODO some callbacks, parent/sub
// cached from the InterpolatorInfo
AnimInterpolatorInfo::ApplyCB applyCB;
AnimInterpolatorInfo::BlendCB blendCB;
AnimInterpolatorInfo::InterpCB interpCB;
AnimInterpolatorInfo::AddCB addCB;
// after this interpolated frames
static AnimInterpolator *create(int32 numNodes, int32 maxKeyFrameSize);
void destroy(void);
bool32 setCurrentAnim(Animation *anim);
void addTime(float32 t);
void *getFrames(void){ return this+1;}
InterpFrameHeader *getInterpFrame(int32 n){
return (InterpFrameHeader*)((uint8*)getFrames() +
n*currentInterpKeyFrameSize);
}
KeyFrameHeader *getAnimFrame(int32 n){
return (KeyFrameHeader*)((uint8*)currentAnim->keyframes +
n*currentAnimKeyFrameSize);
}
};
//
// UV anim
//
struct UVAnimKeyFrame
{
UVAnimKeyFrame *prev;
float32 time;
float32 uv[6];
};
struct UVAnimInterpFrame
{
UVAnimKeyFrame *keyFrame1;
UVAnimKeyFrame *keyFrame2;
float32 uv[6];
};
struct UVAnimDictionary;
// RW does it differently...maybe we should implement RtDict
// and make it more general?
struct UVAnimCustomData
{
char name[32];
int32 nodeToUVChannel[8];
int32 refCount;
void destroy(Animation *anim);
static UVAnimCustomData *get(Animation *anim){
return (UVAnimCustomData*)anim->customData; }
};
// This should be more general probably
struct UVAnimDictEntry
{
Animation *anim;
LLLink inDict;
static UVAnimDictEntry *fromDict(LLLink *lnk){
return LLLinkGetData(lnk, UVAnimDictEntry, inDict); }
};
// This too
struct UVAnimDictionary
{
LinkList animations;
static UVAnimDictionary *create(void);
void destroy(void);
int32 count(void) { return this->animations.count(); }
void add(Animation *anim);
Animation *find(const char *name);
static UVAnimDictionary *streamRead(Stream *stream);
bool streamWrite(Stream *stream);
uint32 streamGetSize(void);
};
extern UVAnimDictionary *currentUVAnimDictionary;
struct UVAnim
{
AnimInterpolator *interp[8];
};
extern int32 uvAnimOffset;
void registerUVAnimPlugin(void);
}

View File

@ -112,14 +112,20 @@ inline V3d normalize(const V3d &v) { return scale(v, 1.0f/length(v)); }
inline V3d setlength(const V3d &v, float32 l) { return scale(v, l/length(v)); }
V3d cross(const V3d &a, const V3d &b);
inline float32 dot(const V3d &a, const V3d &b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
inline V3d lerp(const V3d &a, const V3d &b, float32 r){
return V3d(a.x + r*(b.x - a.x),
a.y + r*(b.y - a.y),
a.z + r*(b.z - a.z));
};
struct Quat
{
float32 w, x, y, z;
Quat(void) : w(0.0f), x(0.0f), y(0.0f), z(0.0f) {}
Quat(float32 w, float32 x, float32 y, float32 z) : w(w), x(x), y(y), z(z) {}
Quat(float32 w, V3d vec) : w(w), x(vec.x), y(vec.y), z(vec.z) {}
Quat(V3d vec) : w(0.0f), x(vec.x), y(vec.y), z(vec.z) {}
// order is important for streaming
float32 x, y, z, w;
Quat(void) : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
Quat(float32 w, float32 x, float32 y, float32 z) : x(x), y(y), z(z), w(w) {}
Quat(float32 w, V3d vec) : x(vec.x), y(vec.y), z(vec.z), w(w) {}
Quat(V3d vec) : x(vec.x), y(vec.y), z(vec.z), w(0.0f) {}
static Quat rotation(float32 angle, const V3d &axis){
return Quat(cos(angle/2.0f), scale(axis, sin(angle/2.0f))); }
void set(float32 w, float32 x, float32 y, float32 z){
@ -129,12 +135,17 @@ struct Quat
inline Quat add(const Quat &q, const Quat &p) { return Quat(q.w+p.w, q.x+p.x, q.y+p.y, q.z+p.z); }
inline Quat sub(const Quat &q, const Quat &p) { return Quat(q.w-p.w, q.x-p.x, q.y-p.y, q.z-p.z); }
inline Quat negate(const Quat &q) { return Quat(-q.w, -q.x, -q.y, -q.z); }
inline float32 dot(const Quat &q, const Quat &p) { return q.w*p.w + q.x*p.x + q.y*p.y + q.z*p.z; }
inline Quat scale(const Quat &q, float32 r) { return Quat(q.w*r, q.x*r, q.y*r, q.z*r); }
inline float32 length(const Quat &q) { return sqrt(q.w*q.w + q.x*q.x + q.y*q.y + q.z*q.z); }
inline Quat normalize(const Quat &q) { return scale(q, 1.0f/length(q)); }
inline Quat conj(const Quat &q) { return Quat(q.w, -q.x, -q.y, -q.z); }
Quat mult(const Quat &q, const Quat &p);
inline V3d rotate(const V3d &v, const Quat &q) { return mult(mult(q, Quat(v)), conj(q)).vec(); }
Quat lerp(const Quat &q, const Quat &p, float32 r);
Quat slerp(const Quat &q, const Quat &p, float32 a);
struct Matrix
{

View File

@ -641,102 +641,4 @@ struct TexDictionary : PluginBase<TexDictionary>
extern TexDictionary *currentTexDictionary;
struct Animation;
struct AnimInterpolatorInfo
{
int32 id;
int32 keyFrameSize;
int32 customDataSize;
void (*streamRead)(Stream *stream, Animation *anim);
void (*streamWrite)(Stream *stream, Animation *anim);
uint32 (*streamGetSize)(Animation *anim);
};
void registerAnimInterpolatorInfo(AnimInterpolatorInfo *interpInfo);
AnimInterpolatorInfo *findAnimInterpolatorInfo(int32 id);
struct Animation
{
AnimInterpolatorInfo *interpInfo;
int32 numFrames;
int32 flags;
float duration;
void *keyframes;
void *customData;
static Animation *create(AnimInterpolatorInfo*, int32 numFrames, int32 flags, float duration);
void destroy(void);
static Animation *streamRead(Stream *stream);
static Animation *streamReadLegacy(Stream *stream);
bool streamWrite(Stream *stream);
bool streamWriteLegacy(Stream *stream);
uint32 streamGetSize(void);
};
struct AnimInterpolator
{
// only a stub right now
Animation *anim;
AnimInterpolator(Animation *anim);
};
struct UVAnimKeyFrame
{
UVAnimKeyFrame *prev;
float time;
float uv[6];
};
struct UVAnimDictionary;
// RW does it differently...maybe we should implement RtDict
// and make it more general?
struct UVAnimCustomData
{
char name[32];
int32 nodeToUVChannel[8];
int32 refCount;
void destroy(Animation *anim);
};
// This should be more general probably
struct UVAnimDictEntry
{
Animation *anim;
LLLink inDict;
static UVAnimDictEntry *fromDict(LLLink *lnk){
return LLLinkGetData(lnk, UVAnimDictEntry, inDict); }
};
// This too
struct UVAnimDictionary
{
LinkList animations;
static UVAnimDictionary *create(void);
void destroy(void);
int32 count(void) { return this->animations.count(); }
void add(Animation *anim);
Animation *find(const char *name);
static UVAnimDictionary *streamRead(Stream *stream);
bool streamWrite(Stream *stream);
uint32 streamGetSize(void);
};
extern UVAnimDictionary *currentUVAnimDictionary;
struct UVAnim
{
AnimInterpolator *interp[8];
};
extern int32 uvAnimOffset;
void registerUVAnimPlugin(void);
}

View File

@ -41,11 +41,13 @@ enum {
VERT_NORMSHORT3,
VERT_FLOAT2,
VERT_FLOAT3,
VERT_FLOAT4,
VERT_ARGB,
VERT_RGBA,
VERT_COMPNORM
};
void instV4d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride);
void instV3d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride);
void uninstV3d(int type, float *dst, uint8 *src, uint32 numVertices, uint32 stride);
void instV2d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride);

View File

@ -7,9 +7,17 @@ namespace rw {
struct HAnimKeyFrame
{
HAnimKeyFrame *prev;
float time;
float q[4];
float t[3];
float32 time;
Quat q;
V3d t;
};
struct HAnimInterpFrame
{
HAnimKeyFrame *keyFrame1;
HAnimKeyFrame *keyFrame2;
Quat q;
V3d t;
};
struct HAnimNodeInfo
@ -24,24 +32,34 @@ struct HAnimHierarchy
{
int32 flags;
int32 numNodes;
float *matrices;
float *matricesUnaligned;
Matrix *matrices;
void *matricesUnaligned;
HAnimNodeInfo *nodeInfo;
Frame *parentFrame;
HAnimHierarchy *parentHierarchy; // mostly unused
AnimInterpolator *currentAnim;
// temporary
int32 maxInterpKeyFrameSize;
static HAnimHierarchy *create(int32 numNodes, int32 *nodeFlags, int32 *nodeIDs, int32 flags, int32 maxKeySize);
static HAnimHierarchy *create(int32 numNodes, int32 *nodeFlags,
int32 *nodeIDs, int32 flags, int32 maxKeySize);
void destroy(void);
void attachByIndex(int32 id);
void attach(void);
int32 getIndex(int32 id);
void updateMatrices(void);
static HAnimHierarchy *get(Frame *f);
static HAnimHierarchy *get(Clump *c){
return find(c->getFrame()); }
static HAnimHierarchy *find(Frame *f);
enum Flags {
SUBHIERARCHY = 0x1,
NOMATRICES = 0x2,
UPDATEMODELLINGMATRICES = 0x1000,
UPDATELTMS = 0x2000,
LOCALSPACEMATRICES = 0x4000
};
enum NodeFlag {
POP = 1,
PUSH
@ -138,6 +156,14 @@ void registerMatFXPlugin(void);
* Skin
*/
struct SkinGlobals
{
int32 geoOffset;
int32 atomicOffset;
ObjPipeline *pipelines[NUM_PLATFORMS];
};
extern SkinGlobals skinGlobals;
struct Skin
{
int32 numBones;
@ -173,15 +199,21 @@ struct Skin
void init(int32 numBones, int32 numUsedBones, int32 numVertices);
void findNumWeights(int32 numVertices);
void findUsedBones(int32 numVertices);
static void setPipeline(Atomic *a, int32 type);
static Skin *get(Geometry *geo){
return *PLUGINOFFSET(Skin*, geo, skinGlobals.geoOffset);
}
static void setHierarchy(Atomic *atomic, HAnimHierarchy *hier){
*PLUGINOFFSET(HAnimHierarchy*, atomic,
skinGlobals.atomicOffset) = hier;
}
static HAnimHierarchy *getHierarchy(Atomic *atomic){
return *PLUGINOFFSET(HAnimHierarchy*, atomic,
skinGlobals.atomicOffset);
}
};
struct SkinGlobals
{
int32 offset;
ObjPipeline *pipelines[NUM_PLATFORMS];
};
extern SkinGlobals skinGlobals;
Stream *readSkinSplitData(Stream *stream, Skin *skin);
Stream *writeSkinSplitData(Stream *stream, Skin *skin);
int32 skinSplitDataSize(Skin *skin);

View File

@ -8,6 +8,7 @@
#include "rwplg.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwanim.h"
#include "rwengine.h"
#include "rwplugins.h"
#include "ps2/rwps2.h"
@ -23,7 +24,7 @@
namespace rw {
SkinGlobals skinGlobals = { 0, { nil } };
SkinGlobals skinGlobals = { 0, 0, { nil } };
static void*
createSkin(void *object, int32 offset, int32)
@ -257,6 +258,26 @@ skinRights(void *object, int32, int32, uint32)
Skin::setPipeline((Atomic*)object, 1);
}
static void*
createSkinAtm(void *object, int32 offset, int32)
{
*PLUGINOFFSET(void*, object, offset) = nil;
return object;
}
static void*
destroySkinAtm(void *object, int32 offset, int32)
{
return object;
}
static void*
copySkinAtm(void *dst, void *src, int32 offset, int32)
{
*PLUGINOFFSET(void*, dst, offset) = *PLUGINOFFSET(void*, src, offset);
return dst;
}
void
registerSkinPlugin(void)
{
@ -274,13 +295,15 @@ registerSkinPlugin(void)
wdgl::initSkin();
gl3::initSkin();
skinGlobals.offset = Geometry::registerPlugin(sizeof(Skin*), ID_SKIN,
createSkin,
destroySkin,
copySkin);
int32 o;
o = Geometry::registerPlugin(sizeof(Skin*), ID_SKIN,
createSkin, destroySkin, copySkin);
Geometry::registerPluginStream(ID_SKIN,
readSkin, writeSkin, getSizeSkin);
Atomic::registerPlugin(0, ID_SKIN, nil, nil, nil);
skinGlobals.geoOffset = o;
o = Atomic::registerPlugin(sizeof(HAnimHierarchy*),ID_SKIN,
createSkinAtm, destroySkinAtm, copySkinAtm);
skinGlobals.atomicOffset = o;
Atomic::setStreamRightsCallback(ID_SKIN, skinRights);
}

350
src/uvanim.cpp Normal file
View File

@ -0,0 +1,350 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include "rwbase.h"
#include "rwerror.h"
#include "rwplg.h"
#include "rwpipeline.h"
#include "rwobjects.h"
#include "rwanim.h"
#include "rwplugins.h"
#define PLUGIN_ID ID_UVANIMATION
namespace rw {
//
// UVAnim
//
void
UVAnimCustomData::destroy(Animation *anim)
{
this->refCount--;
if(this->refCount <= 0)
anim->destroy();
}
UVAnimDictionary *currentUVAnimDictionary;
UVAnimDictionary*
UVAnimDictionary::create(void)
{
UVAnimDictionary *dict = (UVAnimDictionary*)malloc(sizeof(UVAnimDictionary));
if(dict == nil){
RWERROR((ERR_ALLOC, sizeof(UVAnimDictionary)));
return nil;
}
dict->animations.init();
return dict;
}
void
UVAnimDictionary::destroy(void)
{
FORLIST(lnk, this->animations){
UVAnimDictEntry *de = UVAnimDictEntry::fromDict(lnk);
UVAnimCustomData *cust = UVAnimCustomData::get(de->anim);
cust->destroy(de->anim);
delete de;
}
free(this);
}
void
UVAnimDictionary::add(Animation *anim)
{
UVAnimDictEntry *de = new UVAnimDictEntry;
de->anim = anim;
this->animations.append(&de->inDict);
}
UVAnimDictionary*
UVAnimDictionary::streamRead(Stream *stream)
{
if(!findChunk(stream, ID_STRUCT, nil, nil)){
RWERROR((ERR_CHUNK, "STRUCT"));
return nil;
}
UVAnimDictionary *dict = UVAnimDictionary::create();
if(dict == nil)
return nil;
int32 numAnims = stream->readI32();
Animation *anim;
for(int32 i = 0; i < numAnims; i++){
if(!findChunk(stream, ID_ANIMANIMATION, nil, nil)){
RWERROR((ERR_CHUNK, "ANIMANIMATION"));
goto fail;
}
anim = Animation::streamRead(stream);
if(anim == nil)
goto fail;
dict->add(anim);
}
return dict;
fail:
dict->destroy();
return nil;
}
bool
UVAnimDictionary::streamWrite(Stream *stream)
{
uint32 size = this->streamGetSize();
writeChunkHeader(stream, ID_UVANIMDICT, size);
writeChunkHeader(stream, ID_STRUCT, 4);
int32 numAnims = this->count();
stream->writeI32(numAnims);
FORLIST(lnk, this->animations){
UVAnimDictEntry *de = UVAnimDictEntry::fromDict(lnk);
de->anim->streamWrite(stream);
}
return true;
}
uint32
UVAnimDictionary::streamGetSize(void)
{
uint32 size = 12 + 4;
FORLIST(lnk, this->animations){
UVAnimDictEntry *de = UVAnimDictEntry::fromDict(lnk);
size += 12 + de->anim->streamGetSize();
}
return size;
}
Animation*
UVAnimDictionary::find(const char *name)
{
FORLIST(lnk, this->animations){
Animation *anim = UVAnimDictEntry::fromDict(lnk)->anim;
UVAnimCustomData *custom = UVAnimCustomData::get(anim);
if(strncmp_ci(custom->name, name, 32) == 0)
return anim;
}
return nil;
}
static void
uvAnimStreamRead(Stream *stream, Animation *anim)
{
UVAnimCustomData *custom = UVAnimCustomData::get(anim);
UVAnimKeyFrame *frames = (UVAnimKeyFrame*)anim->keyframes;
stream->readI32();
stream->read(custom->name, 32);
stream->read(custom->nodeToUVChannel, 8*4);
custom->refCount = 1;
for(int32 i = 0; i < anim->numFrames; i++){
frames[i].time = stream->readF32();
stream->read(frames[i].uv, 6*4);
int32 prev = stream->readI32();
frames[i].prev = &frames[prev];
}
}
static void
uvAnimStreamWrite(Stream *stream, Animation *anim)
{
UVAnimCustomData *custom = UVAnimCustomData::get(anim);
UVAnimKeyFrame *frames = (UVAnimKeyFrame*)anim->keyframes;
stream->writeI32(0);
stream->write(custom->name, 32);
stream->write(custom->nodeToUVChannel, 8*4);
for(int32 i = 0; i < anim->numFrames; i++){
stream->writeF32(frames[i].time);
stream->write(frames[i].uv, 6*4);
stream->writeI32(frames[i].prev - frames);
}
}
static uint32
uvAnimStreamGetSize(Animation *anim)
{
return 4 + 32 + 8*4 + anim->numFrames*(4 + 6*4 + 4);
}
static void
registerUVAnimInterpolator(void)
{
// Linear
AnimInterpolatorInfo *info = new AnimInterpolatorInfo;
info->id = 0x1C0;
info->interpKeyFrameSize = sizeof(UVAnimInterpFrame);
info->animKeyFrameSize = sizeof(UVAnimKeyFrame);
info->customDataSize = sizeof(UVAnimCustomData);
info->applyCB = nil;
info->blendCB = nil;
info->interpCB = nil;
info->addCB = nil;
info->mulRecipCB = nil;
info->streamRead = uvAnimStreamRead;
info->streamWrite = uvAnimStreamWrite;
info->streamGetSize = uvAnimStreamGetSize;
AnimInterpolatorInfo::registerInterp(info);
// Param
info = new AnimInterpolatorInfo;
info->id = 0x1C1;
info->interpKeyFrameSize = sizeof(UVAnimInterpFrame);
info->animKeyFrameSize = sizeof(UVAnimKeyFrame);
info->customDataSize = sizeof(UVAnimCustomData);
info->applyCB = nil;
info->blendCB = nil;
info->interpCB = nil;
info->addCB = nil;
info->mulRecipCB = nil;
info->streamRead = uvAnimStreamRead;
info->streamWrite = uvAnimStreamWrite;
info->streamGetSize = uvAnimStreamGetSize;
AnimInterpolatorInfo::registerInterp(info);
}
int32 uvAnimOffset;
static void*
createUVAnim(void *object, int32 offset, int32)
{
UVAnim *uvanim;
uvanim = PLUGINOFFSET(UVAnim, object, offset);
memset(uvanim, 0, sizeof(*uvanim));
return object;
}
static void*
destroyUVAnim(void *object, int32 offset, int32)
{
UVAnim *uvanim;
uvanim = PLUGINOFFSET(UVAnim, object, offset);
for(int32 i = 0; i < 8; i++){
AnimInterpolator *ip = uvanim->interp[i];
if(ip){
UVAnimCustomData *custom =
UVAnimCustomData::get(ip->currentAnim);
custom->destroy(ip->currentAnim);
delete ip;
}
}
return object;
}
static void*
copyUVAnim(void *dst, void *src, int32 offset, int32)
{
UVAnim *srcuvanim, *dstuvanim;
dstuvanim = PLUGINOFFSET(UVAnim, dst, offset);
srcuvanim = PLUGINOFFSET(UVAnim, src, offset);
for(int32 i = 0; i < 8; i++){
AnimInterpolator *srcip = srcuvanim->interp[i];
AnimInterpolator *dstip;
if(srcip){
Animation *anim = srcip->currentAnim;
UVAnimCustomData *custom = UVAnimCustomData::get(anim);
dstip = AnimInterpolator::create(anim->getNumNodes(),
anim->interpInfo->interpKeyFrameSize);
dstip->setCurrentAnim(anim);
custom->refCount++;
dstuvanim->interp[i] = dstip;
}
}
return dst;
}
Animation*
makeDummyAnimation(const char *name)
{
AnimInterpolatorInfo *interpInfo = AnimInterpolatorInfo::find(0x1C0);
Animation *anim = Animation::create(interpInfo, 2, 0, 1.0f);
UVAnimCustomData *custom = UVAnimCustomData::get(anim);
strncpy(custom->name, name, 32);
memset(custom->nodeToUVChannel, 0, sizeof(custom->nodeToUVChannel));
custom->refCount = 1;
// TODO: init the frames
// UVAnimKeyFrame *frames = (UVAnimKeyFrame*)anim->keyframes;
return anim;
}
static Stream*
readUVAnim(Stream *stream, int32, void *object, int32 offset, int32)
{
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
if(!findChunk(stream, ID_STRUCT, nil, nil)){
RWERROR((ERR_CHUNK, "STRUCT"));
return nil;
}
char name[32];
uint32 mask = stream->readI32();
uint32 bit = 1;
for(int32 i = 0; i < 8; i++){
if(mask & bit){
stream->read(name, 32);
Animation *anim = nil;
if(currentUVAnimDictionary)
anim = currentUVAnimDictionary->find(name);
if(anim == nil){
anim = makeDummyAnimation(name);
if(currentUVAnimDictionary)
currentUVAnimDictionary->add(anim);
}
UVAnimCustomData *custom = UVAnimCustomData::get(anim);
AnimInterpolator *interp;
interp = AnimInterpolator::create(anim->getNumNodes(),
anim->interpInfo->interpKeyFrameSize);
interp->setCurrentAnim(anim);
custom->refCount++;
uvanim->interp[i] = interp;
}
bit <<= 1;
}
return stream;
}
static Stream*
writeUVAnim(Stream *stream, int32 size, void *object, int32 offset, int32)
{
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
writeChunkHeader(stream, ID_STRUCT, size-12);
uint32 mask = 0;
uint32 bit = 1;
for(int32 i = 0; i < 8; i++){
if(uvanim->interp[i])
mask |= bit;
bit <<= 1;
}
stream->writeI32(mask);
for(int32 i = 0; i < 8; i++){
if(uvanim->interp[i]){
UVAnimCustomData *custom =
UVAnimCustomData::get(uvanim->interp[i]->currentAnim);
stream->write(custom->name, 32);
}
}
return stream;
}
static int32
getSizeUVAnim(void *object, int32 offset, int32)
{
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
int32 size = 0;
for(int32 i = 0; i < 8; i++)
if(uvanim->interp[i])
size += 32;
return size ? size + 12 + 4 : 0;
}
void
registerUVAnimPlugin(void)
{
registerUVAnimInterpolator();
uvAnimOffset = Material::registerPlugin(sizeof(UVAnim), ID_UVANIMATION,
createUVAnim, destroyUVAnim, copyUVAnim);
Material::registerPluginStream(ID_UVANIMATION,
readUVAnim, writeUVAnim, getSizeUVAnim);
}
}