OpenGL Matrix

Advanced game related topics
xorc1zt
Enthusiast
Enthusiast
Posts: 276
Joined: Sat Jul 09, 2011 7:57 am

OpenGL Matrix

Post by xorc1zt »

Since opengl 3.0 you must deal with matrix on yourself, this code should provide everything you need.

Turn off #TRACEFUNCTION for disabling the debug tracing.

http://pastebin.com/6tFeNXc2

Code: Select all

; *---------------------------------*
; *   OpenGL Matrix                 *
; *   xorc1zt                       *
; *   2011                          *
; *---------------------------------*


; ** IMPORTANT ** : OpenGL Matrix are column-major ordered
;
;   m[0] m[4] m[8]  m[12]     m[Xx] m[Yx] m[Zx] m[Tx]
;   m[1] m[5] m[9]  m[13]     m[Xy] m[Yy] m[Zy] m[Ty]
;   m[2] m[6] m[10] m[14] ==> m[Xz] m[Yz] m[Zz] m[Tz]
;   m[3] m[7] m[11] m[15]     m[Xw] m[Yw] m[Zw] m[Tw]
;
;

EnableExplicit
#MATRIX_SIZEBYTE = 64 ; 16*float
#TRACEFUNCTION = #False

Macro traceFunction(string)
  CompilerIf #TRACEFUNCTION
    Debug "[ TRACE ]: "+string
  CompilerEndIf
EndMacro

Interface MATRIX
  debugValues()
  getAddress()
  identity()
  multiply(MATRIX)
  rotateX(angledegree.f)
  rotateY(angledegree.f)
  rotateZ(angledegree.f)
  translate(x.f, y.f, z.f)
  perspective(angle.f, near.f, far.f, aspect.f)
  orthogonal(left.f, right.f, bottom.f, top.f, near.f, far.f)
  lookAt(eyeX.f, eyeY.f, eyeZ.f, centerX.f, centerY.f, centerZ.f, upX.f, upY.f, upZ.f)
  push()
  pop()
  destroy()
EndInterface

Structure PARENTSTR
  value.f[16]
  *parent.PARENTSTR
EndStructure

Structure MATRIXSTR
  VTable.l
  value.f[16]
  label.s
  *parent.PARENTSTR
EndStructure

Enumeration
  #Xx
  #Xy
  #Xz
  #Xw
  #Yx
  #Yy
  #Yz
  #Yw
  #Zx
  #Zy
  #Zz
  #Zw
  #Tx
  #Ty
  #Tz
  #Tw
EndEnumeration

Declare   crossProduct( Array *a.f(1), Array *b.f(1), Array *result.f(1))
Declare   normalize(Array *a.f(1))
Declare   debugValues(*Self.MATRIXSTR)
Declare.i getAddress(*Self.MATRIXSTR)
Declare   identity(*Self.MATRIXSTR)
Declare   multiply(*self.MATRIXSTR, *matrix.MATRIXSTR)
Declare   rotateX(*Self.MATRIXSTR, angledegree.f)
Declare   rotateY(*Self.MATRIXSTR, angledegree.f)
Declare   rotateZ(*Self.MATRIXSTR, angledegree.f)
Declare   translate(*Self.MATRIXSTR, x.f, y.f, z.f)
Declare   perspective(*Self.MATRIXSTR, angle.f, near.f, far.f, aspect.f)
Declare   orthogonal(*Self.MATRIXSTR, left.f, right.f, bottom.f, top.f, near.f, far.f)
Declare   lookAt(*Self.MATRIXSTR, eyeX.f, eyeY.f, eyeZ.f, centerX.f, centerY.f, centerZ.f, upX.f, upY.f, upZ.f)
Declare   push(*Self.MATRIXSTR)
Declare   pop(*Self.MATRIXSTR)
Declare   destroy(*Self.MATRIXSTR)
Declare.i createMatrix(label.s)   

Procedure crossProduct( Array *a.f(1), Array *b.f(1), Array *result.f(1))
  traceFunction("crossProduct()")
  
  *result(0) = ( *a(1) * *b(2) ) - ( *b(1) * *a(2) )
  *result(1) = ( *a(2) * *b(0) ) - ( *b(2) * *a(0) )
  *result(2) = ( *a(0) * *b(1) ) - ( *b(0) * *a(1) )
EndProcedure

Procedure normalize(Array *a.f(1))
  traceFunction("normalize()")
  
  Define mag.f = Sqr( *a(0) * *a(0) + *a(1) * *a(1) + *a(2) * *a(2) )
  *a(0) / mag
  *a(1) / mag
  *a(2) / mag
EndProcedure

Procedure debugValues(*Self.MATRIXSTR)
  traceFunction("debugValues()")
  
  Debug "---- MATRIX: "+*self\label+" ----"
  Debug StrF( *self\value[#Xx] )+" "+StrF( *self\value[#Yx] )+" "+StrF( *self\value[#Zx] )+" "+StrF( *self\value[#Tx] )
  Debug StrF( *self\value[#Xy] )+" "+StrF( *self\value[#Yy] )+" "+StrF( *self\value[#Zy] )+" "+StrF( *self\value[#Ty] )
  Debug StrF( *self\value[#Xz] )+" "+StrF( *self\value[#Yz] )+" "+StrF( *self\value[#Zz] )+" "+StrF( *self\value[#Tz] )
  Debug StrF( *self\value[#Xw] )+" "+StrF( *self\value[#Yw] )+" "+StrF( *self\value[#Zw] )+" "+StrF( *self\value[#Tw] )
EndProcedure

Procedure.i getAddress(*Self.MATRIXSTR)
  traceFunction("getAddress()")
  ProcedureReturn @*self\value[0]
EndProcedure

Procedure identity(*Self.MATRIXSTR)
  traceFunction("indentity()")
  
  CompilerIf 1
    With *Self
      \value[#Xx] = 1
      \value[#Xy] = 0
      \value[#Xz] = 0
      \value[#Xw] = 0
      
      \value[#Yx] = 0
      \value[#Yy] = 1
      \value[#Yz] = 0
      \value[#Yw] = 0
      
      \value[#Zx] = 0
      \value[#Zy] = 0
      \value[#Zz] = 1
      \value[#Zw] = 0
      
      \value[#Tx] = 0
      \value[#Ty] = 0
      \value[#Tz] = 0
      \value[#Tw] = 1
    EndWith
  CompilerElse
    CopyMemory(?MatrixIdentity, @*self\value[0], #MATRIX_SIZEBYTE)
  CompilerEndIf
EndProcedure

Procedure multiply(*self.MATRIXSTR, *matrix.MATRIXSTR)
  Define tempmatrix.MATRIXSTR
  
  traceFunction("multiply()")
  
  tempmatrix\value[#Xx] = (*self\value[0]  * *matrix\value[0])
  tempmatrix\value[#Xx] + (*self\value[4]  * *matrix\value[1])
  tempmatrix\value[#Xx] + (*self\value[8]  * *matrix\value[2])
  tempmatrix\value[#Xx] + (*self\value[12] * *matrix\value[3])
  
  tempmatrix\value[#Xy] = (*self\value[1]  * *matrix\value[0])
  tempmatrix\value[#Xy] + (*self\value[5]  * *matrix\value[1])
  tempmatrix\value[#Xy] + (*self\value[9]  * *matrix\value[2])
  tempmatrix\value[#Xy] + (*self\value[13] * *matrix\value[3])
  
  tempmatrix\value[#Xz] = (*self\value[2]  * *matrix\value[0])
  tempmatrix\value[#Xz] + (*self\value[6]  * *matrix\value[1])
  tempmatrix\value[#Xz] + (*self\value[10] * *matrix\value[2])
  tempmatrix\value[#Xz] + (*self\value[14] * *matrix\value[3])
  
  tempmatrix\value[#Xw] = (*self\value[3]  * *matrix\value[0])
  tempmatrix\value[#Xw] + (*self\value[7]  * *matrix\value[1])
  tempmatrix\value[#Xw] + (*self\value[11] * *matrix\value[2])
  tempmatrix\value[#Xw] + (*self\value[15] * *matrix\value[3])  
  
  tempmatrix\value[#Yx] = (*self\value[0]  * *matrix\value[4])
  tempmatrix\value[#Yx] + (*self\value[4]  * *matrix\value[5])
  tempmatrix\value[#Yx] + (*self\value[8]  * *matrix\value[6])
  tempmatrix\value[#Yx] + (*self\value[12] * *matrix\value[7])
  
  tempmatrix\value[#Yy] = (*self\value[1]  * *matrix\value[4])
  tempmatrix\value[#Yy] + (*self\value[5]  * *matrix\value[5])
  tempmatrix\value[#Yy] + (*self\value[9]  * *matrix\value[6])
  tempmatrix\value[#Yy] + (*self\value[13] * *matrix\value[7])
  
  tempmatrix\value[#Yz] = (*self\value[2]  * *matrix\value[4])
  tempmatrix\value[#Yz] + (*self\value[6]  * *matrix\value[5])
  tempmatrix\value[#Yz] + (*self\value[10] * *matrix\value[6])
  tempmatrix\value[#Yz] + (*self\value[14] * *matrix\value[7])
  
  tempmatrix\value[#Yw] = (*self\value[3]  * *matrix\value[4])
  tempmatrix\value[#Yw] + (*self\value[7]  * *matrix\value[5])
  tempmatrix\value[#Yw] + (*self\value[11] * *matrix\value[6])
  tempmatrix\value[#Yw] + (*self\value[15] * *matrix\value[7])  

  tempmatrix\value[#Zx] = (*self\value[0]  * *matrix\value[8])
  tempmatrix\value[#Zx] + (*self\value[4]  * *matrix\value[9])
  tempmatrix\value[#Zx] + (*self\value[8]  * *matrix\value[10])
  tempmatrix\value[#Zx] + (*self\value[12] * *matrix\value[11])
  
  tempmatrix\value[#Zy] = (*self\value[1]  * *matrix\value[8])
  tempmatrix\value[#Zy] + (*self\value[5]  * *matrix\value[9])
  tempmatrix\value[#Zy] + (*self\value[9]  * *matrix\value[10])
  tempmatrix\value[#Zy] + (*self\value[13] * *matrix\value[11])
  
  tempmatrix\value[#Zz] = (*self\value[2]  * *matrix\value[8])
  tempmatrix\value[#Zz] + (*self\value[6]  * *matrix\value[9])
  tempmatrix\value[#Zz] + (*self\value[10] * *matrix\value[10])
  tempmatrix\value[#Zz] + (*self\value[14] * *matrix\value[11])
  
  tempmatrix\value[#Zw] = (*self\value[3]  * *matrix\value[8])
  tempmatrix\value[#Zw] + (*self\value[7]  * *matrix\value[9])
  tempmatrix\value[#Zw] + (*self\value[11] * *matrix\value[10])
  tempmatrix\value[#zw] + (*self\value[15] * *matrix\value[11])
  
  tempmatrix\value[#Tx] = (*self\value[0]  * *matrix\value[12])
  tempmatrix\value[#Tx] + (*self\value[4]  * *matrix\value[13])
  tempmatrix\value[#Tx] + (*self\value[8]  * *matrix\value[14])
  tempmatrix\value[#Tx] + (*self\value[12] * *matrix\value[15])
  
  tempmatrix\value[#Ty] = (*self\value[1]  * *matrix\value[12])
  tempmatrix\value[#Ty] + (*self\value[5]  * *matrix\value[13])
  tempmatrix\value[#Ty] + (*self\value[9]  * *matrix\value[14])
  tempmatrix\value[#Ty] + (*self\value[13] * *matrix\value[15])
  
  tempmatrix\value[#Tz] = (*self\value[2]  * *matrix\value[12])
  tempmatrix\value[#Tz] + (*self\value[6]  * *matrix\value[13])
  tempmatrix\value[#Tz] + (*self\value[10] * *matrix\value[14])
  tempmatrix\value[#Tz] + (*self\value[14] * *matrix\value[15])
  
  tempmatrix\value[#Tw] = (*self\value[3]  * *matrix\value[12])
  tempmatrix\value[#Tw] + (*self\value[7]  * *matrix\value[13])
  tempmatrix\value[#Tw] + (*self\value[11] * *matrix\value[14])
  tempmatrix\value[#Tw] + (*self\value[15] * *matrix\value[15])
  
  CopyMemory(@tempmatrix\value[0], @*self\value[0], #MATRIX_SIZEBYTE)
EndProcedure

Procedure rotateX(*Self.MATRIXSTR, angledegree.f)
  Define tempmatrix.MATRIXSTR
  Define sine.f
  Define cosine.f
  
  traceFunction("rotateX()")
  
  angledegree = Radian(angledegree)
  sine = Sin(angledegree)
  cosine = Cos(angledegree)
  
  identity(tempmatrix)
  
  With tempmatrix
	  \value[#Yy] = cosine
	  \value[#Yz] = -sine
	  \value[#Zy] = sine
	  \value[#Zz] = cosine
	EndWith
	
	multiply(*self, tempmatrix)
EndProcedure

Procedure rotateY(*Self.MATRIXSTR, angledegree.f)
  Define tempmatrix.MATRIXSTR
  Define sine.f
  Define cosine.f
  
  traceFunction("rotateY()")
  
  angledegree = Radian(angledegree)
  sine = Sin(angledegree)
  cosine = Cos(angledegree)
  
  identity(tempmatrix)
  
  With tempmatrix
	  \value[#Xx] = cosine
	  \value[#Zx] = sine
	  \value[#Xz] = -sine
	  \value[#Zz] = cosine
	EndWith
	
	multiply(*self, tempmatrix)
EndProcedure

Procedure rotateZ(*Self.MATRIXSTR, angledegree.f)
  Define tempmatrix.MATRIXSTR
  Define sine.f
  Define cosine.f
  
  traceFunction("rotateZ()")
  
  angledegree = Radian(angledegree)
  sine = Sin(angledegree)
  cosine = Cos(angledegree)
  
  identity(tempmatrix)
  
  With tempmatrix
	  \value[#Xx] = cosine
	  \value[#Xy] = -sine
	  \value[#Yx] = sine
	  \value[#Yy] = cosine
	EndWith
	
	multiply(*self, tempmatrix)
EndProcedure

Procedure translate(*Self.MATRIXSTR, x.f, y.f, z.f)
  Define tempmatrix.MATRIXSTR

  traceFunction("translate()")
  
  identity(tempmatrix)
  
  With tempmatrix
	  \value[#Tx] = x
	  \value[#Ty] = y
	  \value[#Tz] = z
	EndWith

	multiply(*self, tempmatrix)
EndProcedure

Procedure perspective(*Self.MATRIXSTR, angle.f, near.f, far.f, aspect.f)
  Define y_scale.f
  Define x_scale.f
  Define frustum_length.f
  
  traceFunction("perspective()")
  
  y_scale = 1.0/Tan(Radian(angle/2))
  x_scale = y_scale/aspect
  frustum_length = (far-near)
  
  With *self
    \value[#Xx] = x_scale
    \value[#Yy] = y_scale
    \value[#Zz] = -( (near+far)/frustum_length )
    \value[#Zw] = -1
    \value[#Tz] = -( (2*near*far)/frustum_length )
    
    \value[#Xy] = 0
    \value[#Xz] = 0
    \value[#Xw] = 0
    \value[#Yx] = 0
    \value[#Yz] = 0
    \value[#Yw] = 0
    \value[#Zx] = 0
    \value[#Zy] = 0
    \value[#Tx] = 0
    \value[#Ty] = 0
    \value[#Tw] = 0
  EndWith
EndProcedure

Procedure orthogonal(*Self.MATRIXSTR, left.f, right.f, bottom.f, top.f, near.f, far.f)
  traceFunction("orthogonal()")
  
  With *Self
    \value[#Xx] = 2/(right-left)
    \value[#Yy] = 2/(top-bottom)
    \value[#Zz] = -2/(far-near)
    \value[#Tx] = -( (right+left)/(right-left) )
    \value[#Ty] = -( (top+bottom)/(top-bottom) )
    \value[#Tz] = -( (far+near)/(far-near) )
    \value[#Tw] = 1
    
    \value[#Xy] = 0
    \value[#Xz] = 0
    \value[#Xw] = 0
    \value[#Yx] = 0
    \value[#Yz] = 0
    \value[#Yw] = 0
    \value[#Zx] = 0
    \value[#Zy] = 0
  EndWith
EndProcedure

Procedure lookAt(*Self.MATRIXSTR, eyeX.f, eyeY.f, eyeZ.f, centerX.f, centerY.f, centerZ.f, upX.f, upY.f, upZ.f)
  Dim axe.f(2)
  Dim regard.f(2)
  Dim normal.f(2)
  Dim newaxe.f(2)
  Define tempmatrix.MATRIXSTR
  
  traceFunction("lookAt()")
  
  axe(0) = upX
  axe(1) = upY
  axe(2) = upZ
  regard(0) = centerX-eyeX
  regard(1) = centerY-eyeY
  regard(2) = centerZ-eyeZ
  
  crossProduct( regard(), axe(), normal() )
  crossProduct( normal(), regard(), newaxe() )
  
  normalize( normal() )
  normalize( newaxe() )
  normalize( regard() )
  
  With tempmatrix
    \value[#Xx] = normal(0)
    \value[#Xy] = newaxe(0)
    \value[#Xz] = -regard(0)
    \value[#Yx] = normal(1)
    \value[#Yy] = newaxe(1)
    \value[#Yz] = -regard(1)
    \value[#Zx] = normal(2)
    \value[#Zy] = newaxe(2)
    \value[#Zz] = -regard(2)
    \value[#Tw] = 1.0
  EndWith
  
  multiply(*self, tempmatrix)
  translate(*self, -eyeX, -eyeY, -eyeZ)
EndProcedure

Procedure push(*Self.MATRIXSTR)
  Define *tempstr.PARENTSTR = AllocateMemory( SizeOf(PARENTSTR) )
  
  traceFunction("push()")
  CopyMemory(@*Self\value[0], @*tempstr\value[0], #MATRIX_SIZEBYTE)
  
  If *Self\parent
    *tempstr\parent = *Self\parent
  EndIf
  
  *Self\parent = *tempstr
EndProcedure

Procedure pop(*Self.MATRIXSTR)
  Define *tempstr.PARENTSTR = *Self\parent
  
  traceFunction("pop()")
  
  If Not *Self\parent
    Debug "No matrix to restore"
    ProcedureReturn
  EndIf
  
  CopyMemory(@*tempstr\value[0], @*Self\value[0], #MATRIX_SIZEBYTE)
  
  If *tempstr\parent
    *Self\parent = *tempstr\parent
  Else
    *self\parent = #Null
  EndIf
  
  FreeMemory(*tempstr)
EndProcedure

Procedure destroy(*Self.MATRIXSTR)
  traceFunction("destroy()")
  FreeMemory(*self)
EndProcedure

Procedure.i createMatrix(label.s)
  Define *temp.MATRIXSTR
  
  traceFunction("createMatrix()")
    
  *temp.MATRIXSTR = AllocateMemory( SizeOf( MATRIXSTR ) )
  *temp\VTable = ?VTable
  *temp\label = label
  ProcedureReturn *temp
EndProcedure

DataSection
  VTable:
  Data.l @debugValues()
  Data.l @getAddress()
  Data.l @identity()
  Data.l @multiply()
  Data.l @rotateX()
  Data.l @rotateY()
  Data.l @rotateZ()
  Data.l @translate()
  Data.l @perspective()
  Data.l @orthogonal()
  Data.l @lookAt()
  Data.l @push()
  Data.l @pop()
  Data.l @destroy()
  
  MatrixIdentity:
  Data.f 1, 0, 0, 0
  Data.f 0, 1, 0, 0
  Data.f 0, 0, 1, 0
  Data.f 0, 0, 0, 1
EndDataSection
here is a example of use

Code: Select all

;-- example --
Define projection.MATRIX = CreateMatrix("projection")
Define modelview.MATRIX = CreateMatrix("modelview")

projection\identity()
modelview\identity()

projection\perspective(75, 1, 100, 800/600)
modelview\lookAt(5, 5, 5, 0, 0, 0, 0, 1, 0 )

projection\debugValues()
modelview\debugValues()

projection\destroy()

; projection\debugValues()  *** Will produce a crash because projection is no more ***
you can send your matrice to your shader with "getAddress()"

Code: Select all

glUniformMatrix4fv( glGetUniformLocation(programgl_id, "projection"), 1, #GL_FALSE, projection\getAddress() )
xorc1zt
Enthusiast
Enthusiast
Posts: 276
Joined: Sat Jul 09, 2011 7:57 am

Re: OpenGL Matrix

Post by xorc1zt »

added a stack with push() and pop() like opengl 1.1

Code: Select all

Procedure push(*Self.MATRIXSTR)
  Define *tempstr.PARENTSTR = AllocateMemory( SizeOf(PARENTSTR) )
 
  traceFunction("push()")
  CopyMemory(@*Self\value[0], @*tempstr\value[0], #MATRIX_SIZEBYTE)
 
  If *Self\parent
    *tempstr\parent = *Self\parent
  EndIf
 
  *Self\parent = *tempstr
EndProcedure

Procedure pop(*Self.MATRIXSTR)
  Define *tempstr.PARENTSTR = *Self\parent
 
  traceFunction("pop()")
 
  If Not *Self\parent
    Debug "No matrix to restore"
    ProcedureReturn
  EndIf
 
  CopyMemory(@*tempstr\value[0], @*Self\value[0], #MATRIX_SIZEBYTE)
 
  If *tempstr\parent
    *Self\parent = *tempstr\parent
  Else
    *self\parent = #Null
  EndIf
 
  FreeMemory(*tempstr)
EndProcedure
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: OpenGL Matrix

Post by luis »

Thanks for sharing it :)
"Have you tried turning it off and on again ?"
A little PureBasic review
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: OpenGL Matrix

Post by IdeasVacuum »

Excellent stuff - I think it really belongs in the Game Math post. :wink:
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Niffo
Enthusiast
Enthusiast
Posts: 500
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: OpenGL Matrix

Post by Niffo »

Thank you VERY much ! (6 years later ;) )
Niffo
Post Reply