/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2008.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: include/sgx/core/math/numerics.inl

*/

#ifndef SGX_CORE_MATH_NUMERICS_INLINE
#define SGX_CORE_MATH_NUMERICS_INLINE	1

#include <cmath>

/**
Return the absolute value of f. That is, its value as a position number.
*/
SGX_INLINE tREAL32 sgxAbs(tREAL32 f)
{
    if (f < 0) return -f;
    return f;
}

/**
Is equal?
Returns TRUE only if both values are equal. The equality test here uses
a differential epsilon, so any two numbers within sgxEPSILON of each
other are considered equal. You can give your own episilon if necessary.
*/
SGX_INLINE tBOOL sgxEq(tREAL32 fValue1, tREAL32 fValue2, tREAL32 epsilon=SGX_EPSILON)
{
    return sgxAbs(fValue1 - fValue2) < epsilon;
}

/**
Not equal to?
Returns TRUE only if both values are not equal.
See sgxEq.
*/
SGX_INLINE tBOOL sgxNeq(tREAL32 fValue1, tREAL32 fValue2, tREAL32 epsilon=SGX_EPSILON)
{
    return sgxAbs(fValue1 - fValue2) >= epsilon;
}

/**
Calculate the square root.
The results of negative numbers are undefined.
*/
SGX_INLINE tREAL32 sgxSqr(tREAL32 f)
{
	return (tREAL32)std::sqrt((double)f);
}

/**
Raise the number @base to the power of @exponent.
*/
SGX_INLINE tREAL32 sgxPower(tREAL32 base, tREAL32 exponent)
{
extern double pow(double,double);
	return (tREAL32)pow((double)base, (double)exponent);
}

/**
Returns the signed value of @f. That is, -1 for negative numbers,
+1 for positives, and 0 for zero. 
Note: Epsilon is not used.
*/
SGX_INLINE tREAL32 sgxSign(tREAL32 f)
{
	if (f < 0) {
		return -1.0f;
	} else if (f > 0) {
		return 1.0f;
	} else {
		return 0;
	}
}

/**
Round down to the nearest whole number.
*/
SGX_INLINE tINT32 sgxFloor(tREAL32 f)
{
	return SGX_STATIC_CAST(tINT32,f);
}

/**
Return a number that is nearer to @approaching, beginning from @from.
The step made towards @approach will never be greater than @max_delta.
*/
SGX_INLINE tREAL32 sgxApproach(const tREAL32 from, const tREAL32 approaching, const tREAL32 max_delta=0.1f)
{
	tREAL32 next = from;

	if (next > approaching) {
		next -= max_delta;
		if (next < approaching) {
			return approaching;
		}
	} else if (next < approaching) {
		next += max_delta;
		if (next > approaching) {
			return approaching;
		}
	}

	return next;			
}

/**
Returns the fractional equivalent of @from (i.e. a number between 0 and
1) based on the @scale given. So if @from == @scale then 1 is returned,
and if @from == 0 then 0 is returned, and all other numbers are linearly
scaled inbetween.
*/
SGX_INLINE tREAL32 sgxConvert(const tINT32 from, const tREAL32 scale)
{
	tREAL32 val = SGX_STATIC_CAST(tREAL32, from);
	val /= scale;
	return val;
}

/**
Returns the scaled value of the fractional number @from, which should lie
between 0 and 1. An input of 1 would return @scale, and is the reverse
operation of the other @sgxConvert.
*/
SGX_INLINE tINT32 sgxConvert(const tREAL32 from, const tINT32 scale)
{
	tINT32 val = SGX_STATIC_CAST(tINT32, from);
	val *= scale;
	return val;
}

template <typename T>
SGX_INLINE T sgxRescale(T value, T originalFrom, T originalTo, T scaledFrom, T scaledTo) {
	if (value < originalFrom) 		value = originalFrom;
	if (value > originalTo) 		value = originalTo;
	if (originalFrom == originalTo) return originalFrom;
	return scaledFrom + ((value - originalFrom)*(scaledTo-scaledFrom)) / (originalTo - originalFrom);
}


#endif /* SGX_CORE_MATH_NUMERICS_INLINE */
