mirror of
https://github.com/aap/librw.git
synced 2025-05-12 03:14:13 +01:00
got animation, hanim and skinning basically working
This commit is contained in:
parent
b1e55a7784
commit
5dff69431e
1
rw.h
1
rw.h
@ -6,6 +6,7 @@
|
|||||||
#include "src/rwplg.h"
|
#include "src/rwplg.h"
|
||||||
#include "src/rwpipeline.h"
|
#include "src/rwpipeline.h"
|
||||||
#include "src/rwobjects.h"
|
#include "src/rwobjects.h"
|
||||||
|
#include "src/rwanim.h"
|
||||||
#include "src/rwengine.h"
|
#include "src/rwengine.h"
|
||||||
#include "src/rwplugins.h"
|
#include "src/rwplugins.h"
|
||||||
#include "src/ps2/rwps2.h"
|
#include "src/ps2/rwps2.h"
|
||||||
|
438
src/anim.cpp
438
src/anim.cpp
@ -8,18 +8,23 @@
|
|||||||
#include "rwplg.h"
|
#include "rwplg.h"
|
||||||
#include "rwpipeline.h"
|
#include "rwpipeline.h"
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
|
#include "rwanim.h"
|
||||||
#include "rwplugins.h"
|
#include "rwplugins.h"
|
||||||
|
|
||||||
#define PLUGIN_ID 2 // ?
|
#define PLUGIN_ID 0
|
||||||
|
|
||||||
namespace rw {
|
namespace rw {
|
||||||
|
|
||||||
|
//
|
||||||
|
// AnimInterpolatorInfo
|
||||||
|
//
|
||||||
|
|
||||||
#define MAXINTERPINFO 10
|
#define MAXINTERPINFO 10
|
||||||
|
|
||||||
static AnimInterpolatorInfo *interpInfoList[MAXINTERPINFO];
|
static AnimInterpolatorInfo *interpInfoList[MAXINTERPINFO];
|
||||||
|
|
||||||
void
|
void
|
||||||
registerAnimInterpolatorInfo(AnimInterpolatorInfo *interpInfo)
|
AnimInterpolatorInfo::registerInterp(AnimInterpolatorInfo *interpInfo)
|
||||||
{
|
{
|
||||||
for(int32 i = 0; i < MAXINTERPINFO; i++)
|
for(int32 i = 0; i < MAXINTERPINFO; i++)
|
||||||
if(interpInfoList[i] == nil){
|
if(interpInfoList[i] == nil){
|
||||||
@ -30,7 +35,7 @@ registerAnimInterpolatorInfo(AnimInterpolatorInfo *interpInfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnimInterpolatorInfo*
|
AnimInterpolatorInfo*
|
||||||
findAnimInterpolatorInfo(int32 id)
|
AnimInterpolatorInfo::find(int32 id)
|
||||||
{
|
{
|
||||||
for(int32 i = 0; i < MAXINTERPINFO; i++){
|
for(int32 i = 0; i < MAXINTERPINFO; i++){
|
||||||
if(interpInfoList[i] && interpInfoList[i]->id == id)
|
if(interpInfoList[i] && interpInfoList[i]->id == id)
|
||||||
@ -39,17 +44,30 @@ findAnimInterpolatorInfo(int32 id)
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Animation
|
||||||
|
//
|
||||||
|
|
||||||
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->interpInfo = interpInfo;
|
||||||
anim->numFrames = numFrames;
|
anim->numFrames = numFrames;
|
||||||
anim->flags = flags;
|
anim->flags = flags;
|
||||||
anim->duration = duration;
|
anim->duration = duration;
|
||||||
uint8 *data = new uint8[anim->numFrames*interpInfo->keyFrameSize + interpInfo->customDataSize];
|
|
||||||
anim->keyframes = data;
|
anim->keyframes = data;
|
||||||
data += anim->numFrames*interpInfo->keyFrameSize;
|
data += anim->numFrames*interpInfo->animKeyFrameSize;
|
||||||
anim->customData = data;
|
anim->customData = data;
|
||||||
return anim;
|
return anim;
|
||||||
}
|
}
|
||||||
@ -57,11 +75,20 @@ Animation::create(AnimInterpolatorInfo *interpInfo, int32 numFrames, int32 flags
|
|||||||
void
|
void
|
||||||
Animation::destroy(void)
|
Animation::destroy(void)
|
||||||
{
|
{
|
||||||
uint8 *c = (uint8*)this->keyframes;
|
|
||||||
delete[] c;
|
|
||||||
free(this);
|
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*
|
||||||
Animation::streamRead(Stream *stream)
|
Animation::streamRead(Stream *stream)
|
||||||
{
|
{
|
||||||
@ -69,7 +96,7 @@ Animation::streamRead(Stream *stream)
|
|||||||
if(stream->readI32() != 0x100)
|
if(stream->readI32() != 0x100)
|
||||||
return nil;
|
return nil;
|
||||||
int32 typeID = stream->readI32();
|
int32 typeID = stream->readI32();
|
||||||
AnimInterpolatorInfo *interpInfo = findAnimInterpolatorInfo(typeID);
|
AnimInterpolatorInfo *interpInfo = AnimInterpolatorInfo::find(typeID);
|
||||||
int32 numFrames = stream->readI32();
|
int32 numFrames = stream->readI32();
|
||||||
int32 flags = stream->readI32();
|
int32 flags = stream->readI32();
|
||||||
float duration = stream->readF32();
|
float duration = stream->readF32();
|
||||||
@ -82,15 +109,15 @@ Animation*
|
|||||||
Animation::streamReadLegacy(Stream *stream)
|
Animation::streamReadLegacy(Stream *stream)
|
||||||
{
|
{
|
||||||
Animation *anim;
|
Animation *anim;
|
||||||
AnimInterpolatorInfo *interpInfo = findAnimInterpolatorInfo(1);
|
AnimInterpolatorInfo *interpInfo = AnimInterpolatorInfo::find(1);
|
||||||
int32 numFrames = stream->readI32();
|
int32 numFrames = stream->readI32();
|
||||||
int32 flags = stream->readI32();
|
int32 flags = stream->readI32();
|
||||||
float duration = stream->readF32();
|
float duration = stream->readF32();
|
||||||
anim = Animation::create(interpInfo, numFrames, flags, duration);
|
anim = Animation::create(interpInfo, numFrames, flags, duration);
|
||||||
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
||||||
for(int32 i = 0; i < anim->numFrames; i++){
|
for(int32 i = 0; i < anim->numFrames; i++){
|
||||||
stream->read(frames[i].q, 4*4);
|
stream->read(&frames[i].q, 4*4);
|
||||||
stream->read(frames[i].t, 3*4);
|
stream->read(&frames[i].t, 3*4);
|
||||||
frames[i].time = stream->readF32();
|
frames[i].time = stream->readF32();
|
||||||
int32 prev = stream->readI32();
|
int32 prev = stream->readI32();
|
||||||
frames[i].prev = &frames[prev];
|
frames[i].prev = &frames[prev];
|
||||||
@ -120,8 +147,8 @@ Animation::streamWriteLegacy(Stream *stream)
|
|||||||
assert(interpInfo->id == 1);
|
assert(interpInfo->id == 1);
|
||||||
HAnimKeyFrame *frames = (HAnimKeyFrame*)this->keyframes;
|
HAnimKeyFrame *frames = (HAnimKeyFrame*)this->keyframes;
|
||||||
for(int32 i = 0; i < this->numFrames; i++){
|
for(int32 i = 0; i < this->numFrames; i++){
|
||||||
stream->write(frames[i].q, 4*4);
|
stream->write(&frames[i].q, 4*4);
|
||||||
stream->write(frames[i].t, 3*4);
|
stream->write(&frames[i].t, 3*4);
|
||||||
stream->writeF32(frames[i].time);
|
stream->writeF32(frames[i].time);
|
||||||
stream->writeI32(frames[i].prev - frames);
|
stream->writeI32(frames[i].prev - frames);
|
||||||
}
|
}
|
||||||
@ -136,321 +163,114 @@ Animation::streamGetSize(void)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimInterpolator::AnimInterpolator(Animation *anim)
|
|
||||||
{
|
|
||||||
this->anim = anim;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// UVAnim
|
// AnimInterpolator
|
||||||
//
|
//
|
||||||
|
|
||||||
void
|
AnimInterpolator*
|
||||||
UVAnimCustomData::destroy(Animation *anim)
|
AnimInterpolator::create(int32 numNodes, int32 maxFrameSize)
|
||||||
{
|
{
|
||||||
this->refCount--;
|
AnimInterpolator *interp;
|
||||||
if(this->refCount <= 0)
|
int32 sz;
|
||||||
anim->destroy();
|
int32 realsz = maxFrameSize;
|
||||||
}
|
|
||||||
|
|
||||||
UVAnimDictionary *currentUVAnimDictionary;
|
// Add some space for pointers and padding, hopefully this will
|
||||||
|
// enough. Don't change maxFrameSize not to mess up streaming.
|
||||||
UVAnimDictionary*
|
if(sizeof(void*) > 4)
|
||||||
UVAnimDictionary::create(void)
|
realsz += 16;
|
||||||
{
|
sz = sizeof(AnimInterpolator) + numNodes*realsz;
|
||||||
UVAnimDictionary *dict = (UVAnimDictionary*)malloc(sizeof(UVAnimDictionary));
|
interp = (AnimInterpolator*)malloc(sz);
|
||||||
if(dict == nil){
|
if(interp == nil){
|
||||||
RWERROR((ERR_ALLOC, sizeof(UVAnimDictionary)));
|
RWERROR((ERR_ALLOC, sz));
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
dict->animations.init();
|
interp->currentAnim = nil;
|
||||||
return dict;
|
interp->currentTime = 0.0f;
|
||||||
|
interp->nextFrame = nil;
|
||||||
|
interp->maxInterpKeyFrameSize = maxFrameSize;
|
||||||
|
interp->currentInterpKeyFrameSize = maxFrameSize;
|
||||||
|
interp->currentAnimKeyFrameSize = -1;
|
||||||
|
interp->numNodes = numNodes;;
|
||||||
|
|
||||||
|
return interp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool32
|
||||||
UVAnimDictionary::add(Animation *anim)
|
AnimInterpolator::setCurrentAnim(Animation *anim)
|
||||||
{
|
{
|
||||||
UVAnimDictEntry *de = new UVAnimDictEntry;
|
int32 i;
|
||||||
de->anim = anim;
|
AnimInterpolatorInfo *interpInfo = anim->interpInfo;
|
||||||
this->animations.append(&de->inDict);
|
this->currentAnim = anim;
|
||||||
}
|
this->currentTime = 0.0f;
|
||||||
|
int32 maxkf = this->maxInterpKeyFrameSize;
|
||||||
UVAnimDictionary*
|
if(sizeof(void*) > 4) // see above in create()
|
||||||
UVAnimDictionary::streamRead(Stream *stream)
|
maxkf += 16;
|
||||||
{
|
if(interpInfo->interpKeyFrameSize > maxkf){
|
||||||
if(!findChunk(stream, ID_STRUCT, nil, nil)){
|
RWERROR((ERR_GENERAL, "interpolation frame too big"));
|
||||||
RWERROR((ERR_CHUNK, "STRUCT"));
|
return 0;
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
UVAnimDictionary *dict = UVAnimDictionary::create();
|
this->currentInterpKeyFrameSize = interpInfo->interpKeyFrameSize;
|
||||||
if(dict == nil)
|
this->currentAnimKeyFrameSize = interpInfo->animKeyFrameSize;
|
||||||
return nil;
|
this->applyCB = interpInfo->applyCB;
|
||||||
int32 numAnims = stream->readI32();
|
this->blendCB = interpInfo->blendCB;
|
||||||
Animation *anim;
|
this->interpCB = interpInfo->interpCB;
|
||||||
for(int32 i = 0; i < numAnims; i++){
|
this->addCB = interpInfo->addCB;
|
||||||
if(!findChunk(stream, ID_ANIMANIMATION, nil, nil)){
|
for(i = 0; i < numNodes; i++){
|
||||||
RWERROR((ERR_CHUNK, "ANIMANIMATION"));
|
InterpFrameHeader *intf;
|
||||||
goto fail;
|
KeyFrameHeader *kf1, *kf2;
|
||||||
}
|
intf = this->getInterpFrame(i);
|
||||||
anim = Animation::streamRead(stream);
|
kf1 = this->getAnimFrame(i);
|
||||||
if(anim == nil)
|
kf2 = this->getAnimFrame(i+numNodes);
|
||||||
goto fail;
|
intf->keyFrame1 = kf1;
|
||||||
dict->add(anim);
|
intf->keyFrame2 = kf2;
|
||||||
|
this->interpCB(intf, kf1, kf2, 0.0f, anim->customData);
|
||||||
}
|
}
|
||||||
return dict;
|
this->nextFrame = this->getAnimFrame(numNodes*2);
|
||||||
fail:
|
return 1;
|
||||||
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*)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
|
void
|
||||||
registerUVAnimPlugin(void)
|
AnimInterpolator::addTime(float32 t)
|
||||||
{
|
{
|
||||||
registerUVAnimInterpolator();
|
int32 i;
|
||||||
uvAnimOffset = Material::registerPlugin(sizeof(UVAnim), ID_UVANIMATION,
|
if(t <= 0.0f)
|
||||||
createUVAnim, destroyUVAnim, copyUVAnim);
|
return;
|
||||||
Material::registerPluginStream(ID_UVANIMATION, readUVAnim, writeUVAnim, getSizeUVAnim);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
70
src/base.cpp
70
src/base.cpp
@ -10,7 +10,6 @@
|
|||||||
#include "rwplg.h"
|
#include "rwplg.h"
|
||||||
#include "rwpipeline.h"
|
#include "rwpipeline.h"
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
#include "rwplugins.h"
|
|
||||||
#include "rwengine.h"
|
#include "rwengine.h"
|
||||||
|
|
||||||
namespace rw {
|
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);
|
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
|
V3d
|
||||||
cross(const V3d &a, const V3d &b)
|
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);
|
a.x*b.y - a.y*b.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* q must be normalized */
|
||||||
Matrix
|
Matrix
|
||||||
Matrix::makeRotation(const Quat &q)
|
Matrix::makeRotation(const Quat &q)
|
||||||
{
|
{
|
||||||
Matrix res;
|
Matrix res;
|
||||||
res.right.x = q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z;
|
float xx = q.x*q.x;
|
||||||
res.right.y = 2*q.w*q.z + 2*q.x*q.y;
|
float yy = q.y*q.y;
|
||||||
res.right.z = 2*q.x*q.z - 2*q.w*q.y;
|
float zz = q.z*q.z;
|
||||||
res.up.x = 2*q.x*q.y - 2*q.w*q.z;
|
float yz = q.y*q.z;
|
||||||
res.up.y = q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z;
|
float zx = q.z*q.x;
|
||||||
res.up.z = 2*q.w*q.x + 2*q.y*q.z;
|
float xy = q.x*q.y;
|
||||||
res.at.x = 2*q.w*q.y + 2*q.x*q.z;
|
float wx = q.w*q.x;
|
||||||
res.at.y = 2*q.y*q.z - 2*q.w*q.x;
|
float wy = q.w*q.y;
|
||||||
res.at.z = q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z;
|
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.rightw = res.upw = res.atw = 0.0f;
|
||||||
res.posw = 1.0f;
|
res.posw = 1.0f;
|
||||||
return res;
|
return res;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
ECODE(ERR_GENERAL,
|
ECODE(ERR_GENERAL,
|
||||||
"General Error")
|
"Error: %s")
|
||||||
ECODE(ERR_ALLOC,
|
ECODE(ERR_ALLOC,
|
||||||
"Couldn't allocate 0x%X bytes")
|
"Couldn't allocate 0x%X bytes")
|
||||||
ECODE(ERR_FILE,
|
ECODE(ERR_FILE,
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwd3d.h"
|
#include "rwd3d.h"
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwd3d.h"
|
#include "rwd3d.h"
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
|
||||||
#include "rwxbox.h"
|
#include "rwxbox.h"
|
||||||
|
|
||||||
#include "rwxboximpl.h"
|
#include "rwxboximpl.h"
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwxbox.h"
|
#include "rwxbox.h"
|
||||||
@ -115,7 +116,7 @@ skinInstanceCB(Geometry *geo, InstanceDataHeader *header)
|
|||||||
{
|
{
|
||||||
defaultInstanceCB(geo, header);
|
defaultInstanceCB(geo, header);
|
||||||
|
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
Skin *skin = Skin::get(geo);
|
||||||
if(skin == nil)
|
if(skin == nil)
|
||||||
return;
|
return;
|
||||||
NativeSkin *natskin = new NativeSkin;
|
NativeSkin *natskin = new NativeSkin;
|
||||||
@ -169,7 +170,7 @@ skinUninstanceCB(Geometry *geo, InstanceDataHeader *header)
|
|||||||
{
|
{
|
||||||
defaultUninstanceCB(geo, header);
|
defaultUninstanceCB(geo, header);
|
||||||
|
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
Skin *skin = Skin::get(geo);
|
||||||
if(skin == nil)
|
if(skin == nil)
|
||||||
return;
|
return;
|
||||||
NativeSkin *natskin = (NativeSkin*)skin->platformData;
|
NativeSkin *natskin = (NativeSkin*)skin->platformData;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "rwplg.h"
|
#include "rwplg.h"
|
||||||
#include "rwpipeline.h"
|
#include "rwpipeline.h"
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
|
#include "rwanim.h"
|
||||||
#include "rwplugins.h"
|
#include "rwplugins.h"
|
||||||
#include "ps2/rwps2.h"
|
#include "ps2/rwps2.h"
|
||||||
#include "ps2/rwps2plg.h"
|
#include "ps2/rwps2plg.h"
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
|
||||||
#ifdef RW_OPENGL
|
#ifdef RW_OPENGL
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
|
||||||
#ifdef RW_OPENGL
|
#ifdef RW_OPENGL
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include "rwgl3.h"
|
#include "rwgl3.h"
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
|
||||||
#ifdef RW_OPENGL
|
#ifdef RW_OPENGL
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#ifdef RW_OPENGL
|
#ifdef RW_OPENGL
|
||||||
@ -229,10 +230,13 @@ makeMatFXPipeline(void)
|
|||||||
|
|
||||||
// Skin
|
// Skin
|
||||||
|
|
||||||
|
Shader *skinShader;
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
skinOpen(void *o, int32, int32)
|
skinOpen(void *o, int32, int32)
|
||||||
{
|
{
|
||||||
skinGlobals.pipelines[PLATFORM_GL3] = makeSkinPipeline();
|
skinGlobals.pipelines[PLATFORM_GL3] = makeSkinPipeline();
|
||||||
|
skinShader = Shader::fromFiles("skin.vert", "simple.frag");
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,15 +251,250 @@ initSkin(void)
|
|||||||
{
|
{
|
||||||
Driver::registerPlugin(PLATFORM_GL3, 0, ID_SKIN,
|
Driver::registerPlugin(PLATFORM_GL3, 0, ID_SKIN,
|
||||||
skinOpen, skinClose);
|
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*
|
ObjPipeline*
|
||||||
makeSkinPipeline(void)
|
makeSkinPipeline(void)
|
||||||
{
|
{
|
||||||
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
|
ObjPipeline *pipe = new ObjPipeline(PLATFORM_GL3);
|
||||||
pipe->instanceCB = defaultInstanceCB;
|
pipe->instanceCB = skinInstanceCB;
|
||||||
pipe->uninstanceCB = defaultUninstanceCB;
|
pipe->uninstanceCB = skinUninstanceCB;
|
||||||
pipe->renderCB = defaultRenderCB;
|
pipe->renderCB = skinRenderCB;
|
||||||
pipe->pluginID = ID_SKIN;
|
pipe->pluginID = ID_SKIN;
|
||||||
pipe->pluginData = 1;
|
pipe->pluginData = 1;
|
||||||
return pipe;
|
return pipe;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
|
||||||
#ifdef RW_OPENGL
|
#ifdef RW_OPENGL
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
|
||||||
#ifdef RW_OPENGL
|
#ifdef RW_OPENGL
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include "rwgl3.h"
|
#include "rwgl3.h"
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
|
||||||
#ifdef RW_OPENGL
|
#ifdef RW_OPENGL
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include "rwgl3.h"
|
#include "rwgl3.h"
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwwdgl.h"
|
#include "rwwdgl.h"
|
||||||
@ -603,7 +604,7 @@ skinInstanceCB(Geometry *g, int32 i, uint32 offset)
|
|||||||
header->dataSize = offset*g->numVertices;
|
header->dataSize = offset*g->numVertices;
|
||||||
header->data = new uint8[header->dataSize];
|
header->data = new uint8[header->dataSize];
|
||||||
|
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
|
Skin *skin = Skin::get(g);
|
||||||
if(skin == nil)
|
if(skin == nil)
|
||||||
return 8;
|
return 8;
|
||||||
|
|
||||||
@ -631,7 +632,7 @@ skinUninstanceCB(Geometry *geo)
|
|||||||
{
|
{
|
||||||
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
|
||||||
|
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
Skin *skin = Skin::get(geo);
|
||||||
if(skin == nil)
|
if(skin == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
107
src/hanim.cpp
107
src/hanim.cpp
@ -8,6 +8,7 @@
|
|||||||
#include "rwplg.h"
|
#include "rwplg.h"
|
||||||
#include "rwpipeline.h"
|
#include "rwpipeline.h"
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
|
#include "rwanim.h"
|
||||||
#include "rwplugins.h"
|
#include "rwplugins.h"
|
||||||
#include "ps2/rwps2.h"
|
#include "ps2/rwps2.h"
|
||||||
#include "ps2/rwps2plg.h"
|
#include "ps2/rwps2plg.h"
|
||||||
@ -25,22 +26,24 @@ int32 hAnimOffset;
|
|||||||
bool32 hAnimDoStream = 1;
|
bool32 hAnimDoStream = 1;
|
||||||
|
|
||||||
HAnimHierarchy*
|
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));
|
HAnimHierarchy *hier = (HAnimHierarchy*)malloc(sizeof(*hier));
|
||||||
|
hier->currentAnim = AnimInterpolator::create(numNodes, maxKeySize);
|
||||||
|
|
||||||
hier->numNodes = numNodes;
|
hier->numNodes = numNodes;
|
||||||
hier->flags = flags;
|
hier->flags = flags;
|
||||||
hier->maxInterpKeyFrameSize = maxKeySize;
|
|
||||||
hier->parentFrame = nil;
|
hier->parentFrame = nil;
|
||||||
hier->parentHierarchy = hier;
|
hier->parentHierarchy = hier;
|
||||||
if(hier->flags & 2)
|
if(hier->flags & NOMATRICES){
|
||||||
hier->matrices = hier->matricesUnaligned = nil;
|
hier->matrices = nil;
|
||||||
else{
|
hier->matricesUnaligned = nil;
|
||||||
|
}else{
|
||||||
hier->matricesUnaligned =
|
hier->matricesUnaligned =
|
||||||
(float*) new uint8[hier->numNodes*64 + 15];
|
(void*) new uint8[hier->numNodes*64 + 15];
|
||||||
hier->matrices =
|
hier->matrices =
|
||||||
(float*)((uintptr)hier->matricesUnaligned & ~0xF);
|
(Matrix*)((uintptr)hier->matricesUnaligned & ~0xF);
|
||||||
}
|
}
|
||||||
hier->nodeInfo = new HAnimNodeInfo[hier->numNodes];
|
hier->nodeInfo = new HAnimNodeInfo[hier->numNodes];
|
||||||
for(int32 i = 0; i < hier->numNodes; i++){
|
for(int32 i = 0; i < hier->numNodes; i++){
|
||||||
@ -112,6 +115,43 @@ HAnimHierarchy::find(Frame *f)
|
|||||||
return HAnimHierarchy::find(f->child);
|
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*
|
||||||
HAnimData::get(Frame *f)
|
HAnimData::get(Frame *f)
|
||||||
{
|
{
|
||||||
@ -161,6 +201,8 @@ readHAnim(Stream *stream, int32, void *object, int32 offset, int32)
|
|||||||
if(numNodes != 0){
|
if(numNodes != 0){
|
||||||
int32 flags = stream->readI32();
|
int32 flags = stream->readI32();
|
||||||
int32 maxKeySize = 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 *nodeFlags = new int32[numNodes];
|
||||||
int32 *nodeIDs = new int32[numNodes];
|
int32 *nodeIDs = new int32[numNodes];
|
||||||
for(int32 i = 0; i < numNodes; i++){
|
for(int32 i = 0; i < numNodes; i++){
|
||||||
@ -190,7 +232,7 @@ writeHAnim(Stream *stream, int32, void *object, int32 offset, int32)
|
|||||||
HAnimHierarchy *hier = hanim->hierarchy;
|
HAnimHierarchy *hier = hanim->hierarchy;
|
||||||
stream->writeI32(hier->numNodes);
|
stream->writeI32(hier->numNodes);
|
||||||
stream->writeI32(hier->flags);
|
stream->writeI32(hier->flags);
|
||||||
stream->writeI32(hier->maxInterpKeyFrameSize);
|
stream->writeI32(hier->currentAnim->maxInterpKeyFrameSize);
|
||||||
for(int32 i = 0; i < hier->numNodes; i++){
|
for(int32 i = 0; i < hier->numNodes; i++){
|
||||||
stream->writeI32(hier->nodeInfo[i].id);
|
stream->writeI32(hier->nodeInfo[i].id);
|
||||||
stream->writeI32(hier->nodeInfo[i].index);
|
stream->writeI32(hier->nodeInfo[i].index);
|
||||||
@ -217,9 +259,9 @@ hAnimFrameRead(Stream *stream, Animation *anim)
|
|||||||
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
||||||
for(int32 i = 0; i < anim->numFrames; i++){
|
for(int32 i = 0; i < anim->numFrames; i++){
|
||||||
frames[i].time = stream->readF32();
|
frames[i].time = stream->readF32();
|
||||||
stream->read(frames[i].q, 4*4);
|
stream->read(&frames[i].q, 4*4);
|
||||||
stream->read(frames[i].t, 3*4);
|
stream->read(&frames[i].t, 3*4);
|
||||||
int32 prev = stream->readI32();
|
int32 prev = stream->readI32()/0x24;
|
||||||
frames[i].prev = &frames[prev];
|
frames[i].prev = &frames[prev];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,9 +272,9 @@ hAnimFrameWrite(Stream *stream, Animation *anim)
|
|||||||
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
||||||
for(int32 i = 0; i < anim->numFrames; i++){
|
for(int32 i = 0; i < anim->numFrames; i++){
|
||||||
stream->writeF32(frames[i].time);
|
stream->writeF32(frames[i].time);
|
||||||
stream->write(frames[i].q, 4*4);
|
stream->write(&frames[i].q, 4*4);
|
||||||
stream->write(frames[i].t, 3*4);
|
stream->write(&frames[i].t, 3*4);
|
||||||
stream->writeI32(frames[i].prev - frames);
|
stream->writeI32((frames[i].prev - frames)*0x24);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +284,31 @@ hAnimFrameGetSize(Animation *anim)
|
|||||||
return anim->numFrames*(4 + 4*4 + 3*4 + 4);
|
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
|
void
|
||||||
registerHAnimPlugin(void)
|
registerHAnimPlugin(void)
|
||||||
{
|
{
|
||||||
@ -255,12 +322,18 @@ registerHAnimPlugin(void)
|
|||||||
|
|
||||||
AnimInterpolatorInfo *info = new AnimInterpolatorInfo;
|
AnimInterpolatorInfo *info = new AnimInterpolatorInfo;
|
||||||
info->id = 1;
|
info->id = 1;
|
||||||
info->keyFrameSize = sizeof(HAnimKeyFrame);
|
info->interpKeyFrameSize = sizeof(HAnimInterpFrame);
|
||||||
info->customDataSize = sizeof(HAnimKeyFrame);
|
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->streamRead = hAnimFrameRead;
|
||||||
info->streamWrite = hAnimFrameWrite;
|
info->streamWrite = hAnimFrameWrite;
|
||||||
info->streamGetSize = hAnimFrameGetSize;
|
info->streamGetSize = hAnimFrameGetSize;
|
||||||
registerAnimInterpolatorInfo(info);
|
AnimInterpolatorInfo::registerInterp(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "rwpipeline.h"
|
#include "rwpipeline.h"
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
#include "rwengine.h"
|
#include "rwengine.h"
|
||||||
|
#include "rwanim.h"
|
||||||
#include "rwplugins.h"
|
#include "rwplugins.h"
|
||||||
#include "ps2/rwps2.h"
|
#include "ps2/rwps2.h"
|
||||||
#include "ps2/rwps2plg.h"
|
#include "ps2/rwps2plg.h"
|
||||||
|
@ -51,6 +51,19 @@ findMinVertAndNumVertices(uint16 *indices, uint32 numIndices, uint32 *minVert, i
|
|||||||
*numVertices = max - min + 1;
|
*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
|
void
|
||||||
instV3d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride)
|
instV3d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwps2.h"
|
#include "rwps2.h"
|
||||||
#include "rwps2plg.h"
|
#include "rwps2plg.h"
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwps2.h"
|
#include "rwps2.h"
|
||||||
#include "rwps2plg.h"
|
#include "rwps2plg.h"
|
||||||
@ -947,8 +948,8 @@ genericUninstanceCB(MatPipeline *pipe, Geometry *geo, uint32 flags[], Mesh *mesh
|
|||||||
uint32 *weights = nil;
|
uint32 *weights = nil;
|
||||||
int8 *adc = nil;
|
int8 *adc = nil;
|
||||||
Skin *skin = nil;
|
Skin *skin = nil;
|
||||||
if(skinGlobals.offset)
|
if(skinGlobals.geoOffset)
|
||||||
skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
skin = Skin::get(geo);
|
||||||
|
|
||||||
PipeAttribute *a;
|
PipeAttribute *a;
|
||||||
for(int32 i = 0; i < nelem(pipe->attribs); i++)
|
for(int32 i = 0; i < nelem(pipe->attribs); i++)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwps2.h"
|
#include "rwps2.h"
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "../rwplg.h"
|
#include "../rwplg.h"
|
||||||
#include "../rwpipeline.h"
|
#include "../rwpipeline.h"
|
||||||
#include "../rwobjects.h"
|
#include "../rwobjects.h"
|
||||||
|
#include "../rwanim.h"
|
||||||
#include "../rwengine.h"
|
#include "../rwengine.h"
|
||||||
#include "../rwplugins.h"
|
#include "../rwplugins.h"
|
||||||
#include "rwps2.h"
|
#include "rwps2.h"
|
||||||
@ -183,7 +184,7 @@ instanceSkinData(Geometry*, Mesh *m, Skin *skin, uint32 *data)
|
|||||||
void
|
void
|
||||||
skinInstanceCB(MatPipeline *, Geometry *g, Mesh *m, uint8 **data)
|
skinInstanceCB(MatPipeline *, Geometry *g, Mesh *m, uint8 **data)
|
||||||
{
|
{
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
|
Skin *skin = Skin::get(g);
|
||||||
if(skin == nil)
|
if(skin == nil)
|
||||||
return;
|
return;
|
||||||
instanceSkinData(g, m, skin, (uint32*)data[4]);
|
instanceSkinData(g, m, skin, (uint32*)data[4]);
|
||||||
@ -193,7 +194,7 @@ skinInstanceCB(MatPipeline *, Geometry *g, Mesh *m, uint8 **data)
|
|||||||
int32
|
int32
|
||||||
findVertexSkin(Geometry *g, uint32 flags[], uint32 mask, Vertex *v)
|
findVertexSkin(Geometry *g, uint32 flags[], uint32 mask, Vertex *v)
|
||||||
{
|
{
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
|
Skin *skin = Skin::get(g);
|
||||||
float32 *wghts = nil;
|
float32 *wghts = nil;
|
||||||
uint8 *inds = nil;
|
uint8 *inds = nil;
|
||||||
if(skin){
|
if(skin){
|
||||||
@ -245,7 +246,7 @@ findVertexSkin(Geometry *g, uint32 flags[], uint32 mask, Vertex *v)
|
|||||||
void
|
void
|
||||||
insertVertexSkin(Geometry *geo, int32 i, uint32 mask, Vertex *v)
|
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);
|
insertVertex(geo, i, mask, v);
|
||||||
if(mask & 0x10000){
|
if(mask & 0x10000){
|
||||||
memcpy(&skin->weights[i*4], v->w, 16);
|
memcpy(&skin->weights[i*4], v->w, 16);
|
||||||
@ -308,7 +309,7 @@ skinUninstanceCB(MatPipeline*, Geometry *geo, uint32 flags[], Mesh *mesh, uint8
|
|||||||
void
|
void
|
||||||
skinPreCB(MatPipeline*, Geometry *geo)
|
skinPreCB(MatPipeline*, Geometry *geo)
|
||||||
{
|
{
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
Skin *skin = Skin::get(geo);
|
||||||
if(skin == nil)
|
if(skin == nil)
|
||||||
return;
|
return;
|
||||||
uint8 *data = skin->data;
|
uint8 *data = skin->data;
|
||||||
@ -322,7 +323,7 @@ skinPreCB(MatPipeline*, Geometry *geo)
|
|||||||
void
|
void
|
||||||
skinPostCB(MatPipeline*, Geometry *geo)
|
skinPostCB(MatPipeline*, Geometry *geo)
|
||||||
{
|
{
|
||||||
Skin *skin = *PLUGINOFFSET(Skin*, geo, skinGlobals.offset);
|
Skin *skin = Skin::get(geo);
|
||||||
if(skin){
|
if(skin){
|
||||||
skin->findNumWeights(geo->numVertices);
|
skin->findNumWeights(geo->numVertices);
|
||||||
skin->findUsedBones(geo->numVertices);
|
skin->findUsedBones(geo->numVertices);
|
||||||
|
174
src/rwanim.h
Normal file
174
src/rwanim.h
Normal 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);
|
||||||
|
|
||||||
|
}
|
21
src/rwbase.h
21
src/rwbase.h
@ -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)); }
|
inline V3d setlength(const V3d &v, float32 l) { return scale(v, l/length(v)); }
|
||||||
V3d cross(const V3d &a, const V3d &b);
|
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 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
|
struct Quat
|
||||||
{
|
{
|
||||||
float32 w, x, y, z;
|
// order is important for streaming
|
||||||
Quat(void) : w(0.0f), x(0.0f), y(0.0f), z(0.0f) {}
|
float32 x, y, z, w;
|
||||||
Quat(float32 w, float32 x, float32 y, float32 z) : w(w), x(x), y(y), z(z) {}
|
Quat(void) : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
|
||||||
Quat(float32 w, V3d vec) : w(w), x(vec.x), y(vec.y), z(vec.z) {}
|
Quat(float32 w, float32 x, float32 y, float32 z) : x(x), y(y), z(z), w(w) {}
|
||||||
Quat(V3d vec) : w(0.0f), x(vec.x), y(vec.y), z(vec.z) {}
|
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){
|
static Quat rotation(float32 angle, const V3d &axis){
|
||||||
return Quat(cos(angle/2.0f), scale(axis, sin(angle/2.0f))); }
|
return Quat(cos(angle/2.0f), scale(axis, sin(angle/2.0f))); }
|
||||||
void set(float32 w, float32 x, float32 y, float32 z){
|
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 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 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 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 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 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); }
|
inline Quat conj(const Quat &q) { return Quat(q.w, -q.x, -q.y, -q.z); }
|
||||||
Quat mult(const Quat &q, const Quat &p);
|
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(); }
|
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
|
struct Matrix
|
||||||
{
|
{
|
||||||
|
@ -641,102 +641,4 @@ struct TexDictionary : PluginBase<TexDictionary>
|
|||||||
|
|
||||||
extern TexDictionary *currentTexDictionary;
|
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,11 +41,13 @@ enum {
|
|||||||
VERT_NORMSHORT3,
|
VERT_NORMSHORT3,
|
||||||
VERT_FLOAT2,
|
VERT_FLOAT2,
|
||||||
VERT_FLOAT3,
|
VERT_FLOAT3,
|
||||||
|
VERT_FLOAT4,
|
||||||
VERT_ARGB,
|
VERT_ARGB,
|
||||||
VERT_RGBA,
|
VERT_RGBA,
|
||||||
VERT_COMPNORM
|
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 instV3d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride);
|
||||||
void uninstV3d(int type, float *dst, uint8 *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);
|
void instV2d(int type, uint8 *dst, float *src, uint32 numVertices, uint32 stride);
|
||||||
|
@ -7,9 +7,17 @@ namespace rw {
|
|||||||
struct HAnimKeyFrame
|
struct HAnimKeyFrame
|
||||||
{
|
{
|
||||||
HAnimKeyFrame *prev;
|
HAnimKeyFrame *prev;
|
||||||
float time;
|
float32 time;
|
||||||
float q[4];
|
Quat q;
|
||||||
float t[3];
|
V3d t;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HAnimInterpFrame
|
||||||
|
{
|
||||||
|
HAnimKeyFrame *keyFrame1;
|
||||||
|
HAnimKeyFrame *keyFrame2;
|
||||||
|
Quat q;
|
||||||
|
V3d t;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HAnimNodeInfo
|
struct HAnimNodeInfo
|
||||||
@ -24,24 +32,34 @@ struct HAnimHierarchy
|
|||||||
{
|
{
|
||||||
int32 flags;
|
int32 flags;
|
||||||
int32 numNodes;
|
int32 numNodes;
|
||||||
float *matrices;
|
Matrix *matrices;
|
||||||
float *matricesUnaligned;
|
void *matricesUnaligned;
|
||||||
HAnimNodeInfo *nodeInfo;
|
HAnimNodeInfo *nodeInfo;
|
||||||
Frame *parentFrame;
|
Frame *parentFrame;
|
||||||
HAnimHierarchy *parentHierarchy; // mostly unused
|
HAnimHierarchy *parentHierarchy; // mostly unused
|
||||||
|
AnimInterpolator *currentAnim;
|
||||||
|
|
||||||
// temporary
|
static HAnimHierarchy *create(int32 numNodes, int32 *nodeFlags,
|
||||||
int32 maxInterpKeyFrameSize;
|
int32 *nodeIDs, int32 flags, int32 maxKeySize);
|
||||||
|
|
||||||
static HAnimHierarchy *create(int32 numNodes, int32 *nodeFlags, int32 *nodeIDs, int32 flags, int32 maxKeySize);
|
|
||||||
void destroy(void);
|
void destroy(void);
|
||||||
void attachByIndex(int32 id);
|
void attachByIndex(int32 id);
|
||||||
void attach(void);
|
void attach(void);
|
||||||
int32 getIndex(int32 id);
|
int32 getIndex(int32 id);
|
||||||
|
void updateMatrices(void);
|
||||||
|
|
||||||
static HAnimHierarchy *get(Frame *f);
|
static HAnimHierarchy *get(Frame *f);
|
||||||
|
static HAnimHierarchy *get(Clump *c){
|
||||||
|
return find(c->getFrame()); }
|
||||||
static HAnimHierarchy *find(Frame *f);
|
static HAnimHierarchy *find(Frame *f);
|
||||||
|
|
||||||
|
enum Flags {
|
||||||
|
SUBHIERARCHY = 0x1,
|
||||||
|
NOMATRICES = 0x2,
|
||||||
|
|
||||||
|
UPDATEMODELLINGMATRICES = 0x1000,
|
||||||
|
UPDATELTMS = 0x2000,
|
||||||
|
LOCALSPACEMATRICES = 0x4000
|
||||||
|
};
|
||||||
enum NodeFlag {
|
enum NodeFlag {
|
||||||
POP = 1,
|
POP = 1,
|
||||||
PUSH
|
PUSH
|
||||||
@ -138,6 +156,14 @@ void registerMatFXPlugin(void);
|
|||||||
* Skin
|
* Skin
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct SkinGlobals
|
||||||
|
{
|
||||||
|
int32 geoOffset;
|
||||||
|
int32 atomicOffset;
|
||||||
|
ObjPipeline *pipelines[NUM_PLATFORMS];
|
||||||
|
};
|
||||||
|
extern SkinGlobals skinGlobals;
|
||||||
|
|
||||||
struct Skin
|
struct Skin
|
||||||
{
|
{
|
||||||
int32 numBones;
|
int32 numBones;
|
||||||
@ -173,15 +199,21 @@ struct Skin
|
|||||||
void init(int32 numBones, int32 numUsedBones, int32 numVertices);
|
void init(int32 numBones, int32 numUsedBones, int32 numVertices);
|
||||||
void findNumWeights(int32 numVertices);
|
void findNumWeights(int32 numVertices);
|
||||||
void findUsedBones(int32 numVertices);
|
void findUsedBones(int32 numVertices);
|
||||||
|
|
||||||
static void setPipeline(Atomic *a, int32 type);
|
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 *readSkinSplitData(Stream *stream, Skin *skin);
|
||||||
Stream *writeSkinSplitData(Stream *stream, Skin *skin);
|
Stream *writeSkinSplitData(Stream *stream, Skin *skin);
|
||||||
int32 skinSplitDataSize(Skin *skin);
|
int32 skinSplitDataSize(Skin *skin);
|
||||||
|
35
src/skin.cpp
35
src/skin.cpp
@ -8,6 +8,7 @@
|
|||||||
#include "rwplg.h"
|
#include "rwplg.h"
|
||||||
#include "rwpipeline.h"
|
#include "rwpipeline.h"
|
||||||
#include "rwobjects.h"
|
#include "rwobjects.h"
|
||||||
|
#include "rwanim.h"
|
||||||
#include "rwengine.h"
|
#include "rwengine.h"
|
||||||
#include "rwplugins.h"
|
#include "rwplugins.h"
|
||||||
#include "ps2/rwps2.h"
|
#include "ps2/rwps2.h"
|
||||||
@ -23,7 +24,7 @@
|
|||||||
|
|
||||||
namespace rw {
|
namespace rw {
|
||||||
|
|
||||||
SkinGlobals skinGlobals = { 0, { nil } };
|
SkinGlobals skinGlobals = { 0, 0, { nil } };
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
createSkin(void *object, int32 offset, int32)
|
createSkin(void *object, int32 offset, int32)
|
||||||
@ -257,6 +258,26 @@ skinRights(void *object, int32, int32, uint32)
|
|||||||
Skin::setPipeline((Atomic*)object, 1);
|
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
|
void
|
||||||
registerSkinPlugin(void)
|
registerSkinPlugin(void)
|
||||||
{
|
{
|
||||||
@ -274,13 +295,15 @@ registerSkinPlugin(void)
|
|||||||
wdgl::initSkin();
|
wdgl::initSkin();
|
||||||
gl3::initSkin();
|
gl3::initSkin();
|
||||||
|
|
||||||
skinGlobals.offset = Geometry::registerPlugin(sizeof(Skin*), ID_SKIN,
|
int32 o;
|
||||||
createSkin,
|
o = Geometry::registerPlugin(sizeof(Skin*), ID_SKIN,
|
||||||
destroySkin,
|
createSkin, destroySkin, copySkin);
|
||||||
copySkin);
|
|
||||||
Geometry::registerPluginStream(ID_SKIN,
|
Geometry::registerPluginStream(ID_SKIN,
|
||||||
readSkin, writeSkin, getSizeSkin);
|
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);
|
Atomic::setStreamRightsCallback(ID_SKIN, skinRights);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
350
src/uvanim.cpp
Normal file
350
src/uvanim.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user