mirror of
https://github.com/aap/librw.git
synced 2025-02-01 13:36:38 +00:00
forgot file
This commit is contained in:
parent
c7fa3b3b8c
commit
eedf096b39
307
src/anim.cpp
Normal file
307
src/anim.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "rwbase.h"
|
||||
#include "rwplugin.h"
|
||||
#include "rwpipeline.h"
|
||||
#include "rwobjects.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace rw {
|
||||
|
||||
#define MAXINTERPINFO 10
|
||||
|
||||
static AnimInterpolatorInfo *interpInfoList[MAXINTERPINFO];
|
||||
|
||||
void
|
||||
registerAnimInterpolatorInfo(AnimInterpolatorInfo *interpInfo)
|
||||
{
|
||||
for(int32 i = 0; i < MAXINTERPINFO; i++)
|
||||
if(interpInfoList[i] == NULL){
|
||||
interpInfoList[i] = interpInfo;
|
||||
return;
|
||||
}
|
||||
assert(0 && "no room for interpolatorInfo");
|
||||
}
|
||||
|
||||
AnimInterpolatorInfo*
|
||||
findAnimInterpolatorInfo(int32 id)
|
||||
{
|
||||
for(int32 i = 0; i < MAXINTERPINFO; i++){
|
||||
if(interpInfoList[i] && interpInfoList[i]->id == id)
|
||||
return interpInfoList[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Animation::Animation(AnimInterpolatorInfo *interpInfo, int32 numFrames, int32 flags, float duration)
|
||||
{
|
||||
this->interpInfo = interpInfo;
|
||||
this->numFrames = numFrames;
|
||||
this->flags = flags;
|
||||
this->duration = duration;
|
||||
uint8 *data = new uint8[this->numFrames*interpInfo->keyFrameSize + interpInfo->customDataSize];
|
||||
this->keyframes = data;
|
||||
data += this->numFrames*interpInfo->keyFrameSize;
|
||||
this->customData = data;
|
||||
}
|
||||
|
||||
Animation*
|
||||
Animation::streamRead(Stream *stream)
|
||||
{
|
||||
Animation *anim;
|
||||
assert(stream->readI32() == 0x100);
|
||||
int32 typeID = stream->readI32();
|
||||
AnimInterpolatorInfo *interpInfo = findAnimInterpolatorInfo(typeID);
|
||||
int32 numFrames = stream->readI32();
|
||||
int32 flags = stream->readI32();
|
||||
float duration = stream->readF32();
|
||||
anim = new Animation(interpInfo, numFrames, flags, duration);
|
||||
interpInfo->streamRead(stream, anim);
|
||||
return anim;
|
||||
}
|
||||
|
||||
bool
|
||||
Animation::streamWrite(Stream *stream)
|
||||
{
|
||||
stream->writeI32(0x100);
|
||||
stream->writeI32(this->interpInfo->id);
|
||||
stream->writeI32(this->numFrames);
|
||||
stream->writeI32(this->flags);
|
||||
stream->writeF32(this->duration);
|
||||
this->interpInfo->streamWrite(stream, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
Animation::streamGetSize(void)
|
||||
{
|
||||
uint32 size = 4 + 4 + 4 + 4 + 4;
|
||||
size += this->interpInfo->streamGetSize(this);
|
||||
return size;
|
||||
}
|
||||
|
||||
AnimInterpolator::AnimInterpolator(Animation *anim)
|
||||
{
|
||||
this->anim = anim;
|
||||
}
|
||||
|
||||
UVAnimDictionary *currentUVAnimDictionary;
|
||||
|
||||
UVAnimDictionary*
|
||||
UVAnimDictionary::streamRead(Stream *stream)
|
||||
{
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
UVAnimDictionary *dict = new UVAnimDictionary;
|
||||
dict->numAnims = stream->readI32();
|
||||
dict->anims = new Animation*[dict->numAnims];
|
||||
for(int32 i = 0; i < dict->numAnims; i++){
|
||||
assert(findChunk(stream, ID_ANIMANIMATION, NULL, NULL));
|
||||
dict->anims[i] = Animation::streamRead(stream);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
bool
|
||||
UVAnimDictionary::streamWrite(Stream *stream)
|
||||
{
|
||||
uint32 size = this->streamGetSize();
|
||||
writeChunkHeader(stream, ID_UVANIMDICT, size);
|
||||
writeChunkHeader(stream, ID_STRUCT, 4);
|
||||
stream->writeI32(this->numAnims);
|
||||
for(int32 i = 0; i < this->numAnims; i++){
|
||||
writeChunkHeader(stream, ID_ANIMANIMATION, this->anims[i]->streamGetSize());
|
||||
this->anims[i]->streamWrite(stream);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
UVAnimDictionary::streamGetSize(void)
|
||||
{
|
||||
uint32 size = 12 + 4;
|
||||
for(int32 i = 0; i < this->numAnims; i++)
|
||||
size += 12 + this->anims[i]->streamGetSize();
|
||||
return size;
|
||||
}
|
||||
|
||||
Animation*
|
||||
UVAnimDictionary::find(const char *name)
|
||||
{
|
||||
for(int32 i = 0; i < this->numAnims; i++){
|
||||
Animation *anim = this->anims[i];
|
||||
UVAnimCustomData *custom = (UVAnimCustomData*)anim->customData;
|
||||
if(strncmp(custom->name, name, 32) == 0) // strncmp correct?
|
||||
return anim;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
struct UVAnim
|
||||
{
|
||||
AnimInterpolator *interp[8];
|
||||
};
|
||||
|
||||
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);
|
||||
// TODO: ref counts &c.
|
||||
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);
|
||||
memcpy(dstuvanim, srcuvanim, sizeof(*srcuvanim));
|
||||
// TODO: ref counts &c.
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void
|
||||
readUVAnim(Stream *stream, int32, void *object, int32 offset, int32)
|
||||
{
|
||||
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
|
||||
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
||||
char name[32];
|
||||
uint32 mask = stream->readI32();
|
||||
uint32 bit = 1;
|
||||
for(int32 i = 0; i < 8; i++){
|
||||
if(mask & bit){
|
||||
stream->read(name, 32);
|
||||
assert(currentUVAnimDictionary != NULL);
|
||||
Animation *anim = currentUVAnimDictionary->find(name);
|
||||
AnimInterpolator *interp = new AnimInterpolator(anim);
|
||||
uvanim->interp[i] = interp;
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32
|
||||
getSizeUVAnim(void *object, int32 offset, int32)
|
||||
{
|
||||
UVAnim *uvanim = PLUGINOFFSET(UVAnim, object, offset);
|
||||
int32 size = 12 + 4;
|
||||
for(int32 i = 0; i < 8; i++)
|
||||
if(uvanim->interp[i])
|
||||
size += 32;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
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