//-----------------------------------------------------------------------------
//
//  $Logfile:: /Quake 2 Engine/Sin/code/game/q_shared.c                       $
// $Revision:: 31                                                             $
//   $Author:: Markd                                                          $
//     $Date:: 1/26/99 5:45p                                                  $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// $Log:: /Quake 2 Engine/Sin/code/game/q_shared.c                            $
// 
// 31    1/26/99 5:45p Markd
// Added TransformFromTriangle for 2015
// 
// 30    10/05/98 12:28a Jimdose
// Added angledist
// 
// 29    9/28/98 5:51p Markd
// 
// 28    9/03/98 2:11p Aldie
// Added checksums checks to .def files
// 
// 27    8/22/98 8:48p Jimdose
// Added support for alternate gravity axis
// 
// 26    8/03/98 7:34p Markd
// Added SURFACE_DamageMultiplier func
// 
// 25    8/02/98 9:00p Markd
// Merged code 3.17
// 
// 24    7/21/98 9:06p Markd
// Music Mood conversion stuff
// 
// 23    7/10/98 6:13a Jimdose
// Nearly lost the file because H: was full! :O
// 
// 22    6/15/98 5:35p Markd
// put in UnsignedShort stuff
// 
// 21    5/27/98 8:06p Aldie
// Made a SIN_Parse and SIN_GetToken, and it works like the old one.
// 
// 20    5/26/98 12:34a Markd
// Fixed RotateBounds function
// 
// 19    5/24/98 6:49p Markd
// Got rid of unused variables
// 
// 18    5/24/98 6:29p Markd
// Added CalculateRotatedBounds2 
// 
// 17    5/24/98 4:48p Jimdose
// Made char *'s const
// 
// 16    5/20/98 11:12a Markd
// made certain functions take const char *'s instead of char *'s.
// 
// 15    5/13/98 6:21p Markd
// Added CalculateRotatedBounds
// 
// 14    5/12/98 1:15p Aldie
// Made Com_Parse substitute \n in an embedded string.
// 
// 13    4/17/98 6:48p Markd
// Put in /* support
// 
// 12    3/30/98 11:07p Aldie
// Updated COM_Parse to get strings within strings.
// 
// 11    3/30/98 9:38p Markd
// Made COM_GetToken handle Quoted-Double Quotes correctly
// 
// 10    3/27/98 6:59p Markd
// Changed Origin From Triangle and Transform From Triangle
// 
// 9     3/24/98 9:58a Markd
// Added TransformFromTriangle
// 
// 8     3/18/98 9:03p Jimdose
// Fixed assertion in BoxOnPlaneSide
// 
// 7     3/04/98 2:08p Markd
// Fixed bug in COM_GetToken it was returning null when it should have returned
// ""
// 
// 6     2/28/98 4:43p Aldie
// Added Matrix4TransformVector
// 
// 5     2/25/98 4:38p Markd
// Added COM_GetToken
// 
// 4     2/16/98 2:10p Jimdose
// Added the following math utility functions: MatrixToEulerAngles,
// TransposeMatrix, MatrixTransformVector, OrthoNormalize, QuatToMat,
// MatToQuat, SlerpQuaternion, AnglesToMat, RotateAxis, MultQuat, EulerToQuat,
// VectorsToEulerAngles
// 
// 3     12/30/97 6:04p Jimdose
// Added header text
//
// DESCRIPTION:
// 

#include "q_shared.h"
#include <float.h>
#include <ctype.h>

#define DEG2RAD( a ) ( a * M_PI ) / 180.0F

const vec3_t vec3_origin = {0,0,0};
qboolean bigendien;

#ifdef SIN

#define X 0
#define Y 1
#define Z 2
#define W 3
#define QUAT_EPSILON 0.00001

const gravityaxis_t gravity_axis[ GRAVITY_NUM_AXIS ] =
	{
		{ X, Y, Z, 1 },
		{ Y, Z, X, 1 },
		{ Z, X, Y, 1 },
		{ X, Y, Z, -1 },
		{ Y, Z, X, -1 },
		{ Z, X, Y, -1 }
	};

#endif

//============================================================================

#ifdef _WIN32
#pragma optimize( "", off )
#endif

void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
{
	float	m[3][3];
	float	im[3][3];
	float	zrot[3][3];
	float	tmpmat[3][3];
	float	rot[3][3];
	int	i;
	vec3_t vr, vup, vf;

	vf[0] = dir[0];
	vf[1] = dir[1];
	vf[2] = dir[2];

	PerpendicularVector( vr, dir );
	CrossProduct( vr, vf, vup );

	m[0][0] = vr[0];
	m[1][0] = vr[1];
	m[2][0] = vr[2];

	m[0][1] = vup[0];
	m[1][1] = vup[1];
	m[2][1] = vup[2];

	m[0][2] = vf[0];
	m[1][2] = vf[1];
	m[2][2] = vf[2];

	memcpy( im, m, sizeof( im ) );

	im[0][1] = m[1][0];
	im[0][2] = m[2][0];
	im[1][0] = m[0][1];
	im[1][2] = m[2][1];
	im[2][0] = m[0][2];
	im[2][1] = m[1][2];

	memset( zrot, 0, sizeof( zrot ) );
	zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;

	zrot[0][0] = cos( DEG2RAD( degrees ) );
	zrot[0][1] = sin( DEG2RAD( degrees ) );
	zrot[1][0] = -sin( DEG2RAD( degrees ) );
	zrot[1][1] = cos( DEG2RAD( degrees ) );

	R_ConcatRotations( m, zrot, tmpmat );
	R_ConcatRotations( tmpmat, im, rot );

	for ( i = 0; i < 3; i++ )
	{
		dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
	}
}

#ifdef _WIN32
#pragma optimize( "", on )
#endif

void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
{
	float		angle;
	static float		sr, sp, sy, cr, cp, cy;
	// static to help MS compiler fp bugs

	angle = angles[YAW] * (M_PI*2 / 360);
	sy = sin(angle);
	cy = cos(angle);
	angle = angles[PITCH] * (M_PI*2 / 360);
	sp = sin(angle);
	cp = cos(angle);
	angle = angles[ROLL] * (M_PI*2 / 360);
	sr = sin(angle);
	cr = cos(angle);

	if (forward)
	{
		forward[0] = cp*cy;
		forward[1] = cp*sy;
		forward[2] = -sp;
	}
	if (right)
	{
		right[0] = (-1*sr*sp*cy+-1*cr*-sy);
		right[1] = (-1*sr*sp*sy+-1*cr*cy);
		right[2] = -1*sr*cp;
	}
	if (up)
	{
		up[0] = (cr*sp*cy+-sr*-sy);
		up[1] = (cr*sp*sy+-sr*cy);
		up[2] = cr*cp;
	}
}


void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
{
	float d;
	vec3_t n;
	float inv_denom;

	inv_denom = 1.0F / DotProduct( normal, normal );

	d = DotProduct( normal, p ) * inv_denom;

	n[0] = normal[0] * inv_denom;
	n[1] = normal[1] * inv_denom;
	n[2] = normal[2] * inv_denom;

	dst[0] = p[0] - d * n[0];
	dst[1] = p[1] - d * n[1];
	dst[2] = p[2] - d * n[2];
}

/*
** assumes "src" is normalized
*/
void PerpendicularVector( vec3_t dst, const vec3_t src )
{
	int	pos;
	int i;
	float minelem = 1.0f;
	vec3_t tempvec;

	/*
	** find the smallest magnitude axially aligned vector
	*/
	for ( pos = 0, i = 0; i < 3; i++ )
	{
		if ( fabs( src[i] ) < minelem )
		{
			pos = i;
			minelem = fabs( src[i] );
		}
	}
	tempvec[0] = tempvec[1] = tempvec[2] = 0.0f;
	tempvec[pos] = 1.0f;
	/* project the point onto the plane defined by src */
	ProjectPointOnPlane( dst, tempvec, src );
	/* normalize the result */
	VectorNormalize( dst );
}



/*
================
R_ConcatRotations
================
*/
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
{
	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
				in1[0][2] * in2[2][0];
	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
				in1[0][2] * in2[2][1];
	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
				in1[0][2] * in2[2][2];
	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
				in1[1][2] * in2[2][0];
	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
				in1[1][2] * in2[2][1];
	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
				in1[1][2] * in2[2][2];
	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
				in1[2][2] * in2[2][0];
	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
				in1[2][2] * in2[2][1];
	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
				in1[2][2] * in2[2][2];
}


/*
================
R_ConcatTransforms
================
*/
void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
{
	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
				in1[0][2] * in2[2][0];
	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
				in1[0][2] * in2[2][1];
	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
				in1[0][2] * in2[2][2];
	out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
				in1[0][2] * in2[2][3] + in1[0][3];
	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
				in1[1][2] * in2[2][0];
	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
				in1[1][2] * in2[2][1];
	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
				in1[1][2] * in2[2][2];
	out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
				in1[1][2] * in2[2][3] + in1[1][3];
	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
				in1[2][2] * in2[2][0];
	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
				in1[2][2] * in2[2][1];
	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
				in1[2][2] * in2[2][2];
	out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
				in1[2][2] * in2[2][3] + in1[2][3];
}


//============================================================================


float Q_fabs (float f)
{
#if 0
	if (f >= 0)
		return f;
	return -f;
#else
	int tmp = * ( int * ) &f;
	tmp &= 0x7FFFFFFF;
	return * ( float * ) &tmp;
#endif
}

#if defined _M_IX86 && !defined C_ONLY
#pragma warning (disable:4035)
__declspec( naked ) long Q_ftol( float f )
{
	static int tmp;
	__asm fld dword ptr [esp+4]
	__asm fistp tmp
	__asm mov eax, tmp
	__asm ret
}
#pragma warning (default:4035)
#endif

/*
===============
LerpAngle

===============
*/
float LerpAngle (float a2, float a1, float frac)
{
	if (a1 - a2 > 180)
		a1 -= 360;
	if (a1 - a2 < -180)
		a1 += 360;
	return a2 + frac * (a1 - a2);
}


float	anglemod(float a)
{
#if 0
	if (a >= 0)
		a -= 360*(int)(a/360);
	else
		a += 360*( 1 + (int)(-a/360) );
#endif
	a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
	return a;
}

float angledist( float ang )
	{
	float a;

	a = anglemod( ang );
	if ( a > 180 )
		{
		a -= 360;
		}

	return a;
}

// this is the slow, general version
int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
{
	int		i;
	float	dist1, dist2;
	int		sides;
	vec3_t	corners[2];

	for (i=0 ; i<3 ; i++)
	{
		if (p->normal[i] < 0)
		{
			corners[0][i] = emins[i];
			corners[1][i] = emaxs[i];
		}
		else
		{
			corners[1][i] = emins[i];
			corners[0][i] = emaxs[i];
		}
	}
	dist1 = DotProduct (p->normal, corners[0]) - p->dist;
	dist2 = DotProduct (p->normal, corners[1]) - p->dist;
	sides = 0;
	if (dist1 >= 0)
		sides = 1;
	if (dist2 < 0)
		sides |= 2;

	return sides;
}

/*
==================
BoxOnPlaneSide

Returns 1, 2, or 1 + 2
==================
*/
#if !id386 || defined __linux__ 
int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
{
	float	dist1, dist2;
	int		sides;

// fast axial cases
	if (p->type < 3)
	{
		if (p->dist <= emins[p->type])
			return 1;
		if (p->dist >= emaxs[p->type])
			return 2;
		return 3;
	}
	
// general case
	switch (p->signbits)
	{
	case 0:
		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
		dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
	break;
	case 1:
		dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
	break;
	case 2:
		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
		dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
	break;
	case 3:
		dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
	break;
	case 4:
		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
		dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
	break;
	case 5:
		dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
	break;
	case 6:
		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
		dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
	break;
	case 7:
		dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
	break;
	default:
		dist1 = dist2 = 0;		// shut up compiler
		// assert( 1 ) doesn't do jack shit
		assert( 0 );
		break;
	}

	sides = 0;
	if (dist1 >= p->dist)
		sides = 1;
	if (dist2 < p->dist)
		sides |= 2;

//	assert( sides != 0 );
//	if (sides == 0) {
//		void DebugStr(const unsigned char *);
//
//		DebugStr("\pSides == 0");
//	}

	return sides;
}
#else
#pragma warning( disable: 4035 )

__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
{
	static int bops_initialized;
	static int Ljmptab[8];

	__asm {

		push ebx
			
		cmp bops_initialized, 1
		je  initialized
		mov bops_initialized, 1
		
		mov Ljmptab[0*4], offset Lcase0
		mov Ljmptab[1*4], offset Lcase1
		mov Ljmptab[2*4], offset Lcase2
		mov Ljmptab[3*4], offset Lcase3
		mov Ljmptab[4*4], offset Lcase4
		mov Ljmptab[5*4], offset Lcase5
		mov Ljmptab[6*4], offset Lcase6
		mov Ljmptab[7*4], offset Lcase7
			
initialized:

		mov edx,ds:dword ptr[4+12+esp]
		mov ecx,ds:dword ptr[4+4+esp]
		xor eax,eax
		mov ebx,ds:dword ptr[4+8+esp]
		mov al,ds:byte ptr[17+edx]
		cmp al,8
		jge Lerror
		fld ds:dword ptr[0+edx]
		fld st(0)
		jmp dword ptr[Ljmptab+eax*4]
Lcase0:
		fmul ds:dword ptr[ebx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ebx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
		jmp LSetSides
Lcase1:
		fmul ds:dword ptr[ecx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ebx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
		jmp LSetSides
Lcase2:
		fmul ds:dword ptr[ebx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ecx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
		jmp LSetSides
Lcase3:
		fmul ds:dword ptr[ecx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ecx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
		jmp LSetSides
Lcase4:
		fmul ds:dword ptr[ebx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ebx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
		jmp LSetSides
Lcase5:
		fmul ds:dword ptr[ecx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ebx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
		jmp LSetSides
Lcase6:
		fmul ds:dword ptr[ebx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ecx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ecx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
		jmp LSetSides
Lcase7:
		fmul ds:dword ptr[ecx]
		fld ds:dword ptr[0+4+edx]
		fxch st(2)
		fmul ds:dword ptr[ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[4+ecx]
		fld ds:dword ptr[0+8+edx]
		fxch st(2)
		fmul ds:dword ptr[4+ebx]
		fxch st(2)
		fld st(0)
		fmul ds:dword ptr[8+ecx]
		fxch st(5)
		faddp st(3),st(0)
		fmul ds:dword ptr[8+ebx]
		fxch st(1)
		faddp st(3),st(0)
		fxch st(3)
		faddp st(2),st(0)
LSetSides:
		faddp st(2),st(0)
		fcomp ds:dword ptr[12+edx]
		xor ecx,ecx
		fnstsw ax
		fcomp ds:dword ptr[12+edx]
		and ah,1
		xor ah,1
		add cl,ah
		fnstsw ax
		and ah,1
		add ah,ah
		add cl,ah
		pop ebx
		mov eax,ecx
		ret
Lerror:
		int 3
	}
}
#pragma warning( default: 4035 )
#endif


void ClearBounds (vec3_t mins, vec3_t maxs)
{
	mins[0] = mins[1] = mins[2] = 99999;
	maxs[0] = maxs[1] = maxs[2] = -99999;
}

void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
{
	int		i;
	vec_t	val;

	for (i=0 ; i<3 ; i++)
	{
		val = v[i];
		if (val < mins[i])
			mins[i] = val;
		if (val > maxs[i])
			maxs[i] = val;
	}
}


int VectorCompare (vec3_t v1, vec3_t v2)
{
	if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2])
			return 0;
			
	return 1;
}


vec_t VectorNormalize (vec3_t v)
{
	float	length, ilength;

	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
	length = sqrt (length);		// FIXME

	if (length)
	{
		ilength = 1/length;
		v[0] *= ilength;
		v[1] *= ilength;
		v[2] *= ilength;
	}
		
	return length;

}

vec_t VectorNormalize2 (vec3_t v, vec3_t out)
{
	float	length, ilength;

	length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
	length = sqrt (length);		// FIXME

	if (length)
	{
		ilength = 1/length;
		out[0] = v[0]*ilength;
		out[1] = v[1]*ilength;
		out[2] = v[2]*ilength;
	}
		
	return length;

}

void VectorMA (const vec3_t veca, float scale,const vec3_t vecb, vec3_t vecc)
{
	vecc[0] = veca[0] + scale*vecb[0];
	vecc[1] = veca[1] + scale*vecb[1];
	vecc[2] = veca[2] + scale*vecb[2];
}


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

void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
{
	out[0] = veca[0]-vecb[0];
	out[1] = veca[1]-vecb[1];
	out[2] = veca[2]-vecb[2];
}

void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
{
	out[0] = veca[0]+vecb[0];
	out[1] = veca[1]+vecb[1];
	out[2] = veca[2]+vecb[2];
}

void _VectorCopy (const vec3_t in, vec3_t out)
{
	out[0] = in[0];
	out[1] = in[1];
	out[2] = in[2];
}

void CrossProduct (const vec3_t v1,const vec3_t v2, vec3_t cross)
{
	cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
	cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
	cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}

vec_t VectorLength(const vec3_t v)
{
	int		i;
	float	length;
	
	length = 0;
	for (i=0 ; i< 3 ; i++)
		length += v[i]*v[i];
	length = sqrt (length);		// FIXME

	return length;
}

void VectorInverse (vec3_t v)
{
	v[0] = -v[0];
	v[1] = -v[1];
	v[2] = -v[2];
}

void VectorScale (const vec3_t in, vec_t scale, vec3_t out)
{
	out[0] = in[0]*scale;
	out[1] = in[1]*scale;
	out[2] = in[2]*scale;
}


int Q_log2(int val)
{
	int answer=0;
	while (val>>=1)
		answer++;
	return answer;
}

#ifdef SIN

/*
=================
CalculateRotatedBounds
=================
*/         
void CalculateRotatedBounds( vec3_t angles, vec3_t mins, vec3_t maxs )
   {
   int i;
   vec3_t forward,right,up;
   vec3_t rotmins, rotmaxs;
   float trans[3][3];

   AngleVectors( angles, forward, right, up );
	for (i=0 ; i<3 ; i++)
	   {
		trans[i][0] =  forward[i];
		trans[i][1] =  -right[i];
		trans[i][2] =  up[i];
	   }
   ClearBounds( rotmins, rotmaxs );
	for ( i = 0; i < 8; i++ )
   	{
		vec3_t   tmp, rottemp;

		if ( i & 1 )
			tmp[0] = mins[0];
		else
			tmp[0] = maxs[0];

		if ( i & 2 )
			tmp[1] = mins[1];
		else
			tmp[1] = maxs[1];

		if ( i & 4 )
			tmp[2] = mins[2];
		else
			tmp[2] = maxs[2];

      MatrixTransformVector( tmp, trans, rottemp );
      AddPointToBounds( rottemp, rotmins, rotmaxs );
		}
   VectorCopy( rotmins, mins );
   VectorCopy( rotmaxs, maxs );
   }

/*
=================
CalculateRotatedBounds2
=================
*/         
void CalculateRotatedBounds2( float trans[3][3], vec3_t mins, vec3_t maxs )
   {
   int i;
   vec3_t rotmins, rotmaxs;

   ClearBounds( rotmins, rotmaxs );
	for ( i = 0; i < 8; i++ )
   	{
		vec3_t   tmp, rottemp;

		if ( i & 1 )
			tmp[0] = mins[0];
		else
			tmp[0] = maxs[0];

		if ( i & 2 )
			tmp[1] = mins[1];
		else
			tmp[1] = maxs[1];

		if ( i & 4 )
			tmp[2] = mins[2];
		else
			tmp[2] = maxs[2];

      MatrixTransformVector( tmp, trans, rottemp );
      AddPointToBounds( rottemp, rotmins, rotmaxs );
		}
   VectorCopy( rotmins, mins );
   VectorCopy( rotmaxs, maxs );
   }

/*
=================
OriginFromTriangle
=================
*/         
//  coordinate system at center 
void OriginFromTriangle( const float tri[3][3], vec3_t pos )
   {
   int i;

   VectorClear( pos );
   for (i=0;i<3;i++)
      pos[i] = (tri[0][i] + tri[1][i] + tri[2][i])/3;
   }

/*
=================
TransformFromTriangle
=================
*/         
//         0
//        /\
//       /  \
//    0 /    \  2
//     /      \
//    /        \
//   /----------\
//  1      1     2
//
// ((type>>2)&0x3)
// 0 -  edge 0 is first edge
// 1 -  edge 1 is first edge
// 2 -  edge 2 is first edge
//
// (type>>4)
// 0 - forward is perpendicular, up is first edge, right is on the same plane as the triangle
// 1 - forward is perpendicular, up is first edge, right is on the same plane as the triangle(inverted)
// 2 - forward is first edge, up is on the same plane as the triangle, up is perpendicular
// 3 - forward is first edge, up is on the same plane as the triangle(inverted), up is perpendicular
// 4 - forward is perpendicular to first edge, up is perpendicular, right is first edge
// 5 - forward is perpendicular to first edge, up is perpendicular, right is first edge(inverted)
// 6 - forward is perpendicular, up is first edge, right is on the same plane as the triangle
// 7 - forward is perpendicular, up is first edge, right is on the same plane as the triangle(inverted)
//
void TransformFromTriangle( const float tri[3][3], float trans[3][3], vec3_t pos )
   {
   vec3_t edge[2];
   vec3_t cross;
   vec3_t other;
   vec3_t forward, right, up;

   OriginFromTriangle( tri, pos );

   VectorSubtract( tri[2], tri[0], edge[0] );
   VectorSubtract( tri[1], tri[0], edge[1] );

   VectorNormalize( edge[0] );
   VectorNormalize( edge[1] );
   CrossProduct( edge[1], edge[0], cross );
   CrossProduct( edge[1], cross, other );

   VectorCopy( cross, forward );
   VectorCopy( other, right );
   VectorNegate( edge[1], up );

   VectorCopy( forward, trans[0] );
   VectorCopy( right, trans[1] );
   VectorCopy( up, trans[2] );

/*
   switch( (type>>2)&0x3 )
      {
      case 0:
         VectorSubtract( tri[2], tri[0], edge[0] );
         VectorSubtract( tri[1], tri[0], edge[1] );
         break;
      case 1:
         VectorSubtract( tri[0], tri[1], edge[0] );
         VectorSubtract( tri[2], tri[1], edge[1] );
         break;
      case 2:
         VectorSubtract( tri[1], tri[2], edge[0] );
         VectorSubtract( tri[0], tri[2], edge[1] );
         break;
      default:
         VectorSubtract( tri[2], tri[0], edge[0] );
         VectorSubtract( tri[1], tri[0], edge[1] );
         break;
      }
   VectorNormalize( edge[0] );
   VectorNormalize( edge[1] );
   CrossProduct( edge[1], edge[0], cross );
   CrossProduct( edge[1], cross, other );
   switch( type>>4 )
      {
      case 0:
         VectorCopy( cross, forward );
         VectorCopy( other, right );
         VectorNegate( edge[1], up );
         break;
      case 1:
         VectorCopy( cross, forward );
         VectorCopy( other, right );
         VectorCopy( edge[1], up );
         break;
      case 2:
         VectorCopy( cross, forward );
         VectorCopy( other, right );
         VectorNegate( edge[0], up );
         break;
      case 3:
         VectorCopy( cross, forward );
         VectorCopy( other, right );
         VectorCopy( edge[0], up );
         break;
      case 4:
         VectorCopy( edge[0], forward );
         VectorNegate( other, up );
         VectorCopy( cross, right );
         break;
      case 5:
         VectorCopy( edge[0], forward );
         VectorCopy( other, up );
         VectorCopy( cross, right );
         break;
      case 6:
         VectorCopy( other, forward );
         VectorNegate( edge[0], right );
         VectorCopy( cross, up );
         break;
      case 7:
         VectorCopy( other, forward );
         VectorCopy( edge[0], right );
         VectorCopy( cross, up );
         break;
      case 8:
         VectorCopy( edge[0], forward );
         VectorNegate( other, right );
         VectorCopy( cross, up );
         break;
      case 9:
         VectorCopy( edge[0], forward );
         VectorCopy( other, right );
         VectorCopy( cross, up );
         break;
      default:
         VectorCopy( edge[0], forward );
         VectorNegate( other, right );
         VectorCopy( cross, up );
         break;
      }
   // fill in the matrix
   VectorCopy( forward, trans[0] );
   VectorCopy( right, trans[1] );
   VectorCopy( up, trans[2] );
*/
   }

// 2015 code
void TransformFromTriangle_2015(const float tri[3][3], float trans[3][3], vec3_t pos)
{
   vec3_t edge[2];
   vec3_t cross;
   vec3_t other;
   vec3_t forward, right, up;
   
   OriginFromTriangle( tri, pos );
   
   VectorSubtract( tri[2], tri[0], edge[0] );
   VectorSubtract( tri[1], tri[0], edge[1] );
   
   VectorNormalize( edge[0] );
   VectorNormalize( edge[1] );
   CrossProduct( edge[1], edge[0], cross );
   VectorNormalize( cross ); // 
   CrossProduct( edge[1], cross, other );
   VectorNormalize( other ); // 
   
   VectorCopy( cross, forward );
   VectorCopy( other, right );
// VectorNegate( edge[1], up );
   VectorCopy( edge[1], up );
   
   VectorCopy( forward, trans[0] );
   VectorCopy( right, trans[1] );
   VectorCopy( up, trans[2] );
}

static char *musicmoods[ mood_totalnumber ] =
   {
   "none",
   "normal",
   "action",
   "suspense",
   "mystery",
   "success",
   "failure",
   "surprise",
   "special",
   "aux1",
   "aux2",
   "aux3",
   "aux4",
   "aux5",
   "aux6",
   "aux7"
   };

/*
=================
MusicMood_NameToNum
=================
*/         
int MusicMood_NameToNum( const char * name )
   {
   int i;

   if ( !name )
      return -1;

	for ( i = 0; i < mood_totalnumber; i++ )
      {
      if ( !strcmp( name, musicmoods[ i ] ) )
         {
         return i;
         }
      }
   return -1;
   }

/*
=================
MusicMood_NumToName
=================
*/         
const char * MusicMood_NumToName( int num )
   {
   if ( ( num < 0 ) || ( num >= mood_totalnumber ) )
      return "";
   else
      return musicmoods[ num ];
   }

/*
===============
SURFACE_DamageMultiplier
===============
*/
float SURFACE_DamageMultiplier( int flags )
   {
   float mult;

   mult = 0;
   switch ( flags )
      {
      case SURF_TYPE_FLESH:
      case SURF_TYPE_FABRIC:
      case SURF_TYPE_VEGETATION:
      case SURF_TYPE_WATER:
      case SURF_TYPE_PAPER:
         mult = 0;
         break;
      case SURF_TYPE_DIRT:
         mult = 0.2;
         break;
      case SURF_TYPE_WOOD:
         mult = 0.5;
         break;
      case SURF_TYPE_METAL:
      case SURF_TYPE_DUCT:
      case SURF_TYPE_GRILL:
         mult = 1;
         break;
      case SURF_TYPE_GRAVEL:
      case SURF_TYPE_STONE:
      case SURF_TYPE_CONCRETE:
         mult = 1.5;
         break;
      case SURF_TYPE_GLASS:
      case SURF_TYPE_MONITOR:
         mult = 3;
         break;
      default:
         break;
      }
   return mult;
   }

#endif

//====================================================================================

/*
============
COM_SkipPath
============
*/
#ifdef SIN
const char *COM_SkipPath (const char *pathname)
{
	const char	*last;
#else
char *COM_SkipPath (char *pathname)
{
	char	*last;
#endif
	
	last = pathname;
	while (*pathname)
	{
		if (*pathname=='/')
			last = pathname+1;
		pathname++;
	}
	return last;
}

/*
============
COM_ParseHex
============
*/
int COM_ParseHex (const char *hex)
{
	const char    *str;
	int    num;

	num = 0;
	str = hex;

	while (*str)
	{
		num <<= 4;
		if (*str >= '0' && *str <= '9')
			num += *str-'0';
		else if (*str >= 'a' && *str <= 'f')
			num += 10 + *str-'a';
		else if (*str >= 'A' && *str <= 'F')
			num += 10 + *str-'A';
		else
			Com_Printf("Bad hex number: %s",hex);
		str++;
	}

	return num;
}

/*
============
COM_StripExtension
============
*/
#ifdef SIN
void COM_StripExtension (const char *in, char *out)
#else
void COM_StripExtension (char *in, char *out)
#endif
{
	while (*in && *in != '.')
		*out++ = *in++;
	*out = 0;
}

/*
============
COM_FileExtension
============
*/
#ifdef SIN
char *COM_FileExtension (const char *in)
#else
char *COM_FileExtension (char *in)
#endif
{
	static char exten[8];
	int		i;

	while (*in && *in != '.')
		in++;
	if (!*in)
		return "";
	in++;
	for (i=0 ; i<7 && *in ; i++,in++)
		exten[i] = *in;
	exten[i] = 0;
	return exten;
}

/*
============
COM_FileBase
============
*/
#ifdef SIN
void COM_FileBase (const char *in, char *out)
{
	const char *s;
	const char *s2;
#else
void COM_FileBase (char *in, char *out)
{
	char *s, *s2;
#endif

	s = in + strlen(in) - 1;
	
	while (s != in && *s != '.')
		s--;
	
	for (s2 = s ; s2 != in && *s2 != '/' ; s2--)
	;
	
	if (s-s2 < 2)
		out[0] = 0;
	else
	{
		s--;
		strncpy (out,s2+1, s-s2);
		out[s-s2] = 0;
	}
}

/*
============
COM_FilePath

Returns the path up to, but not including the last /
============
*/
#ifdef SIN
void COM_FilePath (const char *in, char *out)
{
	const char *s;
#else
void COM_FilePath (char *in, char *out)
{
	char *s;
#endif
	
	s = in + strlen(in) - 1;
	
	while (s != in && *s != '/')
		s--;

	strncpy (out,in, s-in);
	out[s-in] = 0;
}


/*
==================
COM_DefaultExtension
==================
*/
#ifdef SIN
void COM_DefaultExtension (char *path, const char *extension)
#else
void COM_DefaultExtension (char *path, char *extension)
#endif
{
	char    *src;
//
// if path doesn't have a .EXT, append extension
// (extension should include the .)
//
	src = path + strlen(path) - 1;

	while (*src != '/' && src != path)
	{
		if (*src == '.')
			return;                 // it has an extension
		src--;
	}

	strcat (path, extension);
}

/*
============================================================================

					BYTE ORDER FUNCTIONS

============================================================================
*/

// can't just use function pointers, or dll linkage can
// mess up when qcommon is included in multiple places
static short (*_BigShort) (short l);
static short (*_LittleShort) (short l);
static int (*_BigLong) (int l);
static int (*_LittleLong) (int l);
static float (*_BigFloat) (float l);
static float (*_LittleFloat) (float l);

#ifdef SIN
static unsigned short (*_BigUnsignedShort) (unsigned short l);
static unsigned short (*_LittleUnsignedShort) (unsigned short l);
static unsigned int (*_BigUnsignedLong) (unsigned int l);
static unsigned int (*_LittleUnsignedLong) (unsigned int l);
static double (*_BigDouble) (double l);
static double (*_LittleDouble) (double l);
#endif

short BigShort(short l)
{
	return _BigShort(l);
}

short LittleShort(short l)
{
	return _LittleShort(l);
}

int BigLong (int l)
{
	return _BigLong(l);
}

int LittleLong (int l)
{
	return _LittleLong(l);
}

float BigFloat (float l)
{
	return _BigFloat(l);
}

float LittleFloat (float l)
{
	return _LittleFloat(l);
}

#ifdef SIN

unsigned short BigUnsignedShort(unsigned short l)
{
	return _BigUnsignedShort(l);
}

unsigned short LittleUnsignedShort(unsigned short l)
{
	return _LittleUnsignedShort(l);
}

unsigned int BigUnsignedLong(unsigned int l)
{
	return _BigUnsignedLong(l);
}

unsigned int LittleUnsignedLong(unsigned int l)
{
	return _LittleUnsignedLong(l);
}

double BigDouble(double l) 
{
	return _BigDouble(l);
}

double LittleDouble(double l)
{
	return _LittleDouble(l);
}

#endif

static short ShortSwap (short l)
{
	byte    b1,b2;
	b1 = l&255;
	b2 = (l>>8)&255;
	return (b1<<8) + b2;
}

static short ShortNoSwap (short l)
{
	return l;
}

#ifdef SIN

static unsigned short UnsignedShortSwap (unsigned short l)
{
	byte b1,b2;

	b1 = l&255;
	b2 = (l>>8)&255;

	return (b1<<8) + b2;
}

static unsigned short UnsignedShortNoSwap (unsigned short l)
{
	return l;
}

#endif

static int LongSwap (int l)
{
	byte    b1,b2,b3,b4;

	b1 = l&255;
	b2 = (l>>8)&255;
	b3 = (l>>16)&255;
	b4 = (l>>24)&255;

	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}

static int LongNoSwap (int l)
{
	return l;
}

static unsigned int UnsignedLongSwap (unsigned int l)
{
	byte    b1,b2,b3,b4;

	b1 = l&255;
	b2 = (l>>8)&255;
	b3 = (l>>16)&255;
	b4 = (l>>24)&255;

	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}

static double DoubleNoSwap (double l)
{
	return l;
}

static double DoubleSwap (double l)
{
	int i;
	union {
		char	c[8];
		double	d;
	} in, out;
	
	in.d = l;
	
	for (i = 0; i < 8; ++i)
		out.c[7-i] = in.c[i];
	
	return out.d;
}

static unsigned int UnsignedLongNoSwap (unsigned int l)
{
	return l;
}

static float FloatSwap (float f)
{
	union
	{
		float	f;
		byte	b[4];
	} dat1, dat2;
	
	
	dat1.f = f;
	dat2.b[0] = dat1.b[3];
	dat2.b[1] = dat1.b[2];
	dat2.b[2] = dat1.b[1];
	dat2.b[3] = dat1.b[0];
	return dat2.f;
}

static float FloatNoSwap (float f)
{
	return f;
}

/*
================
Swap_Init
================
*/
void Swap_Init (void)
{
	byte	swaptest[2] = {1,0};

// set the byte swapping variables in a portable manner	
	if ( *(short *)swaptest == 1)
	{
		bigendien = false;
		_BigShort = ShortSwap;
		_LittleShort = ShortNoSwap;
		_BigLong = LongSwap;
		_LittleLong = LongNoSwap;
		_BigFloat = FloatSwap;
		_LittleFloat = FloatNoSwap;
#ifdef SIN
		_BigUnsignedShort = UnsignedShortSwap;
		_LittleUnsignedShort = UnsignedShortNoSwap;
#endif
	}
	else
	{
		bigendien = true;
		_BigShort = ShortNoSwap;
		_LittleShort = ShortSwap;
		_BigLong = LongNoSwap;
		_LittleLong = LongSwap;
		_BigFloat = FloatNoSwap;
		_LittleFloat = FloatSwap;
#ifdef SIN
		_BigUnsignedShort = UnsignedShortNoSwap;
		_LittleUnsignedShort = UnsignedShortSwap;
		_BigUnsignedLong = UnsignedLongNoSwap;
		_LittleUnsignedLong = UnsignedLongSwap;
		_BigDouble = DoubleNoSwap;
//		_LittleDouble = SwapDouble;
		_LittleDouble = DoubleSwap;
#endif
	}
}



/*
============
va

does a varargs printf into a temp buffer, so I don't need to have
varargs versions of all text functions.
FIXME: make this buffer size safe someday
============
*/
char *va(const char *format, ...)
{
	va_list		argptr;
	static char		string[1024];
	
	va_start (argptr, format);
	vsprintf (string, format,argptr);
	va_end (argptr);

	return string;	
}


static char	com_token[MAX_STRING_CHARS];

#ifdef SIN
/*
==============
COM_GetToken

Parse a token out of a string
==============
*/
const char *COM_GetToken(const char **data_p, qboolean crossline)
{
	int		c;
	int		len;
	const char *data;

	data = *data_p;
	len = 0;
	com_token[0] = 0;
	
	if (!data)
	{
		*data_p = NULL;
		return "";
	}
		
// skip whitespace
skipwhite:
	while ( (c = *data) <= ' ')
	{
#ifdef SIN
      if (c == '\n' && !crossline)
         {
         *data_p = data;
         return "";
         }
#endif
		if (c == 0)
		{
			*data_p = NULL;
			return "";
		}
		data++;
	}
	
// skip // comments
	if (c=='/' && data[1] == '/')
	{
		while (*data && *data != '\n')
			data++;
		goto skipwhite;
	}

// skip /* comments
	if (c=='/' && data[1] == '*')
	   {
      data++;
      while (*data)
         {
         if ( (*(data-1)=='*') && (*data == '/') )
            break;
         data++;
         }
		while (*data && *data != '\n')
			data++;
		goto skipwhite;
	   }
	

// handle quoted strings specially
	if (c == '\"')
	{
		data++;
		while (1)
		{
			c = *data++;
         if (c == '\\' && *data == '\"')
            {
			   if (len < MAX_STRING_CHARS)
			      {
				   com_token[len] = '\"';
				   len++;
			      }
            data++;
            }
			else if (c=='\"' || !c)
			{
				com_token[len] = 0;
				*data_p = data;
				return com_token;
			}
         else if (len < MAX_STRING_CHARS)
			{
#ifdef SIN
            if (c == '\\' && *data == 'n')
               {
               com_token[len] = '\n';
               data++;
               }
		      else
               {
               com_token[len] = c;
               }
				len++;
#else
            com_token[len] = c;
				len++;
#endif
			}
		}
	}

// parse a regular word
	do
	{
		if (len < MAX_STRING_CHARS)
		{
			com_token[len] = c;
			len++;
		}
		data++;
		c = *data;
	} while (c>32);

	if (len == MAX_STRING_CHARS)
	{
//		Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
		len = 0;
	}
	com_token[len] = 0;

	*data_p = data;
	return com_token;
}


#ifdef SIN
/*
==============
SIN_GetToken

Parse a token out of a string
==============
*/
const char *SIN_GetToken(const char **data_p, qboolean crossline)
{
	int		c;
	int		len;
	const char *data;

	data = *data_p;
	len = 0;
	com_token[0] = 0;
	
	if (!data)
	{
		*data_p = NULL;
		return "";
	}
		
// skip whitespace
skipwhite:
	while ( (c = *data) <= ' ')
	{
#ifdef SIN
      if (c == '\n' && !crossline)
         {
         *data_p = data;
         return "";
         }
#endif
		if (c == 0)
		{
			*data_p = NULL;
			return "";
		}
		data++;
	}
	
// skip // comments
	if (c=='/' && data[1] == '/')
	{
		while (*data && *data != '\n')
			data++;
		goto skipwhite;
	}

// skip /* comments
	if (c=='/' && data[1] == '*')
	   {
      data++;
      while (*data)
         {
         if ( (*(data-1)=='*') && (*data == '/') )
            break;
         data++;
         }
		while (*data && *data != '\n')
			data++;
		goto skipwhite;
	   }
	

// handle quoted strings specially
	if (c == '\"')
	{
		data++;
		while (1)
		{
			c = *data++;
         if (c == '\\' && *data == '\"')
            {
			   if (len < MAX_STRING_CHARS)
			      {
				   com_token[len] = '\"';
				   len++;
			      }
            data++;
            }
			else if (c=='\"' || !c)
			{
				com_token[len] = 0;
				*data_p = data;
				return com_token;
			}
         else if (len < MAX_STRING_CHARS)
			{
            com_token[len] = c;
				len++;
			}
		}
	}

// parse a regular word
	do
	{
		if (len < MAX_STRING_CHARS)
		{
			com_token[len] = c;
			len++;
		}
		data++;
		c = *data;
	} while (c>32);

	if (len == MAX_STRING_CHARS)
	{
//		Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
		len = 0;
	}
	com_token[len] = 0;

	*data_p = data;
	return com_token;
}


const char *SIN_Parse (const char **data_p)
   {
   return SIN_GetToken( data_p, true );
   }
#endif

/*
==============
COM_Parse

Parse a token out of a string
==============
*/
#ifdef SIN
const char *COM_Parse (const char **data_p)
#else
char *COM_Parse (char **data_p)
#endif
{
   return COM_GetToken( data_p, true );
}
#else
/*
==============
COM_Parse

Parse a token out of a string
==============
*/
char *COM_Parse (char **data_p)
{
	int		c;
	int		len;
	char	*data;

	data = *data_p;
	len = 0;
	com_token[0] = 0;
	
	if (!data)
	{
		*data_p = NULL;
		return "";
	}
		
// skip whitespace
skipwhite:
	while ( (c = *data) <= ' ')
	{
		if (c == 0)
		{
			*data_p = NULL;
			return "";
		}
		data++;
	}
	
// skip // comments
	if (c=='/' && data[1] == '/')
	{
		while (*data && *data != '\n')
			data++;
		goto skipwhite;
	}
	

// handle quoted strings specially
	if (c == '\"')
	{
		data++;
		while (1)
		{
			c = *data++;
			if (c=='\"' || !c)
			{
				com_token[len] = 0;
				*data_p = data;
				return com_token;
			}
			if (len < MAX_TOKEN_CHARS)
			{
				com_token[len] = c;
				len++;
			}
		}
	}

// parse a regular word
	do
	{
		if (len < MAX_TOKEN_CHARS)
		{
			com_token[len] = c;
			len++;
		}
		data++;
		c = *data;
	} while (c>32);

	if (len == MAX_TOKEN_CHARS)
	{
//		Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
		len = 0;
	}
	com_token[len] = 0;

	*data_p = data;
	return com_token;
}
#endif


/*
===============
Com_PageInMemory

===============
*/
static int paged_total;

void Com_PageInMemory (byte *buffer, int size)
{
	int		i;

	for (i=size-1 ; i>0 ; i-=4096)
		paged_total += buffer[i];
}


/*
============================================================================

					LIBRARY REPLACEMENT FUNCTIONS

============================================================================
*/

// FIXME: replace all Q_stricmp with Q_strcasecmp
int Q_stricmp (const char *s1, const char *s2)
{
#if defined(_WIN32)
	return _stricmp (s1, s2);
#elif defined(__DJGPP__)
	return stricmp (s1, s2);
#else
	return strcasecmp (s1, s2);
#endif
}

int Q_strncasecmp (char *s1, char *s2, int n)
{
	int		c1, c2;

	do
	{
		c1 = *s1++;
		c2 = *s2++;

		if (!n--)
			return 0;		// strings are equal until end point

		if (c1 != c2)
		{
			if (c1 >= 'a' && c1 <= 'z')
				c1 -= ('a' - 'A');
			if (c2 >= 'a' && c2 <= 'z')
				c2 -= ('a' - 'A');
			if (c1 != c2)
				return -1;		// strings not equal
		}
	} while (c1);

	return 0;		// strings are equal
}

int Q_strcasecmp (char *s1, char *s2)
{
	return Q_strncasecmp (s1, s2, 99999);
}

/* FS: From KMQ2 */
/*
=================
Q_strncpyz

Safe strncpy that ensures a trailing zero
=================
*/
void Q_strncpyz (char *dst, const char *src, int dstSize)
{
	if (!dst) {
	//	Com_Error (ERR_FATAL, "Q_strncpyz: NULL dst");
	//	Com_Printf ("Q_strncpyz: NULL dst\n");
		return;
	}
	if (!src) {
	//	Com_Error (ERR_FATAL, "Q_strncpyz: NULL src");
	//	Com_Printf ("Q_strncpyz: NULL src\n");
		return;
	}
	if (dstSize < 1) {
	//	Com_Error (ERR_FATAL, "Q_strncpyz: dstSize < 1");
	//	Com_Printf ("Q_strncpyz: dstSize < 1\n");
		return;
	}

	strncpy(dst, src, dstSize-1);
	dst[dstSize-1] = 0;
}

/*
=================
Q_strncatz

Safe strncat that ensures a trailing zero
=================
*/
void Q_strncatz (char *dst, const char *src, int dstSize)
{
	if (!dst) {
	//	Com_Error (ERR_FATAL, "Q_strncatz: NULL dst");
	//	Com_Printf ("Q_strncatz: NULL dst\n");
		return;
	}
	if (!src) {
	//	Com_Error (ERR_FATAL, "Q_strncatz: NULL src");
	//	Com_Printf ("Q_strncatz: NULL src\n");
		return;
	}
	if (dstSize < 1) {
	//	Com_Error (ERR_FATAL, "Q_strncatz: dstSize < 1");
	//	Com_Printf ("Q_strncatz: dstSize < 1\n");
		return;
	}

	while (--dstSize && *dst)
		dst++;

	if (dstSize > 0){
		while (--dstSize && *src)
			*dst++ = *src++;

		*dst = 0;
	}
}

char *Q_strlwr (char *string)
{
	char	*s = string;

	while (*s) {
		*s = tolower(*s);
		s++;
	}
	return string;
}

char *Q_strupr (char *string)
{
	char	*s = string;

	while (*s) {
		*s = toupper(*s);
		s++;
	}
	return string;
}

#if defined(__DJGPP__) || defined(_WIN32)
char * /* from OpenBSD */
strtok_r(char *s, const char *delim, char **last)
{
	const char *spanp;
	int c, sc;
	char *tok;

	if (s == NULL && (s = *last) == NULL)
		return (NULL);

	/*
	 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
	 */
cont:
	c = *s++;
	for (spanp = delim; (sc = *spanp++) != 0;) {
		if (c == sc)
			goto cont;
	}

	if (c == 0) {		/* no non-delimiter characters */
		*last = NULL;
		return (NULL);
	}
	tok = s - 1;

	/*
	 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
	 * Note that delim must have one NUL; we stop if we see that, too.
	 */
	for (;;) {
		c = *s++;
		spanp = delim;
		do {
			if ((sc = *spanp++) == c) {
				if (c == 0)
					s = NULL;
				else
					s[-1] = '\0';
				*last = s;
				return (tok);
			}
		} while (sc != 0);
	}
	/* NOTREACHED */
}
#endif

void Com_sprintf (char *dest, int size, const char *fmt, ...)
{
	char bigbuffer[32000];		/* You've go to be kidding... */
	int len;
	va_list argptr;

	va_start (argptr,fmt);
	len = vsprintf (bigbuffer,fmt,argptr);
	va_end (argptr);
	if (len >= size)
	{
		Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
	}
	strncpy (dest, bigbuffer, size-1);
}

/*
=====================================================================

  INFO STRINGS

=====================================================================
*/

/*
===============
Info_ValueForKey

Searches the string for the given
key and returns the associated value, or an empty string.
===============
*/
#ifdef SIN
const char *Info_ValueForKey (const char *s, const char *key)
#else
char *Info_ValueForKey (char *s, char *key)
#endif
{
	char	pkey[512];
	static	char value[2][512];	// use two buffers so compares
								// work without stomping on each other
	static	int	valueindex;
	char	*o;
	
	valueindex ^= 1;
	if (*s == '\\')
		s++;
	while (1)
	{
		o = pkey;
		while (*s != '\\')
		{
			if (!*s)
				return "";
			*o++ = *s++;
		}
		*o = 0;
		s++;

		o = value[valueindex];

		while (*s != '\\' && *s)
		{
			if (!*s)
				return "";
			*o++ = *s++;
		}
		*o = 0;

		if (!strcmp (key, pkey) )
			return value[valueindex];

		if (!*s)
			return "";
		s++;
	}
}

#ifdef SIN
void Info_RemoveKey (char *s, const char *key)
#else
void Info_RemoveKey (char *s, char *key)
#endif
{
	char	*start;
	char	pkey[512];
	char	value[512];
	char	*o;

	if (strstr (key, "\\"))
	{
//		Com_Printf ("Can't use a key with a \\\n");
		return;
	}

	while (1)
	{
		start = s;
		if (*s == '\\')
			s++;
		o = pkey;
		while (*s != '\\')
		{
			if (!*s)
				return;
			*o++ = *s++;
		}
		*o = 0;
		s++;

		o = value;
		while (*s != '\\' && *s)
		{
			if (!*s)
				return;
			*o++ = *s++;
		}
		*o = 0;

		if (!strcmp (key, pkey) )
		{
			strcpy (start, s);	// remove this part
			return;
		}

		if (!*s)
			return;
	}

}

/*
==================
Info_Validate

Some characters are illegal in info strings because they
can mess up the server's parsing
==================
*/
#ifdef SIN
qboolean Info_Validate (const char *s)
#else
qboolean Info_Validate (char *s)
#endif
{
	if (strstr (s, "\""))
		return false;
	if (strstr (s, ";"))
		return false;
	return true;
}

#ifdef SIN
void Info_SetValueForKey (char *s, const char *key, const char *value)
#else
void Info_SetValueForKey (char *s, char *key, char *value)
#endif
{
	char	newi[MAX_INFO_STRING], *v;
	int		c;
	int		maxsize = MAX_INFO_STRING;

	if (strstr (key, "\\") || strstr (value, "\\") )
	{
		Com_Printf ("Can't use keys or values with a \\\n");
		return;
	}

	if (strstr (key, ";") )
	{
		Com_Printf ("Can't use keys or values with a semicolon\n");
		return;
	}

	if (strstr (key, "\"") || strstr (value, "\"") )
	{
		Com_Printf ("Can't use keys or values with a \"\n");
		return;
	}

	if (strlen(key) > MAX_INFO_KEY-1 || strlen(value) > MAX_INFO_KEY-1)
	{
		Com_Printf ("Keys and values must be < 64 characters.\n");
		return;
	}
	Info_RemoveKey (s, key);
	if (!value || !strlen(value))
		return;

	Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);

	if (strlen(newi) + strlen(s) > maxsize)
	{
		Com_Printf ("Info string length exceeded\n");
		return;
	}

	// only copy ascii values
	s += strlen(s);
	v = newi;
	while (*v)
	{
		c = *v++;
		c &= 127;		// strip high bits
		if (c >= 32 && c < 127)
			*s++ = c;
	}
	*s = 0;
}

//====================================================================


void MatrixTransformVector
	(
	vec3_t in,
	float mat[ 3 ][ 3 ],
	vec3_t out
	)

	{
	out[ 0 ] = in[ 0 ] * mat[ 0 ][ 0 ] + in[ 1 ] * mat[ 1 ][ 0 ] + in[ 2 ] * mat[ 2 ][ 0 ];
	out[ 1 ] = in[ 0 ] * mat[ 0 ][ 1 ] + in[ 1 ] * mat[ 1 ][ 1 ] + in[ 2 ] * mat[ 2 ][ 1 ];
	out[ 2 ] = in[ 0 ] * mat[ 0 ][ 2 ] + in[ 1 ] * mat[ 1 ][ 2 ] + in[ 2 ] * mat[ 2 ][ 2 ];
	}

void Matrix4TransformVector
	(
	vec3_t in,
	float mat[ 4 ][ 4 ],
	vec3_t out
	)

	{
	out[ 0 ] = in[ 0 ] * mat[ 0 ][ 0 ] + in[ 1 ] * mat[ 1 ][ 0 ] + in[ 2 ] * mat[ 2 ][ 0 ] + mat[ 3 ][ 0 ];
	out[ 1 ] = in[ 0 ] * mat[ 0 ][ 1 ] + in[ 1 ] * mat[ 1 ][ 1 ] + in[ 2 ] * mat[ 2 ][ 1 ] + mat[ 3 ][ 1 ];
	out[ 2 ] = in[ 0 ] * mat[ 0 ][ 2 ] + in[ 1 ] * mat[ 1 ][ 2 ] + in[ 2 ] * mat[ 2 ][ 2 ] + mat[ 3 ][ 2 ];
	}

void VectorsToEulerAngles
	(
	vec3_t forward,
	vec3_t right,
	vec3_t up,
	vec3_t ang
	)

	{
	double theta;
	double cp;
	double sp;

	sp = forward[ 2 ];

	// cap off our sin value so that we don't get any NANs
	if ( sp > 1.0 )
		{
		sp = 1.0;
		}
	if ( sp < -1.0 )
		{
		sp = -1.0;
		}

	theta = -asin( sp );
	cp = cos( theta );

	if ( cp > 8192 * FLT_EPSILON )
		{
		ang[ 0 ] = theta * 180 / M_PI;
		ang[ 1 ] = atan2( forward[ 1 ], forward[ 0 ] ) * 180 / M_PI;
		ang[ 2 ] = atan2( -right[ 2 ], up[ 2 ] ) * 180 / M_PI;
		}
	else
		{
		ang[ 0 ] = theta * 180 / M_PI;
		ang[ 1 ] = -atan2( right[ 0 ], right[ 1 ] ) * 180 / M_PI;
		ang[ 2 ] = 0;
		}
	}

void MatrixToEulerAngles
	(
	float mat[ 3 ][ 3 ],
	vec3_t ang
	)

	{
	double theta;
	double cp;
	double sp;

	sp = mat[ 0 ][ 2 ];

	// cap off our sin value so that we don't get any NANs
	if ( sp > 1.0 )
		{
		sp = 1.0;
		}
	if ( sp < -1.0 )
		{
		sp = -1.0;
		}

	theta = -asin( sp );
	cp = cos( theta );

	if ( cp > 8192 * FLT_EPSILON )
		{
		ang[ 0 ] = theta * 180 / M_PI;
		ang[ 1 ] = atan2( mat[ 0 ][ 1 ], mat[ 0 ][ 0 ] ) * 180 / M_PI;
		ang[ 2 ] = atan2( mat[ 1 ][ 2 ], mat[ 2 ][ 2 ] ) * 180 / M_PI;
		}
	else
		{
		ang[ 0 ] = theta * 180 / M_PI;
		ang[ 1 ] = -atan2( mat[ 1 ][ 0 ], mat[ 1 ][ 1 ] ) * 180 / M_PI;
		ang[ 2 ] = 0;
		}
	}

void TransposeMatrix
	(
	float in[ 3 ][ 3 ],
	float out[ 3 ][ 3 ]
	)

	{
	out[ 0 ][ 0 ] = in[ 0 ][ 0 ];
	out[ 0 ][ 1 ] = in[ 1 ][ 0 ];
	out[ 0 ][ 2 ] = in[ 2 ][ 0 ];
	out[ 1 ][ 0 ] = in[ 0 ][ 1 ];
	out[ 1 ][ 1 ] = in[ 1 ][ 1 ];
	out[ 1 ][ 2 ] = in[ 2 ][ 1 ];
	out[ 2 ][ 0 ] = in[ 0 ][ 2 ];
	out[ 2 ][ 1 ] = in[ 1 ][ 2 ];
	out[ 2 ][ 2 ] = in[ 2 ][ 2 ];
	}

void OrthoNormalize
	(
	float mat[3][3]
	)

	{
	VectorNormalize( mat[ 0 ] );
	CrossProduct( mat[ 0 ], mat[ 1 ], mat[ 2 ] );
	VectorNormalize( mat[ 2 ] );
	CrossProduct( mat[ 2 ], mat[ 0 ], mat[ 1 ] );
	VectorNormalize( mat[ 1 ] );
	}

float NormalizeQuat(float q[ 4 ])
{
	float	length, ilength;

	length = q[ 0 ] * q[ 0 ] + q[ 1 ] * q[ 1 ] + q[ 2 ] * q[ 2 ] + q[ 3 ] * q[ 3 ];
	length = sqrt( length );

	if ( length )
	{
		ilength = 1 / length;
		q[ 0 ] *= ilength;
		q[ 1 ] *= ilength;
		q[ 2 ] *= ilength;
		q[ 3 ] *= ilength;
	}
		
	return length;
}

void MatToQuat(const float srcMatrix[ 3 ][ 3 ], float destQuat[ 4 ])
{
	double  	trace, s;
	int     	i, j, k;
	static int 	next[3] = {Y, Z, X};

	trace = srcMatrix[X][X] + srcMatrix[Y][Y]+ srcMatrix[Z][Z];

	if (trace > 0.0)
		{
		s = sqrt(trace + 1.0);
		destQuat[W] = s * 0.5;
		s = 0.5 / s;
    
		destQuat[X] = (srcMatrix[Z][Y] - srcMatrix[Y][Z]) * s;
		destQuat[Y] = (srcMatrix[X][Z] - srcMatrix[Z][X]) * s;
		destQuat[Z] = (srcMatrix[Y][X] - srcMatrix[X][Y]) * s;
		} 
	else 
		{
		i = X;
		if (srcMatrix[Y][Y] > srcMatrix[X][X])
			i = Y;
		if (srcMatrix[Z][Z] > srcMatrix[i][i])
			i = Z;
		j = next[i];  
		k = next[j];
    
		s = sqrt( (srcMatrix[i][i] - (srcMatrix[j][j]+srcMatrix[k][k])) + 1.0 );
		destQuat[i] = s * 0.5;
    
		s = 0.5 / s;
    
		destQuat[W] = (srcMatrix[k][j] - srcMatrix[j][k]) * s;
		destQuat[j] = (srcMatrix[j][i] + srcMatrix[i][j]) * s;
		destQuat[k] = (srcMatrix[k][i] + srcMatrix[i][k]) * s;
		}
	}

void AnglesToMat(const float ang[ 3 ],float mat[ 3 ][ 3 ])
{
	AngleVectors( ang, mat[ 0 ], mat[ 1 ], mat[ 2 ] );
	VectorNegate( mat[ 1 ], mat[ 1 ] );
}

void RotateAxis(float axis[ 3 ],float angle,float q[ 4 ])
{
	float sin_a;
	float inv_sin_a;
	float cos_a;
	float r;

	r = angle * M_PI / 360;
	
	sin_a = sin( r );
	if ( fabs( sin_a ) > 0.00000001 )
	{
		inv_sin_a = 1 / sin_a;
	}
	else
	{
		inv_sin_a = 0;
	}
	cos_a = cos( r );

	q[ X ] = axis[ 0 ] * inv_sin_a;
	q[ Y ] = axis[ 1 ] * inv_sin_a;
	q[ Z ] = axis[ 2 ] * inv_sin_a;
	q[ W ] = cos_a;
}

void MultQuat(float q1[ 4 ],float q2[ 4 ],float out[ 4 ])
{
	out[ 0 ] = q1[X]*q2[X] - q1[Y]*q2[Y] - q1[Z]*q2[Z] - q1[W]*q2[W];
	out[ 1 ] = q1[X]*q2[Y] + q1[Y]*q2[X] + q1[Z]*q2[W] - q1[W]*q2[Z];
	out[ 2 ] = q1[X]*q2[Z] - q1[Y]*q2[W] + q1[Z]*q2[X] + q1[W]*q2[Y];
	out[ 3 ] = q1[X]*q2[W] + q1[Y]*q2[Z] - q1[Z]*q2[Y] + q1[W]*q2[X];
}

void QuatToMat(float q[ 4 ],float m[ 3 ][ 3 ])
{
	float wx, wy, wz;
	float xx, yy, yz;
	float xy, xz, zz;
	float x2, y2, z2;

	x2 = q[ X ] + q[ X ];
	y2 = q[ Y ] + q[ Y ];
	z2 = q[ Z ] + q[ Z ];

	xx = q[ X ] * x2;
	xy = q[ X ] * y2;
	xz = q[ X ] * z2;

	yy = q[ Y ] * y2;
	yz = q[ Y ] * z2;
	zz = q[ Z ] * z2;

	wx = q[ W ] * x2;
	wy = q[ W ] * y2;
	wz = q[ W ] * z2;

	m[ 0 ][ 0 ] = 1.0 - ( yy + zz );
	m[ 0 ][ 1 ] = xy - wz;
	m[ 0 ][ 2 ] = xz + wy;

	m[ 1 ][ 0 ] = xy + wz;
	m[ 1 ][ 1 ] = 1.0 - ( xx + zz );
	m[ 1 ][ 2 ] = yz - wx;

	m[ 2 ][ 0 ] = xz - wy;
	m[ 2 ][ 1 ] = yz + wx;
	m[ 2 ][ 2 ] = 1.0 - ( xx + yy );
}

#define DELTA 1e-6

void SlerpQuaternion(float from[ 4 ],float to[ 4 ],float t,float res[ 4 ])
{
	float		to1[ 4 ];
	double	omega, cosom, sinom, scale0, scale1;
	
	cosom = from[ X ] * to[ X ] + from[ Y ] * to[ Y ] + from[ Z ] * to[ Z ] + from[ W ] * to [ W ];
	if ( cosom < 0.0 )
	{
		cosom = -cosom;
		to1[ X ] = -to[ X ];
		to1[ Y ] = -to[ Y ];
		to1[ Z ] = -to[ Z ];
		to1[ W ] = -to[ W ];
	}	
	else if 
		(
		( from[ X ] == to[ X ] ) &&
		( from[ Y ] == to[ Y ] ) &&
		( from[ Z ] == to[ Z ] ) &&
		( from[ W ] == to[ W ] ) 
		)
		{
			// equal case, early exit
			res[ X ] = to[ X ];
			res[ Y ] = to[ Y ];
			res[ Z ] = to[ Z ];
			res[ W ] = to[ W ];
			return;
	}
	else
	{
		to1[ X ] = to[ X ];
		to1[ Y ] = to[ Y ];
		to1[ Z ] = to[ Z ];
		to1[ W ] = to[ W ];
	}

	if ( ( 1.0 - cosom ) > DELTA )
	{
		omega = acos( cosom );
		sinom = sin( omega );
		scale0 = sin( ( 1.0 - t ) * omega ) / sinom;
		scale1 = sin( t * omega ) / sinom;
	}
	else
	{
		scale0 = 1.0 - t;
		scale1 = t;
	}
	res[ X ] = scale0 * from[ X ] + scale1 * to1[ X ];
	res[ Y ] = scale0 * from[ Y ] + scale1 * to1[ Y ];
	res[ Z ] = scale0 * from[ Z ] + scale1 * to1[ Z ];
	res[ W ] = scale0 * from[ W ] + scale1 * to1[ W ];
}

void EulerToQuat(const float ang[ 3 ],float q[ 4 ])
{
	float mat[ 3 ][ 3 ];
	AnglesToMat( ang, mat );
	MatToQuat( mat, q );
}

float Sinatof(const char *text)
{
	if (text && text[0]) {
		return atof(text);
	}
	return 0;
}

long Com_HashFileName (const char *fname, int hashSize, qboolean sized)
{
	int		i = 0;
	long	hash = 0;
	char	letter;

	if (fname[0] == '/' || fname[0] == '\\') i++;	// skip leading slash
	while (fname[i] != '\0')
	{
		letter = tolower(fname[i]);
	//	if (letter == '.') break;
		if (letter == '\\') letter = '/';	// fix filepaths
		hash += (long)(letter)*(i+119);
		i++;
	}
	hash = (hash ^ (hash >> 10) ^ (hash >> 20));
	if (sized) {
		hash &= (hashSize-1);
	}
	return hash;
}

void *AllocClear (size_t size)
{
	void *ptr = malloc(size);
	memset(ptr, 0, size);

	return ptr;
}

void Free (void *ptr)
{
	if(ptr)
	{
		free(ptr);
	}
}
