namespace Math
{
	const float Epsilon = 1.401298E-45;
	const float piHalf = 1.570796f;
	//------------------------------------------------------------------------------------------------------------------------
	// Compares two floating point values if they are similar.
	//------------------------------------------------------------------------------------------------------------------------
	bool Approximately(const float a, const float b)
	{
		return Fabs(b - a) < Maxf(1E-06f * Maxf(Fabs(a), Fabs(b)), Epsilon * 8.0f);
	}
	//------------------------------------------------------------------------------------------------------------------------
	// Compares a kVec3 point to a float value if they are similar.
	//------------------------------------------------------------------------------------------------------------------------
	bool Vec3Approximately(kVec3 a, const float b)
	{
		return Approximately(a.x, b) && Approximately(a.y, b) && Approximately(a.z, b);
	}
	//------------------------------------------------------------------------------------------------------------------------
	// Returns the number of digits in the integer (ignores negative values)
	//------------------------------------------------------------------------------------------------------------------------
	int IntLength(const int n)
	{
		int num = Math::Abs(n);
		int count = 0;
		while (num > 0)
		{
			num /= 10;
			count++;
		}
		return count;
	}
	//------------------------------------------------------------------------------------------------------------------------
	float Minf(const float a, const float b)
	{
		return (a < b) ? a : b;
	}
	//------------------------------------------------------------------------------------------------------------------------
	float Maxf(const float a, const float b)
	{
		return (a > b) ? a : b;
	}
	//------------------------------------------------------------------------------------------------------------------------
	int Min(const int a, const int b)
	{
		return (a < b) ? a : b;
	}
	//------------------------------------------------------------------------------------------------------------------------
	int Max(const int a, const int b)
	{
		return (a > b) ? a : b;
	}
	//------------------------------------------------------------------------------------------------------------------------
	float SmoothStepBP(const float from, const float to, float t)
	{
		t = Math::Clampf(t, 0.0f, 1.0f);
		t = -2.0f * t * t * t + 3.0f * t * t;
		return to * t + from * (1.0f - t);
	}
	//------------------------------------------------------------------------------------------------------------------------
	kVec3 SmoothStepVec3(const kVec3 &in from, const kVec3 &in to, float t)
	{
		t = -2.0f * t * t * t + 3.0f * t * t;
		float it = 1.0f - t;
		return kVec3(to.x * t + from.x * it, to.y * t + from.y * it, to.z * t + from.z * it);
	}
	//------------------------------------------------------------------------------------------------------------------------
	float LerpClamped(const float start, const float end, float time)
	{
		return Math::Lerp(start, end, Math::Clampf(time, 0.0f, 1.0f));
	}
	//------------------------------------------------------------------------------------------------------------------------
	int LerpClampedInt(const int start, const int end, const float time)
	{
		return int(Math::Lerp(start, end, Math::Clampf(time, 0.0f, 1.0f)));
	}
	//------------------------------------------------------------------------------------------------------------------------
	float Clampf(const float value, const float min, const float max)
	{
		return (value < min) ? min : ((value > max) ? max : value);
	}
	//------------------------------------------------------------------------------------------------------------------------
	int Clamp(const int value, const int min, const int max)
	{
		return (value < min) ? min : ((value > max) ? max : value);
	}
	//------------------------------------------------------------------------------------------------------------------------
	float Round(const float value)
	{
		int a = int(value * 10);
		int b = int(value) * 10;
		if (value < 0)
		{
			return (a + b >= 5) ? Math::Floor(value) : Math::Ceil(value);
		}
		return (a - b >= 5) ? Math::Ceil(value) : Math::Floor(value);
	}
	//------------------------------------------------------------------------------------------------------------------------
	int RoundToInt(const float value)
	{
		return int(Round(value));
	}
	//------------------------------------------------------------------------------------------------------------------------
    // Returns a clamped angle to intervals of angleClamp degrees
	//------------------------------------------------------------------------------------------------------------------------
    float ClampAngle(const float value, const float angleClamp)
    {
        return Round(value / angleClamp) * angleClamp;
    }
	//------------------------------------------------------------------------------------------------------------------------
	// Converts an Angle(in rads) to a kVec3 using x,y as direction with magnitude of 1
	//------------------------------------------------------------------------------------------------------------------------
	kVec3 AngleToDirectionXY(const float r)
	{
		return kVec3(Math::Sin(r), Math::Cos(r), 0.0f);
	}
	//------------------------------------------------------------------------------------------------------------------------
	float Vec3Dot(const kVec3 &in lhs, const kVec3 &in rhs)
	{
		return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
	}
	//------------------------------------------------------------------------------------------------------------------------
	kVec3 Vec3Reflect(const kVec3 &in inDirection, const kVec3 &in inNormal)
	{
		//missing add and mul operators so doing addassign and mulassign instead
		float t2 = -2.0f * Vec3Dot(inNormal, inDirection);
		kVec3 t = inNormal;
		t *= t2;
		t += inDirection;
		return t;
		//return -2.0f * Vec3Dot(inNormal, inDirection) * inNormal + inDirection;
	}
	//------------------------------------------------------------------------------------------------------------------------
}
