#pragma once

#include <math.h>
#include <wtypes.h>
#include "d3dx9math.h"

#define FP_ONE_BITS 0x3F800000
#define FP_BITS(fp) (*(DWORD *)&(fp))

// r = 1/p
#define FP_INV(r,p)                                                          \
{                                                                            \
    int _i = 2 * FP_ONE_BITS - *(int *)&(p);                                 \
    r = *(float *)&_i;                                                       \
    r = r * (2.0f - (p) * r);                                                \
}

#define FP_EXP(e,p)                                                          \
{                                                                            \
    int _i;                                                                  \
    e = -1.44269504f * (float)0x00800000 * (p);                              \
    _i = (int)e + 0x3F800000;                                                \
    e = *(float *)&_i;                                                       \
}

extern unsigned int fast_sqrt_table[0x10000];  // declare table of square roots 

typedef union FastSqrtUnion
{
  float f;
  unsigned int i;
} FastSqrtUnion;

inline float fastsqrt(float n)
{
  
  if (FP_BITS(n) == 0)
    return 0.0;                 // check for square root of 0
  
  FP_BITS(n) = fast_sqrt_table[(FP_BITS(n) >> 8) & 0xFFFF] | ((((FP_BITS(n) - 0x3F800000) >> 1) + 0x3F800000) & 0x7F800000);
  
  return n;
}

extern void build_sqrt_table(void);

inline float rsqrtSSE(float f)
{
    __asm
    {
        rsqrtss xmm0, f
        movss f, xmm0
    }
    return f;
}


// At the assembly level the recommended workaround for the second FIST bug is the same for the first; 
// inserting the FRNDINT instruction immediately preceding the FIST instruction. 

__forceinline void FloatToInt(int *int_pointer, float f) 
{
	__asm  fld  f
  __asm  mov  edx,int_pointer
  __asm  FRNDINT
  __asm  fistp dword ptr [edx];

}

extern float g_sint[4096];
extern float g_cost[4096];

extern void build_sin_table(void);

inline float fastsin(float a)
{
	return g_sint[((int)(a*651.8986469f))&0xfff];
}

inline float fastcos(float a)
{
	return g_cost[((int)(a*651.8986469f))&0xfff];
}