// 
//
//  Typical 3d vector math code.
//  By S Melax 1998-2008
// 
//
//

#include "vecmath.h"
#include <memory.h> // for memcpy
#include <float.h>

float   squared(float a){return a*a;}
float   clamp(float a,const float minval, const float maxval) {return Min(maxval,Max(minval,a));}
int     clamp(int a,const int minval, const int maxval) {return Min(maxval,Max(minval,a));}


float Round(float a,float precision) 
{
	return floorf(0.5f+a/precision)*precision;
}


float Interpolate(const float &f0,const float &f1,float alpha) 
{
	return f0*(1-alpha) + f1*alpha;
}


int     argmin(const float a[],int n)
{
	int r=0;
	for(int i=1;i<n;i++) 
    {
		if(a[i]<a[r]) 
        {
			r = i;			
		}
	}
	return r;
}


int     argmax(const float a[],int n)
{
	int r=0;
	for(int i=1;i<n;i++) 
	{
		if(a[i]>a[r]) 
		{
			r = i;			
		}
	}
	return r;
}



//------------ float3 (3D) --------------



float3 vabs(const float3 &v)
{
	return float3(fabsf(v.x),fabsf(v.y),fabsf(v.z));
}



float3 safenormalize(const float3 &v)
{
	if(magnitude(v)<=0.0f)
	{
		return float3(1,0,0);
	}
	return normalize(v);
}

float3 Round(const float3 &a,float precision)
{
	return float3(Round(a.x,precision),Round(a.y,precision),Round(a.z,precision));
}


float3 Interpolate(const float3 &v0,const float3 &v1,float alpha) 
{
	return v0*(1-alpha) + v1*alpha;
}

float3 Orth(const float3& v)
{
	float3 absv=vabs(v);
	float3 u(1,1,1);
	u[argmax(&absv[0],3)] =0.0f;
	return normalize(cross(u,v));
}

void BoxLimits(const float3 *verts,int verts_count, float3 &bmin,float3 &bmax)
{
	bmin=float3( FLT_MAX, FLT_MAX, FLT_MAX);
	bmax=float3(-FLT_MAX,-FLT_MAX,-FLT_MAX);
	for(int i=0;i<verts_count;i++)
	{
		bmin = VectorMin(bmin,verts[i]);
		bmax = VectorMax(bmax,verts[i]);
	}
}	
void BoxLimits(const float4 *verts,int verts_count, float3 &bmin,float3 &bmax)
{
	bmin=float3( FLT_MAX, FLT_MAX, FLT_MAX);
	bmax=float3(-FLT_MAX,-FLT_MAX,-FLT_MAX);
	for(int i=0;i<verts_count;i++)
	{
		bmin = VectorMin(bmin,verts[i].xyz());
		bmax = VectorMax(bmax,verts[i].xyz());
	}
}
int overlap(const float3 &bmina,const float3 &bmaxa,const float3 &bminb,const float3 &bmaxb)
{
	for(int j=0;j<3;j++)
	{
		if(bmina[j]>bmaxb[j]) return 0;
		if(bminb[j]>bmaxa[j]) return 0;
	}
	return 1;
}

// the statement v1*v2 is ambiguous since there are 3 types
// of vector multiplication
//  - componantwise (for example combining colors)
//  - dot product
//  - cross product
// Therefore we never declare/implement this function.
// So we will never see:  float3 operator*(float3 a,float3 b) 




//------------ float3x3 ---------------
float Determinant(const float3x3 &m)
{
	return  m.x.x*m.y.y*m.z.z + m.y.x*m.z.y*m.x.z + m.z.x*m.x.y*m.y.z 
		   -m.x.x*m.z.y*m.y.z - m.y.x*m.x.y*m.z.z - m.z.x*m.y.y*m.x.z ;
}

float3x3 Inverse(const float3x3 &a)
{
	float3x3 b;
	float d=Determinant(a);
	assert(d!=0);
	for(int i=0;i<3;i++) 
    {
		for(int j=0;j<3;j++) 
        {
			int i1=(i+1)%3;
			int i2=(i+2)%3;
			int j1=(j+1)%3;
			int j2=(j+2)%3;
			// reverse indexs i&j to take transpose
			b[j][i] = (a[i1][j1]*a[i2][j2]-a[i1][j2]*a[i2][j1])/d;
		}
	}
	// Matrix check=a*b; // Matrix 'check' should be the identity (or close to it)
	return b;
}


float3x3 Transpose( const float3x3& m )
{
	return float3x3( float3(m.x.x,m.y.x,m.z.x),
					float3(m.x.y,m.y.y,m.z.y),
					float3(m.x.z,m.y.z,m.z.z));
}


float3 operator*(const float3& v , const float3x3 &m ) { 
	return float3((m.x.x*v.x + m.y.x*v.y + m.z.x*v.z), 
				  (m.x.y*v.x + m.y.y*v.y + m.z.y*v.z), 
				  (m.x.z*v.x + m.y.z*v.y + m.z.z*v.z));
}
float3 operator*(const float3x3 &m,const float3& v  ) { 
	return float3(dot(m.x,v),dot(m.y,v),dot(m.z,v));
}


float3x3 operator*( const float3x3& a, const float3x3& b )  
{ 
	return float3x3(a.x*b,a.y*b,a.z*b); 
}

float3x3 operator*( const float3x3& a, const float& s )  
{ 
	return float3x3(a.x*s, a.y*s ,a.z*s); 
}
float3x3 operator/( const float3x3& a, const float& s )  
{ 
	float t=1/s;
	return float3x3(a.x*t, a.y*t ,a.z*t); 
}
float3x3 operator+( const float3x3& a, const float3x3& b )
{
	return float3x3(a.x+b.x, a.y+b.y, a.z+b.z);
}
float3x3 operator-( const float3x3& a, const float3x3& b )
{
	return float3x3(a.x-b.x, a.y-b.y, a.z-b.z);
}
float3x3 &operator+=( float3x3& a, const float3x3& b )
{
	a.x+=b.x;
	a.y+=b.y;
	a.z+=b.z;
	return a;
}
float3x3 &operator-=( float3x3& a, const float3x3& b )
{
	a.x-=b.x;
	a.y-=b.y;
	a.z-=b.z;
	return a;
}
float3x3 &operator*=( float3x3& a, const float& s )
{
	a.x*=s;
	a.y*=s;
	a.z*=s;
	return a;
}

float3x3 outerprod(const float3& a,const float3& b)
{
	return float3x3(a.x*b,a.y*b,a.z*b);  // a is a column vector b is a row vector
}

//--------------- 4D ----------------

float4   operator*( const float4&   v, const float4x4& m )
{
	return v.x*m.x + v.y*m.y + v.z*m.z + v.w*m.w; // yes this actually works
}


//  Dont implement m*v for now, since that might confuse us
//  All our transforms are based on multiplying the "row" vector on the left
//float4   operator*(const float4x4& m , const float4&   v )
//{
//	return float4(dot(v,m.x),dot(v,m.y),dot(v,m.z),dot(v,m.w));
//}


float4x4 operator*( const float4x4& a, const float4x4& b )
{
	return float4x4(a.x*b,a.y*b,a.z*b,a.w*b);
}

float4x4 MatrixTranspose(const float4x4 &m)
{
	return float4x4(
		m.x.x, m.y.x, m.z.x, m.w.x,
		m.x.y, m.y.y, m.z.y, m.w.y,
		m.x.z, m.y.z, m.z.z, m.w.z,
		m.x.w, m.y.w, m.z.w, m.w.w );
}

float4x4 MatrixRigidInverse(const float4x4 &m)
{
	float4x4 trans_inverse = MatrixTranslation(-m.w.xyz());
	float4x4 rot   = m;
	rot.w = float4(0,0,0,1);
	return trans_inverse * MatrixTranspose(rot);
}


float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf )
{
	float h = 1.0f/tanf(fovy/2.0f); // view space height
	float w = h / aspect ;  // view space width
	return float4x4(
		w, 0, 0             ,   0,
		0, h, 0             ,   0,
		0, 0, zf/(zn-zf)    ,  -1,
		0, 0, zn*zf/(zn-zf) ,   0 );
}



float4x4 MatrixLookAt(const float3& eye, const float3& at, const float3& up)
{
	float4x4 m;
	m.w.w = 1.0f;
	m.w.xyz() = eye;
	m.z.xyz() = normalize(eye-at);
	m.x.xyz() = normalize(cross(up,m.z.xyz()));
	m.y.xyz() = cross(m.z.xyz(),m.x.xyz());
	return MatrixRigidInverse(m);
}


float4x4 MatrixTranslation(const float3 &t)
{
	return float4x4(
		1,  0,  0,  0,
		0,  1,  0,  0,
		0,  0,  1,  0,
		t.x,t.y,t.z,1 );
}


float4x4 MatrixRotationZ(const float angle_radians)
{
	float s =  sinf(angle_radians);
	float c =  cosf(angle_radians);
	return float4x4(
		c,  s,  0,  0,
		-s, c,  0,  0,
		0,  0,  1,  0,
		0,  0,  0,  1 );
}



int operator==( const float4x4 &a, const float4x4 &b )
{
	return (a.x==b.x && a.y==b.y && a.z==b.z && a.w==b.w);
}


float4x4 Inverse(const float4x4 &m)
{
	float4x4 d;
	float *dst = &d.x.x;
	float tmp[12]; /* temp array for pairs */
	float src[16]; /* array of transpose source matrix */
	float det; /* determinant */
	/* transpose matrix */
	for ( int i = 0; i < 4; i++) {
		src[i] = m(i,0) ;
		src[i + 4] = m(i,1);
		src[i + 8] = m(i,2);
		src[i + 12] = m(i,3); 
	}
	/* calculate pairs for first 8 elements (cofactors) */
	tmp[0]  = src[10] * src[15];
	tmp[1]  = src[11] * src[14];
	tmp[2]  = src[9] * src[15];
	tmp[3]  = src[11] * src[13];
	tmp[4]  = src[9] * src[14];
	tmp[5]  = src[10] * src[13];
	tmp[6]  = src[8] * src[15];
	tmp[7]  = src[11] * src[12];
	tmp[8]  = src[8] * src[14];
	tmp[9]  = src[10] * src[12];
	tmp[10] = src[8] * src[13];
	tmp[11] = src[9] * src[12];
	/* calculate first 8 elements (cofactors) */
	dst[0]  = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];
	dst[0] -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];
	dst[1]  = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];
	dst[1] -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];
	dst[2]  = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];
	dst[2] -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];
	dst[3]  = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];
	dst[3] -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];
	dst[4]  = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];
	dst[4] -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];
	dst[5]  = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];
	dst[5] -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];
	dst[6]  = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];
	dst[6] -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];
	dst[7]  = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];
	dst[7] -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];
	/* calculate pairs for second 8 elements (cofactors) */
	tmp[0]  = src[2]*src[7];
	tmp[1]  = src[3]*src[6];
	tmp[2]  = src[1]*src[7];
	tmp[3]  = src[3]*src[5];
	tmp[4]  = src[1]*src[6];
	tmp[5]  = src[2]*src[5];
	tmp[6]  = src[0]*src[7];
	tmp[7]  = src[3]*src[4];
	tmp[8]  = src[0]*src[6];
	tmp[9]  = src[2]*src[4];
	tmp[10] = src[0]*src[5];
	tmp[11] = src[1]*src[4];
	/* calculate second 8 elements (cofactors) */
	dst[8]  = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];
	dst[8] -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];
	dst[9]  = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];
	dst[9] -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];
	dst[10] = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];
	dst[10]-= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];
	dst[11] = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];
	dst[11]-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];
	dst[12] = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];
	dst[12]-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];
	dst[13] = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];
	dst[13]-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];
	dst[14] = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];
	dst[14]-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];
	dst[15] = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];
	dst[15]-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];
	/* calculate determinant */
	det=src[0]*dst[0]+src[1]*dst[1]+src[2]*dst[2]+src[3]*dst[3];
	/* calculate matrix inverse */
	det = 1/det;
	for ( int j = 0; j < 16; j++)
	dst[j] *= det;
	return d;
}


//--------- Quaternion --------------
   
template<> void Quaternion::Normalize()
{
	float m = sqrtf(squared(w)+squared(x)+squared(y)+squared(z));
	if(m<0.000000001f) {
		w=1.0f;
		x=y=z=0.0f;
		return;
	}
	(*this) *= (1.0f/m);
}

float3 rotate( const Quaternion& q, const float3& v )
{
	// The following is equivalent to:   
	//return (q.getmatrix() * v);  
	float qx2 = q.x*q.x;
	float qy2 = q.y*q.y;
	float qz2 = q.z*q.z;

	float qxqy = q.x*q.y;
	float qxqz = q.x*q.z;
	float qxqw = q.x*q.w;
	float qyqz = q.y*q.z;
	float qyqw = q.y*q.w;
	float qzqw = q.z*q.w;
	return float3(
		(1-2*(qy2+qz2))*v.x + (2*(qxqy-qzqw))*v.y + (2*(qxqz+qyqw))*v.z ,
		(2*(qxqy+qzqw))*v.x + (1-2*(qx2+qz2))*v.y + (2*(qyqz-qxqw))*v.z ,
		(2*(qxqz-qyqw))*v.x + (2*(qyqz+qxqw))*v.y + (1-2*(qx2+qy2))*v.z  );
}


Quaternion slerp(const Quaternion &_a, const Quaternion& b, float interp )
{
	Quaternion a=_a;
	if(dot(a,b) <0.0) 
    {
		a.w=-a.w;
		a.x=-a.x;
		a.y=-a.y;
		a.z=-a.z;
	}
	float d = dot(a,b);
	if(d>=1.0) {
		return a;
	}
	float theta = acosf(d);
	if(theta==0.0f) { return(a);}
	return a*(sinf(theta-interp*theta)/sinf(theta)) + b*(sinf(interp*theta)/sinf(theta));
}


Quaternion Interpolate(const Quaternion &q0,const Quaternion &q1,float alpha) {
	return slerp(q0,q1,alpha);
}


Quaternion YawPitchRoll( float yaw, float pitch, float roll ) 
{
	return   QuatFromAxisAngle(float3(0.0f,0.0f,1.0f),DegToRad(yaw  ))
	       * QuatFromAxisAngle(float3(1.0f,0.0f,0.0f),DegToRad(pitch))
	       * QuatFromAxisAngle(float3(0.0f,1.0f,0.0f),DegToRad(roll ));
}

float Yaw( const Quaternion& q )
{
	static float3 v;
	v=q.ydir();
	return (v.y==0.0&&v.x==0.0) ? 0.0f: RadToDeg(atan2f(-v.x,v.y));
}

float Pitch( const Quaternion& q )
{
	static float3 v;
	v=q.ydir();
	return RadToDeg(atan2f(v.z,sqrtf(squared(v.x)+squared(v.y))));
}

float Roll( const Quaternion &_q )
{
	Quaternion q=_q;
	q = QuatFromAxisAngle(float3(0.0f,0.0f,1.0f),-DegToRad(Yaw(q)))  *q;
	q = QuatFromAxisAngle(float3(1.0f,0.0f,0.0f),-DegToRad(Pitch(q)))  *q;
	return RadToDeg(atan2f(-q.xdir().z,q.xdir().x));
}

float Yaw( const float3& v )
{
	return (v.y==0.0&&v.x==0.0) ? 0.0f: RadToDeg(atan2f(-v.x,v.y));
}

float Pitch( const float3& v )
{
	return RadToDeg(atan2f(v.z,sqrtf(squared(v.x)+squared(v.y))));
}






//--------- utility functions -------------

//        RotationArc()
// Given two vectors v0 and v1 this function
// returns quaternion q where q*v0==v1.
// Routine taken from game programming gems.
Quaternion RotationArc(float3 v0,float3 v1){
	static Quaternion q;
	v0 = normalize(v0);  // Comment these two lines out if you know its not needed.
	v1 = normalize(v1);  // If vector is already unit length then why do it again?
	float3  c = cross(v0,v1);
	float   d = dot(v0,v1);
	if(d<=-1.0f) { float3 a=Orth(v0); return Quaternion(a.x,a.y,a.z,0);} // 180 about any orthogonal axis axis
	float   s = sqrtf((1+d)*2);
	q.x = c.x / s;
	q.y = c.y / s;
	q.z = c.z / s;
	q.w = s /2.0f;
	return q;
}


float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v) 
{
	// builds a 4x4 transformation matrix based on orientation q and translation v 
	float qx2 = q.x*q.x;
	float qy2 = q.y*q.y;
	float qz2 = q.z*q.z;

	float qxqy = q.x*q.y;
	float qxqz = q.x*q.z;
	float qxqw = q.x*q.w;
	float qyqz = q.y*q.z;
	float qyqw = q.y*q.w;
	float qzqw = q.z*q.w;

	return float4x4(
		1-2*(qy2+qz2),  
		2*(qxqy+qzqw),  
		2*(qxqz-qyqw),  
		0            ,  
		2*(qxqy-qzqw),  
		1-2*(qx2+qz2),  
		2*(qyqz+qxqw),  
		0            ,  
		2*(qxqz+qyqw),  
		2*(qyqz-qxqw),  
		1-2*(qx2+qy2),  
		0    , 
		 v.x ,
		 v.y ,
		 v.z ,
		 1.0f );
}



float3 PlaneLineIntersection(const float3 &normal,const float dist, const float3 &p0, const float3 &p1)
{
	// returns the point where the line p0-p1 intersects the plane n&d
	float3 dif;
	dif = p1-p0;
	float dn= dot(normal,dif);
	float t = -(dist+dot(normal,p0) )/dn;
	return p0 + (dif*t);
}

float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a)
{
	// project point a on segment [p0,p1]
	float3 d= p1-p0;
	float t= dot(d,(a-p0)) / dot(d,d);
	return p0+ d*t;
}


float LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a)
{
	// project point a on segment [p0,p1]
	float3 d= p1-p0;
	float t= dot(d,(a-p0)) / dot(d,d);
	return t;
}



float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2)
{
	// return the normal of the triangle
	// inscribed by v0, v1, and v2
	float3 cp=cross(v1-v0,v2-v1);
	float m=magnitude(cp);
	if(m==0) return float3(1,0,0);
	return cp*(1.0f/m);
}



int BoxInside(const float3 &p, const float3 &bmin, const float3 &bmax) 
{
	return (p.x >= bmin.x && p.x <=bmax.x && 
			p.y >= bmin.y && p.y <=bmax.y && 
			p.z >= bmin.z && p.z <=bmax.z );
}


int BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax,float3 *impact)
{
	if(BoxInside(v0,bmin,bmax))
    {
        *impact=v0;
        return 1;
    }
	if(v0.x<=bmin.x && v1.x>=bmin.x) 
    {
		float a = (bmin.x-v0.x)/(v1.x-v0.x);
		//v.x = bmin.x;
		float vy =  (1-a) *v0.y + a*v1.y;
		float vz =  (1-a) *v0.z + a*v1.z;
		if(vy>=bmin.y && vy<=bmax.y && vz>=bmin.z && vz<=bmax.z) 
        {
			impact->x = bmin.x;
			impact->y = vy;
			impact->z = vz;
			return 1;
		}
	}
	else if(v0.x >= bmax.x  &&  v1.x <= bmax.x) 
    {
		float a = (bmax.x-v0.x)/(v1.x-v0.x);
		//v.x = bmax.x;
		float vy =  (1-a) *v0.y + a*v1.y;
		float vz =  (1-a) *v0.z + a*v1.z;
		if(vy>=bmin.y && vy<=bmax.y && vz>=bmin.z && vz<=bmax.z) 
        {
			impact->x = bmax.x;
			impact->y = vy;
			impact->z = vz;
			return 1;
		}
	}
	if(v0.y<=bmin.y && v1.y>=bmin.y) 
    {
		float a = (bmin.y-v0.y)/(v1.y-v0.y);
		float vx =  (1-a) *v0.x + a*v1.x;
		//v.y = bmin.y;
		float vz =  (1-a) *v0.z + a*v1.z;
		if(vx>=bmin.x && vx<=bmax.x && vz>=bmin.z && vz<=bmax.z) 
        {
			impact->x = vx;
			impact->y = bmin.y;
			impact->z = vz;
			return 1;
		}
	}
	else if(v0.y >= bmax.y  &&  v1.y <= bmax.y) 
    {
		float a = (bmax.y-v0.y)/(v1.y-v0.y);
		float vx =  (1-a) *v0.x + a*v1.x;
		// vy = bmax.y;
		float vz =  (1-a) *v0.z + a*v1.z;
		if(vx>=bmin.x && vx<=bmax.x && vz>=bmin.z && vz<=bmax.z) 
        {
			impact->x = vx;
			impact->y = bmax.y;
			impact->z = vz;
			return 1;
		}
	}
	if(v0.z<=bmin.z && v1.z>=bmin.z) 
    {
		float a = (bmin.z-v0.z)/(v1.z-v0.z);
		float vx =  (1-a) *v0.x + a*v1.x;
		float vy =  (1-a) *v0.y + a*v1.y;
		// v.z = bmin.z;
		if(vy>=bmin.y && vy<=bmax.y && vx>=bmin.x && vx<=bmax.x) 
        {
			impact->x = vx;
			impact->y = vy;
			impact->z = bmin.z;
			return 1;
		}
	}
	else if(v0.z >= bmax.z  &&  v1.z <= bmax.z) 
    {
		float a = (bmax.z-v0.z)/(v1.z-v0.z);
		float vx =  (1-a) *v0.x + a*v1.x;
		float vy =  (1-a) *v0.y + a*v1.y;
		// v.z = bmax.z;
		if(vy>=bmin.y && vy<=bmax.y && vx>=bmin.x && vx<=bmax.x) 
        {
			impact->x = vx;
			impact->y = vy;
			impact->z = bmax.z;
			return 1;
		}
	}
	return 0;
}


float DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint, float3 *vpoint)
{
	static float3 cp;
	cp = normalize(cross(udir,vdir));

	float distu = -dot(cp,ustart);
	float distv = -dot(cp,vstart);
	float dist = (float)fabs(distu-distv);
	if(upoint) 
    {
		float3 normal = normalize(cross(vdir,cp));
		*upoint = PlaneLineIntersection(normal,-dot(normal,vstart),ustart,ustart+udir);
	}
	if(vpoint) 
    {
		float3 normal = normalize(cross(udir,cp));
		*vpoint = PlaneLineIntersection(normal,-dot(normal,ustart),vstart,vstart+vdir);
	}
	return dist;
}


Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir1, const float3 &dir2) 
{
	// routine taken from game programming gems.
	// Implement track ball functionality to spin stuf on the screen
	//  cop   center of projection
	//  cor   center of rotation
	//  dir1  old mouse direction 
	//  dir2  new mouse direction
	// pretend there is a sphere around cor.  Then find the points
	// where dir1 and dir2 intersect that sphere.  Find the
	// rotation that takes the first point to the second.
	float m;
	// compute plane 
	float3 nrml = cor - cop;
	float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop
	nrml = normalize(nrml);
	float dist = -dot(nrml,cor);
	float3 u= PlaneLineIntersection(nrml,dist,cop,cop+dir1);
	u=u-cor;
	u=u*fudgefactor;
	m= magnitude(u);
	if(m>1) 
    {
        u/=m;
    }
	else 
    {
		u=u - (nrml * sqrtf(1-m*m));
	}
	float3 v= PlaneLineIntersection(nrml,dist,cop,cop+dir2);
	v=v-cor;
	v=v*fudgefactor;
	m= magnitude(v);
	if(m>1) 
    {
        v/=m;
    }
	else 
    {
		v=v - (nrml * sqrtf(1-m*m));
	}
	return RotationArc(u,v);
}


int countpolyhit=0;
int HitCheckPoly(const float3 *vert, const int n, const float3 &v0, const float3 &v1, float3 *impact, float3 *normal)
{
	countpolyhit++;
	int i;
	float3 nrml(0,0,0);
	for(i=0;i<n;i++) 
    {
		int i1=(i+1)%n;
		int i2=(i+2)%n;
		nrml = nrml + cross(vert[i1]-vert[i],vert[i2]-vert[i1]);
	}

	float m = magnitude(nrml);
	if(m==0.0)
    {
        return 0;
    }
	nrml = nrml * (1.0f/m);
	float dist = -dot(nrml,vert[0]);
	float d0,d1;
	if((d0=dot(v0,nrml)+dist) <0  ||  (d1=dot(v1,nrml)+dist) >0) 
    {        
        return 0;
    }

	static float3 the_point; 
	// By using the cached plane distances d0 and d1
	// we can optimize the following:
	//     the_point = planelineintersection(nrml,dist,v0,v1);
	float a = d0/(d0-d1);
	the_point = v0*(1-a) + v1*a;


	int inside=1;
	for(int j=0;inside && j<n;j++) 
    {
			// let inside = 0 if outside
			float3 pp1,pp2,side;
			pp1 = vert[j] ;
			pp2 = vert[(j+1)%n];
			side = cross((pp2-pp1),(the_point-pp1));
			inside = (dot(nrml,side) >= 0.0);
	}
	if(inside) 
    {
		if(normal){*normal=nrml;}
		if(impact){*impact=the_point;}
	}
	return inside;
}

int SolveQuadratic(float a,float b,float c,float *ta,float *tb)  // if true returns roots ta,tb where ta<=tb
{
	assert(ta);
	assert(tb);
	float d = b*b-4.0f*a*c; // discriminant
	if(d<0.0f) return 0;
	float sqd = sqrtf(d);
	*ta = (-b-sqd) / (2.0f * a);
	*tb = (-b+sqd) / (2.0f * a);
	return 1;
}

int HitCheckRaySphere(const float3& sphereposition,float radius, const float3& _v0, const float3& _v1, float3 *impact,float3 *normal)
{
	assert(impact);
	assert(normal);
	float3 dv = _v1-_v0;
	float3 v0 = _v0 - sphereposition; // solve in coord system of the sphere
	if(radius<=0.0f || _v0==_v1) return 0; // only true if point moves from outside to inside sphere.
	float a = dot(dv,dv);
	float b = 2.0f * dot(dv,v0);
	float c = dot(v0,v0) - radius*radius;
	if(c<0.0f) return 0; // we are already inside the sphere.

	float ta, tb;
	int doesIntersect = SolveQuadratic(a, b, c, &ta, &tb);

	if (!doesIntersect) return 0;

	if (ta >= 0.0f && ta <= 1.0f && (ta <= tb || tb<=0.0f))
	{
		*impact = _v0 + dv * ta;
		*normal = (v0 + dv*ta)/radius;
		return 1;
	}
	if (tb >= 0.0f && tb <= 1.0f)
	{
		assert(tb <= ta || ta <=0.0f);  // tb must be better than ta
		*impact = _v0 + dv * tb;
		*normal = (v0 + dv*tb)/radius;
		return 1;
	}
	return 0;
}

int HitCheckRayCylinder(const float3 &p0,const float3 &p1,float radius,const float3& _v0,const float3& _v1, float3 *impact,float3 *normal)
{
	assert(impact);
	assert(normal);
	// only concerned about hitting the sides, not the caps for now
	float3x3 m=RotationArc(p1-p0,float3(0,0,1.0f)).getmatrix();
	float h = ((p1-p0)*m ).z;  
	float3 v0 = (_v0-p0) *m;
	float3 v1 = (_v1-p0) *m;
	if(v0.z <= 0.0f && v1.z <= 0.0f) return 0;  // entirely below cylinder
	if(v0.z >= h    && v1.z >= h   ) return 0;  // ray is above cylinder
	if(v0.z <0.0f )  v0 = PlaneLineIntersection(float3(0,0,1.0f), 0,v0,v1);  // crop to cylinder range
	if(v1.z <0.0f )  v1 = PlaneLineIntersection(float3(0,0,1.0f), 0,v0,v1);
	if(v0.z > h   )  v0 = PlaneLineIntersection(float3(0,0,1.0f),-h,v0,v1);
	if(v1.z > h   )  v1 = PlaneLineIntersection(float3(0,0,1.0f),-h,v0,v1);
	if(v0.x==v1.x && v0.y==v1.y) return 0;
	float3 dv = v1-v0;
	
	float a = dv.x*dv.x+dv.y*dv.y;
	float b = 2.0f * (dv.x*v0.x+dv.y*v0.y);
	float c = (v0.x*v0.x+v0.y*v0.y) - radius*radius;
	if(c<0.0f) return 0; // we are already inside the cylinder .

	float ta, tb;
	int doesIntersect = SolveQuadratic(a, b, c, &ta, &tb);

	if (!doesIntersect) return 0;

	if (ta >= 0.0f && ta <= 1.0f && (ta <= tb || tb<=0.0f))
	{
		*impact = (v0 + dv * ta)*Transpose(m) + p0;
		*normal = (float3(v0.x,v0.y,0.0f) + float3(dv.x,dv.y,0) * ta) /radius * Transpose(m);
		return 1;
	}
	if (tb >= 0.0f && tb <= 1.0f)
	{
		assert(tb <= ta || ta <=0.0f);  // tb must be better than ta
		*impact = (v0 + dv * tb)*Transpose(m) + p0;  // compute intersection in original space
		*normal = (float3(v0.x,v0.y,0.0f) + float3(dv.x,dv.y,0) * tb) /radius * Transpose(m);
		return 1;
	}
	return 0;
}

int HitCheckSweptSphereTri(const float3 &p0,const float3 &p1,const float3 &p2,float radius, const float3& v0,const float3& _v1, float3 *impact,float3 *normal)
{
	float3 unused;
	if(!normal) normal=&unused;
	float3 v1=_v1;  // so we can update v1 after each sub intersection test if necessary
	int hit=0;
	float3 cp = cross(p1-p0,p2-p0);
	if(dot(cp,v1-v0)>=0.0f) return 0; // coming from behind and/or moving away
	float3 n = normalize(cp);
	float3 tv[3];
	tv[0] = p0 + n*radius;
	tv[1] = p1 + n*radius;
	tv[2] = p2 + n*radius;
	hit += HitCheckPoly(tv,3,v0,v1,&v1,normal);
	hit += HitCheckRayCylinder(p0,p1,radius,v0,v1,&v1,normal);
	hit += HitCheckRayCylinder(p1,p2,radius,v0,v1,&v1,normal);
	hit += HitCheckRayCylinder(p2,p0,radius,v0,v1,&v1,normal);
	hit += HitCheckRaySphere(p0,radius,v0,v1,&v1,normal);
	hit += HitCheckRaySphere(p1,radius,v0,v1,&v1,normal);
	hit += HitCheckRaySphere(p2,radius,v0,v1,&v1,normal);
	if(hit && impact) *impact = v1 + *normal * 0.001f;
	return hit;
}


float3 PlanesIntersection(const Plane &p0,const Plane &p1, const Plane &p2)
{
	float3x3 mp =Transpose(float3x3(p0.normal(),p1.normal(),p2.normal()));
	float3x3 mi = Inverse(mp);
	float3   b(p0.dist(),p1.dist(),p2.dist());
	return   -b * mi;
}


float3 PlanesIntersection(const Plane *planes,int planes_count,const float3 &seed)
{
	int i;
	float3x3 A; // gets initilized to 0 matrix
	float3 b(0,0,0);
	for(i=0;i<planes_count;i++)
	{
		const Plane &p=planes[i];
		A += outerprod(p.normal(),p.normal());
		b += p.normal() * -p.dist();
	}
	float3x3 evecs = Diagonalizer(A).getmatrix();  // eigenvectors
	float3   evals = Diagonal(evecs*A*Transpose(evecs)); // eigenvalues
	for(i=0;i<3;i++)
	{
		if(fabsf(evals[i])<1.0f)  // not sure if they are necessarily positive 
		{
			Plane p;
			p.normal() = evecs[i]* squared(1.0f-evals[i]);
			p.dist() = -dot(seed,p.normal());
			A += outerprod(p.normal(),p.normal());
			b += p.normal() * -p.dist();
		}
	}
	return Inverse(A) * b;
}


Plane Transform(const Plane &p, const float3 &translation, const Quaternion &rotation) 
{
	//   Transforms the plane by the given translation/rotation.
	float3 newnormal = rotate(rotation,p.normal());
	return Plane(newnormal, p.dist() - dot(newnormal,translation));
}


float3 PlaneProject(const Plane &plane, const float3 &point)
{
	return point - plane.normal() * (dot(point,plane.normal())+plane.dist());
}
float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1)
{
	// returns the point where the line p0-p1 intersects the plane n&d
	float3 dif;
	dif = p1-p0;
	float dn= dot(plane.normal(),dif);
	float t = -(plane.dist()+dot(plane.normal(),p0) )/dn;
	return p0 + (dif*t);
}



int Clip(const float3 &plane_normal,float plane_dist,const float3 *verts_in,int count_in,float3* verts_out)
{
	// clips a polygon specified by the non-indexed vertex list verts_in.
	// verts_out must be preallocated with a size >= count+1
	assert(verts_out);
	int n=0;
	int prev_status = (dot(plane_normal,verts_in[count_in-1])+plane_dist > 0) ;  
	for(int i=0;i<count_in;i++)
	{
		int status = (dot(plane_normal,verts_in[i])+plane_dist > 0) ;
		if(status != prev_status)
		{
			verts_out[n++] = PlaneLineIntersection(plane_normal,plane_dist,verts_in[(i==0)?count_in-1:i-1],verts_in[i]);
		}
		if(status==0) // under 
		{
			verts_out[n++] = verts_in[i];
		}
	}
	assert(n<=count_in+1);  // remove if intention to use this routine on convex polygons
	return n;
}

int ClipPolyPoly(const float3 &normal,const float3 *clipper,int clipper_count,const float3 *verts_in, int in_count,float3 *scratch)
{
	// clips polys against each other.
	// requires sufficiently allocated temporary memory in scratch buffer
	// function returns final number of vertices in clipped polygon.
	// Resulting vertices are returned in the scratch buffer.
	// if the arrays are the same &verts_in==&scratch the routine should still work anyways.
	// the first argument (normal) is the normal of polygon clipper.
	// its generally assumed both are convex polygons.
	assert(scratch);  // size should be >= 2*(clipper_count+in_count)
	int i;
	int bsize = clipper_count+in_count;
	int count = in_count;
	for(i=0;i<clipper_count;i++)
	{
		int i1 = (i+1)%clipper_count;
		float3 n = cross(clipper[i1]-clipper[i],normal);
		if(n==float3(0,0,0)) continue;
		n=normalize(n);
		count = Clip(n,-dot(clipper[i],n),(i==0)?verts_in:(i%2)?scratch:scratch+bsize,count,(i%2)?scratch+bsize:scratch);
		assert(count<bsize);
	}
	if(clipper_count%2) memcpy(scratch,scratch+bsize,count*sizeof(float3));
	return count;
}

float Volume(const float3 *vertices, const int3 *tris, const int count) 
{
    // count is the number of triangles (tris) 
    float  volume=0;
    for(int i=0; i<count; i++)  // for each triangle
    {
        volume += Determinant(float3x3(vertices[tris[i][0]],vertices[tris[i][1]],vertices[tris[i][2]])); //divide by 6 later for efficiency
    }
    return volume/6.0f;  // since the determinant give 6 times tetra volume
}
 
float3 CenterOfMass(const float3 *vertices, const int3 *tris, const int count) 
{
	// count is the number of triangles (tris) 
	float3 com(0,0,0);
	float  volume=0; // actually accumulates the volume*6
	for(int i=0; i<count; i++)  // for each triangle
	{
		float3x3 A(vertices[tris[i][0]],vertices[tris[i][1]],vertices[tris[i][2]]);  
		float vol=Determinant(A);  // dont bother to divide by 6 
		com += vol * (A.x+A.y+A.z);  // divide by 4 at end
		volume+=vol;
	}
	com /= volume*4.0f; 
	return com;
}
float3x3 Inertia(const float3 *vertices, const int3 *tris, const int count, const float3& com /* =float3(0,0,0) */ ) 
{
	// count is the number of triangles (tris) 
	// The moments are calculated based on the center of rotation (com) which defaults to [0,0,0] if unsupplied
	// assume mass==1.0  you can multiply by mass later.
	// for improved accuracy the next 3 variables, the determinant d, and its calculation should be changed to double
	float  volume=0;                          // technically this variable accumulates the volume times 6
	float3 diag(0,0,0);                       // accumulate matrix main diagonal integrals [x*x, y*y, z*z]
	float3 offd(0,0,0);                       // accumulate matrix off-diagonal  integrals [y*z, x*z, x*y]
	for(int i=0; i<count; i++)  // for each triangle
	{
		float3x3 A(vertices[tris[i][0]]-com,vertices[tris[i][1]]-com,vertices[tris[i][2]]-com);  // matrix trick for volume calc by taking determinant
		float    d = Determinant(A);  // vol of tiny parallelapiped= d * dr * ds * dt (the 3 partials of my tetral triple integral equasion)
		volume +=d;                   // add vol of current tetra (note it could be negative - that's ok we need that sometimes)
		for(int j=0;j<3;j++)
		{
			int j1=(j+1)%3;   
			int j2=(j+2)%3;   
			diag[j] += (A[0][j]*A[1][j] + A[1][j]*A[2][j] + A[2][j]*A[0][j] + 
						A[0][j]*A[0][j] + A[1][j]*A[1][j] + A[2][j]*A[2][j]  ) *d; // divide by 60.0f later;
			offd[j] += (A[0][j1]*A[1][j2]  + A[1][j1]*A[2][j2]  + A[2][j1]*A[0][j2]  +
						A[0][j1]*A[2][j2]  + A[1][j1]*A[0][j2]  + A[2][j1]*A[1][j2]  +
						A[0][j1]*A[0][j2]*2+ A[1][j1]*A[1][j2]*2+ A[2][j1]*A[2][j2]*2 ) *d; // divide by 120.0f later
		}
	}
	diag /= volume*(60.0f /6.0f);  // divide by total volume (vol/6) since density=1/volume
	offd /= volume*(120.0f/6.0f);
	return float3x3(diag.y+diag.z  , -offd.z      , -offd.y,
				   -offd.z        , diag.x+diag.z, -offd.x,
				   -offd.y        , -offd.x      , diag.x+diag.y );
}


float3x3 ShapeInertiaContrib(const float3& cor, const float3& position, const Quaternion &orientation,
							 const float3& shape_com, const float3x3& shape_inertia, float shape_mass)
{
	// transforms 3x3 inertia tensor from local reference frame to a more global one.
	// essentially returns the contribution of a subshape to the inertia of a larger rigid body
	// typical usage:  
	//         foreach shape s { totalinertia += InertiaContribution(...); }
	// cor - new center of rotation that we are translating to.
	// This could be the center of mass of the compound object.
	// Another application is when an object is attached to something (nail-joint) that is static, in which
	// one easy way to implement this is to lock the center of rotation and adjust the inertia accordingly.
	// position & orientation - is the current pose or transform of the shape.
	// Obviously position, orientation and cor are all described wrt the same reference frame.
	// shape_com and shape_inertia are the center of mass and the inertia of the shape in the local coordinate system of that shape.
	// To clarify, if a shape happened to be located somewhere else then position or orientation would be different, but
	// com and inertia would be the same.
	float3x3 Identity(1.0f,0,0,0,1.0f,0,0,0,1.0f);
	float3x3 R = orientation.getmatrix();
	float3 r = (shape_com*R + position) - cor;
	return Transpose(R)*shape_inertia*R + (Identity*dot(r,r)-outerprod(r,r))*shape_mass; 
}



Quaternion Diagonalizer(const float3x3 &A)
{
	// A must be a symmetric matrix.
	// returns quaternion q such that its corresponding matrix Q 
	// can be used to Diagonalize A
	// Diagonal matrix D = Q * A * Transpose(Q);  and  A = QT*D*Q
	// The rows of q are the eigenvectors D's diagonal is the eigenvalues
	// As per 'row' convention if float3x3 Q = q.getmatrix(); then v*Q = q*v*conj(q)
	int maxsteps=24;  // certainly wont need that many.
	int i;
	Quaternion q(0,0,0,1);
	for(i=0;i<maxsteps;i++)
	{
		float3x3 Q  = q.getmatrix(); // v*Q == q*v*conj(q)
		float3x3 D  = Q * A * Transpose(Q);  // A = Q^T*D*Q
		float3 offdiag(D[1][2],D[0][2],D[0][1]); // elements not on the diagonal
		float3 om(fabsf(offdiag.x),fabsf(offdiag.y),fabsf(offdiag.z)); // mag of each offdiag elem
		int k = (om.x>om.y&&om.x>om.z)?0: (om.y>om.z)? 1 : 2; // index of largest element of offdiag
		int k1 = (k+1)%3;
		int k2 = (k+2)%3;
		if(offdiag[k]==0.0f) break;  // diagonal already
		float thet = (D[k2][k2]-D[k1][k1])/(2.0f*offdiag[k]);
		float sgn = (thet>0.0f)?1.0f:-1.0f;
		thet    *= sgn; // make it positive
		float t = sgn /(thet +((thet<1.E6f)?sqrtf(squared(thet)+1.0f):thet)) ; // sign(T)/(|T|+sqrt(T^2+1))
		float c = 1.0f/sqrtf(squared(t)+1.0f); //  c= 1/(t^2+1) , t=s/c 
		if(c==1.0f) break;  // no room for improvement - reached machine precision.
		Quaternion jr(0,0,0,0); // jacobi rotation for this iteration.
		jr[k] = sgn*sqrtf((1.0f-c)/2.0f);  // using 1/2 angle identity sin(a/2) = sqrt((1-cos(a))/2)  
		jr[k] *= -1.0f; // since our quat-to-matrix convention was for v*M instead of M*v
		jr.w  = sqrtf(1.0f - squared(jr[k]));
		if(jr.w==1.0f) break; // reached limits of floating point precision
		q =  q*jr;  
		q.Normalize();
	} 
	return q;
}

float3 Diagonal(const float3x3 &M)
{
	return float3(M[0][0],M[1][1],M[2][2]);
}
