Browse Source

Animation state editing. Note: is a breaking change to AnimatedModel serialization, due to the extra variable needed!

Lasse Öörni 13 years ago
parent
commit
eb3af6e90f

+ 28 - 1
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -76,7 +76,7 @@ void CreateNodeWindow()
 
 
     // Fill vector structure data
     // Fill vector structure data
     Array<String> billboardVariables = {
     Array<String> billboardVariables = {
-        "Number Of Billboards",
+        "Billboard Count",
         "   Position",
         "   Position",
         "   Size", 
         "   Size", 
         "   UV Coordinates", 
         "   UV Coordinates", 
@@ -85,6 +85,17 @@ void CreateNodeWindow()
         "   Is Enabled"
         "   Is Enabled"
     };
     };
     vectorStructs.Push(VectorStruct("BillboardSet", "Billboards", billboardVariables, 1));
     vectorStructs.Push(VectorStruct("BillboardSet", "Billboards", billboardVariables, 1));
+    
+    Array<String> animationStateVariables = {
+        "Anim State Count",
+        "   Animation",
+        "   Start Bone",
+        "   Is Looped",
+        "   Weight",
+        "   Time",
+        "   Layer"
+    };
+    vectorStructs.Push(VectorStruct("AnimatedModel", "Animation States", animationStateVariables, 1));
 
 
     nodeWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorNodeWindow.xml"), uiStyle);
     nodeWindow = ui.LoadLayout(cache.GetResource("XMLFile", "UI/EditorNodeWindow.xml"), uiStyle);
     ui.root.AddChild(nodeWindow);
     ui.root.AddChild(nodeWindow);
@@ -906,6 +917,12 @@ void PickResource(StringHash eventType, VariantMap& eventData)
         String resourceType = GetTypeName(targets[0].attributes[resourcePickIndex].GetResourceRefList().type);
         String resourceType = GetTypeName(targets[0].attributes[resourcePickIndex].GetResourceRefList().type);
         @resourcePicker = GetResourcePicker(resourceType);
         @resourcePicker = GetResourcePicker(resourceType);
     }
     }
+    else if (info.type == VAR_VARIANTVECTOR)
+    {
+        String resourceType = GetTypeName(targets[0].attributes[resourcePickIndex].GetVariantVector()
+            [resourcePickSubIndex].GetResourceRef().type);
+        @resourcePicker = GetResourcePicker(resourceType);
+    }
     else
     else
         @resourcePicker = null;
         @resourcePicker = null;
 
 
@@ -982,6 +999,16 @@ void PickResourceDone(StringHash eventType, VariantMap& eventData)
                 target.ApplyAttributes();
                 target.ApplyAttributes();
             }
             }
         }
         }
+        else if (info.type == VAR_VARIANTVECTOR)
+        {
+            Array<Variant>@ attrs = target.attributes[resourcePickIndex].GetVariantVector();
+            ResourceRef ref = attrs[resourcePickSubIndex].GetResourceRef();
+            ref.type = ShortStringHash(resourcePicker.resourceType);
+            ref.id = StringHash(resourceName);
+            attrs[resourcePickSubIndex] = ref;
+            target.attributes[resourcePickIndex] = Variant(attrs);
+            target.ApplyAttributes();
+        }
     }
     }
 
 
     UpdateAttributes(false);
     UpdateAttributes(false);

+ 1 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -650,6 +650,7 @@ static void RegisterAnimatedModel(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAnimationState(Animation@+)", asMETHODPR(AnimatedModel, RemoveAnimationState, (Animation*), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAnimationState(Animation@+)", asMETHODPR(AnimatedModel, RemoveAnimationState, (Animation*), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAnimationState(const String&in)", asMETHODPR(AnimatedModel, RemoveAnimationState, (const String&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAnimationState(const String&in)", asMETHODPR(AnimatedModel, RemoveAnimationState, (const String&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAnimationState(AnimationState@+)", asMETHODPR(AnimatedModel, RemoveAnimationState, (AnimationState*), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAnimationState(AnimationState@+)", asMETHODPR(AnimatedModel, RemoveAnimationState, (AnimationState*), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedModel", "void RemoveAnimationState(uint)", asMETHODPR(AnimatedModel, RemoveAnimationState, (unsigned), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAllAnimationStates()", asMETHOD(AnimatedModel, RemoveAllAnimationStates), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void RemoveAllAnimationStates()", asMETHOD(AnimatedModel, RemoveAllAnimationStates), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void SetMorphWeight(uint, float)", asMETHODPR(AnimatedModel, SetMorphWeight, (unsigned, float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void SetMorphWeight(uint, float)", asMETHODPR(AnimatedModel, SetMorphWeight, (unsigned, float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void ResetMorphWeights()", asMETHOD(AnimatedModel, ResetMorphWeights), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "void ResetMorphWeights()", asMETHOD(AnimatedModel, ResetMorphWeights), asCALL_THISCALL);

+ 70 - 31
Engine/Graphics/AnimatedModel.cpp

@@ -91,10 +91,10 @@ void AnimatedModel::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Invisible Anim LOD Factor", GetInvisibleLodFactor, SetInvisibleLodFactor, float, 0.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Invisible Anim LOD", GetInvisibleLodFactor, SetInvisibleLodFactor, float, 0.0f, AM_DEFAULT);
     COPY_BASE_ATTRIBUTES(AnimatedModel, Drawable);
     COPY_BASE_ATTRIBUTES(AnimatedModel, Drawable);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector, VariantVector(), AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector, VariantVector(), AM_FILE | AM_NOEDIT);
-    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Animation States", GetAnimationStatesAttr, SetAnimationStatesAttr, VariantVector, VariantVector(), AM_FILE | AM_NOEDIT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Animation States", GetAnimationStatesAttr, SetAnimationStatesAttr, VariantVector, VariantVector(), AM_FILE);
     REF_ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BUFFER, "Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_DEFAULT | AM_NOEDIT);
     REF_ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BUFFER, "Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_DEFAULT | AM_NOEDIT);
 }
 }
 
 
@@ -397,6 +397,19 @@ void AnimatedModel::RemoveAnimationState(Animation* animation)
 {
 {
     if (animation)
     if (animation)
         RemoveAnimationState(animation->GetNameHash());
         RemoveAnimationState(animation->GetNameHash());
+    else
+    {
+        for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
+        {
+            AnimationState* state = *i;
+            if (!state->GetAnimation())
+            {
+                animationStates_.Erase(i);
+                MarkAnimationDirty();
+                return;
+            }
+        }
+    }
 }
 }
 
 
 void AnimatedModel::RemoveAnimationState(const String& animationName)
 void AnimatedModel::RemoveAnimationState(const String& animationName)
@@ -410,11 +423,15 @@ void AnimatedModel::RemoveAnimationState(StringHash animationNameHash)
     {
     {
         AnimationState* state = *i;
         AnimationState* state = *i;
         Animation* animation = state->GetAnimation();
         Animation* animation = state->GetAnimation();
-        // Check both the animation and the resource name
-        if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
+        if (animation)
         {
         {
-            animationStates_.Erase(i);
-            MarkAnimationDirty();
+            // Check both the animation and the resource name
+            if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
+            {
+                animationStates_.Erase(i);
+                MarkAnimationDirty();
+                return;
+            }
         }
         }
     }
     }
 }
 }
@@ -432,6 +449,15 @@ void AnimatedModel::RemoveAnimationState(AnimationState* state)
     }
     }
 }
 }
 
 
+void AnimatedModel::RemoveAnimationState(unsigned index)
+{
+    if (index < animationStates_.Size())
+    {
+        animationStates_.Erase(index);
+        MarkAnimationDirty();
+    }
+}
+
 void AnimatedModel::RemoveAllAnimationStates()
 void AnimatedModel::RemoveAllAnimationStates()
 {
 {
     animationStates_.Clear();
     animationStates_.Clear();
@@ -579,10 +605,12 @@ AnimationState* AnimatedModel::GetAnimationState(const String& animationName) co
     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
     {
     {
         Animation* animation = (*i)->GetAnimation();
         Animation* animation = (*i)->GetAnimation();
-        
-        // Check both the animation and the resource name
-        if (animation->GetName() == animationName || animation->GetAnimationName() == animationName)
-            return *i;
+        if (animation)
+        {
+            // Check both the animation and the resource name
+            if (animation->GetName() == animationName || animation->GetAnimationName() == animationName)
+                return *i;
+        }
     }
     }
     
     
     return 0;
     return 0;
@@ -593,10 +621,12 @@ AnimationState* AnimatedModel::GetAnimationState(StringHash animationNameHash) c
     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
     {
     {
         Animation* animation = (*i)->GetAnimation();
         Animation* animation = (*i)->GetAnimation();
-        
-        // Check both the animation and the resource name
-        if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
-            return *i;
+        if (animation)
+        {
+            // Check both the animation and the resource name
+            if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
+                return *i;
+        }
     }
     }
     
     
     return 0;
     return 0;
@@ -741,26 +771,33 @@ void AnimatedModel::SetAnimationStatesAttr(VariantVector value)
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     RemoveAllAnimationStates();
     RemoveAllAnimationStates();
     unsigned index = 0;
     unsigned index = 0;
-    while (index < value.Size())
+    unsigned numStates = index < value.Size() ? value[index++].GetUInt() : 0;
+    while (numStates)
     {
     {
-        const ResourceRef& animRef = value[index++].GetResourceRef();
-        AnimationState* state = AddAnimationState(cache->GetResource<Animation>(animRef.id_));
-        if (state)
+        if (index < value.Size() - 5)
         {
         {
-            const Variant& startBone = value[index++];
-            // Allow bone name also as String for handcrafted XML data
-            if (startBone.GetType() == VAR_INT)
-                state->SetStartBone(skeleton_.GetBone(startBone.GetStringHash()));
-            else if (startBone.GetType() == VAR_STRING)
-                state->SetStartBone(skeleton_.GetBone(startBone.GetString()));
-            state->SetLooped(value[index++].GetBool());
-            state->SetWeight(value[index++].GetFloat());
-            state->SetTime(value[index++].GetFloat());
-            state->SetLayer(value[index++].GetInt());
+            // Note: null animation is allowed here for editing
+            const ResourceRef& animRef = value[index++].GetResourceRef();
+            SharedPtr<AnimationState> newState(new AnimationState(this, cache->GetResource<Animation>(animRef.id_)));
+            animationStates_.Push(newState);
+            
+            newState->SetStartBone(skeleton_.GetBone(value[index++].GetString()));
+            newState->SetLooped(value[index++].GetBool());
+            newState->SetWeight(value[index++].GetFloat());
+            newState->SetTime(value[index++].GetFloat());
+            newState->SetLayer(value[index++].GetInt());
         }
         }
         else
         else
-            index += 5;
+        {
+            // If not enough data, just add an empty animation state
+            SharedPtr<AnimationState> newState(new AnimationState(this, 0));
+            animationStates_.Push(newState);
+        }
+        
+        --numStates;
     }
     }
+    
+    MarkAnimationOrderDirty();
 }
 }
 
 
 void AnimatedModel::SetMorphsAttr(const PODVector<unsigned char>& value)
 void AnimatedModel::SetMorphsAttr(const PODVector<unsigned char>& value)
@@ -787,12 +824,14 @@ VariantVector AnimatedModel::GetBonesEnabledAttr() const
 VariantVector AnimatedModel::GetAnimationStatesAttr() const
 VariantVector AnimatedModel::GetAnimationStatesAttr() const
 {
 {
     VariantVector ret;
     VariantVector ret;
+    ret.Push(animationStates_.Size());
     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
     {
     {
         AnimationState* state = *i;
         AnimationState* state = *i;
+        Animation* animation = state->GetAnimation();
         Bone* startBone = state->GetStartBone();
         Bone* startBone = state->GetStartBone();
-        ret.Push(ResourceRef(Animation::GetTypeStatic(), state->GetAnimation()->GetNameHash()));
-        ret.Push(startBone ? startBone->nameHash_ : StringHash());
+        ret.Push(ResourceRef(Animation::GetTypeStatic(), animation ? animation->GetNameHash() : StringHash()));
+        ret.Push(startBone ? startBone->name_ : String());
         ret.Push(state->IsLooped());
         ret.Push(state->IsLooped());
         ret.Push(state->GetWeight());
         ret.Push(state->GetWeight());
         ret.Push(state->GetTime());
         ret.Push(state->GetTime());

+ 2 - 0
Engine/Graphics/AnimatedModel.h

@@ -76,6 +76,8 @@ public:
     void RemoveAnimationState(StringHash animationNameHash);
     void RemoveAnimationState(StringHash animationNameHash);
     /// Remove an animation by AnimationState pointer.
     /// Remove an animation by AnimationState pointer.
     void RemoveAnimationState(AnimationState* state);
     void RemoveAnimationState(AnimationState* state);
+    /// Remove an animation by index.
+    void RemoveAnimationState(unsigned index);
     /// Remove all animations.
     /// Remove all animations.
     void RemoveAllAnimationStates();
     void RemoveAllAnimationStates();
     /// Set animation LOD bias.
     /// Set animation LOD bias.

+ 15 - 5
Engine/Graphics/AnimationState.cpp

@@ -43,8 +43,12 @@ AnimationState::AnimationState(AnimatedModel* model, Animation* animation) :
 {
 {
     SetStartBone(0);
     SetStartBone(0);
     
     
-    // Setup a cache for last keyframe of each track
-    lastKeyFrame_.Resize(animation_->GetNumTracks());
+    if (animation_)
+    {
+        // Setup a cache for last keyframe of each track
+        lastKeyFrame_.Resize(animation_->GetNumTracks());
+    }
+    
     for (unsigned i = 0; i < lastKeyFrame_.Size(); ++i)
     for (unsigned i = 0; i < lastKeyFrame_.Size(); ++i)
         lastKeyFrame_[i] = 0;
         lastKeyFrame_[i] = 0;
 }
 }
@@ -55,7 +59,7 @@ AnimationState::~AnimationState()
 
 
 void AnimationState::SetStartBone(Bone* startBone)
 void AnimationState::SetStartBone(Bone* startBone)
 {
 {
-    if (!model_)
+    if (!model_ || !animation_)
         return;
         return;
     
     
     Skeleton& skeleton = model_->GetSkeleton();
     Skeleton& skeleton = model_->GetSkeleton();
@@ -117,6 +121,9 @@ void AnimationState::SetWeight(float weight)
 
 
 void AnimationState::SetTime(float time)
 void AnimationState::SetTime(float time)
 {
 {
+    if (!animation_)
+        return;
+    
     time = Clamp(time, 0.0f, animation_->GetLength());
     time = Clamp(time, 0.0f, animation_->GetLength());
     if (time != time_)
     if (time != time_)
     {
     {
@@ -136,6 +143,9 @@ void AnimationState::AddWeight(float delta)
 
 
 void AnimationState::AddTime(float delta)
 void AnimationState::AddTime(float delta)
 {
 {
+    if (!animation_)
+        return;
+    
     float length = animation_->GetLength();
     float length = animation_->GetLength();
     if (delta == 0.0f || length == 0.0f)
     if (delta == 0.0f || length == 0.0f)
         return;
         return;
@@ -203,12 +213,12 @@ Bone* AnimationState::GetStartBone() const
 
 
 float AnimationState::GetLength() const
 float AnimationState::GetLength() const
 {
 {
-    return animation_->GetLength();
+    return animation_ ? animation_->GetLength() : 0.0f;
 }
 }
 
 
 void AnimationState::Apply()
 void AnimationState::Apply()
 {
 {
-    if (!IsEnabled())
+    if (!animation_ || !IsEnabled())
         return;
         return;
     
     
     // Check first if full weight or blending
     // Check first if full weight or blending