/*****************************************************************************
 * $Id: gfx_funcs2.hh,v 1.11 2006/10/31 01:56:15 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Various small functions: function macros, inline functions, template functions.
 * @remarks	Include this after gfx_types.hh.
 *          Writing "inline" in template functions does increase speed (gcc 3.4).
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GFX_FUNCS2_HH
#define GFX_FUNCS2_HH 1

namespace gfx {

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// function macros ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// inline functions ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/// Cope with floating-point inaccuracy.
/// Return true if two floats are approximately equal.
static inline bool FEQ( fp a, fp b ) { return ABS(a-b) < 0.001; }
static inline bool FNE( fp a, fp b ) { return ABS(a-b) > 0.001; }
static inline bool FEQ_FLOAT_LARGE( fp f ) { return ABS(f-FLOAT_LARGE) < 100.0; }
static inline bool FEQ_FLOAT_SMALL( fp f ) { return ABS(f-FLOAT_SMALL) < 100.0; }

/// Compare floats: compare full integral part, compare fracDigits of fractional part.
/// Eg: FEQ( 1.234, 1.234, 4 )
/// Note: In practice, usually, fracDigits should be small, or miscompares will be frequent.
/// Tested by gfx/tests/math.cc.
template<typename FP>
bool
FEQ( const FP a, const FP b, const uint fracDigits )
{
    FP aInt, bInt, aFrac, bFrac;
    aFrac = modf( a, &aInt );  // split float into integral.fractional
    bFrac = modf( b, &bInt );
    long ai = long(aInt);
    long bi = long(bInt);
    if ( ai == bi )  // are integral parts equal?
    {
        // Multiply fractional digits to shift them to integer side of decimal point.
        // Eg 1.2345 --> 12345 (fracDigits=4)
        const FP fracDigitsPow = pow( FP(10.0), FP(fracDigits) );
        long af = long(aFrac * fracDigitsPow);
        long bf = long(bFrac * fracDigitsPow);
        return af == bf;
    }
    else
        return false;
}

/*****************************************************************************
 * Clamp value to 0xFF.
 * ClampFF(uint) is the fastest.
 *****************************************************************************/
static inline uint8
ClampFF( uint i )
{
	// gcc 4.x does inline an optimal x86 CMOV instruction.
	if ( EX(i < 0xff) )
		return uint8(i);
	else
		return 0xff;
}
static inline uint8
ClampFF( int i )
{
	if ( i < 0 )
		return 0;
	else if ( i > 0xff )
		return 0xff;
	else
		return uint8(i);
}
static inline uint8
ClampFF( fp f )
{
    if ( f >= 1.0 )
        return 0xff;
    else if ( f < 0.0 )
        return 0;
    else
        return uint8( f * 256.0 );
}

/*****************************************************************************
 * Clamp float to within 0.0,...,1.0.
 *****************************************************************************/
static inline fp
Clamp1( fp f )
{
	if ( UX(f < 0.0) )
		return 0.0;
	else if ( UX(f > 1.0) )
		return 1.0;
	else
		return f;
}
static inline fp
Clamp( fp f, fp low = 0.0, fp high = 1.0 )
{
	if ( UX( f < low ) )
		return low;
	else if ( UX( f > high ) )
		return high;
	else
		return f;
}

////////////////////////////////////////////////////////////////////////////////
///////////////////////// template functions ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

} // namespace gfx

#endif // GFX_FUNCS2_HH
