PlayAnimation: Delete previous animations in same slot if no weight is given.

This will simplify fixing several animation leaks.
objectmenu
Sven Eberhardt 2016-01-28 22:02:27 -05:00
parent 80b8879805
commit 1f81b87c33
6 changed files with 40 additions and 19 deletions

View File

@ -28,7 +28,8 @@
<param>
<type>array</type>
<name>weight</name>
<desc>Specifies how to compute the weight of the animation in case the animation is combined with another animation in the given slot. The value needs to be created with one of the "Anim_" animation functions.</desc>
<desc>Specifies how to compute the weight of the animation in case the animation is combined with another animation in the given slot. The value needs to be created with one of the "Anim_" animation functions.<br />If nil, the animation is created with constant weight 1000 and other animations in the same slot are removed.</desc>
<optional />
</param>
<param>
<type>int</type>
@ -45,6 +46,7 @@
</params>
</syntax>
<desc>Starts playing a new animation. The return value of this function is the animation number of the animation node inserted which can be used to manipulate or remove the animation later. If there are already animations in the given slot then additionally a combination node is created. This combination node is assigned the returned number plus 1.</desc>
<remark>If a weight is specified, other animations remain in the slot and are automatically combined. Scripters are responsible for removing animations either by replacing them (pass nil as weight), calling <funclink>StopAnimation</funclink> or using the ANIM_Remove flag in the <funclink>Anim_Linear</funclink> function.</remark>
<remark>See the <emlink href="definition/animations.html">animation documentation</emlink> for further explanations of the animation system.</remark>
<examples>
<example>

View File

@ -1177,26 +1177,26 @@ void StdMeshInstance::SetCompletion(float completion)
#endif
}
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight)
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight, bool stop_previous_animation)
{
const StdMeshAnimation* animation = Mesh->GetSkeleton().GetAnimationByName(animation_name);
if (!animation) { delete position; delete weight; return NULL; }
return PlayAnimation(*animation, slot, sibling, position, weight);
return PlayAnimation(*animation, slot, sibling, position, weight, stop_previous_animation);
}
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight)
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight, bool stop_previous_animation)
{
position->Value = Clamp(position->Value, Fix0, ftofix(animation.Length));
AnimationNode* child = new AnimationNode(&animation, position);
InsertAnimationNode(child, slot, sibling, weight);
InsertAnimationNode(child, slot, sibling, weight, stop_previous_animation);
return child;
}
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshBone* bone, const StdMeshTransformation& trans, int slot, AnimationNode* sibling, ValueProvider* weight)
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdMeshBone* bone, const StdMeshTransformation& trans, int slot, AnimationNode* sibling, ValueProvider* weight, bool stop_previous_animation)
{
AnimationNode* child = new AnimationNode(bone, trans);
InsertAnimationNode(child, slot, sibling, weight);
InsertAnimationNode(child, slot, sibling, weight, stop_previous_animation);
return child;
}
@ -1750,11 +1750,19 @@ StdMeshInstance::AnimationNodeList::iterator StdMeshInstance::GetStackIterForSlo
return AnimationStack.insert(AnimationStack.end(), NULL);
}
void StdMeshInstance::InsertAnimationNode(AnimationNode* node, int slot, AnimationNode* sibling, ValueProvider* weight)
void StdMeshInstance::InsertAnimationNode(AnimationNode* node, int slot, AnimationNode* sibling, ValueProvider* weight, bool stop_previous_animation)
{
assert(!sibling || !stop_previous_animation);
// Default
if (!sibling) sibling = GetRootAnimationForSlot(slot);
assert(!sibling || sibling->Slot == slot);
// Stop any animation already running in this slot?
if (sibling && stop_previous_animation)
{
StopAnimation(sibling);
sibling = NULL;
}
// Find two subsequent numbers in case we need to create two nodes, so
// script can deduce the second node.

View File

@ -541,9 +541,9 @@ public:
void SetCompletion(float completion);
float GetCompletion() const { return Completion; }
AnimationNode* PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight);
AnimationNode* PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight);
AnimationNode* PlayAnimation(const StdMeshBone* bone, const StdMeshTransformation& trans, int slot, AnimationNode* sibling, ValueProvider* weight);
AnimationNode* PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight, bool stop_previous_animation);
AnimationNode* PlayAnimation(const StdMeshAnimation& animation, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight, bool stop_previous_animation);
AnimationNode* PlayAnimation(const StdMeshBone* bone, const StdMeshTransformation& trans, int slot, AnimationNode* sibling, ValueProvider* weight, bool stop_previous_animation);
void StopAnimation(AnimationNode* node);
AnimationNode* GetAnimationNodeByNumber(unsigned int number);
@ -627,7 +627,7 @@ protected:
typedef std::vector<AnimationNode*> AnimationNodeList;
AnimationNodeList::iterator GetStackIterForSlot(int slot, bool create);
void InsertAnimationNode(AnimationNode* node, int slot, AnimationNode* sibling, ValueProvider* weight);
void InsertAnimationNode(AnimationNode* node, int slot, AnimationNode* sibling, ValueProvider* weight, bool stop_previous_animation);
bool ExecuteAnimationNode(AnimationNode* node);
void ApplyBoneTransformToVertices(const std::vector<StdSubMesh::Vertex>& mesh_vertices, std::vector<StdMeshVertex>& instance_vertices);
void SetBoneTransformsDirty(bool value);

View File

@ -767,7 +767,7 @@ void C4GraphicsOverlay::UpdateFacet()
const StdMeshAnimation* Animation = pSourceGfx->Mesh->GetSkeleton().GetAnimationByName(AnimationName->GetData());
if (!Animation) return;
pMeshInstance->PlayAnimation(*Animation, 0, NULL, new C4ValueProviderRef<int32_t>(iPhase, ftofix(Animation->Length / action->GetPropertyInt(P_Length))), new C4ValueProviderConst(itofix(1)));
pMeshInstance->PlayAnimation(*Animation, 0, NULL, new C4ValueProviderRef<int32_t>(iPhase, ftofix(Animation->Length / action->GetPropertyInt(P_Length))), new C4ValueProviderConst(itofix(1)), true);
}
break;

View File

@ -2863,7 +2863,7 @@ bool C4Object::SetAction(C4PropList * Act, C4Object *pTarget, C4Object *pTarget2
if (Animation)
{
// note that weight is ignored
Action.Animation = pMeshInstance->PlayAnimation(Animation->GetData(), 0, NULL, new C4ValueProviderAction(this), new C4ValueProviderConst(itofix(1)));
Action.Animation = pMeshInstance->PlayAnimation(Animation->GetData(), 0, NULL, new C4ValueProviderAction(this), new C4ValueProviderConst(itofix(1)), true);
}
}
// Stop previous act sound

View File

@ -1806,13 +1806,16 @@ static long FnGetUnusedOverlayID(C4Object *Obj, long iBaseIndex)
return iBaseIndex;
}
static Nillable<int> FnPlayAnimation(C4Object *Obj, C4String *szAnimation, int iSlot, C4ValueArray* PositionProvider, C4ValueArray* WeightProvider, Nillable<int> iSibling, Nillable<int> iAttachNumber)
static Nillable<int> FnPlayAnimation(C4Object *Obj, C4String *szAnimation, int iSlot, C4ValueArray* PositionProvider, Nillable<C4ValueArray*> WeightProvider, Nillable<int> iSibling, Nillable<int> iAttachNumber)
{
if (!Obj) return C4Void();
if (!Obj->pMeshInstance) return C4Void();
if (iSlot == 0) return C4Void(); // Reserved for ActMap animations
if (!PositionProvider) return C4Void();
if (!WeightProvider) return C4Void();
// If no weight provider is passed, this animation should be played exclusively.
bool stop_previous_animations = WeightProvider.IsNil();
// Exclusive mode cannot work with a sibling
if (!iSibling.IsNil() && stop_previous_animations) return C4Void();
StdMeshInstance* Instance = Obj->pMeshInstance;
if (!iAttachNumber.IsNil())
@ -1834,7 +1837,15 @@ static Nillable<int> FnPlayAnimation(C4Object *Obj, C4String *szAnimation, int i
if (!animation) return C4Void();
StdMeshInstance::ValueProvider* p_provider = CreateValueProviderFromArray(Obj, *PositionProvider, animation);
StdMeshInstance::ValueProvider* w_provider = CreateValueProviderFromArray(Obj, *WeightProvider);
StdMeshInstance::ValueProvider* w_provider;
if (stop_previous_animations)
{
w_provider = new C4ValueProviderConst(Fix1);
}
else
{
w_provider = CreateValueProviderFromArray(Obj, *WeightProvider);
}
if (!p_provider || !w_provider)
{
delete p_provider;
@ -1842,7 +1853,7 @@ static Nillable<int> FnPlayAnimation(C4Object *Obj, C4String *szAnimation, int i
return C4Void();
}
StdMeshInstance::AnimationNode* n_node = Instance->PlayAnimation(*animation, iSlot, s_node, p_provider, w_provider);
StdMeshInstance::AnimationNode* n_node = Instance->PlayAnimation(*animation, iSlot, s_node, p_provider, w_provider, stop_previous_animations);
if (!n_node) return C4Void();
return n_node->GetNumber();
@ -1892,7 +1903,7 @@ static Nillable<int> FnTransformBone(C4Object *Obj, C4String *szBoneName, C4Valu
// a check here and return nil if the matrix cannot be decomposed.
StdMeshTransformation trans = matrix.Decompose();
StdMeshInstance::AnimationNode* n_node = Instance->PlayAnimation(bone, trans, iSlot, s_node, w_provider);
StdMeshInstance::AnimationNode* n_node = Instance->PlayAnimation(bone, trans, iSlot, s_node, w_provider, false);
if (!n_node) return C4Void();
return n_node->GetNumber();