#include #include #include #include #include "rwbase.h" #include "rwerror.h" #include "rwplg.h" #include "rwpipeline.h" #include "rwobjects.h" #include "rwengine.h" #include "rwanim.h" #include "rwplugins.h" #include "ps2/rwps2.h" #include "ps2/rwps2plg.h" #include "d3d/rwxbox.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" #include "gl/rwwdgl.h" #include "gl/rwgl3.h" #define PLUGIN_ID ID_HANIM namespace rw { int32 hAnimOffset; bool32 hAnimDoStream = 1; HAnimHierarchy* HAnimHierarchy::create(int32 numNodes, int32 *nodeFlags, int32 *nodeIDs, int32 flags, int32 maxKeySize) { HAnimHierarchy *hier = (HAnimHierarchy*)rwMalloc(sizeof(*hier), MEMDUR_EVENT | ID_HANIM); if(hier == nil){ RWERROR((ERR_ALLOC, sizeof(*hier))); return nil; } hier->currentAnim = AnimInterpolator::create(numNodes, maxKeySize); hier->numNodes = numNodes; hier->flags = flags; hier->parentFrame = nil; hier->parentHierarchy = hier; if(hier->flags & NOMATRICES){ hier->matrices = nil; hier->matricesUnaligned = nil; }else{ hier->matricesUnaligned = (void*) new uint8[hier->numNodes*64 + 15]; hier->matrices = (Matrix*)((uintptr)hier->matricesUnaligned & ~0xF); } hier->nodeInfo = new HAnimNodeInfo[hier->numNodes]; for(int32 i = 0; i < hier->numNodes; i++){ hier->nodeInfo[i].id = nodeIDs[i]; hier->nodeInfo[i].index = i; hier->nodeInfo[i].flags = nodeFlags[i]; hier->nodeInfo[i].frame = nil; } return hier; } void HAnimHierarchy::destroy(void) { delete[] (uint8*)this->matricesUnaligned; delete[] this->nodeInfo; rwFree(this); } static Frame* findById(Frame *f, int32 id) { if(f == nil) return nil; HAnimData *hanim = HAnimData::get(f); if(hanim->id >= 0 && hanim->id == id) return f; Frame *ff = findById(f->next, id); if(ff) return ff; return findById(f->child, id); } void HAnimHierarchy::attachByIndex(int32 idx) { int32 id = this->nodeInfo[idx].id; Frame *f = findById(this->parentFrame, id); this->nodeInfo[idx].frame = f; } void HAnimHierarchy::attach(void) { for(int32 i = 0; i < this->numNodes; i++) this->attachByIndex(i); } int32 HAnimHierarchy::getIndex(int32 id) { for(int32 i = 0; i < this->numNodes; i++) if(this->nodeInfo[i].id == id) return i; return -1; } HAnimHierarchy* HAnimHierarchy::get(Frame *f) { return HAnimData::get(f)->hierarchy; } HAnimHierarchy* HAnimHierarchy::find(Frame *f) { if(f == nil) return nil; HAnimHierarchy *hier = HAnimHierarchy::get(f); if(hier) return hier; hier = HAnimHierarchy::find(f->next); if(hier) return hier; return HAnimHierarchy::find(f->child); } void HAnimHierarchy::updateMatrices(void) { // TODO: handle more (all!) cases Matrix rootMat, animMat; Matrix *curMat, *parentMat; Matrix **sp, *stack[64]; Frame *frm, *parfrm; int32 i; AnimInterpolator *anim = this->currentAnim; sp = stack; curMat = this->matrices; frm = this->parentFrame; if(frm && (parfrm = frm->getParent())) rootMat = *parfrm->getLTM(); else rootMat.setIdentity(); parentMat = &rootMat; HAnimNodeInfo *node = this->nodeInfo; for(i = 0; i < this->numNodes; i++){ anim->applyCB(&animMat, anim->getInterpFrame(i)); Matrix::mult(curMat, parentMat, &animMat); if(node->flags & PUSH) *sp++ = parentMat; parentMat = curMat; if(node->flags & POP) parentMat = *--sp; node++; curMat++; } } HAnimData* HAnimData::get(Frame *f) { return PLUGINOFFSET(HAnimData, f, hAnimOffset); } static void* createHAnim(void *object, int32 offset, int32) { HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); hanim->id = -1; hanim->hierarchy = nil; return object; } static void* destroyHAnim(void *object, int32 offset, int32) { HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); if(hanim->hierarchy) hanim->hierarchy->destroy(); hanim->id = -1; hanim->hierarchy = nil; return object; } static void* copyHAnim(void *dst, void *src, int32 offset, int32) { HAnimData *dsthanim = PLUGINOFFSET(HAnimData, dst, offset); HAnimData *srchanim = PLUGINOFFSET(HAnimData, src, offset); dsthanim->id = srchanim->id; // TODO dsthanim->hierarchy = nil; return dst; } static Stream* readHAnim(Stream *stream, int32, void *object, int32 offset, int32) { int32 ver, numNodes; HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); ver = stream->readI32(); assert(ver == 0x100); hanim->id = stream->readI32(); numNodes = stream->readI32(); if(numNodes != 0){ int32 flags = stream->readI32(); int32 maxKeySize = stream->readI32(); // Sizes are fucked for 64 bit pointers but // AnimInterpolator::create() will take care of that int32 *nodeFlags = new int32[numNodes]; int32 *nodeIDs = new int32[numNodes]; for(int32 i = 0; i < numNodes; i++){ nodeIDs[i] = stream->readI32(); stream->readI32(); // index...unused nodeFlags[i] = stream->readI32(); } hanim->hierarchy = HAnimHierarchy::create(numNodes, nodeFlags, nodeIDs, flags, maxKeySize); hanim->hierarchy->parentFrame = (Frame*)object; delete[] nodeFlags; delete[] nodeIDs; } return stream; } static Stream* writeHAnim(Stream *stream, int32, void *object, int32 offset, int32) { HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); stream->writeI32(256); stream->writeI32(hanim->id); if(hanim->hierarchy == nil){ stream->writeI32(0); return stream; } HAnimHierarchy *hier = hanim->hierarchy; stream->writeI32(hier->numNodes); stream->writeI32(hier->flags); stream->writeI32(hier->currentAnim->maxInterpKeyFrameSize); for(int32 i = 0; i < hier->numNodes; i++){ stream->writeI32(hier->nodeInfo[i].id); stream->writeI32(hier->nodeInfo[i].index); stream->writeI32(hier->nodeInfo[i].flags); } return stream; } static int32 getSizeHAnim(void *object, int32 offset, int32) { HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset); if(!hAnimDoStream || version >= 0x35000 && hanim->id == -1 && hanim->hierarchy == nil) return 0; if(hanim->hierarchy) return 12 + 8 + hanim->hierarchy->numNodes*12; return 12; } static void hAnimFrameRead(Stream *stream, Animation *anim) { HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes; for(int32 i = 0; i < anim->numFrames; i++){ frames[i].time = stream->readF32(); stream->read(&frames[i].q, 4*4); stream->read(&frames[i].t, 3*4); int32 prev = stream->readI32()/0x24; frames[i].prev = &frames[prev]; } } static void hAnimFrameWrite(Stream *stream, Animation *anim) { HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes; for(int32 i = 0; i < anim->numFrames; i++){ stream->writeF32(frames[i].time); stream->write(&frames[i].q, 4*4); stream->write(&frames[i].t, 3*4); stream->writeI32((frames[i].prev - frames)*0x24); } } static uint32 hAnimFrameGetSize(Animation *anim) { return anim->numFrames*(4 + 4*4 + 3*4 + 4); } //void hanimBlendCB(void *out, void *in1, void *in2, float32 a); //void hanimAddCB(void *out, void *in1, void *in2); //void hanimMulRecipCB(void *frame, void *start); static void hanimApplyCB(void *result, void *frame) { Matrix *m = (Matrix*)result; HAnimInterpFrame *f = (HAnimInterpFrame*)frame; m->rotate(f->q, COMBINEREPLACE); m->pos = f->t; } static void hanimInterpCB(void *vout, void *vin1, void *vin2, float32 t, void*) { HAnimInterpFrame *out = (HAnimInterpFrame*)vout; HAnimKeyFrame *in1 = (HAnimKeyFrame*)vin1; HAnimKeyFrame *in2 = (HAnimKeyFrame*)vin2; assert(t >= in1->time && t <= in2->time); float32 a = (t - in1->time)/(in2->time - in1->time); out->t = lerp(in1->t, in2->t, a); out->q = slerp(in1->q, in2->q, a); } void registerHAnimPlugin(void) { hAnimOffset = Frame::registerPlugin(sizeof(HAnimData), ID_HANIM, createHAnim, destroyHAnim, copyHAnim); Frame::registerPluginStream(ID_HANIM, readHAnim, writeHAnim, getSizeHAnim); AnimInterpolatorInfo *info = new AnimInterpolatorInfo; info->id = 1; info->interpKeyFrameSize = sizeof(HAnimInterpFrame); info->animKeyFrameSize = sizeof(HAnimKeyFrame); info->customDataSize = 0; info->applyCB = hanimApplyCB; info->blendCB = nil; info->interpCB = hanimInterpCB; info->addCB = nil; info->mulRecipCB = nil; info->streamRead = hAnimFrameRead; info->streamWrite = hAnimFrameWrite; info->streamGetSize = hAnimFrameGetSize; AnimInterpolatorInfo::registerInterp(info); } }