The Matrix 4 - How Neo Got His Groove Back.

BlitzMax Forums/BlitzMax OpenGL Programming/The Matrix 4 - How Neo Got His Groove Back.

Having some wierd issues with using matrixes in gl rather than it's usual rotatef funcs,

This code, embeded into v2's camera bind for testing,

  glRotatef 0,1,0,0
  glRotatef 1,0,Angle,0


Works as expected. The box arcing around the scene(As the camera is position 250 units away from it)

But, when I try to use the entities local(or global, it has both) matrix to define the rotation of the camera, something very wierd happens.
Instead of an arcing box I get a black screen, except for a brief full screen of white.

Which to me indicates something in matrix code(Which does work, tested as I was doing it 2dally.) isn't reallying conforming to the gl matrix layout..

Here's the matrix code I'm using,



Type Matrix
	
	Method New()
	
		Mat=New Double[16]
			
	End Method
	
	Method Delete()
	
	'	Release Mat
		Mat=Null
	
	End Method
	
	Method Identity()
	
		Local Index:Int
		
		Mat[ 0 ] = 1
		For Index=1 To 15
			Mat[ Index ]=0
		Next
	
	End Method
	
	Method Pitch( nPitch:Double )
	
		Self.Identity()
		mat[5]=Cos( nPitch )
		mat[6]=Sin( nPitch )
		mat[9]=-Sin( nPitch )
	    mat[10]=Cos( nPitch )
	    mat[15]=1
	
	End Method
	
	Method Yaw( nYaw:Double )
	
	   Self.Identity()
		mat[0]=Cos( nYaw )
		mat[2]=-Sin( nYaw )
		mat[5]=1
		mat[8]=Sin( nYaw )
		Mat[10]=Cos( nYaw )
	
	End Method
	
	Method Roll( nRoll:Double )
	
	   Self.Identity()
		mat[0]=Cos( nRoll )
		mat[1]=Sin( nRoll )
		mat[4]=-Sin( nRoll )
		mat[5]=Cos( nRoll )
	
	End Method
		
	Method Position( nX:Double,nY:Double,nZ:Double )
	
		Self.Identity()
		mat[0] = 1
		mat[3] = nX
		mat[5] = 1
		mat[7] = nY
		mat[11] = nZ
		mat[15] = 1
	
	End Method
	
	Method Copy( IN:Matrix)
	
	   Local Index:Int,Val:Double
	
	   For Index=0 To 15
		Mat[Index]=IN.Mat[Index]
	   Next	
	
	End Method
	
	Method Rotate( nPitch:Double,nYaw:Double,nRoll:Double,X:Double=0,Y:Double=0,Z:Double=0 )
		
		Self.identity()
		Local Temp:Matrix = New Matrix
				
		Self.Pitch( nPitch )
		Temp.Copy( Self )
		Self.Yaw( nYaw ) 
		Temp.Multiply( Self )
		Self.Roll( nRoll )
		Temp.Multiply( Self )
		Self.Position( X,Y,Z )
		Temp.Multiply( Self )
		
		Self.Copy( Temp )
		
	End Method
		
	Method TForm_Point( X:Double,Y:Double,Z:Double )
	
		tFormX = (mat[0] * X) + (mat[1] * Y) + (mat[2] * Z) + mat[3]
		tFormY = (mat[4] * X) + (mat[5] * Y) + (mat[6] * Z) + mat[7]
		tFormZ = (mat[8] * X) + (mat[9] * Y) + (Mat[10] * Z) + mat[11]
	
	End Method
	
	Method TForm_Point2D( X:Double,Y:Double )
		
		Local Z=0
		tFormX = (mat[0] * X) + (mat[1] * Y) + (mat[2] * Z) + mat[3]
		tFormY = (mat[4] * X) + (mat[5] * Y) + (mat[6] * Z) + mat[7]
		
	End Method
	
	
	
	Method Multiply( With:Matrix )
	
		Local Temp:Matrix = New Matrix
		Local M:Int,m1:Int,m2:Int
	
		For m=0 To 3
			For m1=0 To 3
				Temp.Mat[ m1*4+m]=0
				For m2=0 To 3
					Temp.Mat[ m1*4+m]:+With.Mat[m2*4+m]*Mat[m1*4+m2]
				Next
			Next
	   Next
	
	   Local Index:Int,Val:Double 
	
	   For Val:Double =EachIn Temp.mat
		Mat[Index]=Val
		Index:+1
	   Next
	   'Release Temp
	
	End Method
	
	Method Debug( PrintFunc:Int(Out:String) )
		
		For Local J=0 To 15
			
			printFunc (J+1)+":"+Mat[J]
			
		Next
			
	End Method
	
	Field Mat:Double[]
	Field tFormX:Double,tFormY:Double,tFormZ:Double,tW:Double
End Type



This is the code from the entity class that generates the 'correct' matrix for rotations.

Method Rotate( Pitch:Double,Yaw:Double,Roll:Double,GlobalRotation = True )
	
		If GlobalRotation
			
			Rotation.Rotate( Pitch,Yaw,Roll )
			LocalRot.Copy( Rotation )
			
			If Parent<>Null
				
				Rotation.Multiply( Parent.Rotation )
			'	Self.UpdateSubs()
						
			Else
			
				LocalRot.Rotate( 0,0,0 )
			
			EndIf
			
			Self.UpdateSubs()
						
		Else
			
			If Parent<>Null
			
				Local Temp:Matrix = New Matrix
				Temp.Rotate( Pitch,Yaw,Roll )
				Rotation.Copy( Parent.Rotation )
				Rotation.Multiply( Temp )
				Self.UpdateSubs()
			Else
				
				Rotation.Rotate( Pitch,Yaw,Roll )
				LocalRot.Rotate( 0,0,0 )
				Self.UpdateSubs()
				
			EndIf
			
		EndIf
	End Method



Any ideas would be nice, I've hit a brick wall, but don't really want to switch back to glrotatef etc...

This is how I pass the matrix to gl,

glmultmatrixd(Double Ptr(Varptr rotation.mat[0]) )
or same par, with glLoadMatrixD depending on situration. 
Wierd thing is I get identical results whichever one I use to define the camera's rotation. Which is the first rotation, and only in the simple test.


Well fixed it already. Shock horror it's actually alot faster now too.

Method Rotate( nPitch:Double,nYaw:Double,nRoll:Double )
	
	   Local A!,B!,C!,D!,E!,F!,AD!,BD!
	   A   = Cos( npitch)
   	   B   = Sin( npitch)
   	   C       = Cos(nyaw)
   	   D       = Sin(nyaw)
   	   E       = Cos(nroll)
       F       = Sin(nroll)
	   AD      =   A * D
   	   BD      =   B * D
	   mat[0]  =   C * E
	   mat[1]  =  -C * F
	   mat[2]  =   D
	   mat[4]  =  BD * E + A * F
	   mat[5]  = -BD * F + A * E
	   mat[6]  =  -B * C
	   mat[8]  = -AD * E + B * F
	   mat[9]  =  AD * F + B * E
	   mat[10] =   A * C
   	   mat[3]  =  mat[7] = mat[11] = mat[12] = mat[13] = mat[14] = 0
   	   mat[15] =  1
	
	End Method



mat[3] = mat[7] = mat[11] = mat[12] = mat[13] = mat[14] = 0



*confused......
Does that set mat[3] to 0 or -1 depending on if they all match 0 or not?!

I just converted it from some C++ code tbh.

And it's not working after all, for some reason it clips half the screen now(-320 displays fine)..can't manually adjust the viewport to compensate either.

Quats here we come...

it's amazing what you can figure out without using IF :)

Yes, I invented the IFless optimization over at blitzcoder.
Or to be more accurate, I discovered it and ignored the fact it's been used for years and claimed it as my own. American Style.

:)

The rr...um... AO..? Technique?

The what now? But yeah, if it's good I invented it...

just an FYI, i recently converted code using the same type of syntax:


mat[3] = mat[7] = mat[11] = mat[12] = mat[13] = mat[14] = 0


and while it compiles, it does not work. a simple test:
Framework BRL.Blitz

Local a:Int,b:Int,c:Int

a = b = c = 3

DebugLog(a)
DebugLog(b)
DebugLog(c)


ah, any suggestions how to get the above code working then? Might explain why it's producing a ton of visual problems when using it. (Same code works fine using glRotatef with quats, so it's not a gl problem)

I duno- I made it up... Antony Optimisation? :/

Let's walk away from thie conversation before it gets anymore surreal :)

Here's my math code just in the case that it might help...

Rem
	 Xiphias License
	 
	 This license is based off of the zlib/libpng license,
	 I do not take credit for the creation of it as such.
	 
	 This software is 'as-is', without any express or implied
	 warranty.	In no event will the author(s) be held liable
	 for damages arising from the use of this software.

	 You are granted to use this software for any purpose,
	 including commercial applications of the software, and
	 to alter, redistribute, and copy it freely, subject to
	 the following terms:

	 1. You are not to misrepresent the origin of the software;
			you must not claim that you created the original software.
			If you use this software, an acknowledgement in the product
			documentation (or elsewhere) would be appreciated, but it is
			not required.

	 2. Altered source versions must be plainly marked as such, and must
			not be misrepresented as being the original software.

	 3. This notice may not be removed or altered from any source distribution.

	 If you disagree with any of the terms of the license, you are not permitted
	 to use the software and should delete it immediately.
EndRem

Rem
	This software is written by Noel R. Cower
	<hooker.with.a.penis@...;

	Copyright (C) 2005 Noel Raymond Cower
EndRem

Import Brl.Math

Strict

Private

Const RAD_TO_DEGREE! = 180!/Pi
Const DEGREE_TO_RAD! = Pi/180!

Public

Rem bbdoc: Converts degrees to radians
End Rem
Function DegreeToRad!( d! )
	Return d*DEGREE_TO_RAD
End Function

Rem bbdoc: Converts radians to degrees
End Rem
Function RadToDegree!( r! )
	Return r*RAD_TO_DEGREE
End Function

Rem bbdoc: Gets the cotangent of an angle
End Rem
Function Cotangent!( A! )
	Return Tan( 90! - A )
End Function

Rem bbdoc: Gets the nearest power of two to an integer
End Rem
Function NearestPower:Int( i:Int )
	Local q:Int,r:Int=1
	While Not ( i < r And i > q )
		q=r
		r=q*2
	Wend
	Local da:Int=i-q
	Local db:Int=r-i
	If da > db Then
		Return r
	Else
		Return q
	EndIf
End Function

Rem bbdoc: Gets the slope of two points
End Rem
Function Slope!( x1!, y1!, x2!, y2! )
	Local m! = ( y1-y2 )/( x1-x2 )
	If m <= .0001! And m > 0! Then Return .0001!
	If m >= -.0001! And m < 0! Then Return -.0001!
	Return m
End Function

Rem bbdoc: Gets the Y intercept of two points
End Rem
Function YIntercept!( x1!, y1!, x2!, y2! )
	Return y1 - ( Slope( x1, y1, x2, y2 ) * x1 )
End Function

Rem bbdoc: Gets the Y value of X along the line made by two points
End Rem
Function ReturnedY!( x!, x1!, y1!, x2!, y2! )
	Return Slope( x1, y1, x2, y2 ) * x + YIntercept( x1, y1, x2, y2 )
End Function

Rem bbdoc: 4-by-4 homogenous matrix class
about:
Keep in mind that aside from Translate and Scale, all methods
will return a new matrix with the requested operations performed.
End Rem
Type Matrix
	Field m00# = 1, m01# = 0, m02# = 0, m03# = 0
	Field m10# = 0, m11# = 1, m12# = 0, m13# = 0
	Field m20# = 0, m21# = 0, m22# = 1, m23# = 0
	Field m30# = 0, m31# = 0, m32# = 0, m33# = 1
	
	Rem bbdoc: Copies the Matrix class
	End Rem
	Method Copy:Matrix( )
		Local i:Matrix = New Matrix
		MemCopy( Varptr i.m00, Varptr m00, 64 )
		Return i
	End Method
	
	Rem bbdoc: Sets the translation elements of the matrix
	End Rem
	Method Translate( x#, y#, z# )
		m03 = x
		m13 = y
		m23 = z
	End Method
	
	Rem bbdoc: Scales the rotation elements of the matrix
	End Rem
	Method Scale( x#, y#, z# )
		m00 :* x
		m10 :* x
		m20 :* x
		
		m01 :* y
		m11 :* y
		m21 :* y
		
		m02 :* z
		m12 :* z
		m22 :* z
	End Method
	
	Rem bbdoc: Transforms the matrix by another matrix
	End Rem
	Method TransformMat:Matrix( i:Matrix )
		Local r:Matrix = New Matrix
		
		r.m00 = m00 * i.m00 + m01 * i.m10 + m02 * i.m20 + m03 * i.m30
		r.m01 = m00 * i.m01 + m01 * i.m11 + m02 * i.m21 + m03 * i.m31
		r.m02 = m00 * i.m02 + m01 * i.m12 + m02 * i.m22 + m03 * i.m32
		r.m03 = m00 * i.m03 + m01 * i.m13 + m02 * i.m23 + m03 * i.m33
		
		r.m10 = m10 * i.m00 + m11 * i.m10 + m12 * i.m20 + m13 * i.m30
		r.m11 = m10 * i.m01 + m11 * i.m11 + m12 * i.m21 + m13 * i.m31
		r.m12 = m10 * i.m02 + m11 * i.m12 + m12 * i.m22 + m13 * i.m32
		r.m13 = m10 * i.m03 + m11 * i.m13 + m12 * i.m23 + m13 * i.m33
		
		r.m20 = m20 * i.m00 + m21 * i.m10 + m22 * i.m20 + m23 * i.m30
		r.m21 = m20 * i.m01 + m21 * i.m11 + m22 * i.m21 + m23 * i.m31
		r.m22 = m20 * i.m02 + m21 * i.m12 + m22 * i.m22 + m23 * i.m32
		r.m23 = m20 * i.m03 + m21 * i.m13 + m22 * i.m23 + m23 * i.m33
		
		r.m30 = m30 * i.m00 + m31 * i.m10 + m32 * i.m20 + m33 * i.m30
		r.m31 = m30 * i.m01 + m31 * i.m11 + m32 * i.m21 + m33 * i.m31
		r.m32 = m30 * i.m02 + m31 * i.m12 + m32 * i.m22 + m33 * i.m32
		r.m33 = m30 * i.m03 + m31 * i.m13 + m32 * i.m23 + m33 * i.m33
		
		Return r
	End Method
	
	Rem bbdoc: Transforms a vector by the matrix
	End Rem
	Method TransformVec:Vector( i:Vector )
		Local r:Vector = New Vector
		Local w# = 1.0/( m30 + m31 + m32 + m33 )
		
		r.x = ( ( m00*i.x ) + ( m01*i.y ) + ( m02*i.z ) + m03 ) * w
		r.y = ( ( m10*i.x ) + ( m11*i.y ) + ( m12*i.z ) + m13 ) * w
		r.z = ( ( m20*i.x ) + ( m21*i.y ) + ( m22*i.z ) + m23 ) * w
		
		Return r
	End Method
	
	Rem bbdoc: Adds two matrices
	End Rem
	Method Add:Matrix( i:Matrix )
		Local a:Float Ptr = GetPtr( )
		Local b:Float Ptr = GetPtr( )
		Local r:Matrix = New Matrix
		Local c:Float Ptr = r.GetPtr( )
		For Local n:Int = 0 To 15
			c[n]=a[n]+b[n]
		Next
		Return r
	End Method
	
	Rem bbdoc: Subtracts two matrices
	End Rem
	Method Subtract:Matrix( i:Matrix )
	 Local a:Float Ptr = GetPtr( )
		Local b:Float Ptr = GetPtr( )
		Local r:Matrix = New Matrix
		Local c:Float Ptr = r.GetPtr( )
		For Local n:Int = 0 To 15
			c[n]=a[n]-b[n]
		Next
		Return r
	End Method
	
	Rem bbdoc: Transposes the matrix
	End Rem
	Method Transpose:Matrix( )
	 Local x:Int,y:Int
	 Local r:Matrix = New Matrix
	 Local a:Float Ptr = GetPtr( )
	 Local b:Float Ptr = r.GetPtr( )
	 For x = 0 To 3
		 For y = 0 To 3
			 b[x*4+y] = a[y*4+x]
		 Next
	 Next
	 Return r
	End Method
	
	Rem bbdoc: Returns a pointer to the first matrix element
	End Rem
	Method GetPtr:Float Ptr( )
		Return Varptr m00
	End Method
	
	Rem bbdoc: Returns an array made from the elements of the matrix
	End Rem
	Method ToArray:Float[]( )
		Local r:Float[16]
		MemCopy( Varptr r[0], GetPtr( ), 64 )
		Return r
	End Method
	
	Rem bbdoc: Creates a matrix from an array of floats
	End Rem
	Function FromArray:Matrix( arr:Float[] )
		Return FromPtr( Varptr arr[0] )
	End Function
	
	Rem bbdoc: Creates an array from a pointer to an array of floats
	End Rem
	Function FromPtr:Matrix( arr:Float Ptr )
		Local r:Matrix = New Matrix
		Local p:Float Ptr = r.GetPtr( )
		MemCopy( p, arr, 64 )
		Return r
	End Function
End Type

Rem bbdoc: Three-component vector class
about:
Keep in mind that aside from Dot, Magnitude, Normalize, Floor, and Ceil,
all methods will return a new Vector with the requested operations performed.
End Rem
Type Vector
	Rem bbdoc: X component
	End Rem
	Field x#
	Rem bbdoc: Y component
	End Rem
	Field y#
	Rem bbdoc: Z component
	End Rem
	Field z#
	
	Rem bbdoc: Adds a vector
	End Rem
	Method Add:Vector( i:Vector )
		Local r:Vector = New Vector
		r.x = x+i.x
		r.y = y+i.y
		r.z = z+i.z
		Return r
	End Method
	
	Rem bbdoc: Subtracts a vector
	End Rem
	Method Subtract:Vector( i:Vector )
		Local r:Vector = New Vector
		r.x = x-i.x
		r.y = y-i.y
		r.z = z-i.z
		Return r
	End Method
	
	Rem bbdoc: Multiplies a vector with another vector
	End Rem
	Method Multiply:Vector( i:Vector )
		Local r:Vector = New Vector
		r.x = x*i.x
		r.y = y*i.y
		r.z = z*i.z
		Return r
	End Method
	
	Rem bbdoc: Divides a vector by another vector
	End Rem
	Method Divide:Vector( i:Vector )
		Local r:Vector = New Vector
		r.x = x/i.x
		r.y = y/i.y
		r.z = z/i.z
		Return r
	End Method
	
	Rem bbdoc: Scales a vector by a scalar
	End Rem
	Method Scale:Vector( i:Float )
		Local r:Vector = New Vector
		r.x = x*i
		r.y = y*i
		r.z = z*i
		Return r
	End Method
	
	Rem bbdoc: Gets the dot product of two vectors (Self and another)
	End Rem
	Method Dot:Float( i:Vector )
		Return x*i.x+y*i.y+z*i.z
	End Method
	
	Rem bbdoc: Gets the magnitude of the vector
	End Rem
	Method Magnitude:Float( )
		Return Sqr( x*x + y*y + z*z )
	End Method
	
	Rem bbdoc: Normalizes the vector
	End Rem
	Method Normalize( )
		Local s:Float = 1.0 / Magnitude( )
		x:*s
		y:*s
		z:*s
	End Method
	
	Rem bbdoc: Gets the cross product of two vectors (Self and another)
	End Rem
	Method Cross:Vector( i:Vector )
		Local r:Vector = New Vector
		r.x = y*i.z - z*i.y
		r.y = x*i.z - z*i.x
		r.z = x*i.y - y*i.x
		Return r
	End Method
	
	Rem bbdoc: Returns a reflection vector
	End Rem
	Method Reflect:Vector( i:Vector )
		Local f:Float = 2*Dot( i )
		Return Subtract( i.Scale( f ) )
	End Method
	
	Rem bbdoc: Returns a quaternion containing the rotation between two vectors
	End Rem
	Method RotationTo:Quat( dest:Vector )
		' Based on the Axiom engine's Vector3.GetRotationTo method code
		' Which is in turn based on Stan Melax's article in Game Programming Gems
		Local q:Quat = New Quat
		
		Local v0:Vector = Vector.Create( x, y, z )
		Local v1:Vector = New Vector
	 
		Local c:Vector = v0.Cross( v1 )
		Local d:Float = v0.Dot( v1 )
		
		If d >= 1.0 Then Return New Quat
	 
		Local s:Float = Sqr( ( 1+d ) * 2 )
		Local inverse:Float = 1.0 / s
		
		q.x = c.x * inverse
		q.y = c.y * inverse
		q.z = c.z * inverse
		q.w = s*.5
	 
		Return q
	End Method
	
	Rem bbdoc: Floors a vector
	End Rem
	Method Floor( i:Vector )
		If i.x < x Then x = i.x
		If i.y < y Then y = i.y
		If i.z < z Then z = i.z
	End Method
	
	Rem bbdoc: Ceils a vector
	End Rem
	Method Ceil( i:Vector )
		If i.x > x Then x = i.x
		If i.y > y Then y = i.y
		If i.z > z Then z = i.z
	End Method
	
	Rem bbdoc: Returns a pointer to the first component of the vector
	End Rem
	Method GetPtr:Float Ptr( )
		Return Varptr x
	End Method
	
	Rem bbdoc: Converts the vector to a float array
	End Rem
	Method ToArray:Float[]( )
		Local r:Float[3]
		MemCopy( Varptr r[0], GetPtr( ), 12 )
		Return r
	End Method
	
	Rem bbdoc: Copies the Vector class
	End Rem
	Method Copy:Vector( )
		Local i:Vector = New Vector
		MemCopy( i.GetPtr( ), GetPtr( ), 12 )
		Return i
	End Method
	
	Rem bbdoc: Creates a new vector
	End Rem
	Function Create:Vector( x#, y#, z# )
		Local i:Vector = New Vector
		i.x = x
		i.y = y
		i.z = z
		Return i
	End Function
	
	Rem bbdoc: Creates a vector from an array of floats
	End Rem
	Function FromArray:Vector( arr:Float[] )
		Return FromPtr( Varptr arr[0] )
	End Function
	
	Rem bbdoc: Creates a vector from a pointer to a float array
	End Rem
	Function FromPtr:Vector( arr:Float Ptr )
		Local r:Vector = New Vector
		Local p:Float Ptr = r.GetPtr( )
		MemCopy( p, arr, 12 )
		Return r
	End Function
End Type

Rem bbdoc: Quaternion class.
about:
A lot of code in this class is based off of that in the
<a href="http://www.axiom3d.org">Axiom engine</a>.<br/><br/>
Aside from Magnitude, Normalize, and Dot, all methods will
return a new Quat with the requested operations performed.
End Rem
Type Quat
	Rem bbdoc: W component
	End Rem
	Field w#=1
	Rem bbdoc: X component
	End Rem
	Field x#=0
	Rem bbdoc: Y component
	End Rem
	Field y#=0
	Rem bbdoc: Z component
	End Rem
	Field z#=0
	
	Rem bbdoc: Gets the magnitude of the quaternion
	End Rem
	Method Magnitude:Float( )
		Return Sqr( w*w + x*x + y*y + z*z )
	End Method
	
	Rem bbdoc: Normalizes a quaternion
	End Rem
	Method Normalize( )
		Local s:Float = 1.0 / Magnitude( )
		w:*s
		x:*s
		y:*s
		z:*s
	End Method
	
	Rem bbdoc: Multiplies a quaternion
	End Rem
	Method MultiplyQuat:Quat( i:Quat )
		Local r:Quat = New Quat
		
		r.w = w*i.w - x*i.x - y*i.y - z*i.z
		r.x = w*i.x - x*i.w - y*i.z - z*i.y
		r.y = w*i.y - y*i.w - z*i.x - x*i.z
		r.z = w*i.z - z*i.w - x*i.y - y*i.x
		
		Return r
	End Method
	
	Rem bbdoc: Multiplies a vector
	End Rem
	Method MultiplyVec:Vector( i:Vector )
		Local a:Vector,b:Vector,c:Vector=Vector.FromArray( [x,y,z] )
		a=c.Cross( i )
		b=c.Cross( a )
		a.Scale( 2*w )
		b.Scale( 2 )
		
		Return i.Add( a.Add( b ) )
	End Method
	
	Rem bbdoc: Scales the quaternion
	End Rem
	Method Scale:Quat( f:Float )
		Local r:Quat = New Quat
		r.w = w*f
		r.x = x*f
		r.y = y*f
		r.z = z*f
		Return r
	End Method
	
	Rem bbdoc: Adds the quaternion
	End Rem
	Method Add:Quat( i:Quat )
		Local r:Quat = New Quat
		r.w = w+i.w
		r.x = x+i.x
		r.y = y+i.y
		r.z = z+i.z
		Return r
	End Method
	
	Rem bbdoc: Subtracts the quaternion
	End Rem
	Method Subtract:Quat( i:Quat )
		Local r:Quat = New Quat
		r.w = w+i.w
		r.x = x+i.x
		r.y = y+i.y
		r.z = z+i.z
		Return r
	End Method
	
	Rem bbdoc: Gets the dot product of two quaternions (Self and another)
	End Rem
	Method Dot:Float( i:Quat )
		Return w*i.w + x*i.x + y*i.y + z*i.z
	End Method
	
	Rem bbdoc: Gets the quaternion slerp of two quaternions
	End Rem
	Function Slerp:Quat( time:Float, a:Quat, b:Quat, useShortest = False )
		' Based off of code in Axiom
		Local cs:Float = a.Dot( b )
		Local angle:Float = ACos( cs )
		
		If Abs(angle) < .0001 Then Return a.Copy( )
		
		Local sn:Float = Sin( angle )
		Local iSin:Float = 1.0/sn
		Local co1:Float = Sin( ( 1.0-time ) * angle ) * iSin
		Local co2:Float = Sin( time * angle ) * iSin
		
		Local r:Quat
		
		If cs < .0 And useShortest > 0 Then
			co1 = -co1
			r = a.Scale( co1 ).Add( b.Scale( co2 ) )
			r.Normalize( )
		Else
			r = a.Scale( co1 ).Add( b.Scale( co2 ) )
		EndIf
		
		Return r
	End Function
	
	Rem bbdoc: Creates a quaternion from an angle and an axis
	End Rem
	Function FromAngleAxis:Quat( a:Float, ax:Vector )
		' Based off of code in Axiom
		Local r:Quat = New Quat
		
		Local ha:Float = .5*a
		Local sn:Float = Sin( ha )
		
		r.w = Cos( ha )
		r.x = sn*ax.x
		r.y = sn*ax.y
		r.z = sn*ax.z
		
		Return r
	End Function
	
	Rem bbdoc: Blank
	End Rem
	Function Squad:Quat( t:Float, p:Quat, a:Quat, b:Quat, q:Quat, useShortest = False )
		' Based off of code in Axiom
		Local time:Float = 2*t*( 1.0-t )
		
		Local slerpA:Quat = Slerp( t, p, q, useShortest )
		Local slerpB:Quat = Slerp( t, a, b )
		
		Return Slerp( time, slerpA, slerpB )
	End Function
	
	Rem bbdoc: Sets @angle to the angle of the quaternion and @ax to the axis.
	End Rem
	Method ToAngleAxis( angle:Float Var, ax:Vector Var )
		' Based off of code in Axiom
		Local sqrLen:Float = x*x + y*y + z*z
		
		If sqrLen > 0 Then
			angle = 2 * ACos( w )
			Local invLength:Float = 1.0 / Sqr( sqrLen )
			ax.x = x * invLength
			ax.y = y * invLength
			ax.z = z * invLength
		Else
			angle = 0
			ax.x = 1
			ax.y = 0
			ax.z = 0
		EndIf
	End Method
	
	Rem bbdoc: Returns a matrix made from the quaternion
	End Rem
	Method ToMatrix:Matrix( )
		' Based off of code in Axiom
		Local m:Matrix = New Matrix
		
		Local tx# = 2*x
		Local ty# = 2*y
		Local tz# = 2*z
		Local twx# = tx*w
		Local twy# = ty*w
		Local twz# = tz*w
		Local txx# = tx*x
		Local txy# = ty*x
		Local txz# = tz*x
		Local tyy# = ty*y
		Local tyz# = tz*y
		Local tzz# = tz*z
		
		m.m00 = 1.0-(tyy+tzz)
		m.m01 = txy-twz
		m.m02 = txz+twy
		m.m10 = txy+twz
		m.m11 = 1.0-(txx+tzz)
		m.m12 = tyz-twx
		m.m20 = txz-twy
		m.m21 = tyz+twx
		m.m22 = 1.0-(txx+tyy)
		
		Return m
	End Method
	
	Rem bbdoc: Returns the inverse of the quaternion
	End Rem
	Method Inverse:Quat( )
		Local norm:Float = Dot( Self )
		If norm > 0 Then
			Local r:Quat = New Quat
			Local inorm:Float = 1.0 / norm
			r.w = w * inorm
			r.x = -x * inorm
			r.y = -y * inorm
			r.z = -z * inorm
			Return r
		EndIf
		
		Return Quat.Zero( )
	End Method
	
	Rem bbdoc: Returns the axises of the quaternion
	End Rem
	Method ToAxes( xAxis:Vector Var, yAxis:Vector Var, zAxis:Vector Var )
		xAxis = New Vector
		yAxis = New Vector
		zAxis = New Vector
		
		Local rot:Matrix = ToMatrix( )
		
		xAxis.x = rot.m00
		xAxis.y = rot.m10
		xAxis.z = rot.m20
		
		yAxis.x = rot.m01
		yAxis.y = rot.m11
		yAxis.z = rot.m21
		
		zAxis.x = rot.m02
		zAxis.y = rot.m12
		zAxis.z = rot.m22
	End Method
	
	Rem bbdoc: Creates a quaternion from axises
	End Rem
	Method FromAxes( xAxis:Vector, yAxis:Vector, zAxis:Vector )
		Local rot:Matrix = New Matrix
		
		rot.m00 = xAxis.x
		rot.m10 = xAxis.y
		rot.m20 = xAxis.z
		
		rot.m01 = yAxis.x
		rot.m11 = yAxis.y
		rot.m21 = yAxis.z
		
		rot.m02 = zAxis.x
		rot.m12 = zAxis.y
		rot.m22 = zAxis.z
		
		Local q:Quat = FromRotationMatrix( rot )
		MemCopy( GetPtr( ), q.GetPtr( ), 16 )
	End Method
	
	Rem bbdoc: Creates a quaternion from a matrix
	End Rem
	Function FromRotationMatrix:Quat( mat:Matrix )
		Local this:Quat = New Quat
		
		Local trace:Float = mat.m00 + mat.m11 + mat.m22
		Local root:Float = 0
		
		If trace > 0 Then
			root = Sqr( trace + 1 )
			this.w = .5 * root
			root = .5 / root
			this.x = ( mat.m21-mat.m12 ) * root
			this.y = ( mat.m02-mat.m20 ) * root
			this.z = ( mat.m10-mat.m01 ) * root
		Else
			Local p:Float Ptr = mat.GetPtr( )
			Local i:Int = 0
			If mat.m11 > mat.m00 Then i=1
			If mat.m22 > p[i*4+i] Then i=2
			
			Local j:Int = _next( i )
			Local k:Int = _next( j )
			
			root = Sqr( p[i*4+i] - p[j*4+j] - p[k*4+k] + 1.0 )
			
			Local aq:Float Ptr = this.GetPtr( )
			aq[i] = .5 * root
			this.w = .5 / root
			aq[j] = (p[j+i*4] + p[i+j*4])*root
			aq[k] = (p[k+i*4] + p[i+k*4])*root
		EndIf
		
		Return this
		
		Function _next( i:Int )
			Select i
				Case 0
					Return 1
				Case 1
					Return 2
				Case 2
					Return 0
			End Select
		End Function
	End Function
	
	Rem bbdoc: Blank
	End Rem
	Method Log:Quat( )
		Local r:Quat = Quat.Zero( )
		If Abs( w ) < 1.0 Then
			Local angle:Float = ACos( w )
			Local sn:Float = Sin( angle )
			
			If Abs( sn ) > .0001 Then
				Local co:Float = angle / sn
				r.x = co*x
				r.y = co*y
				r.z = co*z
			Else
				r.x = x
				r.y = y
				r.z = z
			EndIf
		EndIf
		
		Return r
	End Method
	
	Rem bbdoc: Gets a zero-ed quaternion
	End Rem
	Function Zero:Quat( )
		Return Create( 0, 0, 0, 0 )
	End Function
	
	Rem bbdoc: Creates a new quaternion
	End Rem
	Function Create:Quat( w# = 1, x# = 0, y# = 0, z# = 0 )
		Local r:Quat = New Quat
		r.w = w; r.x = x; r.y = y; r.z = z
		Return r
	End Function
	
	Rem bbdoc: Converts the quaternion to a float array
	End Rem
	Method ToArray:Float[]( )
		Local r:Float[4]
		MemCopy( Varptr r[0], GetPtr( ), 16 )
		Return r
	End Method
	
	Rem bbdoc: Returns a float pointer to the first component of the quaternion
	End Rem
	Method GetPtr:Float Ptr( )
		Return Varptr w
	End Method
	
	Rem bbdoc: Creates a quaternion from an array
	End Rem
	Function FromArray:Quat( arr:Float[] )
		Return FromPtr( Varptr arr[0] )
	End Function
	
	Rem bbdoc: Creates a quaternion from a pointer to a float array
	End Rem
	Function FromPtr:Quat( arr:Float Ptr )
		Local r:Quat = New Quat
		MemCopy( r.GetPtr( ), arr, 16 )
		Return r
	End Function
	
	Rem bbdoc: Copies the quaternion class
	End Rem
	Method Copy:Quat( )
		Local r:Quat = New Quat
		MemCopy( r.GetPtr( ), GetPtr( ), 16 )
		Return r
	End Method
End Type

Rem bbdoc: Plane class
End Rem
Type Plane
	Field norm:Vector, d#
	
	Method New( )
		norm = Vector.Create( 0, 1, 0 )
		d = 1
	End Method
	
	Rem bbdoc: Gets the distance from a vector to the plane
	End Rem
	Method Distance#( p:Vector )
		Return norm.Dot( p ) + d
	End Method
	
	Rem bbdoc: Returns which side of the plane a vector is on
	End Rem
	Method Side( p:Vector )
		Local di:Float = Distance( p )
		
		If di > 0 Then
			Return 1
		ElseIf di < 0 Then
			Return -1
		EndIf
		Return 0
	End Method
	
	Rem bbdoc: Gets the plane normal vector
	End Rem
	Method GetNormal:Vector( )
		Return norm.Copy( )
	End Method
	
	Rem bbdoc: Creates a new plane
	End Rem
	Function Create:Plane( normal:Vector, d# )
		Local i:Plane = New Plane
		i.norm = normal.Copy( )
		i.d = d
		Return i
	End Function
	
	Rem bbdoc: Creates a plane from an array of floats
	End Rem
	Function FromArray:Plane( arr:Float[] )
		Return FromPtr( Varptr arr[0] )
	End Function
	
	Rem bbdoc: Creates a plane from a pointer to an array of floats
	End Rem
	Function FromPtr:Plane( arr:Float Ptr )
		Local i:Plane = New Plane
		i.norm = Vector.FromPtr( arr )
		i.d = arr[3]
		Return i
	End Function
	
	'' Can't do a standard memory copy for Planes, as they have a Vector reference
	Rem bbdoc: Copies the Plane class
	End Rem
	Method Copy:Plane( )
		Local i:Plane = New Plane
		i.d = d
		i.norm = norm.Copy( )
		Return i
	End Method
End Type

Rem bbdoc: Rectangle class
End Rem
Type Rect
	Rem bbdoc: X component
	End Rem
	Field x#
	Rem bbdoc: Y component
	End Rem
	Field y#
	Rem bbdoc: Width component
	End Rem
	Field w#
	Rem bbdoc: Height component
	End Rem
	Field h#
	
	Rem bbdoc: Whether or not the rectangle intersects with another rectangle
	End Rem
	Method Intersects( other:Rect )
		If x > other.x+other.w Or..
			x+w < other.x Or..
			y > other.y+other.h Or..
			y+h < other.y Then Return 0
		Return 1
	End Method
	
	Rem bbdoc: Returns whether or not @p is inside the rectangle
	End Rem
	Method PointInside( p:Point )
		If p.x < x+w And p.y < y+h And p.x > x And p.y > y Then Return 1
		Return 0
	End Method
End Type

' AKA Vector2
'' I didn't include the extras like FromPtr/FromArray/etc. since
'' this is only a 2-component vector.	Use Create if you need a new one.
Rem bbdoc: Point class
End Rem
Type Point
	Rem bbdoc: X component
	End Rem
	Field x#
	Rem bbdoc: Y component
	End Rem
	Field y#
	
	Rem bbdoc: Returns the magnitude of the point
	End Rem
	Method Magnitude#( )
		Return Sqr( x*x + y*y )
	End Method
	
	Rem bbdoc: Returns the difference of two points
	End Rem
	Method Subtract:Point( i:Point )
		Return Create( x-i.x, y-i.y )
	End Method
	
	Rem bbdoc: Returns the sum of two points
	End Rem
	Method Add:Point( i:Point )
		Return Create( x+i.x, y+i.y )
	End Method
	
	Rem bbdoc: Returns the product of two points
	End Rem
	Method Multiply:Point( i:Point )
		Return Create( x*i.x, y*i.y )
	End Method
	
	Rem bbdoc: Returns the divisor of two points
	End Rem
	Method Divide:Point( i:Point )
		Return Create( x/i.x, y/i.y )
	End Method
	
	Rem bbdoc: Creates a new point
	End Rem
	Function Create:Point( x#, y# )
		Local i:Point = New Point
		i.x = x
		i.y = y
		Return i
	End Function
	
	Rem bbdoc: Copies the point
	End Rem
	Method Copy:Point( )
		Return Create( x, y )
	End Method
End Type

Rem bbdoc: Alias for the Point class
End Rem
Type Vector2 Extends Point
End Type

Rem bbdoc: Alias for the Matrix class
End Rem
Type Matrix4 Extends Matrix
End Type

Rem bbdoc: Alias for the Quat class
End Rem
Type Quaternion Extends Quat
End Type

Rem bbdoc: Alias for the Vector class
End Rem
Type Vector3 Extends Vector
End Type


Edit: And don't forget to transpose matrices before doing glLoadMatrixf( YourMatrix.GetPtr( ) )

Thanks Noel, my matrix rotation code is now working fine thankfully so i'm halt tempted to stay with it rather than try yours,
Though I do have a problem, tform on points is producing wierd results when both pitch and yaw is involved, resulting in sub-entities arcing when they should only pivot..my vector/mult code is the same as yours, technically, so I'm stomped again. One of these days i'll have to learn some maths for real...

But anyway, did your code work fine for such things? I.e, if I tformed a vector of 100,0,0 on a rotation matrix consisting of 45,90,0, would the resultant vector properly only be affected by the yaw as the pitch shouldn't affect anything that has a z value of 0.

?

Nope, smae 'problem'.

<Bleep>.


if I tformed a vector of 100,0,0 on a rotation matrix consisting of 45,90,0, would the resultant vector properly only be affected by the yaw as the pitch shouldn't affect anything that has a z value of 0.



Antony, what do you expect to happen here? If I visualise the transform as rotating the reference axis, wouldn't 100,0,0 => 0,-50,-50? (quick guess, could be wrong)

Shouldn't do. I mean consider a player character.

Facing forward.

Roll it 90 degrees. Now in b3d if you MoveEntity Man,0,0,5
It'll only move..wait..are you right? Is this guy right?

Have I been going nuts over something that is not even a bug?

Can we get a confirmation? ANYONE! :)

just a thought

mat[3] = mat[7] = mat[11] = mat[12] = mat[13] = mat[14] = 0


doesnt zero anything. as it does in C, I guess thats where you copied the code from...

Yeah, I fixed that a while back.

Just had to zero them individually.

I'm really no good at maths...(Shocker!)

wait till you look at doing a rotation on any axis using quats... urrgh, its not nice!

Dont suppose you know an easy way to work out up, side and forward vectors from eular angles do you?

The way I'd do it is, transform the euler angles into a rotation matrix, then,

to get the up vector tform a vector of 0,1,0 by the rotation matrix, side -1 or 1,0,0 and for forward, 0,0,1

It should then be rotated correctly.

As is I'm almost certainly stopping developing vivid2.0 now, in favour of ogre/vc. At least until max3d is out. Too much work :)

Awesome.

/\ Bored man typing, we've got a bored man typing here./\

antony any danger of you sending me what you have on vivid2.0 so I can develop it further?

Can do, although if you make millions out of it I want a nice car out of it :)

I'll send it later this morning. just woke up.

oh, thought it was open source?

Well, it's upto you really. You can upload it as an open source project or just keep it for yourself.

well I could if you sent it... >:)

Oh don't worry, I will. I'm just the world's most least motivated man. :)

ether that or vivid's just vapour-ware :))

Well check your inbox mr suspecious :)