forgot file

This commit is contained in:
aap 2015-09-09 23:28:37 +02:00
parent c7fa3b3b8c
commit eedf096b39

307
src/anim.cpp Normal file
View 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);
}
}