Screen rotation

BlitzMax Forums/BlitzMax Programming/Screen rotation

This might be of use to somebody.
Although DX only I'm sure the OGL equivalent is very similar.
If anybody wants to clean it up, add to it or comment feel free.
I haven't put it in the Code Archives yet as I'm not too sure how much use it is in a real situation. I haven't put too much thought into it either.
Thanks to Noel for his Math3D lib in the Code Archives.
Import Brl.Math

Strict

Const RAD_TO_DEGREE! = 180!/Pi
Const DEGREE_TO_RAD! = Pi / 180!
Const gw:Float = 800.0
Const gh:Float=600.0
Graphics gw , gh
SetViewport -(gw/2),-(gh/2),gw*2,gh*2
Local depth:Float = 2.0
Local scale :Float = 1.0
Local angle:Float=5.0
Local image1:timage = LoadImage("ground.png")
Local image2:timage=LoadImage("max.png")
Local backup_matrix:matrix=matrix.create(2.0/gw,0.0,0.0,0.0,..
									0.0,( - 2.0 / gh) , 0.0 , 0.0 , ..
									0.0,0.0,(2.0/2.0),0.0,..
		 							 - 1.0 - (1.0 / gw) , 1.0 + (1.0 / gh) , 1.0 , 1.0)
Local world_matrix:matrix=matrix.create(2.0/gw,0.0,0.0,0.0,..
									0.0,( - 2.0 / gh) , 0.0 , 0.0 , ..
									0.0,0.0,(2.0/2.0),0.0,..
		 							 - 1.0 - (1.0 / gw) , 1.0 + (1.0 / gh) , 1.0 , 1.0)

Local transform_z_left:matrix = matrix.create(Cos(angle) , Sin(angle), 0.0 , 0.0 , ..
									-Sin(angle), Cos(angle), 0.0 , 0.0 , ..
									0.0 , 0.0 , 1.0 , 0.0 , .. 
									0.0 , 0.0 , 0.0 , 1.0)
									
Local transform_z_right:matrix = transform_z_left.transpose()
										
setmatrix(world_matrix)		
While Not KeyHit(KEY_ESCAPE)
	Cls
	If KeyDown(KEY_SPACE)
		world_matrix = backup_matrix
		SetScale 1.0,1.0
		setmatrix(world_matrix)
	EndIf
	TileImage image1 , 0 , 0
	DrawImage image2 , mousex(),mousey()
	If KeyDown(KEY_LEFT) 
		world_matrix = world_matrix.transformmat(transform_z_left) 
		setmatrix(world_matrix)
	EndIf
	If KeyDown(KEY_RIGHT)
		world_matrix = world_matrix.transformmat(transform_z_right) 
		setmatrix(world_matrix)
	EndIf
	If KeyDown(KEY_UP)
		SetScale 2.0 , 2.0
	EndIf
	If KeyDown(key_down)
		SetScale 0.5 , 0.5
	EndIf
	Flip
Wend

Function setmatrix(in:matrix)
		Local change_matrix:Float[]
		change_matrix=[in.m00,in.m01,in.m02,in.m03,in.m10,in.m11,in.m12,in.m13,in.m20,in.m21,in.m22,in.m23,in.m30,in.m31,in.m32,in.m33]
		D3D7GraphicsDriver().Direct3DDevice7().SetTransform(D3DTS_PROJECTION , change_matrix)
End Function

Function DegreeToRad:Float( d:Float )
	Return d*DEGREE_TO_RAD
End Function

Function RadToDegree!( r! )
	Return r*RAD_TO_DEGREE
End Function

' 4x4 Matrix
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
	Function Create:matrix(in00# , in01# , in02# , in03# , in10# , in11# , in12# , in13# , in20# , in21# , in22# , in23# , ..
		in30#,in31# , in32# , in33#)
		Local temp_matrix:matrix = New matrix
			temp_matrix.m00=in00
			temp_matrix.m01=in01
			temp_matrix.m02=in02
			temp_matrix.m03=in03
			temp_matrix.m10=in10
			temp_matrix.m11=in11
			temp_matrix.m12=in12
			temp_matrix.m13=in13
			temp_matrix.m20=in20
			temp_matrix.m21=in21
			temp_matrix.m22=in22
			temp_matrix.m23=in23
			temp_matrix.m30=in30
			temp_matrix.m31=in31
			temp_matrix.m32=in32
			temp_matrix.m33 = in33
		Return temp_matrix
	End Function
	
	Method Copy:Matrix( )
		Local i:Matrix = New Matrix
		MemCopy( Varptr i.m00, Varptr m00, 64 )
		Return i
	End Method
	
	Method Translate( x#, y#, z# )
		m03 = x
		m13 = y
		m23 = z
	End Method
	
	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
	
	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
		
	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
	
	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
	
	
	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
	
	Method GetPtr:Float Ptr( )
		Return Varptr m00
	End Method
	
	Method ToArray:Float[]( )
		Local r:Float[16]
		MemCopy( Varptr r[0], GetPtr( ), 64 )
		Return r
	End Method
	
	Function FromArray:Matrix( arr:Float[] )
		Return FromPtr( Varptr arr[0] )
	End Function
	
	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



<edit> The viewport and setscale could be slicker plus mouse movement would need adjusting. However, it's the screen rotation I was most interested in doing.

Wow this is pretty complicated, it's much easier in OpenGL ;-D

Cool tho.

Wow this is pretty complicated, it's much easier in OpenGL ;-D


That's good to hear. Can you add the Bmax GL driver version of the same thing to this post so it's in the same place?

Since I dont have DX/Windows I dont know exactly what your code is doing. Are you just trying to allow the game content to be displayed at like 90 degress so the user has to stand their monitor on its side in order to see a tall view of the game?

Wow! *very* nice one!

Thanks for sharing!

Since I dont have DX/Windows I dont know exactly what your code is doing

It's rotating the projection matrix so the viewed screen and anything drawn on it is rotated.

neat thanks! My screen must have non-square pixels even though I'm in 1024z768 as I'm sure it warps a bit as it spins.

... I think it does as well unless it's an optical illusion.

Ok.

Yes, if you rotate the general `orientation` of the display then you have to switch around your aspect ratio otherwise it will be out of proportion and you'll get the stretching that Grey Alien is seeing. So instead of doing like width/height you have to do height/width.

And you also should not rotate the projection matrix if you are using OpenGL - it will create texturing and lighting problems later. The texturing/lighting systems do not take into account the rotation or position of the camera. You should rotate or translate the MODELVIEW matrix instead. Move the game world in front of the camera, do not move the projection itself. The projection matrix is meant to ONLY be used to define the `projection` - the conversion of 3D coordinates to flat 2D coordinates.