dca3-style animation compression for miami
This commit is contained in:
@@ -67,7 +67,7 @@ CAnimBlendAssocGroup::CopyAnimation(uint32 id)
|
||||
CAnimBlendAssociation *anim = GetAnimation(id);
|
||||
if(anim == nil)
|
||||
return nil;
|
||||
CAnimManager::UncompressAnimation(anim->hierarchy);
|
||||
|
||||
return new CAnimBlendAssociation(*anim);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ CAnimBlendAssocGroup::CopyAnimation(const char *name)
|
||||
CAnimBlendAssociation *anim = GetAnimation(name);
|
||||
if(anim == nil)
|
||||
return nil;
|
||||
CAnimManager::UncompressAnimation(anim->hierarchy);
|
||||
|
||||
return new CAnimBlendAssociation(*anim);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,15 +142,6 @@ CAnimBlendAssociation::SetCurrentTime(float time)
|
||||
break;
|
||||
}
|
||||
|
||||
CAnimManager::UncompressAnimation(hierarchy);
|
||||
#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
|
||||
#endif
|
||||
{
|
||||
for(i = 0; i < numNodes; i++)
|
||||
if(nodes[i].sequence)
|
||||
|
||||
@@ -10,8 +10,7 @@ struct AnimBlendFrameData
|
||||
IGNORE_TRANSLATION = 4,
|
||||
VELOCITY_EXTRACTION = 8,
|
||||
VELOCITY_EXTRACTION_3D = 0x10,
|
||||
UPDATE_KEYFRAMES = 0x20,
|
||||
COMPRESSED = 0x40
|
||||
UPDATE_KEYFRAMES = 0x20
|
||||
};
|
||||
|
||||
uint8 flag;
|
||||
|
||||
@@ -8,18 +8,14 @@ CAnimBlendHierarchy::CAnimBlendHierarchy(void)
|
||||
{
|
||||
sequences = nil;
|
||||
numSequences = 0;
|
||||
compressed = 0;
|
||||
totalLength = 0.0f;
|
||||
linkPtr = nil;
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendHierarchy::Shutdown(void)
|
||||
{
|
||||
CAnimManager::RemoveFromUncompressedCache(this);
|
||||
RemoveAnimSequences();
|
||||
totalLength = 0.0f;
|
||||
compressed = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -32,7 +28,6 @@ void
|
||||
CAnimBlendHierarchy::CalcTotalTime(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
totalLength = 0.0f;
|
||||
|
||||
for(i = 0; i < numSequences; i++){
|
||||
@@ -40,35 +35,10 @@ CAnimBlendHierarchy::CalcTotalTime(void)
|
||||
if(sequences[i].numFrames == 0)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
totalLength = Max(totalLength, sequences[i].GetKeyFrame(sequences[i].numFrames-1)->deltaTime);
|
||||
for(j = sequences[i].numFrames-1; j >= 1; j--){
|
||||
KeyFrame *kf1 = sequences[i].GetKeyFrame(j);
|
||||
KeyFrame *kf2 = sequences[i].GetKeyFrame(j-1);
|
||||
kf1->deltaTime -= kf2->deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendHierarchy::CalcTotalTimeCompressed(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
totalLength = 0.0f;
|
||||
|
||||
for(i = 0; i < numSequences; i++){
|
||||
#ifdef FIX_BUGS
|
||||
if(sequences[i].numFrames == 0)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
totalLength = Max(totalLength, sequences[i].GetKeyFrameCompressed(sequences[i].numFrames-1)->GetDeltaTime());
|
||||
for(j = sequences[i].numFrames-1; j >= 1; j--){
|
||||
KeyFrameCompressed *kf1 = sequences[i].GetKeyFrameCompressed(j);
|
||||
KeyFrameCompressed *kf2 = sequences[i].GetKeyFrameCompressed(j-1);
|
||||
kf1->deltaTime -= kf2->deltaTime;
|
||||
}
|
||||
float seqTime = 0.0f;
|
||||
for(j = 0; j < sequences[i].numFrames; j++)
|
||||
seqTime += sequences[i].GetDeltaTime(j);
|
||||
totalLength = Max(totalLength, seqTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,33 +59,6 @@ CAnimBlendHierarchy::RemoveAnimSequences(void)
|
||||
numSequences = 0;
|
||||
}
|
||||
|
||||
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();
|
||||
CalcTotalTime();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendHierarchy::RemoveUncompressedData(void)
|
||||
{
|
||||
#ifdef ANIM_COMPRESSION
|
||||
int i;
|
||||
assert(!compressed);
|
||||
for(i = 0; i < numSequences; i++)
|
||||
sequences[i].RemoveUncompressedData();
|
||||
#endif
|
||||
compressed = 1;
|
||||
}
|
||||
|
||||
#ifdef USE_CUSTOM_ALLOCATOR
|
||||
void
|
||||
|
||||
@@ -15,22 +15,17 @@ public:
|
||||
char name[24];
|
||||
CAnimBlendSequence *sequences;
|
||||
int16 numSequences;
|
||||
bool compressed;
|
||||
bool keepCompressed;
|
||||
float totalLength;
|
||||
CLink<CAnimBlendHierarchy*> *linkPtr;
|
||||
|
||||
CAnimBlendHierarchy(void);
|
||||
void Shutdown(void);
|
||||
void SetName(char *name);
|
||||
void CalcTotalTime(void);
|
||||
void CalcTotalTimeCompressed(void);
|
||||
void RemoveQuaternionFlips(void);
|
||||
void RemoveAnimSequences(void);
|
||||
void Uncompress(void);
|
||||
void RemoveUncompressedData(void);
|
||||
void MoveMemory(bool onlyone = false);
|
||||
bool IsCompressed() { return !!compressed; };
|
||||
};
|
||||
|
||||
VALIDATE_SIZE(CAnimBlendHierarchy, 0x28);
|
||||
@@ -29,53 +29,18 @@ CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight)
|
||||
|
||||
float blend = association->GetBlendAmount(weight);
|
||||
if(blend > 0.0f){
|
||||
KeyFrameTrans *kfA = (KeyFrameTrans*)sequence->GetKeyFrame(frameA);
|
||||
KeyFrameTrans *kfB = (KeyFrameTrans*)sequence->GetKeyFrame(frameB);
|
||||
float t = kfA->deltaTime == 0.0f ? 0.0f : (kfA->deltaTime - remainingTime)/kfA->deltaTime;
|
||||
float kfAdt = sequence->GetDeltaTime(frameA);
|
||||
float t = kfAdt == 0.0f ? 0.0f : (kfAdt - remainingTime)/kfAdt;
|
||||
if(sequence->type & CAnimBlendSequence::KF_TRANS){
|
||||
trans = kfB->translation + t*(kfA->translation - kfB->translation);
|
||||
auto kfAt = sequence->GetTranslation(frameA);
|
||||
auto kfBt = sequence->GetTranslation(frameB);
|
||||
trans = kfBt + t*(kfAt - kfBt);
|
||||
trans *= blend;
|
||||
}
|
||||
if(sequence->type & CAnimBlendSequence::KF_ROT){
|
||||
rot.Slerp(kfB->rotation, kfA->rotation, theta, invSin, t);
|
||||
rot *= blend;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
auto kfAr = sequence->GetRotation(frameA);
|
||||
auto kfBr = sequence->GetRotation(frameB);
|
||||
rot.Slerp(kfBr, kfAr, theta, invSin, t);
|
||||
rot *= blend;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +74,7 @@ CAnimBlendNode::NextKeyFrame(void)
|
||||
frameA = 0;
|
||||
}
|
||||
|
||||
remainingTime += sequence->GetKeyFrame(frameA)->deltaTime;
|
||||
remainingTime += sequence->GetDeltaTime(frameA);
|
||||
}
|
||||
|
||||
frameB = frameA - 1;
|
||||
@@ -120,42 +85,42 @@ CAnimBlendNode::NextKeyFrame(void)
|
||||
return looped;
|
||||
}
|
||||
|
||||
bool
|
||||
CAnimBlendNode::NextKeyFrameCompressed(void)
|
||||
{
|
||||
bool looped;
|
||||
// bool
|
||||
// CAnimBlendNode::NextKeyFrameCompressed(void)
|
||||
// {
|
||||
// bool looped;
|
||||
|
||||
if(sequence->numFrames <= 1)
|
||||
return false;
|
||||
// if(sequence->numFrames <= 1)
|
||||
// return false;
|
||||
|
||||
looped = false;
|
||||
frameB = frameA;
|
||||
// looped = false;
|
||||
// frameB = frameA;
|
||||
|
||||
// Advance as long as we have to
|
||||
while(remainingTime <= 0.0f){
|
||||
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;
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
// remainingTime += sequence->GetKeyFrameCompressed(frameA)->GetDeltaTime();
|
||||
// }
|
||||
|
||||
frameB = frameA - 1;
|
||||
if(frameB < 0)
|
||||
frameB += sequence->numFrames;
|
||||
// frameB = frameA - 1;
|
||||
// if(frameB < 0)
|
||||
// frameB += sequence->numFrames;
|
||||
|
||||
CalcDeltasCompressed();
|
||||
return looped;
|
||||
}
|
||||
// CalcDeltasCompressed();
|
||||
// return looped;
|
||||
// }
|
||||
|
||||
// Set animation to time t
|
||||
bool
|
||||
@@ -171,8 +136,8 @@ CAnimBlendNode::FindKeyFrame(float t)
|
||||
remainingTime = 0.0f;
|
||||
}else{
|
||||
// advance until t is between frameB and frameA
|
||||
while (t > sequence->GetKeyFrame(++frameA)->deltaTime) {
|
||||
t -= sequence->GetKeyFrame(frameA)->deltaTime;
|
||||
while (t > sequence->GetDeltaTime(++frameA)) {
|
||||
t -= sequence->GetDeltaTime(frameA);
|
||||
if (frameA + 1 >= sequence->numFrames) {
|
||||
// reached end of animation
|
||||
if (!association->IsRepeating()) {
|
||||
@@ -185,62 +150,21 @@ CAnimBlendNode::FindKeyFrame(float t)
|
||||
frameB = frameA;
|
||||
}
|
||||
|
||||
remainingTime = sequence->GetKeyFrame(frameA)->deltaTime - t;
|
||||
remainingTime = sequence->GetDeltaTime(frameA) - t;
|
||||
}
|
||||
|
||||
CalcDeltas();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CAnimBlendNode::SetupKeyFrameCompressed(void)
|
||||
{
|
||||
if(sequence->numFrames < 1)
|
||||
return false;
|
||||
|
||||
frameA = 1;
|
||||
frameB = 0;
|
||||
|
||||
if(sequence->numFrames == 1){
|
||||
frameA = 0;
|
||||
remainingTime = 0.0f;
|
||||
}else
|
||||
remainingTime = sequence->GetKeyFrameCompressed(frameA)->GetDeltaTime();
|
||||
|
||||
CalcDeltasCompressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendNode::CalcDeltas(void)
|
||||
{
|
||||
if((sequence->type & CAnimBlendSequence::KF_ROT) == 0)
|
||||
return;
|
||||
KeyFrame *kfA = sequence->GetKeyFrame(frameA);
|
||||
KeyFrame *kfB = sequence->GetKeyFrame(frameB);
|
||||
float cos = DotProduct(kfA->rotation, kfB->rotation);
|
||||
if(cos > 1.0f)
|
||||
cos = 1.0f;
|
||||
theta = Acos(cos);
|
||||
invSin = theta == 0.0f ? 0.0f : 1.0f/Sin(theta);
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendNode::CalcDeltasCompressed(void)
|
||||
{
|
||||
if((sequence->type & CAnimBlendSequence::KF_ROT) == 0)
|
||||
return;
|
||||
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);
|
||||
auto kfAr = sequence->GetRotation(frameA);
|
||||
auto kfBr = sequence->GetRotation(frameB);
|
||||
float cos = DotProduct(kfAr, kfBr);
|
||||
if(cos > 1.0f)
|
||||
cos = 1.0f;
|
||||
theta = Acos(cos);
|
||||
@@ -254,35 +178,17 @@ CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight)
|
||||
|
||||
float blend = association->GetBlendAmount(weight);
|
||||
if(blend > 0.0f){
|
||||
KeyFrameTrans *kfA = (KeyFrameTrans*)sequence->GetKeyFrame(frameA);
|
||||
KeyFrameTrans *kfB = (KeyFrameTrans*)sequence->GetKeyFrame(frameB);
|
||||
float t = kfA->deltaTime == 0.0f ? 0.0f : (kfA->deltaTime - remainingTime)/kfA->deltaTime;
|
||||
auto kfAdt = sequence->GetDeltaTime(frameA);
|
||||
float t = kfAdt == 0.0f ? 0.0f : (kfAdt - remainingTime)/kfAdt;
|
||||
if(sequence->type & CAnimBlendSequence::KF_TRANS){
|
||||
trans = kfB->translation + t*(kfA->translation - kfB->translation);
|
||||
auto kfAt = sequence->GetTranslation(frameA);
|
||||
auto kfBt = sequence->GetTranslation(frameB);
|
||||
trans = kfBt + t*(kfAt - kfBt);
|
||||
trans *= blend;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -291,24 +197,9 @@ CAnimBlendNode::GetEndTranslation(CVector &trans, float weight)
|
||||
|
||||
float blend = association->GetBlendAmount(weight);
|
||||
if(blend > 0.0f){
|
||||
KeyFrameTrans *kf = (KeyFrameTrans*)sequence->GetKeyFrame(sequence->numFrames-1);
|
||||
if(sequence->type & CAnimBlendSequence::KF_TRANS)
|
||||
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 pos;
|
||||
kf->GetTranslation(&pos);
|
||||
CVector pos = sequence->GetTranslation(sequence->numFrames-1);
|
||||
trans = pos * blend;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,9 @@ public:
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -8,16 +8,15 @@ CAnimBlendSequence::CAnimBlendSequence(void)
|
||||
type = 0;
|
||||
numFrames = 0;
|
||||
keyFrames = nil;
|
||||
keyFramesCompressed = nil;
|
||||
#ifdef PED_SKIN
|
||||
boneTag = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
CAnimBlendSequence::~CAnimBlendSequence(void)
|
||||
{
|
||||
if(keyFrames)
|
||||
RwFree(keyFrames);
|
||||
if(keyFramesCompressed)
|
||||
RwFree(keyFramesCompressed);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -27,21 +26,23 @@ CAnimBlendSequence::SetName(char *name)
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendSequence::SetNumFrames(int numFrames, bool translation, bool compressed)
|
||||
CAnimBlendSequence::SetNumFrames(int numFrames, bool translation, bool compress)
|
||||
{
|
||||
int sz;
|
||||
|
||||
if(translation){
|
||||
type |= KF_ROT | KF_TRANS;
|
||||
if(compressed)
|
||||
keyFramesCompressed = RwMalloc(sizeof(KeyFrameTrans) * numFrames);
|
||||
else
|
||||
keyFrames = RwMalloc(sizeof(KeyFrameTrans) * numFrames);
|
||||
if (compress) {
|
||||
type |= KF_COMPRESSED;
|
||||
sz = sizeof(KeyFrameTransCompressed);
|
||||
} else {
|
||||
sz = sizeof(KeyFrameTransUncompressed);
|
||||
}
|
||||
}else{
|
||||
sz = sizeof(KeyFrame);
|
||||
type |= KF_ROT;
|
||||
if(compressed)
|
||||
keyFramesCompressed = RwMalloc(sizeof(KeyFrame) * numFrames);
|
||||
else
|
||||
keyFrames = RwMalloc(sizeof(KeyFrame) * numFrames);
|
||||
}
|
||||
keyFrames = RwMalloc(sz * numFrames);
|
||||
this->numFrames = numFrames;
|
||||
}
|
||||
|
||||
@@ -50,134 +51,19 @@ CAnimBlendSequence::RemoveQuaternionFlips(void)
|
||||
{
|
||||
int i;
|
||||
CQuaternion last;
|
||||
KeyFrame *frame;
|
||||
|
||||
if(numFrames < 2)
|
||||
return;
|
||||
|
||||
frame = GetKeyFrame(0);
|
||||
last = frame->rotation;
|
||||
last = GetRotation(0);
|
||||
for(i = 1; i < numFrames; i++){
|
||||
frame = GetKeyFrame(i);
|
||||
if(DotProduct(last, frame->rotation) < 0.0f)
|
||||
frame->rotation = -frame->rotation;
|
||||
last = frame->rotation;
|
||||
auto KFr = GetRotation(i);
|
||||
if(DotProduct(last, KFr) < 0.0f)
|
||||
SetRotation(i, -KFr);
|
||||
last = GetRotation(i);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef USE_CUSTOM_ALLOCATOR
|
||||
bool
|
||||
CAnimBlendSequence::MoveMemory(void)
|
||||
@@ -198,3 +84,4 @@ CAnimBlendSequence::MoveMemory(void)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,52 +7,67 @@
|
||||
#endif
|
||||
|
||||
// TODO: put them somewhere else?
|
||||
static int16 checked_f2i16(float f) {
|
||||
assert(f >= -32768 && f <= 32767);
|
||||
return f;
|
||||
}
|
||||
|
||||
static uint16 checked_f2u16(float f) {
|
||||
assert(f >= 0 && f <= 65535);
|
||||
return f;
|
||||
}
|
||||
|
||||
#define KF_MINDELTA (1/256.f)
|
||||
|
||||
struct KeyFrame {
|
||||
CQuaternion rotation;
|
||||
float deltaTime; // relative to previous key frame
|
||||
};
|
||||
|
||||
struct KeyFrameTrans : KeyFrame {
|
||||
CVector translation;
|
||||
};
|
||||
|
||||
struct KeyFrameCompressed {
|
||||
int16 rot[4]; // 4096
|
||||
int16 deltaTime; // 60
|
||||
uint16 dltTime; // 256
|
||||
|
||||
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;
|
||||
CQuaternion rotation_() {
|
||||
return { rot[0] * (1/4096.f), rot[1] * (1/4096.f), rot[2] * (1/4096.f), rot[3] * (1/4096.f) };
|
||||
}
|
||||
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 rotation_(const CQuaternion& q) {
|
||||
rot[0] = checked_f2i16(q.x * 4096.0f);
|
||||
rot[1] = checked_f2i16(q.y * 4096.0f);
|
||||
rot[2] = checked_f2i16(q.z * 4096.0f);
|
||||
rot[3] = checked_f2i16(q.w * 4096.0f);
|
||||
}
|
||||
void SetTranslation(const CVector &vec){
|
||||
trans[0] = vec.x*1024.0f;
|
||||
trans[1] = vec.y*1024.0f;
|
||||
trans[2] = vec.z*1024.0f;
|
||||
|
||||
float deltaTime_() {
|
||||
return dltTime * (1/256.0f);
|
||||
}
|
||||
|
||||
void deltaTime_(float t) {
|
||||
dltTime = checked_f2u16(t * 256); // always round down
|
||||
}
|
||||
};
|
||||
|
||||
struct KeyFrameTransUncompressed : KeyFrame {
|
||||
// Some animations use bigger range, eg during the intro
|
||||
CVector trans;
|
||||
CVector translation_() {
|
||||
return trans;
|
||||
}
|
||||
|
||||
void translation_(const CVector &v) {
|
||||
trans = v;
|
||||
}
|
||||
};
|
||||
|
||||
struct KeyFrameTransCompressed : KeyFrame {
|
||||
int16 trans[3]; // 128
|
||||
|
||||
CVector translation_() {
|
||||
return { trans[0] * (1/128.f), trans[1] * (1/128.f), trans[2] * (1/128.f)};
|
||||
}
|
||||
|
||||
void translation_(const CVector &v) {
|
||||
trans[0] = checked_f2i16(v.x * 128.f);
|
||||
trans[1] = checked_f2i16(v.y * 128.f);
|
||||
trans[2] = checked_f2i16(v.z * 128.f);
|
||||
}
|
||||
};
|
||||
|
||||
// The sequence of key frames of one animated node
|
||||
class CAnimBlendSequence
|
||||
@@ -60,34 +75,82 @@ class CAnimBlendSequence
|
||||
public:
|
||||
enum {
|
||||
KF_ROT = 1,
|
||||
KF_TRANS = 2
|
||||
KF_TRANS = 2,
|
||||
KF_COMPRESSED = 4, // only applicable for KF_TRANS
|
||||
};
|
||||
int32 type;
|
||||
char name[24];
|
||||
int32 numFrames;
|
||||
int16 boneTag;
|
||||
void *keyFrames;
|
||||
void *keyFramesCompressed;
|
||||
|
||||
CAnimBlendSequence(void);
|
||||
virtual ~CAnimBlendSequence(void);
|
||||
void SetName(char *name);
|
||||
void SetNumFrames(int numFrames, bool translation, bool compressed);
|
||||
void RemoveQuaternionFlips(void);
|
||||
KeyFrame *GetKeyFrame(int n) {
|
||||
return type & KF_TRANS ?
|
||||
&((KeyFrameTrans*)keyFrames)[n] :
|
||||
&((KeyFrame*)keyFrames)[n];
|
||||
|
||||
void SetTranslation(int n, const CVector &v) {
|
||||
if (type & KF_COMPRESSED) {
|
||||
((KeyFrameTransCompressed*)keyFrames)[n].translation_(v);
|
||||
} else if (type & KF_TRANS) {
|
||||
((KeyFrameTransUncompressed*)keyFrames)[n].translation_(v);
|
||||
} else {
|
||||
assert(false && "SetTranslation called on sequence without translation");
|
||||
}
|
||||
}
|
||||
KeyFrameCompressed *GetKeyFrameCompressed(int n) {
|
||||
return type & KF_TRANS ?
|
||||
&((KeyFrameTransCompressed*)keyFramesCompressed)[n] :
|
||||
&((KeyFrameCompressed*)keyFramesCompressed)[n];
|
||||
|
||||
CVector GetTranslation(int n) {
|
||||
if (type & KF_COMPRESSED) {
|
||||
return ((KeyFrameTransCompressed*)keyFrames)[n].translation_();
|
||||
} else if (type & KF_TRANS) {
|
||||
return ((KeyFrameTransUncompressed*)keyFrames)[n].translation_();
|
||||
} else {
|
||||
assert(false && "GetTranslation called on sequence without translation");
|
||||
}
|
||||
}
|
||||
|
||||
void SetRotation(int n, const CQuaternion &q) {
|
||||
if (type & KF_COMPRESSED) {
|
||||
((KeyFrameTransCompressed*)keyFrames)[n].rotation_(q);
|
||||
} else if (type & KF_TRANS) {
|
||||
((KeyFrameTransUncompressed*)keyFrames)[n].rotation_(q);
|
||||
} else {
|
||||
((KeyFrame*)keyFrames)[n].rotation_(q);
|
||||
}
|
||||
}
|
||||
|
||||
CQuaternion GetRotation(int n) {
|
||||
if (type & KF_COMPRESSED) {
|
||||
return ((KeyFrameTransCompressed*)keyFrames)[n].rotation_();
|
||||
} else if (type & KF_TRANS) {
|
||||
return ((KeyFrameTransUncompressed*)keyFrames)[n].rotation_();
|
||||
} else {
|
||||
return ((KeyFrame*)keyFrames)[n].rotation_();
|
||||
}
|
||||
}
|
||||
|
||||
void SetDeltaTime(int n, float t) {
|
||||
if (type & KF_COMPRESSED) {
|
||||
((KeyFrameTransCompressed*)keyFrames)[n].deltaTime_(t);
|
||||
} else if (type & KF_TRANS) {
|
||||
((KeyFrameTransUncompressed*)keyFrames)[n].deltaTime_(t);
|
||||
} else {
|
||||
((KeyFrame*)keyFrames)[n].deltaTime_(t);
|
||||
}
|
||||
}
|
||||
|
||||
float GetDeltaTime(int n) {
|
||||
if (type & KF_COMPRESSED) {
|
||||
return ((KeyFrameTransCompressed*)keyFrames)[n].deltaTime_();
|
||||
} else if (type & KF_TRANS) {
|
||||
return ((KeyFrameTransUncompressed*)keyFrames)[n].deltaTime_();
|
||||
} else {
|
||||
return ((KeyFrame*)keyFrames)[n].deltaTime_();
|
||||
}
|
||||
}
|
||||
|
||||
bool HasTranslation(void) { return !!(type & KF_TRANS); }
|
||||
void Uncompress(void);
|
||||
void CompressKeyframes(void);
|
||||
void RemoveUncompressedData(void);
|
||||
bool MoveMemory(void);
|
||||
|
||||
void SetBoneTag(int tag) { boneTag = tag; }
|
||||
|
||||
@@ -17,7 +17,6 @@ CAnimBlendHierarchy CAnimManager::ms_aAnimations[NUMANIMATIONS];
|
||||
int32 CAnimManager::ms_numAnimBlocks;
|
||||
int32 CAnimManager::ms_numAnimations;
|
||||
CAnimBlendAssocGroup *CAnimManager::ms_aAnimAssocGroups;
|
||||
CLinkList<CAnimBlendHierarchy*> CAnimManager::ms_animCache;
|
||||
|
||||
AnimAssocDesc aStdAnimDescs[] = {
|
||||
{ ANIM_STD_WALK, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_WALK },
|
||||
@@ -972,7 +971,6 @@ CAnimManager::Initialise(void)
|
||||
{
|
||||
ms_numAnimations = 0;
|
||||
ms_numAnimBlocks = 0;
|
||||
ms_animCache.Init(25);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -986,46 +984,10 @@ CAnimManager::Shutdown(void)
|
||||
for(i = 0; i < ms_numAnimations; i++)
|
||||
ms_aAnimations[i].Shutdown();
|
||||
|
||||
ms_animCache.Shutdown();
|
||||
|
||||
delete[] ms_aAnimAssocGroups;
|
||||
}
|
||||
|
||||
void
|
||||
CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier)
|
||||
{
|
||||
if(hier->keepCompressed){
|
||||
if(hier->totalLength == 0.0f)
|
||||
hier->CalcTotalTimeCompressed();
|
||||
}else{
|
||||
if(!hier->compressed){
|
||||
if(hier->linkPtr){
|
||||
hier->linkPtr->Remove();
|
||||
ms_animCache.head.Insert(hier->linkPtr);
|
||||
}
|
||||
}else{
|
||||
CLink<CAnimBlendHierarchy*> *link = ms_animCache.Insert(hier);
|
||||
if(link == nil){
|
||||
CAnimBlendHierarchy *lastHier = ms_animCache.tail.prev->item;
|
||||
lastHier->RemoveUncompressedData();
|
||||
ms_animCache.Remove(ms_animCache.tail.prev);
|
||||
lastHier->linkPtr = nil;
|
||||
link = ms_animCache.Insert(hier);
|
||||
}
|
||||
hier->linkPtr = link;
|
||||
hier->Uncompress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CAnimManager::RemoveFromUncompressedCache(CAnimBlendHierarchy *hier)
|
||||
{
|
||||
if(hier->linkPtr){
|
||||
ms_animCache.Remove(hier->linkPtr);
|
||||
hier->linkPtr = nil;
|
||||
}
|
||||
}
|
||||
|
||||
CAnimBlock*
|
||||
CAnimManager::GetAnimationBlock(const char *name)
|
||||
@@ -1226,7 +1188,6 @@ CAnimManager::BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId a
|
||||
found->blendAmount = 0.0f;
|
||||
found->blendDelta = delta;
|
||||
}
|
||||
UncompressAnimation(found->hierarchy);
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -1321,11 +1282,8 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*uncompressedA
|
||||
RwStreamRead(stream, buf, name.size);
|
||||
hier->SetName(buf);
|
||||
|
||||
#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)){
|
||||
@@ -1334,10 +1292,6 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*uncompressedA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hier->compressed = compressHier;
|
||||
hier->keepCompressed = false;
|
||||
|
||||
// DG info has number of nodes/sequences
|
||||
RwStreamRead(stream, (char*)&dgan, sizeof(IfpHeader));
|
||||
ROUNDSIZE(dgan.size);
|
||||
@@ -1377,6 +1331,8 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*uncompressedA
|
||||
if(strstr(seq->name, "L Toe"))
|
||||
debug("anim %s has toe keyframes\n", hier->name); // BUG: seq->name
|
||||
|
||||
float *frameTimes = (float*)RwMalloc(sizeof(float) * numFrames);
|
||||
|
||||
for(l = 0; l < numFrames; l++){
|
||||
if(hasScale){
|
||||
RwStreamRead(stream, buf, 0x2C);
|
||||
@@ -1384,58 +1340,47 @@ CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*uncompressedA
|
||||
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
|
||||
}
|
||||
seq->SetRotation(l, rot);
|
||||
seq->SetTranslation(l, trans);
|
||||
// scaling ignored
|
||||
frameTimes[l] = 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
|
||||
}
|
||||
seq->SetRotation(l, rot);
|
||||
seq->SetTranslation(l, trans);
|
||||
frameTimes[l] = 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
|
||||
}
|
||||
seq->SetRotation(l, rot);
|
||||
frameTimes[l] = fbuf[4]; // absolute time here
|
||||
}
|
||||
}
|
||||
|
||||
// convert absolute time to deltas
|
||||
float running_sum = 0.0f;
|
||||
for (l = 0; l < numFrames; l++) {
|
||||
auto dt = frameTimes[l] - running_sum;
|
||||
seq->SetDeltaTime(l, dt);
|
||||
assert(seq->GetDeltaTime(l) <= dt);
|
||||
running_sum += seq->GetDeltaTime(l);
|
||||
// if (seq->GetDeltaTime(l) == 0.0f && dt != 0.0f) {
|
||||
// seq->SetDeltaTime(l, KF_MINDELTA);
|
||||
// }
|
||||
|
||||
// assert(seq->GetDeltaTime(l) != 0.0f || dt == 0.0f);
|
||||
}
|
||||
RwFree(frameTimes);
|
||||
}
|
||||
|
||||
if(!compressHier){
|
||||
hier->RemoveQuaternionFlips();
|
||||
hier->CalcTotalTime();
|
||||
}
|
||||
hier->RemoveQuaternionFlips();
|
||||
hier->CalcTotalTime();
|
||||
}
|
||||
if(animIndex > ms_numAnimations)
|
||||
ms_numAnimations = animIndex;
|
||||
|
||||
@@ -116,8 +116,6 @@ public:
|
||||
|
||||
static void Initialise(void);
|
||||
static void Shutdown(void);
|
||||
static void UncompressAnimation(CAnimBlendHierarchy *anim);
|
||||
static void RemoveFromUncompressedCache(CAnimBlendHierarchy *hier);
|
||||
static CAnimBlock *GetAnimationBlock(int32 block) { return &ms_aAnimBlocks[block]; }
|
||||
static CAnimBlock *GetAnimationBlock(const char *name);
|
||||
static int32 GetAnimationBlockIndex(const char *name);
|
||||
|
||||
@@ -289,15 +289,7 @@ CCutsceneMgr::SetupCutsceneToStart(void)
|
||||
if (ms_pCutsceneObjects[i]->m_pAttachTo != nil) {
|
||||
pAnimBlendAssoc->flags &= (~ASSOC_HAS_TRANSLATION);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + pAnimBlendAssoc->hierarchy->sequences[0].GetTranslation(0));
|
||||
}
|
||||
pAnimBlendAssoc->SetRun();
|
||||
} else {
|
||||
@@ -331,9 +323,6 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject)
|
||||
return;
|
||||
}
|
||||
|
||||
if (pNewAnim->hierarchy->IsCompressed())
|
||||
pNewAnim->hierarchy->keepCompressed = true;
|
||||
|
||||
CStreaming::ImGonnaUseStreamingMemory();
|
||||
pNewAnim = ms_cutsceneAssociations.CopyAnimation(animName);
|
||||
CStreaming::IHaveUsedStreamingMemory();
|
||||
@@ -344,9 +333,6 @@ CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject)
|
||||
|
||||
pAnimBlendClumpData = *RPANIMBLENDCLUMPDATA(pObject->m_rwObject);
|
||||
pAnimBlendClumpData->link.Prepend(&pNewAnim->link);
|
||||
|
||||
if (pNewAnim->hierarchy->keepCompressed)
|
||||
pAnimBlendClumpData->frames->flag |= AnimBlendFrameData::COMPRESSED;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -17,9 +17,6 @@ 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,223 +443,4 @@ FrameUpdateCallBackOffscreen(AnimBlendFrameData *frame, void *arg)
|
||||
{
|
||||
if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION && gpAnimBlendClump->velocity2d)
|
||||
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->velocity2d){
|
||||
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->velocity3d = trans - cur;
|
||||
if(looped)
|
||||
*gpAnimBlendClump->velocity3d += 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->velocity2d){
|
||||
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->velocity3d = trans - cur;
|
||||
if(looped)
|
||||
*gpAnimBlendClump->velocity3d += 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,7 +474,6 @@ RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta, bool doRender)
|
||||
assoc = CAnimBlendAssociation::FromLink(link);
|
||||
if(assoc->UpdateBlend(timeDelta)){
|
||||
if(assoc->hierarchy->sequences){
|
||||
CAnimManager::UncompressAnimation(assoc->hierarchy);
|
||||
if(i < 11)
|
||||
updateData.nodes[i++] = assoc->GetNode(0);
|
||||
if(assoc->flags & ASSOC_MOVEMENT){
|
||||
@@ -494,14 +493,6 @@ 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);
|
||||
|
||||
@@ -43,6 +43,3 @@ 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);
|
||||
|
||||
@@ -4890,133 +4890,111 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void)
|
||||
|
||||
CAnimBlendHierarchy *enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_STD_JACKEDCAR_LHS)->hierarchy;
|
||||
CAnimBlendSequence *seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedDraggedOutCarAnimOffset = lastFrame->translation;
|
||||
vecPedDraggedOutCarAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_STD_CAR_GET_IN_LHS)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedCarDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedCarDoorAnimOffset = lastFrame->translation;
|
||||
vecPedCarDoorAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_STD_CAR_GET_IN_LO_LHS)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedCarDoorLoAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedCarDoorLoAnimOffset = lastFrame->translation;
|
||||
vecPedCarDoorLoAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_STD_QUICKJACKED)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedQuickDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedQuickDraggedOutCarAnimOffset = lastFrame->translation;
|
||||
vecPedQuickDraggedOutCarAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_VAN, ANIM_STD_VAN_GET_IN_REAR_LHS)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedVanRearDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedVanRearDoorAnimOffset = lastFrame->translation;
|
||||
vecPedVanRearDoorAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_STD_TRAIN_GETOUT)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedTrainDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedTrainDoorAnimOffset = lastFrame->translation;
|
||||
vecPedTrainDoorAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_BIKE_STANDARD, ANIM_BIKE_JUMPON_LHS)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedStdBikeJumpRhsAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedStdBikeJumpRhsAnimOffset = lastFrame->translation;
|
||||
vecPedStdBikeJumpRhsAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_BIKE_VESPA, ANIM_BIKE_JUMPON_LHS)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedVespaBikeJumpRhsAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedVespaBikeJumpRhsAnimOffset = lastFrame->translation;
|
||||
vecPedVespaBikeJumpRhsAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_BIKE_HARLEY, ANIM_BIKE_JUMPON_LHS)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedHarleyBikeJumpRhsAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedHarleyBikeJumpRhsAnimOffset = lastFrame->translation;
|
||||
vecPedHarleyBikeJumpRhsAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_BIKE_DIRT, ANIM_BIKE_JUMPON_LHS)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedDirtBikeJumpRhsAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedDirtBikeJumpRhsAnimOffset = lastFrame->translation;
|
||||
vecPedDirtBikeJumpRhsAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_BIKE_HARLEY, ANIM_BIKE_KICK)->hierarchy;
|
||||
seq = enterAssoc->sequences;
|
||||
CAnimManager::UncompressAnimation(enterAssoc);
|
||||
if (seq->numFrames > 0) {
|
||||
if (!seq->HasTranslation())
|
||||
vecPedBikeKickAnimOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
else {
|
||||
KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
|
||||
vecPedBikeKickAnimOffset = lastFrame->translation;
|
||||
vecPedBikeKickAnimOffset = seq->GetTranslation(seq->numFrames - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user