Explorar el Código

Merge pull request #36 from blackberry-gaming/next-kcunney

Next kcunney - CrossFade & Blending
Sean Paul Taylor hace 14 años
padre
commit
1eccc7d52b

+ 40 - 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)
-    : _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);
-    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)
-    : _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);
-    createDefaultClip();
 }
 
 Animation::~Animation()
@@ -46,15 +44,22 @@ Animation::~Animation()
     }
     _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();
+
+    SAFE_DELETE(_clips);
+
+    SAFE_DELETE(_defaultClip);
 }
 
 Animation::Channel::Channel(AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
@@ -133,7 +138,7 @@ void Animation::createClips(const char* animationFile)
 
 AnimationClip* Animation::createClip(const char* id, unsigned long start, unsigned long end)
 {
-    if (findClip(id) != NULL)
+    if (_clips != NULL && findClip(id) != NULL)
     {
         return NULL;
     }
@@ -150,7 +155,10 @@ AnimationClip* Animation::getClip(const char* id)
     // If id is NULL return the default clip.
     if (id == NULL)
     {
-        return _clips[ANIMATION_DEFAULT_CLIP];
+        if (_defaultClip == NULL)
+            createDefaultClip();
+
+        return _defaultClip;
     }
     else
     {
@@ -163,7 +171,10 @@ void Animation::play(const char* id)
     // If id is NULL, play the default clip.
     if (id == NULL)
     {
-        _clips[ANIMATION_DEFAULT_CLIP]->play();
+        if (_defaultClip == NULL)
+            createDefaultClip();
+        
+        _defaultClip->play();
     }
     else
     {
@@ -181,7 +192,10 @@ void Animation::stop(const char* id)
     // If id is NULL, play the default clip.
     if (id == NULL)
     {
-        _clips[ANIMATION_DEFAULT_CLIP]->stop();
+        if (_defaultClip == NULL)
+            createDefaultClip();
+
+        _defaultClip->stop();
     }
     else
     {
@@ -303,22 +317,28 @@ void Animation::addChannel(Channel* channel)
 void Animation::createDefaultClip()
 {
     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)
 {
-    _clips.push_back(clip);
+    if (_clips == NULL)
+        _clips = new std::vector<AnimationClip*>;
+
+    _clips->push_back(clip);
 }
 
 AnimationClip* Animation::findClip(const char* id) const
 {
-    unsigned int clipCount = _clips.size();
+    AnimationClip* clip = NULL;
+    unsigned int clipCount = _clips->size();
     for (unsigned int i = 0; i < clipCount; i++)
     {
-        if (_clips.at(i)->_id.compare(id) == 0)
+        clip = _clips->at(i);
+        if (clip->_id.compare(id) == 0)
         {
-            return _clips.at(i);
+            return _clips->at(i);
         }
     }
     return NULL;

+ 3 - 1
gameplay/src/Animation.h

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

+ 327 - 16
gameplay/src/AnimationClip.cpp

@@ -7,22 +7,27 @@
 #include "Animation.h"
 #include "AnimationTarget.h"
 #include "Game.h"
+#include "Quaternion.h"
 
 namespace gameplay
 {
+    int AnimationClip::_crazyCounter = 0;
 
 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), _crossFadeToClip(NULL), _crossFadeStart(0), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
+      _isFadingOutStarted(false), _isFadingOut(false), _isFadingIn(false), _beginListeners(NULL), _endListeners(NULL)
 {
     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()));
+        _channelPriority[i] = 0;
     }
 }
 
@@ -41,6 +46,8 @@ AnimationClip::~AnimationClip()
         valueIter++;
     }
 
+    SAFE_DELETE(_crossFadeToClip);
+    SAFE_DELETE(_channelPriority);
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
 }
@@ -123,6 +130,16 @@ float AnimationClip::getSpeed() const
     return _speed;
 }
 
+void AnimationClip::setBlendWeight(float blendWeight)
+{
+    _blendWeight = blendWeight;
+}
+
+float AnimationClip::getBlendWeight() const
+{
+    return _blendWeight;
+}
+
 bool AnimationClip::isPlaying() const
 {
     return _isPlaying;
@@ -131,12 +148,52 @@ bool AnimationClip::isPlaying() const
 void AnimationClip::play()
 {
     _animation->_controller->schedule(this);
+    _timeStarted = Game::getGameTime();
 }
 
 void AnimationClip::stop()
 {
     _animation->_controller->unschedule(this);
-    _isPlaying = false;
+    if (_isPlaying)
+    {
+        _isPlaying = false;
+        onEnd();
+    }
+}
+
+void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
+{
+    assert(clip);
+
+    if (clip->_isPlaying && clip->_isFadingOut)
+    {
+        clip->_isFadingOut = false;
+        clip->_crossFadeToClip->_isFadingIn = false;
+        SAFE_RELEASE(clip->_crossFadeToClip);
+    }
+
+    // If I already have a clip I'm fading too.. release it.
+    if (_crossFadeToClip)
+        SAFE_RELEASE(_crossFadeToClip);
+
+    // Assign the clip we're fading to, and increase its ref count.
+    _crossFadeToClip = clip;
+    _crossFadeToClip->addRef();
+        
+    // Set the fade in clip to fading in, and set the duration of the fade in.
+    _crossFadeToClip->_isFadingIn = true;
+    
+    // Set this clip to fade out, and reset the elapsed time for the fade out.
+    _isFadingOut = true;
+    _crossFadeOutElapsed = 0;
+    _crossFadeOutDuration = duration;
+    _crossFadeStart = (Game::getGameTime() - _timeStarted);
+    _isFadingOutStarted = true;
+    
+    if (!_isPlaying)
+        play();
+
+    _crossFadeToClip->play(); 
 }
 
 void AnimationClip::addBeginListener(AnimationClip::Listener* listener)
@@ -157,12 +214,19 @@ void AnimationClip::addEndListener(AnimationClip::Listener* listener)
 
 bool AnimationClip::update(unsigned long elapsedTime)
 {
+    float speed = _speed;
     if (!_isPlaying)
+    {
         onBegin();
-
-    // Update elapsed time.
-    _elapsedTime += elapsedTime;
-    _runningTime += elapsedTime * _speed;
+        _elapsedTime = Game::getGameTime() - _timeStarted;
+        _runningTime = _elapsedTime * speed;
+    }
+    else
+    {
+        // Update elapsed time.
+        _elapsedTime += elapsedTime;
+        _runningTime += elapsedTime * speed;
+    }
 
     float percentComplete = 0.0f;
 
@@ -171,9 +235,15 @@ bool AnimationClip::update(unsigned long elapsedTime)
     {
         _isPlaying = false;
         if (_speed >= 0)
+        {
             percentComplete = _activeDuration % _duration; // Get's the fractional part of the final repeat.
+            if (percentComplete == 0.0f)
+                percentComplete = _duration;
+        }
         else
+        {
             percentComplete = 0.0f; // If we are negative speed, the end value should be 0.
+        }
     }
     else
     {
@@ -183,20 +253,234 @@ 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
     percentComplete = (float)(_startTime + percentComplete) / (float) _animation->_duration;
+    
+    if (_isFadingOut)
+    {
+        if (_isFadingOutStarted) // Calculate elapsed time since the fade out begin.
+        {
+            _crossFadeOutElapsed = (_elapsedTime - _crossFadeStart) * speed;
+            _isFadingOutStarted = false;
+        }
+        else
+        {
+            // continue tracking elapsed time.
+            _crossFadeOutElapsed += elapsedTime * speed;
+        }
 
+        if (_crossFadeOutElapsed < _crossFadeOutDuration)
+        {
+            float tempBlendWeight = (float) (_crossFadeOutDuration - _crossFadeOutElapsed) / (float) _crossFadeOutDuration;
+            _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight);
+            
+            // adjust the clip your blending to's weight to be a percentage of your current blend weight
+            if (_isFadingIn)
+            {
+                _crossFadeToClip->_blendWeight *= _blendWeight;
+                _blendWeight -= _crossFadeToClip->_blendWeight;
+            }
+            else
+            {
+                _blendWeight = tempBlendWeight;
+            }
+        }
+        else
+        {   // Fade done.
+            _crossFadeToClip->_blendWeight = 1.0f;
+                
+            if (_isFadingIn)
+                _crossFadeToClip->_blendWeight *= _blendWeight;
+
+            _crossFadeToClip->_isFadingIn = false;
+            SAFE_RELEASE(_crossFadeToClip);
+            _blendWeight = 0.0f; 
+            _isFadingOut = false;
+            _isPlaying = false;
+        }
+    }
+    
     // Evaluate this clip.
     Animation::Channel* channel = NULL;
     AnimationValue* value = NULL;
-    for (unsigned int i = 0; i < _channelCount; i++)
+    AnimationTarget* target = NULL;
+    unsigned int channelCount = _animation->_channels.size();
+    for (unsigned int i = 0; i < channelCount; i++)
     {
         channel = _animation->_channels[i];
-        value = _values.at(i);
+        target = channel->_target;
+        value = _values[i];
+
+        // Get the current value.
+        target->getAnimationPropertyValue(channel->_propertyId, value);
 
-        // Evaluate point on curve.
-        channel->_curve->evaluate(percentComplete, value->_currentValue);
+        // My channel priority has changed if my priority is greater than the active animation count.
+        if (target->_reassignPriorities)
+        {
+            _channelPriority[i] = target->getPriority();
+        }
+
+        if (_blendWeight != 0.0f)
+        {
+            // Evaluate point on Curve.
+            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.
+                        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)
+        {
+            if (channel->_curve->_quaternionOffsetsCount == 0)
+            {
+                memset(value->_currentValue, 0.0f, value->_componentCount);
+            }
+            else
+            {
+                unsigned int j = 0;
+                unsigned int quaternionOffset = 0;
+                unsigned int quaternionOffsetIndex = 0;
+                
+                do {
+                    quaternionOffset = channel->_curve->_quaternionOffsets[quaternionOffsetIndex];
+                    while (j < quaternionOffset)
+                    {
+                        value->_currentValue[j] = 0.0f;
+                        j++;
+                    }
+
+                    // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+                    Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
+
+                    // Set it to identity.
+                    currentQuaternion->setIdentity();
+                    
+                    // Increase by 4.
+                    j += 4;
+                    quaternionOffsetIndex++;
+                } while (quaternionOffsetIndex < channel->_curve->_quaternionOffsetsCount);
+
+                unsigned int componentCount = value->_componentCount;
+                // Handle remaining scalar values.
+                while (j < componentCount)
+                {
+                    value->_currentValue[j] = 0.0f;
+                    j++;
+                }
+            }
+        }
         
         // Set the animation value on the target property.
-        channel->_target->setAnimationPropertyValue(channel->_propertyId, value);
+        target->setAnimationPropertyValue(channel->_propertyId, value);
     }
 
     // When ended. Probably should move to it's own method so we can call it when the clip is ended early.
@@ -223,6 +507,18 @@ void AnimationClip::onBegin()
         _runningTime = _activeDuration;
     }
 
+    AnimationTarget* target = NULL;
+    unsigned int channelCount = _animation->_channels.size();
+    // Sets the starting value.
+    for (unsigned int i = 0; i < channelCount; i++)
+    {
+        target = _animation->_channels[i]->_target;
+
+        target->increaseActiveAnimationCount();
+        _channelPriority[i] = target->getPriority();
+    }
+
+    // Notify begin listeners.. if any.
     if (_beginListeners)
     {
         std::vector<Listener*>::iterator listener = _beginListeners->begin();
@@ -236,6 +532,21 @@ void AnimationClip::onBegin()
 
 void AnimationClip::onEnd()
 {
+    AnimationTarget* target = NULL;
+    unsigned int channelCount = _animation->_channels.size();
+    for (unsigned int i = 0; i < channelCount; i++)
+    {
+        target = _animation->_channels[i]->_target;
+        
+        // Decrease active animation count on target and reset the channel priority
+        target->decreaseActiveAnimationCount();
+        _channelPriority[i] = 0;
+    }
+
+    _blendWeight = 1.0f;
+    _timeStarted = 0;
+
+    // Notify end listeners if any.
     if (_endListeners)
     {
         std::vector<Listener*>::iterator listener = _endListeners->begin();

+ 42 - 8
gameplay/src/AnimationClip.h

@@ -31,6 +31,8 @@ public:
      */
     static const unsigned int REPEAT_INDEFINITE = 0;
 
+    static int _crazyCounter;
+
     /**
      * Defines an animation event listener.
      */
@@ -141,6 +143,20 @@ public:
      */
     float getSpeed() const;
 
+    /**
+     * Sets the blend weight of the AnimationClip.
+     *
+     * @param blendWeight The blend weight to apply to the clip.
+     */
+    void setBlendWeight(float blendWeight);
+
+    /** 
+     * Gets the blend weight of the AnimationClip.
+     *
+     * @return The blendweight of the AnimationClip.
+     */
+    float getBlendWeight() const;
+
     /**
      * Checks if the AnimationClip is playing.
      *
@@ -158,6 +174,14 @@ public:
      */
     void stop();
 
+    /**
+     * Fades this clip out, and the specified clip in over the given duration.
+     *
+     * @param clip The clip to fade into.
+     * @param duration The duration of the fade.
+     */
+    void crossFade(AnimationClip* clip, unsigned long duration);
+
     /**
      * Adds a animation begin listener.
      *
@@ -213,17 +237,27 @@ private:
     Animation* _animation;                    // Animations that this clip plays in parallel.
     unsigned long _startTime;                 // Start 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.
+    float _repeatCount;                       // The clip's repeat count.
     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.
-    std::vector<Listener*>* _beginListeners;
-    std::vector<Listener*>* _endListeners;
+    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;           // Keeps track of each channel's priority.
+    AnimationClip* _crossFadeToClip;          // The clip to cross fade to
+    unsigned long _crossFadeStart;            // The time at which the cross fade started.
+    unsigned long _crossFadeOutElapsed;       // The amount of time that has elapsed for the crossfade.
+    unsigned long _crossFadeOutDuration;      // The duration of the cross fade.
+    float _blendWeight;                       // The clip's blendweight
+    bool _isFadingOutStarted;                 // Flag to indicate if the cross fade started
+    bool _isFadingOut;                        // Flag to indicate if the clip is fading out
+    bool _isFadingIn;                         // Flag to indicate if the clip is fading in.
+    std::vector<AnimationValue*> _values;     // AnimationValue holder.
+    std::vector<Listener*>* _beginListeners;  // Collection of begin listeners on the clip
+    std::vector<Listener*>* _endListeners;    // Collection of end listeners on the clip
+
 };
 
 }

+ 8 - 5
gameplay/src/AnimationController.cpp

@@ -113,8 +113,9 @@ void AnimationController::stopAllAnimations()
     {
         AnimationClip* clip = *clipIter;
         clip->_isPlaying = false;
+        clip->onEnd();
+        clipIter = _runningClips.erase(clipIter);
         SAFE_RELEASE(clip);
-        clipIter++;
     }
     _runningClips.clear();
 
@@ -160,6 +161,7 @@ void AnimationController::schedule(AnimationClip* clip)
     {
         _runningClips.remove(clip);
         clip->_isPlaying = false;
+        clip->onEnd();
     }
     else
     {
@@ -187,12 +189,12 @@ void AnimationController::update(long elapsedTime)
         return;
 
     std::list<AnimationClip*>::iterator clipIter = _runningClips.begin();
-
+    unsigned int clipCount = 0;
     while (clipIter != _runningClips.end())
     {
-        if ((*clipIter)->update(elapsedTime))
+        AnimationClip* clip = (*clipIter);
+        if (clip->update(elapsedTime))
         {
-            AnimationClip* clip = *clipIter;
             clipIter = _runningClips.erase(clipIter);
             SAFE_RELEASE(clip);
         }
@@ -200,8 +202,9 @@ void AnimationController::update(long elapsedTime)
         {
             clipIter++;
         }
+        clipCount++;
     }
-
+    
     if (_runningClips.empty())
         _state = IDLE;
 }

+ 2 - 3
gameplay/src/AnimationController.h

@@ -161,7 +161,7 @@ private:
      * Unschedules an AnimationClip.
      */
     void unschedule(AnimationClip* clip);
-
+    
     /**
      * Callback for when the controller receives a frame update event.
      */
@@ -181,11 +181,10 @@ private:
      * Removes all animations from the AnimationTarget.
      */ 
     void destroyAllAnimations();
-
+    
     State _state;                               // The current state of the AnimationController.
     std::list<AnimationClip*> _runningClips;    // A list of currently running AnimationClips.
     std::vector<Animation*> _animations;
-    //Animation** _animations;                    // A list of animations on this target.
 };
 
 }

+ 29 - 1
gameplay/src/AnimationTarget.cpp

@@ -13,7 +13,7 @@ namespace gameplay
 {
 
 AnimationTarget::AnimationTarget()
-    : _targetType(SCALAR), _animations(NULL)
+    : _targetType(SCALAR), _activeAnimationCount(0), _currentPriority(0), _animations(NULL), _reassignPriorities(false)
 {
 }
 
@@ -78,6 +78,34 @@ Animation* AnimationTarget::getAnimation(const char* id) const
     return NULL;
 }
 
+void AnimationTarget::increaseActiveAnimationCount()
+{
+    ++_activeAnimationCount;
+}
+
+void AnimationTarget::decreaseActiveAnimationCount()
+{
+    --_activeAnimationCount;
+
+    _reassignPriorities = true;
+    _currentPriority = 0;
+}
+
+unsigned int AnimationTarget::getPriority() 
+{
+    if (_reassignPriorities)
+    {
+        ++_currentPriority;
+
+        if (_currentPriority == _activeAnimationCount)
+            _reassignPriorities = false;
+
+        return _currentPriority;
+    }
+
+    return _activeAnimationCount;
+}
+
 }
 
 

+ 20 - 1
gameplay/src/AnimationTarget.h

@@ -21,6 +21,7 @@ class AnimationValue;
 class AnimationTarget : public Ref
 {
     friend class Animation;
+    friend class AnimationClip;
     friend class AnimationController;
 
 public:
@@ -104,7 +105,25 @@ private:
      */
     AnimationTarget(const AnimationTarget& copy);
 
-    std::vector<Animation*>* _animations;
+    /**
+     * Increases the active animation count on the target by one.
+     */
+    void increaseActiveAnimationCount();
+
+    /**
+     * Decreases the active animation count on the target by one.
+     */
+    void decreaseActiveAnimationCount();
+
+    /**
+     * Gets the priority to assign to the channel when reassigning priorities.
+     */
+    unsigned int getPriority();
+
+    unsigned int _activeAnimationCount;        // The number of active animations targeting this AnimationTarget.
+    bool _reassignPriorities;                  // A flag to indicate that channel priorities for this AnimationTarget need to be reassigned
+    unsigned int _currentPriority;             // Used to keep track of the current priority when reassigning channel priorities
+    std::vector<Animation*>* _animations;      // Collection of all animations on that target the AnimationTarget
 
 };
 }

+ 3 - 1
gameplay/src/AnimationValue.cpp

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

+ 2 - 0
gameplay/src/AnimationValue.h

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

+ 23 - 23
gameplay/src/gameplay-main-macosx.mm

@@ -1,24 +1,24 @@
-#ifndef GAMEPLAYMAINMACOSX_H_
-#define GAMEPLAYMAINMACOSX_H_
-
-#ifdef __APPLE__
-
-#include "gameplay.h"
-using namespace gameplay;
-
-
-/**
- * Main entry point.
- */
-int main(int argc, char** argv)
-{
-    Game* game = Game::getInstance();
-    assert(game != NULL);
-    Platform* platform = Platform::create(game);
-    return platform->enterMessagePump();
-}
-
-
-#endif
-
+#ifndef GAMEPLAYMAINMACOSX_H_
+#define GAMEPLAYMAINMACOSX_H_
+
+#ifdef __APPLE__
+
+#include "gameplay.h"
+using namespace gameplay;
+
+
+/**
+ * Main entry point.
+ */
+int main(int argc, char** argv)
+{
+    Game* game = Game::getInstance();
+    assert(game != NULL);
+    Platform* platform = Platform::create(game);
+    return platform->enterMessagePump();
+}
+
+
+#endif
+
 #endif