//=================================================================
//
// Copyright (c) Microsoft Corporation 1999 - All Rights Reserved.
//
//=================================================================

#ifndef __imath_h
#define __imath_h

#define     int_ONE                     16384
#define     int_SHIFT                   14
#define     int_MAX                     0x7fff
#define     int_MIN                     0x8000

#define     long_ONE                    0x01000000
#define     long_SHIFT                  24
#define     long_MAX                    0x7fffffff
#define     long_MIN                    0x80000000

#define     int_PI_4                    0x00010000
#define     int_PI_2                    0x00020000
#define     int_PI                      0x00040000
#define     int_2_PI                    0x00080000
#define     int_mask_2_PI               0x0007ffff
#define     int_Shift_PI_2              17
#define     int_Shift_PI                18

#define     MathPI                      3.14159265358979323846

inline  int range360(int a)             { return a & int_mask_2_PI; }
inline  int range180(int a)             { return range360(a+int_PI)-int_PI; }

extern "C" {

DWORD   __cdecl     dsqrt   (DWORD,DWORD);
long    __cdecl     leng2l  (long,long);
long    __cdecl     leng3l  (long,long,long);
long    __cdecl     leng3dl (void*);
long    __cdecl     lengp3dl(void*);
long    __cdecl     norm3dl (void*,int);

int     __cdecl     isin    (int);
int     __cdecl     icos    (int);
int     __cdecl     itan    (int);
long    __cdecl     lsin    (long);
long    __cdecl     lcos    (long);
int     __cdecl     iatan2  (int,int);
int     __cdecl     lbsf    (DWORD);
int     __cdecl     lbsr    (DWORD);
};

inline  short   ABS (short a)           { return (a<0)?-a:a; }
inline  int     ABS (int   a)           { return (a<0)?-a:a; }
inline  long    ABS (long  a)           { return (a<0)?-a:a; }

//inline  int     BSF (long  a)           { return lbsf(DWORD(a));}
inline  int     BSF (DWORD a)           { return lbsf(a); }

//inline  int     BSR (long  a)           { return lbsr(DWORD(a));}
inline  int     BSR (DWORD a)           { return lbsr(a); }

inline  DWORD   SQRT(short a)           { return dsqrt(DWORD(a), 0); }
inline  DWORD   SQRT(int   a)           { return dsqrt(DWORD(a), 0); }
inline  DWORD   SQRT(long  a)           { return dsqrt(DWORD(a), 0); }
inline  DWORD   SQRT(WORD  a)           { return dsqrt(DWORD(a), 0); }
inline  DWORD   SQRT(DWORD a)           { return dsqrt(a       , 0); }

inline  int     ONE(int)                { return int_ONE; }
inline  long    ONE(long)               { return int_ONE; }
inline  int     SIN(int a)              { return isin(a); }
inline  int     COS(int a)              { return icos(a); }
inline  int		TAN(int a)				{ return itan(a); }
inline  int     ATAN2(int y,int x)      { return iatan2(y,x); }

#ifdef  _MSC_VER

#pragma warning(disable:4035)   // re-enable below
#if 0
inline  long    mult(long a,long b)
{
	__asm {
		mov		eax,a;
		imul	b;
		shrd	eax,edx,int_SHIFT;
	}
}

inline  int     mult(int a,int b)
{
	__asm {
        mov     eax,a;
        imul    b;
		shrd	eax,edx,int_SHIFT;
	}
}

inline  short   mult(short a,short b)
{
	__asm {
        movsx   eax,a;
        movsx   ebx,b;
        imul    eax,ebx;
        sar     eax,int_SHIFT;
	}
}

inline  long    multD(long a,long b)
{
	__asm {
		mov		eax,a;
		imul	b;
        shrd    eax,edx,long_SHIFT;
	}
}

inline  long    mult(long a,long b,int s)
{
	__asm {
		mov		eax,a;
		imul	b;
        mov     ecx,s
        shrd    eax,edx,cl;
	}
}

inline  long    mult(int a,int b,int s)
{
	__asm {
		mov		eax,a;
		imul	b;
        mov     ecx,s
        shrd    eax,edx,cl;
	}
}


inline  long    mult(int a,long b)
{
	__asm {
		mov		eax,a;
		imul	b;
		shrd	eax,edx,int_SHIFT;
	}
}

inline  long    mult(int a,short b)
{
	__asm {
        movsx   eax,b;
        imul    a;
		shrd	eax,edx,int_SHIFT;
	}
}

#else
inline  long    mult(long a,long b)
{
	__asm {
		mov		eax,a;
		imul	b;
        add     eax,int_ONE/2
        adc     edx,0
		shrd	eax,edx,int_SHIFT;
	}
}

inline  int     mult(int a,int b)
{
	__asm {
        mov     eax,a;
        imul    b;
        add     eax,int_ONE/2
        adc     edx,0
		shrd	eax,edx,int_SHIFT;
	}
}

inline  short   mult(short a,short b)
{
	__asm {
        movsx   eax,a;
        movsx   ebx,b;
        imul    eax,ebx;
        add     eax,int_ONE/2
        sar     eax,int_SHIFT;
	}
}

inline  long    multD(long a,long b)
{
	__asm {
		mov		eax,a;
		imul	b;
        add     eax,long_ONE/2
        adc     edx,0
        shrd    eax,edx,long_SHIFT;
	}
}

inline  long    mult(long a,long b,int s)
{
	__asm {
		mov		eax,a;
		imul	b;
        mov     ecx,s
        mov     ebx,1
        shl     ebx,cl
        shr     ebx,1
        add     eax,ebx
        adc     edx,0
        shrd    eax,edx,cl;
	}
}

inline  long    mult(int a,int b,int s)
{
	__asm {
		mov		eax,a;
		imul	b;
        mov     ecx,s
        mov     ebx,1
        shl     ebx,cl
        shr     ebx,1
        add     eax,ebx
        adc     edx,0
        shrd    eax,edx,cl;
	}
}


inline  long    mult(int a,long b)
{
	__asm {
		mov		eax,a;
		imul	b;
        add     eax,int_ONE/2
        adc     edx,0
		shrd	eax,edx,int_SHIFT;
	}
}

inline  long    mult(int a,short b)
{
	__asm {
        movsx   eax,b;
        imul    a;
        add     eax,int_ONE/2
        adc     edx,0
		shrd	eax,edx,int_SHIFT;
	}
}
#endif


inline  long    mult_div(long a,long b,long c)
{
	__asm {
		mov		eax,a;
		imul	b;
		mov		ebx, c;
        idiv    ebx;
	}
}
inline  long    divd(long a,long b)
{
	__asm {
		mov		eax,a;
		cdq
        shld    edx,eax,int_SHIFT;
        shl     eax,int_SHIFT;
		mov		ebx, b;
        idiv    ebx;
	}
}

inline  int     divd(int a,int b)
{
	__asm {
		mov		eax,a;
        cdq
        shld    edx,eax,int_SHIFT;
        shl     eax,int_SHIFT;
		mov		ebx, b;
        idiv    ebx;
	}
}

inline  short   divd(short a,short b)
{
	__asm {
        movsx   eax,a;
        cdq
        shld    edx,eax,int_SHIFT;
        shl     eax,int_SHIFT;
        movsx   ebx,b;
        idiv    ebx;
	}
}

inline  long    divdD(long a,long b)
{
	__asm {
		mov		eax,a;
        cdq
        shld    edx,eax,long_SHIFT;
        shl     eax,long_SHIFT;
		mov		ebx, b;
        idiv    ebx;
	}
}

inline  long    divd(long a,long b,int s)
{
	__asm {
		mov		eax,a;
        cdq
        mov     ecx,s;
        shld    edx,eax,cl;
        shl     eax,cl
		mov		ebx, b;
        idiv    ebx;
	}
}


#pragma warning(default:4035)
#endif


//int   length  (short,short,short);
//int   length  (short,short);

inline  int     length  (int  _x,int  _y)           { return int(leng2l(_x,_y));}
inline  long    length  (long _x,long _y)           { return leng2l(_x,_y);}

inline  int     length  (int  _x,int  _y,int  _z)   { return int(leng3l(_x,_y,_z));}
inline  long    length  (long _x,long _y,long _z)   { return leng3l(_x,_y,_z);}


#define grad_a(a)                       int(a*45.511111111111111111)
#define grad_b(a)                       ((a*45)/2048)
#define iatan2_2PI(a,b)                 (int_mask_2_PI & iatan2(a,b))

#define IGrad_(a)                       int(double(a)*double(int_PI)/180.0)
#define GradI_(a)                       (double(a)*180.0/double(int_PI))
#define IRad_(a)                        int(double(a)*double(int_PI)/MathPI)
#define RadI_(a)                        (double(a)*MathPI/double(int_PI))
#define IFloat_(a)                      int(double(a)*double(int_ONE))
#define FloatI_(a)                      (double(a)/double(int_ONE))


#define ireal_(a)                       int(double(a)*double(int_ONE))

inline   int    i_float (float a)       { return int(int_ONE*a); }
inline   float  float_i (int a)         { return ((float)a)/int_ONE; }

/*
inline  int     i_grad  (int a)         { return iimult_div(a,2048,45);}
inline  int     grad_i  (int a)         { return iimult_div(a,45,2048);}
inline  int     i_rad   (int a)         { return int(double(a)*8192.0/My_PI);}
inline  double  rad_i   (int a)         { return double(double(a)*My_PI/8192.0);}
*/

void random_init(long nmb);
long random_abs(long nmb);
long random_sign(long nmb);

#endif
