/*
	Twilight Prophecy 3D/Multimedia SDK
	A multi-platform development system for virtual reality and multimedia.

	Copyright (C) 1997-2001 by Twilight 3D Finland Oy Ltd.
*/
#ifndef PRCORE_FLOAT_HPP
#define PRCORE_FLOAT_HPP



namespace prcore
{

	// type conversions

#ifdef PRCORE_LITTLE_ENDIAN
#define PRCORE_FLTBIT(v) ((int32*)&v)[0]
#else
#define PRCORE_FLTBIT(v) ((int32*)&v)[1]
#endif

inline int32 DoubleToInt(double v)
{
	v += (68719476736.0 * 1.5);
	return PRCORE_FLTBIT(v) >> 16;
}

inline int32 DoubleToFixed(double v)
{
	v += (68719476736.0 * 1.5);
	return PRCORE_FLTBIT(v);
}

inline int32 FloatToInt(float v)
{
	double magic = 68719476736.0 * 1.5 + v;
	return PRCORE_FLTBIT(magic) >> 16;
}

inline int32 FloatToFixed(float v)
{
	double magic = 68719476736.0 * 1.5 + v;
	return PRCORE_FLTBIT(magic);
}

inline uint32 FloatSign(const float& v)
{	
	return (((uint32&)v) & 0x80000000);
}

#undef PRCORE_FLTBIT

	// type conversions complying to the ieee754 rounding rules
	// from: Ville "wili" Miettinen @ www.flipcode.com code-of-day column

inline int FloatToIntChop(const float& v)
{
	int32& u = *(int32*)&v;
	int32 s = u >> 31;
	int32 e = ((u & 0x7fffffff) >> 23) - 127;
	return (((((uint32)((u & ((1<<23) - 1)) | (1<<23)) << 8) >> (31-e)) ^ (s)) - s ) &~ (e>>31);
}

inline int FloatToIntFloor(const float& v)
{
	int32& u = *(int32*)&v;
	int32 sign = u >> 31;
	int32 exponent = ((u & 0x7fffffff)>>23) - 127;
	int32 expsign = ~(exponent >> 31);
	int32 mantissa = (u & ((1<<23) - 1));
	return (((((uint32)(mantissa | (1<<23)) << 8) >> (31-exponent)) & expsign) ^ (sign)) + ((!((mantissa<<8) & (((1<<(31-(exponent & expsign)))) - 1))) & sign);
}

inline int FloatToIntCeil(const float& v)
{
	int32 u = (*(int32*)&v) ^ 0x80000000;
	int32 sign = u >> 31;
	int32 exponent = ((u & 0x7fffffff)>>23) - 127;
	int32 expsign = ~(exponent>>31);
	int32 mantissa = (u & ((1<<23) - 1));
	return -(int)((((((uint32)(mantissa | (1<<23)) << 8) >> (31-exponent)) & expsign) ^ (sign)) + ((!((mantissa<<8) & (((1<<(31-(exponent & expsign)))) - 1))) & sign & expsign));
}

	// macros

inline float Lerp(float a, float b, float t)
{
	return a + (b - a) * t;
}

inline float Snap(float p, float grid)
{
	return grid ? float( floor((p + grid*0.5f)/grid) * grid) : p;
}

	// logarithm & squareroot
	
inline float rsqrt(float v)
{
	float h = v * 0.5f;
	int32& i = (int32&)v;
	i = 0x5f3759df - (i >> 1);
	v *= 1.5f - (h * v * v);
	v *= 1.5f - (h * v * v);
	return v;
}

inline int sqrtlog2(float v)
{
	return (((((int32&)v - 0x3f800000) >> 1) + 0x3f800000) >> 23) - 127;
}

inline int flog2(float v)
{
	return int(((uint32&)v >> 23) & 0xff) - 127;
}

inline int ilog2(uint16 v)
{
	float fv = float( v );
	return (((int&)fv) >> 23) - 127;
}

	// trigonometry
	
template <typename T>
inline float sinf(T v)
{
	return (float)sin(v);
}

template <typename T>
inline float cosf(T v)
{
	return (float)cos(v);
}

} // namespace prcore



#endif