CameraProjMode

BlitzMax Modules Forums/MiniB3D/CameraProjMode

Well nothing great, but a small addition to the functionset.
It enable the same cammodes as in b3d.

Replace the TCamera.bmx with this one :
Type TCamera Extends TEntity

	Global cam_list:TList=CreateList()

	Field vx,vy,vwidth,vheight
	Field cls_r#=0.0,cls_g#=0.0,cls_b#=0.0
	Field cls_color=True,cls_zbuffer=True
	
	Field range_near#=1.0,range_far#=1000.0
	Field zoom#=1.0
	
	Field fog_mode
	Field fog_r#,fog_g#,fog_b#
	Field fog_range_near#=1.0,fog_range_far#=1000.0
	
	' used by CameraProject
	Field mod_mat![16]
	Field proj_mat![16]
    Field viewport[4]
	Field mode:Int = 1
	Global projected_x#
	Global projected_y#
	Global projected_z#
	
	Field frustum#[6,4]

	Method New()
	
		If LOG_NEW
			DebugLog "New TCamera"
		EndIf
	
	End Method
	
	Method Delete()
	
		If LOG_DEL
			DebugLog "Del TCamera"
		EndIf
	
	End Method

	Method CopyEntity:TCamera(parent_ent:TEntity=Null)

		' new cam
		Local cam:TCamera=New TCamera
		
		' copy contents of child list before adding parent
		For Local ent:TEntity=EachIn child_list
			ent.CopyEntity(cam)
		Next
		
		' lists
		
		' add parent, add to list
		cam.AddParent(parent_ent:TEntity)
		cam.EntityListAdd(entity_list)
		
		' add to collision entity list
		If collision_type<>0
			TCollision.ent_lists[collision_type].AddLast(cam)
		EndIf
		
		' add to pick entity list
		If pick_mode<>0
			TPick.ent_list.AddLast(cam)
		EndIf
		
		' update matrix
		If cam.parent<>Null
			cam.mat.Overwrite(cam.parent.mat)
		Else
			cam.mat.LoadIdentity()
		EndIf
		
		' copy entity info
		
		cam.mat.Multiply(mat)
		
		cam.px#=px#
		cam.py#=py#
		cam.pz#=pz#
		cam.sx#=sx#
		cam.sy#=sy#
		cam.sz#=sz#
		cam.rx#=rx#
		cam.ry#=ry#
		cam.rz#=rz#
		cam.qw#=qw#
		cam.qx#=qx#
		cam.qy#=qy#
		cam.qz#=qz#

		cam.name$=name$
		cam.class$=class$
		cam.order=order
		cam.hidden=0'hidden
		cam.parent_hidden=0
			
		cam.cull_radius#=cull_radius#
		cam.radius_x#=radius_x#
		cam.radius_y#=radius_y#
		cam.box_x#=box_x#
		cam.box_y#=box_y#
		cam.box_z#=box_z#
		cam.box_w#=box_w#
		cam.box_h#=box_h#
		cam.box_d#=box_d#
		cam.pick_mode=pick_mode
		cam.obscurer=obscurer

		' copy camera info
		
		cam.EntityListAdd(cam_list) ' add new cam to global cam list
		
		cam.vx=vx
		cam.vy=vy
		cam.vwidth=vwidth
		cam.vheight=vheight
		cam.cls_r#=cls_r#
		cam.cls_g#=cls_g#
		cam.cls_b#=cls_b#
		cam.cls_color=cls_color
		cam.cls_zbuffer=cls_zbuffer
		cam.range_near#=range_near#
		cam.range_far#=range_far#
		cam.zoom#=zoom#
		cam.fog_mode=fog_mode
		cam.fog_r#=fog_r#
		cam.fog_g#=fog_g#
		cam.fog_b#=fog_b#
		cam.fog_range_near#=fog_range_near#
		cam.fog_range_far#=fog_range_far#

	End Method
	
	Method FreeEntity()
	
		Super.FreeEntity() 
		
		ListRemove cam_list,Self
		
	End Method

	Function CreateCamera:TCamera(parent_ent:TEntity=Null)

		Local cam:TCamera=New TCamera
		
		cam.CameraViewport(0,0,TGlobal.width,TGlobal.height)
		
		cam.class$="Camera"
		
		cam.AddParent(parent_ent:TEntity)
		cam.EntityListAdd(entity_list) ' add to entity list
		cam.EntityListAdd(cam_list) ' add to cam list
		
		' update matrix
		If cam.parent<>Null
			cam.mat.Overwrite(cam.parent.mat)
			cam.UpdateMat()
		Else
			cam.UpdateMat(True)
		EndIf

		Return cam

	End Function

	Method CameraViewport(x,y,w,h)

		vx=x
		vy=TGlobal.height-h-y
		vwidth=w
		vheight=h

	End Method
	
	Method CameraClsColor(r#,g#,b#)

		cls_r#=r#/255.0
		cls_g#=g#/255.0
		cls_b#=b#/255.0

	End Method
	
	Method CameraClsMode(color,zbuffer)

		cls_color=color
		cls_zbuffer=zbuffer
	
	End Method
	
	Method CameraRange(near#,far#)

		range_near#=near#
		range_far#=far#
	
	End Method
	
	Method CameraZoom(zoom_val#)

		zoom#=zoom_val#

	End Method
	
	' Calls function in TPick
	Method CameraPick:TEntity(x#,y#)
	
		Return TPick.CameraPick(Self,x#,y#)
	
	End Method
	
	Method CameraFogMode(mode)

		fog_mode=mode

	End Method
	
	Method CameraFogColor(r#,g#,b#)

		fog_r#=r#/255.0
		fog_g#=g#/255.0
		fog_b#=b#/255.0

	End Method
	
	Method CameraFogRange(near#,far#)

		fog_range_near#=near#
		fog_range_far#=far#
	
	End Method

    Method CameraProject(x#,y#,z#)

		Local px!
		Local py!
		Local pz!

        gluProject(x#,y#,-z#,mod_mat!,proj_mat!,viewport,Varptr px!,Varptr py!,Varptr pz!)

		projected_x#=-vx+Float(px!)
		projected_y#=vy+vheight-Float(py!)
		projected_z#=Float(pz!)

    End Method

	Method ProjectedX#()
	
		Return projected_x#
	
	End Method
	
	Method ProjectedY#()

		Return projected_y#
	
	End Method
	
	Method ProjectedZ#()
	
		Return projected_z#
	
	End Method

	Method EntityInView#(ent:TEntity)

		If TMesh(ent)<>Null

			' get new mesh bounds if necessary
			TMesh(ent).GetBounds()

		EndIf
		
		Return EntityInFrustum(ent)
		
	End Method
		
	Method ExtractFrustum()

		Local proj#[16]
		Local modl#[16]
		Local clip#[16]
		Local t#
		
		' Get the current PROJECTION matrix from OpenGL
		glGetFloatv( GL_PROJECTION_MATRIX, proj )
		
		' Get the current MODELVIEW matrix from OpenGL
		glGetFloatv( GL_MODELVIEW_MATRIX, modl )
		
		' Combine the two matrices (multiply projection by modelview)
		clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12]
		clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13]
		clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14]
		clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15]
		
		clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12]
		clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13]
		clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14]
		clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15]
		
		clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12]
		clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13]
		clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14]
		clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15]
		
		clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12]
		clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13]
		clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14]
		clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15]
		
		' Extract the numbers for the right plane
		frustum[0,0] = clip[ 3] - clip[ 0]
		frustum[0,1] = clip[ 7] - clip[ 4]
		frustum[0,2] = clip[11] - clip[ 8]
		frustum[0,3] = clip[15] - clip[12]
		
		' Normalize the result
		t = Sqr( frustum[0,0] * frustum[0,0] + frustum[0,1] * frustum[0,1] + frustum[0,2] * frustum[0,2] )
		frustum[0,0] :/ t
		frustum[0,1] :/ t
		frustum[0,2] :/ t
		frustum[0,3] :/ t
		
		' Extract the numbers for the left plane 
		frustum[1,0] = clip[ 3] + clip[ 0]
		frustum[1,1] = clip[ 7] + clip[ 4]
		frustum[1,2] = clip[11] + clip[ 8]
		frustum[1,3] = clip[15] + clip[12]
		
		' Normalize the result
		t = Sqr( frustum[1,0] * frustum[1,0] + frustum[1,1] * frustum[1,1] + frustum[1,2] * frustum[1,2] )
		frustum[1,0] :/ t
		frustum[1,1] :/ t
		frustum[1,2] :/ t
		frustum[1,3] :/ t
		
		' Extract the BOTTOM plane
		frustum[2,0] = clip[ 3] + clip[ 1]
		frustum[2,1] = clip[ 7] + clip[ 5]
		frustum[2,2] = clip[11] + clip[ 9]
		frustum[2,3] = clip[15] + clip[13]
		
		' Normalize the result
		t = Sqr( frustum[2,0] * frustum[2,0] + frustum[2,1] * frustum[2,1] + frustum[2,2] * frustum[2,2] )
		frustum[2,0] :/ t
		frustum[2,1] :/ t
		frustum[2,2] :/ t
		frustum[2,3] :/ t
		
		' Extract the TOP plane
		frustum[3,0] = clip[ 3] - clip[ 1]
		frustum[3,1] = clip[ 7] - clip[ 5]
		frustum[3,2] = clip[11] - clip[ 9]
		frustum[3,3] = clip[15] - clip[13]
		
		' Normalize the result
		t = Sqr( frustum[3,0] * frustum[3,0] + frustum[3,1] * frustum[3,1] + frustum[3,2] * frustum[3,2] )
		frustum[3,0] :/ t
		frustum[3,1] :/ t
		frustum[3,2] :/ t
		frustum[3,3] :/ t
		
		' Extract the FAR plane
		frustum[4,0] = clip[ 3] - clip[ 2]
		frustum[4,1] = clip[ 7] - clip[ 6]
		frustum[4,2] = clip[11] - clip[10]
		frustum[4,3] = clip[15] - clip[14]
		
		' Normalize the result
		t = Sqr( frustum[4,0] * frustum[4,0] + frustum[4,1] * frustum[4,1] + frustum[4,2] * frustum[4,2] )
		frustum[4,0] :/ t
		frustum[4,1] :/ t
		frustum[4,2] :/ t
		frustum[4,3] :/ t
		
		' Extract the NEAR plane
		frustum[5,0] = clip[ 3] + clip[ 2]
		frustum[5,1] = clip[ 7] + clip[ 6]
		frustum[5,2] = clip[11] + clip[10]
		frustum[5,3] = clip[15] + clip[14]

		' Normalize the result 
		t = Sqr( frustum[5,0] * frustum[5,0] + frustum[5,1] * frustum[5,1] + frustum[5,2] * frustum[5,2] )
		frustum[5,0] :/ t
		frustum[5,1] :/ t
		frustum[5,2] :/ t
		frustum[5,3] :/ t

	End Method

	Method EntityInFrustum#(ent:TEntity)
	
		Local x#=ent.EntityX#(True)
		Local y#=ent.EntityY#(True)
		Local z#=ent.EntityZ#(True)

		Local radius#=Abs(ent.cull_radius#) ' use absolute value as cull_radius will be negative value if set by MeshCullRadius (manual cull)

		' if entity is mesh, we need to use mesh centre for culling which may be different from entity position
		If TMesh(ent)
		
			' mesh centre
			x#=TMesh(ent).min_x
			y#=TMesh(ent).min_y
			z#=TMesh(ent).min_z
			x#=x#+(TMesh(ent).max_x-TMesh(ent).min_x)/2.0
			y#=y#+(TMesh(ent).max_y-TMesh(ent).min_y)/2.0
			z#=z#+(TMesh(ent).max_z-TMesh(ent).min_z)/2.0
			
			' transform mesh centre into world space
			TEntity.TFormPoint x#,y#,z#,ent,Null
			x#=tformed_x
			y#=tformed_y
			z#=tformed_z
			
			' radius - apply entity scale
			Local rx#=radius#*ent.EntityScaleX(True)
			Local ry#=radius#*ent.EntityScaleY(True)
			Local rz#=radius#*ent.EntityScaleZ(True)
			If rx#>=ry# And rx#>=rz#
				radius#=Abs(rx#)
			Else If ry#>=rx# And ry#>=rz#
				radius#=Abs(ry#)
			Else
				radius#=Abs(rz#)
			EndIf
		
		EndIf
		
		' is sphere in frustum

		Local d#
		For Local p=0 To 5
			d# = frustum[p,0] * x + frustum[p,1] * y + frustum[p,2] * -z + frustum[p,3]
			If d <= -radius Then Return 0
		Next
	
		Return d + radius
	
	End Method
	
	Rem
	Method SphereInFrustum#(x#,y#,z#,radius#)
	
		Local d#
	
		For Local p=0 To 5
	
			d# = frustum[p,0] * x + frustum[p,1] * y + frustum[p,2] * z + frustum[p,3]
	      
			If d <= -radius Then Return 0
	
		Next
	
		Return d + radius
	
	End Method
	End Rem
	
	' Helper funcs
	Rem	
	Method Update0()

		' viewport
		glViewport(vx,vy,vwidth,vheight)
		glScissor(vx,vy,vwidth,vheight)
		glClearColor(cls_r#,cls_g#,cls_b#,1.0)
		
		' clear buffers
		If cls_color=True And cls_zbuffer=True
			glDepthMask(GL_TRUE)
			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
		Else
			If cls_color=True
				glClear(GL_COLOR_BUFFER_BIT)
			Else
				If cls_zbuffer=True
					glDepthMask(GL_TRUE)
					glClear(GL_DEPTH_BUFFER_BIT)
				EndIf
			EndIf
		EndIf
		
		'fog
		If fog_mode>0
			glEnable(GL_FOG)
			glFogi(GL_FOG_MODE,GL_LINEAR)
			glFogf(GL_FOG_START,fog_range_near#)
			glFogf(GL_FOG_END,fog_range_far#)
			Local rgb#[]=[fog_r#,fog_g#,fog_b#]
			glFogfv(GL_FOG_COLOR,rgb#)
		Else
			glDisable(GL_FOG)
		EndIf
					
		glMatrixMode(GL_PROJECTION)
		glLoadIdentity()
		Local ratio#=(Float(vwidth)/vheight)
		gluPerspective(ATan((1.0/(zoom#*ratio#)))*2.0,ratio#,range_near#,range_far#)
				
		glMatrixMode(GL_MODELVIEW)
		
		Local new_mat:TMatrix=mat.Inverse()	
		glLoadMatrixf(new_mat.grid)

		' Get projection/model/viewport info - for use with CameraProject
		glGetDoublev(GL_MODELVIEW_MATRIX,Varptr mod_mat[0])
		glGetDoublev(GL_PROJECTION_MATRIX,Varptr proj_mat[0])
		glGetIntegerv(GL_VIEWPORT,Varptr viewport[0])
		
		ExtractFrustum()

	End Method
	End Rem

	Method Update()

		' viewport
		glViewport(vx,vy,vwidth,vheight)
		glScissor(vx,vy,vwidth,vheight)
		glClearColor(cls_r#,cls_g#,cls_b#,1.0)

		' clear buffers
		If cls_color=True And cls_zbuffer=True
			glDepthMask(GL_TRUE)
			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
		Else
			If cls_color=True
				glClear(GL_COLOR_BUFFER_BIT)
			Else
				If cls_zbuffer=True
					glDepthMask(GL_TRUE)
					glClear(GL_DEPTH_BUFFER_BIT)
				EndIf
			EndIf
		EndIf

		'fog
		If fog_mode>0
			glEnable(GL_FOG)
			glFogi(GL_FOG_MODE,GL_LINEAR)
			glFogf(GL_FOG_START,fog_range_near#)
			glFogf(GL_FOG_END,fog_range_far#)
			Local rgb#[]=[fog_r#,fog_g#,fog_b#]
			glFogfv(GL_FOG_COLOR,rgb#)
		Else
			glDisable(GL_FOG)
		EndIf

		Local ratio#=(Float(vwidth)/vheight)
		Local jx#=TGlobal.j[TGlobal.jitter,0]
		Local jy#=TGlobal.j[TGlobal.jitter,1]
		If TGlobal.aa=False Then jx#=0;jy#=0
		
		accPerspective(ATan((1.0/(zoom#*ratio#)))*2.0,ratio#,range_near#,range_far#,jx#,jy#,0.0,0.0,1.0)

		Local new_mat:TMatrix=mat.Inverse()	
		glLoadMatrixf(new_mat.grid)

		' Get projection/model/viewport info - for use with CameraProject
		glGetDoublev(GL_MODELVIEW_MATRIX,Varptr mod_mat[0])
		glGetDoublev(GL_PROJECTION_MATRIX,Varptr proj_mat[0])
		glGetIntegerv(GL_VIEWPORT,Varptr viewport[0])
		
		ExtractFrustum()
	
	End Method
	
	Method accPerspective(fovy#,aspect#,zNear#,zFar#,pixdx#,pixdy#,eyedx#,eyedy#,focus#)
	
		Local fov2#,left_#,right_#,bottom#,top#
		'fov2=((fovy*Pi)/180.0)/2.0
		fov2=fovy/2.0
		
		top=zNear/(Cos(fov2)/Sin(fov2))
		bottom=-top
		right_=top*aspect
		left_=-right_
	
		accFrustum(left_,right_,bottom,top,zNear,zFar,pixdx,pixdy,eyedx,eyedy,focus)
	
	End Method

	Method accFrustum(left_#,right_#,bottom#,top#,zNear#,zFar#,pixdx#,pixdy#,eyedx#,eyedy#,focus#)
	
		Local xwsize#,ywsize#
		Local dx#,dy#
		
		xwsize=right_-left_
		ywsize=top-bottom
		dx=-(pixdx*xwsize/Float(viewport[2])+eyedx*zNear/focus)
		dy=-(pixdy*ywsize/Float(viewport[3])+eyedy*zNear/focus)
		
		glMatrixMode(GL_PROJECTION)
		glLoadIdentity()
		'Local ratio#=(Float(vwidth)/vheight)
		'gluPerspective(ATan((1.0/(zoom#*ratio#)))*2.0,ratio#,range_near#,range_far#)
		If mode = 1 Then
			glFrustum(left_+dx,right_+dx,bottom+dy,top+dy,zNear,zFar)
		Else If mode = 2
			glOrtho(left_+dx,right_+dx,bottom+dy,top+dy,zNear,zFar)
		EndIf
		glMatrixMode(GL_MODELVIEW)
		glLoadIdentity()
		glTranslatef(-eyedx,-eyedy,0.0)
		
	End Method
	
	Method CameraProjMode(mode:Int = 1)
		Self.mode = mode
	End Method

End Type


And in functions.bmx under 'todo :
Replace the CameraProjMode Function ..
Function CameraProjMode(cam:TCamera,mode)
	Cam.CameraProjMode(mode)
End Function


And know the b3d manual sample translated to minib3d:

Import "minib3d.bmx"

Graphics3D 640,480
'SetBuffer BackBuffer()

camera:Tcamera=CreateCamera()
PositionEntity camera,0,0,-10

light=CreateLight()
RotateEntity light,0,0,0

'; Create cube 1, near To camera
cube1=CreateCube()
EntityColor cube1,255,0,0
PositionEntity cube1,0,0,0

'; Create cube 2, same size as cube 1 but further away
cube2=CreateCube()
EntityColor cube2,0,255,0
PositionEntity cube2,5,5,5
Local mode:Int = 0
While Not KeyDown(KEY_ESCAPE)

'; If spacebar pressed Then change mode value
If KeyHit(KEY_SPACE)=True Then mode=mode+1 ; If mode=3 Then mode=0

'; If mode value = 2 (orthagraphic), Then reduce zoom value To 0.1
If mode=2 Then zoom#=0.1 Else zoom#=1

'; Set camera projection mode using mode value
CameraProjMode camera,mode

'; Set camera zoom using zoom value
CameraZoom camera,zoom#

RenderWorld

Text 0,0,"Press spacebar to change the camera project mode"
Text 0,20,"CameraProjMode camera,"+mode
Text 0,40,"CameraZoom camera,"+zoom#

Flip

Cls

Wend

End 


Maybe its useful for people writing editors and the like.

thanks!!!!
I run to try it!

wow! works really good!! ty!
Hoping that Simon will include this function fix in next releases!

Cool! Tested it and it works fine with CameraPick, CameraProject etc which is what I was worried about.

I will indeed add this to the next release - thanks klepto.

Awesome snippet this, just want to say that this mod is great!