/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2004 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef __SYSMATH_H
#define __SYSMATH_H

#include <math.h>

#pragma warning(disable:4244)
#pragma warning(disable:4305)
#pragma warning(disable:4996)

#ifdef __ICL // intel compiler warning
	#pragma warning(disable:181)  // argument is incompatible with corresponding format string conversion
	#pragma warning(disable:175)  // subscript out of range
	#pragma warning(disable:810)  // conversion from "unsigned __int64" to "LONG={long}" may lose significant bits
	#pragma warning(disable:1684)  // conversion from pointer to same-sized integral type (potential portability problem)
//#pragma warning(disable:1563) // use of temporaries
	#pragma warning(disable:1478) // sscanf, vsprintf deprecated
	#pragma warning(disable:1786) // Intel sscanf, vsprintf deprecated
#endif

#define __TYPES_READY

struct Matrix;
struct Vector;

#define FALSE 0
#define TRUE  1
#define NULL 	0


#ifndef __WINDOWS_H
#ifndef _WINDOWS_
typedef short int	          WORD;
#endif
#endif
typedef unsigned short int	UWORD;
typedef long 								LONG;
typedef unsigned long				ULONG;
typedef int                 Bool;
typedef float								SReal;
typedef double							LReal;
typedef void*								Hndl;
typedef int									INT;
typedef unsigned int 				UINT;
typedef char								CHAR;
typedef unsigned char				UCHAR;

#ifdef __C4D_64BIT
	#ifdef __ICL
		typedef long long LLONG;
		typedef unsigned long long LULONG;
		typedef unsigned long long VULONG;
		typedef signed long long VLONG;
	#else
		typedef _W64 __int64    LLONG;
		typedef _W64 unsigned __int64    LULONG;
		typedef _W64 unsigned __int64    VULONG;
		typedef _W64 signed __int64		   VLONG;
	#endif
#else
	typedef __int64							LLONG;
	typedef unsigned __int64		LULONG;
	typedef unsigned long				VULONG;
	typedef signed long					VLONG;
#endif

#ifndef MAXLONG
	#define MAXLONG						0x7fffffff
#endif
#ifndef MINLONG
	#define MINLONG						(-0x7fffffff) // explicitely not 0x80000000
#endif
#ifndef MAXULONG
	#define MAXULONG					0xffffffff
#endif
#ifndef MAXWORD
	#define MAXWORD						32767L
#endif
#ifndef MAXUWORD
	#define MAXUWORD					65535L
#endif

typedef float								Real;
#define MAXREAL							( 9.0e18)
#define MINREAL							(-9.0e18)

#define NOTOK								(-1)

#define pi		3.1415926535897932384626433832795
#define pi2		6.283185307179586476925286766559
#define pi05	1.5707963267948966192313216916398

inline Real  FMin(Real a,  Real b) { if (a<b) return a; return b; }
inline LReal FMin(LReal a, LReal b) { if (a<b) return a; return b; }
inline LONG  LMin(LONG a,  LONG b) { if (a<b) return a; return b; }

inline Real  FMax(Real a, Real b) { if (a<b) return b; return a; }
inline LReal FMax(LReal a, LReal b) { if (a<b) return b; return a; }
inline LONG  LMax(LONG a, LONG b) { if (a<b) return b; return a; }

inline Real  FCut(Real  a,Real b,Real c) { if (a<b) return b; if (a>c) return c; return a; }
inline LReal FCut(LReal a,LReal b,LReal c) { if (a<b) return b; if (a>c) return c; return a; }
inline LONG  LCut(LONG  a,LONG b,LONG c) { if (a<b) return b; if (a>c) return c; return a; }
template <class A> inline A TCut(A a,A b,A c) { if (a<b) return b; if (a>c) return c; return a; }

#ifndef __ICL
  #ifdef __PC
	inline LONG FtoL(float r)
	{
		LONG exp = (*(ULONG*)&r >> 23) & 0xFF,res;
		if (exp<0x7F)	return 0;
		if (exp>0x9e) res=MAXLONG;
		else res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(0x9e-exp);
		if (*(ULONG*)&r & 0x80000000) res=-res;
		return res;
	}
  #else
	#define FtoL(x)		LONG(x)
  #endif

	#define Abs(a)			(((a)<0)?-(a):(a))

	inline Real Sin(Real r)  { return (Real)sin((double)r); }
	inline Real Cos(Real r)  { return (Real)cos((double)r); }
	inline Real Tan(Real r)  { return (Real)tan((double)r); }
	inline Real ATan(Real r) { return (Real)atan((double)r); }
	inline Real Exp(Real r)  { return (Real)exp((double)r); }
	inline Real Ln(Real r)   { return (Real)log((double)r); }
	inline Real Ld(Real r)   { return (Real)log((double)r) / 0.69314718055994530941723212145818f; }
	inline Real Ln10(Real r) { return (Real)log10((double)r); }
	inline Real Sqrt(Real r) { return (Real)sqrt((double)r); }
	inline Real Floor(Real r){ return (Real)floor((double)r); }
	inline Real Ceil(Real r) { return (Real)ceil((double)r); }
	inline Real Cosh(Real r) { return (Real)cosh((double)r); }
	inline Real Sinh(Real r) { return (Real)sinh((double)r); }
	inline Real Tanh(Real r) { return (Real)tanh((double)r); }
	inline Real Pow(Real r,Real s)  { return (Real)pow((double)r,(double)s); }
	inline Real FMod(Real r,Real s) { return (Real)fmod((double)r,(double)s); }

	inline LReal Sin(LReal r)  { return sin(r); }
	inline LReal Cos(LReal r)  { return cos(r); }
	inline LReal Tan(LReal r)  { return tan(r); }
	inline LReal ATan(LReal r) { return atan(r); }
	inline LReal Exp(LReal r)  { return exp(r); }
	inline LReal Ln(LReal r)   { return log(r); }
	inline LReal Ld(LReal r)   { return log(r) / 0.69314718055994530941723212145818; }
	inline LReal Ln10(LReal r) { return log10(r); }
	inline LReal Sqrt(LReal r) { return sqrt(r); }
	inline LReal Floor(LReal r){ return floor(r); }
	inline LReal Ceil(LReal r) { return ceil(r); }
	inline LReal Cosh(LReal r) { return cosh(r); }
	inline LReal Sinh(LReal r) { return sinh(r); }
	inline LReal Tanh(LReal r) { return tanh(r); }
	inline LReal Pow(LReal r,LReal s)  { return pow(r,s); }
	inline LReal FMod(LReal r,LReal s) { return fmod(r,s); }

  inline Real ASin(Real val)
	{
		if(val>=1.0) return pi05;
		else if(val<=-1.0) return -pi05;
		return asin((double)val);
	}

	inline LReal ASin(LReal val)
	{
		if(val>=1.0) return pi05;
		else if(val<=-1.0) return -pi05;
		return asin((double)val);
	}

	inline Real ACos(Real val)
	{
		if(val>=1.0) return 0.0;
		else if(val<=-1.0) return pi;
		return acos((double)val);
	}

	inline LReal ACos(LReal val)
	{
		if(val>=1.0) return 0.0;
		else if(val<=-1.0) return pi;
		return acos((double)val);
	}

	inline LONG LFloor(Real r)
	{
		LONG exp = (*(ULONG*)&r >> 23) & 0xFF;
		exp-=0x7f;

		if (*(ULONG*)&r & 0x80000000)
		{
			if (exp<0) return -1;
			if (exp>31) return MINLONG;

			LONG res = (0x7FFFFF)>>exp;
			LONG sub = ((*(ULONG*)&r)&res)!=0;
			res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
			return -res-sub;
		}

		if (exp<0) return 0;
		if (exp>31) return MAXLONG;
		return ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
	}

	inline LONG LCeil(Real r)
	{
		LONG exp = (*(ULONG*)&r >> 23) & 0xFF;
		exp-=0x7f;

		if (!(*(ULONG*)&r & 0x80000000))
		{
			if (exp<0) return 1;
			if (exp>31) return MAXLONG;

			LONG res = (0x7FFFFF)>>exp;
			LONG sub = ((*(ULONG*)&r)&res)!=0;
			res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
			return res+sub;
		}

		if (exp<0) return 0;
		if (exp>31) return MINLONG;
		return -LONG(ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp));
	}

#else

	#define FtoL(x)		LONG(x)

	inline Real  Abs( Real f) { return fabs(f); }
	inline LReal Abs(LReal f) { return fabs(f); }
	template <class X> inline X Abs(X f) { if (f<0) return -f; return f; }

	inline Real Sin(Real r)  { return sin(r); }
	inline Real Cos(Real r)  { return cos(r); }
	inline Real Tan(Real r)  { return tan(r); }
	inline Real ATan(Real r) { return atan(r); }
	inline Real Exp(Real r)  { return exp(r); }
	inline Real Ln(Real r)   { return log(r); }
	inline Real Ld(Real r)   { return log(r) / 0.69314718055994530941723212145818f; }
	inline Real Ln10(Real r) { return log10(r); }
	inline Real Sqrt(Real r) { return sqrt(r); }
	inline Real Floor(Real r){ return floor(r); }
	inline Real Ceil(Real r) { return ceil(r); }
	inline Real Cosh(Real r) { return cosh(r); }
	inline Real Sinh(Real r) { return sinh(r); }
	inline Real Tanh(Real r) { return tanh(r); }
	inline Real Pow(Real r,Real s)  { return pow(r,s); }
	inline Real FMod(Real r,Real s) { return fmod(r,s); }
	inline Real ASin(Real val) { if(val>=1.0) return pi05; else if(val<=-1.0) return -pi05; return asin(val); }
	inline Real ACos(Real val) { if(val>=1.0) return 0.0; else if(val<=-1.0) return pi; return acos(val); }

	inline LReal Sin(LReal r)  { return sin(r); }
	inline LReal Cos(LReal r)  { return cos(r); }
	inline LReal Tan(LReal r)  { return tan(r); }
	inline LReal ATan(LReal r) { return atan(r); }
	inline LReal Exp(LReal r)  { return exp(r); }
	inline LReal Ln(LReal r)   { return log(r); }
	inline LReal Ld(LReal r)   { return log(r) / 0.69314718055994530941723212145818f; }
	inline LReal Ln10(LReal r) { return log10(r); }
	inline LReal Sqrt(LReal r) { return sqrt(r); }
	inline LReal Floor(LReal r){ return floor(r); }
	inline LReal Ceil(LReal r) { return ceil(r); }
	inline LReal Cosh(LReal r) { return cosh(r); }
	inline LReal Sinh(LReal r) { return sinh(r); }
	inline LReal Tanh(LReal r) { return tanh(r); }
	inline LReal Pow(LReal r,LReal s)  { return pow(r,s); }
	inline LReal FMod(LReal r,LReal s) { return fmod(r,s); }
	inline LReal ASin(LReal val) { if(val>=1.0) return pi05; else if(val<=-1.0) return -pi05; return asin(val); }
	inline LReal ACos(LReal val) { if(val>=1.0) return 0.0; else if(val<=-1.0) return pi; return acos(val); }

	inline LONG LFloor(Real r)  { return LONG(Floor(r)); }
	inline LONG LCeil(Real r)   { return LONG(Ceil(r));  }
#endif

inline LONG LFloor(LReal r) { return LONG(Floor(r)); }
inline LONG LCeil(LReal r)  { return LONG(Ceil(r));  }

inline Real  Rad(Real r)    { return ((r)*pi/180.0); }
inline LReal Rad(LReal r)   { return ((r)*pi/180.0); }
inline Real  Deg(Real r)    { return ((r)*180.0/pi); }
inline LReal Deg(LReal r)   { return ((r)*180.0/pi); }
inline void SinCos(Real w,Real &sn,Real &cn) { sn=Sin(w); cn=Cos(w); }
inline void SinCos(LReal w,LReal &sn,LReal &cn) { sn=Sin(w); cn=Cos(w); }

#define Mod(a,b)	((a)<0?((a)-(((a)-(b)+1)/(b))*(b)):(a)%(b))

inline LONG SAFELONG(Real x)
{
	if(x<=MINLONG)
		return MINLONG;
	else if(x>=MAXLONG)
		return MAXLONG;

	return FtoL(x);
}

#endif
