#include <../source/TAL/objbase.h>

#ifdef	MATH_NO_MACRO

vboolean V_GLOBAL	IsEqualEpsilon(vec_t v1,vec_t v2,vec_t epsilon)
{
	return (v_abs(v1-v2) < epsilon) ? true : false;
}

/*		Assignment	*/
void	V_GLOBAL	vec2Set(vec2_t v,vec_t x,vec_t y)
{
	v[0]=x;
	v[1]=y;
}

void	V_GLOBAL	vec3Set(vec3_t v,vec_t x,vec_t y,vec_t z)
{
	v[0]=x;
	v[1]=y;
	v[2]=z;
}

void	V_GLOBAL	vec4Set(vec4_t v,vec_t x,vec_t y,vec_t z,vec_t w)
{
	v[0]=x;
	v[1]=y;
	v[2]=z;
	v[3]=w;
}

/*		Setting to zero	*/
void	V_GLOBAL	vec2Zero(vec2_t	v)
{
	v[0]=v[1]=0;
}

void	V_GLOBAL	vec3Zero(vec3_t	v)
{
	v[0]=v[1]=v[2]=0;
}

void	V_GLOBAL	vec4Zero(vec4_t	v)
{
	v[0]=v[1]=v[2]=v[3]=0;
}

/*		Copying	*/
void	V_GLOBAL	vec2Copy(vec2_t dst,vec2_t src)
{
	dst[0]=src[0];
	dst[1]=src[1];
}

void	V_GLOBAL	vec3Copy(vec3_t dst,vec3_t src)
{
	dst[0]=src[0];
	dst[1]=src[1];
	dst[2]=src[2];
}

void	V_GLOBAL	vec4Copy(vec4_t dst,vec4_t src)
{
	dst[0]=src[0];
	dst[1]=src[1];
	dst[2]=src[2];
	dst[3]=src[3];
}

/*		Addition	*/
void	V_GLOBAL	vec2Add(vec2_t dst,vec2_t v1,vec2_t	v2)
{
	dst[0]=v1[0]+v2[0];
	dst[1]=v1[1]+v2[1];
}

void	V_GLOBAL	vec3Add(vec3_t dst,vec3_t v1,vec3_t	v2)
{
	dst[0]=v1[0]+v2[0];
	dst[1]=v1[1]+v2[1];
	dst[2]=v1[2]+v2[2];
}

void	V_GLOBAL	vec4Add(vec4_t dst,vec4_t v1,vec4_t	v2)
{
	dst[0]=v1[0]+v2[0];
	dst[1]=v1[1]+v2[1];
	dst[2]=v1[2]+v2[2];
	dst[3]=v1[3]+v2[3];
}

/*		Subtraction	*/
void	V_GLOBAL	vec2Sub(vec2_t dst,vec2_t v1,vec2_t	v2)
{
	dst[0]=v1[0]-v2[0];
	dst[1]=v1[1]-v2[1];
}

void	V_GLOBAL	vec3Sub(vec3_t dst,vec3_t v1,vec3_t	v2)
{
	dst[0]=v1[0]-v2[0];
	dst[1]=v1[1]-v2[1];
	dst[2]=v1[2]-v2[2];
}

void	V_GLOBAL	vec4Sub(vec4_t dst,vec4_t v1,vec4_t	v2)
{
	dst[0]=v1[0]-v2[0];
	dst[1]=v1[1]-v2[1];
	dst[2]=v1[2]-v2[2];
	dst[3]=v1[3]-v2[3];
}

/*		Multiplication by scalar	*/
void	V_GLOBAL	vec2Scale(vec2_t dst,vec2_t	vec,vec_t ml)
{
	dst[0]=vec[0]*ml;
	dst[1]=vec[1]*ml;
}

void	V_GLOBAL	vec3Scale(vec3_t dst,vec3_t	vec,vec_t ml)
{
	dst[0]=vec[0]*ml;
	dst[1]=vec[1]*ml;
	dst[2]=vec[2]*ml;
}

void	V_GLOBAL	vec4Scale(vec4_t dst,vec4_t	vec,vec_t ml)
{
	dst[0]=vec[0]*ml;
	dst[1]=vec[1]*ml;
	dst[2]=vec[2]*ml;
	dst[3]=vec[3]*ml;
}

/*		Multiplication by -1 not in-place	*/
void	V_GLOBAL	vec2Negate(vec2_t dst,vec2_t src)
{
	dst[0]=-src[0];
	dst[1]=-src[1];
}

void	V_GLOBAL	vec3Negate(vec3_t dst,vec3_t src)
{
	dst[0]=-src[0];
	dst[1]=-src[1];
	dst[2]=-src[2];
}

void	V_GLOBAL	vec4Negate(vec4_t dst,vec4_t src)
{
	dst[0]=-src[0];
	dst[1]=-src[1];
	dst[2]=-src[2];
	dst[3]=-src[3];
}

/*		Dot	products	*/
vec_t	V_GLOBAL	vec2Dot(vec2_t v1,vec2_t v2)
{
	return v1[0]*v2[0]+v1[1]*v2[1];
}


vec_t	V_GLOBAL	vec3Dot(vec3_t v1,vec3_t v2)
{
	return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
}

vec_t	V_GLOBAL	vec4Dot(vec3_t v1,vec3_t v2)
{
	return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]+v1[3]*v2[3];
}

/*		Vector length */
vec_t	V_GLOBAL	vec2Abs(vec2_t vec)
{
	return (vec_t)sqrt(vec2Dot(vec,vec));
}

vec_t	V_GLOBAL	vec3Abs(vec3_t vec)
{
	return (vec_t)sqrt(vec3Dot(vec,vec));
}

vec_t	V_GLOBAL	vec4Abs(vec4_t vec)
{
	return (vec_t)sqrt(vec4Dot(vec,vec));
}

/*		These functions make unit vectors (not in place) */
void	V_GLOBAL	vec2Unit(vec2_t dst,vec2_t src)
{
	vec_t ra;
	ra=(vec_t)1.0/vec2Abs(src);
	vec2Scale(dst,src,ra);
}

void	V_GLOBAL	vec3Unit(vec3_t dst,vec3_t src)
{
	vec_t ra;
	ra=(vec_t)1.0/vec3Abs(src);
	vec3Scale(dst,src,ra);
}

/*		This function makes homogenize vector */
void	V_GLOBAL	vec4Homogenize(vec4_t dst,vec4_t src)
{
	vec_t rw;
	rw = (vec_t)1.0 / src[3];
	vec3Scale((vec_p)dst,(vec_p)src,rw);
	dst[3] = (vec_t)1.0;
}

/*		Cross product in 2-D space (oriented parallelogram area)		*/
vec_t	V_GLOBAL	vec2Cross(vec2_t v1,vec2_t v2)
{
	return v1[0]*v2[1] - v1[1]*v2[0];
}

/*		Cross product in 3-D space (oriented parallelepiped volume)		*/
void	V_GLOBAL	vec3Cross(vec3_t dst,vec3_t	v1,vec3_t v2)
{
	dst[0]=v1[1]*v2[2]-v1[2]*v2[1];
	dst[1]=v1[2]*v2[0]-v1[0]*v2[2];
	dst[2]=v1[0]*v2[1]-v1[1]*v2[0];
}

/*		These functions return indices of minimal/maximal components	*/
int		V_GLOBAL	vec2MinAbsInd(vec2_t vec)
{
	return (v_abs(vec[0]) < v_abs(vec[1])) ? 0 : 1;
}

int		V_GLOBAL	vec2MaxAbsInd(vec2_t vec)
{
	return (v_abs(vec[0]) > v_abs(vec[1])) ? 0 : 1;
}

/*		This returns true if argument is almost zero					*/
vboolean	V_GLOBAL	IsZero(vec_t v)
{
	return (v_abs(v)<FLOAT_ZERO_EPSILON) ? true :	false;
}

/*		These return true if length of vector is almost zero			*/
vboolean	V_GLOBAL	vec2IsZero(vec2_t vec)
{
	return (vec2Dot(vec,vec)<FLOAT_ZERO_EPSILON_SQUARE) ? true : false;
}
  
vboolean	V_GLOBAL	vec3IsZero(vec3_t vec)
{
	return (vec3Dot(vec,vec)<FLOAT_ZERO_EPSILON_SQUARE)	? true : false;
}
  
vboolean	V_GLOBAL	vec4IsZero(vec4_t vec)
{
	return (vec4Dot(vec,vec)<FLOAT_ZERO_EPSILON_SQUARE)	? true : false;
}

/*		These return true if vectors are almost equal					*/
vboolean	V_GLOBAL	vec2IsEqual(vec2_t v1,vec2_t v2)
{
  return IsZero(v1[0]-v2[0]) && IsZero(v1[1]-v2[1]);
}

vboolean	V_GLOBAL	vec3IsEqual(vec3_t v1,vec3_t v2)
{
  return IsZero(v1[0]-v2[0]) && IsZero(v1[1]-v2[1])	&& IsZero(v1[2]-v2[2]);
}

vboolean	V_GLOBAL	vec4IsEqual(vec4_t v1,vec4_t v2)
{
	return IsZero(v1[0]-v2[0]) && IsZero(v1[1]-v2[1])	&& IsZero(v1[2]-v2[2])
  		&& IsZero(v1[3]-v2[3]);
}

/*		These make 2/3/4 products of components of args				*/
void	V_GLOBAL	vec2VecScale(vec2_t dst,vec2_t v1,vec2_t v2)
{
	dst[0]=v1[0]*v2[0];
	dst[1]=v1[1]*v2[1];
}

void	V_GLOBAL	vec3VecScale(vec3_t dst,vec3_t v1,vec3_t v2)
{
	dst[0]=v1[0]*v2[0];
	dst[1]=v1[1]*v2[1];
	dst[2]=v1[2]*v2[2];
}

void	V_GLOBAL	vec4VecScale(vec4_t dst,vec4_t v1,vec4_t v2)
{
	dst[0]=v1[0]*v2[0];
	dst[1]=v1[1]*v2[1];
	dst[2]=v1[2]*v2[2];
	dst[3]=v1[3]*v2[3];
}

/*		These make 2/3/4 quotiens of components of args. Useful when one
 *	need to construct scale factors by given initial and final sizes.
 */
void	V_GLOBAL	vec2ZoomIF(vec2_t zoom,	vec2_t initial,	vec2_t final)
{
	zoom[0]	= final[0] / initial[0];
	zoom[1]	= final[1] / initial[1];
}

void	V_GLOBAL	vec3ZoomIF(vec3_t zoom,	vec3_t initial,	vec3_t final)
{
	zoom[0]	= final[0] / initial[0];
	zoom[1]	= final[1] / initial[1];
	zoom[2]	= final[2] / initial[2];
}

void	V_GLOBAL	vec4ZoomIF(vec4_t zoom,	vec4_t initial,	vec4_t final)
{
	zoom[0]	= final[0] / initial[0];
	zoom[1]	= final[1] / initial[1];
	zoom[2]	= final[2] / initial[2];
	zoom[3]	= final[3] / initial[3];
}

/*		Conversion from degrees to radians								*/
void	V_GLOBAL	vec2ToRadians(vec2_t dst,vec2_t	src)
{
	vec2Scale(dst,src,ANGLE_TO_RAD);
}

void	V_GLOBAL	vec3ToRadians(vec3_t dst,vec3_t	src)
{
	vec3Scale(dst,src,ANGLE_TO_RAD);
}

void	V_GLOBAL	vec4ToRadians(vec4_t dst,vec4_t	src)
{
	vec4Scale(dst,src,ANGLE_TO_RAD);
}

/*		Conversion from radians to degrees								*/
void	V_GLOBAL	vec2ToDegrees(vec2_t dst,vec2_t	src)
{
	vec2Scale(dst,src,RAD_TO_ANGLE);
}

void	V_GLOBAL	vec3ToDegrees(vec3_t dst,vec3_t	src)
{
	vec3Scale(dst,src,RAD_TO_ANGLE);
}

void	V_GLOBAL	vec4ToDegrees(vec4_t dst,vec4_t	src)
{
	vec4Scale(dst,src,RAD_TO_ANGLE);
}

/*	================================================================
 *	Matrix operations
 *	==============================================================*/

/*		Setting to zero	*/
void	V_GLOBAL	mat2Zero(matrix2_t mat)
{
	memZero32(mat,sizeof(vec_t));
}

void	V_GLOBAL	mat3Zero(matrix3_t mat)
{
	memZero32(mat,(9*sizeof(vec_t))>>2);
}

void	V_GLOBAL	mat4Zero(matrix4_t mat)
{
	memZero32(mat,sizeof(vec_t)<<2);
}

void	V_GLOBAL	mat3x4Zero(matrix3x4_t mat)
{
	memZero32(mat,3*sizeof(vec_t));
}

/*		Copying */
void	V_GLOBAL	mat2Copy(matrix2_t dst,matrix2_t src)
{
	memCopy32(dst,src,sizeof(vec_t));
}

void	V_GLOBAL	mat3Copy(matrix3_t dst,matrix3_t src)
{
	memCopy32((dst),src,9*sizeof(vec_t)>>2);
}

void	V_GLOBAL	mat4Copy(matrix4_t dst,matrix4_t src)
{
	memCopy32(dst,src,sizeof(vec_t)<<2);
}

void	V_GLOBAL	mat3x4Copy(matrix3x4_t dst,matrix3x4_t src)
{
	memCopy32(dst,src,3*sizeof(vec_t));
}

/*		Setting to identity state */
void	V_GLOBAL	mat2Unit(matrix2_t mat)
{
	mat[1][0]=mat[0][1]=0.0;
	mat[0][0]=mat[1][1]=1.0;
}

void	V_GLOBAL	mat3Unit(matrix3_t mat)
{
	mat3Zero(mat);
	mat[0][0]=mat[1][1]=mat[2][2]=1.0;
}

void	V_GLOBAL	mat4Unit(matrix4_t mat)
{
	mat4Zero(mat);
	mat[0][0]=mat[1][1]=mat[2][2]=mat[3][3]=1.0;
}

void	V_GLOBAL	mat3x4Unit(matrix3x4_t mat)
{
	mat3x4Zero(mat);
	mat[0][0]=mat[1][1]=mat[2][2]=1.0;
}

/*		This copies	3󱬭atrix into	LU-corner of 4󲭳x4-matrix	*/
void	V_GLOBAL	mat4SetLU(matrix4_t dst,matrix3_t LU)
{
	dst[0][0]=LU[0][0]; dst[0][1]=LU[0][1]; dst[0][2]=LU[0][2];
	dst[1][0]=LU[1][0]; dst[1][1]=LU[1][1]; dst[1][2]=LU[1][2];
	dst[2][0]=LU[2][0]; dst[2][1]=LU[2][1]; dst[2][2]=LU[2][2];
}

/*		This copies	LU-corner of 4󲭳󲬭atrix	into 3󱬭atrix	*/
void	V_GLOBAL	mat3GetLU(matrix3_t LU,matrix4_t src)
{
	LU[0][0]=src[0][0]; LU[0][1]=src[0][1]; LU[0][2]=src[0][2];
	LU[1][0]=src[1][0]; LU[1][1]=src[1][1]; LU[1][2]=src[1][2];
	LU[2][0]=src[2][0]; LU[2][1]=src[2][1]; LU[2][2]=src[2][2];
}

/*		This inserts three 3-vectors into rows of 3x3-matrix	*/
void	V_GLOBAL	mat3SetRows(matrix3_t mat,vec3_t v1,vec3_t v2,vec3_t v3)
{
	mat[0][0]=v1[0]; mat[0][1]=v1[1]; mat[0][2]=v1[2];
	mat[1][0]=v2[0]; mat[1][1]=v2[1]; mat[1][2]=v2[2];
	mat[2][0]=v3[0]; mat[2][1]=v3[1]; mat[2][2]=v3[2];
}

/*		Inserts	three 3-vectors	into cols of 3x3-matrix	*/
void	V_GLOBAL	mat3SetCols(matrix3_t mat,vec3_t v1,vec3_t v2,vec3_t v3)
{
	mat[0][0]=v1[0]; mat[0][1]=v2[0]; mat[0][2]=v3[0];
	mat[1][0]=v1[1]; mat[1][1]=v2[1]; mat[1][2]=v3[1];
	mat[2][0]=v1[2]; mat[2][1]=v2[2]; mat[2][2]=v3[2];
}

/*		Inserts	three 3-vectors	into rows of 3x4-matrix	*/
void	V_GLOBAL mat3x4SetRows(matrix3x4_t mat,vec3_t v1,vec3_t v2,vec3_t v3)
{
	mat[0][0]=v1[0]; mat[0][1]=v1[1]; mat[0][2]=v1[2]; mat[0][3]=0;
	mat[1][0]=v2[0]; mat[1][1]=v2[1]; mat[1][2]=v2[2]; mat[1][3]=0;
	mat[2][0]=v3[0]; mat[2][1]=v3[1]; mat[2][2]=v3[2]; mat[2][3]=0;
}

/*		Inserts	four 3-vectors into	cols of	3x4-matrix	*/
void	V_GLOBAL mat3x4SetCols(matrix3x4_t mat,vec3_t v1,vec3_t v2,vec3_t v3,
								vec3_t v4)
{
	mat[0][0]=v1[0]; mat[0][1]=v2[0]; mat[0][2]=v3[0]; mat[0][3]=v4[0];
	mat[1][0]=v1[1]; mat[1][1]=v2[1]; mat[1][2]=v3[1]; mat[1][3]=v4[1];
	mat[2][0]=v1[2]; mat[2][1]=v2[2]; mat[2][2]=v3[2]; mat[2][3]=v4[2];
}

/*	  Transposition of matrix2_t not-in-place */
void	V_GLOBAL	mat2Transpose(matrix2_t dst,matrix2_t src)
{
	dst[0][0]=src[0][0];
	dst[0][1]=src[1][0];
	dst[1][0]=src[0][1];
	dst[1][1]=src[1][1];
}

/*		Transposition of matrix2_t in-place */
void	V_GLOBAL	mat2TransposeIP(matrix2_t mat)
{
  vec_t temp;
  temp=mat[0][1];mat[0][1]=mat[1][0];mat[1][0]=temp;
}

/*		Matrix by vector multiplication */
void	V_GLOBAL	mat2VecMul(vec2_t dst,matrix2_t mat,vec2_t v)
{
	dst[0]=mat[0][0]*v[0]+mat[0][1]*v[1];
	dst[1]=mat[1][0]*v[0]+mat[1][1]*v[1];
}

void	V_GLOBAL	mat3VecMul(vec3_t dst,matrix3_t mat,vec3_t v)
{
	dst[0]=mat[0][0]*v[0]+mat[0][1]*v[1]+mat[0][2]*v[2];
	dst[1]=mat[1][0]*v[0]+mat[1][1]*v[1]+mat[1][2]*v[2];
	dst[2]=mat[2][0]*v[0]+mat[2][1]*v[1]+mat[2][2]*v[2];
}

void	V_GLOBAL	mat4VecMul(vec4_t dst,matrix4_t mat,vec4_t v)
{
	dst[0]=mat[0][0]*v[0]+mat[0][1]*v[1]+mat[0][2]*v[2]+mat[0][3]*v[3];
	dst[1]=mat[1][0]*v[0]+mat[1][1]*v[1]+mat[1][2]*v[2]+mat[1][3]*v[3];
	dst[2]=mat[2][0]*v[0]+mat[2][1]*v[1]+mat[2][2]*v[2]+mat[2][3]*v[3];
	dst[3]=mat[3][0]*v[0]+mat[3][1]*v[1]+mat[3][2]*v[2]+mat[3][3]*v[3];
}

/*		Matrix 3x4 by 3 - vector "multiplication". Actualy, there is a
 *	matrix3_t by vec3_t multiplication combined with translation.
 */
void	V_GLOBAL	mat3x4VecMul(vec3_t dst,matrix3x4_t mat,vec3_t v)
{
	dst[0]=mat[0][0]*v[0]+mat[0][1]*v[1]+mat[0][2]*v[2]+mat[0][3];
	dst[1]=mat[1][0]*v[0]+mat[1][1]*v[1]+mat[1][2]*v[2]+mat[1][3];
	dst[2]=mat[2][0]*v[0]+mat[2][1]*v[1]+mat[2][2]*v[2]+mat[2][3];
}

/*		Multiplication of two matrices if 2x2 size */
void	V_GLOBAL	mat2MatMul(matrix2_t dst,matrix2_t m1,matrix2_t	m2)
{
	dst[0][0]=m1[0][0]*m2[0][0]+m1[0][1]*m2[1][0];
	dst[0][1]=m1[0][0]*m2[0][1]+m1[0][1]*m2[1][1];
	dst[1][0]=m1[1][0]*m2[0][0]+m1[1][1]*m2[1][0];
	dst[1][1]=m1[1][0]*m2[0][1]+m1[1][1]*m2[1][1];
}

/*		Left and right concatenation of two transforms */
void	V_GLOBAL	mat3x4ConcatBefore(matrix3x4_t dst,matrix3x4_t transform)
{
	matrix3x4_t tmp;
	mat3x4MatMul(tmp, transform, dst);
	mat3x4Copy(dst, tmp);
}

void	V_GLOBAL	mat3x4ConcatAfter(matrix3x4_t dst,matrix3x4_t transform)
{
	matrix3x4_t tmp;
	mat3x4MatMul(tmp,dst,transform);
	mat3x4Copy(dst, tmp);
}

/*	======================================================================
 *	Color operations
 *	======================================================================
 */

void	V_GLOBAL	rgbFromByte(vec3_t rgb,color3b_t brgb)
{
	rgb[0]=brgb[0];
	rgb[1]=brgb[1];
	rgb[2]=brgb[2];
	vec3Scale(rgb,rgb,(vec_t)(0.00392156862745098 /* 1/255 */ ));
}

void	V_GLOBAL	rgbaFromByte(vec4_t rgba,color3b_t brgba)
{
	rgba[0]=brgba[0];
	rgba[1]=brgba[1];
	rgba[2]=brgba[2];
	rgba[3]=brgba[3];
	vec4Scale(rgba,rgba,(vec_t)(0.00392156862745098 /* 1/255 */ ));
}

void	V_GLOBAL	rgbaByteCopy(color4b_t dest,color4b_t src)
{
	*((u32_t*)dest)=*(u32_t*)src;
}

void	V_GLOBAL	rgbByteFromFloat(color3b_t brgb,vec3_t rgb)
{
	vec3_t scaled;
	vec3Scale(scaled,rgb,255);
	brgb[0]=CLAMP_FLOAT_TO_BYTE(scaled[0]);
	brgb[1]=CLAMP_FLOAT_TO_BYTE(scaled[1]);
	brgb[2]=CLAMP_FLOAT_TO_BYTE(scaled[2]);
}

void	V_GLOBAL	rgbaByteFromFloat(color4b_t brgba,vec4_t rgba)
{
	vec4_t scaled;
	vec4Scale(scaled,rgba,255);
	brgba[0]=CLAMP_FLOAT_TO_BYTE(scaled[0]);
	brgba[1]=CLAMP_FLOAT_TO_BYTE(scaled[1]);
	brgba[2]=CLAMP_FLOAT_TO_BYTE(scaled[2]);
	brgba[3]=CLAMP_FLOAT_TO_BYTE(scaled[3]);
}

#endif		/* MATH_NO_MACRO */

/*
 *	Code for these functions is always generated.
 */
 
/* Triple scalar product */
vec_t	V_GLOBAL	vec3Triple(vec3_t v1, vec3_t v2, vec3_t	v3)
{
	vec3_t v;
	vec3Cross(v,v1,v2);
	return vec3Dot(v,v3);
}

/*		Minimal/maximal indices for 3/4 - vectors */
int		V_GLOBAL	vec3MinInd(vec3_t vec)
{
	int	a;
	a = (vec[0] < vec[1]) ? 0 : 1;
	return (vec[a] < vec[2]) ? a : 2;
}

int		V_GLOBAL	vec3MinAbsInd(vec3_t vec)
{
	int	a;
	vec3_t absv;
	vec3Set(absv,v_abs(vec[0]),v_abs(vec[1]),v_abs(vec[2]));
	a=(absv[0]<absv[1])	? 0	: 1;
	return (absv[a]<absv[2]) ? a : 2;
}

int		V_GLOBAL	vec4MinInd(vec4_t vec)
{
	int	a,b;
	a = (vec[0] < vec[1]) ? 0	: 1;
	b = (vec[2] < vec[3]) ? 2	: 3;
	return (vec[a] < vec[b]) ? a : b;
}

int		V_GLOBAL	vec4MinAbsInd(vec4_t vec)
{
	int	a,b;
	vec4_t absv;
	vec4Set(absv,v_abs(vec[0]),v_abs(vec[1]),v_abs(vec[2]),v_abs(vec[3]));
	a=(absv[0]<absv[1])	? 0	: 1;
	b=(absv[2]<absv[3])	? 2	: 3;
	return (absv[a]<absv[b]) ? a : b;
}

int		V_GLOBAL	vec3MaxInd(vec3_t vec)
{
	int	a;
	a = (vec[0] > vec[1]) ? 0 : 1;
	return (vec[a] > vec[2]) ? a : 2;
}

int		V_GLOBAL	vec3MaxAbsInd(vec3_t vec)
{
	int	a;
	vec3_t absv;
	vec3Set(absv,v_abs(vec[0]),v_abs(vec[1]),v_abs(vec[2]));
	a=(absv[0]>absv[1])	? 0	: 1;
	return (absv[a]>absv[2]) ? a : 2;
}

int		V_GLOBAL	vec4MaxInd(vec4_t vec)
{
	int	a,b;
	a =(vec[0]>vec[1])	? 0	: 1;
	b =(vec[2]>vec[3])	? 2	: 3;
	return (vec[a]>vec[b]) ? a : b;
}

int		V_GLOBAL	vec4MaxAbsInd(vec4_t vec)
{
	int	a,b;
	vec4_t absv;
	vec4Set(absv,v_abs(vec[0]),v_abs(vec[1]),v_abs(vec[2]),v_abs(vec[3]));
	a=(absv[0]>absv[1])	? 0	: 1;
	b=(absv[2]>absv[3])	? 2	: 3;
	return (absv[a]>absv[b]) ? a : b;
}

#ifdef	MATH_NO_MACRO

/*	This routine returns true if distance between two points less then
 *	given 'epsilon'
 */
vboolean	V_GLOBAL	vec3IsEqualEpsilon(vec3_t a, vec3_t	b, vec_t epsilon)
{
	vec3_t ab;
	vec3Sub(ab,b,a);
	return vec3Abs(ab) < epsilon ? true	: false;
}

#endif

/*		Transposition of 3/4 matrices not-in-place */
void	V_GLOBAL	mat3Transpose(matrix3_t	dst,matrix3_t src)
{
	dst[0][0]=src[0][0]; dst[0][1]=src[1][0]; dst[0][2]=src[2][0];
	dst[1][0]=src[0][1]; dst[1][1]=src[1][1]; dst[1][2]=src[2][1];
	dst[2][0]=src[0][2]; dst[2][1]=src[1][2]; dst[2][2]=src[2][2];
}

void	V_GLOBAL	mat4Transpose(matrix4_t	dst,matrix4_t src)
{
	dst[0][0]=src[0][0]; dst[0][1]=src[1][0]; dst[0][2]=src[2][0];
		dst[0][3]=src[3][0];
	dst[1][0]=src[0][1]; dst[1][1]=src[1][1]; dst[1][2]=src[2][1];
		dst[1][3]=src[3][1];
	dst[2][0]=src[0][2]; dst[2][1]=src[1][2]; dst[2][2]=src[2][2];
		dst[2][3]=src[3][2];
	dst[3][0]=src[0][3]; dst[3][1]=src[1][3]; dst[3][2]=src[2][3];
		dst[3][3]=src[3][3];
}

/*		Transposition of 3/4 matrices in-place */
void	V_GLOBAL	mat3TransposeIP(matrix3_t mat)
{
	vec_t temp;
	temp=mat[0][1];	mat[0][1]=mat[1][0]; mat[1][0]=temp;
	temp=mat[0][2];	mat[0][2]=mat[2][0]; mat[2][0]=temp;
	temp=mat[1][2];	mat[1][2]=mat[2][1]; mat[2][1]=temp;
}

void	V_GLOBAL	mat4TransposeIP(matrix4_t mat)
{
	vec_t temp;
	temp=mat[0][1];	mat[0][1]=mat[1][0]; mat[1][0]=temp;
	temp=mat[0][2];	mat[0][2]=mat[2][0]; mat[2][0]=temp;
	temp=mat[0][3];	mat[0][3]=mat[3][0]; mat[3][0]=temp;
	temp=mat[1][2];	mat[1][2]=mat[2][1]; mat[2][1]=temp;
	temp=mat[1][3];	mat[1][3]=mat[3][1]; mat[3][1]=temp;
	temp=mat[2][3];	mat[2][3]=mat[3][2]; mat[3][2]=temp;
}

/*	Multiplication of 3/4 matrices */
void	V_GLOBAL	mat3MatMul(matrix3_t dst,matrix3_t m1,matrix3_t m2)
{
	dst[0][0]=m1[0][0]*m2[0][0]+m1[0][1]*m2[1][0]+m1[0][2]*m2[2][0];
	dst[0][1]=m1[0][0]*m2[0][1]+m1[0][1]*m2[1][1]+m1[0][2]*m2[2][1];
	dst[0][2]=m1[0][0]*m2[0][2]+m1[0][1]*m2[1][2]+m1[0][2]*m2[2][2];
	dst[1][0]=m1[1][0]*m2[0][0]+m1[1][1]*m2[1][0]+m1[1][2]*m2[2][0];
	dst[1][1]=m1[1][0]*m2[0][1]+m1[1][1]*m2[1][1]+m1[1][2]*m2[2][1];
	dst[1][2]=m1[1][0]*m2[0][2]+m1[1][1]*m2[1][2]+m1[1][2]*m2[2][2];
	dst[2][0]=m1[2][0]*m2[0][0]+m1[2][1]*m2[1][0]+m1[2][2]*m2[2][0];
	dst[2][1]=m1[2][0]*m2[0][1]+m1[2][1]*m2[1][1]+m1[2][2]*m2[2][1];
	dst[2][2]=m1[2][0]*m2[0][2]+m1[2][1]*m2[1][2]+m1[2][2]*m2[2][2];
}

void	V_GLOBAL	mat4MatMul(matrix4_t dst,matrix4_t m1,matrix4_t m2)
{
	dst[0][0]=m1[0][0]*m2[0][0]+m1[0][1]*m2[1][0]+m1[0][2]*m2[2][0]+\
		m1[0][3]*m2[3][0];
	dst[0][1]=m1[0][0]*m2[0][1]+m1[0][1]*m2[1][1]+m1[0][2]*m2[2][1]+\
		m1[0][3]*m2[3][1];
	dst[0][2]=m1[0][0]*m2[0][2]+m1[0][1]*m2[1][2]+m1[0][2]*m2[2][2]+\
		m1[0][3]*m2[3][2];
	dst[0][3]=m1[0][0]*m2[0][3]+m1[0][1]*m2[1][3]+m1[0][2]*m2[2][3]+\
		m1[0][3]*m2[3][3];
	dst[1][0]=m1[1][0]*m2[0][0]+m1[1][1]*m2[1][0]+m1[1][2]*m2[2][0]+\
		m1[1][3]*m2[3][0];
	dst[1][1]=m1[1][0]*m2[0][1]+m1[1][1]*m2[1][1]+m1[1][2]*m2[2][1]+\
		m1[1][3]*m2[3][1];
	dst[1][2]=m1[1][0]*m2[0][2]+m1[1][1]*m2[1][2]+m1[1][2]*m2[2][2]+\
		m1[1][3]*m2[3][2];
	dst[1][3]=m1[1][0]*m2[0][3]+m1[1][1]*m2[1][3]+m1[1][2]*m2[2][3]+\
		m1[1][3]*m2[3][3];
	dst[2][0]=m1[2][0]*m2[0][0]+m1[2][1]*m2[1][0]+m1[2][2]*m2[2][0]+\
		m1[2][3]*m2[3][0];
	dst[2][1]=m1[2][0]*m2[0][1]+m1[2][1]*m2[1][1]+m1[2][2]*m2[2][1]+\
		m1[2][3]*m2[3][1];
	dst[2][2]=m1[2][0]*m2[0][2]+m1[2][1]*m2[1][2]+m1[2][2]*m2[2][2]+\
		m1[2][3]*m2[3][2];
	dst[2][3]=m1[2][0]*m2[0][3]+m1[2][1]*m2[1][3]+m1[2][2]*m2[2][3]+\
		m1[2][3]*m2[3][3];
	dst[3][0]=m1[3][0]*m2[0][0]+m1[3][1]*m2[1][0]+m1[3][2]*m2[2][0]+\
		m1[3][3]*m2[3][0];
	dst[3][1]=m1[3][0]*m2[0][1]+m1[3][1]*m2[1][1]+m1[3][2]*m2[2][1]+\
		m1[3][3]*m2[3][1];
	dst[3][2]=m1[3][0]*m2[0][2]+m1[3][1]*m2[1][2]+m1[3][2]*m2[2][2]+\
		m1[3][3]*m2[3][2];
	dst[3][3]=m1[3][0]*m2[0][3]+m1[3][1]*m2[1][3]+m1[3][2]*m2[2][3]+\
		m1[3][3]*m2[3][3];
}

/*	"Multiplication" of two transform matrices */
void	V_GLOBAL	mat3x4MatMul(matrix3x4_t dst,matrix3x4_t m1,matrix3x4_t m2)
{
	dst[0][0] =	m1[0][0] * m2[0][0]	+ m1[0][1] * m2[1][0] +	\
		m1[0][2] * m2[2][0];
	dst[0][1] =	m1[0][0] * m2[0][1]	+ m1[0][1] * m2[1][1] +	\
		m1[0][2] * m2[2][1];
	dst[0][2] =	m1[0][0] * m2[0][2]	+ m1[0][1] * m2[1][2] +	\
		m1[0][2] * m2[2][2];
	dst[0][3] =	m1[0][0] * m2[0][3]	+ m1[0][1] * m2[1][3] +	\
		m1[0][2] * m2[2][3]	+ m1[0][3];
	dst[1][0] =	m1[1][0] * m2[0][0]	+ m1[1][1] * m2[1][0] +	\
		m1[1][2] * m2[2][0];
	dst[1][1] =	m1[1][0] * m2[0][1]	+ m1[1][1] * m2[1][1] +	\
		m1[1][2] * m2[2][1];
	dst[1][2] =	m1[1][0] * m2[0][2]	+ m1[1][1] * m2[1][2] +	\
		m1[1][2] * m2[2][2];
	dst[1][3] =	m1[1][0] * m2[0][3]	+ m1[1][1] * m2[1][3] +	\
		m1[1][2] * m2[2][3]	+ m1[1][3];
	dst[2][0] =	m1[2][0] * m2[0][0]	+ m1[2][1] * m2[1][0] +	\
		m1[2][2] * m2[2][0];
	dst[2][1] =	m1[2][0] * m2[0][1]	+ m1[2][1] * m2[1][1] +	\
		m1[2][2] * m2[2][1];
	dst[2][2] =	m1[2][0] * m2[0][2]	+ m1[2][1] * m2[1][2] +	\
		m1[2][2] * m2[2][2];
	dst[2][3] =	m1[2][0] * m2[0][3]	+ m1[2][1] * m2[1][3] +	\
		m1[2][2] * m2[2][3]	+ m1[2][3];
}

/*		Transformation of elements of vec3_t - array */
void	V_GLOBAL	vec3TransformVectors(vec3_t vecs[],matrix3x4_t mat,int n)
{
	int i;
	vec3_t temp;
	for(i=0;i<n;i++)
	{
		vec3Copy(temp,vecs[i]);
		mat3x4VecMul(vecs[i],mat,temp);
	}
}

/*
 *	The routines below is for solving systems of linear equations
 *	of order 2,3 and 4. Solution stored in 'b' vector.
 */
void	V_GLOBAL	mat2Solve(matrix2_t a,vec2_t b)
{
	V_ASSERT(!IsZero(a[0][0]) && !IsZero(a[1][1]));
	a[0][1]/=a[0][0];
	b[0]/=a[0][0];
	a[1][1]-=a[1][0]*a[0][1];
	b[1]-=a[1][0]*b[0];
	b[1]/=a[1][1];
	b[0]-=a[0][1]*b[1];
}

void	V_GLOBAL	mat2Solve2v(vec2_t r1,vec2_t r2,vec2_t b)
{
	matrix2_t m;
	m[0][0]=r1[0];m[0][1]=r1[1];
	m[1][0]=r2[0];m[1][1]=r2[1];
	mat2Solve(m,b);
}

void	V_GLOBAL	mat2Solve4s(vec_t a00,vec_t a01,vec_t a10,vec_t a11,
	vec2_t b)
{
	matrix2_t m;
	m[0][0]=a00;
	m[0][1]=a01;
	m[1][0]=a10;
	m[1][1]=a11;
	mat2Solve(m,b);
}

vboolean V_GLOBAL
mat3Solve(matrix3_t a,vec3_t b)
{
	int	i,j,k,l,ind,ind2;
	vec_t elem,_b,temp;
	for(k=0;k<3;k++)
	{
		ind=k;
		for(ind2=ind+1;ind2<3;ind2++)
			if(v_abs(a[ind][k]) < v_abs(a[ind2][k]))
				ind = ind2;
		if(IsZero(a[ind][k]))
		{
#ifdef	CHECKED_BUILD
			conlPrintf(LOG_ERROR,
				"mat3Solve(): no pivot in column #%d.\n",k);
#endif	/* CHECKED_BUILD */
			return false;
		}
		if(ind!=k)
		{
			/* swap rows 'ind' and 'k' */
			for(l=0;l<3;l++)
			{
				temp=a[ind][l];
				a[ind][l]=a[k][l];
				a[k][l]=temp;
			}
			/* swap elements in b */
			_b=b[ind];
			b[ind]=b[k];
			b[k]=_b;
		}
		elem = a[k][k];
		for(j=k+1;j<3;j++)
			a[k][j]/=elem;
		b[k]/=elem;
		for(i=0;i<k;i++)
		{
			for(j=k+1;j<3;j++)
				a[i][j]-=a[i][k]*a[k][j];
			b[i]-=a[i][k]*b[k];
		}
		for(i=k+1;i<3;i++)
		{
			for(j=k+1;j<3;j++)
				a[i][j]-=a[i][k]*a[k][j];
			b[i]-=a[i][k]*b[k];
		}
	}
	return true;
}

void	V_GLOBAL	mat4Solve(matrix4_t a,vec4_t b)
{
	int	i,j,k,l,ind;
	vec_t elem,_b,temp;
	for(k=0;k<4;k++)
	{
		ind=k;
		/* find pivot element; we use first element with abs > eps */
		/* FIXME */
		while(IsZero(a[ind][k]))
		{
			ind++;
			if(ind==4)	/* No pivot */
			{
#ifdef	CHECKED_BUILD
				conlPrintf(LOG_ERROR,
					"mat4Solve(): no pivot in column #%d.\n",k);
#endif	/* CHECKED_BUILD */
				mat4Unit(a);
				vec4Set(b,1,1,1,1);
				return;
			}
		}
		if(ind!=k)
		{
			/* swap rows */
			for(l=0;l<4;l++)
			{
				temp=a[ind][l];
				a[ind][l]=a[k][l];
				a[k][l]=temp;
			}
			/* swap elements in b */
			_b=b[ind];
			b[ind]=b[k];
			b[k]=_b;
		}
		elem = a[k][k];
		for(j=k+1;j<4;j++)
			a[k][j]/=elem;
		b[k]/=elem;
		for(i=0;i<k;i++)
		{
			for(j=k+1;j<4;j++)
				a[i][j]-=a[i][k]*a[k][j];
			b[i]-=a[i][k]*b[k];
		}
		for(i=k+1;i<4;i++)
		{
			for(j=k+1;j<4;j++)
				a[i][j]-=a[i][k]*a[k][j];
			b[i]-=a[i][k]*b[k];
		}
	}
}

/*	======================================================================
 *	Conversion from RGB to HSV and vice versa
 *	====================================================================*/

/*
 * FIXME: this is good, and old implementation of vec3Min[Max]Ind()
 * should be removed.
 */
#define	VEC3_MINMAX_IND(v,min_ind,max_ind) \
	(min_ind) = (max_ind) = 0; \
	if((v)[1] > *(v)) \
		(max_ind) = 1; \
	else \
		(min_ind) = 1; \
	if((v)[2] > (v)[max_ind]) \
		(max_ind) = 2; \
	else if((v)[2] < (v)[min_ind]) \
		(min_ind) = 2;

void	V_GLOBAL
hsvFromRgb(vec3_t hsv,vec3_t rgb)
{
	vec_t c_min, c_max, delta, r,g,b;
	u32_t min_ind, max_ind;
	VEC3_MINMAX_IND(rgb,min_ind,max_ind);
	c_min = rgb[min_ind];
	c_max = rgb[max_ind];
	delta = c_max - c_min;
	hsv[2] = c_max;
	if(IsZero(c_max))
	{
		hsv[0] = 0.5;
		hsv[1] = 0;
		return;
	}
	r = rgb[0];
	g = rgb[1];
	b = rgb[2];
	hsv[1] = delta / c_max;
	if(IsZero(delta))
	{
		hsv[0] = 0;
		return;
	}
	switch(max_ind)
	{
		case 0: /* red dominates */
			hsv[0] = (g - b) / delta;
			break;
		case 1: /* green dominates */
			hsv[0] = 2 + (b - r) / delta;
			break;
		default: /* blue dominates */
			hsv[0] = 4 + (r - g) / delta;
			break;
	}
	hsv[0] *= (vec_t)1 / (vec_t)6;
	if(hsv[0] < 0)
		hsv[0] += 1;
}

void	V_GLOBAL
hsvFromRgbEx(vec3_t hsv,vec3_t rgb,vboolean *h_valid)
{
	vec_t c_min, c_max, delta, r,g,b;
	u32_t min_ind, max_ind;
	VEC3_MINMAX_IND(rgb,min_ind,max_ind);
	c_min = rgb[min_ind];
	c_max = rgb[max_ind];
	delta = c_max-c_min;
	hsv[2] = c_max;
	if(IsZero(c_max))
	{
		if(h_valid)
			*h_valid = false;
		hsv[0] = 0.5;
		hsv[1] = 0;
		return;
	}
	if(h_valid)
		*h_valid = true;
	r = rgb[0];
	g = rgb[1];
	b = rgb[2];
	hsv[1] = delta / c_max;
	if(IsZero(delta))
	{
		hsv[0] = 0;
		return;
	}
	switch(max_ind)
	{
		case 0: /* red dominates */
			hsv[0] = (g - b) / delta;
			break;
		case 1: /* green dominates */
			hsv[0] = 2 + (b - r) / delta;
			break;
		default: /* blue dominates */
			hsv[0] = 4 + (r - g) / delta;
			break;
	}
	hsv[0] *= (vec_t)1 / (vec_t)6;
	if(hsv[0] < 0)
		hsv[0] += 1;
}

void	V_GLOBAL
rgbFromHsv(vec3_t rgb,vec3_t hsv)
{
	int i;
	vec_t f,p,q,t,h,s,v;
	if(IsZero(hsv[1]))
	{
		vec3Set(rgb,hsv[2],hsv[2],hsv[2]);
		return;
	}
	h = hsv[0];
	s = hsv[1];
	v = hsv[2];
	if(IsZero(h - 1))
		h = 0;
	h *= 6;
	i = (int)floor(h);
	f = h - i;
	p = v * (1 - s);
	q = v * (1 - s * f);
	t = v * (1 - s * (1 - f));
	switch(i)
	{
		case 0:
			vec3Set(rgb,v,t,p);
			break;
		case 1:
			vec3Set(rgb,q,v,p);
			break;
		case 2:
			vec3Set(rgb,p,v,t);
			break;
		case 3:
			vec3Set(rgb,p,q,v);
			break;
		case 4:
			vec3Set(rgb,t,p,v);
			break;
		case 5:
			vec3Set(rgb,v,p,q);
			break;
	}
}
