From 9982f1f21bca3bb51ac7d31cede606beef5c0f67 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 18 Dec 2020 23:46:51 +0100 Subject: [PATCH] anim compression --- src/animation/AnimBlendAssociation.cpp | 8 +- src/animation/AnimBlendClumpData.h | 2 +- src/animation/AnimBlendHierarchy.cpp | 19 ++- src/animation/AnimBlendHierarchy.h | 4 +- src/animation/AnimBlendNode.cpp | 127 +++++++++++++- src/animation/AnimBlendNode.h | 4 + src/animation/AnimBlendSequence.cpp | 114 +++++++++++++ src/animation/AnimBlendSequence.h | 50 +++++- src/animation/AnimManager.cpp | 137 ++++++++------- src/animation/AnimManager.h | 2 +- src/animation/CutsceneMgr.cpp | 21 ++- src/animation/FrameUpdate.cpp | 222 +++++++++++++++++++++++++ src/animation/RpAnimBlend.cpp | 14 +- src/animation/RpAnimBlend.h | 3 + src/core/config.h | 5 + src/math/Quaternion.h | 5 + src/rw/MemoryHeap.cpp | 2 +- 17 files changed, 651 insertions(+), 88 deletions(-) diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp index 2f4739a6..b91b35ee 100644 --- a/src/animation/AnimBlendAssociation.cpp +++ b/src/animation/AnimBlendAssociation.cpp @@ -139,11 +139,15 @@ CAnimBlendAssociation::SetCurrentTime(float time) } CAnimManager::UncompressAnimation(hierarchy); - if(hierarchy->compressed2){ +#ifdef ANIM_COMPRESSION + // strangely PC has this but android doesn't + if(hierarchy->keepCompressed){ for(i = 0; i < numNodes; i++) if(nodes[i].sequence) nodes[i].SetupKeyFrameCompressed(); - }else{ + }else +#endif + { for(i = 0; i < numNodes; i++) if(nodes[i].sequence) nodes[i].FindKeyFrame(currentTime); diff --git a/src/animation/AnimBlendClumpData.h b/src/animation/AnimBlendClumpData.h index 315cbd8a..633fc7b9 100644 --- a/src/animation/AnimBlendClumpData.h +++ b/src/animation/AnimBlendClumpData.h @@ -12,7 +12,7 @@ struct AnimBlendFrameData VELOCITY_EXTRACTION = 8, VELOCITY_EXTRACTION_3D = 0x10, UPDATE_KEYFRAMES = 0x20, - UNK_COMPRESSED = 0x40, + COMPRESSED = 0x40 }; uint8 flag; diff --git a/src/animation/AnimBlendHierarchy.cpp b/src/animation/AnimBlendHierarchy.cpp index d3d6287a..3bbc1e04 100644 --- a/src/animation/AnimBlendHierarchy.cpp +++ b/src/animation/AnimBlendHierarchy.cpp @@ -65,10 +65,10 @@ CAnimBlendHierarchy::CalcTotalTimeCompressed(void) continue; #endif - totalLength = Max(totalLength, sequences[i].GetKeyFrameCompressed(sequences[i].numFrames-1)->deltaTime/60.0f); + totalLength = Max(totalLength, sequences[i].GetKeyFrameCompressed(sequences[i].numFrames-1)->GetDeltaTime()); for(j = sequences[i].numFrames-1; j >= 1; j--){ - KeyFrame *kf1 = sequences[i].GetKeyFrameCompressed(j); - KeyFrame *kf2 = sequences[i].GetKeyFrameCompressed(j-1); + KeyFrameCompressed *kf1 = sequences[i].GetKeyFrameCompressed(j); + KeyFrameCompressed *kf2 = sequences[i].GetKeyFrameCompressed(j-1); kf1->deltaTime -= kf2->deltaTime; } } @@ -94,6 +94,12 @@ CAnimBlendHierarchy::RemoveAnimSequences(void) void CAnimBlendHierarchy::Uncompress(void) { +#ifdef ANIM_COMPRESSION + int i; + assert(compressed); + for(i = 0; i < numSequences; i++) + sequences[i].Uncompress(); +#endif compressed = 0; if(totalLength == 0.0f){ RemoveQuaternionFlips(); @@ -104,6 +110,11 @@ CAnimBlendHierarchy::Uncompress(void) void CAnimBlendHierarchy::RemoveUncompressedData(void) { - // useless +#ifdef ANIM_COMPRESSION + int i; + assert(!compressed); + for(i = 0; i < numSequences; i++) + sequences[i].RemoveUncompressedData(); +#endif compressed = 1; } diff --git a/src/animation/AnimBlendHierarchy.h b/src/animation/AnimBlendHierarchy.h index b34ae210..815251b3 100644 --- a/src/animation/AnimBlendHierarchy.h +++ b/src/animation/AnimBlendHierarchy.h @@ -11,8 +11,8 @@ public: char name[24]; CAnimBlendSequence *sequences; int16 numSequences; - bool compressed; // not really used - bool compressed2; // not really used + bool compressed; + bool keepCompressed; float totalLength; CLink *linkPtr; diff --git a/src/animation/AnimBlendNode.cpp b/src/animation/AnimBlendNode.cpp index ac1328eb..62423004 100644 --- a/src/animation/AnimBlendNode.cpp +++ b/src/animation/AnimBlendNode.cpp @@ -47,6 +47,44 @@ CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight) return looped; } +bool +CAnimBlendNode::UpdateCompressed(CVector &trans, CQuaternion &rot, float weight) +{ + bool looped = false; + + trans = CVector(0.0f, 0.0f, 0.0f); + rot = CQuaternion(0.0f, 0.0f, 0.0f, 0.0f); + + if(association->IsRunning()){ + remainingTime -= association->timeStep; + if(remainingTime <= 0.0f) + looped = NextKeyFrameCompressed(); + } + + float blend = association->GetBlendAmount(weight); + if(blend > 0.0f){ + KeyFrameTransCompressed *kfA = (KeyFrameTransCompressed*)sequence->GetKeyFrameCompressed(frameA); + KeyFrameTransCompressed *kfB = (KeyFrameTransCompressed*)sequence->GetKeyFrameCompressed(frameB); + float t = kfA->deltaTime == 0 ? 0.0f : (kfA->GetDeltaTime() - remainingTime)/kfA->GetDeltaTime(); + if(sequence->type & CAnimBlendSequence::KF_TRANS){ + CVector transA, transB; + kfA->GetTranslation(&transA); + kfB->GetTranslation(&transB); + trans = transB + t*(transA - transB); + trans *= blend; + } + if(sequence->type & CAnimBlendSequence::KF_ROT){ + CQuaternion rotA, rotB; + kfA->GetRotation(&rotA); + kfB->GetRotation(&rotB); + rot.Slerp(rotB, rotA, theta, invSin, t); + rot *= blend; + } + } + + return looped; +} + bool CAnimBlendNode::NextKeyFrame(void) { @@ -84,6 +122,43 @@ CAnimBlendNode::NextKeyFrame(void) return looped; } +bool +CAnimBlendNode::NextKeyFrameCompressed(void) +{ + bool looped; + + if(sequence->numFrames <= 1) + return false; + + looped = false; + frameB = frameA; + + // Advance as long as we have to + while(remainingTime <= 0.0f){ + frameA++; + + if(frameA >= sequence->numFrames){ + // reached end of animation + if(!association->IsRepeating()){ + frameA--; + remainingTime = 0.0f; + return false; + } + looped = true; + frameA = 0; + } + + remainingTime += sequence->GetKeyFrameCompressed(frameA)->GetDeltaTime(); + } + + frameB = frameA - 1; + if(frameB < 0) + frameB += sequence->numFrames; + + CalcDeltasCompressed(); + return looped; +} + // Set animation to time t bool CAnimBlendNode::FindKeyFrame(float t) @@ -132,7 +207,7 @@ CAnimBlendNode::SetupKeyFrameCompressed(void) frameA = 0; remainingTime = 0.0f; }else - remainingTime = sequence->GetKeyFrameCompressed(frameA)->deltaTime/60.0f; + remainingTime = sequence->GetKeyFrameCompressed(frameA)->GetDeltaTime(); CalcDeltasCompressed(); return true; @@ -157,9 +232,17 @@ CAnimBlendNode::CalcDeltasCompressed(void) { if((sequence->type & CAnimBlendSequence::KF_ROT) == 0) return; - KeyFrame *kfA = sequence->GetKeyFrameCompressed(frameA); - KeyFrame *kfB = sequence->GetKeyFrameCompressed(frameB); - float cos = DotProduct(kfA->rotation, kfB->rotation); + KeyFrameCompressed *kfA = sequence->GetKeyFrameCompressed(frameA); + KeyFrameCompressed *kfB = sequence->GetKeyFrameCompressed(frameB); + CQuaternion rotA, rotB; + kfA->GetRotation(&rotA); + kfB->GetRotation(&rotB); + float cos = DotProduct(rotA, rotB); + if(cos < 0.0f){ + rotB *= -1.0f; + kfB->SetRotation(rotB); + } + cos = DotProduct(rotA, rotB); if(cos > 1.0f) cos = 1.0f; theta = Acos(cos); @@ -183,6 +266,26 @@ CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight) } } +void +CAnimBlendNode::GetCurrentTranslationCompressed(CVector &trans, float weight) +{ + trans = CVector(0.0f, 0.0f, 0.0f); + + float blend = association->GetBlendAmount(weight); + if(blend > 0.0f){ + KeyFrameTransCompressed *kfA = (KeyFrameTransCompressed*)sequence->GetKeyFrameCompressed(frameA); + KeyFrameTransCompressed *kfB = (KeyFrameTransCompressed*)sequence->GetKeyFrameCompressed(frameB); + float t = kfA->deltaTime == 0 ? 0.0f : (kfA->GetDeltaTime() - remainingTime)/kfA->GetDeltaTime(); + if(sequence->type & CAnimBlendSequence::KF_TRANS){ + CVector transA, transB; + kfA->GetTranslation(&transA); + kfB->GetTranslation(&transB); + trans = transB + t*(transA - transB); + trans *= blend; + } + } +} + void CAnimBlendNode::GetEndTranslation(CVector &trans, float weight) { @@ -195,3 +298,19 @@ CAnimBlendNode::GetEndTranslation(CVector &trans, float weight) trans = kf->translation * blend; } } + +void +CAnimBlendNode::GetEndTranslationCompressed(CVector &trans, float weight) +{ + trans = CVector(0.0f, 0.0f, 0.0f); + + float blend = association->GetBlendAmount(weight); + if(blend > 0.0f){ + KeyFrameTransCompressed *kf = (KeyFrameTransCompressed*)sequence->GetKeyFrameCompressed(sequence->numFrames-1); + if(sequence->type & CAnimBlendSequence::KF_TRANS){ + CVector trans; + kf->GetTranslation(&trans); + trans = trans * blend; + } + } +} diff --git a/src/animation/AnimBlendNode.h b/src/animation/AnimBlendNode.h index 9446e1ae..99a657ac 100644 --- a/src/animation/AnimBlendNode.h +++ b/src/animation/AnimBlendNode.h @@ -20,13 +20,17 @@ public: void Init(void); bool Update(CVector &trans, CQuaternion &rot, float weight); + bool UpdateCompressed(CVector &trans, CQuaternion &rot, float weight); bool NextKeyFrame(void); + bool NextKeyFrameCompressed(void); bool FindKeyFrame(float t); bool SetupKeyFrameCompressed(void); void CalcDeltas(void); void CalcDeltasCompressed(void); void GetCurrentTranslation(CVector &trans, float weight); + void GetCurrentTranslationCompressed(CVector &trans, float weight); void GetEndTranslation(CVector &trans, float weight); + void GetEndTranslationCompressed(CVector &trans, float weight); }; diff --git a/src/animation/AnimBlendSequence.cpp b/src/animation/AnimBlendSequence.cpp index a97dc980..c429ff43 100644 --- a/src/animation/AnimBlendSequence.cpp +++ b/src/animation/AnimBlendSequence.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "AnimBlendSequence.h" +#include "MemoryHeap.h" //--MIAMI: file done @@ -65,3 +66,116 @@ CAnimBlendSequence::RemoveQuaternionFlips(void) last = frame->rotation; } } + +void +CAnimBlendSequence::Uncompress(void) +{ + int i; + + if(numFrames == 0) + return; + + PUSH_MEMID(MEMID_ANIMATION); + + float rotScale = 1.0f/4096.0f; + float timeScale = 1.0f/60.0f; + float transScale = 1.0f/1024.0f; + if(type & KF_TRANS){ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameTrans)); + KeyFrameTransCompressed *ckf = (KeyFrameTransCompressed*)keyFramesCompressed; + KeyFrameTrans *kf = (KeyFrameTrans*)newKfs; + for(i = 0; i < numFrames; i++){ + kf->rotation.x = ckf->rot[0]*rotScale; + kf->rotation.y = ckf->rot[1]*rotScale; + kf->rotation.z = ckf->rot[2]*rotScale; + kf->rotation.w = ckf->rot[3]*rotScale; + kf->deltaTime = ckf->deltaTime*timeScale; + kf->translation.x = ckf->trans[0]*transScale; + kf->translation.y = ckf->trans[1]*transScale; + kf->translation.z = ckf->trans[2]*transScale; + kf++; + ckf++; + } + keyFrames = newKfs; + }else{ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrame)); + KeyFrameCompressed *ckf = (KeyFrameCompressed*)keyFramesCompressed; + KeyFrame *kf = (KeyFrame*)newKfs; + for(i = 0; i < numFrames; i++){ + kf->rotation.x = ckf->rot[0]*rotScale; + kf->rotation.y = ckf->rot[1]*rotScale; + kf->rotation.z = ckf->rot[2]*rotScale; + kf->rotation.w = ckf->rot[3]*rotScale; + kf->deltaTime = ckf->deltaTime*timeScale; + kf++; + ckf++; + } + keyFrames = newKfs; + } + REGISTER_MEMPTR(&keyFrames); + + RwFree(keyFramesCompressed); + keyFramesCompressed = nil; + + POP_MEMID(); +} + +void +CAnimBlendSequence::CompressKeyframes(void) +{ + int i; + + if(numFrames == 0) + return; + + PUSH_MEMID(MEMID_ANIMATION); + + float rotScale = 4096.0f; + float timeScale = 60.0f; + float transScale = 1024.0f; + if(type & KF_TRANS){ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameTransCompressed)); + KeyFrameTransCompressed *ckf = (KeyFrameTransCompressed*)newKfs; + KeyFrameTrans *kf = (KeyFrameTrans*)keyFrames; + for(i = 0; i < numFrames; i++){ + ckf->rot[0] = kf->rotation.x*rotScale; + ckf->rot[1] = kf->rotation.y*rotScale; + ckf->rot[2] = kf->rotation.z*rotScale; + ckf->rot[3] = kf->rotation.w*rotScale; + ckf->deltaTime = kf->deltaTime*timeScale + 0.5f; + ckf->trans[0] = kf->translation.x*transScale; + ckf->trans[1] = kf->translation.y*transScale; + ckf->trans[2] = kf->translation.z*transScale; + kf++; + ckf++; + } + keyFramesCompressed = newKfs; + }else{ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameCompressed)); + KeyFrameCompressed *ckf = (KeyFrameCompressed*)newKfs; + KeyFrame *kf = (KeyFrame*)keyFrames; + for(i = 0; i < numFrames; i++){ + ckf->rot[0] = kf->rotation.x*rotScale; + ckf->rot[1] = kf->rotation.y*rotScale; + ckf->rot[2] = kf->rotation.z*rotScale; + ckf->rot[3] = kf->rotation.w*rotScale; + ckf->deltaTime = kf->deltaTime*timeScale + 0.5f; + kf++; + ckf++; + } + keyFramesCompressed = newKfs; + } + REGISTER_MEMPTR(&keyFramesCompressed); + + POP_MEMID(); +} + +void +CAnimBlendSequence::RemoveUncompressedData(void) +{ + if(numFrames == 0) + return; + CompressKeyframes(); + RwFree(keyFrames); + keyFrames = nil; +} diff --git a/src/animation/AnimBlendSequence.h b/src/animation/AnimBlendSequence.h index 4dce3b13..b370c5c6 100644 --- a/src/animation/AnimBlendSequence.h +++ b/src/animation/AnimBlendSequence.h @@ -12,6 +12,43 @@ struct KeyFrameTrans : KeyFrame { CVector translation; }; +struct KeyFrameCompressed { + int16 rot[4]; // 4096 + int16 deltaTime; // 60 + + void GetRotation(CQuaternion *quat){ + float scale = 1.0f/4096.0f; + quat->x = rot[0]*scale; + quat->y = rot[1]*scale; + quat->z = rot[2]*scale; + quat->w = rot[3]*scale; + } + void SetRotation(const CQuaternion &quat){ + rot[0] = quat.x * 4096.0f; + rot[1] = quat.y * 4096.0f; + rot[2] = quat.z * 4096.0f; + rot[3] = quat.w * 4096.0f; + } + float GetDeltaTime(void) { return deltaTime/60.0f; } + void SetTime(float t) { deltaTime = t*60.0f + 0.5f; } +}; + +struct KeyFrameTransCompressed : KeyFrameCompressed { + int16 trans[3]; // 1024 + + void GetTranslation(CVector *vec) { + float scale = 1.0f/1024.0f; + vec->x = trans[0]*scale; + vec->y = trans[1]*scale; + vec->z = trans[2]*scale; + } + void SetTranslation(const CVector &vec){ + trans[0] = vec.x*1024.0f; + trans[1] = vec.y*1024.0f; + trans[2] = vec.z*1024.0f; + } +}; + // The sequence of key frames of one animated node class CAnimBlendSequence @@ -38,16 +75,15 @@ public: &((KeyFrameTrans*)keyFrames)[n] : &((KeyFrame*)keyFrames)[n]; } - KeyFrame *GetKeyFrameCompressed(int n) { + KeyFrameCompressed *GetKeyFrameCompressed(int n) { return type & KF_TRANS ? - &((KeyFrameTrans*)keyFramesCompressed)[n] : - &((KeyFrame*)keyFramesCompressed)[n]; + &((KeyFrameTransCompressed*)keyFramesCompressed)[n] : + &((KeyFrameCompressed*)keyFramesCompressed)[n]; } bool HasTranslation(void) { return !!(type & KF_TRANS); } - // TODO? these are unused -// void Uncompress(void); -// void CompressKeyframes(void); -// void RemoveUncompressedData(void); + void Uncompress(void); + void CompressKeyframes(void); + void RemoveUncompressedData(void); void SetBoneTag(int tag) { boneTag = tag; } }; diff --git a/src/animation/AnimManager.cpp b/src/animation/AnimManager.cpp index 0aa6486b..edb7f877 100644 --- a/src/animation/AnimManager.cpp +++ b/src/animation/AnimManager.cpp @@ -992,7 +992,7 @@ CAnimManager::Shutdown(void) void CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier) { - if(hier->compressed2){ + if(hier->keepCompressed){ if(hier->totalLength == 0.0f) hier->CalcTotalTimeCompressed(); }else{ @@ -1275,7 +1275,7 @@ CAnimManager::LoadAnimFile(const char *filename) //--MIAMI: done void -CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32]) +CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*uncompressedAnims)[32]) { #define ROUNDSIZE(x) if((x) & 3) (x) += 4 - ((x)&3) struct IfpHeader { @@ -1320,16 +1320,22 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32] RwStreamRead(stream, buf, name.size); hier->SetName(buf); - // Unimplemented uncompressed anim thing - if (somename) { - for (int i = 0; somename[i][0]; i++) { - if (!CGeneral::faststricmp(somename[i], hier->name)) +#ifdef ANIM_COMPRESSION + bool compressHier = compress; +#else + bool compressHier = false; +#endif + if (uncompressedAnims) { + for (int i = 0; uncompressedAnims[i][0]; i++) { + if (!CGeneral::faststricmp(uncompressedAnims[i], hier->name)){ debug("Loading %s uncompressed\n", hier->name); + compressHier = false; + } } } - hier->compressed = false; - hier->compressed2 = false; + hier->compressed = compressHier; + hier->keepCompressed = false; // DG info has number of nodes/sequences RwStreamRead(stream, (char*)&dgan, sizeof(IfpHeader)); @@ -1349,67 +1355,86 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32] ROUNDSIZE(anim.size); RwStreamRead(stream, buf, anim.size); int numFrames = *(int*)(buf+28); + seq->SetName(buf); if(anim.size == 44) seq->SetBoneTag(*(int*)(buf+40)); - seq->SetName(buf); if(numFrames == 0) continue; + bool hasScale = false; + bool hasTranslation = false; RwStreamRead(stream, &info, sizeof(info)); - if(strncmp(info.ident, "KR00", 4) == 0){ - seq->SetNumFrames(numFrames, false, false); - KeyFrame *kf = seq->GetKeyFrame(0); - if (strstr(seq->name, "L Toe")) - debug("anim %s has toe keyframes\n", hier->name); // , seq->name); - - for(l = 0; l < numFrames; l++, kf++){ - RwStreamRead(stream, buf, 0x14); - kf->rotation.x = -fbuf[0]; - kf->rotation.y = -fbuf[1]; - kf->rotation.z = -fbuf[2]; - kf->rotation.w = fbuf[3]; - kf->deltaTime = fbuf[4]; // absolute time here - } + if(strncmp(info.ident, "KRTS", 4) == 0){ + hasScale = true; + seq->SetNumFrames(numFrames, true, compressHier); }else if(strncmp(info.ident, "KRT0", 4) == 0){ - seq->SetNumFrames(numFrames, true, false); - KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0); - if (strstr(seq->name, "L Toe")) - debug("anim %s has toe keyframes\n", hier->name); // , seq->name); + hasTranslation = true; + seq->SetNumFrames(numFrames, true, compressHier); + }else if(strncmp(info.ident, "KR00", 4) == 0){ + seq->SetNumFrames(numFrames, false, compressHier); + } + if(strstr(seq->name, "L Toe")) + debug("anim %s has toe keyframes\n", hier->name); // BUG: seq->name - for(l = 0; l < numFrames; l++, kf++){ - RwStreamRead(stream, buf, 0x20); - kf->rotation.x = -fbuf[0]; - kf->rotation.y = -fbuf[1]; - kf->rotation.z = -fbuf[2]; - kf->rotation.w = fbuf[3]; - kf->translation.x = fbuf[4]; - kf->translation.y = fbuf[5]; - kf->translation.z = fbuf[6]; - kf->deltaTime = fbuf[7]; // absolute time here - } - }else if(strncmp(info.ident, "KRTS", 4) == 0){ - seq->SetNumFrames(numFrames, true, false); - KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0); - if (strstr(seq->name, "L Toe")) - debug("anim %s has toe keyframes\n", hier->name); // , seq->name); - - for(l = 0; l < numFrames; l++, kf++){ + for(l = 0; l < numFrames; l++){ + if(hasScale){ RwStreamRead(stream, buf, 0x2C); - kf->rotation.x = -fbuf[0]; - kf->rotation.y = -fbuf[1]; - kf->rotation.z = -fbuf[2]; - kf->rotation.w = fbuf[3]; - kf->translation.x = fbuf[4]; - kf->translation.y = fbuf[5]; - kf->translation.z = fbuf[6]; - // scaling ignored - kf->deltaTime = fbuf[10]; // absolute time here + CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]); + rot.Invert(); + CVector trans(fbuf[4], fbuf[5], fbuf[6]); + + if(compressHier){ + KeyFrameTransCompressed *kf = (KeyFrameTransCompressed*)seq->GetKeyFrameCompressed(l); + kf->SetRotation(rot); + kf->SetTranslation(trans); + // scaling ignored + kf->SetTime(fbuf[10]); // absolute time here + }else{ + KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(l); + kf->rotation = rot; + kf->translation = trans; + // scaling ignored + kf->deltaTime = fbuf[10]; // absolute time here + } + }else if(hasTranslation){ + RwStreamRead(stream, buf, 0x20); + CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]); + rot.Invert(); + CVector trans(fbuf[4], fbuf[5], fbuf[6]); + + if(compressHier){ + KeyFrameTransCompressed *kf = (KeyFrameTransCompressed*)seq->GetKeyFrameCompressed(l); + kf->SetRotation(rot); + kf->SetTranslation(trans); + kf->SetTime(fbuf[7]); // absolute time here + }else{ + KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(l); + kf->rotation = rot; + kf->translation = trans; + kf->deltaTime = fbuf[7]; // absolute time here + } + }else{ + RwStreamRead(stream, buf, 0x14); + CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]); + rot.Invert(); + + if(compressHier){ + KeyFrameCompressed *kf = (KeyFrameCompressed*)seq->GetKeyFrameCompressed(l); + kf->SetRotation(rot); + kf->SetTime(fbuf[4]); // absolute time here + }else{ + KeyFrame *kf = (KeyFrame*)seq->GetKeyFrame(l); + kf->rotation = rot; + kf->deltaTime = fbuf[4]; // absolute time here + } } } } - hier->RemoveQuaternionFlips(); - hier->CalcTotalTime(); + if(!compressHier){ + hier->RemoveQuaternionFlips(); + hier->CalcTotalTime(); + } } if(animIndex > ms_numAnimations) ms_numAnimations = animIndex; diff --git a/src/animation/AnimManager.h b/src/animation/AnimManager.h index a55577b1..8333b865 100644 --- a/src/animation/AnimManager.h +++ b/src/animation/AnimManager.h @@ -136,7 +136,7 @@ public: static CAnimBlendAssociation *BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId, float delta); static void LoadAnimFiles(void); static void LoadAnimFile(const char *filename); - static void LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32] = nil); + static void LoadAnimFile(RwStream *stream, bool compress, char (*uncompressedAnims)[32] = nil); static void CreateAnimAssocGroups(void); static void RemoveLastAnimFile(void); static CAnimBlendAssocGroup* GetAnimAssocGroups(void) { return ms_aAnimAssocGroups; } diff --git a/src/animation/CutsceneMgr.cpp b/src/animation/CutsceneMgr.cpp index 64951a87..b312236b 100644 --- a/src/animation/CutsceneMgr.cpp +++ b/src/animation/CutsceneMgr.cpp @@ -291,12 +291,15 @@ CCutsceneMgr::SetupCutsceneToStart(void) if (ms_pCutsceneObjects[i]->m_pAttachTo != nil) { pAnimBlendAssoc->flags &= (~ASSOC_HAS_TRANSLATION); } else { - KeyFrameTrans* keyFrames; - if (pAnimBlendAssoc->hierarchy->IsCompressed()) - keyFrames = ((KeyFrameTrans*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrameCompressed(0)); - else - keyFrames = ((KeyFrameTrans*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrame(0)); - ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + keyFrames->translation); + if (pAnimBlendAssoc->hierarchy->IsCompressed()){ + KeyFrameTransCompressed *keyFrames = ((KeyFrameTransCompressed*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrameCompressed(0)); + CVector trans; + keyFrames->GetTranslation(&trans); + ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + trans); + }else{ + KeyFrameTrans *keyFrames = ((KeyFrameTrans*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrame(0)); + ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + keyFrames->translation); + } } pAnimBlendAssoc->SetRun(); } else { @@ -331,7 +334,7 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject) } if (pNewAnim->hierarchy->IsCompressed()) - pNewAnim->hierarchy->compressed2 = true; + pNewAnim->hierarchy->keepCompressed = true; CStreaming::ImGonnaUseStreamingMemory(); pNewAnim = ms_cutsceneAssociations.CopyAnimation(animName); @@ -344,8 +347,8 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject) pAnimBlendClumpData = *RPANIMBLENDCLUMPDATA(pObject->m_rwObject); pAnimBlendClumpData->link.Prepend(&pNewAnim->link); - if (pNewAnim->hierarchy->compressed2) - pAnimBlendClumpData->frames->flag |= AnimBlendFrameData::UNK_COMPRESSED; + if (pNewAnim->hierarchy->keepCompressed) + pAnimBlendClumpData->frames->flag |= AnimBlendFrameData::COMPRESSED; } void diff --git a/src/animation/FrameUpdate.cpp b/src/animation/FrameUpdate.cpp index faeea709..a085fd4b 100644 --- a/src/animation/FrameUpdate.cpp +++ b/src/animation/FrameUpdate.cpp @@ -19,6 +19,9 @@ void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackWithVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackWith3dVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackNonSkinnedCompressed(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinnedCompressed(AnimBlendFrameData *frame, void *arg); + void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg) { @@ -446,3 +449,222 @@ FrameUpdateCallBackOffscreen(AnimBlendFrameData *frame, void *arg) if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && gpAnimBlendClump->velocity) FrameUpdateCallBackWithVelocityExtractionSkinned(frame, arg); } + + +void +FrameUpdateCallBackNonSkinnedCompressed(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + CVector trans(0.0f, 0.0f, 0.0f); + CVector cur(0.0f, 0.0f, 0.0f); + CVector end(0.0f, 0.0f, 0.0f); + bool looped = false; + RwMatrix *mat = RwFrameGetMatrix(frame->frame); + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && + gpAnimBlendClump->velocity){ + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->sequence->HasTranslation()){ + if((*node)->association->HasTranslation()){ + (*node)->GetCurrentTranslationCompressed(vec, 1.0f-totalBlendAmount); + cur += vec; + } + } + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + bool nodelooped = (*node)->UpdateCompressed(vec, q, 1.0f-totalBlendAmount); +#ifdef FIX_BUGS + if(DotProduct(rot, q) < 0.0f) + rot -= q; + else +#endif + rot += q; + if((*node)->sequence->HasTranslation()){ + pos += vec; + if((*node)->association->HasTranslation()){ + trans += vec; + looped |= nodelooped; + if(nodelooped){ + (*node)->GetEndTranslationCompressed(vec, 1.0f-totalBlendAmount); + end += vec; + } + } + } + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + RwMatrixSetIdentity(mat); + rot.Normalise(); + rot.Get(mat); + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + *gpAnimBlendClump->velocity = trans - cur; + if(looped) + *gpAnimBlendClump->velocity += end; + mat->pos.x = (pos - trans).x + frame->resetPos.x; + mat->pos.y = (pos - trans).y + frame->resetPos.y; + mat->pos.z = (pos - trans).z + frame->resetPos.z; + } + RwMatrixUpdate(mat); + }else{ + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + (*node)->UpdateCompressed(vec, q, 1.0f-totalBlendAmount); + if((*node)->sequence->HasTranslation()) + pos += vec; +#ifdef FIX_BUGS + if(DotProduct(rot, q) < 0.0f) + rot -= q; + else +#endif + rot += q; + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + RwMatrixSetIdentity(mat); + rot.Normalise(); + rot.Get(mat); + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + mat->pos.x = pos.x; + mat->pos.y = pos.y; + mat->pos.z = pos.z; + mat->pos.x += frame->resetPos.x; + mat->pos.y += frame->resetPos.y; + mat->pos.z += frame->resetPos.z; + } + RwMatrixUpdate(mat); + } +} + +void +FrameUpdateCallBackSkinnedCompressed(AnimBlendFrameData *frame, void *arg) +{ + CVector vec, pos(0.0f, 0.0f, 0.0f); + CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f); + float totalBlendAmount = 0.0f; + CVector trans(0.0f, 0.0f, 0.0f); + CVector cur(0.0f, 0.0f, 0.0f); + CVector end(0.0f, 0.0f, 0.0f); + bool looped = false; + RpHAnimStdInterpFrame *xform = frame->hanimFrame; + CAnimBlendNode **node; + AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg; + + if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && + gpAnimBlendClump->velocity){ + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->sequence->HasTranslation()){ + if((*node)->association->HasTranslation()){ + (*node)->GetCurrentTranslationCompressed(vec, 1.0f-totalBlendAmount); + cur += vec; + } + } + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + bool nodelooped = (*node)->UpdateCompressed(vec, q, 1.0f-totalBlendAmount); +#ifdef FIX_BUGS + if(DotProduct(rot, q) < 0.0f) + rot -= q; + else +#endif + rot += q; + if((*node)->sequence->HasTranslation()){ + pos += vec; + if((*node)->association->HasTranslation()){ + trans += vec; + looped |= nodelooped; + if(nodelooped){ + (*node)->GetEndTranslationCompressed(vec, 1.0f-totalBlendAmount); + end += vec; + } + } + } + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + *gpAnimBlendClump->velocity = trans - cur; + if(looped) + *gpAnimBlendClump->velocity += end; + xform->t.x = (pos - trans).x + frame->resetPos.x; + xform->t.y = (pos - trans).y + frame->resetPos.y; + xform->t.z = (pos - trans).z + frame->resetPos.z; + } + }else{ + float transBlendAmount = 0.0f; + + if(updateData->foobar) + for(node = updateData->nodes; *node; node++) + if((*node)->sequence && (*node)->association->IsPartial()) + totalBlendAmount += (*node)->association->blendAmount; + + for(node = updateData->nodes; *node; node++){ + if((*node)->sequence){ + (*node)->UpdateCompressed(vec, q, 1.0f-totalBlendAmount); + if((*node)->sequence->HasTranslation()){ + pos += vec; + transBlendAmount += (*node)->association->blendAmount; + } + if(DotProduct(rot, q) < 0.0f) + rot -= q; + else + rot += q; + } + ++*node; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){ + rot.Normalise(); + xform->q.imag.x = rot.x; + xform->q.imag.y = rot.y; + xform->q.imag.z = rot.z; + xform->q.real = rot.w; + } + + if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){ + xform->t.x = transBlendAmount*pos.x; + xform->t.y = transBlendAmount*pos.y; + xform->t.z = transBlendAmount*pos.z; + xform->t.x += (1.0f-transBlendAmount)*frame->resetPos.x; + xform->t.y += (1.0f-transBlendAmount)*frame->resetPos.y; + xform->t.z += (1.0f-transBlendAmount)*frame->resetPos.z; + } + } +} diff --git a/src/animation/RpAnimBlend.cpp b/src/animation/RpAnimBlend.cpp index e93615b7..c4103dbf 100644 --- a/src/animation/RpAnimBlend.cpp +++ b/src/animation/RpAnimBlend.cpp @@ -8,6 +8,7 @@ #include "AnimBlendClumpData.h" #include "AnimBlendHierarchy.h" #include "AnimBlendAssociation.h" +#include "AnimManager.h" #include "RpAnimBlend.h" #include "PedModelInfo.h" @@ -443,6 +444,9 @@ RpAnimBlendNodeUpdateKeyframes(AnimBlendFrameData *frames, AnimBlendFrameUpdateD } } +// TODO: +// CAnimBlendClumpData::LoadFramesIntoSPR +// CAnimBlendClumpData::ForAllFramesInSPR void RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender) { @@ -466,7 +470,7 @@ RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender) assoc = CAnimBlendAssociation::FromLink(link); if(assoc->UpdateBlend(timeDelta)){ if(assoc->hierarchy->sequences){ - //CAnimManager::UncompressAnimation(v6->hierarchy) + CAnimManager::UncompressAnimation(assoc->hierarchy); if(i < 11) updateData.nodes[i++] = assoc->GetNode(0); if(assoc->flags & ASSOC_MOVEMENT){ @@ -486,6 +490,14 @@ RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender) updateData.nodes[i] = nil; +#ifdef ANIM_COMPRESSION + if(clumpData->frames[0].flag & AnimBlendFrameData::COMPRESSED){ + if(IsClumpSkinned(clump)) + clumpData->ForAllFrames(FrameUpdateCallBackSkinnedCompressed, &updateData); + else + clumpData->ForAllFrames(FrameUpdateCallBackNonSkinnedCompressed, &updateData); + }else +#endif if(doRender){ if(clumpData->frames[0].flag & AnimBlendFrameData::UPDATE_KEYFRAMES) RpAnimBlendNodeUpdateKeyframes(clumpData->frames, &updateData, clumpData->numFrames); diff --git a/src/animation/RpAnimBlend.h b/src/animation/RpAnimBlend.h index d0f7a114..6e9e0f0f 100644 --- a/src/animation/RpAnimBlend.h +++ b/src/animation/RpAnimBlend.h @@ -43,3 +43,6 @@ extern CAnimBlendClumpData *gpAnimBlendClump; void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackOffscreen(AnimBlendFrameData *frame, void *arg); + +void FrameUpdateCallBackNonSkinnedCompressed(AnimBlendFrameData *frame, void *arg); +void FrameUpdateCallBackSkinnedCompressed(AnimBlendFrameData *frame, void *arg); diff --git a/src/core/config.h b/src/core/config.h index 0079eb38..0780eb7a 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -192,6 +192,11 @@ enum Config { // those infamous texts #define DRAW_GAME_VERSION_TEXT +// Memory allocation and compression +// #define USE_CUSTOM_ALLOCATOR // use CMemoryHeap for allocation. use with care, not finished yet +//#define COMPRESSED_COL_VECTORS // use compressed vectors for collision vertices +//#define ANIM_COMPRESSION // only keep most recently used anims uncompressed + #if defined GTA_PS2 # define GTA_PS2_STUFF # define RANDOMSPLASH diff --git a/src/math/Quaternion.h b/src/math/Quaternion.h index a5a34626..47c94f7c 100644 --- a/src/math/Quaternion.h +++ b/src/math/Quaternion.h @@ -12,6 +12,11 @@ public: float MagnitudeSqr(void) const { return x*x + y*y + z*z + w*w; } void Normalise(void); void Multiply(const CQuaternion &q1, const CQuaternion &q2); + void Invert(void){ // Conjugate would have been a better name + x = -x; + y = -y; + z = -z; + } const CQuaternion &operator+=(CQuaternion const &right) { x += right.x; diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp index 45dd1fc2..285a7c70 100644 --- a/src/rw/MemoryHeap.cpp +++ b/src/rw/MemoryHeap.cpp @@ -341,7 +341,7 @@ CMemoryHeap::TidyHeap(void) } } -// +// MIAMI: this is empty void CMemoryHeap::RegisterMemPointer(void *ptr) {