text:
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//

#ifndef MATH_LIB_H
#define MATH_LIB_H

#include <math.h>
#include "tier0/basetypes.h"
#include "mathlib/vector.h"
#include "mathlib/vector2d.h"
#include "tier0/dbg.h"

#include "mathlib/math_pfns.h"
#ifndef ALIGN8_POST
#define ALIGN8_POST
#endif
// plane_t structure
// !!! if this is changed, it must be changed in asm code too !!!
// FIXME: does the asm code even exist anymore?
// FIXME: this should move to a different file
struct cplane_t
{
	Vector	normal;
	float	dist;
	byte	type;			// for fast side tests
	byte	signbits;		// signx + (signy<<1) + (signz<<1)
	byte	pad[2];

#ifdef VECTOR_NO_SLOW_OPERATIONS
	cplane_t() {}

private:
	// No copy constructors allowed if we're in optimal mode
	cplane_t(const cplane_t& vOther);
#endif
};

// structure offset for asm code
#define CPLANE_NORMAL_X			0
#define CPLANE_NORMAL_Y			4
#define CPLANE_NORMAL_Z			8
#define CPLANE_DIST				12
#define CPLANE_TYPE				16
#define CPLANE_SIGNBITS			17
#define CPLANE_PAD0				18
#define CPLANE_PAD1				19

// 0-2 are axial planes
#define	PLANE_X			0
#define	PLANE_Y			1
#define	PLANE_Z			2

// 3-5 are non-axial planes snapped to the nearest
#define	PLANE_ANYX		3
#define	PLANE_ANYY		4
#define	PLANE_ANYZ		5

//-----------------------------------------------------------------------------
// Frustum plane indices.
// WARNING: there is code that depends on these values
//-----------------------------------------------------------------------------

enum
{
	FRUSTUM_RIGHT		= 0,
	FRUSTUM_LEFT		= 1,
	FRUSTUM_TOP			= 2,
	FRUSTUM_BOTTOM		= 3,
	FRUSTUM_NEARZ		= 4,
	FRUSTUM_FARZ		= 5,
	FRUSTUM_NUMPLANES	= 6
};

extern int SignbitsForPlane( cplane_t *out );
class Frustum_t;

// Computes Y fov from an X fov and a screen aspect ratio + X from Y
float CalcFovY( float flFovX, float flScreenAspect );
float CalcFovX( float flFovY, float flScreenAspect );

// Generate a frustum based on perspective view parameters
// NOTE: FOV is specified in degrees, as the *full* view angle (not half-angle)
class VPlane;
void GeneratePerspectiveFrustum( const Vector& origin, const QAngle &angles, float flZNear, float flZFar, float flFovX, float flAspectRatio, Frustum_t &frustum );
void GeneratePerspectiveFrustum( const Vector& origin, const Vector &forward, const Vector &right, const Vector &up, float flZNear, float flZFar, float flFovX, float flFovY, VPlane *pPlanesOut );
// Cull the world-space bounding box to the specified frustum.
// bool R_CullBox( const Vector& mins, const Vector& maxs, const Frustum_t &frustum );
// bool R_CullBoxSkipNear( const Vector& mins, const Vector& maxs, const Frustum_t &frustum );
void GenerateOrthoFrustum( const Vector &origin, const Vector &forward, const Vector &right, const Vector &up, float flLeft, float flRight, float flBottom, float flTop, float flZNear, float flZFar, VPlane *pPlanesOut );

class matrix3x4a_t;

struct matrix3x4_t
{
	matrix3x4_t() {}
	matrix3x4_t(
		float m00, float m01, float m02, float m03,
		float m10, float m11, float m12, float m13,
		float m20, float m21, float m22, float m23 )
	{
		m_flMatVal[0][0] = m00;	m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03;
		m_flMatVal[1][0] = m10;	m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13;
		m_flMatVal[2][0] = m20;	m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23;
	}

	//-----------------------------------------------------------------------------
	// Creates a matrix where the X axis = forward
	// the Y axis = left, and the Z axis = up
	//-----------------------------------------------------------------------------
	void Init( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
	{
		m_flMatVal[0][0] = xAxis.x; m_flMatVal[0][1] = yAxis.x; m_flMatVal[0][2] = zAxis.x; m_flMatVal[0][3] = vecOrigin.x;
		m_flMatVal[1][0] = xAxis.y; m_flMatVal[1][1] = yAxis.y; m_flMatVal[1][2] = zAxis.y; m_flMatVal[1][3] = vecOrigin.y;
		m_flMatVal[2][0] = xAxis.z; m_flMatVal[2][1] = yAxis.z; m_flMatVal[2][2] = zAxis.z; m_flMatVal[2][3] = vecOrigin.z;
	}

	//-----------------------------------------------------------------------------
	// Creates a matrix where the X axis = forward
	// the Y axis = left, and the Z axis = up
	//-----------------------------------------------------------------------------
	matrix3x4_t( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin )
	{
		Init( xAxis, yAxis, zAxis, vecOrigin );
	}

	inline void SetOrigin( Vector const & p )
	{
		m_flMatVal[0][3] = p.x;
		m_flMatVal[1][3] = p.y;
		m_flMatVal[2][3] = p.z;
	}

	inline void Invalidate( void )
	{
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				m_flMatVal[i][j] = VEC_T_NAN;
			}
		}
	}

	float *operator[]( int i )				{ Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; }
	const float *operator[]( int i ) const	{ Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; }
	float *Base()							{ return &m_flMatVal[0][0]; }
	const float *Base() const				{ return &m_flMatVal[0][0]; }

	float m_flMatVal[3][4];
};

class ALIGN16 matrix3x4a_t : public matrix3x4_t
{
public:
	/*
	matrix3x4a_t() { if (((size_t)Base()) % 16 != 0) { Error( "matrix3x4a_t missaligned" ); } }
	*/
	matrix3x4a_t& operator=( const matrix3x4_t& src ) { memcpy( Base(), src.Base(), sizeof( float ) * 3 * 4 ); return *this; };
};

#ifndef M_PI
	#define M_PI		3.14159265358979323846	// matches value in gcc v2 math.h
#endif

#define M_PI_F		((float)(M_PI))	// Shouldn't collide with anything.

// NJS: Inlined to prevent floats from being autopromoted to doubles, as with the old system.
#ifndef RAD2DEG
	#define RAD2DEG( x  )  ( (float)(x) * (float)(180.f / M_PI_F) )
#endif

#ifndef DEG2RAD
	#define DEG2RAD( x  )  ( (float)(x) * (float)(M_PI_F / 180.f) )
#endif

// Used to represent sides of things like planes.
#define	SIDE_FRONT	0
#define	SIDE_BACK	1
#define	SIDE_ON		2
#define SIDE_CROSS  -2      // necessary for polylib.c

#define ON_VIS_EPSILON  0.01    // necessary for vvis (flow.c) -- again look into moving later!
#define	EQUAL_EPSILON	0.001   // necessary for vbsp (faces.c) -- should look into moving it there?

extern bool s_bMathlibInitialized;

extern  const Vector vec3_origin;
extern  const QAngle vec3_angle;
extern	const Quaternion quat_identity;
extern const Vector vec3_invalid;
extern	const int nanmask;

#define	IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)

FORCEINLINE vec_t DotProduct(const vec_t *v1, const vec_t *v2)
{
	return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
FORCEINLINE void VectorSubtract(const vec_t *a, const vec_t *b, vec_t *c)
{
	c[0]=a[0]-b[0];
	c[1]=a[1]-b[1];
	c[2]=a[2]-b[2];
}
FORCEINLINE void VectorAdd(const vec_t *a, const vec_t *b, vec_t *c)
{
	c[0]=a[0]+b[0];
	c[1]=a[1]+b[1];
	c[2]=a[2]+b[2];
}
FORCEINLINE void VectorCopy(const vec_t *a, vec_t *b)
{
	b[0]=a[0];
	b[1]=a[1];
	b[2]=a[2];
}
FORCEINLINE void VectorClear(vec_t *a)
{
	a[0]=a[1]=a[2]=0;
}

FORCEINLINE float VectorMaximum(const vec_t *v)
{
	return MAX( v[0], MAX( v[1], v[2] ) );
}

FORCEINLINE float VectorMaximum(const Vector& v)
{
	return MAX( v.x, MAX( v.y, v.z ) );
}

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

// Cannot be forceinline as they have overloads:
inline void VectorFill(vec_t *a, float b)
{
	a[0]=a[1]=a[2]=b;
}

inline void VectorNegate(vec_t *a)
{
	a[0]=-a[0];
	a[1]=-a[1];
	a[2]=-a[2];
}

//#define VectorMaximum(a)		( max( (a)[0], max( (a)[1], (a)[2] ) ) )
#define Vector2Clear(x)			{(x)[0]=(x)[1]=0;}
#define Vector2Negate(x)		{(x)[0]=-((x)[0]);(x)[1]=-((x)[1]);}
#define Vector2Copy(a,b)		{(b)[0]=(a)[0];(b)[1]=(a)[1];}
#define Vector2Subtract(a,b,c)	{(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];}
#define Vector2Add(a,b,c)		{(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];}
#define Vector2Scale(a,b,c)		{(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];}

// NJS: Some functions in VBSP still need to use these for dealing with mixing vec4's and shorts with vec_t's.
// remove when no longer needed.
#define VECTOR_COPY( A, B ) do { (B)[0] = (A)[0]; (B)[1] = (A)[1]; (B)[2]=(A)[2]; } while(0)
#define DOT_PRODUCT( A, B ) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] )

FORCEINLINE void VectorMAInline( const float* start, float scale, const float* direction, float* dest )
{
	dest[0]=start[0]+direction[0]*scale;
	dest[1]=start[1]+direction[1]*scale;
	dest[2]=start[2]+direction[2]*scale;
}

FORCEINLINE void VectorMAInline( const Vector& start, float scale, const Vector& direction, Vector& dest )
{
	dest.x=start.x+direction.x*scale;
	dest.y=start.y+direction.y*scale;
	dest.z=start.z+direction.z*scale;
}

FORCEINLINE void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest )
{
	VectorMAInline(start, scale, direction, dest);
}

FORCEINLINE void VectorMA( const float * start, float scale, const float *direction, float *dest )
{
	VectorMAInline(start, scale, direction, dest);
}

int VectorCompare (const float *v1, const float *v2);

inline float VectorLength(const float *v)
{
	return FastSqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + FLT_EPSILON );
}

void CrossProduct (const float *v1, const float *v2, float *cross);

qboolean VectorsEqual( const float *v1, const float *v2 );

inline vec_t RoundInt (vec_t in)
{
	return floor(in + 0.5f);
}

size_t Q_log2( unsigned int val );

// Math routines done in optimized assembly math package routines
void inline SinCos( float radians, float *sine, float *cosine )
{
#if defined( _X360 )
	XMScalarSinCos( sine, cosine, radians );
#elif defined( COMPILER_MSVC32 )
	_asm
	{
		fld		DWORD PTR [radians]
		fsincos

		mov edx, DWORD PTR [cosine]
		mov eax, DWORD PTR [sine]

		fstp DWORD PTR [edx]
		fstp DWORD PTR [eax]
	}
#elif defined( GNUC )
	register double __cosr, __sinr;
 	__asm __volatile__ ("fsincos" : "=t" (__cosr), "=u" (__sinr) : "0" (radians));

  	*sine = __sinr;
  	*cosine = __cosr;
#else
	*sine = sinf(radians);
	*cosine = cosf(radians);
#endif
}

#define SIN_TABLE_SIZE	256
#define FTOIBIAS		12582912.f
extern float SinCosTable[SIN_TABLE_SIZE];

inline float TableCos( float theta )
{
	union
	{
		int i;
		float f;
	} ftmp;

	// ideally, the following should compile down to: theta * constant + constant, changing any of these constants from defines sometimes fubars this.
	ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + ( FTOIBIAS + ( SIN_TABLE_SIZE / 4 ) );
	return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ];
}

inline float TableSin( float theta )
{
	union
	{
		int i;
		float f;
	} ftmp;

	// ideally, the following should compile down to: theta * constant + constant
	ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + FTOIBIAS;
	return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ];
}

template<class T>
FORCEINLINE T Square( T const &a )
{
	return a * a;
}

// return the smallest power of two >= x.
// returns 0 if x == 0 or x > 0x80000000 (ie numbers that would be negative if x was signed)
// NOTE: the old code took an int, and if you pass in an int of 0x80000000 casted to a uint,
//       you'll get 0x80000000, which is correct for uints, instead of 0, which was correct for ints
FORCEINLINE uint SmallestPowerOfTwoGreaterOrEqual( uint x )
{
	x -= 1;
	x |= x >> 1;
	x |= x >> 2;
	x |= x >> 4;
	x |= x >> 8;
	x |= x >> 16;
	return x + 1;
}

// return the largest power of two <= x. Will return 0 if passed 0
FORCEINLINE uint LargestPowerOfTwoLessThanOrEqual( uint x )
{
	if ( x >= 0x80000000 )
		return 0x80000000;

	return SmallestPowerOfTwoGreaterOrEqual( x + 1 ) >> 1;
}

// Math routines for optimizing division
void FloorDivMod (double numer, double denom, int *quotient, int *rem);
int GreatestCommonDivisor (int i1, int i2);

// Test for FPU denormal mode
bool IsDenormal( const float &val );

// MOVEMENT INFO
enum
{
	PITCH = 0,	// up / down
	YAW,		// left / right
	ROLL		// fall over
};

void MatrixAngles( const matrix3x4_t & matrix, float *angles ); // !!!!
void MatrixVectors( const matrix3x4_t &matrix, Vector* pForward, Vector *pRight, Vector *pUp );
void VectorTransform (const float *in1, const matrix3x4_t & in2, float *out);
void VectorITransform (const float *in1, const matrix3x4_t & in2, float *out);
void VectorRotate( const float *in1, const matrix3x4_t & in2, float *out);
void VectorRotate( const Vector &in1, const QAngle &in2, Vector &out );
void VectorRotate( const Vector &in1, const Quaternion &in2, Vector &out );
void VectorIRotate( const float *in1, const matrix3x4_t & in2, float *out);

#ifndef VECTOR_NO_SLOW_OPERATIONS

QAngle TransformAnglesToLocalSpace( const QAngle &angles, const matrix3x4_t &parentMatrix );
QAngle TransformAnglesToWorldSpace( const QAngle &angles, const matrix3x4_t &parentMatrix );

#endif

void MatrixInitialize( matrix3x4_t &mat, const Vector &vecOrigin, const Vector &vecXAxis, const Vector &vecYAxis, const Vector &vecZAxis );
void MatrixCopy( const matrix3x4_t &in, matrix3x4_t &out );
void MatrixInvert( const matrix3x4_t &in, matrix3x4_t &out );

// Matrix equality test
bool MatricesAreEqual( const matrix3x4_t &src1, const matrix3x4_t &src2, float flTolerance = 1e-5 );

void MatrixGetColumn( const matrix3x4_t &in, int column, Vector &out );
void MatrixSetColumn( const Vector &in, int column, matrix3x4_t &out );

//void DecomposeRotation( const matrix3x4_t &mat, float *out );
void ConcatRotations (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out);
void ConcatTransforms (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out);
// faster version assumes m0, m1, out are 16-byte aligned addresses
void ConcatTransforms_Aligned( const matrix3x4a_t &m0, const matrix3x4a_t &m1, matrix3x4a_t &out );

// For identical interface w/ VMatrix
inline void MatrixMultiply ( const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out )
{
	ConcatTransforms( in1, in2, out );
}

void QuaternionSlerp( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
void QuaternionSlerpNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
void QuaternionBlend( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
void QuaternionBlendNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt );
void QuaternionIdentityBlend( const Quaternion &p, float t, Quaternion &qt );
float QuaternionAngleDiff( const Quaternion &p, const Quaternion &q );
void QuaternionScale( const Quaternion &p, float t, Quaternion &q );
void QuaternionAlign( const Quaternion &p, const Quaternion &q, Quaternion &qt );
float QuaternionDotProduct( const Quaternion &p, const Quaternion &q );
void QuaternionConjugate( const Quaternion &p, Quaternion &q );
void QuaternionInvert( const Quaternion &p, Quaternion &q );
float QuaternionNormalize( Quaternion &q );
void QuaternionAdd( const Quaternion &p, const Quaternion &q, Quaternion &qt );
void QuaternionMult( const Quaternion &p, const Quaternion &q, Quaternion &qt );
void QuaternionExp( const Quaternion &p, Quaternion &q );
void QuaternionLn( const Quaternion &p, Quaternion &q );
void QuaternionAverageExponential( Quaternion &q, int nCount, const Quaternion *pQuaternions, const float *pflWeights = NULL );
void QuaternionLookAt( const Vector &vecForward, const Vector &referenceUp, Quaternion &q );
void QuaternionMatrix( const Quaternion &q, matrix3x4_t &matrix );
void QuaternionMatrix( const Quaternion &q, const Vector &pos, matrix3x4_t &matrix );
void QuaternionAngles( const Quaternion &q, QAngle &angles );
void AngleQuaternion( const QAngle& angles, Quaternion &qt );
void QuaternionAngles( const Quaternion &q, RadianEuler &angles );
void AngleQuaternion( RadianEuler const &angles, Quaternion &qt );
void QuaternionAxisAngle( const Quaternion &q, Vector &axis, float &angle );
void AxisAngleQuaternion( const Vector &axis, float angle, Quaternion &q );
void BasisToQuaternion( const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Quaternion &q );
void MatrixQuaternion( const matrix3x4_t &mat, Quaternion &q );

// A couple methods to find the dot product of a vector with a matrix row or column...
inline float MatrixRowDotProduct( const matrix3x4_t &in1, int row, const Vector& in2 )
{
	Assert( (row >= 0) && (row < 3) );
	return DotProduct( in1[row], in2.Base() );
}

inline float MatrixColumnDotProduct( const matrix3x4_t &in1, int col, const Vector& in2 )
{
	Assert( (col >= 0) && (col < 4) );
	return in1[0][col] * in2[0] + in1[1][col] * in2[1] + in1[2][col] * in2[2];
}

int __cdecl BoxOnPlaneSide (const float *emins, const float *emaxs, const cplane_t *plane);

inline float anglemod(float a)
{
	a = (360.f/65536) * ((int)(a*(65536.f/360.0f)) & 65535);
	return a;
}

// Remap a value in the range [A,B] to [C,D].
inline float RemapVal( float val, float A, float B, float C, float D)
{
	if ( A == B )
		return fsel( val - B , D , C );
	return C + (D - C) * (val - A) / (B - A);
}

inline float RemapValClamped( float val, float A, float B, float C, float D)
{
	if ( A == B )
		return fsel( val - B , D , C );
	float cVal = (val - A) / (B - A);
	cVal = clamp<float>( cVal, 0.0f, 1.0f );

	return C + (D - C) * cVal;
}

// Returns A + (B-A)*flPercent.
// float Lerp( float flPercent, float A, float B );
template <class T>
FORCEINLINE T Lerp( float flPercent, T const &A, T const &B )
{
	return A + (B - A) * flPercent;
}

FORCEINLINE float Sqr( float f )
{
	return f*f;
}

// 5-argument floating point linear interpolation.
// FLerp(f1,f2,i1,i2,x)=
//    f1 at x=i1
//    f2 at x=i2
//   smooth lerp between f1 and f2 at x>i1 and x<i2
//   extrapolation for x<i1 or x>i2
//
//   If you know a function f(x)'s value (f1) at position i1, and its value (f2) at position i2,
//   the function can be linearly interpolated with FLerp(f1,f2,i1,i2,x)
//    i2=i1 will cause a divide by zero.
static inline float FLerp(float f1, float f2, float i1, float i2, float x)
{
  return f1+(f2-f1)*(x-i1)/(i2-i1);
}

#ifndef VECTOR_NO_SLOW_OPERATIONS

// YWB:  Specialization for interpolating euler angles via quaternions...
template<> FORCEINLINE QAngle Lerp<QAngle>( float flPercent, const QAngle& q1, const QAngle& q2 )
{
	// Avoid precision errors
	if ( q1 == q2 )
		return q1;

	Quaternion src, dest;

	// Convert to quaternions
	AngleQuaternion( q1, src );
	AngleQuaternion( q2, dest );

	Quaternion result;

	// Slerp
	QuaternionSlerp( src, dest, flPercent, result );

	// Convert to euler
	QAngle output;
	QuaternionAngles( result, output );
	return output;
}

#else

#pragma error

// NOTE NOTE: I haven't tested this!! It may not work! Check out interpolatedvar.cpp in the client dll to try it
template<> FORCEINLINE QAngleByValue Lerp<QAngleByValue>( float flPercent, const QAngleByValue& q1, const QAngleByValue& q2 )
{
	// Avoid precision errors
	if ( q1 == q2 )
		return q1;

	Quaternion src, dest;

	// Convert to quaternions
	AngleQuaternion( q1, src );
	AngleQuaternion( q2, dest );

	Quaternion result;

	// Slerp
	QuaternionSlerp( src, dest, flPercent, result );

	// Convert to euler
	QAngleByValue output;
	QuaternionAngles( result, output );
	return output;
}

#endif // VECTOR_NO_SLOW_OPERATIONS

// Swap two of anything.
template <class T>
FORCEINLINE void V_swap( T& x, T& y )
{
	T temp = x;
	x = y;
	y = temp;
}

template <class T> FORCEINLINE T AVG(T a, T b)
{
	return (a+b)/2;
}

// number of elements in an array of static size
#define NELEMS(x) ((sizeof(x))/sizeof(x[0]))

// XYZ macro, for printf type functions - ex printf("%f %f %f",XYZ(myvector));
#define XYZ(v) (v).x,(v).y,(v).z

//
// Returns a clamped value in the range [min, max].
//
#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val)))

inline float Sign( float x )
{
	return fsel( x, 1.0f, -1.0f ); // x >= 0 ? 1.0f : -1.0f
	//return (x <0.0f) ? -1.0f : 1.0f;
}

//
// Clamps the input integer to the given array bounds.
// Equivalent to the following, but without using any branches:
//
// if( n < 0 ) return 0;
// else if ( n > maxindex ) return maxindex;
// else return n;
//
// This is not always a clear performance win, but when you have situations where a clamped
// value is thrashing against a boundary this is a big win. (ie, valid, invalid, valid, invalid, ...)
//
// Note: This code has been run against all possible integers.
//
inline int ClampArrayBounds( int n, unsigned maxindex )
{
	// mask is 0 if less than 4096, 0xFFFFFFFF if greater than
	unsigned int inrangemask = 0xFFFFFFFF + (((unsigned) n) > maxindex );
	unsigned int lessthan0mask = 0xFFFFFFFF + ( n >= 0 );

	// If the result was valid, set the result, (otherwise sets zero)
	int result = (inrangemask & n);

	// if the result was out of range or zero.
	result |= ((~inrangemask) & (~lessthan0mask)) & maxindex;

	return result;
}

// Turn a number "inside out".
// See Recording Animation in Binary Order for Progressive Temporal Refinement
// by Paul Heckbert from "Graphics Gems".
//
// If you want to iterate something from 0 to n, you can use this to iterate non-sequentially, in
// such a way that you will start with widely separated values and then refine the gaps between
// them, as you would for progressive refinement. This works with non-power of two ranges.
int InsideOut( int nTotal, int nCounter );

#define BOX_ON_PLANE_SIDE(emins, emaxs, p)	\
	(((p)->type < 3)?						\
	(										\
		((p)->dist <= (emins)[(p)->type])?	\
			1								\
		:									\
		(									\
			((p)->dist >= (emaxs)[(p)->type])?\
				2							\
			:								\
				3							\
		)									\
	)										\
	:										\
		BoxOnPlaneSide( (emins), (emaxs), (p)))

//-----------------------------------------------------------------------------
// FIXME: Vector versions.... the float versions will go away hopefully soon!
//-----------------------------------------------------------------------------

void AngleVectors (const QAngle& angles, Vector *forward);
void AngleVectors (const QAngle& angles, Vector *forward, Vector *right, Vector *up);
void AngleVectorsTranspose (const QAngle& angles, Vector *forward, Vector *right, Vector *up);
void AngleMatrix (const QAngle &angles, matrix3x4_t &mat );
void AngleMatrix( const QAngle &angles, const Vector &position, matrix3x4_t &mat );
void AngleMatrix (const RadianEuler &angles, matrix3x4_t &mat );
void AngleMatrix( RadianEuler const &angles, const Vector &position, matrix3x4_t &mat );
void AngleIMatrix (const QAngle &angles, matrix3x4_t &mat );
void AngleIMatrix (const QAngle &angles, const Vector &position, matrix3x4_t &mat );
void AngleIMatrix (const RadianEuler &angles, matrix3x4_t &mat );
void VectorAngles( const Vector &forward, QAngle &angles );
void VectorAngles( const Vector &forward, const Vector &pseudoup, QAngle &angles );
void VectorMatrix( const Vector &forward, matrix3x4_t &mat );
void VectorVectors( const Vector &forward, Vector &right, Vector &up );
void SetIdentityMatrix( matrix3x4_t &mat );
void SetScaleMatrix( float x, float y, float z, matrix3x4_t &dst );
void MatrixBuildRotationAboutAxis( const Vector &vAxisOfRot, float angleDegrees, matrix3x4_t &dst );

inline void SetScaleMatrix( float flScale, matrix3x4_t &dst )
{
	SetScaleMatrix( flScale, flScale, flScale, dst );
}

inline void SetScaleMatrix( const Vector& scale, matrix3x4_t &dst )
{
	SetScaleMatrix( scale.x, scale.y, scale.z, dst );
}

// Computes the inverse transpose
void MatrixTranspose( matrix3x4_t& mat );
void MatrixTranspose( const matrix3x4_t& src, matrix3x4_t& dst );
void MatrixInverseTranspose( const matrix3x4_t& src, matrix3x4_t& dst );

inline void PositionMatrix( const Vector &position, matrix3x4_t &mat )
{
	MatrixSetColumn( position, 3, mat );
}

inline void MatrixPosition( const matrix3x4_t &matrix, Vector &position )
{
	position[0] = matrix[0][3];
	position[1] = matrix[1][3];
	position[2] = matrix[2][3];
}

inline void VectorRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out)
{
	VectorRotate( &in1.x, in2, &out.x );
}

inline void VectorIRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out)
{
	VectorIRotate( &in1.x, in2, &out.x );
}

inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles )
{
	MatrixAngles( matrix, &angles.x );
}

inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles, Vector &position )
{
	MatrixAngles( matrix, angles );
	MatrixPosition( matrix, position );
}

inline void MatrixAngles( const matrix3x4_t &matrix, RadianEuler &angles )
{
	MatrixAngles( matrix, &angles.x );

	angles.Init( DEG2RAD( angles.z ), DEG2RAD( angles.x ), DEG2RAD( angles.y ) );
}

void MatrixAngles( const matrix3x4_t &mat, RadianEuler &angles, Vector &position );

void MatrixAngles( const matrix3x4_t &mat, Quaternion &q, Vector &position );

inline int VectorCompare (const Vector& v1, const Vector& v2)
{
	return v1 == v2;
}

inline void VectorTransform (const Vector& in1, const matrix3x4_t &in2, Vector &out)
{
	VectorTransform( &in1.x, in2, &out.x );
}

inline void VectorITransform (const Vector& in1, const matrix3x4_t &in2, Vector &out)
{
	VectorITransform( &in1.x, in2, &out.x );
}

/*
inline void DecomposeRotation( const matrix3x4_t &mat, Vector &out )
{
	DecomposeRotation( mat, &out.x );
}
*/

inline int BoxOnPlaneSide (const Vector& emins, const Vector& emaxs, const cplane_t *plane )
{
	return BoxOnPlaneSide( &emins.x, &emaxs.x, plane );
}

inline void VectorFill(Vector& a, float b)
{
	a[0]=a[1]=a[2]=b;
}

inline void VectorNegate(Vector& a)
{
	a[0] = -a[0];
	a[1] = -a[1];
	a[2] = -a[2];
}

inline vec_t VectorAvg(Vector& a)
{
	return ( a[0] + a[1] + a[2] ) / 3;
}

//-----------------------------------------------------------------------------
// Box/plane test (slow version)
//-----------------------------------------------------------------------------
inline int FASTCALL BoxOnPlaneSide2 (const Vector& emins, const Vector& emaxs, const cplane_t *p, float tolerance = 0.f )
{
	Vector	corners[2];

	if (p->normal[0] < 0)
	{
		corners[0][0] = emins[0];
		corners[1][0] = emaxs[0];
	}
	else
	{
		corners[1][0] = emins[0];
		corners[0][0] = emaxs[0];
	}

	if (p->normal[1] < 0)
	{
		corners[0][1] = emins[1];
		corners[1][1] = emaxs[1];
	}
	else
	{
		corners[1][1] = emins[1];
		corners[0][1] = emaxs[1];
	}

	if (p->normal[2] < 0)
	{
		corners[0][2] = emins[2];
		corners[1][2] = emaxs[2];
	}
	else
	{
		corners[1][2] = emins[2];
		corners[0][2] = emaxs[2];
	}

	int sides = 0;

	float dist1 = DotProduct (p->normal, corners[0]) - p->dist;
	if (dist1 >= tolerance)
		sides = 1;

	float dist2 = DotProduct (p->normal, corners[1]) - p->dist;
	if (dist2 < -tolerance)
		sides |= 2;

	return sides;
}

//-----------------------------------------------------------------------------
// Helpers for bounding box construction
//-----------------------------------------------------------------------------

void ClearBounds (Vector& mins, Vector& maxs);
void AddPointToBounds (const Vector& v, Vector& mins, Vector& maxs);

//-----------------------------------------------------------------------------
// Ensures that the min and max bounds values are valid.
// (ClearBounds() sets min > max, which is clearly invalid.)
//-----------------------------------------------------------------------------
bool AreBoundsValid( const Vector &vMin, const Vector &vMax );

//-----------------------------------------------------------------------------
// Returns true if the provided point is in the AABB defined by vMin
// at the lower corner and vMax at the upper corner.
//-----------------------------------------------------------------------------
bool IsPointInBounds( const Vector &vPoint, const Vector &vMin, const Vector &vMax );

//
// COLORSPACE/GAMMA CONVERSION STUFF
//
void BuildGammaTable( float gamma, float texGamma, float brightness, int overbright );

// convert texture to linear 0..1 value
inline float TexLightToLinear( int c, int exponent )
{
	extern float power2_n[256];
	Assert( exponent >= -128 && exponent <= 127 );
	return ( float )c * power2_n[exponent+128];
}

// convert texture to linear 0..1 value
int LinearToTexture( float f );
// converts 0..1 linear value to screen gamma (0..255)
int LinearToScreenGamma( float f );
float TextureToLinear( int c );

// compressed color format
struct ColorRGBExp32
{
	byte r, g, b;
	signed char exponent;
};

void ColorRGBExp32ToVector( const ColorRGBExp32& in, Vector& out );
void VectorToColorRGBExp32( const Vector& v, ColorRGBExp32 &c );

// solve for "x" where "a x^2 + b x + c = 0", return true if solution exists
bool SolveQuadratic( float a, float b, float c, float &root1, float &root2 );

// solves for "a, b, c" where "a x^2 + b x + c = y", return true if solution exists
bool SolveInverseQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c );

// solves for a,b,c specified as above, except that it always creates a monotonically increasing or
// decreasing curve if the data is monotonically increasing or decreasing. In order to enforce the
// monoticity condition, it is possible that the resulting quadratic will only approximate the data
// instead of interpolating it. This code is not especially fast.
bool SolveInverseQuadraticMonotonic( float x1, float y1, float x2, float y2,
									 float x3, float y3, float &a, float &b, float &c );

// solves for "a, b, c" where "1/(a x^2 + b x + c ) = y", return true if solution exists
bool SolveInverseReciprocalQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c );

// rotate a vector around the Z axis (YAW)
void VectorYawRotate( const Vector& in, float flYaw, Vector &out);

// Bias takes an X value between 0 and 1 and returns another value between 0 and 1
// The curve is biased towards 0 or 1 based on biasAmt, which is between 0 and 1.
// Lower values of biasAmt bias the curve towards 0 and higher values bias it towards 1.
//
// For example, with biasAmt = 0.2, the curve looks like this:
//
// 1
// |				  *
// |				  *
// |			     *
// |			   **
// |			 **
// |	  	 ****
// |*********
// |___________________
// 0                   1
//
//
// With biasAmt = 0.8, the curve looks like this:
//
// 1
// | 	**************
// |  **
// | *
// | *
// |*
// |*
// |*
// |___________________
// 0                   1
//
// With a biasAmt of 0.5, Bias returns X.
float Bias( float x, float biasAmt );

// Gain is similar to Bias, but biasAmt biases towards or away from 0.5.
// Lower bias values bias towards 0.5 and higher bias values bias away from it.
//
// For example, with biasAmt = 0.2, the curve looks like this:
//
// 1
// | 				  *
// | 				 *
// | 				**
// |  ***************
// | **
// | *
// |*
// |___________________
// 0                   1
//
//
// With biasAmt = 0.8, the curve looks like this:
//
// 1
// |  		    *****
// |  		 ***
// |  		*
// | 		*
// | 		*
// |   	 ***
// |*****
// |___________________
// 0                   1
float Gain( float x, float biasAmt );

// SmoothCurve maps a 0-1 value into another 0-1 value based on a cosine wave
// where the derivatives of the function at 0 and 1 (and 0.5) are 0. This is useful for
// any fadein/fadeout effect where it should start and end smoothly.
//
// The curve looks like this:
//
// 1
// |  		**
// | 	   *  *
// | 	  *	   *
// | 	  *	   *
// | 	 *		*
// |   **		 **
// |***			   ***
// |___________________
// 0                   1
//
float SmoothCurve( float x );

// This works like SmoothCurve, with two changes:
//
// 1. Instead of the curve peaking at 0.5, it will peak at flPeakPos.
//    (So if you specify flPeakPos=0.2, then the peak will slide to the left).
//
// 2. flPeakSharpness is a 0-1 value controlling the sharpness of the peak.
//    Low values blunt the peak and high values sharpen the peak.
float SmoothCurve_Tweak( float x, float flPeakPos=0.5, float flPeakSharpness=0.5 );

//float ExponentialDecay( float halflife, float dt );
//float ExponentialDecay( float decayTo, float decayTime, float dt );

// halflife is time for value to reach 50%
inline float ExponentialDecay( float halflife, float dt )
{
	// log(0.5) == -0.69314718055994530941723212145818
	return expf( -0.69314718f / halflife * dt);
}

// decayTo is factor the value should decay to in decayTime
inline float ExponentialDecay( float decayTo, float decayTime, float dt )
{
	return expf( logf( decayTo ) / decayTime * dt);
}

// Get the integrated distanced traveled
// decayTo is factor the value should decay to in decayTime
// dt is the time relative to the last velocity update
inline float ExponentialDecayIntegral( float decayTo, float decayTime, float dt  )
{
	return (powf( decayTo, dt / decayTime) * decayTime - decayTime) / logf( decayTo );
}

// hermite basis function for smooth interpolation
// Similar to Gain() above, but very cheap to call
// value should be between 0 & 1 inclusive
inline float SimpleSpline( float value )
{
	float valueSquared = value * value;

	// Nice little ease-in, ease-out spline-like curve
	return (3 * valueSquared - 2 * valueSquared * value);
}

// remaps a value in [startInterval, startInterval+rangeInterval] from linear to
// spline using SimpleSpline
inline float SimpleSplineRemapVal( float val, float A, float B, float C, float D)
{
	if ( A == B )
		return val >= B ? D : C;
	float cVal = (val - A) / (B - A);
	return C + (D - C) * SimpleSpline( cVal );
}

// remaps a value in [startInterval, startInterval+rangeInterval] from linear to
// spline using SimpleSpline
inline float SimpleSplineRemapValClamped( float val, float A, float B, float C, float D )
{
	if ( A == B )
		return val >= B ? D : C;
	float cVal = (val - A) / (B - A);
	cVal = clamp( cVal, 0.0f, 1.0f );
	return C + (D - C) * SimpleSpline( cVal );
}

FORCEINLINE int RoundFloatToInt(float f)
{
#if defined( _X360 )
#ifdef Assert
	Assert( IsFPUControlWordSet() );
#endif
	union
	{
		double flResult;
		int pResult[2];
	};
	flResult = __fctiw( f );
	return pResult[1];
#else // !X360
	int nResult;
#if defined( COMPILER_MSVC32 )
	__asm
	{
		fld f
		fistp nResult
	}
#elif GNUC
	__asm __volatile__ (
		"fistpl %0;": "=m" (nResult): "t" (f) : "st"
	);
#else
	nResult = static_cast<int>(f);
#endif
	return nResult;
#endif
}

FORCEINLINE unsigned char RoundFloatToByte(float f)
{
#if defined( _X360 )
#ifdef Assert
	Assert( IsFPUControlWordSet() );
#endif
	union
	{
		double flResult;
		int pIntResult[2];
		unsigned char pResult[8];
	};
	flResult = __fctiw( f );
#ifdef Assert
	Assert( pIntResult[1] >= 0 && pIntResult[1] <= 255 );
#endif
	return pResult[7];

#else // !X360

	int nResult;

#if defined( COMPILER_MSVC32 )
	__asm
	{
		fld f
		fistp nResult
	}
#elif GNUC
	__asm __volatile__ (
		"fistpl %0;": "=m" (nResult): "t" (f) : "st"
	);
#else
	nResult = static_cast<unsigned int> (f) & 0xff;
#endif

#ifdef Assert
	Assert( nResult >= 0 && nResult <= 255 );
#endif
	return nResult;

#endif
}

FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f)
{
#if defined( _X360 )
#ifdef Assert
	Assert( IsFPUControlWordSet() );
#endif
	union
	{
		double flResult;
		int pIntResult[2];
		unsigned long pResult[2];
	};
	flResult = __fctiw( f );
	Assert( pIntResult[1] >= 0 );
	return pResult[1];
#else  // !X360

#if defined( COMPILER_MSVC32 )
	unsigned char nResult[8];
	__asm
	{
		fld f
		fistp       qword ptr nResult
	}
	return *((unsigned long*)nResult);
#elif defined( COMPILER_GCC )
	unsigned char nResult[8];
	__asm __volatile__ (
		"fistpl %0;": "=m" (nResult): "t" (f) : "st"
	);
	return *((unsigned long*)nResult);
#else
	return static_cast<unsigned long>(f);
#endif

#endif
}

FORCEINLINE bool IsIntegralValue( float flValue, float flTolerance = 0.001f )
{
	return fabs( RoundFloatToInt( flValue ) - flValue ) < flTolerance;
}

// Fast, accurate ftol:
FORCEINLINE int Float2Int( float a )
{
#if defined( _X360 )
	union
	{
		double flResult;
		int pResult[2];
	};
	flResult = __fctiwz( a );
	return pResult[1];
#else  // !X360

	int RetVal;

#if defined( COMPILER_MSVC32 )
	int CtrlwdHolder;
	int CtrlwdSetter;
	__asm
	{
		fld    a					// push 'a' onto the FP stack
		fnstcw CtrlwdHolder		// store FPU control word
		movzx  eax, CtrlwdHolder	// move and zero extend word into eax
		and    eax, 0xFFFFF3FF	// set all bits except rounding bits to 1
		or     eax, 0x00000C00	// set rounding mode bits to round towards zero
		mov    CtrlwdSetter, eax	// Prepare to set the rounding mode -- prepare to enter plaid!
		fldcw  CtrlwdSetter		// Entering plaid!
		fistp  RetVal				// Store and converted (to int) result
		fldcw  CtrlwdHolder		// Restore control word
	}
#else
	RetVal = static_cast<int>( a );
#endif

	return RetVal;
#endif
}

// Over 15x faster than: (int)floor(value)
inline int Floor2Int( float a )
{
   int RetVal;

#if defined( _X360 )
	RetVal = (int)floor( a );
#elif defined( COMPILER_MSVC32 )
   int CtrlwdHolder;
   int CtrlwdSetter;
   __asm
   {
      fld    a					// push 'a' onto the FP stack
      fnstcw CtrlwdHolder		// store FPU control word
      movzx  eax, CtrlwdHolder	// move and zero extend word into eax
      and    eax, 0xFFFFF3FF	// set all bits except rounding bits to 1
      or     eax, 0x00000400	// set rounding mode bits to round down
      mov    CtrlwdSetter, eax	// Prepare to set the rounding mode -- prepare to enter plaid!
      fldcw  CtrlwdSetter		// Entering plaid!
      fistp  RetVal				// Store floored and converted (to int) result
      fldcw  CtrlwdHolder		// Restore control word
   }
#else
	RetVal = static_cast<int>( floor(a) );
#endif

	return RetVal;
}

//-----------------------------------------------------------------------------
// Fast color conversion from float to unsigned char
//-----------------------------------------------------------------------------
FORCEINLINE unsigned char FastFToC( float c )
{
	volatile float dc;

	// ieee trick
	dc = c * 255.0f + (float)(1 << 23);

	// return the lsb
#if defined( _X360 )
	return ((unsigned char*)&dc)[3];
#else
	return *(unsigned char*)&dc;
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Bound input float to .001 (millisecond) boundary
// Input  : in -
// Output : inline float
//-----------------------------------------------------------------------------
inline float ClampToMsec( float in )
{
	int msec = Floor2Int( in * 1000.0f + 0.5f );
	return msec / 1000.0f;
}

// Over 15x faster than: (int)ceil(value)
inline int Ceil2Int( float a )
{
   int RetVal;

#if defined( _X360 )
	RetVal = (int)ceil( a );
#elif defined( COMPILER_MSVC32 )
   int CtrlwdHolder;
   int CtrlwdSetter;
   __asm
   {
      fld    a					// push 'a' onto the FP stack
      fnstcw CtrlwdHolder		// store FPU control word
      movzx  eax, CtrlwdHolder	// move and zero extend word into eax
      and    eax, 0xFFFFF3FF	// set all bits except rounding bits to 1
      or     eax, 0x00000800	// set rounding mode bits to round down
      mov    CtrlwdSetter, eax	// Prepare to set the rounding mode -- prepare to enter plaid!
      fldcw  CtrlwdSetter		// Entering plaid!
      fistp  RetVal				// Store floored and converted (to int) result
      fldcw  CtrlwdHolder		// Restore control word
   }
#else
	RetVal = static_cast<int>( ceil(a) );
#endif

	return RetVal;
}

// Regular signed area of triangle
#define TriArea2D( A, B, C ) \
	( 0.5f * ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) )

// This version doesn't premultiply by 0.5f, so it's the area of the rectangle instead
#define TriArea2DTimesTwo( A, B, C ) \
	( ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) )

// Get the barycentric coordinates of "pt" in triangle [A,B,C].
inline void GetBarycentricCoords2D(
	Vector2D const &A,
	Vector2D const &B,
	Vector2D const &C,
	Vector2D const &pt,
	float bcCoords[3] )
{
	// Note, because to top and bottom are both x2, the issue washes out in the composite
	float invTriArea = 1.0f / TriArea2DTimesTwo( A, B, C );

	// NOTE: We assume here that the lightmap coordinate vertices go counterclockwise.
	// If not, TriArea2D() is negated so this works out right.
	bcCoords[0] = TriArea2DTimesTwo( B, C, pt ) * invTriArea;
	bcCoords[1] = TriArea2DTimesTwo( C, A, pt ) * invTriArea;
	bcCoords[2] = TriArea2DTimesTwo( A, B, pt ) * invTriArea;
}

// Return true of the sphere might touch the box (the sphere is actually treated
// like a box itself, so this may return true if the sphere's bounding box touches
// a corner of the box but the sphere itself doesn't).
inline bool QuickBoxSphereTest(
	const Vector& vOrigin,
	float flRadius,
	const Vector& bbMin,
	const Vector& bbMax )
{
	return vOrigin.x - flRadius < bbMax.x && vOrigin.x + flRadius > bbMin.x &&
		vOrigin.y - flRadius < bbMax.y && vOrigin.y + flRadius > bbMin.y &&
		vOrigin.z - flRadius < bbMax.z && vOrigin.z + flRadius > bbMin.z;
}

// Return true of the boxes intersect (but not if they just touch).
inline bool QuickBoxIntersectTest(
	const Vector& vBox1Min,
	const Vector& vBox1Max,
	const Vector& vBox2Min,
	const Vector& vBox2Max )
{
	return
		vBox1Min.x < vBox2Max.x && vBox1Max.x > vBox2Min.x &&
		vBox1Min.y < vBox2Max.y && vBox1Max.y > vBox2Min.y &&
		vBox1Min.z < vBox2Max.z && vBox1Max.z > vBox2Min.z;
}

extern float GammaToLinearFullRange( float gamma );
extern float LinearToGammaFullRange( float linear );
extern float GammaToLinear( float gamma );
extern float LinearToGamma( float linear );

extern float SrgbGammaToLinear( float flSrgbGammaValue );
extern float SrgbLinearToGamma( float flLinearValue );
extern float X360GammaToLinear( float fl360GammaValue );
extern float X360LinearToGamma( float flLinearValue );
extern float SrgbGammaTo360Gamma( float flSrgbGammaValue );

// linear (0..4) to screen corrected vertex space (0..1?)
FORCEINLINE float LinearToVertexLight( float f )
{
	extern float lineartovertex[4096];

	// Gotta clamp before the multiply; could overflow...
	// assume 0..4 range
	int i = RoundFloatToInt( f * 1024.f );

	// Presumably the comman case will be not to clamp, so check that first:
	if( (unsigned)i > 4095 )
	{
		if ( i < 0 )
			i = 0;		// Compare to zero instead of 4095 to save 4 bytes in the instruction stream
		else
			i = 4095;
	}

	return lineartovertex[i];
}

FORCEINLINE unsigned char LinearToLightmap( float f )
{
	extern unsigned char lineartolightmap[4096];

	// Gotta clamp before the multiply; could overflow...
	int i = RoundFloatToInt( f * 1024.f );	// assume 0..4 range

	// Presumably the comman case will be not to clamp, so check that first:
	if ( (unsigned)i > 4095 )
	{
		if ( i < 0 )
			i = 0;		// Compare to zero instead of 4095 to save 4 bytes in the instruction stream
		else
			i = 4095;
	}

	return lineartolightmap[i];
}

FORCEINLINE void ColorClamp( Vector& color )
{
	float maxc = MAX( color.x, MAX( color.y, color.z ) );
	if ( maxc > 1.0f )
	{
		float ooMax = 1.0f / maxc;
		color.x *= ooMax;
		color.y *= ooMax;
		color.z *= ooMax;
	}

	if ( color[0] < 0.f ) color[0] = 0.f;
	if ( color[1] < 0.f ) color[1] = 0.f;
	if ( color[2] < 0.f ) color[2] = 0.f;
}

inline void ColorClampTruncate( Vector& color )
{
	if (color[0] > 1.0f) color[0] = 1.0f; else if (color[0] < 0.0f) color[0] = 0.0f;
	if (color[1] > 1.0f) color[1] = 1.0f; else if (color[1] < 0.0f) color[1] = 0.0f;
	if (color[2] > 1.0f) color[2] = 1.0f; else if (color[2] < 0.0f) color[2] = 0.0f;
}

// Interpolate a Catmull-Rom spline.
// t is a [0,1] value and interpolates a curve between p2 and p3.
void Catmull_Rom_Spline(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector &output );

// Interpolate a Catmull-Rom spline.
// Returns the tangent of the point at t of the spline
void Catmull_Rom_Spline_Tangent(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector &output );

// area under the curve [0..t]
void Catmull_Rom_Spline_Integral(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

// area under the curve [0..1]
void Catmull_Rom_Spline_Integral(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	Vector& output );

// Interpolate a Catmull-Rom spline.
// Normalize p2->p1 and p3->p4 to be the same length as p2->p3
void Catmull_Rom_Spline_Normalize(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector &output );

// area under the curve [0..t]
// Normalize p2->p1 and p3->p4 to be the same length as p2->p3
void Catmull_Rom_Spline_Integral_Normalize(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

// Interpolate a Catmull-Rom spline.
// Normalize p2.x->p1.x and p3.x->p4.x to be the same length as p2.x->p3.x
void Catmull_Rom_Spline_NormalizeX(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector &output );

// area under the curve [0..t]
void Catmull_Rom_Spline_NormalizeX(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

// Interpolate a Hermite spline.
// t is a [0,1] value and interpolates a curve between p1 and p2 with the deltas d1 and d2.
void Hermite_Spline(
	const Vector &p1,
	const Vector &p2,
	const Vector &d1,
	const Vector &d2,
	float t,
	Vector& output );

float Hermite_Spline(
	float p1,
	float p2,
	float d1,
	float d2,
	float t );

// t is a [0,1] value and interpolates a curve between p1 and p2 with the slopes p0->p1 and p1->p2
void Hermite_Spline(
	const Vector &p0,
	const Vector &p1,
	const Vector &p2,
	float t,
	Vector& output );

float Hermite_Spline(
	float p0,
	float p1,
	float p2,
	float t );

void Hermite_SplineBasis( float t, float basis[] );

void Hermite_Spline(
	const Quaternion &q0,
	const Quaternion &q1,
	const Quaternion &q2,
	float t,
	Quaternion &output );

// See http://en.wikipedia.org/wiki/Kochanek-Bartels_curves
//
// Tension:  -1 = Round -> 1 = Tight
// Bias:     -1 = Pre-shoot (bias left) -> 1 = Post-shoot (bias right)
// Continuity: -1 = Box corners -> 1 = Inverted corners
//
// If T=B=C=0 it's the same matrix as Catmull-Rom.
// If T=1 & B=C=0 it's the same as Cubic.
// If T=B=0 & C=-1 it's just linear interpolation
//
// See http://news.povray.org/povray.binaries.tutorials/attachment/%3CXns91B880592482seed7@povray.org%3E/Splines.bas.txt
// for example code and descriptions of various spline types...
//
void Kochanek_Bartels_Spline(
	float tension,
	float bias,
	float continuity,
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

void Kochanek_Bartels_Spline_NormalizeX(
	float tension,
	float bias,
	float continuity,
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

// See link at Kochanek_Bartels_Spline for info on the basis matrix used
void Cubic_Spline(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

void Cubic_Spline_NormalizeX(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

// See link at Kochanek_Bartels_Spline for info on the basis matrix used
void BSpline(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

void BSpline_NormalizeX(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

// See link at Kochanek_Bartels_Spline for info on the basis matrix used
void Parabolic_Spline(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

void Parabolic_Spline_NormalizeX(
	const Vector &p1,
	const Vector &p2,
	const Vector &p3,
	const Vector &p4,
	float t,
	Vector& output );

// Evaluate the cubic Bernstein basis for the input parametric coordinate.
// Output is the coefficient for that basis polynomial.
float CubicBasis0( float t );
float CubicBasis1( float t );
float CubicBasis2( float t );
float CubicBasis3( float t );

// quintic interpolating polynomial from Perlin.
// 0->0, 1->1, smooth-in between with smooth tangents
FORCEINLINE float QuinticInterpolatingPolynomial(float t)
{
	// 6t^5-15t^4+10t^3
	return t * t * t *( t * ( t* 6.0 - 15.0 ) + 10.0 );
}

// given a table of sorted tabulated positions, return the two indices and blendfactor to linear
// interpolate. Does a search. Can be used to find the blend value to interpolate between
// keyframes.
void GetInterpolationData( float const *pKnotPositions,
						   float const *pKnotValues,
						   int nNumValuesinList,
						   int nInterpolationRange,
						   float flPositionToInterpolateAt,
						   bool bWrap,
						   float *pValueA,
						   float *pValueB,
						   float *pInterpolationValue);
float RangeCompressor( float flValue, float flMin, float flMax, float flBase );

// Get the minimum distance from vOrigin to the bounding box defined by [mins,maxs]
// using voronoi regions.
// 0 is returned if the origin is inside the box.
float CalcSqrDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point );
void CalcClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut );
void CalcSqrDistAndClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut, float &distSqrOut );

inline float CalcDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point )
{
	float flDistSqr = CalcSqrDistanceToAABB( mins, maxs, point );
	return sqrt(flDistSqr);
}

// Get the closest point from P to the (infinite) line through vLineA and vLineB and
// calculate the shortest distance from P to the line.
// If you pass in a value for t, it will tell you the t for (A + (B-A)t) to get the closest point.
// If the closest point lies on the segment between A and B, then 0 <= t <= 1.
void  CalcClosestPointOnLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 );
float CalcDistanceToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
float CalcDistanceSqrToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );

// The same three functions as above, except now the line is closed between A and B.
void  CalcClosestPointOnLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 );
float CalcDistanceToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );
float CalcDistanceSqrToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 );

// A function to compute the closes line segment connnection two lines (or false if the lines are parallel, etc.)
bool CalcLineToLineIntersectionSegment(
   const Vector& p1,const Vector& p2,const Vector& p3,const Vector& p4,Vector *s1,Vector *s2,
   float *t1, float *t2 );

// The above functions in 2D
void  CalcClosestPointOnLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 );
float CalcDistanceToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
float CalcDistanceSqrToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
void  CalcClosestPointOnLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 );
float CalcDistanceToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );
float CalcDistanceSqrToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 );

// Init the mathlib
void MathLib_Init( float gamma = 2.2f, float texGamma = 2.2f, float brightness = 0.0f, int overbright = 2.0f, bool bAllow3DNow = true, bool bAllowSSE = true, bool bAllowSSE2 = true, bool bAllowMMX = true );
bool MathLib_MMXEnabled( void );
bool MathLib_SSEEnabled( void );
bool MathLib_SSE2Enabled( void );

inline float Approach( float target, float value, float speed );
float ApproachAngle( float target, float value, float speed );
float AngleDiff( float destAngle, float srcAngle );
float AngleDistance( float next, float cur );
float AngleNormalize( float angle );

// ensure that 0 <= angle <= 360
float AngleNormalizePositive( float angle );

bool AnglesAreEqual( float a, float b, float tolerance = 0.0f );

void RotationDeltaAxisAngle( const QAngle &srcAngles, const QAngle &destAngles, Vector &deltaAxis, float &deltaAngle );
void RotationDelta( const QAngle &srcAngles, const QAngle &destAngles, QAngle *out );

//-----------------------------------------------------------------------------
// Clips a line segment such that only the portion in the positive half-space
// of the plane remains.  If the segment is entirely clipped, the vectors
// are set to vec3_invalid (all components are FLT_MAX).
//
// flBias is added to the dot product with the normal.  A positive bias
// results in a more inclusive positive half-space, while a negative bias
// results in a more exclusive positive half-space.
//-----------------------------------------------------------------------------
void ClipLineSegmentToPlane( const Vector &vNormal, const Vector &vPlanePoint, Vector *p1, Vector *p2, float flBias = 0.0f );

void ComputeTrianglePlane( const Vector& v1, const Vector& v2, const Vector& v3, Vector& normal, float& intercept );
int PolyFromPlane( Vector *outVerts, const Vector& normal, float dist, float fHalfScale = 9000.0f );
int ClipPolyToPlane( Vector *inVerts, int vertCount, Vector *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon = 0.1f );
int ClipPolyToPlane_Precise( double *inVerts, int vertCount, double *outVerts, const double *normal, double dist, double fOnPlaneEpsilon = 0.1 );
float TetrahedronVolume( const Vector &p0, const Vector &p1, const Vector &p2, const Vector &p3 );
float TriangleArea( const Vector &p0, const Vector &p1, const Vector &p2 );

//-----------------------------------------------------------------------------
// Computes a reasonable tangent space for a triangle
//-----------------------------------------------------------------------------
void CalcTriangleTangentSpace( const Vector &p0, const Vector &p1, const Vector &p2,
							  const Vector2D &t0, const Vector2D &t1, const Vector2D& t2,
							  Vector &sVect, Vector &tVect );

//-----------------------------------------------------------------------------
// Transforms a AABB into another space; which will inherently grow the box.
//-----------------------------------------------------------------------------
void TransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );

//-----------------------------------------------------------------------------
// Uses the inverse transform of in1
//-----------------------------------------------------------------------------
void ITransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );

//-----------------------------------------------------------------------------
// Rotates a AABB into another space; which will inherently grow the box.
// (same as TransformAABB, but doesn't take the translation into account)
//-----------------------------------------------------------------------------
void RotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );

//-----------------------------------------------------------------------------
// Uses the inverse transform of in1
//-----------------------------------------------------------------------------
void IRotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut );

//-----------------------------------------------------------------------------
// Transform a plane
//-----------------------------------------------------------------------------
inline void MatrixTransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane )
{
	// What we want to do is the following:
	// 1) transform the normal into the new space.
	// 2) Determine a point on the old plane given by plane dist * plane normal
	// 3) Transform that point into the new space
	// 4) Plane dist = DotProduct( new normal, new point )

	// An optimized version, which works if the plane is orthogonal.
	// 1) Transform the normal into the new space
	// 2) Realize that transforming the old plane point into the new space
	// is given by [ d * n'x + Tx, d * n'y + Ty, d * n'z + Tz ]
	// where d = old plane dist, n' = transformed normal, Tn = translational component of transform
	// 3) Compute the new plane dist using the dot product of the normal result of #2

	// For a correct result, this should be an inverse-transpose matrix
	// but that only matters if there are nonuniform scale or skew factors in this matrix.
	VectorRotate( inPlane.normal, src, outPlane.normal );
	outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal );
	outPlane.dist += outPlane.normal.x * src[0][3] + outPlane.normal.y * src[1][3] + outPlane.normal.z * src[2][3];
}

inline void MatrixITransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane )
{
	// The trick here is that Tn = translational component of transform,
	// but for an inverse transform, Tn = - R^-1 * T
	Vector vecTranslation;
	MatrixGetColumn( src, 3, vecTranslation );

	Vector vecInvTranslation;
	VectorIRotate( vecTranslation, src, vecInvTranslation );

	VectorIRotate( inPlane.normal, src, outPlane.normal );
	outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal );
	outPlane.dist -= outPlane.normal.x * vecInvTranslation[0] + outPlane.normal.y * vecInvTranslation[1] + outPlane.normal.z * vecInvTranslation[2];
}

int CeilPow2( int in );
int FloorPow2( int in );

FORCEINLINE float * UnpackNormal_HEND3N( const unsigned int *pPackedNormal, float *pNormal )
{
	int temp[3];
	temp[0] = ((*pPackedNormal >> 0L) & 0x7ff);
	if ( temp[0] & 0x400 )
	{
		temp[0] = 2048 - temp[0];
	}
	temp[1] = ((*pPackedNormal >> 11L) & 0x7ff);
	if ( temp[1] & 0x400 )
	{
		temp[1] = 2048 - temp[1];
	}
	temp[2] = ((*pPackedNormal >> 22L) & 0x3ff);
	if ( temp[2] & 0x200 )
	{
		temp[2] = 1024 - temp[2];
	}
	pNormal[0] = (float)temp[0] * 1.0f/1023.0f;
	pNormal[1] = (float)temp[1] * 1.0f/1023.0f;
	pNormal[2] = (float)temp[2] * 1.0f/511.0f;
	return pNormal;
}

FORCEINLINE unsigned int * PackNormal_HEND3N( const float *pNormal, unsigned int *pPackedNormal )
{
	int temp[3];

	temp[0] = Float2Int( pNormal[0] * 1023.0f );
	temp[1] = Float2Int( pNormal[1] * 1023.0f );
	temp[2] = Float2Int( pNormal[2] * 511.0f );

	// the normal is out of bounds, determine the source and fix
	// clamping would be even more of a slowdown here
	Assert( temp[0] >= -1023 && temp[0] <= 1023 );
	Assert( temp[1] >= -1023 && temp[1] <= 1023 );
	Assert( temp[2] >= -511 && temp[2] <= 511 );

	*pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) |
                     ( ( temp[1] & 0x7ff ) << 11L ) |
                     ( ( temp[0] & 0x7ff ) << 0L );
	return pPackedNormal;
}

FORCEINLINE unsigned int * PackNormal_HEND3N( float nx, float ny, float nz, unsigned int *pPackedNormal )
{
	int temp[3];

	temp[0] = Float2Int( nx * 1023.0f );
	temp[1] = Float2Int( ny * 1023.0f );
	temp[2] = Float2Int( nz * 511.0f );

	// the normal is out of bounds, determine the source and fix
	// clamping would be even more of a slowdown here
	Assert( temp[0] >= -1023 && temp[0] <= 1023 );
	Assert( temp[1] >= -1023 && temp[1] <= 1023 );
	Assert( temp[2] >= -511 && temp[2] <= 511 );

	*pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) |
                     ( ( temp[1] & 0x7ff ) << 11L ) |
                     ( ( temp[0] & 0x7ff ) << 0L );
	return pPackedNormal;
}

FORCEINLINE float * UnpackNormal_SHORT2( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE )
{
	// Unpacks from Jason's 2-short format (fills in a 4th binormal-sign (+1/-1) value, if this is a tangent vector)

	// FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits)
	short iX = (*pPackedNormal & 0x0000FFFF);
	short iY = (*pPackedNormal & 0xFFFF0000) >> 16;

	float zSign = +1;
	if ( iX < 0 )
	{
		zSign = -1;
		iX    = -iX;
	}
	float tSign = +1;
	if ( iY < 0 )
	{
		tSign = -1;
		iY    = -iY;
	}

	pNormal[0] = ( iX - 16384.0f ) / 16384.0f;
	pNormal[1] = ( iY - 16384.0f ) / 16384.0f;
	float mag = ( pNormal[0]*pNormal[0] + pNormal[1]*pNormal[1] );
	if ( mag > 1.0f )
	{
		mag = 1.0f;
	}
	pNormal[2] = zSign*sqrtf( 1.0f - mag );
	if ( bIsTangent )
	{
		pNormal[3] = tSign;
	}

	return pNormal;
}

FORCEINLINE unsigned int * PackNormal_SHORT2( float nx, float ny, float nz, unsigned int *pPackedNormal, float binormalSign = +1.0f )
{
	// Pack a vector (ASSUMED TO BE NORMALIZED) into Jason's 4-byte (SHORT2) format.
	// This simply reconstructs Z from X & Y. It uses the sign bits of the X & Y coords
	// to reconstruct the sign of Z and, if this is a tangent vector, the sign of the
	// binormal (this is needed because tangent/binormal vectors are supposed to follow
	// UV gradients, but shaders reconstruct the binormal from the tangent and normal
	// assuming that they form a right-handed basis).

	nx += 1;					// [-1,+1] -> [0,2]
	ny += 1;
	nx *= 16384.0f;				// [ 0, 2] -> [0,32768]
	ny *= 16384.0f;

	// '0' and '32768' values are invalid encodings
	nx = MAX( nx, 1.0f );		// Make sure there are no zero values
	ny = MAX( ny, 1.0f );
	nx = MIN( nx, 32767.0f );	// Make sure there are no 32768 values
	ny = MIN( ny, 32767.0f );

	if ( nz < 0.0f )
		nx = -nx;				// Set the sign bit for z

	ny *= binormalSign;			// Set the sign bit for the binormal (use when encoding a tangent vector)

	// FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits), also use Float2Int()
	short sX = (short)nx;		// signed short [1,32767]
	short sY = (short)ny;

	*pPackedNormal = ( sX & 0x0000FFFF ) | ( sY << 16 ); // NOTE: The mask is necessary (if sX is negative and cast to an int...)

	return pPackedNormal;
}

FORCEINLINE unsigned int * PackNormal_SHORT2( const float *pNormal, unsigned int *pPackedNormal, float binormalSign = +1.0f )
{
	return PackNormal_SHORT2( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, binormalSign );
}

// Unpacks a UBYTE4 normal (for a tangent, the result's fourth component receives the binormal 'sign')
FORCEINLINE float * UnpackNormal_UBYTE4( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE )
{
	unsigned char cX, cY;
	if ( bIsTangent )
	{
		cX = *pPackedNormal >> 16;					// Unpack Z
		cY = *pPackedNormal >> 24;					// Unpack W
	}
	else
	{
		cX = *pPackedNormal >>  0;					// Unpack X
		cY = *pPackedNormal >>  8;					// Unpack Y
	}

	float x = cX - 128.0f;
	float y = cY - 128.0f;
	float z;

	float zSignBit = x < 0 ? 1.0f : 0.0f;			// z and t negative bits (like slt asm instruction)
	float tSignBit = y < 0 ? 1.0f : 0.0f;
	float zSign    = -( 2*zSignBit - 1 );			// z and t signs
	float tSign    = -( 2*tSignBit - 1 );

	x = x*zSign - zSignBit;							// 0..127
	y = y*tSign - tSignBit;
	x = x - 64;										// -64..63
	y = y - 64;

	float xSignBit = x < 0 ? 1.0f : 0.0f;	// x and y negative bits (like slt asm instruction)
	float ySignBit = y < 0 ? 1.0f : 0.0f;
	float xSign    = -( 2*xSignBit - 1 );			// x and y signs
	float ySign    = -( 2*ySignBit - 1 );

	x = ( x*xSign - xSignBit ) / 63.0f;				// 0..1 range
	y = ( y*ySign - ySignBit ) / 63.0f;
	z = 1.0f - x - y;

	float oolen	 = 1.0f / sqrt( x*x + y*y + z*z );	// Normalize and
	x			*= oolen * xSign;					// Recover signs
	y			*= oolen * ySign;
	z			*= oolen * zSign;

	pNormal[0] = x;
	pNormal[1] = y;
	pNormal[2] = z;
	if ( bIsTangent )
	{
		pNormal[3] = tSign;
	}

	return pNormal;
}

//////////////////////////////////////////////////////////////////////////////
// See: http://www.oroboro.com/rafael/docserv.php/index/programming/article/unitv2
//
// UBYTE4 encoding, using per-octant projection onto x+y+z=1
// Assume input vector is already unit length
//
// binormalSign specifies 'sign' of binormal, stored in t sign bit of tangent
// (lets the shader know whether norm/tan/bin form a right-handed basis)
//
// bIsTangent is used to specify which WORD of the output to store the data
// The expected usage is to call once with the normal and once with
// the tangent and binormal sign flag, bitwise OR'ing the returned DWORDs
FORCEINLINE unsigned int * PackNormal_UBYTE4( float nx, float ny, float nz, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f )
{
	float xSign = nx < 0.0f ? -1.0f : 1.0f;			// -1 or 1 sign
	float ySign = ny < 0.0f ? -1.0f : 1.0f;
	float zSign = nz < 0.0f ? -1.0f : 1.0f;
	float tSign = binormalSign;
	Assert( ( binormalSign == +1.0f ) || ( binormalSign == -1.0f ) );

	float xSignBit = 0.5f*( 1 - xSign );			// [-1,+1] -> [1,0]
	float ySignBit = 0.5f*( 1 - ySign );			// 1 is negative bit (like slt instruction)
	float zSignBit = 0.5f*( 1 - zSign );
	float tSignBit = 0.5f*( 1 - binormalSign );

	float absX = xSign*nx;							// 0..1 range (abs)
	float absY = ySign*ny;
	float absZ = zSign*nz;

	float xbits = absX / ( absX + absY + absZ );	// Project onto x+y+z=1 plane
	float ybits = absY / ( absX + absY + absZ );

	xbits *= 63;									// 0..63
	ybits *= 63;

	xbits  = xbits * xSign - xSignBit;				// -64..63 range
	ybits  = ybits * ySign - ySignBit;
	xbits += 64.0f;									// 0..127 range
	ybits += 64.0f;

	xbits  = xbits * zSign - zSignBit;				// Negate based on z and t
	ybits  = ybits * tSign - tSignBit;				// -128..127 range

	xbits += 128.0f;								// 0..255 range
	ybits += 128.0f;

	unsigned char cX = (unsigned char) xbits;
	unsigned char cY = (unsigned char) ybits;

	if ( !bIsTangent )
		*pPackedNormal = (cX <<  0) | (cY <<  8);	// xy for normal
	else
		*pPackedNormal = (cX << 16) | (cY << 24);	// zw for tangent

	return pPackedNormal;
}

FORCEINLINE unsigned int * PackNormal_UBYTE4( const float *pNormal, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f )
{
	return PackNormal_UBYTE4( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, bIsTangent, binormalSign );
}

FORCEINLINE void RGB2YUV( int &nR, int &nG, int &nB, float &fY, float &fU, float &fV, bool bApplySaturationCurve )
{
	// YUV conversion:
	//  |Y|   |  0.299f     0.587f     0.114f   |   |R|
	//  |U| = | -0.14713f  -0.28886f   0.436f   | x |G|
	//  |V|   |  0.615f    -0.51499f  -0.10001f |   |B|
	//
	// The coefficients in the first row sum to one, whereas the 2nd and 3rd rows each sum to zero (UV (0,0) means greyscale).
	// Ranges are Y [0,1], U [-0.436,+0.436] and V [-0.615,+0.615].
	// We scale and offset to [0,1] and allow the caller to round as they please.

	fY = (  0.29900f*nR +  0.58700f*nG +  0.11400f*nB ) / 255;
	fU = ( -0.14713f*nR + -0.28886f*nG +  0.43600f*nB )*( 0.5f / 0.436f ) / 255 + 0.5f;
	fV = (  0.61500f*nR + -0.51499f*nG + -0.10001f*nB )*( 0.5f / 0.615f ) / 255 + 0.5f;

	if ( bApplySaturationCurve )
	{
		// Apply a curve to saturation, and snap-to-grey for low saturations
		const float SNAP_TO_GREY = 0;//0.0125f; Disabled, saturation curve seems sufficient
		float dX, dY, sat, scale;
		dX    = 2*( fU - 0.5f );
		dY    = 2*( fV - 0.5f );
		sat   = sqrtf( dX*dX + dY*dY );
		sat   = clamp( ( sat*( 1 + SNAP_TO_GREY ) - SNAP_TO_GREY ), 0, 1 );
		scale = ( sat == 0 ) ? 0 : MIN( ( sqrtf( sat ) / sat ), 4.0f );
		fU    = 0.5f + scale*( fU - 0.5f );
		fV    = 0.5f + scale*( fV - 0.5f );
	}
}

#ifdef _X360
// Used for direct CPU access to VB data on 360 (used by shaderapi, studiorender and engine)
struct VBCPU_AccessInfo_t
{
	// Points to the GPU data pointer in the CVertexBuffer struct (VB data can be relocated during level transitions)
	const byte **ppBaseAddress;
	// pBaseAddress should be computed from ppBaseAddress immediately before use
	const byte  *pBaseAddress;
	int          nStride;
	int          nPositionOffset;
	int          nTexCoord0_Offset;
	int          nNormalOffset;
	int          nBoneIndexOffset;
	int          nBoneWeightOffset;
	int          nCompressionType;
	// TODO: if needed, add colour and tangents
};
#endif

//-----------------------------------------------------------------------------
// Convert RGB to HSV
//-----------------------------------------------------------------------------
void RGBtoHSV( const Vector &rgb, Vector &hsv );

//-----------------------------------------------------------------------------
// Convert HSV to RGB
//-----------------------------------------------------------------------------
void HSVtoRGB( const Vector &hsv, Vector &rgb );

//-----------------------------------------------------------------------------
// Fast version of pow and log
//-----------------------------------------------------------------------------

float FastLog2(float i);			// log2( i )
float FastPow2(float i);			// 2^i
float FastPow(float a, float b);	// a^b
float FastPow10( float i );			// 10^i

//-----------------------------------------------------------------------------
// For testing float equality
//-----------------------------------------------------------------------------

inline bool CloseEnough( float a, float b, float epsilon = EQUAL_EPSILON )
{
	return fabs( a - b ) <= epsilon;
}

inline bool CloseEnough( const Vector &a, const Vector &b, float epsilon = EQUAL_EPSILON )
{
	return fabs( a.x - b.x ) <= epsilon &&
		fabs( a.y - b.y ) <= epsilon &&
		fabs( a.z - b.z ) <= epsilon;
}

// Fast compare
// maxUlps is the maximum error in terms of Units in the Last Place. This
// specifies how big an error we are willing to accept in terms of the value
// of the least significant digit of the floating point number's
// representation. maxUlps can also be interpreted in terms of how many
// representable floats we are willing to accept between A and B.
// This function will allow maxUlps-1 floats between A and B.
bool AlmostEqual(float a, float b, int maxUlps = 10);

inline bool AlmostEqual( const Vector &a, const Vector &b, int maxUlps = 10)
{
	return AlmostEqual( a.x, b.x, maxUlps ) &&
		AlmostEqual( a.y, b.y, maxUlps ) &&
		AlmostEqual( a.z, b.z, maxUlps );
}

inline float Approach( float target, float value, float speed )
{
	float delta = target - value;

#if defined(_X360) || defined( PS3 ) // use conditional move for speed on 360

	return fsel( delta-speed,	// delta >= speed ?
				 value + speed,	// if delta == speed, then value + speed == value + delta == target
				 fsel( (-speed) - delta, // delta <= -speed
						value - speed,
						target )
				);  // delta < speed && delta > -speed

#else

	if ( delta > speed )
		value += speed;
	else if ( delta < -speed )
		value -= speed;
	else
		value = target;

	return value;

#endif
}

#endif	// MATH_BASE_H

redpajama_set_name: RedPajamaGithub


Did you know that your smartphone had hidden menus?
Hidden menus and codes on cell phones are anything but new. Back in the days, even the old-school brick phones had these, allowing people who knew about them to access service options and software information. Today, a "secret" menu exists on most (if not all) popular smartphones, and to get to it, you just need to input the right code.
What code, you ask? Well, you've probably heard of *#06# which you type in your dialer, as if you were about to "call" it. When this particular code is entered, and it should work on any cell phone, the device's identity number (IMEI) is displayed. A smartphone's hidden menu can be accessed with a code that looks pretty similar to this one.
On iPhone, for example, you enter *3001#12345#* in the Phone app and then hit the call button to get to the field test menu. There's not much going on there, however, unless you're a technician. You can view SIM card information, details on the cell network's status, and all sorts of other cryptic numbers. It is interesting that signal strength in displayed in decibels while in this menu, not represented by circles.
Hidden menus and codes on Android phones may differ, depending on the device's make and model. This one, however, should work on most – *#*#4636#*#* (or *#*#INFO#*#*). It takes the user to a testing menu where network information is displayed, along with details on battery status and app activity. Be warned: don't change anything and don't press any buttons in this menu unless you know what they do! On a side note, this particular menu was used to "enable" 4G LTE in Canada on the Nexus 4.
And if you own a Nokia Lumia smartphone, try dialing ##634#. This will take you to an on-device diagnostics tool where the phone's hardware can be tested from. It will also let you see your phone's battery consumption in real time.
And what is the use of this for the average joe? All the same, I know some few samsung secret codes already.
Not everyone's an average joe.
I'm sure a lot of average joes read Phone Arena. It's not just about commenting.
the guy just said something and u already want to eat him up my goodness.
On my Lumia 710, after opening the hidden menu from the dialer, it appears on my list of installed apps. Does it do the same for Windows Phone 8/8.1?
"On a side note, this particular menu was used to "enable" 4G LTE in Canada on the Nexus 4." On a side note, this particular menu was used to "enable" 4G LTE in Canada on the Nexus 4 (And on T-Mobile in the US) There, fixed that for you!
I found the 4636 code and used it because AT&T didn't freaking let me switch between Edge, WCDMA, and LTE, in the normal settings.
While codes are fun, as the post points out, some of them give you the ability to mess up your phone. For Android, Network Info II (Alexander Schillings, donation-ware) will give you more information than I knew what to do with (although other PA readers will undoubtably understand it all).
You guys should see the hidden settings and config options on the iPhone. Its ridiculously crazy.


There are and have been many Jazz festivals around the world every year, but for the most part, they are all pretty much alike, sadly nothing special. EllaFest will be the Rolls Royce of Jazz Festivals, the only one deserving to celebrate the greatest vocalist and Jazz artist of all time, Ella Fitzgerald. No corn dogs, carnival food or County Fair atmosphere. Instead this special event with feature quaint bistro tables, wine, cheese, top chefs, upscale everything.
Hosted by the wonderfully talented Jazz vocalist, Ella's son, Ray Brown Jr, this festival will present the top Jazz artists, and unlike other so-called Jazz festivals, there will be no rock acts to sell more tickets. Since this will be the premiere Jazz festival all major Jazz stars want to appear here. There will be multiple stages for non-stop live music.
Starting on a Friday evening, EllaFest will open with a video montage of Ella's performances followed by Ray Brown, Jr doing a Tribute to his legendary mother. The festival will continue all day Saturday with a top name artist headliner, Sunday evening will close with The Inductions & Awards Ceremony of The International Jazz Hall Of Fame, which will be taped for a television special.
This will be an upscale event catering to an adult, highly educated and affluent audience. Produced by music industry veteran Shelly Liebowitz, Ray Brown Jr and staged by Joe Buffalino.


DCNPL Green Ville, is a gated plot community on the Indore-Ujjain Road, Indore. The community hosts several plots of varied sizes. Its strategic location renders great connectivity to both Indore and Ujjain, while being at a convenient distance from the Central Business District of Indore.
DCNPL Green Ville is located in what can be described as the most posh locales of Indore - just off the Indore-Ujjain highway. The enclave is close to some of the finest educational institutions, hospitals, shopping centres, IT campuses, railway station, airport etc.


If your looking for WOWE Kult der Verdammten (Alliance) Gold, you have come to the right place. Nows the time to buy WOWE Kult der Verdammten (Alliance) Gold, and get all of your desired items. So why not buy some on WOWE Kult der Verdammten (Alliance) today? We have been delivering to World of Warcraft EURO for many years where our main focus is so you are having fun and less time spent farming for cheap World of Warcraft EURO Gold.


text:
Home Economy Agriculture Sri Lanka lifts its ban on fertilizers due to political concerns
Sri Lanka lifts its ban on fertilizers due to political concerns
Despite farmer warnings of food shortages and significant damage to the vast tea sector, Sri Lanka's government backed down from relaxing an import restriction on most chemical fertilizers on Thursday (Aug 5) due to political concerns. The South Asian nation has been dealing with a financial constraint exacerbated by the pandemic. The central bank has been enacting wide import bans to stem the outflow of foreign currency since March last year.
Farmers protested the restriction on chemical fertilizers, which are widely used in the tea and rice industries. Farmers reported failed vegetable crops as current stocks began to run out in recent weeks, prompting them to mount protests. The embargo was lifted on Tuesday by Finance Minister Basil Rajapaksa, President Gotabaya Rajapaksa's younger brother.
The President had previously hailed the strategy as assisting Sri Lankan agriculture in becoming "100% organic," including on the world scene. Secretary to the Ministry of Agriculture Udith Jayasinghe told reporters in Colombo that there has been "no change in the government policy move to organic fertilizer."
Under careful regulation, some nitrogen-rich plant fertilizers will be permitted.
Urea fertilizer, which will continue to be banned, is widely used in the US$1.25 billion (S$1.69 billion) tea business and rice growing, the country's primary food. Sri Lanka is one of the world's largest tea exporters. Ceylon tea is prized for its flavor and good quality.
Previous articleProtesters gather at a funeral of a 9-year-old girl who was allegedly raped and murdered: India
Next articleThailand investigates the death of a Swiss visitor who died near a Phuket waterfall

redpajama_set_name: RedPajamaCommonCrawl


I need inf on a CHF page so I can install a steering stabilizer on my 2016 ford F53 chassis. Thank you for your input.
YouTube will have some good insight on the install and modifications.
Chf is moving the anti sway bar, front and rear, to the tighter setting by moving the connecting rod to the upper hole, thus stiffening the anti sway bar. The anti sway bar helps the tipping of the RV from side to side. Keeps the RV more stabile from side to side movements.
A steering stabilizer connects from some rigid part of the front end to the tie rod, which is a long bar that connects to both sides of the front end and keeps both wheels moving in unison. The stabilizer is basically a shock and spring, the spring helps to keep the steering centered and brings the steering back to center quicker after making turns. The shock helps to dampen the steering inputs and feedback from deformations in the road.


text:
In Pushkin's footsteps
Phoebe Taplin
A photo of Alexander Pushkin's portrait. Source: RIA Novosti
On the eve of Alexander Pushkin's birthday RBTH's Phoebe Taplin conveys four scenes from the life and death of Russia's greatest poet.
The creator of Russian literature as we know it was born 213 years ago this week. Alexander Pushkin's verse narrative, Eugene Onegin, effectively started the world famous tradition of Russian novels; his plays and stories inspired operas, songs and ballets and it is rare to meet a Russian who cannot quote his poetry by heart. It is hardly surprising, then, that every town and village wants a piece of him.
Numerous stately homes, churches and cottages claim a connection with the celebrated writer and many places have memorials to him. There is a bronze bust of the poet outside the Moscow school that replaced his probable birthplace. Pushkin was baptized in the glorious, turquoise Epiphany cathedral round the corner.
"The minutes of childhood"
An hour west of Moscow, near the village of Zakharovo, another of Russia's hundreds of Pushkin monuments stands in a small orchard that once belonged to his maternal grandmother, Maria Hannibal. The young Pushkin spent several summers here, in the birch woods near the lake; he later wrote: "My Zakharovo … reflected in the mirror of waters, with its fences, bridge and shady grove" and recalled "with what quiet beauty, the minutes of childhood flowed." The statue shows the poet as a boy, leaning on his grandmother's lap, book in hand, gazing portentously into the distance, as if already conscious that his future greatness is being nurtured by the natural surroundings.
Read more about Russia's literature
The museum, inside the reconstructed wooden house with a belvedere, continues in the same vein. Miscellaneous nineteenth century objects are used to conjure up a sense of the past, and every view and corner is embellished with quotations. A bust of Peter I on the writing desk reinforces the family's history; Pushkin's great grandfather was the captured African prince, Abram Petrovich Hannibal, who became a Russian nobleman and general, and godson of the Tsar. Pushkin later started to write a historical novel about Hannibal, translated as The Negro of Peter the Great.
Illustrations for Pushkin's fairy-tales. Source: Ivan Bilibin
A marble column outside the lovely sixteenth century Transfiguration Church at nearby Vyazyomy marks the grave of Nikolai Pushkin, the poet's younger brother, who died when he was six. In one poem, Pushkin describes an autumn visit to the graveyard "where drowse the dead in solemn peace." This neighboring estate has had many owners, including Boris Godunov, subject of one of Pushkin's best known plays. The current house, with its park of lime trees, was built by the Golitsyn family in the late eighteenth century. Pushkin often stayed here when it belonged to Natalia Golitsyna who was the model for the ancient countess in his story of madness and gambling, The Queen of Spades.
"I am married – and happy"
Pushkin was forced to leave this childhood idyll for his school at Tsarskoe Selo near Saint Petersburg when he was twelve, but he nostalgically revisited the area one last time, just before he got married. Having become a famous poet while still at the Lyceum, Pushkin threw himself into the literary and political life of Saint Petersburg. His involvement in movements for social reform led to censorship and exile. He travelled through the Caucasus and the Crimea and spent two years at his mother's estate in Mikhailovskoe. He wrote later of his delight there in "country life, Russian baths and strawberries"
In 1831, Pushkin married Natalia Goncharova in the church of the Grand Ascension in central Moscow. Having fallen in love at a ball, the poet finally got permission to marry the beautiful 17-year-old, but the wedding day was beset by "evil omens" (dropped wedding rings and blown-out candles). There is a small, gold statue of the couple under a dome outside the church and another, larger version opposite the flat on Arbat Street where they spent their first months of married life.
Pushkin's letters of the time suggest another briefly idyllic period: "I am married – and happy," he wrote; "My only wish is that nothing will change … This condition is so new to me that I feel reborn." A few months in the same city as his mother-in-law, however, saw him packing to move with his wife back to St Petersburg. "I do not like Moscow life", he declared; "You live here not as you want to live, but as old women want you to."
"An icy corpse on the sleigh"
Eugene Onegin prefigures Pushkin's own death; the hero fights a duel, with pistols in the snow, against his friend, Lensky, a poet (whose frozen corpse is then loaded onto the sleigh they arrived in). This case of life imitating art is particularly curious since a major theme in Onegin is the relationship between literature and real life.
On a winter evening in 1837, Pushkin travelled by sleigh from Nevsky Prospekt to the "Black River" area of Petersburg, then filled with woods and dachas, where George D'Anthes fatally wounded him in the stomach; the poet had become convinced that D'Anthes was flirting (and maybe more) with his wife and challenged the French cavalry officer to a duel.
The drama of the ensuing scene, with Pushkin's blood on the snow, has inspired hundreds of poems, plays and paintings, one of which can be seen in Moscow's Pushkin museum on Prechistenka Street. This comprehensive storehouse of Pushkinalia, well worth the modest entrance fee, includes exhibitions on each of Pushkin's major works, plus much-amended manuscript pages covered in trademark doodles and sketches. The museum also charts the poet's life through to its untimely end; the picture reconstructs the scene of the duel, with dying bard and fur-lined troika.
Back in Petersburg, the city's most popular literary museum is Pushkin's last home in the old Volkonsky House, where he lay dying for two days after the duel. Along with other possessions, the museum displays the poet's death mask and last waistcoat, complete with fatal bullet hole. There is a granite obelisk at the site of the duel and another statue in the nearest metro station.
"Long will I be honored by the people"
One of the most significant monuments to Pushkin is the high bronze statue at the crossroads of Moscow's Boulevard Ring and Tverskaya Street. The inscription below it predicts: "Long will I be honored by the people…" It was unveiled in 1880 to the accompaniment of speeches by Fyodor Dostoevsky and Ivan Turgenev.
Later writers were also drawn to the memorial; the poet Marina Tsvetaeva wrote: "I can see those … African shoulders loaded down and overwhelmed with all the Russian snows!" The "metal man on a plinth" also makes a cameo appearance in Bulgakov's The Master and Margarita and has a crucial symbolic role in Tatyana Tolstaya's dystopian novel, Slynx. In this and many other works, Pushkin has become a metaphor for quintessential Russianness. Turgenev declared at its unveiling that the statue would "announce to future generations our right to call ourselves a great nation, because this nation has given birth to such a man."
culture Russian history read russia! literature alexander pushkin Literature Viral in Russia Bookworm's blog The X-Pat Files


Do not have this feature. I will add in the future.
I do not have dual sim option present in DW. In facts, calls to both sims can be answered, but I cannot select which sim to use for outgoing calls.
My device is ZTE Nubia Z7 mini. Model number NX507J, nubia UI V2.5.0, Android 4.4.2.
Could you add this to the supported devices?
Thanks, it worked. I could add a second dial button and the phone used the correct SIM for dialing – depending on which sim button I pressed.
2.and facing a problem of indication "Low memory – main" whats that?
This requires your device is already in DW Contacts support. When you hold down the dial button on the contact list dialog box appears select the SIM card do?
Please try the this test file.
Try to enter your own number in the number box, to avoid unexpected call. then use the list of each dial button. try to find one can be normal use two sim card dial.
If found, please copy the top of the list of device information. And be able to work in the name of the list item. Send this information to me.
You are using the test version of the DW contacts?
It does not work it?
I have the same problem. I tried test-Dual-SIM and my phone (Manufacturer: JIAYU Model:JY-G4) uses two sim card like "Lenovo A630".
Thank you, I've added your device.
For the future: Would be possible to associate own colours to sim cards? Or in the best case to give them also own short names (e.g. O2) instead of numbers 1 or 2?
I want to copy contact from one account to another not between groups (from Microsft to Google or vice-versa) how it can be done.
Press and hold the contact you want to copy. In the popup menu, select More. Then select duplicate.
Events stored in the contact database when you synchronize contacts it will be synchronized. If you need to add the event to your calendar program. Now only be added individually. By opening event entries long press menu.
Since the new version adding a tab in settings is not saved and not visible.
It works fine on my phone. Please try to uninstall and then reinstall.
Maybe you did not choose to display all accounts in the account settings.
I have just bought the latest version, and I have photo contacts already appearing, could I please ask? how do you add a picture to the contacts that the pics are already in my phone but I can't seem to add them in beside the phone number now I have this version!!
Sorry, please forgive my bad English.I probably did not understand what you mean.
You need to modify a contact's picture?
You need to edit a contact interface, click on an existing picture. In the menu you can choose to replace the picture.
Does this app show caller id feature for contacts that are only in this app and not in the native contact app?? So, Will I see the name appear when someone calls or sends a text if their name isnt in the native contacts app?
No, DWC only read the contacts in the contact database.
Please how can remove the desktop widgets?
When I make a call on the top of the desktop there is a widgets that a want to remove.
Turn off all options here.
Sorry – One more thing: Can you please add an option for drop-shadow on fonts?
I will add the theme API in the new version.
So you can download the theme package.
Love this dialer! Thank you! One question: With SO MUCH ability to adjust the theme and change colors, I seem to be missing (not finding) one setting… Is there a way to change the default Red-Selected, Yellow-Active, etc. on the Main Bar (Phone, Favorites, Contacts, Groups etc.)?
As a business, we have hundreds of business contacts with multiple contacts within each business.
We use "groups" in our Outlooks to group the type of contacts, i.e.
THEN, we need to display the contact by COMPANY name not first or last name.
Hello, thanks for your suggestions.I will consider implement it.
Now you can enter a group, and then switch to the organization tab.
I want to thank U for such good app. One suggestion: can U add the ability to dirrect call by typing on the photo in the grid view favorities instead of additional menu (Call, Send SMS, etc) ?
When a call comes in , a menu is available to send auto SMS responder, instead of answering the calls.
These SMS auto responders can be edited and/or personalized ?
DWC does not include this feature now, I think you see to send SMS from the system.
Can I set a direct dial the default or mobile number when i press the name row?
Because my finger is short to press "phone" icon when i use my left hand. It is very uncomfortable and inconvenience when i just have one hand free.
Hello, this feature is not yet complete. But you can customize the dial-up icon is on the right or the left.
How do I edit the default SEND SMS when the caller is calling and I want to send SMS instead of answering the call ?
Now you can modify the "message signature" option. It is in the "SMS & Email settings". It is similar to the default text.
I selected Last Name sort order and then did a synch on my Google Account contact list, but the names still show up with a first name sort. What do I need to do to get a last name sort?
Hello, please select the "Alternate sort order" to try again. Thank you!


text:
Q: Bash: need help passing a a variable to rsync I want to pass $home as a list of directories to be excluded when running rsync. The file:
cat backup_system.sh
#!/bin/bash
set -x
home=''
home=$home'"/home/ravas/Documents/*"',
home=$home'"/home/ravas/Downloads/*"',
home=$home'"/home/ravas/pCloudDrive/*"',
home=$home'"/home/ravas/pCloudLocal/*"',
home=$home'"/home/ravas.old/*"'
echo $home
sudo rsync -aAXv / --exclude={$home,"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} /run/media/ravas/system_backup

The backup runs fine without the $home variable, but if I add it, it doesn't have any effect.
The last two lines of the output show that the directories listed in $home are not expanded with --exclude, whereas the others are.
Needless to say, I'm not very good at bash, and any help would be much appreciated!
./backup_system.sh
+ home=
+ home='"/home/ravas/Documents/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*",'
+ home='"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"'
+ echo '"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"'
"/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"
+ sudo rsync -aAXv /
'--exclude="/home/ravas/Documents/*","/home/ravas/Downloads/*","/home/ravas/pCloudDrive/*","/home/ravas/pCloudLocal/*","/home/ravas.old/*"'
'--exclude=/dev/*' '--exclude=/proc/*' '--exclude=/sys/*' '--exclude=/tmp/*' '--exclude=/run/*' '--exclude=/mnt/*' '--exclude=/media/*' --exclude=/lost+found** /run/media/ravas/system_backup

A: The basic problem is the order that bash parses various things in your command is all wrong for what you're trying to do. Specifically, it parses (and applies and removes) quotes & escapes, then expands {this,that,theother} lists, then expands variable references (like $home). Net result is that by the time $home expands to a comma-separated list of quoted elements, it's too late for either the quotes or commas to have their intended effect.
As usual in cases like this, arrays are the best way to handle this:
homearray=()
homearray+=("/home/ravas/Documents/*")
homearray+=("/home/ravas/Downloads/*")
homearray+=("/home/ravas/pCloudDrive/*")
homearray+=("/home/ravas/pCloudLocal/*")
homearray+=("/home/ravas.old/*")
# Alternate short form:
# homearray=(/home/ravas/{Documents,Downloads,pCloudDrive,pCloudLocal}/"*" "/home/ravas.old/*")
sudo rsync -aAXv / "${homearray[@]/#/--exclude=}" --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} /run/media/ravas/system_backup

Explanation: "${homearray[@]/#/--exclude=}" does three things; first, the [@] makes it expand to all of the elements of the array; then the /#/--exclude= "replaces" the beginning of each element with "--exclude=" (essentially, it prepends "--exclude=" to each element), and finally the double-quotes around it keep the wildcards ("*") from expanding and wreaking havoc.

A: The solution to almost all multiple-argument-related problems is to use an array:
exclusions=(
  --exclude "/home/ravas/Documents/*"
  --exclude "/home/ravas/Downloads/*"
  --exclude "/home/ravas/pCloudDrive/*"
  --exclude "/home/ravas/pCloudLocal/*"
  --exclude "/home/ravas.old/*"
  --exclude "/dev/*"
  --exclude "/proc/*"
  --exclude "/sys/*"
  --exclude "/tmp/*"
  --exclude "/run/*"
  --exclude "/mnt/*"
  --exclude "/media/*"
  --exclude "/lost+found"
)

sudo rsync -aAXv / "${exclusions[@]}" /run/media/ravas/system_backup

If you aren't using standard input for anything else, you can use the --exclude-from option with a here document to shorten this a bit:
sudo rsync -aAXv / --exclude-from - /run/media/ravas/system_backup <<EOF
/home/ravas/Documents/*
/home/ravas/Downloads/*
/home/ravas/pCloudDrive/*
/home/ravas/pCloudLocal/*
/home/ravas.old/*
/dev/*
/proc/*
/sys/*
/tmp/*
/run/*
/mnt/*
/media/*
/lost+found
EOF

A: String handling in Bash is rarely straightforward, but here's something that sort of works...
( list=abc,'"def\ ghi"',jkl ; eval echo --exclude={$list} )

output:
--exclude=abc --exclude=def\ ghi --exclude=jkl

See eval command in Bash and its typical uses

redpajama_set_name: RedPajamaStackExchange


text:
Ruhi Naze (last name also spelled Naj, Naaj, Naz or Naaz) is a Nepali politician and a member of the House of Representatives of the federal parliament of Nepal. She was elected under the proportional representation system from Federal Socialist Forum, Nepal.

References

Living people
Place of birth missing (living people)
21st-century Nepalese politicians
21st-century Nepalese women
Nepal MPs 2017–2022
Madhesi Jana Adhikar Forum, Nepal politicians
People's Socialist Party, Nepal politicians
1971 births

redpajama_set_name: RedPajamaWikipedia


text:
Lothar Matthaus encourages Bastian Schweinsteiger to consider Manchester United move
Manchester United transfer target Bastian Schweinsteiger has been advised by former Bayern Munich midfielder Lothar Matthaus to join Louis Van Gaal at Old Trafford.
Schweinsteiger, a life long Bayern man, is coming into the final year of his contract and has been rumoured to have been tempted by a move to Man United this summer.
The 31-year-old midfielder struggled to recapture his best form during an injury hit campaign last term in which he scored a total of five goals.
Speaking to Bild, German coach and ex-player Matthaus spoke of how a move to Manchester could revive his career.
"Schweinsteiger needs a coach that will play him according to his strengths and Van Gaal will surely do that. If there is an offer from Manchester, Bastian should give it serious consideration," Matthaus said.
"He's never been the fastest player in the world and, as he turns 31 soon, that will not improve but he is certainly intelligent enough and has the necessary vision to be the central link between defence and offensive midfield."
Schweinsteiger was managed by Louis Van Gaal for two years when he lead Bayern to the German title in 2009 and this could prove important in the outcome of this potential signing.
The player wouldn't be guaranteed a automatic place at United and would have to take the amount of playing time he would get into consideration. With the likes of Daley Blind, Ander Herrera, and Marouanne Fellaini already at the club, all of whom are in their prime, it would be hard to justify a large price tag for the German. However, if van Gaal can get him on the cheap, it would be an excellent bit of business.
Tags:Bastian Schweinsteiger
Bastian Schweinsteiger: 'Louis van Gaal was desperate to sign Thomas Muller at Manchester United'
Ian Wright: Luke Shaw should follow exemplary Bastian Schweinsteiger example
Louis van Gaal laments Jose Mourinho's treatment of Bastian Schweinsteiger
Bastian Schweinsteiger encourages MLS move for Zlatan Ibrahimovic
Bastian Schweinsteiger opens up about his struggles at Manchester United
Bastian Schweinsteiger reacts to receiving public apology from Jose Mourinho


23 Jun - 3 min - Uploaded by Sam Patel THE LINK: lafermedejonan.com# Avatar the Legend of Korra episode 23 Jun - 8 min - Uploaded by Double4anime This is my review for legend of korra epsiode 11 and So Amon is Tarrloks brother, Korra. 19 Jun - 40 sec - Uploaded by Don Cheung Avatar: The Legend of Korra Episode 11 - 12 preview season Finale. Don Cheung. Loading. Watch Legend of Korra Book 1 Episode 11 online only at lafermedejonan.com!. 5 Mar Nonton Online Avatar: The Legend of Korra Book 2 Episode Subtitle Indonesia ep sub.