/****************************************************************************************

	Real.h

	Copyright: (c) 2001 Eovia Corp. All rights reserved.

	Author:	Ray Dream (orig. JohnS)
	Date:		3/2/98

	Revision History

	when		who			what & why
	==========	==========	======================================================
	04/07/99	EricG		more math functions
	02/01/99	dsm			moved float consts into header files
	7/17/98		Craig		added RoundRealToInt32(); RoundRealToInt16() now actually rounds.
	5/27/98		Alec		fixed unused arg warning in Real64ToRealCheck
	3/4/98		Greg		Initial conversion (real to real)

*****************************************************************************************/

#ifndef __REAL__
#define __REAL__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicTypes.h"

#include <math.h>

#define mypi			3.1415926535
#define my2pow14 		16384.0
#define my2pow15Minus1 	32767.0

/******************************************************************\
*                                                                  *
* Constants                                                        *
*                                                                  *
\******************************************************************/

const real kRealMinusOne 	= -1.0f;
const real kRealOne 		= 1.0f;
const real kRealTwo			= 2.0f;
const real kRealZero		= 0.0f;
const real kReal32767		= float(my2pow15Minus1);
const real kRealMax		= float(1e20);
const real kRealMin		= float(-1e20);
const real kRealMinus32767	= float(-my2pow15Minus1);
const real kRealEpsilon		= float(1.0/my2pow14);
const real kRealOneHalf		= 0.5f;
const real kRealOneThird	= 1.0f/3.0f;
const real kRealTwoThirds	= 2.0f/3.0f;
const real kRealOneFourth	= 0.25f;

const real kRealPI			= float(mypi);
const real kRealTwoPI		= float(mypi*2.0);
const real kRealHalfPI		= float(mypi/2.0);
const real kRealThirdPI		= float(mypi/3.0);
const real kRealFourthPI	= float(mypi/4.0);
const real kRealRadToDeg	= float(180.0/mypi);
const real kRealDegToRad	= float(mypi/180.0);

const real kRealLogTwo		= 0.6931471805599f;

const real kRealBig			= float(my2pow14); // actually not so big anymore now that we're using floats

#define dsOverflow 32000


/******************************************************************\
*                                                                  *
* Functions                                                        *
*                                                                  *
\******************************************************************/

// Trigonometry and Misc. Math

// angles are in radians
inline real   RealAtan2			(real sin, real cos){ return (real32) atan2(sin,cos); 	}
inline real	  RealAbs			(real xx) 			{ return (real32) fabs(xx); 		}
inline real   RealSin			(real xx) 			{ return (real32) sin(xx); 			}
inline real   RealCos			(real xx) 			{ return (real32) cos(xx); 			}
inline real   RealTan			(real xx) 			{ return (real32) tan(xx); 			}
inline real   RealSqrt			(real xx) 			{ return (real32) sqrt(xx); 		}
inline real   RealExp			(real xx) 			{ return (real32) exp(xx); 			}
inline real   RealLog			(real xx) 			{ return (real32) log(xx); 			}
inline real   RealFloor			(real xx) 			{ return (real32) floor(xx);		}
inline real   RealCeil			(real xx) 			{ return (real32) ceil(xx); 		}

// the angle is in degree
void 		  RealArcSinCos		(real sin, real cos, real& angle);
void 		  RealSinCos		(real angle, real& sin, real& cos);


// Conversion

inline real   FixedToReal		(int32 xx) 	{ return real32(xx)/real32(65536.0); }
inline real   Int16ToReal		(int16 xx)	{ return real32(xx); }
inline real   UInt16ToReal		(uint16 xx)	{ return real32(xx); }
inline int16  RealToInt16		(real xx)	{ return int16(xx);  }
inline uint16 RealToUInt16		(real xx)	{ return uint16(xx); }
inline real   Int32ToReal		(int32 xx)	{ return real32(xx); }
inline real	  UInt32ToReal		(uint32 xx)	{ return real32(xx); }
inline int32  RealToInt32		(real xx)	{ return int32(xx);  }
inline uint32 RealToUInt32		(real xx)	{ return uint32(xx); }
inline int32  RoundRealToInt32	(real xx)	{ return (xx>0) ? (int32) ((xx)+0.5) : -(int32) (0.5-(xx)); }
inline int16  RoundRealToInt16	(real xx)	{ return (xx>0) ? (int16) ((xx)+0.5) : -(int16) (0.5-(xx)); }
inline int32  TruncRealToInt32	(real xx)	{ return int32(real32(xx)); }
inline uint32 TruncRealToUInt32	(real xx)	{ return uint32(real32(xx));}
inline int16  TruncRealToInt16	(real xx)	{ return int16(floor(xx));  }
inline uint16 TruncRealToUInt16	(real xx)	{ return uint16(floor(xx)); }
inline int32  RealToFixed		(real xx) 	{ return int32(xx * real32(65536.0)); }

inline void   RealToReal64		(real xx, real64 &value) 			{ value = xx;}
inline real64 RealToReal64		(real xx) 							{ return xx; }
inline real32 RealToReal32		(real xx) 							{ return xx; }
inline real   Real32ToReal		(real32 xx) 						{ return xx; }
inline real   Real64ToReal		(real64 value) 						{ return real32(value); }
inline real   Real64ToRealCheck	(real64 value, int* overflow = 0)	{ overflow; return real32(value); }

inline real   RadToDeg			(real xx)	{ return xx * real32(57.29577951308);  }
inline real   DegToRad			(real xx)	{ return xx * real32(0.01745329251994);}


// Multiplication

inline real 	RealMul2		(real xx) 	{ return xx * real32(2.0); }
inline real 	RealMul4		(real xx) 	{ return xx * real32(4.0); }
inline real 	RealMul8		(real xx) 	{ return xx * real32(8.0); }
inline real 	RealMul16		(real xx) 	{ return xx * real32(16.0);}
inline int 		MultiplyClip	(real& xx, const real yy) { xx = xx * yy; return 1; }
real 			RealMul2Power	(real xx, int16 yy);

#define Mul(xx,yy) ((xx)*(yy))


// Division

inline real 	RealDiv2		(real xx)	{ return xx*real32(0.5);    }
inline real 	RealDiv4		(real xx)	{ return xx*real32(0.25);   }
inline real 	RealDiv8		(real xx)	{ return xx*real32(0.125);  }
inline real 	RealDiv16		(real xx)	{ return xx*real32(0.0625); }

#define Div(xx,yy) ((xx)/(yy))
#define DivClip(xx,yy) ((xx)/(yy))


// Power

inline real 	RealPow			(real xx, real yy) { return real32(pow(xx, yy)); }

// Spline

real32 Spline(real32 x, const int32 knotsCount, real32* knots);
// same method but for 4 points only
real32 Spline4(real32 x, real32* knots);

const real64  kDouble2fixmagic 	= 68719476736.0*1.5;

#if defined(ARCH_X86) || defined(ARCH_X64)
inline int32 FloorWithFixed(real64 val)
{
	val		= val + kDouble2fixmagic;
	return (((int32*)&val)[0])>>16;
}
#elif defined(ARCH_POWER_PC)

inline int32 FloorWithFixed(real64 val)
{
	val		= val + kDouble2fixmagic;
	return (((int32*)&val)[1])>>16;
}
#else
#error	unknown processor
#endif

#endif