' Updates:
' 26/01/07 - TDebug -> Info2
' 30/01/07 - TBlitz2D -> Text

Type TBlitz2D

	Function Text(x,y,text$)
	
		' reset texture matrix
		glMatrixMode(GL_TEXTURE)		
		glLoadIdentity()
			
		' set active texture to texture 0 so gldrawtext will work correctly
		glActiveTextureARB(GL_TEXTURE0)
		glClientActiveTextureARB(GL_TEXTURE0)
		
		' enable texture 2D
		glEnable(GL_TEXTURE_2D)
		
		glDisable(GL_LIGHTING)
		
		glColor3f(1.0,1.0,1.0)
		
		' enable blend to hide text background
		glEnable(GL_BLEND)
		
		GLDrawText text$,x,y
		
		glDisable(GL_BLEND)
		
		glEnable(GL_LIGHTING)
		
		' disable texture 2D - needed as gldrawtext enables it, but doesn't disable after use
		glDisable(GL_TEXTURE_2D)
		
	End Function
	
	Function MouseXSpeed()
		Global oldmx
		Local mxs=MouseX()-oldmx
		oldmx=MouseX()
		Return mxs
	End Function
	
	Function MouseYSpeed()
		Global oldmy
		Local mys=MouseY()-oldmy
		oldmy=MouseY()
		Return mys
	End Function
	
End Type

Type TUtility

	' MiniB3D functions
	
	' Extra - offers extra functionality that Blitz3D does not

	Function UpdateValue#(current#,destination#,rate#)
	
		'rate#=1.0/rate#
	
		current#=current#+((destination#-current#)*rate#)
	
		Return current#
	
	End Function

End Type

Type TDebug
	
	Global cno ' child no (< and > keys to cycle though child entities)
	Global Info=1 ' current info page (keys 1-9)
	Global bsphere=False ' show/hide bounding sphere (F1)
	
	' sphere used to represent entity bounding sphere
	Global sphere:TMesh

	' MiniB3D functions
	
	' Extra - offers extra functionality that Blitz3D does not

	Function DebugEntity(ent:TEntity,cam:TCamera=Null)

		If ent=Null Then Return

		Local no_children=0
		Local old_cent:TEntity=ent.GetChildFromAll(cno,no_children)
		If old_cent<>Null Then old_cent.EntityColor 255,255,255
	
		If KeyHit(KEY_PERIOD) Then cno=cno+1
		If KeyHit(KEY_COMMA) Then cno=cno-1
		Local no_childs=TEntity.CountAllChildren(ent)
		If cno<0 Then cno=0
		If cno>no_childs Then cno=no_childs

		no_children=0
		Local cent:TEntity=ent.GetChildFromAll(cno,no_children)
	
		If cent=Null Then cent=ent ' if no children entity then use main entity
		
		If cent<>Null
		
			cent.EntityColor 255,0,0
			TBlitz2D.Text 0,80,String(cno)+". "+cent.Name$+" ("+cent.class$+")"
		
			If KeyHit(KEY_1) Then Info=1
			If KeyHit(KEY_2) Then Info=2
			If KeyHit(KEY_3) Then Info=3
			If KeyHit(KEY_F1) Then bsphere=1-bsphere
			
			If Info=1 Then Info1(cent)
			If Info=2 Then Info2(cent)
			If Info=3 Then Info3(cent,cam)
			BoundingSphere(cent)

		EndIf
		
	End Function
	
	Function Info1(ent:TEntity)
	
		Local xx#=0

		xx#=ent.EntityX#(True)
		If xx#<0.0001 And xx#>-0.0001 Then xx#=0
		TBlitz2D.Text 0,120, "X (g): "+String(xx#)
		
		xx#=ent.EntityY#(True)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,140,"Y: "+String(xx#)
		
		xx#=ent.EntityZ#(True)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,160,"Z: "+String(xx#)
		
		xx#=ent.EntityPitch#(True)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,180,"Pitch: "+String(xx#)
		
		xx#=ent.EntityYaw#(True)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,200,"Yaw: "+String(xx#)
		
		xx#=ent.EntityRoll#(True)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,220,"Roll: "+String(xx#)

		xx#=ent.EntityX#(False)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,260,"X (l): "+String(xx#)
		
		xx#=ent.EntityY#(False)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,280,"Y: "+String(xx#)
		
		xx#=ent.EntityZ#(False)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,300,"Z: "+String(xx#)
		
		xx#=ent.EntityPitch#(False)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,320,"Pitch: "+String(xx#)
		
		xx#=ent.EntityYaw#(False)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,340,"Yaw: "+String(xx#)
		
		xx#=ent.EntityRoll#(False)
		If xx#<0.0001 And xx#>-0.0001  Then xx#=0
		TBlitz2D.Text 0,360,"Roll: "+String(xx#)
		
		Local tx=0
		Local ty=380
		For Local iy=0 To 3
			tx=0
			ty=ty+20
			For Local ix=0 To 3
				xx#=ent.mat.grid[ix,iy]
				If xx#<0.0001 And xx#>-0.0001 Then xx#=0
				TBlitz2D.Text tx,ty,String(xx#)
				tx=tx+100
			Next
		Next
	
	End Function
	
	Function Info2(ent:TEntity)
	
		If TMesh(ent)<>Null
	
			Local xx#=0
	
			xx#=TMesh(ent).CountSurfaces()
			TBlitz2D.Text 0,120, "Surfaces: "+String(xx#)
			
			xx#=TMesh(ent).CountVertices()
			TBlitz2D.Text 0,140,"Vertices: "+String(xx#)
			
			xx#=TMesh(ent).CountTriangles()
			TBlitz2D.Text 0,160,"Triangles: "+String(xx#)
			
			xx#=TMesh(ent).MeshWidth()
			TBlitz2D.Text 0,180,"Mesh Width: "+String(xx#)
			
			xx#=TMesh(ent).MeshWidth()
			TBlitz2D.Text 0,200,"Mesh Height: "+String(xx#)
			
			xx#=TMesh(ent).MeshWidth()
			TBlitz2D.Text 0,220,"Mesh Depth: "+String(xx#)
		
		Else
		
			TBlitz2D.Text 0,120, "Entity is not a mesh!"
		
		EndIf
				
	End Function
	
	Function Info3(ent:TEntity,cam:TCamera)
	
		If cam<>Null
		
			TBlitz2D.Text 0,120,"EntityInView: "+String(cam.EntityInView(ent))
		
		Else

			TBlitz2D.Text 0,120, "Camera entity not specified!"
		
		EndIf
	
	End Function
		
	Function BoundingSphere(ent:TEntity)
			
		If sphere=Null
			sphere=TMesh.CreateSphere(8)
		EndIf
			
		If bsphere=False
			sphere.HideEntity
			Return
		EndIf
		
		sphere.ShowEntity
		sphere.EntityAlpha .75
		sphere.EntityColor 255,255,0
			
		Local radius#=Abs(ent.cull_radius#) ' use absolute value as cull_radius will be negative value if set by MeshCullRadius (manual cull)
	
		' mesh centre
		Local x#=TMesh(ent).min_x
		Local y#=TMesh(ent).min_y
		Local 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
		TFormPoint x#,y#,z#,ent,Null
		x#=TFormedX#()
		y#=TFormedY#()
		z#=TFormedZ#()
		
		' 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
		
		PositionEntity sphere,x#,y#,z#,True
		ScaleEntity sphere,radius#,radius#,radius#
		
	End Function
	
End Type

Type DeltaTime

	Global DeltaTList:TList

	Field OldTime:Double
	Field ElapsedTime:Double
	Field Delta:Double
	Field dFps:Double
	Field dDelta:Double
	Field CurrFps:Double
	Field FPSCounter:Double
	Field CurrTime:Double
	Field CheckTime:Double
	
		Method New ()
            	If DeltaTList = Null Then DeltaTList = New TList
            	DeltaTList.AddLast Self
    	End Method		
		
		Method Destroy ()
            	DeltaTList.Remove Self
        End Method

	
		Function Create:DeltaTime(Fps:Double)
			Local dTime:DeltaTime = New DeltaTime
			dTime.Delta = 1
			dTime.dFps = Fps
			dTime.dDelta = 1000/Fps
			Return dTime
		End Function
		
		Function Update()
			Local dTime:DeltaTime
			For dTime:DeltaTime = EachIn DeltaTList
				dTime.CurrTime = MilliSecs()
				dTime.ElapsedTime = dTime.CurrTime - dTime.OldTime
				dTime.OldTime = dTime.CurrTime
				
				If dTime.CurrTime > dTime.CheckTime
					dTime.CheckTime = dTime.CurrTime + 1000
					dTime.CurrFps = dTime.FPSCounter
					dTime.FPSCounter = 0
				Else
					dTime.FPSCounter:+1
				EndIf
			Next
			
		End Function
		
		Function FPS(dTime:DeltaTime)
			Return dTime.CurrFps
		End Function
		
		Function CurrDelta:Double(dTime:DeltaTime)
			Return dTime.ElapsedTime/dTime.dDelta
		End Function
		
End Type
