Browse Source

Clean up Spline code, add support for Catmull-Rom interpolation of other values than Vector3, and fix out of bounds array access in Catmull-Rom interpolation. Add linear interpolation mode. Add script bindings of new interpolation mode enums. Closes #772. Closes #773.

Lasse Öörni 10 years ago
parent
commit
52885a22c4

+ 60 - 16
Source/Urho3D/Core/Spline.cpp

@@ -32,6 +32,7 @@ const char* interpolationModeNames[] =
 {
 {
     "Bezier",
     "Bezier",
     "Catmull-Rom",
     "Catmull-Rom",
+    "Linear",
     0
     0
 };
 };
 
 
@@ -73,7 +74,9 @@ Variant Spline::GetPoint(float f) const
         return BezierInterpolation(knots_, f);
         return BezierInterpolation(knots_, f);
     case CATMULL_ROM_CURVE:
     case CATMULL_ROM_CURVE:
         return CatmullRomInterpolation(knots_, f);
         return CatmullRomInterpolation(knots_, f);
-
+    case LINEAR_CURVE:
+        return LinearInterpolation(knots_, f);
+        
     default:
     default:
         LOGERROR("Unsupported interpolation mode");
         LOGERROR("Unsupported interpolation mode");
         return Variant::EMPTY;
         return Variant::EMPTY;
@@ -159,30 +162,71 @@ Variant Spline::BezierInterpolation(const Vector<Variant>& knots, float t) const
     }
     }
 }
 }
 
 
+template <typename T> Variant CalculateCatmullRom(const T& p0, const T& p1, const T& p2, const T& p3, float t, float t2, float t3)
+{
+    return Variant(0.5f * ((2.0f * p1) + (-p0 + p2) * t +
+        (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * t2 +
+        (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3));
+}
+
 Variant Spline::CatmullRomInterpolation(const Vector<Variant>& knots, float t) const
 Variant Spline::CatmullRomInterpolation(const Vector<Variant>& knots, float t) const
 {
 {
-    if (knots.Size() <4)
-    {
+    if (knots.Size() < 4)
         return Variant::EMPTY;
         return Variant::EMPTY;
-    }
     else
     else
     {
     {
-        int orginIndex;
-        orginIndex=t*(knots.Size()-3);
-        t=fmodf(t*(knots.Size()-3),1.f);
-        Vector3 ret;
-        Vector3 p0=knots[orginIndex].GetVector3();
-        Vector3 p1=knots[orginIndex+1].GetVector3();
-        Vector3 p2=knots[orginIndex+2].GetVector3();
-        Vector3 p3=knots[orginIndex+3].GetVector3();
+        if (t >= 1.f)
+            return knots[knots.Size() - 2];
+
+        int originIndex = t * (knots.Size() - 3);
+        t = fmodf(t * (knots.Size() - 3), 1.f);
         float t2 = t * t;
         float t2 = t * t;
         float t3 = t2 * t;
         float t3 = t2 * t;
 
 
-        ret=0.5f*((2.0f*p1)+(-p0+p2)*t+
-        (2.0f*p0-5.0f*p1+4*p2-p3)*t2+
-        (-p0+3.0f*p1-3.0f*p2+p3)*t3);
+        switch (knots[originIndex].GetType())
+        {
+        case VAR_FLOAT:
+            return CalculateCatmullRom(knots[originIndex].GetFloat(), knots[originIndex + 1].GetFloat(),
+                knots[originIndex + 2].GetFloat(), knots[originIndex + 3].GetFloat(), t, t2, t3);
+
+        case VAR_VECTOR2:
+            return CalculateCatmullRom(knots[originIndex].GetVector2(), knots[originIndex + 1].GetVector2(),
+                knots[originIndex + 2].GetVector2(), knots[originIndex + 3].GetVector2(), t, t2, t3);
+
+        case VAR_VECTOR3:
+            return CalculateCatmullRom(knots[originIndex].GetVector3(), knots[originIndex + 1].GetVector3(),
+                knots[originIndex + 2].GetVector3(), knots[originIndex + 3].GetVector3(), t, t2, t3);
+
+        case VAR_VECTOR4:
+            return CalculateCatmullRom(knots[originIndex].GetVector4(), knots[originIndex + 1].GetVector4(),
+                knots[originIndex + 2].GetVector4(), knots[originIndex + 3].GetVector4(), t, t2, t3);
+
+        case VAR_COLOR:
+            return CalculateCatmullRom(knots[originIndex].GetColor(), knots[originIndex + 1].GetColor(),
+                knots[originIndex + 2].GetColor(), knots[originIndex + 3].GetColor(), t, t2, t3);
+
+        case VAR_DOUBLE:
+            return CalculateCatmullRom(knots[originIndex].GetDouble(), knots[originIndex + 1].GetDouble(),
+                knots[originIndex + 2].GetDouble(), knots[originIndex + 3].GetDouble(), t, t2, t3);
+        
+        default:
+            return Variant::EMPTY;
+        }
+    }
+}
+
+Variant Spline::LinearInterpolation(const Vector<Variant>& knots, float t) const
+{
+    if (knots.Size() < 2)
+        return Variant::EMPTY;
+    else
+    {
+        if (t >= 1.f)
+            return knots.Back();
 
 
-        return Variant(ret);
+        int originIndex = Clamp((int)(t * (knots.Size() - 1)), 0, (int)(knots.Size() - 2));
+        t = fmodf(t * (knots.Size() - 1), 1.f);
+        return LinearInterpolation(knots[originIndex], knots[originIndex + 1], t);
     }
     }
 }
 }
 
 

+ 7 - 4
Source/Urho3D/Core/Spline.h

@@ -34,7 +34,8 @@ namespace Urho3D
 enum InterpolationMode
 enum InterpolationMode
 {
 {
     BEZIER_CURVE = 0,
     BEZIER_CURVE = 0,
-    CATMULL_ROM_CURVE
+    CATMULL_ROM_CURVE,
+    LINEAR_CURVE
 };
 };
 
 
 /// Spline class to get a point on it based off the interpolation mode.
 /// Spline class to get a point on it based off the interpolation mode.
@@ -104,11 +105,13 @@ public:
     void Clear() { knots_.Clear(); }
     void Clear() { knots_.Clear(); }
 
 
 private:
 private:
-    /// Perform Bezier Interpolation on the Spline.
+    /// Perform Bezier interpolation on the Spline.
     Variant BezierInterpolation(const Vector<Variant>& knots, float t) const;
     Variant BezierInterpolation(const Vector<Variant>& knots, float t) const;
-    /// Perform Spline Interpolation on the Spline.
+    /// Perform Spline interpolation on the Spline.
     Variant CatmullRomInterpolation(const Vector<Variant>& knots, float t) const;
     Variant CatmullRomInterpolation(const Vector<Variant>& knots, float t) const;
-    /// LinearInterpolation between two Variants based on underlying type.
+    /// Perform linear interpolation on the Spline.
+    Variant LinearInterpolation(const Vector<Variant>& knots, float t) const;
+    /// Linear interpolation between two Variants based on underlying type.
     Variant LinearInterpolation(const Variant& lhs, const Variant& rhs, float t) const;
     Variant LinearInterpolation(const Variant& lhs, const Variant& rhs, float t) const;
 
 
     /// InterpolationMode.
     /// InterpolationMode.

+ 4 - 2
Source/Urho3D/LuaScript/pkgs/Core/Spline.pkg

@@ -2,7 +2,9 @@ $#include "Core/Spline.h"
 
 
 enum InterpolationMode
 enum InterpolationMode
 {
 {
-    BEZIER_CURVE
+    BEZIER_CURVE,
+    CATMULL_ROM_CURVE,
+    LINEAR_CURVE
 };
 };
 
 
 class Spline
 class Spline
@@ -10,7 +12,7 @@ class Spline
     Spline();
     Spline();
     Spline(InterpolationMode mode);
     Spline(InterpolationMode mode);
     Spline(const Spline& rhs);
     Spline(const Spline& rhs);
-    // When export constructor, the destructor must export also. otherwise Lua will not collect the oject.
+    // When export constructor, the destructor must export also. otherwise Lua will not collect the object.
     ~Spline();
     ~Spline();
     
     
     void operator = (const Spline& rhs);
     void operator = (const Spline& rhs);

+ 3 - 0
Source/Urho3D/Math/Color.h

@@ -102,6 +102,9 @@ public:
     /// Add a color.
     /// Add a color.
     Color operator +(const Color& rhs) const { return Color(r_ + rhs.r_, g_ + rhs.g_, b_ + rhs.b_, a_ + rhs.a_); }
     Color operator +(const Color& rhs) const { return Color(r_ + rhs.r_, g_ + rhs.g_, b_ + rhs.b_, a_ + rhs.a_); }
 
 
+    /// Return negation.
+    Color operator -() const { return Color(-r_, -g_, -b_, -a_); }
+
     /// Substract a color.
     /// Substract a color.
     Color operator -(const Color& rhs) const { return Color(r_ - rhs.r_, g_ - rhs.g_, b_ - rhs.b_, a_ - rhs.a_); }
     Color operator -(const Color& rhs) const { return Color(r_ - rhs.r_, g_ - rhs.g_, b_ - rhs.b_, a_ - rhs.a_); }
 
 

+ 3 - 0
Source/Urho3D/Math/MathDefs.h

@@ -62,6 +62,9 @@ inline bool Equals(float lhs, float rhs) { return lhs + M_EPSILON >= rhs && lhs
 /// Linear interpolation between two float values.
 /// Linear interpolation between two float values.
 inline float Lerp(float lhs, float rhs, float t) { return lhs * (1.0f - t) + rhs * t; }
 inline float Lerp(float lhs, float rhs, float t) { return lhs * (1.0f - t) + rhs * t; }
 
 
+/// Linear interpolation between two double values.
+inline double Lerp(double lhs, double rhs, float t) { return lhs * (1.0f - t) + rhs * t; }
+
 /// Return the smaller of two floats.
 /// Return the smaller of two floats.
 inline float Min(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; }
 inline float Min(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; }
 
 

+ 2 - 0
Source/Urho3D/Script/CoreAPI.cpp

@@ -607,6 +607,8 @@ static void RegisterSpline(asIScriptEngine* engine)
 {
 {
     engine->RegisterEnum("InterpolationMode");
     engine->RegisterEnum("InterpolationMode");
     engine->RegisterEnumValue("InterpolationMode", "BEZIER_CURVE", BEZIER_CURVE);
     engine->RegisterEnumValue("InterpolationMode", "BEZIER_CURVE", BEZIER_CURVE);
+    engine->RegisterEnumValue("InterpolationMode", "CATMULL_ROM_CURVE", CATMULL_ROM_CURVE);
+    engine->RegisterEnumValue("InterpolationMode", "LINEAR_CURVE", LINEAR_CURVE);
 
 
     engine->RegisterObjectType("Spline", sizeof(Spline), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK);
     engine->RegisterObjectType("Spline", sizeof(Spline), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK);
     engine->RegisterObjectBehaviour("Spline", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(ConstructSpline, (Spline*), void), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Spline", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(ConstructSpline, (Spline*), void), asCALL_CDECL_OBJLAST);