#ifndef V_MATH_H
#define V_MATH_H

/*
 * Oldest LibV file
 */

/*
 *  ======================================================================
 *      Symbolic constants
 *  ======================================================================
 */
#ifdef  M_PI
#undef  M_PI
#endif
#define M_PI                            VEC(3.14159265358979323846264338328)
#ifdef  M_2PI
#undef  M_2PI
#endif
#define M_2PI                           VEC(6.28318530717958647692528676656)
#define M_PI2                           VEC(1.57079632679489661923132169164)
#define M_PI3                           VEC(1.04719755119659774615421446109)
#define M_PI4                           VEC(.785398163397448309615660845820)
#define M_PI6                           VEC(.523598775598298873077107230548)
/*  Angles in radians; after underscore - angle in degrees              */
#define ANGLE_0                         VEC(0.0)
#define ANGLE_1                         VEC(.0174532925199432957692369076849)
#define ANGLE_5                         VEC(.0872664625997164788461845384245)
#define ANGLE_10                        VEC(.174532925199432957692369076849)
#define ANGLE_15                        VEC(.261799387799149436538553615273)
#define ANGLE_20                        VEC(.349065850398865915384738153697)
#define ANGLE_30                        M_PI6
#define ANGLE_45                        M_PI4
#define ANGLE_60                        M_PI3
#define ANGLE_72                        VEC(1.25663706143591729538505735331)
#define ANGLE_90                        M_PI2
#define ANGLE_120                       VEC(2.09439510239319549230842892219)
#define ANGLE_135                       VEC(2.35619449019234492884698253746)
#define ANGLE_144                       VEC(2.51327412287183459077011470662)
#define ANGLE_180                       M_PI
#define ANGLE_225                       VEC(3.92699081698724154807830422910)
#define ANGLE_270                       VEC(4.71238898038468985769396507492)
#define ANGLE_315                       VEC(5.49778714378213816730962592074)
#define ANGLE_360                       M_2PI
/*  Radians in degrees - miltiplier to converse from deg. to rad.       */
#define RAD_IN_ANGLE                    ANGLE_TO_RAD
#define ANGLE_TO_RAD                    ANGLE_1
/*  Degrees in radians - miltiplier to converse from rad. to deg.       */
#define ANGLE_IN_RAD                    RAD_TO_ANGLE
#define RAD_TO_ANGLE                    VEC(57.2957795130823208767981548141)

/*  Reference to pitch angle (first component of vector)                */
#define PITCH                           0
/*  Reference to yaw angle (second component of vector)                 */
#define YAW                             1
/*  Reference to roll angle (third component of vector)                 */
#define ROLL                            2

/*
 *  ======================================================================
 *  Miscellaneous macros
 *  ======================================================================
 */

/*      Typecast to vec_t                                               */
#define VEC(v)                          ((vec_t)(v))
/*      Conversions between degrees and radians                         */
#define ToRadians(a)                    ((a)*RAD_IN_ANGLE)
#define ToDegrees(a)                    ((a)*ANGLE_IN_RAD)

/*
 *  Clamps float to range (0 ... 255)
 */
#define CLAMP_FLOAT_TO_BYTE(f) \
		(u8_t)(((f) < 0) ? 0 : (((f) > 255) ? 255 : f))

/*
 *      NOTE.
 *      Configuration macro MATH_NO_MACRO controls code generation. 
 *      If it set in application, it must also be set before
 *      compiling libv source tree.
 */

/*
 *  These function are present only if MATH_NO_MACRO was defined at complilation.
 */

#ifdef  MATH_NO_MACRO

#ifdef  __cplusplus
extern  "C" {
#endif  /* __cplusplus */
	vboolean V_GLOBAL   IsEqualEpsilon(vec_t v1,vec_t v2,vec_t epsilon);

	void    V_GLOBAL    vec2Set(vec2_t v,vec_t x,vec_t y);
	void    V_GLOBAL    vec3Set(vec3_t v,vec_t x,vec_t y,vec_t z);
	void    V_GLOBAL    vec4Set(vec4_t v,vec_t x,vec_t y,vec_t z,vec_t w);
	void    V_GLOBAL    vec2Zero(vec2_t v);
	void    V_GLOBAL    vec3Zero(vec3_t v);
	void    V_GLOBAL    vec4Zero(vec4_t v);
	void    V_GLOBAL    vec2Copy(vec2_t dst,vec2_t src);
	void    V_GLOBAL    vec3Copy(vec3_t dst,vec3_t src);
	void    V_GLOBAL    vec4Copy(vec4_t dst,vec4_t src);
	void    V_GLOBAL    vec2Add(vec2_t dst,vec2_t v1,vec2_t v2);
	void    V_GLOBAL    vec3Add(vec3_t dst,vec3_t v1,vec3_t v2);
	void    V_GLOBAL    vec4Add(vec4_t dst,vec4_t v1,vec4_t v2);
	void    V_GLOBAL    vec2Sub(vec2_t dst,vec2_t v1,vec2_t v2);
	void    V_GLOBAL    vec3Sub(vec3_t dst,vec3_t v1,vec3_t v2);
	void    V_GLOBAL    vec4Sub(vec4_t dst,vec4_t v1,vec4_t v2);
	void    V_GLOBAL    vec2Scale(vec2_t dst,vec2_t vec,vec_t ml);
	void    V_GLOBAL    vec3Scale(vec3_t dst,vec3_t vec,vec_t ml);
	void    V_GLOBAL    vec4Scale(vec4_t dst,vec4_t vec,vec_t ml);
	void    V_GLOBAL    vec2Negate(vec2_t dst,vec2_t src);
	void    V_GLOBAL    vec3Negate(vec3_t dst,vec3_t src);
	void    V_GLOBAL    vec4Negate(vec4_t dst,vec4_t src);
	vec_t   V_GLOBAL    vec2Dot(vec2_t v1,vec2_t v2);
	vec_t   V_GLOBAL    vec3Dot(vec3_t v1,vec3_t v2);
	vec_t   V_GLOBAL    vec4Dot(vec4_t v1,vec4_t v2);
	vec_t   V_GLOBAL    vec2Abs(vec2_t vec);
	vec_t   V_GLOBAL    vec3Abs(vec3_t vec);
	vec_t   V_GLOBAL    vec4Abs(vec4_t vec);
	void    V_GLOBAL    vec2Unit(vec2_t dst,vec2_t src);
	void    V_GLOBAL    vec3Unit(vec3_t dst,vec3_t src);
	void    V_GLOBAL    vec4Homogenize(vec4_t dst,vec4_t src);
	vec_t   V_GLOBAL    vec2Cross(vec2_t v1,vec2_t v2);
	void    V_GLOBAL    vec3Cross(vec3_t dst,vec3_t v1,vec3_t v2);
	int     V_GLOBAL    vec2MinAbsInd(vec2_t vec);
	int     V_GLOBAL    vec2MaxAbsInd(vec2_t vec);
	vboolean    V_GLOBAL    IsZero(vec_t v);
	vboolean    V_GLOBAL    vec2IsZero(vec2_t vec);
	vboolean    V_GLOBAL    vec3IsZero(vec3_t vec);
	vboolean    V_GLOBAL    vec4IsZero(vec4_t vec);
	vboolean    V_GLOBAL    vec2IsEqual(vec2_t v1,vec2_t v2);
	vboolean    V_GLOBAL    vec3IsEqual(vec3_t v1,vec3_t v2);
	vboolean    V_GLOBAL    vec3IsEqualEpsilon(vec3_t a, vec3_t b, vec_t epsilon);
	vboolean    V_GLOBAL    vec4IsEqual(vec4_t v1,vec4_t v2);
	void    V_GLOBAL    vec2VecScale(vec2_t dst,vec2_t v1,vec2_t v2);
	void    V_GLOBAL    vec3VecScale(vec3_t dst,vec3_t v1,vec3_t v2);
	void    V_GLOBAL    vec4VecScale(vec4_t dst,vec4_t v1,vec4_t v2);
	void    V_GLOBAL    vec2ZoomIF(vec2_t zoom, vec2_t initial, vec2_t final);
	void    V_GLOBAL    vec3ZoomIF(vec3_t zoom, vec3_t initial, vec3_t final);
	void    V_GLOBAL    vec4ZoomIF(vec4_t zoom, vec4_t initial, vec4_t final);
	void    V_GLOBAL    vec2ToRadians(vec2_t dst,vec2_t src);
	void    V_GLOBAL    vec3ToRadians(vec3_t dst,vec3_t src);
	void    V_GLOBAL    vec4ToRadians(vec4_t dst,vec4_t src);
	void    V_GLOBAL    vec2ToDegrees(vec2_t dst,vec2_t src);
	void    V_GLOBAL    vec3ToDegrees(vec3_t dst,vec3_t src);
	void    V_GLOBAL    vec4ToDegrees(vec4_t dst,vec4_t src);
	void    V_GLOBAL    mat2Zero(matrix2_t mat);
	void    V_GLOBAL    mat3Zero(matrix3_t mat);
	void    V_GLOBAL    mat4Zero(matrix4_t mat);
	void    V_GLOBAL    mat3x4Zero(matrix3x4_t mat);
	void    V_GLOBAL    mat2Copy(matrix2_t dst,matrix2_t src);
	void    V_GLOBAL    mat3Copy(matrix3_t dst,matrix3_t src);
	void    V_GLOBAL    mat4Copy(matrix4_t dst,matrix4_t src);
	void    V_GLOBAL    mat3x4Copy(matrix3x4_t dst,matrix3x4_t src);
	void    V_GLOBAL    mat2Unit(matrix2_t mat);
	void    V_GLOBAL    mat3Unit(matrix3_t mat);
	void    V_GLOBAL    mat4Unit(matrix4_t mat);
	void    V_GLOBAL    mat3x4Unit(matrix3x4_t mat);
	void    V_GLOBAL    mat4SetLU(matrix4_t dst,matrix3_t LU);
	void    V_GLOBAL    mat3GetLU(matrix3_t LU,matrix4_t src);
	void    V_GLOBAL    mat3SetRows(matrix3_t mat,vec3_t v1,vec3_t v2,
								vec3_t v3);
	void    V_GLOBAL    mat3SetCols(matrix3_t mat,vec3_t v1,vec3_t v2,
								vec3_t v3);
	void    V_GLOBAL    mat3x4SetRows(matrix3x4_t mat,vec3_t v1,vec3_t v2,
								  vec3_t v3);
	void    V_GLOBAL    mat3x4SetCols(matrix3x4_t mat,vec3_t v1,vec3_t v2,
								  vec3_t v3,vec3_t v4);
	void    V_GLOBAL    mat2Transpose(matrix2_t dst,matrix2_t src);
	void    V_GLOBAL    mat2TransposeIP(matrix2_t mat);
	void    V_GLOBAL    mat2VecMul(vec2_t dst,matrix2_t mat,vec2_t v);
	void    V_GLOBAL    mat3VecMul(vec3_t dst,matrix3_t mat,vec3_t v);
	void    V_GLOBAL    mat4VecMul(vec4_t dst,matrix4_t mat,vec4_t v);
	void    V_GLOBAL    mat3x4VecMul(vec3_t dst,matrix3x4_t mat,vec3_t v);
	void    V_GLOBAL    mat2MatMul(matrix2_t dst,matrix2_t m1,matrix2_t m2);
	void    V_GLOBAL    mat3x4ConcatBefore(matrix3x4_t dst,
										matrix3x4_t transform);
	void    V_GLOBAL    mat3x4ConcatAfter(matrix3x4_t dst,
										matrix3x4_t transform);
	void    V_GLOBAL    rgbFromByte(vec3_t rgb,color3b_t brgb);
	void    V_GLOBAL    rgbaFromByte(vec4_t rgba,color4b_t brgba);
	void    V_GLOBAL    rgbaByteCopy(color4b_t dest,color4b_t src);
	void    V_GLOBAL    rgbByteFromFloat(color3b_t brgb,vec3_t rgb);
	void    V_GLOBAL    rgbaByteFromFloat(color4b_t brgba,vec4_t rgba);
#ifdef  __cplusplus
}
#endif      /* __cplusplus */

#else       /* MATH_NO_MACRO not defined */
/*
 *  Include macros for linear algebra ops.
 */
#include    "v_imath.h"
#endif      /* MATH_NO_MACRO */

#ifdef  __cplusplus
extern  "C" {
#endif      /* __cplusplus */
	vec_t   V_GLOBAL    vec3Triple(vec3_t v1, vec3_t v2, vec3_t v3);
	int     V_GLOBAL    vec3MinInd(vec3_t vec);
	int     V_GLOBAL    vec4MinInd(vec4_t vec);
	int     V_GLOBAL    vec3MaxInd(vec3_t vec);
	int     V_GLOBAL    vec4MaxInd(vec4_t vec);
	int     V_GLOBAL    vec3MinAbsInd(vec3_t vec);
	int     V_GLOBAL    vec4MinAbsInd(vec4_t vec);
	int     V_GLOBAL    vec3MaxAbsInd(vec3_t vec);
	int     V_GLOBAL    vec4MaxAbsInd(vec4_t vec);
	void    V_GLOBAL    mat3Transpose(matrix3_t dst,matrix3_t src);
	void    V_GLOBAL    mat4Transpose(matrix4_t dst,matrix4_t src);
	void    V_GLOBAL    mat3TransposeIP(matrix3_t mat);
	void    V_GLOBAL    mat4TransposeIP(matrix4_t mat);
	void    V_GLOBAL    mat3MatMul(matrix3_t dst,matrix3_t m1,matrix3_t m2);
	void    V_GLOBAL    mat4MatMul(matrix4_t dst,matrix4_t m1,matrix4_t m2);
	void    V_GLOBAL    mat3x4MatMul(matrix3x4_t dst,matrix3x4_t m1,matrix3x4_t m2);
	void    V_GLOBAL    vec3TransformVectors(vec3_t vecs[],matrix3x4_t mat,int n);
	void    V_GLOBAL    mat2Solve(matrix2_t a,vec2_t b);
	void    V_GLOBAL    mat2Solve2v(vec2_t r1,vec2_t r2,vec2_t b);
	void    V_GLOBAL    mat2Solve4s(vec_t a00,vec_t a01,vec_t a10,
									vec_t a11,vec2_t b);
	vboolean V_GLOBAL	mat3Solve(matrix3_t a,vec3_t b);
	void    V_GLOBAL    mat4Solve(matrix4_t a,vec4_t b);
	/* hue is in range [0..1) */
	void    V_GLOBAL    hsvFromRgb(vec3_t hsv,vec3_t rgb);
	void	V_GLOBAL	hsvFromRgbEx(vec3_t hsv,vec3_t rgb,vboolean *h_valid);
	void    V_GLOBAL    rgbFromHsv(vec3_t rgb,vec3_t hsv);
#ifdef  __cplusplus
}
#endif      /* __cplusplus */

#endif      /* V_MATH_H */
