Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1135 lines
31 KiB
C++
1135 lines
31 KiB
C++
//===========================================================================//
|
|
// File: AnimIteratorManager.cpp
|
|
// Project: MechWarrior 4
|
|
// Contents:
|
|
//
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 07/01/98 JSE Initial coding,
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Fasa Interactive, Inc.
|
|
// All Rights reserved worldwide
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
|
|
//===========================================================================//
|
|
|
|
|
|
#include <MW4\MW4AnimationSystem.hpp>
|
|
|
|
#include <Stuff\MemoryBlock.hpp>
|
|
|
|
namespace MechWarrior4 {
|
|
DECLARE_TIMER(extern, RunAnimStates);
|
|
DECLARE_TIMER(extern, Iterate);
|
|
DECLARE_TIMER(extern, Blend);
|
|
DECLARE_TIMER(extern, Apply);
|
|
DECLARE_TIMER(extern, BlendAlloc);
|
|
DECLARE_TIMER(extern, blendDealloc);
|
|
DECLARE_TIMER(extern, BlendAnimCombine);
|
|
DECLARE_TIMER(extern, BlendCombine);
|
|
DECLARE_TIMER(extern, BlendAndApply);
|
|
};
|
|
|
|
using namespace MW4Animation;
|
|
using namespace MechWarrior4;
|
|
|
|
//define MW4_ANIMATION_HIER_COUNT
|
|
|
|
|
|
bool AnimHierarchyIteratorManager::doTransitionBlend = true;
|
|
|
|
#if 0
|
|
#define ANIM_LOGIC(string) LOGIC("Animation::" string)
|
|
#else
|
|
#define ANIM_LOGIC(string)
|
|
#endif
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
|
|
Stuff::MemoryBlock*
|
|
BlendBuffer::AllocatedMemory = NULL;
|
|
|
|
void BlendBuffer::InitializeClass()
|
|
{
|
|
Verify(!AllocatedMemory);
|
|
AllocatedMemory =
|
|
new Stuff::MemoryBlock(
|
|
sizeof(BlendBuffer),
|
|
10,
|
|
2,
|
|
"Animation-BlendBuffer"
|
|
);
|
|
Register_Object(AllocatedMemory);
|
|
}
|
|
|
|
void BlendBuffer::TerminateClass()
|
|
{
|
|
Unregister_Object(AllocatedMemory);
|
|
delete AllocatedMemory;
|
|
AllocatedMemory = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
Stuff::MemoryBlock*
|
|
AnimHierarchyNode::AllocatedMemory = NULL;
|
|
|
|
void AnimHierarchyNode::InitializeClass()
|
|
{
|
|
Verify(!AllocatedMemory);
|
|
AllocatedMemory =
|
|
new Stuff::MemoryBlock(
|
|
sizeof(AnimHierarchyNode),
|
|
10,
|
|
2,
|
|
"Animation-BlendHeirarchy"
|
|
);
|
|
Register_Object(AllocatedMemory);
|
|
}
|
|
|
|
void AnimHierarchyNode::TerminateClass()
|
|
{
|
|
Unregister_Object(AllocatedMemory);
|
|
delete AllocatedMemory;
|
|
AllocatedMemory = NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
|
|
AnimHierarchyNode::AnimHierarchyNode(Stuff::Scalar blend_value):
|
|
Plug(DefaultData),
|
|
childrenNodes(NULL),
|
|
animIterators(NULL),
|
|
parentNode(NULL)
|
|
{
|
|
Verify(blend_value >= 0);
|
|
blendValue = blend_value;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
|
|
AnimHierarchyNode::~AnimHierarchyNode()
|
|
{
|
|
Stuff::ChainIteratorOf<AnimHierarchyNode*> iterator1(&childrenNodes);
|
|
Stuff::Plug *anim_plug;
|
|
while ((anim_plug = iterator1.GetCurrent()) != NULL)
|
|
{
|
|
iterator1.Remove();
|
|
Unregister_Object(anim_plug);
|
|
delete anim_plug;
|
|
}
|
|
|
|
// we don't own these so we don't delete them
|
|
Stuff::ChainIteratorOf<AnimIterator*> iterator2(&animIterators);
|
|
while ((anim_plug = iterator1.GetCurrent()) != NULL)
|
|
{
|
|
iterator2.Remove();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
AnimHierarchyIteratorManager::AnimHierarchyIteratorManager(UserDefinedApplyChannelFunction apply_function, void *user_data):
|
|
Plug(DefaultData),
|
|
iteratorHierarchy(NULL),
|
|
currentLayer(NULL)
|
|
{
|
|
Check_Pointer(apply_function);
|
|
Check_Pointer(user_data);
|
|
applyFunction = apply_function;
|
|
userData = user_data;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
AnimHierarchyIteratorManager::~AnimHierarchyIteratorManager()
|
|
{
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
static int AnimationHierarchyPopCount = 0;
|
|
static int AnimationHierarchyPushCount = 0;
|
|
#endif
|
|
|
|
AnimHierarchyNode * AnimHierarchyIteratorManager::PushLayer(Stuff::Scalar blend_value)
|
|
{
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
++AnimationHierarchyPushCount;
|
|
#endif
|
|
|
|
if (iteratorHierarchy.GetCurrent() == NULL)
|
|
{
|
|
Verify(currentLayer.GetCurrent() == NULL);
|
|
|
|
AnimHierarchyNode *new_node = new AnimHierarchyNode(blend_value);
|
|
Register_Object(new_node);
|
|
|
|
iteratorHierarchy.Add(new_node);
|
|
currentLayer.Add(new_node);
|
|
}
|
|
else
|
|
{
|
|
AnimHierarchyNode *new_node = new AnimHierarchyNode(blend_value);
|
|
Register_Object(new_node);
|
|
|
|
AnimHierarchyNode *parent_node = currentLayer.GetCurrent();
|
|
Check_Object(parent_node);
|
|
|
|
parent_node->childrenNodes.Add(new_node);
|
|
new_node->parentNode.Add(parent_node);
|
|
|
|
currentLayer.Remove();
|
|
currentLayer.Add(new_node);
|
|
}
|
|
|
|
return currentLayer.GetCurrent();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void AnimHierarchyIteratorManager::UndoPush()
|
|
{
|
|
AnimHierarchyNode *cur_node = currentLayer.GetCurrent();
|
|
Check_Object(cur_node);
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
++AnimationHierarchyPopCount;
|
|
#endif
|
|
|
|
if( cur_node->parentNode.GetCurrent() != NULL )
|
|
{
|
|
currentLayer.Remove();
|
|
currentLayer.Add(cur_node->parentNode.GetCurrent());
|
|
Unregister_Object(cur_node);
|
|
delete cur_node;
|
|
}
|
|
else
|
|
{
|
|
STOP(("AnimHierarchyIteratorManager::UndoPush() : UNHANDLED CASE"));
|
|
// if it is equal to null we are at the top of the stack...
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void AnimHierarchyIteratorManager::PopLayer()
|
|
{
|
|
|
|
AnimHierarchyNode *cur_node = currentLayer.GetCurrent();
|
|
Check_Object(cur_node);
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
++AnimationHierarchyPopCount;
|
|
#endif
|
|
|
|
if( cur_node->parentNode.GetCurrent() != NULL )
|
|
{
|
|
currentLayer.Remove();
|
|
currentLayer.Add(cur_node->parentNode.GetCurrent());
|
|
}
|
|
else
|
|
{
|
|
currentLayer.Remove();
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
Verify(AnimationHierarchyPopCount == AnimationHierarchyPushCount);
|
|
AnimationHierarchyPopCount = 0;
|
|
AnimationHierarchyPushCount = 0;
|
|
#endif
|
|
// if it is equal to null we are at the top of the stack...
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void AnimHierarchyIteratorManager::AddAnimToCurrentLayer(AnimIterator *iterator)
|
|
{
|
|
Check_Object(iterator);
|
|
AnimHierarchyNode *cur_node = currentLayer.GetCurrent();
|
|
Check_Object(cur_node);
|
|
|
|
cur_node->animIterators.Add(iterator);
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void AnimHierarchyIteratorManager::BlendAndApply
|
|
(
|
|
int total_joint_count,
|
|
void *override_user_data,
|
|
UserDefinedApplyChannelFunction override_apply_function
|
|
)
|
|
{
|
|
|
|
ANIM_LOGIC("BlendAndApply");
|
|
Start_Timer(BlendAndApply);
|
|
|
|
|
|
if (override_user_data == NULL)
|
|
{
|
|
override_user_data = userData;
|
|
}
|
|
if (override_apply_function == NULL)
|
|
{
|
|
override_apply_function = applyFunction;
|
|
}
|
|
|
|
if (iteratorHierarchy.GetCurrent() != NULL)
|
|
{
|
|
|
|
|
|
ANIM_LOGIC("BlendAndApply::Allocation");
|
|
Start_Timer(BlendAlloc);
|
|
|
|
AnimHierarchyNode *root_node = iteratorHierarchy.GetCurrent();
|
|
Check_Object(root_node);
|
|
|
|
//blend
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
TabCount = 0;
|
|
BlendCount = 0;
|
|
#endif
|
|
|
|
BlendBuffer *blend_result = new BlendBuffer(total_joint_count);
|
|
Register_Pointer(blend_result);
|
|
Stop_Timer(BlendAlloc);
|
|
|
|
Stuff::Scalar small_backup = Stuff::SMALL;
|
|
Stuff::SMALL = 0.5f;
|
|
|
|
{
|
|
ANIM_LOGIC("BlendAndApply::Blend");
|
|
Start_Timer(Blend);
|
|
Blend(root_node, blend_result);
|
|
Stop_Timer(Blend);
|
|
}
|
|
|
|
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
SPEW(("jerryeds", "Blend Buffer Allocations : %d", BlendCount ));
|
|
SPEW(("jerryeds", ""));
|
|
#endif
|
|
|
|
{
|
|
ANIM_LOGIC("BlendAndApply::Apply");
|
|
Start_Timer(Apply);
|
|
// apply result
|
|
Apply(blend_result, override_user_data, override_apply_function);
|
|
Stop_Timer(Apply);
|
|
}
|
|
|
|
|
|
Stuff::SMALL = small_backup;
|
|
|
|
{
|
|
ANIM_LOGIC("BlendAndApply::Dealloc");
|
|
Start_Timer(blendDealloc);
|
|
|
|
Unregister_Pointer(blend_result);
|
|
delete blend_result;
|
|
|
|
//then delete...
|
|
Unregister_Object(root_node);
|
|
delete root_node;
|
|
|
|
Stop_Timer(blendDealloc);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
Stop_Timer(BlendAndApply);
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void AnimHierarchyIteratorManager::Apply(
|
|
BlendBuffer *blend_result,
|
|
void *user_data,
|
|
UserDefinedApplyChannelFunction apply_function
|
|
)
|
|
{
|
|
|
|
for (int i = 0; i < blend_result->numberOfJoints; i++)
|
|
{
|
|
ChannelApplication channel_app;
|
|
|
|
bool dirty = false;
|
|
if(blend_result->IsPositionDirty(i))
|
|
{
|
|
channel_app.positionValue = blend_result->positionBuffer[i];
|
|
channel_app.hasPosition = true;
|
|
dirty = true;
|
|
}
|
|
if(blend_result->IsRotationDirty(i))
|
|
{
|
|
channel_app.rotationValue = blend_result->rotationBuffer[i];
|
|
channel_app.hasRotation = true;
|
|
dirty = true;
|
|
}
|
|
if(blend_result->IsVelocityDirty(i))
|
|
{
|
|
|
|
channel_app.velocityValue = blend_result->velocityBuffer[i];
|
|
|
|
if (blend_result->IsAngularVelocityDirty(i))
|
|
{
|
|
Verify(blend_result->IsRotationDirty(i));
|
|
Stuff::LinearMatrix4D mat(Stuff::LinearMatrix4D::Identity);
|
|
mat.BuildRotation(channel_app.rotationValue);
|
|
|
|
channel_app.velocityValue.MultiplyByInverse(blend_result->velocityBuffer[i], mat);
|
|
|
|
}
|
|
else
|
|
{
|
|
channel_app.velocityValue = blend_result->velocityBuffer[i];
|
|
}
|
|
|
|
channel_app.hasVelocity = true;
|
|
dirty = true;
|
|
}
|
|
if(blend_result->IsAngularVelocityDirty(i))
|
|
{
|
|
channel_app.angularVelocityValue = blend_result->angularVelocityBuffer[i];
|
|
channel_app.hasAngularVelocity = true;
|
|
dirty = true;
|
|
}
|
|
if(blend_result->IsTriggerDirty(i))
|
|
{
|
|
channel_app.triggerValue = blend_result->triggerBuffer[i];
|
|
channel_app.hasTrigger = true;
|
|
dirty = true;
|
|
}
|
|
|
|
if (dirty)
|
|
{
|
|
(*apply_function)(channel_app, i, user_data);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void AnimHierarchyIteratorManager::Blend(AnimHierarchyNode *current_node, BlendBuffer *blend_result)
|
|
{
|
|
// normalize...
|
|
Stuff::ChainIteratorOf<AnimHierarchyNode*> node_iterator(¤t_node->childrenNodes);
|
|
Stuff::ChainIteratorOf<AnimIterator*> anim_iterator(¤t_node->animIterators);
|
|
|
|
AnimHierarchyNode *child_node;
|
|
AnimIterator *child_anim;
|
|
|
|
Stuff::Scalar total_node_weight = 0.0f;
|
|
Stuff::Scalar total_anim_weight = 0.0f;
|
|
Stuff::Scalar total_weight = 0.0f;
|
|
|
|
int child_node_count = 0;
|
|
int child_animation_count = 0;
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
|
|
for (int i = 0; i < TabCount; ++i)
|
|
{
|
|
SPEW(("jerryeds", "\t+"));
|
|
}
|
|
SPEW(("jerryeds","|_"));
|
|
++TabCount;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
// normalize stuff
|
|
while ((child_node = node_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
total_node_weight += child_node->blendValue;
|
|
++child_node_count;
|
|
}
|
|
|
|
while ((child_anim = anim_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
total_anim_weight += child_anim->GetBlendValue();
|
|
++child_animation_count;
|
|
}
|
|
|
|
total_weight = total_node_weight + total_anim_weight;
|
|
|
|
Stuff::Scalar current_weight = 0.0f;
|
|
|
|
// mix in the node children...
|
|
if(total_node_weight != 0.0f)
|
|
{
|
|
node_iterator.First();
|
|
if(child_node_count == 1)
|
|
{
|
|
Blend(node_iterator.GetCurrent(), blend_result);
|
|
}
|
|
else
|
|
{
|
|
BlendBuffer *new_blend_result;
|
|
{
|
|
ANIM_LOGIC("BlendAndApply::Blend::Alloc");
|
|
Start_Timer(BlendAlloc);
|
|
|
|
new_blend_result = new BlendBuffer(blend_result->numberOfJoints);
|
|
Register_Pointer(new_blend_result);
|
|
|
|
Stop_Timer(BlendAlloc);
|
|
}
|
|
|
|
while ((child_node = node_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if (child_node->blendValue > 0.0f)
|
|
{
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
for (int tab_count = 0; tab_count < TabCount; ++tab_count)
|
|
{
|
|
SPEW(("jerryeds", "\t+"));
|
|
}
|
|
|
|
SPEW(("jerryeds", "|_ CB : %ff :", child_node->blendValue/total_weight));
|
|
#endif
|
|
|
|
Stuff::Scalar unitized_weight = child_node->blendValue/total_weight;
|
|
current_weight += unitized_weight;
|
|
Stuff::Scalar local_unitized_weight = 0.0f;
|
|
|
|
if (current_weight != 0.0f)
|
|
{
|
|
local_unitized_weight = unitized_weight/current_weight;
|
|
}
|
|
|
|
Blend(child_node, new_blend_result);
|
|
Combine(blend_result, new_blend_result, local_unitized_weight);
|
|
}
|
|
}
|
|
|
|
{
|
|
ANIM_LOGIC("BlendAndApply::Blend::Dealloc");
|
|
Start_Timer(blendDealloc);
|
|
|
|
Unregister_Pointer(new_blend_result);
|
|
delete new_blend_result;
|
|
|
|
Stop_Timer(blendDealloc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (total_anim_weight != 0.0f)
|
|
{
|
|
anim_iterator.First();
|
|
while ((child_anim = anim_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if (child_anim->GetBlendValue() > 0.0f)
|
|
{
|
|
Stuff::Scalar unitized_weight = child_anim->GetBlendValue()/total_weight;
|
|
current_weight += unitized_weight;
|
|
Stuff::Scalar local_unitized_weight = 0.0f;
|
|
|
|
if (current_weight != 0.0f)
|
|
{
|
|
local_unitized_weight = unitized_weight/current_weight;
|
|
}
|
|
|
|
AnimCombine(blend_result, child_anim, local_unitized_weight);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
--TabCount;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void
|
|
AnimHierarchyIteratorManager::AnimCombine(
|
|
BlendBuffer *target_buffer,
|
|
AnimIterator *anim_iterator,
|
|
Stuff::Scalar percent
|
|
)
|
|
{
|
|
if (Stuff::Small_Enough(percent, 0.01f))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
ANIM_LOGIC("BlendAndApply::AnimCombine");
|
|
Start_Timer(BlendAnimCombine);
|
|
|
|
#if defined(MW4_ANIMATION_HIER_COUNT)
|
|
for (int i = 0; i < TabCount; ++i)
|
|
{
|
|
SPEW(("jerryeds", "\t+"));
|
|
}
|
|
|
|
SPEW(("jerryeds", "|_ AC : %ff :", percent));
|
|
#endif
|
|
|
|
|
|
|
|
for (BYTE channel_number = 0; channel_number < anim_iterator->GetAnimChannelCount(); channel_number++)
|
|
{
|
|
|
|
ChannelAnimData *channel = &anim_iterator->animationInstance->animData->animChannelBlock[channel_number];
|
|
|
|
int joint_number = anim_iterator->animationInstance->jointToIndex[channel->jointNumber];
|
|
|
|
|
|
if (joint_number == -1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
if (anim_iterator->DoISkipChannels())
|
|
{
|
|
if (!(anim_iterator->GetAnimData()->animChannelBlock[channel_number].channelType == MW4Animation::ChannelAnimData::VelocityChannelType ||
|
|
anim_iterator->GetAnimData()->animChannelBlock[channel_number].channelType == MW4Animation::ChannelAnimData::AngularVelocityChannelType) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
if(channel->channelType == MW4Animation::ChannelAnimData::VelocityChannelType)
|
|
{
|
|
Verify(anim_iterator->animationInstance->animData->animChannelBlock[channel_number].keyType ==
|
|
MW4Animation::JointAnimData::VelocityLinearKeyType);
|
|
|
|
|
|
MW4Animation::BaseKeyframe *nextFrame = anim_iterator->GetForwardKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframe *lastFrame = anim_iterator->GetReverseKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframeTime *nextFrameTime = anim_iterator->GetForwardKeyFrameTime(channel_number);
|
|
MW4Animation::BaseKeyframeTime *lastFrameTime = anim_iterator->GetReverseKeyFrameTime(channel_number);
|
|
|
|
|
|
Stuff::Point3D position(Stuff::Point3D::Identity);
|
|
Stuff::Point3D velocity(Stuff::Point3D::Identity);
|
|
|
|
if (lastFrame != NULL && nextFrame != NULL)
|
|
{
|
|
velocity = MW4Animation::Point3DVelPosLinearInterpolator(
|
|
lastFrame, nextFrame, lastFrameTime, nextFrameTime, anim_iterator->GetRealTime());
|
|
|
|
position = MW4Animation::Point3DLinearInterpolator(
|
|
lastFrame, nextFrame, lastFrameTime, nextFrameTime, anim_iterator->GetRealTime());
|
|
}
|
|
else if (lastFrame != NULL)
|
|
{
|
|
velocity = MW4Animation::Point3DVelPosSnapInterpolator(
|
|
lastFrame, lastFrame, lastFrameTime, lastFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
position = MW4Animation::Point3DSnapInterpolator(
|
|
lastFrame, lastFrame, lastFrameTime, lastFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
}
|
|
else if (nextFrame != NULL)
|
|
{
|
|
velocity = MW4Animation::Point3DVelPosSnapInterpolator(
|
|
nextFrame, nextFrame, nextFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
position = MW4Animation::Point3DSnapInterpolator(
|
|
nextFrame, nextFrame, nextFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
}
|
|
else
|
|
{
|
|
STOP(("BOTH KEYFRAMES ARE NULL ! : AnimHierarchyIteratorManager::AnimCombine"));
|
|
}
|
|
|
|
|
|
velocity.Multiply(
|
|
velocity,
|
|
anim_iterator->GetVelocityScale());
|
|
|
|
|
|
if (!target_buffer->IsPositionDirty(joint_number))
|
|
{
|
|
target_buffer->SetDirtyPosition(joint_number);
|
|
target_buffer->positionBuffer[joint_number] = position;
|
|
}
|
|
else
|
|
{
|
|
target_buffer->positionBuffer[joint_number].Lerp(
|
|
target_buffer->positionBuffer[joint_number],
|
|
position,
|
|
percent);
|
|
}
|
|
|
|
if (!target_buffer->IsVelocityDirty(joint_number))
|
|
{
|
|
target_buffer->SetDirtyVelocity(joint_number);
|
|
target_buffer->velocityBuffer[joint_number] = velocity;
|
|
}
|
|
else
|
|
{
|
|
target_buffer->velocityBuffer[joint_number].Lerp(
|
|
target_buffer->velocityBuffer[joint_number],
|
|
velocity,
|
|
percent);
|
|
}
|
|
|
|
|
|
}
|
|
else if (channel->channelType == MW4Animation::ChannelAnimData::AngularVelocityChannelType)
|
|
{
|
|
Verify(anim_iterator->animationInstance->animData->animChannelBlock[channel_number].keyType ==
|
|
MW4Animation::JointAnimData::AngularVelocityLinearKeyType);
|
|
|
|
MW4Animation::BaseKeyframe *nextFrame = anim_iterator->GetForwardKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframe *lastFrame = anim_iterator->GetReverseKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframeTime *nextFrameTime = anim_iterator->GetForwardKeyFrameTime(channel_number);
|
|
MW4Animation::BaseKeyframeTime *lastFrameTime = anim_iterator->GetReverseKeyFrameTime(channel_number);
|
|
|
|
|
|
Stuff::UnitQuaternion rotation(Stuff::UnitQuaternion::Identity);
|
|
Stuff::Vector3D angular_velocity(Stuff::Vector3D::Identity);
|
|
|
|
if (lastFrame != NULL && nextFrame != NULL)
|
|
{
|
|
rotation = MW4Animation::QuaternionLinearInterpolatorSlow(
|
|
lastFrame, nextFrame, lastFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
angular_velocity = MW4Animation::AngularVelocityLinearInterpolator(
|
|
lastFrame, nextFrame, lastFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
}
|
|
else if (lastFrame != NULL)
|
|
{
|
|
rotation = MW4Animation::QuaternionSnapInterpolator(
|
|
lastFrame, lastFrame, lastFrameTime, lastFrameTime,anim_iterator->GetRealTime() );
|
|
|
|
angular_velocity = MW4Animation::AngularVelocitySnapInterpolator(
|
|
lastFrame, lastFrame, lastFrameTime, lastFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
}
|
|
else if (nextFrame != NULL)
|
|
{
|
|
rotation = MW4Animation::QuaternionSnapInterpolator(
|
|
nextFrame, nextFrame, nextFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
|
|
angular_velocity = MW4Animation::AngularVelocitySnapInterpolator(
|
|
nextFrame, nextFrame, nextFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
}
|
|
else
|
|
{
|
|
STOP(("BOTH KEYFRAMES ARE NULL ! : AnimHierarchyIteratorManager::AnimCombine"));
|
|
}
|
|
|
|
angular_velocity.Multiply(
|
|
angular_velocity,
|
|
anim_iterator->GetVelocityScale());
|
|
|
|
if (!target_buffer->IsRotationDirty(joint_number))
|
|
{
|
|
target_buffer->SetDirtyRotation(joint_number);
|
|
target_buffer->rotationBuffer[joint_number] = rotation;
|
|
|
|
rotation.FastNormalize();
|
|
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
rotation.TestInstance();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
rotation.TestInstance();
|
|
target_buffer->rotationBuffer[joint_number].TestInstance();
|
|
#endif
|
|
|
|
Stuff::UnitQuaternion temp = target_buffer->rotationBuffer[joint_number];
|
|
target_buffer->rotationBuffer[joint_number].Lerp(
|
|
temp,
|
|
rotation,
|
|
percent);
|
|
|
|
target_buffer->rotationBuffer[joint_number].Normalize();
|
|
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
target_buffer->rotationBuffer[joint_number].TestInstance();
|
|
#endif
|
|
}
|
|
|
|
if (!target_buffer->IsAngularVelocityDirty(joint_number))
|
|
{
|
|
target_buffer->SetDirtyAngularVelocity(joint_number);
|
|
target_buffer->angularVelocityBuffer[joint_number] = angular_velocity;
|
|
}
|
|
else
|
|
{
|
|
target_buffer->angularVelocityBuffer[joint_number].Lerp(
|
|
target_buffer->angularVelocityBuffer[joint_number],
|
|
angular_velocity,
|
|
percent);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
else if (channel->channelType == MW4Animation::ChannelAnimData::PositionChannelType)
|
|
{
|
|
Verify(anim_iterator->animationInstance->animData->animChannelBlock[channel_number].keyType ==
|
|
MW4Animation::JointAnimData::Point3DLinearKeyType);
|
|
|
|
MW4Animation::BaseKeyframe *nextFrame = anim_iterator->GetForwardKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframe *lastFrame = anim_iterator->GetReverseKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframeTime *nextFrameTime = anim_iterator->GetForwardKeyFrameTime(channel_number);
|
|
MW4Animation::BaseKeyframeTime *lastFrameTime = anim_iterator->GetReverseKeyFrameTime(channel_number);
|
|
|
|
|
|
Stuff::Point3D position(Stuff::Point3D::Identity);
|
|
if (lastFrame != NULL && nextFrame != NULL)
|
|
{
|
|
position = MW4Animation::Point3DLinearInterpolator(
|
|
lastFrame, nextFrame, lastFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
}
|
|
else if (lastFrame != NULL)
|
|
{
|
|
position = MW4Animation::Point3DSnapInterpolator(
|
|
lastFrame, lastFrame, lastFrameTime, lastFrameTime, anim_iterator->GetRealTime() );
|
|
}
|
|
else if (nextFrame != NULL)
|
|
{
|
|
position = MW4Animation::Point3DSnapInterpolator(
|
|
nextFrame, nextFrame, nextFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
}
|
|
else
|
|
{
|
|
STOP(("BOTH KEYFRAMES ARE NULL ! : AnimHierarchyIteratorManager::AnimCombine"));
|
|
}
|
|
|
|
|
|
if (!target_buffer->IsPositionDirty(joint_number))
|
|
{
|
|
target_buffer->SetDirtyPosition(joint_number);
|
|
target_buffer->positionBuffer[joint_number] = position;
|
|
}
|
|
else
|
|
{
|
|
if (doTransitionBlend)
|
|
{
|
|
target_buffer->positionBuffer[joint_number].Lerp(
|
|
target_buffer->positionBuffer[joint_number],
|
|
position,
|
|
percent);
|
|
}
|
|
else
|
|
{
|
|
target_buffer->SetDirtyPosition(joint_number);
|
|
target_buffer->positionBuffer[joint_number] = position;
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (channel->channelType == MW4Animation::ChannelAnimData::RotationChannelType)
|
|
{
|
|
Verify(anim_iterator->animationInstance->animData->animChannelBlock[channel_number].keyType ==
|
|
MW4Animation::JointAnimData::QuaternionLinearKeyType);
|
|
|
|
MW4Animation::BaseKeyframe *nextFrame = anim_iterator->GetForwardKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframe *lastFrame = anim_iterator->GetReverseKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframeTime *nextFrameTime = anim_iterator->GetForwardKeyFrameTime(channel_number);
|
|
MW4Animation::BaseKeyframeTime *lastFrameTime = anim_iterator->GetReverseKeyFrameTime(channel_number);
|
|
|
|
Stuff::UnitQuaternion rotation(Stuff::UnitQuaternion::Identity);
|
|
if (lastFrame != NULL && nextFrame != NULL)
|
|
{
|
|
rotation = MW4Animation::QuaternionLinearInterpolator(
|
|
lastFrame, nextFrame, lastFrameTime, nextFrameTime, anim_iterator->GetRealTime());
|
|
}
|
|
else if (lastFrame != NULL)
|
|
{
|
|
rotation = MW4Animation::QuaternionSnapInterpolator(
|
|
lastFrame, lastFrame, lastFrameTime, lastFrameTime, anim_iterator->GetRealTime());
|
|
}
|
|
else if (nextFrame != NULL)
|
|
{
|
|
rotation = MW4Animation::QuaternionSnapInterpolator(
|
|
nextFrame, nextFrame, nextFrameTime, nextFrameTime, anim_iterator->GetRealTime());
|
|
}
|
|
else
|
|
{
|
|
STOP(("BOTH KEYFRAMES ARE NULL ! : AnimHierarchyIteratorManager::AnimCombine"));
|
|
}
|
|
|
|
if (!target_buffer->IsRotationDirty(joint_number))
|
|
{
|
|
target_buffer->SetDirtyRotation(joint_number);
|
|
rotation.FastNormalize();
|
|
target_buffer->rotationBuffer[joint_number] = rotation;
|
|
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
rotation.TestInstance();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
rotation.TestInstance();
|
|
target_buffer->rotationBuffer[joint_number].TestInstance();
|
|
#endif
|
|
|
|
|
|
Stuff::UnitQuaternion temp = target_buffer->rotationBuffer[joint_number];
|
|
|
|
target_buffer->rotationBuffer[joint_number].FastLerp(
|
|
temp,
|
|
rotation,
|
|
percent);
|
|
|
|
target_buffer->rotationBuffer[joint_number].FastNormalize();
|
|
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
target_buffer->rotationBuffer[joint_number].TestInstance();
|
|
#endif
|
|
}
|
|
}
|
|
else if (channel->channelType == MW4Animation::ChannelAnimData::TriggerChannelType)
|
|
{
|
|
Verify(anim_iterator->animationInstance->animData->animChannelBlock[channel_number].keyType ==
|
|
MW4Animation::JointAnimData::TriggerLinearKeyType);
|
|
|
|
MW4Animation::BaseKeyframe *nextFrame = anim_iterator->GetForwardKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframe *lastFrame = anim_iterator->GetReverseKeyFrame(channel_number);
|
|
MW4Animation::BaseKeyframeTime *nextFrameTime = anim_iterator->GetForwardKeyFrameTime(channel_number);
|
|
MW4Animation::BaseKeyframeTime *lastFrameTime = anim_iterator->GetReverseKeyFrameTime(channel_number);
|
|
|
|
int trigger = 0;
|
|
|
|
if (lastFrame != NULL && nextFrame != NULL)
|
|
{
|
|
trigger = MW4Animation::TriggerSnapInterpolator(
|
|
lastFrame, nextFrame, lastFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
}
|
|
else if (lastFrame != NULL)
|
|
{
|
|
trigger = MW4Animation::TriggerSnapInterpolator(
|
|
lastFrame, lastFrame, lastFrameTime, lastFrameTime, anim_iterator->GetRealTime() );
|
|
}
|
|
else if (nextFrame != NULL)
|
|
{
|
|
trigger = MW4Animation::TriggerSnapInterpolator(
|
|
nextFrame, nextFrame, nextFrameTime, nextFrameTime, anim_iterator->GetRealTime() );
|
|
}
|
|
|
|
if (!target_buffer->IsTriggerDirty(joint_number))
|
|
{
|
|
target_buffer->SetDirtyTrigger(joint_number);
|
|
target_buffer->triggerBuffer[joint_number] = trigger;
|
|
}
|
|
else
|
|
{
|
|
target_buffer->triggerBuffer[joint_number] |= trigger;
|
|
}
|
|
}
|
|
}
|
|
|
|
Stop_Timer(BlendAnimCombine);
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void
|
|
AnimHierarchyIteratorManager::Combine(
|
|
BlendBuffer *target_buffer,
|
|
BlendBuffer *new_buffer,
|
|
Stuff::Scalar percent
|
|
)
|
|
{
|
|
if (Stuff::Small_Enough(percent,0.01f))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
ANIM_LOGIC("BlendAndApply::Combine");
|
|
Start_Timer(BlendCombine);
|
|
|
|
for (int i = 0; i < target_buffer->numberOfJoints; ++i)
|
|
{
|
|
if (new_buffer->IsPositionDirty(i))
|
|
{
|
|
|
|
if (!target_buffer->IsPositionDirty(i))
|
|
{
|
|
target_buffer->SetDirtyPosition(i);
|
|
target_buffer->positionBuffer[i] = new_buffer->positionBuffer[i];
|
|
}
|
|
else
|
|
{
|
|
if (doTransitionBlend)
|
|
{
|
|
target_buffer->SetDirtyPosition(i);
|
|
target_buffer->positionBuffer[i].Lerp(
|
|
target_buffer->positionBuffer[i],
|
|
new_buffer->positionBuffer[i],
|
|
percent);
|
|
}
|
|
else
|
|
{
|
|
target_buffer->SetDirtyPosition(i);
|
|
target_buffer->positionBuffer[i] = new_buffer->positionBuffer[i];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (new_buffer->IsVelocityDirty(i))
|
|
{
|
|
if (!target_buffer->IsVelocityDirty(i))
|
|
{
|
|
target_buffer->SetDirtyVelocity(i);
|
|
target_buffer->velocityBuffer[i] = new_buffer->velocityBuffer[i];
|
|
}
|
|
else
|
|
{
|
|
target_buffer->SetDirtyVelocity(i);
|
|
target_buffer->velocityBuffer[i].Lerp(
|
|
target_buffer->velocityBuffer[i],
|
|
new_buffer->velocityBuffer[i],
|
|
percent);
|
|
}
|
|
}
|
|
|
|
if (new_buffer->IsAngularVelocityDirty(i))
|
|
{
|
|
if (!target_buffer->IsAngularVelocityDirty(i))
|
|
{
|
|
target_buffer->SetDirtyAngularVelocity(i);
|
|
target_buffer->angularVelocityBuffer[i] = new_buffer->angularVelocityBuffer[i];
|
|
}
|
|
else
|
|
{
|
|
target_buffer->SetDirtyAngularVelocity(i);
|
|
|
|
target_buffer->angularVelocityBuffer[i].Lerp(
|
|
target_buffer->angularVelocityBuffer[i],
|
|
new_buffer->angularVelocityBuffer[i],
|
|
percent);
|
|
}
|
|
}
|
|
|
|
if (new_buffer->IsRotationDirty(i))
|
|
{
|
|
if (!target_buffer->IsRotationDirty(i))
|
|
{
|
|
target_buffer->SetDirtyRotation(i);
|
|
target_buffer->rotationBuffer[i] = new_buffer->rotationBuffer[i];
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
new_buffer->rotationBuffer[i].TestInstance();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
target_buffer->SetDirtyRotation(i);
|
|
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
target_buffer->rotationBuffer[i].TestInstance();
|
|
new_buffer->rotationBuffer[i].TestInstance();
|
|
#endif
|
|
|
|
Stuff::UnitQuaternion temp = target_buffer->rotationBuffer[i];
|
|
target_buffer->rotationBuffer[i].FastLerp(
|
|
temp,
|
|
new_buffer->rotationBuffer[i],
|
|
percent);
|
|
|
|
target_buffer->rotationBuffer[i].FastNormalize();
|
|
|
|
#if defined(MW4_ANIMATION_DEBUG)
|
|
target_buffer->rotationBuffer[i].TestInstance();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (new_buffer->IsTriggerDirty(i))
|
|
{
|
|
if (!target_buffer->IsTriggerDirty(i))
|
|
{
|
|
target_buffer->SetDirtyTrigger(i);
|
|
target_buffer->triggerBuffer[i] = new_buffer->triggerBuffer[i];
|
|
}
|
|
else
|
|
{
|
|
target_buffer->SetDirtyTrigger(i);
|
|
target_buffer->triggerBuffer[i] |= new_buffer->triggerBuffer[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
Stop_Timer(BlendCombine);
|
|
|
|
} |