// Copyright (C) 2004-2009 Christoph Kubisch & Eike Decker
// This file is part of the "Luxinia Engine".
// For conditions of distribution and use, see copyright notice in luxiniapublicsdk.txt
//
// <Author: Christoph Kubisch>


#ifndef __LUXMATH_TYPES_H__
#define __LUXMATH_TYPES_H__

//////////////////////////////////////////////////////////////////////////

#include <luxplatform/luxplatform.h>

#ifdef __cplusplus
extern "C"{
#endif

#include <math.h>
#include <float.h>
#include <string.h>

	//////////////////////////////////////////////////////////////////////////

	typedef float lxVector2[2];
	typedef float lxVector3[3];
	typedef float lxVector4[4];
	typedef float lxPlane[4];
	typedef float lxMatrix44[16];
	typedef float lxMatrix34[12];
	typedef float lxQuat[4];


	typedef LUX_ALIGNSIMD_S lxMatrix44 lxMatrix44SIMD;
	typedef LUX_ALIGNSIMD_S lxVector4 lxVector4SIMD;
#ifdef LUX_SIMD
	typedef LUX_ALIGNSIMD_S lxVector4 lxVector3SIMD;
#else
	typedef lxVector3 lxVector3SIMD;
#endif

	typedef float*	LUX_RESTRICT lxVector2p;
	typedef float*	LUX_RESTRICT lxVector3p;
	typedef float*	LUX_RESTRICT lxVector4p;
	typedef float*	LUX_RESTRICT lxPlanep;
	typedef float*	LUX_RESTRICT lxMatrix44p;
	typedef float*	LUX_RESTRICT lxMatrix34p;
	typedef float*	LUX_RESTRICT lxQuatp;


	//////////////////////////////////////////////////////////////////////////

	typedef enum lxFrustumPlaneType_e{
		FRUSTUM_TOP,
		FRUSTUM_BOTTOM,
		FRUSTUM_NEAR,
		FRUSTUM_FAR,
		FRUSTUM_LEFT,
		FRUSTUM_RIGHT,

		FRUSTUM_PLANES,
	}lxFrustumPlaneType_t;

	typedef enum lxFrustumCornerType_e{
		FRUSTUM_C_NTR,
		FRUSTUM_C_NTL,
		FRUSTUM_C_NBL,
		FRUSTUM_C_NBR,

		FRUSTUM_C_FTR,
		FRUSTUM_C_FTL,
		FRUSTUM_C_FBL,
		FRUSTUM_C_FBR,

		FRUSTUM_CORNERS,
	}lxFrustumCornerType_t;

	typedef enum lxCullType_e{
		CULL_INTERSECT = -1,
		CULL_OUTSIDE = 0,
		CULL_INSIDE = 1,
	}lxCullType_t;

	typedef struct lxRectInt_s{
		union{
			struct{
				int		x;
				int		y;
				int		width;
				int		height;
			};
			int			sizes[4];
		};
	}lxRectInt_t;

	typedef struct VecInt2_s{
		int		x;
		int		y;
	}lxVecInt2_t;

	typedef struct lxVecInt3_s{
		int		x;
		int		y;
		int		z;
	}lxVecInt3_t;

	typedef struct lxVecFloat3_s{
		float		x;
		float		y;
		float		z;
	}lxVecFloat3_t;

	typedef struct lxVecFloat4_s{
		float		x;
		float		y;
		float		z;
		float		w;
	}lxVecFloat4_t;

	typedef struct lxFrustumPlane_s{
		lxPlane			pvec;
		union{
			int			n[3];
			struct{
				int		nx;
				int		ny;
				int		nz;
			};
		};
		union{
			int			p[3];
			struct{
				int		px;
				int		py;
				int		pz;
			};
		};
	}lxFrustumPlane_t;

	typedef struct lxFrustum_s
	{
		lxFrustumPlane_t	fplanes[FRUSTUM_PLANES];
	}lxFrustum_t;


	typedef struct lxBoundingBox_s
	{
		lxVector3 min;
		lxVector3 max;
		lxVector3 center;
		lxVector3 length;
	}lxBoundingBox_t;

	typedef struct lxBoundingSphere_s
	{
		lxVector3 center;
		float	radius;
		float	radiusSqr;
	}lxBoundingSphere_t;

	typedef struct lxBoundingCone_s
	{
		lxVector3	top;
		lxVector3	axis;
		float	sinDiv;
		float	sinSqr;
		float	cosSqr;
	}lxBoundingCone_t;

	typedef struct lxBoundingCapsule_s
	{
		lxVector3	origin;
		lxVector3	toEnd;		// end-origin, non normalized
		float	radius;
		float	radiusSqr;
	}lxBoundingCapsule_t;

	//////////////////////////////////////////////////////////////////////////


#define LX_CLAMP(a,min,max)	(((a) < (min)) ? (min) : ( ((a) > (max)) ? (max) : (a) ))
#define LX_LERP(t,a,b)			((a) + (((b)-(a))*(t)))
#define LX_BARYCENTRIC(u,v,w,p0,p1,p2)	((u)*(p0) + (v)*(p1) + (w)*(p2))

	// makes a void data value from the float
	LUX_INLINE void* float2void(float f) {
		return (void*)*(size_t*)((void*)&f);
	}
	// makes a float from a data value
	LUX_INLINE float void2float(void *f) {
		return *(float*)&f;
	}

#define DIV_255			(0.003921568627451f)
#define FLOAT_EPSILON	(1.192092896e-07F)

#ifndef MUL_PI
#define MUL_PI		(3.1415926535897932384626433832795f)
#endif
#ifndef MUL_HALF_PI
#define MUL_HALF_PI (1.5707963267948966192313216916395f)
#endif
#ifndef DIV_PI
#define DIV_PI		(0.31830988618379067153776752674503f)
#endif

#define MUL_TWOPI (6.283185307179586476925286766559f)
#define DEG2RAD( a ) (( (a) * MUL_PI   ) * 0.005555555555555555555555555555555f)
#define RAD2DEG( a ) (( (a) * 180.0f ) * DIV_PI )
#define SQRT_2 (1.4142135623730950488016887242097f)
#define SQRT_3 (1.7320508075688772935274463415059f)

#define SHORT_SIGNEDMAX		(32767)
#define SHORT_UNSIGNEDMAX	(0xffff)

#define M_SHORT		(32767.0f)
#define DIV_SHORT	(3.0518509475997192297128208258309e-5f)

#define M_USHORT	(65535.0f)
#define DIV_USHORT	(1.5259021896696421759365224689097e-5f)

#ifdef __cplusplus
}
#endif


#ifdef __cplusplus
class lxCVector4;

class lxCVector3 {
public:
	float	x;
	float	y;
	float	z;

	lxCVector3() {};
	lxCVector3(float all) : x(all),y(all),z(all) {};
	lxCVector3(float x, float y, float z) : x(x),y(y),z(z) {};
	lxCVector3(int x, int y, int z) : x(float(x)),y(float(y)),z(float(z)) {};
	lxCVector3(uint x, uint y, uint z) : x(float(x)),y(float(y)),z(float(z)) {};
	lxCVector3(double x, double y, double z) : x(float(x)),y(float(y)),z(float(z)) {};

	LUX_INLINE operator float* () {
		return &x;
	}
	LUX_INLINE operator const float* () const {
		return &x;
	}
	LUX_INLINE operator lxCVector4 ();

	LUX_INLINE void Set(float nx, float ny, float nz){
		x = nx;
		y = ny;
		z = nz;
	}

	LUX_INLINE float& operator[](int element) {
		LUX_ASSUME(element >= 0 && element < 3);
		return (&x)[element];
	}

	LUX_INLINE const float& operator[](int element) const {
		LUX_ASSUME(element >= 0 && element < 3);
		return (&x)[element];
	}
};


class lxCVector4 {
public:
	float	x;
	float	y;
	float	z;
	float	w;

	lxCVector4() {};
	lxCVector4(float all) : x(all),y(all),z(all),w(all) {};
	lxCVector4(float x, float y, float z) : x(x),y(y),z(z),w(1.0f) {};
	lxCVector4(float x, float y, float z, float w) : x(x),y(y),z(z),w(w) {};
	lxCVector4(uint x, uint y, uint z, uint w) : x(float(x)),y(float(y)),z(float(z)),w(float(w)) {};
	lxCVector4(double x, double y, double z, double w) : x(float(x)),y(float(y)),z(float(z)),w(float(w)) {};

	LUX_INLINE operator float* () {
		return &x;
	}
	LUX_INLINE operator const float* () const {
		return &x;
	}
	LUX_INLINE operator lxCVector3 () {
		return lxCVector3(x,y,z);
	}
	LUX_INLINE void Set(float nx, float ny, float nz){
		x = x;
		y = y;
		z = z;
		w = 1.0f;
	}
	LUX_INLINE void Set(float nx, float ny, float nz, float nw){
		x = nx;
		y = ny;
		z = nz;
		w = nw;
	}
	LUX_INLINE float& operator[](int element) {
		LUX_ASSUME(element >= 0 && element < 4);
		return (&x)[element];
	}

	LUX_INLINE const float& operator[](int element) const {
		LUX_ASSUME(element >= 0 && element < 4);
		return (&x)[element];
	}
};

LUX_INLINE lxCVector3::operator lxCVector4 () {
	return lxCVector4(x,y,z,1.0f);
}

typedef lxCVector4 CQuat;

class lxCMatrix44 {
public:
	lxCVector4	columns[4];

	LUX_INLINE operator float* () {
		return &columns[0].x;
	}
	LUX_INLINE operator const float* () const {
		return &columns[0].x;
	}
	LUX_INLINE float& operator[](int element) {
		LUX_ASSUME(element >= 0 && element < 16);
		return (&columns[0].x)[element];
	}
	LUX_INLINE const float& operator[](int element) const {
		LUX_ASSUME(element >= 0 && element < 16);
		return (&columns[0].x)[element];
	}

	lxCMatrix44() {}
	lxCMatrix44(int one) 
	{
		columns[0].Set(1.0f,0.0f,0.0f,0.0f);
		columns[1].Set(0.0f,1.0f,0.0f,0.0f);
		columns[2].Set(0.0f,0.0f,1.0f,0.0f);
		columns[3].Set(0.0f,0.0f,0.0f,1.0f);
	}

#ifdef LUX_SIMD_SSE
	lxCMatrix44(__m128 *ptr) {
		columns[0].x = ptr[0].m128_f32[0];
		columns[0].y = ptr[0].m128_f32[1];
		columns[0].z = ptr[0].m128_f32[2];
		columns[0].w = ptr[0].m128_f32[3];

		columns[1].x = ptr[1].m128_f32[0];
		columns[1].y = ptr[1].m128_f32[1];
		columns[1].z = ptr[1].m128_f32[2];
		columns[1].w = ptr[1].m128_f32[3];

		columns[2].x = ptr[2].m128_f32[0];
		columns[2].y = ptr[2].m128_f32[1];
		columns[2].z = ptr[2].m128_f32[2];
		columns[2].w = ptr[2].m128_f32[3];

		columns[3].x = ptr[3].m128_f32[0];
		columns[3].y = ptr[3].m128_f32[1];
		columns[3].z = ptr[3].m128_f32[2];
		columns[3].w = ptr[3].m128_f32[3];
	}
#endif
};


typedef LUX_ALIGNSIMD_S lxCMatrix44 lxCMatrix44SIMD;
typedef LUX_ALIGNSIMD_S lxCVector3 lxCVector3SIMD;
typedef LUX_ALIGNSIMD_S lxCVector4 lxCVector4SIMD;


#endif

#endif