'Const Pi:Float=3.14159265359f;	'180 degrees
Const TWOPI:Float=Pi*2.0		'360 degrees
Const HALFPI:Float=Pi*.5		'90  degrees
Const QUARTERPI:Float=Pi*.25	'45  degrees
Const EPSILON:Float=.000001		'small value
Const INFINITY:Float=10000000.0	'big value

Type TVec

	Field x:Float,y:Float,z:Float

	Method Copy:TVec()
		Local q:TVec=New TVec
		q.x=x; q.y=y; q.z=z
		Return q
	End Method

	Function Create0:TVec()
		Local q:TVec=New TVec
		q.x=0.0; q.y=0.0; q.z=0.0
		Return q
	End Function
	
	Function Create:TVec(x#,y#,z#)
		Local q:TVec=New TVec
		q.x=x#; q.y=y#; q.z=z#
		Return q
	End Function
	
	Rem
	operator Float*() ' ? operator overload
		Return &x;
	}
	
	operator Const Float *() ' ? operator overload
		Return &x;
	}
	
	Float &operator[]( Int n ) ' ? operator overload
		Return (&x)[n]; 
	}
	
	Float operator[]( Int n ) ' ? operator overload
		Return (&x)[n]; 
	}
	End Rem
	
	Method Negate:TVec() ' - operator overload
		Return TVec.Create( -x,-y,-z )
	End Method
	
	Method Multiply:TVec( scale:Float ) ' * operator overload
		Return TVec.Create( x*scale,y*scale,z*scale )
	End Method
	
	Method MultiplyVector:TVec( q:TVec ) ' * operator overload
		Return TVec.Create( x*q.x,y*q.y,z*q.z )
	End Method
	
	Method Divide:TVec( scale:Float ) ' / operator overload
		Return TVec.Create( x/scale,y/scale,z/scale )
	End Method
	
	Method DivideVector:TVec( q:TVec ) ' / operator overload
		Return TVec.Create( x/q.x,y/q.y,z/q.z )
	End Method
	
	Method Add:TVec( q:TVec ) ' + operator overload
		Return TVec.Create( x+q.x,y+q.y,z+q.z )
	End Method
	
	Method Subtract:TVec( q:TVec ) ' - operator overload
		Return TVec.Create( x-q.x,y-q.y,z-q.z )
	End Method
	
	Rem
	Vector &operator*=( Float scale ) ' *= operator overload
		x*=scale;y*=scale;z*=scale;Return *this;
	}
	Vector &operator*=( Const Vector &q ) ' *= operator overload
		x*=q.x;y*=q.y;z*=q.z;Return *this;
	}
	Vector &operator/=( Float scale ) ' /= operator overload
		x/=scale;y/=scale;z/=scale;Return *this;
	}
	Vector &operator/=( Const Vector &q ) ' /= operator overload
		x/=q.x;y/=q.y;z/=q.z;Return *this;
	}
	End Rem
	
	Method Inc( q:TVec ) ' += operator overload
		x:+q.x;y:+q.y;z:+q.z
	End Method
	
	Method Dec( q:TVec ) ' -= operator overload
		x:-q.x;y:-q.y;z:-q.z
	End Method
	
	Method LessThan:Int( q:TVec ) ' < operator overload
		If( Abs(x-q.x)>EPSILON )
			If x<q.x Then Return True Else Return False
		EndIf
		If( Abs(y-q.y)>EPSILON )
			If y<q.y Then Return True Else Return False
		EndIf
		Return Abs(z-q.z)>EPSILON And z<q.z
	End Method
	
	Method Equals:Int( q:TVec ) ' = operator overload
		Return Abs(x-q.x)<=EPSILON And Abs(y-q.y)<=EPSILON And Abs(z-q.z)<=EPSILON
	End Method
	
	Method Inequality:Int( q:TVec ) ' != operator overload
		Return Abs(x-q.x)>EPSILON Or Abs(y-q.y)>EPSILON Or Abs(z-q.z)>EPSILON
	End Method
	
	Method Dot:Float( q:TVec )
		Return x*q.x+y*q.y+z*q.z
	End Method
	
	Method Cross:TVec( q:TVec )
		Return TVec.Create( y*q.z-z*q.y,z*q.x-x*q.z,x*q.y-y*q.x )
	End Method
	
	Method Length:Float()
		Return Sqr(x*x+y*y+z*z)
	End Method
	
	Method Distance:Float( q:TVec )
		Local dx:Float=x-q.x; Local dy:Float=y-q.y; Local dz:Float=z-q.z; Return Sqr(dx*dx+dy*dy+dz*dz)
	End Method
	
	Method Normalized:TVec()
		Local l:Float=Length(); Return TVec.Create( x/l,y/l,z/l )
	End Method
	
	Method Normalize()
		Local l:Float=Length(); x:/l; y:/l; z:/l
	End Method
	
	Method Yaw:Float()
		Return -ATan2( x,z )
	End Method
	
	Method Pitch:Float()
		Return -ATan2( y,Sqr( x*x+z*z ) )
	End Method
	
	Method Clear()
		x=0;y=0;z=0
	End Method
	
End Type

Type TLine

	Field o:TVec,d:TVec
	
	Function Create0:TLine()
		Local line:TLine=New Tline
		line.o=TVec.Create(0.0,0.0,0.0)
		line.d=TVec.Create(0.0,0.0,0.0)
		Return line
	End Function

	Function Create:TLine(o:TVec,d:TVec)
		Local line:TLine=New Tline
		line.o=TVec.Create(o.x,o.y,o.z)
		line.d=TVec.Create(d.x,d.y,d.z)
		Return line
	End Function
	
	Method Add:TLine( q:TVec ) ' + operator overload
		Return Create( o.Add(q),d );
	End Method
	
	Method Subtract:TLine( q:TVec ) ' - operator overload
		Return Create( o.Subtract(q),d );
	End Method
	
	Method Multiply:TVec( q:Float ) ' * operator overload
		Return o.Add(d.Multiply(q))
	End Method
	
	Method Nearest:TVec( q:TVec )
		Return o.Add( d.Multiply( ( d.Dot(q.Subtract(o)) / d.Dot(d) ) ) )
	End Method
	
End Type

Type T_Plane

	Field n:TVec
	Field d:Float
	
	Method Copy:T_Plane()
		Local plane:T_Plane=New T_Plane
		plane.n=TVec.Create(n.x,n.y,n.z)
		plane.d=d
		Return plane
	End Method

	Function Create0:T_Plane()
		Local plane:T_Plane=New T_Plane
		plane.n=TVec.Create(0.0,0.0,0.0)
		plane.d=0.0
		Return plane
	End Function

	' normal/offset form
	Function Create:T_Plane(n:TVec,d:Float)
		Local plane:T_Plane=New T_Plane
		plane.n=TVec.Create(n.x,n.y,n.z)
		plane.d=d
		Return plane
	End Function

	' point/normal form
	Function Create1:T_Plane(p:TVec,n:TVec)
		Local plane:T_Plane=New T_Plane
		plane.n=TVec.Create(n.x,n.y,n.z)
		plane.d=n.Negate().Dot(p)
		Return plane
	End Function

	' create plane from tri
	Function CreateFromTri:T_Plane(v0:TVec,v1:TVec,v2:TVec)
		Local plane:T_Plane=New T_Plane
		plane.n=(v1.Subtract(v0)).Cross(v2.Subtract(v0)).normalized()
		plane.d=plane.n.Negate().Dot(v0)
		Return plane
	End Function

	Method Negate:T_Plane() ' - operator overload
		Return T_Plane.Create( n.Negate(),-d )
	End Method
	
	Method t_intersect:Float( q:TLine )
		Return -Distance(q.o)/n.Dot(q.d)
	End Method
	
	Method IntersectLine:TVec( q:TLine )
		Return q.Multiply(t_intersect(q))
	End Method
	
	Method IntersecT_Plane:TLine( q:T_Plane )
		Local lv:TVec=n.Cross( q.n ).Normalized()
		Return TLine.Create( q.IntersectLine( TLine.Create( Nearest( n.Multiply(-d) ),n.Cross(lv) ) ),lv )
	End Method
	
	Method Nearest:TVec( q:TVec )
		Return q.Subtract(n.Multiply(Distance(q)))
	End Method
	
	Method Negate2()
		n=n.Negate();d=-d
	End Method
	
	Method Distance:Float(q:TVec)
		Return n.Dot(q)+d
	End Method

End Type

Type TQuat

	Field w:Float
	Field v:TVec
	
	Function Create0:TQuat()
		Local q:TQuat=New TQuat
		q.w=1.0
		Return q
	End Function
	
	Function Create:TQuat( w:Float,v:TVec )
		Local q:TQuat=New TQuat
		q.w=1.0
		q.v.x=v.x
		q.v.y=v.y
		q.v.z=v.z
		Return q
	End Function
	
	Method Negate:TQuat() ' - operator overload
		Return TQuat.Create( w,v.Negate() )
	End Method
	
	Method Add:TQuat( q:TQuat ) ' + operator overload
		Return TQuat.Create( w+q.w,v.Add(q.v) )
	End Method
	
	Method Subtract:TQuat( q:TQuat ) ' - operator overload
		Return TQuat.Create( w-q.w,v.Subtract(q.v) )
	End Method
	
	Method Multiply:TQuat( q:TQuat ) ' * operator overload
		Return TQuat.Create( w*q.w-v.dot(q.v),(q.v.cross(v)).Add(q.v.Multiply(w)).Add(v.Multiply(q.w)) )
	End Method
	
	Method MultiplyVector:TVec( q:TVec ) ' * operator overload
		Return ( Self.Multiply(TQuat.Create(0,q)).Multiply(Self.Negate()) ).v
	End Method
	
	Method MultiplyFloat:TQuat( q:Float ) ' * operator overload
		Return TQuat.Create( w*q,v.Multiply(q) )
	End Method
	
	Method Divide:TQuat( q:Float ) ' / operator overload
		Return TQuat.Create( w/q,v.Divide(q) )
	End Method
	
	Method Dot:Float( q:TQuat )
		Return v.x*q.v.x+v.y*q.v.y+v.z*q.v.z+w*q.w
	End Method
	
	Method Length:Float()
		Return Sqr( w*w+v.x*v.x+v.y*v.y+v.z*v.z )
	End Method
	
	Method Normalize()
		w=w/Length()
		v.x=v.x/Length()
		v.y=v.y/Length()
		v.z=v.z/Length()
	End Method
	
	Method Normalized:TQuat()
		Local q:TQuat=New TQuat
		q.w=q.w/Length()
		q.v.x=q.v.x/Length()
		q.v.y=q.v.y/Length()
		q.v.z=q.v.z/Length()
		Return q
	End Method
	
	Method SlerpTo:TQuat( q:TQuat,a:Float )
		Local t:TQuat=q
		Local d:Float=dot(q),b:Float=1-a
		If( d<0 ) t.w=-t.w; t.v=t.v.Negate(); d=-d
		If( d<1-EPSILON )
			Local om:Float=ACos( d )
			Local si:Float=Sin( om )
			a=Sin( a*om )/si
			b=Sin( b*om )/si
		EndIf
		Return (Self.MultiplyFloat(b)).Add(t.MultiplyFloat(a))
	End Method
	
	Method i:TVec()
		Local xz:Float=v.x*v.z,wy:Float=w*v.y
		Local xy:Float=v.x*v.y,wz:Float=w*v.z
		Local yy:Float=v.y*v.y,zz:Float=v.z*v.z
		Return TVec.Create( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) )
	End Method
	
	Method j:TVec()
		Local yz:Float=v.y*v.z,wx:Float=w*v.x
		Local xy:Float=v.x*v.y,wz:Float=w*v.z
		Local xx:Float=v.x*v.x,zz:Float=v.z*v.z
		Return TVec.Create( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) )
	End Method
	
	Method k:TVec()
		Local xz:Float=v.x*v.z,wy:Float=w*v.y
		Local yz:Float=v.y*v.z,wx:Float=w*v.x
		Local xx:Float=v.x*v.x,yy:Float=v.y*v.y
		Return TVec.Create( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) )
	End Method
	
End Type

Type TMat

	Field i:TVec,j:TVec,k:TVec
	
	Method Copy:TMat()
		Local m:TMat=New TMat	
		m.i=TVec.Create(i.x,i.y,i.z)
		m.j=TVec.Create(j.x,j.y,j.z)
		m.k=TVec.Create(k.x,k.y,k.z)
		Return m
	End Method

	Function Create0:TMat()
		Local m:TMat=New TMat
		m.i=TVec.Create(1,0,0); m.j=TVec.Create(0,1,0); m.k=TVec.Create(0,0,1)
		Return m
	End Function
	
	Function Create:TMat( i:TVec,j:TVec,k:TVec )
		Local m:TMat=New TMat
		m.i=i; m.j=j; m.k=k
		Return m
	End Function
	
	Function CreateFromQuat:TMat( q:TQuat )
		Local m:TMat=New TMat
		Local xx:Float=q.v.x*q.v.x,yy:Float=q.v.y*q.v.y,zz:Float=q.v.z*q.v.z
		Local xy:Float=q.v.x*q.v.y,xz:Float=q.v.x*q.v.z,yz:Float=q.v.y*q.v.z
		Local wx:Float=q.w*q.v.x,wy:Float=q.w*q.v.y,wz:Float=q.w*q.v.z
		m.i=TVec.Create( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) )
		m.j=TVec.Create( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) )
		m.k=TVec.Create( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) )
		Return m
	End Function
	
	Function CreateFromAngle:TMat( angle:Float,axis:TVec )
		Local m:TMat=New TMat
		Local u:TVec=axis
		Local c:Float=Cos(angle),s:Float=Sin(angle)
		Local x2:Float=axis.x*axis.x,y2:Float=axis.y*axis.y,z2:Float=axis.z*axis.z
		m.i=TVec.Create( x2+c*(1-x2),u.x*u.y*(1-c)-u.z*s,u.z*u.x*(1-c)+u.y*s )
		m.j=TVec.Create( u.x*u.y*(1-c)+u.z*s,y2+c*(1-y2),u.y*u.z*(1-c)-u.x*s )
		m.k=TVec.Create( u.z*u.x*(1-c)-u.y*s,u.y*u.z*(1-c)+u.x*s,z2+c*(1-z2) )
		Return m
	End Function
	
	Rem
	Vector &operator[]( Int n ){
		Return (&i)[n]; 
	}
	Const Vector &operator[]( Int n )Const{
		Return (&i)[n];
	}
	End Rem
	
	Method Inverse:TMat() ' ~ operator overload - inverse?
		Local m:TMat=TMat.Create0()
		m.i.x=i.x;m.i.y=j.x;m.i.z=k.x
		m.j.x=i.y;m.j.y=j.y;m.j.z=k.y
		m.k.x=i.z;m.k.y=j.z;m.k.z=k.z
		Return m
	End Method
	
	Method Determinant:Float()
		Return i.x*(j.y*k.z-j.z*k.y )-i.y*(j.x*k.z-j.z*k.x )+i.z*(j.x*k.y-j.y*k.x )
	End Method
	
	Method Negate:TMat() ' - operator overload
		Local m:TMat=TMat.Create0()
		Local t:Float=1.0/Determinant()
		m.i.x= t*(j.y*k.z-j.z*k.y);m.i.y=-t*(i.y*k.z-i.z*k.y);m.i.z= t*(i.y*j.z-i.z*j.y)
		m.j.x=-t*(j.x*k.z-j.z*k.x);m.j.y= t*(i.x*k.z-i.z*k.x);m.j.z=-t*(i.x*j.z-i.z*j.x)
		m.k.x= t*(j.x*k.y-j.y*k.x);m.k.y=-t*(i.x*k.y-i.y*k.x);m.k.z= t*(i.x*j.y-i.y*j.x)
		Return m
	End Method

	Method Cofactor:TMat()
		Local m:TMat=TMat.Create0()
		m.i.x= (j.y*k.z-j.z*k.y);m.i.y=-(j.x*k.z-j.z*k.x);m.i.z= (j.x*k.y-j.y*k.x)
		m.j.x=-(i.y*k.z-i.z*k.y);m.j.y= (i.x*k.z-i.z*k.x);m.j.z=-(i.x*k.y-i.y*k.x)
		m.k.x= (i.y*j.z-i.z*j.y);m.k.y=-(i.x*j.z-i.z*j.x);m.k.z= (i.x*j.y-i.y*j.x)
		Return m
	End Method	
	
	Method Equals:Int( q:TMat ) ' == operator overload
		Return i=q.i And j=q.j And k=q.k
	End Method
	
	Method Inequality:Int( q:TMat  ) ' != operator overload
		Return i<>q.i Or j<>q.j Or k<>q.k
	End Method
	
	Method MultiplyVector:TVec( q:TVec ) ' * operator overload
		Return TVec.Create( i.x*q.x+j.x*q.y+k.x*q.z,i.y*q.x+j.y*q.y+k.y*q.z,i.z*q.x+j.z*q.y+k.z*q.z )
	End Method
	
	Method Multiply:TMat( q:TMat ) ' * operator overload
		Local m:TMat=TMat.Create0()
		m.i.x=i.x*q.i.x+j.x*q.i.y+k.x*q.i.z;m.i.y=i.y*q.i.x+j.y*q.i.y+k.y*q.i.z;m.i.z=i.z*q.i.x+j.z*q.i.y+k.z*q.i.z
		m.j.x=i.x*q.j.x+j.x*q.j.y+k.x*q.j.z;m.j.y=i.y*q.j.x+j.y*q.j.y+k.y*q.j.z;m.j.z=i.z*q.j.x+j.z*q.j.y+k.z*q.j.z
		m.k.x=i.x*q.k.x+j.x*q.k.y+k.x*q.k.z;m.k.y=i.y*q.k.x+j.y*q.k.y+k.y*q.k.z;m.k.z=i.z*q.k.x+j.z*q.k.y+k.z*q.k.z
		Return m
	End Method
	
	Method Orthogonalize()
		k.Normalize()
		i=j.Cross( k ).Normalized()
		j=k.Cross( i )
	End Method
	
	Method Orthogonalized:TMat()
		Local m:TMat=TMat.Create0()
		m.Orthogonalize()
		Return m
	End Method
	
End Type

Type TBox

	Field a:TVec,b:TVec
	
	Function Create0:TBox()
		Local box:TBox=New TBox
		box.a=TVec.Create(INFINITY,INFINITY,INFINITY)
		box.b=TVec.Create(-INFINITY,-INFINITY,-INFINITY)
		Return box
	End Function
	
	Function CreateFromPoint:TBox( q:TVec )
		Local box:TBox=New TBox
		box.a=TVec.Create(q.x,q.y,q.z)
		box.b=TVec.Create(q.x,q.y,q.z)
		Return box
	End Function
	
	Function Create:TBox( a:TVec,b:TVec )
		Local box:TBox=New TBox
		box.a=TVec.Create(a.x,a.y,a.z)
		box.b=TVec.Create(b.x,b.y,b.z)
		Return box
	End Function
	
	Function CreateFromLine:TBox( l:TLine )
		Local box:TBox=New TBox
		box.a=TVec.Create(l.o.x,l.o.y,l.o.z)
		box.b=TVec.Create(l.o.x,l.o.y,l.o.z)
		box.UpdateFromVector( l.o.Add(l.d) )
		Return box
	End Function
	
	Method Clear()
		a.x=INFINITY;a.y=INFINITY;a.z=INFINITY
		b.x=-INFINITY;b.y=-INFINITY;b.z=-INFINITY
	End Method
	
	Method Empty:Int()
		Return b.x<a.x Or b.y<a.y Or b.z<a.z
	End Method
	
	Method Centre:TVec()
		Return TVec.Create( (a.x+b.x)*.5,(a.y+b.y)*.5,(a.z+b.z)*.5 )
	End Method
	
	Method Corner:TVec( n:Int )
		Local x#=n&1;If x Then x=b.x Else x=a.x
		Local y#=n&2;If y Then y=b.y Else y=a.y
		Local z#=n&4;If z Then z=b.z Else z=a.z
		Return TVec.Create( x,y,z )
	End Method
	
	Method UpdateFromVector( q:TVec )
		If q.x<a.x Then a.x=q.x
		If q.y<a.y Then a.y=q.y
		If q.z<a.z Then a.z=q.z
		If q.x>b.x Then b.x=q.x
		If q.y>b.y Then b.y=q.y
		If q.z>b.z Then b.z=q.z
	End Method
	
	Method UpdateFromBox( q:TBox )
		If q.a.x<a.x Then a.x=q.a.x
		If q.a.y<a.y Then a.y=q.a.y
		If q.a.z<a.z Then a.z=q.a.z
		If q.b.x>b.x Then b.x=q.b.x
		If q.b.y>b.y Then b.y=q.b.y
		If q.b.z>b.z Then b.z=q.b.z
	End Method
	
	Method Overlaps:Int( q:TBox )
		Local x#=b.x<q.b.x;If x Then x=b.x Else x=q.b.x
		Local y#=b.y<q.b.y;If y Then y=b.y Else y=q.b.y
		Local z#=b.z<q.b.z;If z Then z=b.z Else z=q.b.z
		Return x And y And z
	End Method
	
	Method Expand( n:Float )
		a.x:-n;a.y:-n;a.z:-n;b.x:+n;b.y:+n;b.z:+n
	End Method
	
	Method Width:Int()
		Return b.x-a.x
	End Method
	
	Method Height:Int()
		Return b.y-a.y
	End Method
	
	Method Depth:Int()
		Return b.z-a.z
	End Method
	
	Method Contains:Int( q:TVec )
		Return q.x>=a.x And q.x<=b.x And q.y>=a.y And q.y<=b.y And q.z>=a.z And q.z<=b.z
	End Method
	
End Type

Type TTransform

	Field m:TMat
	Field v:TVec

	Function Create0:TTransform()
		Local tform:TTransform=New TTransform
		tform.m:TMat=TMat.Create0()
		tform.v:TVec=TVec.Create0()
		Return tform
	End Function

	Function CreateFromMatrix:TTransform(m:TMat)
		Local tform:TTransform=New TTransform
		tform.m=m.Copy()
		Return tform
	End Function
	
	Function CreateFromVector:TTransform(v:TVec)
		Local tform:TTransform=New TTransform
		tform.v=TVec.Create(v.x,v.y,v.z)
		Return tform
	End Function
	
	Function Create:TTransform(m:TMat,v:TVec)
		Local tform:TTransform=New TTransform
		tform.m=m.Copy()
		tform.v=TVec.Create(v.x,v.y,v.z)
		Return tform
	End Function
	
	Method Negate:TTransform() ' - operator overload
		Local t:TTransform=New TTransform
		t.m=m.Negate();t.v=t.m.MultiplyVector(v.Negate())
		Return t
	End Method
	
	Method Inverse:TTransform() ' ~ operator overload
		Local t:TTransform=New TTransform
		t.m=m.Inverse();t.v=t.m.MultiplyVector(v.Negate())
		Return t
	End Method
	
	Method MultiplyVector:TVec( q:TVec ) ' * operator overload
		Return m.MultiplyVector(q).Add(v)
	End Method
	
	Method MultiplyLine:TLine( q:TLine ) ' * operator overload
		Local t:TVec=Self.MultiplyVector(q.o)
		Return TLine.Create( t,Self.MultiplyVector(q.o.Add(q.d)).Subtract(t) )
	End Method
	
	Method MultiplyBox:TBox( q:TBox ) ' * operator overload
		Local t:TBox=TBox.CreateFromPoint(Self.MultiplyVector(q.corner(0)))
		For Local k:Int=1 To 8
			t.UpdateFromVector( Self.MultiplyVector(q.corner(k)) )
		Next
		Return t
	End Method
	
	Method MultiplyTransform:TTransform( q:TTransform ) ' operator overload
		Local t:TTransform=New TTransform
		t.m=m.Multiply(q.m);t.v=m.MultiplyVector(q.v.Add(v))
		Return t
	End Method
	
	Method Equals:Int( q:TTransform ) ' == operator overload
		Return m.Equals(q.m) And v.Equals(q.v)
	End Method
	
	Method Inequality:Int( q:TTransform ) ' != operator overload
		Return Not Equals( q )
	End Method
	
End Type

Function TransformRadius:Float( r:Float,t:TMat )
	Local sq_3:Float=Sqr(1.0/3.0)
	Return t.MultiplyVector( TVec.Create(sq_3,sq_3,sq_3) ).length()*r
End Function

Function PitchMatrix:TMat( q:Float )
	Return TMat.Create( TVec.Create(1,0,0),TVec.Create(0,Cos(q),Sin(q)),TVec.Create(0,-Sin(q),Cos(q)) )
End Function

Function YawMatrix:TMat( q:Float )
	Return TMat.Create( TVec.Create(Cos(q),0,Sin(q)),TVec.Create(0,1,0),TVec.Create(-Sin(q),0,Cos(q)) )
End Function

Function RollMatrix:TMat( q:Float )
	Return TMat.Create( TVec.Create(Cos(q),Sin(q),0),TVec.Create(-Sin(q),Cos(q),0),TVec.Create(0,0,1) )
End Function

Function MatrixPitch:Float( m:TMat )
	Return m.k.pitch()
End Function

Function MatrixYaw:Float( m:TMat )
	Return m.k.yaw()
End Function

Function MatrixRoll:Float( m:TMat )
	Return ATan2( m.i.y,m.j.y )
End Function

Function ScaleMatrix:TMat( x:Float,y:Float,z:Float )
	Return TMat.Create( TVec.Create( x,0,0 ),TVec.Create( 0,y,0 ),TVec.Create( 0,0,z ) )
End Function

Function ScaleMatrix1:TMat( scale:TVec )
	Return TMat.Create( TVec.Create( scale.x,0,0 ),TVec.Create( 0,scale.y,0 ),TVec.Create( 0,0,scale.z ) )
End Function

Function PitchQuat:TQuat( p:Float )
	Return TQuat.Create( Cos(p/-2),TVec.Create( Sin(p/-2),0,0 ) )
End Function

Function YawQuat:TQuat( y:Float )
	Return TQuat.Create( Cos(y/2),TVec.Create( 0,Sin(y/2),0 ) )
End Function

Function RollQuat:TQuat( r:Float )
	Return TQuat.Create( Cos(r/-2),TVec.Create( 0,0,Sin(r/-2) ) )
End Function

Function RotationMatrix:TMat( p:Float,y:Float,r:Float )
	Return YawMatrix(y).Multiply(PitchMatrix(p)).Multiply(RollMatrix(r))
End Function

Function RotationMatrix1:TMat( rot:TVec )
	Return YawMatrix(rot.y).Multiply(PitchMatrix(rot.x)).Multiply(RollMatrix(rot.z))
EndFunction

Function QuatPitch:Float( q:TQuat )
	Return q.k().Pitch()
End Function

Function QuatYaw:Float( q:TQuat )
	Return q.k().Yaw()
End Function

Function QuatRoll:Float( q:TQuat )
	Return MatrixRoll( TMat.CreateFromQuat(q) )
End Function

Function MatrixQuat:TQuat( p:TMat )
	Local m:TMat m=p
	m.Orthogonalize()
	Local t:Float=m.i.x+m.j.y+m.k.z,w:Float,x:Float,y:Float,z:Float
	If( t>EPSILON )
		t=Sqr( t+1 )*2
		x=(m.k.y-m.j.z)/t
		y=(m.i.z-m.k.x)/t
		z=(m.j.x-m.i.y)/t
		w=t/4
	Else If( m.i.x>m.j.y And m.i.x>m.k.z )
		t=Sqr( m.i.x-m.j.y-m.k.z+1 )*2
		x=t/4
		y=(m.j.x+m.i.y)/t
		z=(m.i.z+m.k.x)/t
		w=(m.k.y-m.j.z)/t
	Else If( m.j.y>m.k.z )
		t=Sqr( m.j.y-m.k.z-m.i.x+1 )*2
		x=(m.j.x+m.i.y)/t
		y=t/4
		z=(m.k.y+m.j.z)/t
		w=(m.i.z-m.k.x)/t
	Else
		t=Sqr( m.k.z-m.j.y-m.i.x+1 )*2
		x=(m.i.z+m.k.x)/t
		y=(m.k.y+m.j.z)/t
		z=t/4
		w=(m.j.x-m.i.y)/t
	EndIf
	Return TQuat.Create( w,TVec.Create( x,y,z ) )
End Function

Type AABB

	Field mini#[3]
	Field maxi#[3]
	
	Function CreateFromTri:AABB(v0:TVector,v1:TVector,v2:TVector)
	
		Local box:AABB=New AABB

		box.mini[0]=1000000;box.mini[1]=1000000;box.mini[2]=1000000
		box.maxi[0]=-1000000;box.maxi[1]=-1000000;box.maxi[2]=-1000000

		If v0.x<box.mini[0] Then box.mini[0]=v0.x
		If v0.y<box.mini[1] Then box.mini[1]=v0.y
		If v0.z<box.mini[2] Then box.mini[2]=v0.z

		If v1.x<box.mini[0] Then box.mini[0]=v1.x
		If v1.y<box.mini[1] Then box.mini[1]=v1.y
		If v1.z<box.mini[2] Then box.mini[2]=v1.z
		
		If v2.x<box.mini[0] Then box.mini[0]=v2.x
		If v2.y<box.mini[1] Then box.mini[1]=v2.y
		If v2.z<box.mini[2] Then box.mini[2]=v2.z

		If v0.x>box.maxi[0] Then box.maxi[0]=v0.x
		If v0.y>box.maxi[1] Then box.maxi[1]=v0.y
		If v0.z>box.maxi[2] Then box.maxi[2]=v0.z

		If v1.x>box.maxi[0] Then box.maxi[0]=v1.x
		If v1.y>box.maxi[1] Then box.maxi[1]=v1.y
		If v1.z>box.maxi[2] Then box.maxi[2]=v1.z
		
		If v2.x>box.maxi[0] Then box.maxi[0]=v2.x
		If v2.y>box.maxi[1] Then box.maxi[1]=v2.y
		If v2.z>box.maxi[2] Then box.maxi[2]=v2.z
		
		Return box
	
	End Function
	
	Function AABBAABBIntersection(a:AABB,b:AABB)

		If a.maxi[0]<b.mini[0] Or a.mini[0]>b.maxi[0] Return 0
		If a.maxi[1]<b.mini[1] Or a.mini[1]>b.maxi[1] Return 0
		If a.maxi[2]<b.mini[2] Or a.mini[2]>b.maxi[2] Return 0
		
		Return True

	End Function
	
	Function SphereAABBIntersection(s:TSphere,a:AABB)
	
		Local sx#=s.c.x#
		Local sy#=s.c.y#
		Local sz#=s.c.z#
		Local sr#=s.r#
		Local bx#=a.mini#[0]
		Local by#=a.mini#[1]
		Local bz#=a.mini#[2]
		Local bw#=a.maxi#[0]-bx#
		Local bh#=a.maxi#[1]-by#
		Local bd#=a.maxi#[2]-bz#
	
		Local dmin#=0
		Local sr2#=sr*sr
		
		' x axis
		If sx < bx
	
			dmin=dmin+((sx-bx)*(sx-bx))
			
		Else If sx>(bx+bw)
	
			dmin=dmin+(((sx-(bx+bw)))*((sx-(bx+bw))))
	
		EndIf
	
		' y axis
		If sy < by
	
			dmin=dmin+((sy-by)*(sy-by))
			
		Else If sy>(by+bh)
	
			dmin=dmin+(((sy-(by+bh)))*((sy-(by+bh))))
	
		EndIf
	
		' z axis
		If sz < bz
	
			dmin=dmin+((sz-bz)*(sz-bz))
	
		Else If sz>(bz+bd)
	
			dmin=dmin+(((sz-(bz+bd)))*((sz-(bz+bd))))
	
		EndIf
	
		If dmin#<=sr2# Then Return True Else Return False
	
	End Function

End Type

Type TSphere

	Field c:TVector=New TVector
	Field r#

End Type
