/*
 *  Curves.h
 *  CRGraphics
 *
 *  Created by Yaroslav Glushchenko on 2/8/11.
 *  Copyright 2011 Corner-A. All rights reserved.
 *
 */

#pragma once

//////////////////////////////////////////////////////////////////////
// Number of helpers for curves interpolation
//////////////////////////////////////////////////////////////////////
namespace Interpolation
{
	template <typename T>
	struct Linear
	{
		inline T operator()(T p0, T p1, float t)
		{
			return p0 + t * (p1 - p0);
		}
	};
	
	template <typename T>
	struct Quadratic
	{
		inline T operator()(T p0, T p1, T p2, float t)
		{
			float inv_t = 1 - t;
			return (inv_t * inv_t)*p0 + 2*t*inv_t*p1 + t*t*p2;
		}
	};
	
	template <typename T>
	struct Cubic
	{
		inline T operator()(T p0, T p1, T p2, T p3, float t)
		{
			float inv_t = 1 - t;
			return (inv_t*inv_t*inv_t)*p0 + (3*t*inv_t*inv_t)*p1 + (3*t*t*inv_t)*p2 + (t*t*t)*p3;
		}
	};
	
	template <typename T>
	struct Cardinal
	{
		float Tension;
		
		Cardinal(float fTension)
			: Tension(fTension)
		{}
		
		inline T operator()(T p0, T p1, T p2, T p3, float t)
		{
			float h00 = 2*t*t*t - 3*t*t + 1;
			float h10 = t*(t*t - 2*t + 1);
			float h01 = t*t*(3 - 2*t);
			float h11 = t*t*(t - 1);
			
			T m0 = (1 - Tension) * (p2 - p0) * 0.5f;
			T m1 = (1 - Tension) * (p3 - p1) * 0.5f;
			
			return h00*p1 + h10*m0 + h01*p2 + h11*m1;
		}
	};
	
	template <typename T>
	struct CatmullRom
	{
		inline T operator()(T p0, T p1, T p2, T p3, float t)
		{
			// as a cardinal curve
			//return Cardinal<T>(0)(p0, p1, p2, p3, t);
			
			// pure formula
			return 0.5f * ((2 * p1) + (-p0 + p2) * t + (2*p0 - 5*p1 + 4*p2 - p3) * t*t + (-p0 + 3*p1- 3*p2 + p3) * t*t*t);
		}
	};
	
	template <typename T>
	struct Bezier
	{
		inline T operator()(T p0, T p1, T p2, T p3, float t)
		{
			float t1 = 1.0f - t;
			return t1 * t1 * t1 * p0 + 3 * t1 * t1 * t * p1 + 3 * t1 * t * t * p2 + t * t * t * p3;
		}
	};
	
	struct BSplineCubic
	{
		inline NSPoint operator()(NSPoint p0, NSPoint p1, NSPoint p2, NSPoint p3, float t)
		{
			float it = 1.0f - t;
			
			float b0 = it*it*it / 6.0f;
			float b1 = (3*t*t*t - 6*t*t + 4) / 6.0f;
			float b2 = (-3*t*t*t +3*t*t + 3*t + 1) / 6.0f;
			float b3 =  t*t*t / 6.0f;
			
			// sum the control points mulitplied by their respective blending functions
			NSPoint result;
			result.x = b0*p0.x + b1*p1.x + b2*p2.x + b3*p3.x;
			result.y = b0*p0.y + b1*p1.y + b2*p2.y + b3*p3.y;
			//result.z = b0*p0.z + b1*p1.z + b2*p2.z + b3*p3.z;
			
			return result;
		}
	};
};