Parcourir la source

animation blending partially completed.
getting latest to avoid merge hell later.

Kieran Cunney il y a 14 ans
Parent
commit
da74e21dec

+ 34 - 20
gameplay/src/Animation.cpp

@@ -22,17 +22,15 @@ namespace gameplay
 {
 {
 
 
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, unsigned int type)
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, unsigned int type)
-    : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0)
+    : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0), _defaultClip(NULL), _clips(NULL)
 {
 {
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, type);
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, type);
-    createDefaultClip();
 }
 }
 
 
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, unsigned int type)
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, unsigned int type)
-    : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0)
+    : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0), _defaultClip(NULL), _clips(NULL)
 {
 {
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
-    createDefaultClip();
 }
 }
 
 
 Animation::~Animation()
 Animation::~Animation()
@@ -46,15 +44,18 @@ Animation::~Animation()
     }
     }
     _channels.clear();
     _channels.clear();
     
     
-    std::vector<AnimationClip*>::iterator clipIter = _clips.begin();
-    
-    while (clipIter != _clips.end())
+    if (_clips != NULL)
     {
     {
-        AnimationClip* clip = *clipIter;
-        SAFE_RELEASE(clip);
-        clipIter++;
+        std::vector<AnimationClip*>::iterator clipIter = _clips->begin();
+    
+        while (clipIter != _clips->end())
+        {   
+            AnimationClip* clip = *clipIter;
+            SAFE_RELEASE(clip);
+            clipIter++;
+        }
+        _clips->clear();
     }
     }
-    _clips.clear();
 }
 }
 
 
 Animation::Channel::Channel(AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
 Animation::Channel::Channel(AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
@@ -135,7 +136,7 @@ void Animation::createClips(const char* animationFile)
 
 
 AnimationClip* Animation::createClip(const char* id, unsigned long start, unsigned long end)
 AnimationClip* Animation::createClip(const char* id, unsigned long start, unsigned long end)
 {
 {
-    if (findClip(id) != NULL)
+    if (_clips != NULL && findClip(id) != NULL)
     {
     {
         return NULL;
         return NULL;
     }
     }
@@ -152,7 +153,10 @@ AnimationClip* Animation::getClip(const char* id)
     // If id is NULL return the default clip.
     // If id is NULL return the default clip.
     if (id == NULL)
     if (id == NULL)
     {
     {
-        return _clips[ANIMATION_DEFAULT_CLIP];
+        if (_defaultClip == NULL)
+            createDefaultClip();
+
+        return _defaultClip;
     }
     }
     else
     else
     {
     {
@@ -165,7 +169,10 @@ void Animation::play(const char* id)
     // If id is NULL, play the default clip.
     // If id is NULL, play the default clip.
     if (id == NULL)
     if (id == NULL)
     {
     {
-        _clips[ANIMATION_DEFAULT_CLIP]->play();
+        if (_defaultClip == NULL)
+            createDefaultClip();
+        
+        _defaultClip->play();
     }
     }
     else
     else
     {
     {
@@ -183,7 +190,10 @@ void Animation::stop(const char* id)
     // If id is NULL, play the default clip.
     // If id is NULL, play the default clip.
     if (id == NULL)
     if (id == NULL)
     {
     {
-        _clips[ANIMATION_DEFAULT_CLIP]->stop();
+        if (_defaultClip == NULL)
+            createDefaultClip();
+
+        _defaultClip->stop();
     }
     }
     else
     else
     {
     {
@@ -305,22 +315,26 @@ void Animation::addChannel(Channel* channel)
 void Animation::createDefaultClip()
 void Animation::createDefaultClip()
 {
 {
     std::string clipId = _id + ANIMATION_DEFAULT_CLIP_SUFFIX;
     std::string clipId = _id + ANIMATION_DEFAULT_CLIP_SUFFIX;
-    _clips.push_back(new AnimationClip(clipId.c_str(), this, 0.0f, _duration));
+
+    _defaultClip = new AnimationClip(clipId.c_str(), this, 0.0f, _duration);
 }
 }
 
 
 void Animation::addClip(AnimationClip* clip)
 void Animation::addClip(AnimationClip* clip)
 {
 {
-    _clips.push_back(clip);
+    if (_clips == NULL)
+        _clips = new std::vector<AnimationClip*>;
+
+    _clips->push_back(clip);
 }
 }
 
 
 AnimationClip* Animation::findClip(const char* id) const
 AnimationClip* Animation::findClip(const char* id) const
 {
 {
-    unsigned int clipCount = _clips.size();
+    unsigned int clipCount = _clips->size();
     for (unsigned int i = 0; i < clipCount; i++)
     for (unsigned int i = 0; i < clipCount; i++)
     {
     {
-        if (_clips.at(i)->_id.compare(id) == 0)
+        if (_clips->at(i)->_id.compare(id) == 0)
         {
         {
-            return _clips.at(i);
+            return _clips->at(i);
         }
         }
     }
     }
     return NULL;
     return NULL;

+ 2 - 1
gameplay/src/Animation.h

@@ -170,7 +170,8 @@ private:
     std::string _id;                        // The Animation's ID.
     std::string _id;                        // The Animation's ID.
     unsigned long _duration;                // the length of the animation (in milliseconds).
     unsigned long _duration;                // the length of the animation (in milliseconds).
     std::vector<Channel*> _channels;        // The channels within this Animation.
     std::vector<Channel*> _channels;        // The channels within this Animation.
-    std::vector<AnimationClip*> _clips;     // All the clips created from this Animation.
+    AnimationClip* _defaultClip;
+    std::vector<AnimationClip*>* _clips;     // All the clips created from this Animation.
 };
 };
 
 
 }
 }

+ 310 - 14
gameplay/src/AnimationClip.cpp

@@ -7,21 +7,25 @@
 #include "Animation.h"
 #include "Animation.h"
 #include "AnimationTarget.h"
 #include "AnimationTarget.h"
 #include "Game.h"
 #include "Game.h"
+#include "Quaternion.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
-    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _elapsedTime(0), _runningTime(0), _channelCount(animation->_channels.size()), _repeatCount(1.0f), _speed(1.0f), _isPlaying(false), _beginListeners(NULL), _endListeners(NULL)
+    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), _repeatCount(1.0f), _activeDuration(_duration * _repeatCount), _speed(1.0f), _isPlaying(false), 
+      _timeStarted(0), _elapsedTime(0), _runningTime(0), _channelPriority(NULL), _crossFadeClip(NULL), _crossFadeFrom(NULL), _crossFadeStart(0), _crossFadeInDuration(0), _crossFadeOutDuration(0), _blendWeight(1.0f), _isFadingOut(false), _isFadingIn(false),  
+      _beginListeners(NULL), _endListeners(NULL)
 {
 {
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
-
-    _duration = (_endTime - _startTime);
-    _activeDuration = _duration * _repeatCount;
     
     
-    for (unsigned int i = 0; i < _channelCount; i++)
+    unsigned int channelCount = _animation->_channels.size();
+    _channelPriority = new unsigned int[channelCount];
+    
+    for (unsigned int i = 0; i < channelCount; i++)
     {
     {
         _values.push_back(new AnimationValue(_animation->_channels[i]->_curve->getComponentCount()));
         _values.push_back(new AnimationValue(_animation->_channels[i]->_curve->getComponentCount()));
+        _channelPriority[i] = 0;
     }
     }
 }
 }
 
 
@@ -58,6 +62,10 @@ AnimationClip::~AnimationClip()
         _endListeners->clear();
         _endListeners->clear();
         SAFE_DELETE(_endListeners);
         SAFE_DELETE(_endListeners);
     }
     }
+
+    SAFE_DELETE_ARRAY(_channelPriority);
+
+    SAFE_RELEASE(_crossFadeClip);
 }
 }
 
 
 const char* AnimationClip::getID() const
 const char* AnimationClip::getID() const
@@ -146,12 +154,46 @@ bool AnimationClip::isPlaying() const
 void AnimationClip::play()
 void AnimationClip::play()
 {
 {
     _animation->_controller->schedule(this);
     _animation->_controller->schedule(this);
+    _timeStarted = Game::getGameTime();
 }
 }
 
 
 void AnimationClip::stop()
 void AnimationClip::stop()
 {
 {
     _animation->_controller->unschedule(this);
     _animation->_controller->unschedule(this);
-    _isPlaying = false;
+    if (_isPlaying)
+    {
+        _isPlaying = false;
+        onEnd();
+    }
+}
+
+void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
+{
+    if (_crossFadeClip)
+        _crossFadeClip->release();
+
+    _crossFadeClip = clip;
+    clip->addRef();
+
+    _crossFadeClip->_isFadingOut = false;
+    _crossFadeClip->_isFadingIn = true;
+    _crossFadeClip->_crossFadeInDuration = duration;
+    _crossFadeClip->_crossFadeFrom = this;
+    //_crossFadeClip->_inBlendWeight = 0.0f;
+    _isFadingOut = true;
+    _isFadingIn = false;
+
+    if (_crossFadeFrom)
+    {
+        _crossFadeFrom->release();
+        _crossFadeFrom = NULL;
+    }
+
+    _crossFadeOutDuration = duration;
+    _crossFadeStart = (Game::getGameTime() - _timeStarted);
+
+    //if (!_crossFadeClip->_isPlaying)
+        _crossFadeClip->play();
 }
 }
 
 
 void AnimationClip::addBeginListener(AnimationClip::Listener* listener)
 void AnimationClip::addBeginListener(AnimationClip::Listener* listener)
@@ -173,11 +215,17 @@ void AnimationClip::addEndListener(AnimationClip::Listener* listener)
 bool AnimationClip::update(unsigned long elapsedTime)
 bool AnimationClip::update(unsigned long elapsedTime)
 {
 {
     if (!_isPlaying)
     if (!_isPlaying)
+    {
         onBegin();
         onBegin();
-
-    // Update elapsed time.
-    _elapsedTime += elapsedTime;
-    _runningTime += elapsedTime * _speed;
+        _elapsedTime = Game::getGameTime() - _timeStarted;
+        _runningTime = _elapsedTime * _speed;
+    }
+    else
+    {
+        // Update elapsed time.
+        _elapsedTime += elapsedTime;
+        _runningTime += elapsedTime * 0.25;
+    }
 
 
     float percentComplete = 0.0f;
     float percentComplete = 0.0f;
 
 
@@ -186,9 +234,15 @@ bool AnimationClip::update(unsigned long elapsedTime)
     {
     {
         _isPlaying = false;
         _isPlaying = false;
         if (_speed >= 0)
         if (_speed >= 0)
+        {
             percentComplete = _activeDuration % _duration; // Get's the fractional part of the final repeat.
             percentComplete = _activeDuration % _duration; // Get's the fractional part of the final repeat.
+            if (percentComplete == 0.0f)
+                percentComplete = _duration;
+        }
         else
         else
+        {
             percentComplete = 0.0f; // If we are negative speed, the end value should be 0.
             percentComplete = 0.0f; // If we are negative speed, the end value should be 0.
+        }
     }
     }
     else
     else
     {
     {
@@ -199,16 +253,222 @@ bool AnimationClip::update(unsigned long elapsedTime)
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
     percentComplete = (float)(_startTime + percentComplete) / (float) _animation->_duration;
     percentComplete = (float)(_startTime + percentComplete) / (float) _animation->_duration;
 
 
+    if (_isFadingIn)
+    {
+        if ((unsigned long) _elapsedTime < _crossFadeInDuration)
+        {
+            _blendWeight = (float) _elapsedTime / (float) _crossFadeInDuration;
+        }
+        else
+        {
+            _blendWeight = 1.0f;
+            _isFadingIn = false;
+        }
+
+        if (_isFadingOut)
+        {
+            unsigned long elapsedFade = (_elapsedTime - _crossFadeStart) ;//* _speed;
+            if (elapsedFade < _crossFadeOutDuration)
+            {
+                _blendWeight = (float) (_crossFadeOutDuration - elapsedFade) / (float) _crossFadeOutDuration;
+                //_crossFadeClip->_blendWeight *= (1.0f - _blendWeight);// * _inBlendWeight;
+            }
+            else
+            {
+                _blendWeight = 0.0f;
+                _isFadingOut = false;
+                //_crossFadeClip->_blendWeight = 1.0f;
+                //_crossFadeClip->_isFadingIn = false;
+                _crossFadeClip->release();
+                _crossFadeClip = NULL;
+                _isPlaying = false;
+            }
+        }
+    }
+    else if (_isFadingOut)
+    {
+        unsigned long elapsedFade = (_elapsedTime - _crossFadeStart) ;//* _speed;
+        if (elapsedFade < _crossFadeOutDuration)
+        {
+            _blendWeight = (float) (_crossFadeOutDuration - elapsedFade) / (float) _crossFadeOutDuration;
+            //_crossFadeClip->_blendWeight *= (1.0f - _blendWeight);// * _inBlendWeight;
+        }
+        else
+        {
+            _blendWeight = 0.0f;
+            _isFadingOut = false;
+            //_crossFadeClip->_blendWeight = 1.0f;
+            //_crossFadeClip->_isFadingIn = false;
+            _crossFadeClip->release();
+            _crossFadeClip = NULL;
+            _isPlaying = false;
+        }
+
+        /*if (_isFadingIn)
+        {
+            if ((unsigned long) _elapsedTime < _crossFadeInDuration)
+            {
+                _blendWeight *= (float) _elapsedTime / (float) _crossFadeInDuration;
+            }
+            else
+            {
+                _blendWeight *= 1.0f;
+                _isFadingIn = false;
+            }
+        }*/
+    }
+
+    /*float fadingOutBlendWeight = 0.0f;
+
+    if (_crossFadeFrom)
+        fadingOutBlendWeight = _crossFadeFrom->_blendWeight + _blendWeight;*/
+
     // Evaluate this clip.
     // Evaluate this clip.
     Animation::Channel* channel = NULL;
     Animation::Channel* channel = NULL;
     AnimationValue* value = NULL;
     AnimationValue* value = NULL;
-    for (unsigned int i = 0; i < _channelCount; i++)
+    unsigned int channelCount = _animation->_channels.size();
+    for (unsigned int i = 0; i < channelCount; i++)
     {
     {
         channel = _animation->_channels[i];
         channel = _animation->_channels[i];
-        value = _values.at(i);
+        value = _values[i];
+
+        // Get the current value.
+        channel->_target->getAnimationPropertyValue(channel->_propertyId, value);
+
+        unsigned int activeAnimationCount = channel->_target->getActiveAnimationCount();
+        // My channel priority has changed if my priority is greater than the active animation count.
+        if (_channelPriority[i] > activeAnimationCount)
+        {
+            // Readjust channel priority.
+            _channelPriority[i] -= (_channelPriority[i] - activeAnimationCount);
+        }
 
 
-        // Evaluate point on curve.
-        channel->_curve->evaluate(percentComplete, value->_currentValue);
+        if (_blendWeight != 0.0f)
+        {
+            // Evaluate point on Curve.
+            //channel->_curve->evaluate(percentComplete, value->_currentValue);
+            channel->_curve->evaluate(percentComplete, value->_interpolatedValue);
+
+            if (channel->_curve->_quaternionOffsetsCount == 0)
+            {
+                if (_channelPriority[i] == 1)
+                {
+                    unsigned int componentCount = value->_componentCount;
+                    for (unsigned int j = 0; j < componentCount; j++)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
+
+                        value->_currentValue[j] = value->_interpolatedValue[j];
+                    }
+                }
+                else
+                {
+                    unsigned int componentCount = value->_componentCount;
+                    for (unsigned int j = 0; j < componentCount; j++)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
+
+                        value->_currentValue[j] += value->_interpolatedValue[j];
+                    }
+                }
+            }
+            else
+            {   //We have Quaternions!!!
+                unsigned int j = 0;
+                unsigned int quaternionOffsetIndex = 0;
+                unsigned int quaternionOffset = 0;
+
+                if (_channelPriority[i] == 1)
+                {
+                    do {
+                        quaternionOffset = channel->_curve->_quaternionOffsets[quaternionOffsetIndex];
+                        while (j < quaternionOffset)
+                        {
+                            if (_blendWeight != 1.0f)
+                                value->_interpolatedValue[j] *= _blendWeight;
+
+                            value->_currentValue[j] = value->_interpolatedValue[j];
+                            j++;
+                        }
+
+                        // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+
+                        Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
+                        Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
+
+                        // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
+                        if (_blendWeight != 1.0f)
+                            Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
+                    
+                        // Add in contribution.
+                        currentQuaternion->set(*interpolatedQuaternion);
+                    
+                        // Increase by 4.
+                        j += 4;
+                        quaternionOffsetIndex++;
+                    } while (quaternionOffsetIndex < channel->_curve->_quaternionOffsetsCount);
+
+                    unsigned int componentCount = value->_componentCount;
+                    // Handle remaining scalar values.
+                    while (j < componentCount)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
+
+                        value->_currentValue[j] = value->_interpolatedValue[j];
+                        j++;
+                    }
+                }
+                else
+                {
+                    do {
+                        quaternionOffset = channel->_curve->_quaternionOffsets[quaternionOffsetIndex];
+                        while (j < quaternionOffset)
+                        {
+                            if (_blendWeight != 1.0f)
+                                value->_interpolatedValue[j] *= _blendWeight;
+
+                            value->_currentValue[j] += value->_interpolatedValue[j];
+                            j++;
+                        }
+
+                        // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+
+                        Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
+                        Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
+
+                        // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
+                        if (_blendWeight != 1.0f)
+                            Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
+                    
+                        // Add in contribution.
+                        //Quaternion::multiply(*, *currentQuaternion, currentQuaternion);
+                        currentQuaternion->multiply(*interpolatedQuaternion);
+                    
+                        // Increase by 4.
+                        j += 4;
+                        quaternionOffsetIndex++;
+                    } while (quaternionOffsetIndex < channel->_curve->_quaternionOffsetsCount);
+
+                    unsigned int componentCount = value->_componentCount;
+                    // Handle remaining scalar values.
+                    while (j < componentCount)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
+
+                        value->_currentValue[j] += value->_interpolatedValue[j];
+                        j++;
+                    }
+                }
+            }
+        }
+        else if (_channelPriority[i] == 1)
+        {
+            memset(value->_currentValue, 0.0f, value->_componentCount);
+        }
         
         
         // Set the animation value on the target property.
         // Set the animation value on the target property.
         channel->_target->setAnimationPropertyValue(channel->_propertyId, value);
         channel->_target->setAnimationPropertyValue(channel->_propertyId, value);
@@ -238,6 +498,22 @@ void AnimationClip::onBegin()
         _runningTime = _activeDuration;
         _runningTime = _activeDuration;
     }
     }
 
 
+    Animation::Channel* channel = NULL;
+    AnimationValue* value = NULL;
+    AnimationTarget* target = NULL;
+    unsigned int channelCount = _animation->_channels.size();
+    // Sets the starting value.
+    for (unsigned int i = 0; i < channelCount; i++)
+    {
+        channel = _animation->_channels[i];
+        value = _values[i];
+        target = channel->_target;
+
+        target->increaseActiveAnimationCount();
+        _channelPriority[i] = target->getActiveAnimationCount();
+    }
+
+    // Notify begin listeners.. if any.
     if (_beginListeners)
     if (_beginListeners)
     {
     {
         std::vector<Listener*>::iterator listener = _beginListeners->begin();
         std::vector<Listener*>::iterator listener = _beginListeners->begin();
@@ -251,6 +527,26 @@ void AnimationClip::onBegin()
 
 
 void AnimationClip::onEnd()
 void AnimationClip::onEnd()
 {
 {
+    Animation::Channel* channel = NULL;
+    AnimationValue* value = NULL;
+    AnimationTarget* target = NULL;
+    unsigned int channelCount = _animation->_channels.size();
+    for (unsigned int i = 0; i < channelCount; i++)
+    {
+        channel = _animation->_channels[i];
+        value = _values[i];
+        target = channel->_target;
+        // Reset the clips channel priority, and decrease the active animation count on the target.
+        _channelPriority[i] = 0;
+        target->decreaseActiveAnimationCount();
+    }
+
+    _blendWeight = 1.0f;
+    _isFadingIn = false;
+    _isFadingOut = false;
+    _timeStarted = 0;
+
+    // Notify end listeners if any.
     if (_endListeners)
     if (_endListeners)
     {
     {
         std::vector<Listener*>::iterator listener = _endListeners->begin();
         std::vector<Listener*>::iterator listener = _endListeners->begin();

+ 17 - 6
gameplay/src/AnimationClip.h

@@ -158,6 +158,8 @@ public:
      */
      */
     void stop();
     void stop();
 
 
+    void crossFade(AnimationClip* clip, unsigned long duration);
+
     /**
     /**
      * Adds a animation begin listener.
      * Adds a animation begin listener.
      *
      *
@@ -213,15 +215,24 @@ private:
     Animation* _animation;                    // Animations that this clip plays in parallel.
     Animation* _animation;                    // Animations that this clip plays in parallel.
     unsigned long _startTime;                 // Start time of the clip.
     unsigned long _startTime;                 // Start time of the clip.
     unsigned long _endTime;                   // End time of the clip.
     unsigned long _endTime;                   // End time of the clip.
-    unsigned long _elapsedTime;               // Time elapsed while the clip is running.
-    long _runningTime;                        // Keeps track of the Animation's relative time in respect to the active duration.
-    unsigned int _channelCount;               // The number of channels in the clip.
-    std::vector<AnimationValue*> _values;     // AnimationValue holder.
-    float _repeatCount;                       // The clip's repeat count.
-    float _speed;                             // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
     unsigned long _duration;                  // The total duration.
     unsigned long _duration;                  // The total duration.
+    float _repeatCount;                       // The clip's repeat count.
     unsigned long _activeDuration;            // The active duration of the clip.
     unsigned long _activeDuration;            // The active duration of the clip.
+    float _speed;                             // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
     bool _isPlaying;                          // A flag to indicate whether the clip is playing.
     bool _isPlaying;                          // A flag to indicate whether the clip is playing.
+    unsigned long _timeStarted;               // The game time when this clip was actually started.
+    unsigned long _elapsedTime;               // Time elapsed while the clip is running.
+    long _runningTime;                        // Keeps track of the Animation's relative time in respect to the active duration.
+    unsigned int* _channelPriority;
+    AnimationClip* _crossFadeClip;
+    AnimationClip* _crossFadeFrom;
+    unsigned long _crossFadeStart;
+    unsigned long _crossFadeInDuration;
+    unsigned long _crossFadeOutDuration;
+    float _blendWeight;
+    bool _isFadingOut;
+    bool _isFadingIn;
+    std::vector<AnimationValue*> _values;     // AnimationValue holder.
     std::vector<Listener*>* _beginListeners;
     std::vector<Listener*>* _beginListeners;
     std::vector<Listener*>* _endListeners;
     std::vector<Listener*>* _endListeners;
 };
 };

+ 3 - 2
gameplay/src/AnimationController.cpp

@@ -113,10 +113,10 @@ void AnimationController::stopAllAnimations()
     while (clipIter != _runningClips.end())
     while (clipIter != _runningClips.end())
     {
     {
         AnimationClip* clip = *clipIter;
         AnimationClip* clip = *clipIter;
-        clipIter = _runningClips.erase(clipIter);
         clip->_isPlaying = false;
         clip->_isPlaying = false;
+        clip->onEnd();
+        clipIter = _runningClips.erase(clipIter);
         SAFE_RELEASE(clip);
         SAFE_RELEASE(clip);
-        clipIter++;
     }
     }
 
 
     _state = IDLE;
     _state = IDLE;
@@ -161,6 +161,7 @@ void AnimationController::schedule(AnimationClip* clip)
     {
     {
         _runningClips.remove(clip);
         _runningClips.remove(clip);
         clip->_isPlaying = false;
         clip->_isPlaying = false;
+        clip->onEnd();
     }
     }
     else
     else
     {
     {

+ 16 - 1
gameplay/src/AnimationTarget.cpp

@@ -13,7 +13,7 @@ namespace gameplay
 {
 {
 
 
 AnimationTarget::AnimationTarget()
 AnimationTarget::AnimationTarget()
-    : _targetType(SCALAR), _animations(NULL)
+    : _targetType(SCALAR), _activeAnimationCount(0), _animations(NULL)
 {
 {
 }
 }
 
 
@@ -78,6 +78,21 @@ Animation* AnimationTarget::getAnimation(const char* id) const
     return NULL;
     return NULL;
 }
 }
 
 
+void AnimationTarget::increaseActiveAnimationCount()
+{
+    _activeAnimationCount++;
+}
+
+void AnimationTarget::decreaseActiveAnimationCount()
+{
+    _activeAnimationCount--;
+}
+
+unsigned int AnimationTarget::getActiveAnimationCount() const
+{
+    return _activeAnimationCount;
+}
+
 }
 }
 
 
 
 

+ 8 - 0
gameplay/src/AnimationTarget.h

@@ -21,6 +21,7 @@ class AnimationValue;
 class AnimationTarget : public Ref
 class AnimationTarget : public Ref
 {
 {
     friend class Animation;
     friend class Animation;
+    friend class AnimationClip;
     friend class AnimationController;
     friend class AnimationController;
 
 
 public:
 public:
@@ -104,6 +105,13 @@ private:
      */
      */
     AnimationTarget(const AnimationTarget& copy);
     AnimationTarget(const AnimationTarget& copy);
 
 
+    void increaseActiveAnimationCount();
+
+    void decreaseActiveAnimationCount();
+
+    unsigned int getActiveAnimationCount() const;
+
+    unsigned int _activeAnimationCount;
     std::vector<Animation*>* _animations;
     std::vector<Animation*>* _animations;
 
 
 };
 };

+ 3 - 1
gameplay/src/AnimationValue.cpp

@@ -9,14 +9,16 @@ namespace gameplay
 {
 {
 
 
 AnimationValue::AnimationValue(unsigned int componentCount)
 AnimationValue::AnimationValue(unsigned int componentCount)
-  : _componentCount(componentCount)
+  : _componentCount(componentCount), _componentSize(componentCount * sizeof(float))
 {
 {
     _currentValue = new float[_componentCount];
     _currentValue = new float[_componentCount];
+    _interpolatedValue = new float[_componentCount];
 }
 }
 
 
 AnimationValue::~AnimationValue()
 AnimationValue::~AnimationValue()
 {
 {
     SAFE_DELETE_ARRAY(_currentValue);
     SAFE_DELETE_ARRAY(_currentValue);
+    SAFE_DELETE_ARRAY(_interpolatedValue);
 }
 }
 
 
 float AnimationValue::getFloat(unsigned int index) const
 float AnimationValue::getFloat(unsigned int index) const

+ 2 - 0
gameplay/src/AnimationValue.h

@@ -77,7 +77,9 @@ private:
     ~AnimationValue();
     ~AnimationValue();
 
 
     unsigned int _componentCount;   // The number of float values for the property.
     unsigned int _componentCount;   // The number of float values for the property.
+    unsigned int _componentSize;
     float* _currentValue;           // The current value of the property.
     float* _currentValue;           // The current value of the property.
+    float* _interpolatedValue;
 };
 };
 
 
 }
 }