anim compression

This commit is contained in:
aap 2020-12-18 23:46:51 +01:00
parent 73d080bcc8
commit 9982f1f21b
17 changed files with 651 additions and 88 deletions

View File

@ -139,11 +139,15 @@ CAnimBlendAssociation::SetCurrentTime(float time)
} }
CAnimManager::UncompressAnimation(hierarchy); 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++) for(i = 0; i < numNodes; i++)
if(nodes[i].sequence) if(nodes[i].sequence)
nodes[i].SetupKeyFrameCompressed(); nodes[i].SetupKeyFrameCompressed();
}else{ }else
#endif
{
for(i = 0; i < numNodes; i++) for(i = 0; i < numNodes; i++)
if(nodes[i].sequence) if(nodes[i].sequence)
nodes[i].FindKeyFrame(currentTime); nodes[i].FindKeyFrame(currentTime);

View File

@ -12,7 +12,7 @@ struct AnimBlendFrameData
VELOCITY_EXTRACTION = 8, VELOCITY_EXTRACTION = 8,
VELOCITY_EXTRACTION_3D = 0x10, VELOCITY_EXTRACTION_3D = 0x10,
UPDATE_KEYFRAMES = 0x20, UPDATE_KEYFRAMES = 0x20,
UNK_COMPRESSED = 0x40, COMPRESSED = 0x40
}; };
uint8 flag; uint8 flag;

View File

@ -65,10 +65,10 @@ CAnimBlendHierarchy::CalcTotalTimeCompressed(void)
continue; continue;
#endif #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--){ for(j = sequences[i].numFrames-1; j >= 1; j--){
KeyFrame *kf1 = sequences[i].GetKeyFrameCompressed(j); KeyFrameCompressed *kf1 = sequences[i].GetKeyFrameCompressed(j);
KeyFrame *kf2 = sequences[i].GetKeyFrameCompressed(j-1); KeyFrameCompressed *kf2 = sequences[i].GetKeyFrameCompressed(j-1);
kf1->deltaTime -= kf2->deltaTime; kf1->deltaTime -= kf2->deltaTime;
} }
} }
@ -94,6 +94,12 @@ CAnimBlendHierarchy::RemoveAnimSequences(void)
void void
CAnimBlendHierarchy::Uncompress(void) CAnimBlendHierarchy::Uncompress(void)
{ {
#ifdef ANIM_COMPRESSION
int i;
assert(compressed);
for(i = 0; i < numSequences; i++)
sequences[i].Uncompress();
#endif
compressed = 0; compressed = 0;
if(totalLength == 0.0f){ if(totalLength == 0.0f){
RemoveQuaternionFlips(); RemoveQuaternionFlips();
@ -104,6 +110,11 @@ CAnimBlendHierarchy::Uncompress(void)
void void
CAnimBlendHierarchy::RemoveUncompressedData(void) CAnimBlendHierarchy::RemoveUncompressedData(void)
{ {
// useless #ifdef ANIM_COMPRESSION
int i;
assert(!compressed);
for(i = 0; i < numSequences; i++)
sequences[i].RemoveUncompressedData();
#endif
compressed = 1; compressed = 1;
} }

View File

@ -11,8 +11,8 @@ public:
char name[24]; char name[24];
CAnimBlendSequence *sequences; CAnimBlendSequence *sequences;
int16 numSequences; int16 numSequences;
bool compressed; // not really used bool compressed;
bool compressed2; // not really used bool keepCompressed;
float totalLength; float totalLength;
CLink<CAnimBlendHierarchy*> *linkPtr; CLink<CAnimBlendHierarchy*> *linkPtr;

View File

@ -47,6 +47,44 @@ CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight)
return looped; 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 bool
CAnimBlendNode::NextKeyFrame(void) CAnimBlendNode::NextKeyFrame(void)
{ {
@ -84,6 +122,43 @@ CAnimBlendNode::NextKeyFrame(void)
return looped; 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 // Set animation to time t
bool bool
CAnimBlendNode::FindKeyFrame(float t) CAnimBlendNode::FindKeyFrame(float t)
@ -132,7 +207,7 @@ CAnimBlendNode::SetupKeyFrameCompressed(void)
frameA = 0; frameA = 0;
remainingTime = 0.0f; remainingTime = 0.0f;
}else }else
remainingTime = sequence->GetKeyFrameCompressed(frameA)->deltaTime/60.0f; remainingTime = sequence->GetKeyFrameCompressed(frameA)->GetDeltaTime();
CalcDeltasCompressed(); CalcDeltasCompressed();
return true; return true;
@ -157,9 +232,17 @@ CAnimBlendNode::CalcDeltasCompressed(void)
{ {
if((sequence->type & CAnimBlendSequence::KF_ROT) == 0) if((sequence->type & CAnimBlendSequence::KF_ROT) == 0)
return; return;
KeyFrame *kfA = sequence->GetKeyFrameCompressed(frameA); KeyFrameCompressed *kfA = sequence->GetKeyFrameCompressed(frameA);
KeyFrame *kfB = sequence->GetKeyFrameCompressed(frameB); KeyFrameCompressed *kfB = sequence->GetKeyFrameCompressed(frameB);
float cos = DotProduct(kfA->rotation, kfB->rotation); 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) if(cos > 1.0f)
cos = 1.0f; cos = 1.0f;
theta = Acos(cos); 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 void
CAnimBlendNode::GetEndTranslation(CVector &trans, float weight) CAnimBlendNode::GetEndTranslation(CVector &trans, float weight)
{ {
@ -195,3 +298,19 @@ CAnimBlendNode::GetEndTranslation(CVector &trans, float weight)
trans = kf->translation * blend; 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;
}
}
}

View File

@ -20,13 +20,17 @@ public:
void Init(void); void Init(void);
bool Update(CVector &trans, CQuaternion &rot, float weight); bool Update(CVector &trans, CQuaternion &rot, float weight);
bool UpdateCompressed(CVector &trans, CQuaternion &rot, float weight);
bool NextKeyFrame(void); bool NextKeyFrame(void);
bool NextKeyFrameCompressed(void);
bool FindKeyFrame(float t); bool FindKeyFrame(float t);
bool SetupKeyFrameCompressed(void); bool SetupKeyFrameCompressed(void);
void CalcDeltas(void); void CalcDeltas(void);
void CalcDeltasCompressed(void); void CalcDeltasCompressed(void);
void GetCurrentTranslation(CVector &trans, float weight); void GetCurrentTranslation(CVector &trans, float weight);
void GetCurrentTranslationCompressed(CVector &trans, float weight);
void GetEndTranslation(CVector &trans, float weight); void GetEndTranslation(CVector &trans, float weight);
void GetEndTranslationCompressed(CVector &trans, float weight);
}; };

View File

@ -1,6 +1,7 @@
#include "common.h" #include "common.h"
#include "AnimBlendSequence.h" #include "AnimBlendSequence.h"
#include "MemoryHeap.h"
//--MIAMI: file done //--MIAMI: file done
@ -65,3 +66,116 @@ CAnimBlendSequence::RemoveQuaternionFlips(void)
last = frame->rotation; 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;
}

View File

@ -12,6 +12,43 @@ struct KeyFrameTrans : KeyFrame {
CVector translation; 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 // The sequence of key frames of one animated node
class CAnimBlendSequence class CAnimBlendSequence
@ -38,16 +75,15 @@ public:
&((KeyFrameTrans*)keyFrames)[n] : &((KeyFrameTrans*)keyFrames)[n] :
&((KeyFrame*)keyFrames)[n]; &((KeyFrame*)keyFrames)[n];
} }
KeyFrame *GetKeyFrameCompressed(int n) { KeyFrameCompressed *GetKeyFrameCompressed(int n) {
return type & KF_TRANS ? return type & KF_TRANS ?
&((KeyFrameTrans*)keyFramesCompressed)[n] : &((KeyFrameTransCompressed*)keyFramesCompressed)[n] :
&((KeyFrame*)keyFramesCompressed)[n]; &((KeyFrameCompressed*)keyFramesCompressed)[n];
} }
bool HasTranslation(void) { return !!(type & KF_TRANS); } bool HasTranslation(void) { return !!(type & KF_TRANS); }
// TODO? these are unused void Uncompress(void);
// void Uncompress(void); void CompressKeyframes(void);
// void CompressKeyframes(void); void RemoveUncompressedData(void);
// void RemoveUncompressedData(void);
void SetBoneTag(int tag) { boneTag = tag; } void SetBoneTag(int tag) { boneTag = tag; }
}; };

View File

@ -992,7 +992,7 @@ CAnimManager::Shutdown(void)
void void
CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier) CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier)
{ {
if(hier->compressed2){ if(hier->keepCompressed){
if(hier->totalLength == 0.0f) if(hier->totalLength == 0.0f)
hier->CalcTotalTimeCompressed(); hier->CalcTotalTimeCompressed();
}else{ }else{
@ -1275,7 +1275,7 @@ CAnimManager::LoadAnimFile(const char *filename)
//--MIAMI: done //--MIAMI: done
void 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) #define ROUNDSIZE(x) if((x) & 3) (x) += 4 - ((x)&3)
struct IfpHeader { struct IfpHeader {
@ -1320,16 +1320,22 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32]
RwStreamRead(stream, buf, name.size); RwStreamRead(stream, buf, name.size);
hier->SetName(buf); hier->SetName(buf);
// Unimplemented uncompressed anim thing #ifdef ANIM_COMPRESSION
if (somename) { bool compressHier = compress;
for (int i = 0; somename[i][0]; i++) { #else
if (!CGeneral::faststricmp(somename[i], hier->name)) 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); debug("Loading %s uncompressed\n", hier->name);
compressHier = false;
}
} }
} }
hier->compressed = false; hier->compressed = compressHier;
hier->compressed2 = false; hier->keepCompressed = false;
// DG info has number of nodes/sequences // DG info has number of nodes/sequences
RwStreamRead(stream, (char*)&dgan, sizeof(IfpHeader)); RwStreamRead(stream, (char*)&dgan, sizeof(IfpHeader));
@ -1349,68 +1355,87 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32]
ROUNDSIZE(anim.size); ROUNDSIZE(anim.size);
RwStreamRead(stream, buf, anim.size); RwStreamRead(stream, buf, anim.size);
int numFrames = *(int*)(buf+28); int numFrames = *(int*)(buf+28);
seq->SetName(buf);
if(anim.size == 44) if(anim.size == 44)
seq->SetBoneTag(*(int*)(buf+40)); seq->SetBoneTag(*(int*)(buf+40));
seq->SetName(buf);
if(numFrames == 0) if(numFrames == 0)
continue; continue;
bool hasScale = false;
bool hasTranslation = false;
RwStreamRead(stream, &info, sizeof(info)); RwStreamRead(stream, &info, sizeof(info));
if(strncmp(info.ident, "KR00", 4) == 0){ if(strncmp(info.ident, "KRTS", 4) == 0){
seq->SetNumFrames(numFrames, false, false); hasScale = true;
KeyFrame *kf = seq->GetKeyFrame(0); seq->SetNumFrames(numFrames, true, compressHier);
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
}
}else if(strncmp(info.ident, "KRT0", 4) == 0){ }else if(strncmp(info.ident, "KRT0", 4) == 0){
seq->SetNumFrames(numFrames, true, false); hasTranslation = true;
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0); seq->SetNumFrames(numFrames, true, compressHier);
if (strstr(seq->name, "L Toe")) }else if(strncmp(info.ident, "KR00", 4) == 0){
debug("anim %s has toe keyframes\n", hier->name); // , seq->name); seq->SetNumFrames(numFrames, false, compressHier);
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){ if(strstr(seq->name, "L Toe"))
seq->SetNumFrames(numFrames, true, false); debug("anim %s has toe keyframes\n", hier->name); // BUG: seq->name
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); RwStreamRead(stream, buf, 0x2C);
kf->rotation.x = -fbuf[0]; CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]);
kf->rotation.y = -fbuf[1]; rot.Invert();
kf->rotation.z = -fbuf[2]; CVector trans(fbuf[4], fbuf[5], fbuf[6]);
kf->rotation.w = fbuf[3];
kf->translation.x = fbuf[4]; if(compressHier){
kf->translation.y = fbuf[5]; KeyFrameTransCompressed *kf = (KeyFrameTransCompressed*)seq->GetKeyFrameCompressed(l);
kf->translation.z = fbuf[6]; 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 // scaling ignored
kf->deltaTime = fbuf[10]; // absolute time here 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
}
}
} }
} }
if(!compressHier){
hier->RemoveQuaternionFlips(); hier->RemoveQuaternionFlips();
hier->CalcTotalTime(); hier->CalcTotalTime();
} }
}
if(animIndex > ms_numAnimations) if(animIndex > ms_numAnimations)
ms_numAnimations = animIndex; ms_numAnimations = animIndex;
} }

View File

@ -136,7 +136,7 @@ public:
static CAnimBlendAssociation *BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId, float delta); static CAnimBlendAssociation *BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId, float delta);
static void LoadAnimFiles(void); static void LoadAnimFiles(void);
static void LoadAnimFile(const char *filename); 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 CreateAnimAssocGroups(void);
static void RemoveLastAnimFile(void); static void RemoveLastAnimFile(void);
static CAnimBlendAssocGroup* GetAnimAssocGroups(void) { return ms_aAnimAssocGroups; } static CAnimBlendAssocGroup* GetAnimAssocGroups(void) { return ms_aAnimAssocGroups; }

View File

@ -291,13 +291,16 @@ CCutsceneMgr::SetupCutsceneToStart(void)
if (ms_pCutsceneObjects[i]->m_pAttachTo != nil) { if (ms_pCutsceneObjects[i]->m_pAttachTo != nil) {
pAnimBlendAssoc->flags &= (~ASSOC_HAS_TRANSLATION); pAnimBlendAssoc->flags &= (~ASSOC_HAS_TRANSLATION);
} else { } else {
KeyFrameTrans* keyFrames; if (pAnimBlendAssoc->hierarchy->IsCompressed()){
if (pAnimBlendAssoc->hierarchy->IsCompressed()) KeyFrameTransCompressed *keyFrames = ((KeyFrameTransCompressed*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrameCompressed(0));
keyFrames = ((KeyFrameTrans*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrameCompressed(0)); CVector trans;
else keyFrames->GetTranslation(&trans);
keyFrames = ((KeyFrameTrans*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrame(0)); 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); ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + keyFrames->translation);
} }
}
pAnimBlendAssoc->SetRun(); pAnimBlendAssoc->SetRun();
} else { } else {
ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset); ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset);
@ -331,7 +334,7 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject)
} }
if (pNewAnim->hierarchy->IsCompressed()) if (pNewAnim->hierarchy->IsCompressed())
pNewAnim->hierarchy->compressed2 = true; pNewAnim->hierarchy->keepCompressed = true;
CStreaming::ImGonnaUseStreamingMemory(); CStreaming::ImGonnaUseStreamingMemory();
pNewAnim = ms_cutsceneAssociations.CopyAnimation(animName); pNewAnim = ms_cutsceneAssociations.CopyAnimation(animName);
@ -344,8 +347,8 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject)
pAnimBlendClumpData = *RPANIMBLENDCLUMPDATA(pObject->m_rwObject); pAnimBlendClumpData = *RPANIMBLENDCLUMPDATA(pObject->m_rwObject);
pAnimBlendClumpData->link.Prepend(&pNewAnim->link); pAnimBlendClumpData->link.Prepend(&pNewAnim->link);
if (pNewAnim->hierarchy->compressed2) if (pNewAnim->hierarchy->keepCompressed)
pAnimBlendClumpData->frames->flag |= AnimBlendFrameData::UNK_COMPRESSED; pAnimBlendClumpData->frames->flag |= AnimBlendFrameData::COMPRESSED;
} }
void void

View File

@ -19,6 +19,9 @@ void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackWithVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackWithVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackWith3dVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackWith3dVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackNonSkinnedCompressed(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackSkinnedCompressed(AnimBlendFrameData *frame, void *arg);
void void
FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg) FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg)
{ {
@ -446,3 +449,222 @@ FrameUpdateCallBackOffscreen(AnimBlendFrameData *frame, void *arg)
if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && gpAnimBlendClump->velocity) if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && gpAnimBlendClump->velocity)
FrameUpdateCallBackWithVelocityExtractionSkinned(frame, arg); 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;
}
}
}

View File

@ -8,6 +8,7 @@
#include "AnimBlendClumpData.h" #include "AnimBlendClumpData.h"
#include "AnimBlendHierarchy.h" #include "AnimBlendHierarchy.h"
#include "AnimBlendAssociation.h" #include "AnimBlendAssociation.h"
#include "AnimManager.h"
#include "RpAnimBlend.h" #include "RpAnimBlend.h"
#include "PedModelInfo.h" #include "PedModelInfo.h"
@ -443,6 +444,9 @@ RpAnimBlendNodeUpdateKeyframes(AnimBlendFrameData *frames, AnimBlendFrameUpdateD
} }
} }
// TODO:
// CAnimBlendClumpData::LoadFramesIntoSPR
// CAnimBlendClumpData::ForAllFramesInSPR
void void
RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender) RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender)
{ {
@ -466,7 +470,7 @@ RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender)
assoc = CAnimBlendAssociation::FromLink(link); assoc = CAnimBlendAssociation::FromLink(link);
if(assoc->UpdateBlend(timeDelta)){ if(assoc->UpdateBlend(timeDelta)){
if(assoc->hierarchy->sequences){ if(assoc->hierarchy->sequences){
//CAnimManager::UncompressAnimation(v6->hierarchy) CAnimManager::UncompressAnimation(assoc->hierarchy);
if(i < 11) if(i < 11)
updateData.nodes[i++] = assoc->GetNode(0); updateData.nodes[i++] = assoc->GetNode(0);
if(assoc->flags & ASSOC_MOVEMENT){ if(assoc->flags & ASSOC_MOVEMENT){
@ -486,6 +490,14 @@ RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender)
updateData.nodes[i] = nil; 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(doRender){
if(clumpData->frames[0].flag & AnimBlendFrameData::UPDATE_KEYFRAMES) if(clumpData->frames[0].flag & AnimBlendFrameData::UPDATE_KEYFRAMES)
RpAnimBlendNodeUpdateKeyframes(clumpData->frames, &updateData, clumpData->numFrames); RpAnimBlendNodeUpdateKeyframes(clumpData->frames, &updateData, clumpData->numFrames);

View File

@ -43,3 +43,6 @@ extern CAnimBlendClumpData *gpAnimBlendClump;
void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackOffscreen(AnimBlendFrameData *frame, void *arg); void FrameUpdateCallBackOffscreen(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackNonSkinnedCompressed(AnimBlendFrameData *frame, void *arg);
void FrameUpdateCallBackSkinnedCompressed(AnimBlendFrameData *frame, void *arg);

View File

@ -192,6 +192,11 @@ enum Config {
// those infamous texts // those infamous texts
#define DRAW_GAME_VERSION_TEXT #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 #if defined GTA_PS2
# define GTA_PS2_STUFF # define GTA_PS2_STUFF
# define RANDOMSPLASH # define RANDOMSPLASH

View File

@ -12,6 +12,11 @@ public:
float MagnitudeSqr(void) const { return x*x + y*y + z*z + w*w; } float MagnitudeSqr(void) const { return x*x + y*y + z*z + w*w; }
void Normalise(void); void Normalise(void);
void Multiply(const CQuaternion &q1, const CQuaternion &q2); 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) { const CQuaternion &operator+=(CQuaternion const &right) {
x += right.x; x += right.x;

View File

@ -341,7 +341,7 @@ CMemoryHeap::TidyHeap(void)
} }
} }
// // MIAMI: this is empty
void void
CMemoryHeap::RegisterMemPointer(void *ptr) CMemoryHeap::RegisterMemPointer(void *ptr)
{ {