Преглед изворни кода

Removes support for multiple quaternion offsets in the Curve.cpp
Changes addQuaternionOffset(int offset) to setQuaternionOffset(int offset) and the scope has change to private
Optimization: When from and to value are equal (and when all quaternion components are equal, we save an interpolation and just directly set the value

Kieran Cunney пре 14 година
родитељ
комит
6bb482905c

+ 1 - 1
gameplay-encoder/src/MeshSkin.cpp

@@ -292,7 +292,7 @@ void MeshSkin::computeBounds()
         {
         case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
             curve = new Curve(keyCount, 10);
-            curve->addQuaternionOffset(3);
+            curve->setQuaternionOffset(3);
             break;
         }
         if (curve == NULL)

+ 18 - 24
gameplay/src/Animation.cpp

@@ -240,18 +240,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
 
     Curve* curve = new Curve(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
-    {
-        switch (propertyId)
-        {
-        case Transform::ANIMATE_ROTATE:
-        case Transform::ANIMATE_ROTATE_TRANSLATE:
-            curve->addQuaternionOffset(ANIMATION_ROTATE_OFFSET);
-            break;
-        case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
-            curve->addQuaternionOffset(ANIMATION_SRT_OFFSET);
-            break;
-        }
-    }
+        setTransformRotationOffset(curve, propertyId);
 
     unsigned long lowest = keyTimes[0];
     unsigned long duration = keyTimes[keyCount-1] - lowest;
@@ -287,18 +276,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
 
     Curve* curve = new Curve(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
-    {
-        switch (propertyId)
-        {
-        case Transform::ANIMATE_ROTATE:
-        case Transform::ANIMATE_ROTATE_TRANSLATE:
-            curve->addQuaternionOffset(ANIMATION_ROTATE_OFFSET);
-            break;
-        case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
-            curve->addQuaternionOffset(ANIMATION_SRT_OFFSET);
-            break;
-        }
-    }
+        setTransformRotationOffset(curve, propertyId);
     
     unsigned long lowest = keyTimes[0];
     unsigned long duration = keyTimes[keyCount-1] - lowest;
@@ -356,4 +334,20 @@ void Animation::removeChannel(Channel* channel)
         _controller->destroyAnimation(this);
 }
 
+void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId)
+{
+    switch (propertyId)
+    {
+    case Transform::ANIMATE_ROTATE:
+    case Transform::ANIMATE_ROTATE_TRANSLATE:
+        curve->setQuaternionOffset(ANIMATION_ROTATE_OFFSET);
+        return;
+    case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
+        curve->setQuaternionOffset(ANIMATION_SRT_OFFSET);
+        return;
+    }
+
+    return;
+}
+
 }

+ 5 - 0
gameplay/src/Animation.h

@@ -173,6 +173,11 @@ private:
      * Removes a channel from the animation.
      */
     void removeChannel(Channel* channel);
+
+    /**
+     * Sets the rotation offset in a Curve representing a Transform's animation data.
+     */
+    void setTransformRotationOffset(Curve* curve, unsigned int propertyId);
     
     AnimationController* _controller;       // The AnimationController that this Animation will run on.
     std::string _id;                        // The Animation's ID.

+ 47 - 81
gameplay/src/AnimationClip.cpp

@@ -311,7 +311,7 @@ bool AnimationClip::update(unsigned long elapsedTime)
             // Evaluate point on Curve.
             channel->_curve->evaluate(percentComplete, value->_interpolatedValue);
 
-            if (channel->_curve->_quaternionOffsetsCount == 0)
+            if (!channel->_curve->_quaternionOffset)
             {
                 if (value->_isFirstActing)
                 {
@@ -338,131 +338,97 @@ bool AnimationClip::update(unsigned long elapsedTime)
             }
             else
             {   //We have Quaternions!!!
-                unsigned int j = 0;
-                unsigned int quaternionOffsetIndex = 0;
-                unsigned int quaternionOffset = 0;
-
+                unsigned int quaternionOffset = *(channel->_curve->_quaternionOffset);
+                
                 if (value->_isFirstActing)
                 {
-                    do {
-                        quaternionOffset = channel->_curve->_quaternionOffsets[quaternionOffsetIndex];
-                        while (j < quaternionOffset)
-                        {
-                            if (_blendWeight != 1.0f)
-                                value->_interpolatedValue[j] *= _blendWeight;
-
-                            value->_currentValue[j] = value->_interpolatedValue[j];
-                            j++;
-                        }
+                    unsigned int j = 0;
+                    for (; j < quaternionOffset; j++)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
 
-                        // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+                        value->_currentValue[j] = value->_interpolatedValue[j];
+                    }
 
-                        Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
-                        Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + 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);
+                    // 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);
+                    // 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)
+                    for (j += 4; j < componentCount; j++)
                     {
                         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++;
-                        }
+                    unsigned int j = 0;
+                    for (; j < quaternionOffset; j++)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
 
-                        // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+                        value->_currentValue[j] += value->_interpolatedValue[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);
+                    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);
+                    // 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);
+                    // 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)
+                    for (j += 4; j < componentCount; j++)
                     {
                         if (_blendWeight != 1.0f)
                             value->_interpolatedValue[j] *= _blendWeight;
 
                         value->_currentValue[j] += value->_interpolatedValue[j];
-                        j++;
                     }
                 }
             }
         }
         else if (value->_isFirstActing)
         {
-            if (channel->_curve->_quaternionOffsetsCount == 0)
+            if (!channel->_curve->_quaternionOffset)
             {
                 memset(value->_currentValue, 0.0f, value->_componentCount);
             }
             else
             {
+                unsigned int quaternionOffset = *(channel->_curve->_quaternionOffset);
                 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);
+                for (; j < quaternionOffset; j++)
+                {
+                    value->_currentValue[j] = 0.0f;
+                }
 
-                    // Set it to identity.
-                    currentQuaternion->setIdentity();
-                    
-                    // Increase by 4.
-                    j += 4;
-                    quaternionOffsetIndex++;
-                } while (quaternionOffsetIndex < channel->_curve->_quaternionOffsetsCount);
+                // 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();
+                
                 unsigned int componentCount = value->_componentCount;
-                // Handle remaining scalar values.
-                while (j < componentCount)
+                for (j += 4; j < componentCount; j++)
                 {
                     value->_currentValue[j] = 0.0f;
-                    j++;
                 }
             }
         }

+ 206 - 246
gameplay/src/Curve.cpp

@@ -55,13 +55,9 @@ namespace gameplay
 {
 
 Curve::Curve(unsigned int pointCount, unsigned int componentCount)
-    : _pointCount(pointCount), _componentCount(componentCount), _componentSize(0), _quaternionOffsets(NULL), _quaternionOffsetsCount(0), _points(NULL)
+    : _pointCount(pointCount), _componentCount(componentCount), _componentSize(sizeof(float)*componentCount), _quaternionOffset(NULL), _points(NULL)
 {
-    assert(pointCount > 1 && componentCount > 0);
-
-    _componentSize = sizeof(float)*componentCount;
     _points = new Point[_pointCount];
-
     for (unsigned int i = 0; i < _pointCount; i++)
     {
         _points[i].time = 0.0f;
@@ -76,7 +72,7 @@ Curve::Curve(unsigned int pointCount, unsigned int componentCount)
 Curve::~Curve()
 {
     SAFE_DELETE_ARRAY(_points);
-    SAFE_DELETE_ARRAY(_quaternionOffsets);
+    SAFE_DELETE_ARRAY(_quaternionOffset);
 }
 
 Curve::Point::Point()
@@ -704,69 +700,17 @@ void Curve::evaluate(float time, float* dst) const
         }
     }
 
-    float* fromValue = from->value;
-    float* toValue = to->value;
-
-    if (!_quaternionOffsets)
-    {
-        for (unsigned int i = 0; i < _componentCount; i++)
-        {
-            dst[i] = lerp(t, fromValue[i], toValue[i]);
-        }
-    }
-    else
-    {
-        // Interpolate values as scalars up to first quaternion offset.
-        unsigned int quaternionOffsetIndex = 0;
-        unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-        unsigned int i = 0;
-        
-        do {
-            while (i < quaternionOffset)
-            {
-                dst[i] = lerp(t, fromValue[i], toValue[i]);
-                i++;
-            }
-            // Handle quaternion component.
-            float interpTime = lerp(t, fromValue[i], toValue[i]);
-            interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
-            i += 4;
-            quaternionOffsetIndex++;
-            quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-        } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-
-        while (i < _componentCount)
-        {
-            dst[i] = lerp(t, fromValue[i], toValue[i]);
-            i++;
-        }
-    }
+    interpolateLinear(t, from, to, dst);
 }
 
-void Curve::addQuaternionOffset(unsigned int offset)
+void Curve::setQuaternionOffset(unsigned int offset)
 {
-    if (!_quaternionOffsets)
-    {
-        _quaternionOffsetsCount = 1;
-        _quaternionOffsets = new unsigned int[_quaternionOffsetsCount];
-        _quaternionOffsets[0] = offset;
-    }
-    else
-    {
-        assert((offset >= _componentCount - 4) && (offset > (_quaternionOffsets[_quaternionOffsetsCount - 1] + 3)));
-
-        unsigned int oldSize = _quaternionOffsetsCount;
-        _quaternionOffsetsCount++;
-        
-        unsigned int* newArray = new unsigned int[_quaternionOffsetsCount];
-        memcpy(newArray, _quaternionOffsets, sizeof(unsigned int) * oldSize);
-        
-        // set new offset.
-        newArray[oldSize] = offset;
+    assert(offset <= (_componentCount - 4));
 
-        SAFE_DELETE_ARRAY(_quaternionOffsets);    // delete old array
-        _quaternionOffsets = newArray;  // point to new array.
-    }
+    if (!_quaternionOffset)
+        _quaternionOffset = new unsigned int[1];
+    
+    *_quaternionOffset = offset;
 }
 
 void Curve::interpolateBezier(float s, Point* from, Point* to, float* dst) const
@@ -785,38 +729,40 @@ void Curve::interpolateBezier(float s, Point* from, Point* to, float* dst) const
     float* inValue = to->inValue;
 
 
-    if (!_quaternionOffsets)
+    if (!_quaternionOffset)
     {
         for (unsigned int i = 0; i < _componentCount; i++)
         {
-            dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
         }
     }
     else
     {
-        // Interpolate values as scalars up to first quaternion offset.
-        unsigned int quaternionOffsetIndex = 0;
-        unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
         unsigned int i = 0;
-        
-        do {
-            while (i < quaternionOffset)
-            {
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
                 dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
-                i++;
-            }
-            // Handle quaternion component.
-            float interpTime = bezier(eq1, eq2, eq3, eq4, from->time, outValue[i], to->time, inValue[i]);
-            interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
-            i += 4;
-            quaternionOffsetIndex++;
-            quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-        } while (quaternionOffsetIndex < _quaternionOffsetsCount);
+        }
 
-        while (i < _componentCount)
+        // Handle quaternion component.
+        float interpTime = bezier(eq1, eq2, eq3, eq4, from->time, outValue[i], to->time, inValue[i]);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
         {
-            dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
-            i++;
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
         }
     }
 }
@@ -835,45 +781,46 @@ void Curve::interpolateBSpline(float s, Point* c0, Point* c1, Point* c2, Point*
     float* c2Value = c2->value;
     float* c3Value = c3->value;
 
-    if (!_quaternionOffsets)
+    if (!_quaternionOffset)
     {
         for (unsigned int i = 0; i < _componentCount; i++)
         {
-            dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
         }
     }
     else
     {
-        // Interpolate values as scalars up to first quaternion offset.
-        unsigned int quaternionOffsetIndex = 0;
-        unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
         unsigned int i = 0;
-        do {
-            while (i < quaternionOffset)
-            {
-                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
-                i++;
-            }
-            // Handle quaternion component.
-            float interpTime;
-            if (c0->time == c1->time)
-                interpTime = bspline(eq0, eq1, eq2, eq3, -c0->time, c1->time, c2->time, c3->time);
-            else if (c2->time == c3->time)
-                interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, -c3->time); 
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
             else
-                interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, c3->time);
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime;
+        if (c0->time == c1->time)
+            interpTime = bspline(eq0, eq1, eq2, eq3, -c0->time, c1->time, c2->time, c3->time);
+        else if (c2->time == c3->time)
+            interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, -c3->time); 
+        else
+            interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, c3->time);
+        interpolateQuaternion(s, (c1Value + i) , (c2Value + i), (dst + i));
             
-            interpolateQuaternion(s, (c1Value + i) , (c2Value + i), (dst + i));
-            i += 4;
-            quaternionOffsetIndex++;
-            quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-        } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-        
-        // Handle remaining scalar values.
-        while (i < _componentCount)
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
         {
-            dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
-            i++;
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
         }
     }
 }
@@ -893,40 +840,40 @@ void Curve::interpolateHermite(float s, Point* from, Point* to, float* dst) cons
     float* outValue = from->outValue;
     float* inValue = to->inValue;
 
-    if (!_quaternionOffsets)
+    if (!_quaternionOffset)
     {
         for (unsigned int i = 0; i < _componentCount; i++)
         {
-            dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
         }
     }
     else
     {
-        // Interpolate values as scalars up to first quaternion offset.
-        unsigned int quaternionOffsetIndex = 0;
-        unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
         unsigned int i = 0;
-
-        do {
-            while (i < quaternionOffset)
-            {
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
                 dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
-                i++;
-            }
-            // Handle quaternion component.
-            float interpTime = hermite(h00, h01, h10, h11, from->time, outValue[i], to->time, inValue[i]);
-            interpolateQuaternion(interpTime, (from->value + i), (to->value + i), (dst + i));
-            i += 4;
-            quaternionOffsetIndex++;
-            quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-            
-        } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-       
-        // Handle remaining scalar values.
-        while (i < _componentCount)
+        }
+
+        // Handle quaternion component.
+        float interpTime = hermite(h00, h01, h10, h11, from->time, outValue[i], to->time, inValue[i]);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
         {
-            dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
-            i++;
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
         }
     }
 }
@@ -942,38 +889,40 @@ void Curve::interpolateHermiteFlat(float s, Point* from, Point* to, float* dst)
     float* fromValue = from->value;
     float* toValue = to->value;
 
-    if (!_quaternionOffsets)
+    if (!_quaternionOffset)
     {
         for (unsigned int i = 0; i < _componentCount; i++)
         {
-            dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
         }
     }
     else
     {
-        // Interpolate values as scalars up to first quaternion offset.
-        unsigned int quaternionOffsetIndex = 0;
-        unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
         unsigned int i = 0;
-        float interpTime = hermiteFlat(h00, h01, from->time, to->time);
-        do {
-            while (i < quaternionOffset)
-            {
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
                 dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
-                i++;
-            }
-            // We've hit a quaternion component, so handle it. increase the component counter by 4, and increase quaternionOffsetIndex
-            interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
-            i += 4;
-            quaternionOffsetIndex++;
-            quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-        } while (quaternionOffsetIndex < _quaternionOffsetsCount);
+        }
 
-        // Handle remaining scalar values.
-        while (i < _componentCount)
+        // Handle quaternion component.
+        float interpTime = hermiteFlat(h00, h01, from->time, to->time);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
         {
-            dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
-            i++;
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
         }
     }
 }
@@ -994,43 +943,51 @@ void Curve::interpolateHermiteSmooth(float s, unsigned int index, Point* from, P
     float* fromValue = from->value;
     float* toValue = to->value;
 
-    if (!_quaternionOffsets)
+    if (!_quaternionOffset)
     {
         for (unsigned int i = 0; i < _componentCount; i++)
         {
-            if (index == 0)
+            if (fromValue[i] == toValue[i])
             {
-                outValue = toValue[i] - fromValue[i];
+                dst[i] = fromValue[i];
             }
             else
             {
-                outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
-            }
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
 
-            if (index == _pointCount - 2)
-            {
-                inValue = toValue[i] - fromValue[i];
-            }
-            else
-            {
-                inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
-            }
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
 
-            dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
         }
     }
     else
     {
-        // Interpolate values as scalars up to first quaternion offset.
-        unsigned int quaternionOffsetIndex = 0;
-        unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
         unsigned int i = 0;
-
-        do {
-            // Handle scalar values up to the quaternion offset.
-            while (i < quaternionOffset)
+        for (i = 0; i < quaternionOffset; i++)
+        {   
+            if (fromValue[i] == toValue[i])
             {
-                // Interpolate as scalar.
+                dst[i] = fromValue[i];
+            }
+            else
+            {    
                 if (index == 0)
                 {
                     outValue = toValue[i] - fromValue[i];
@@ -1050,59 +1007,61 @@ void Curve::interpolateHermiteSmooth(float s, unsigned int index, Point* from, P
                 }
 
                 dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
-                i++;
-            }
-            
-            if (index == 0)
-            {
-                outValue = to->time - from->time;
-            }
-            else
-            {
-                outValue = (to->time - (from - 1)->time) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
             }
+        }
 
-            if (index == _pointCount - 2)
-            {
-                inValue = to->time - from->time;
-            }
-            else
-            {
-                inValue = ((to + 1)->time - from->time) * ((to->time - from->time) / ((to + 1)->time - from->time));
-            }
+        // Handle quaternion component.
+        if (index == 0)
+        {
+            outValue = to->time - from->time;
+        }
+        else
+        {
+            outValue = (to->time - (from - 1)->time) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+        }
 
-            float interpTime = hermiteSmooth(h00, h01, h10, h11, from->time, outValue, to->time, inValue);
-            interpolateQuaternion(interpTime, (from->value + i), (to->value + i), (dst + i));
-            i+=4;
-            quaternionOffsetIndex++;
-            quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-        } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-        
+        if (index == _pointCount - 2)
+        {
+            inValue = to->time - from->time;
+        }
+        else
+        {
+            inValue = ((to + 1)->time - from->time) * ((to->time - from->time) / ((to + 1)->time - from->time));
+        }
 
-        // Handle remaining scalar values.
-        while (i < _componentCount)
+        float interpTime = hermiteSmooth(h00, h01, h10, h11, from->time, outValue, to->time, inValue);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
         {
-            // Interpolate as scalar.
-            if (index == 0)
+            if (fromValue[i] == toValue[i])
             {
-                outValue = toValue[i] - fromValue[i];
+                dst[i] = fromValue[i];
             }
             else
             {
-                outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
-            }
+                // Interpolate as scalar.
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
 
-            if (index == _pointCount - 2)
-            {
-                inValue = toValue[i] - fromValue[i];
-            }
-            else
-            {
-                inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
-            }
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
 
-            dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
-            i++;
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
         }
     }
 }
@@ -1112,38 +1071,39 @@ void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
     float* fromValue = from->value;
     float* toValue = to->value;
 
-    if (!_quaternionOffsets)
+    if (!_quaternionOffset)
     {
         for (unsigned int i = 0; i < _componentCount; i++)
         {
-            dst[i] = lerp(s, fromValue[i], toValue[i]);
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerp(s, fromValue[i], toValue[i]);
         }
     }
     else
     {
-        // Interpolate values as scalars up to first quaternion offset.
-        unsigned int quaternionOffsetIndex = 0;
-        unsigned int quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
         unsigned int i = 0;
-        do {
-            // Loop through values until you hit the next quaternion offset.
-            while (i < quaternionOffset)
-            {
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerp(s, fromValue[i], toValue[i]);
+        }
+
+        // Handle quaternion component.
+        interpolateQuaternion(s, (fromValue + i), (toValue + i), (dst + i));
+        
+        // handle any remaining components as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
                 dst[i] = lerp(s, fromValue[i], toValue[i]);
-                i++;
-            }
-            // Handle quaternion component.
-            interpolateQuaternion(s, (from->value + quaternionOffset), (to->value + quaternionOffset), (dst + quaternionOffset));        
-            i += 4;
-            quaternionOffsetIndex++;
-            quaternionOffset = _quaternionOffsets[quaternionOffsetIndex];
-        } while (quaternionOffsetIndex < _quaternionOffsetsCount);
-
-        // Loop through the last remaining values, if any.
-        while (i < _componentCount)
-        {
-            dst[i] = lerp(s, fromValue[i], toValue[i]);
-            i++;
         }
     }
 }

+ 12 - 14
gameplay/src/Curve.h

@@ -12,6 +12,7 @@ class Curve
     friend class Animation;
     friend class AnimationClip;
     friend class AnimationController;
+    friend class MeshSkin;
 
 public:
 
@@ -353,18 +354,6 @@ public:
      */
     void evaluate(float time, float* dst) const;
 
-    /**
-     * Adds an offset for the beginning of a Quaternion piece of data within the curve's value span at the specified
-     * index. The next four components of data starting at the given index will be interpolated as a Quaternion.
-     * This function will assert an error if the given index is less than the component size less the four components required
-     * to store a quaternion.
-     * One can set multiple offsets within the value span. However, this function will assert an error if the index
-     * are not ordered, or if the index 
-     * 
-     * @param index The index of the Quaternion rotation data.
-     */
-    void addQuaternionOffset(unsigned int index);
-
 private:
 
     /**
@@ -446,6 +435,16 @@ private:
      */ 
     int determineIndex(float time) const;
 
+    /**
+     * Sets the offset for the beginning of a Quaternion piece of data within the curve's value span at the specified
+     * index. The next four components of data starting at the given index will be interpolated as a Quaternion.
+     * This function will assert an error if the given index is greater than the component size subtracted by the four components required
+     * to store a quaternion.
+     * 
+     * @param index The index of the Quaternion rotation data.
+     */
+    void setQuaternionOffset(unsigned int index);
+
     /**
      * Gets the InterpolationType value for the given string ID
      *
@@ -457,8 +456,7 @@ private:
     unsigned int _pointCount;           // Number of points on the curve.
     unsigned int _componentCount;       // Number of components on the curve.
     unsigned int _componentSize;        // The component size (in bytes).
-    unsigned int* _quaternionOffsets;   // Offset for the rotation component.
-    unsigned int _quaternionOffsetsCount;
+    unsigned int* _quaternionOffset;    // Offset for the rotation component.
     Point* _points;                     // The points on the curve.
 };
 

+ 6 - 0
gameplay/src/Quaternion.cpp

@@ -281,6 +281,12 @@ void Quaternion::slerp(const Quaternion& q1, const Quaternion& q2, float t, Quat
         return;
     }
 
+    if (q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w)
+    {
+        memcpy(dst, &q1, sizeof(float) * 4);
+        return;
+    }
+
     float halfY, alpha, beta;
     float u, f1, f2a, f2b;
     float ratio1, ratio2;