' Updates:
' 05/02/07 - AntiAlias added, RenderWorldAA added
' 05/02/07 - RenderWorld, Graphics3D

Type TGlobal

	Global width,height,mode,depth,rate
	Global ambient_red#=0.5,ambient_green#=0.5,ambient_blue#=0.5

	' anti aliasing globs
	Global aa ' anti_alias true/false
	Global ACSIZE ' accum size
	Global jitter
	Global j#[16 , 2]
	Global isWireframe:Byte = False
	Global FPSStatic:DeltaTime = DeltaTime.Create(60)
	Global ActiveShadow:Byte = False
	Global ShadowMode:Int = 0
	Global ShadowRender:Int = 0 'SetTo ZPass 1 = ZFail
	Global StencilBits:Int
	Global midStencilVal:Int
	Global RenderedTris:Int = 0


	Function Graphics3D(w,h,d=0,m=0,r=60)
	
		width=w
		height=h
		depth=d
		mode=m
		rate=r
		
		If mode<>1 Then depth=0
		
		SetGraphicsDriver(GLMax2DDriver()) 
		Graphics(width,height,depth,rate,GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER|GRAPHICS_ACCUMBUFFER|GRAPHICS_STENCILBUFFER)

		GraphicsInit()
		
		THardwareInfo.GetInfo()
		
		glGetIntegerv(GL_STENCIL_BITS, Varptr stencilBits);
		If Not stencilBits Then
			Print("No stencil buffer - no shadows");
		EndIf
		midStencilVal = Int(2^(Int(stencilBits) - 1))
		glClearStencil(midStencilVal)

						
	End Function
	
	Function CanvasGraphics3D(Canvas:TGadget)
	
		SetGraphicsDriver GLMax2DDriver() ,GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER|GRAPHICS_STENCILBUFFER|GRAPHICS_ACCUMBUFFER
		
		TGlobal.width = Canvas.ClientWidth()
		TGlobal.height = Canvas.ClientHeight()
		TGlobal.depth=16
		TGlobal.mode=0
		TGlobal.rate = 60
		
		SetGraphics CanvasGraphics( canvas )
		
		GraphicsInit()
		THardwareInfo.GetInfo()
		
				
		glGetIntegerv(GL_STENCIL_BITS, Varptr stencilBits);
		If Not stencilBits Then
			Print("No stencil buffer - no shadows");
		EndIf
		midStencilVal = Int(2^(Int(stencilBits) - 1))
		glClearStencil(midStencilVal)
		
		'Print "MidSTVAL : " + midStencilVal
				
	End Function
	
	Function UpdateCanvas3D(Canvas:TGadget)
		TGlobal.width = Canvas.ClientWidth()
		TGlobal.height = Canvas.ClientHeight()
	End Function



	Function AntiAlias(samples)

		aa=True

		If samples=False Then aa=0;Return
		
		Select samples
			Case 1 RestoreData j2; ACSIZE=2
			Case 2 RestoreData j2; ACSIZE=2
			Case 3 RestoreData j3; ACSIZE=3
			Case 4 RestoreData j4; ACSIZE=4
			Case 5 RestoreData j5; ACSIZE=5
			Case 6 RestoreData j6; ACSIZE=6
			Case 8 RestoreData j8; ACSIZE=8
			Case 9 RestoreData j9; ACSIZE=9
			Case 12 RestoreData j12; ACSIZE=12
			Case 16 RestoreData j16; ACSIZE=16
			Default aa=False; ACSIZE=0; Return
		End Select

		For Local i=0 Until samples
		
			ReadData j[i,0],j[i,1]
		
		Next

	End Function
	
	Function Wireframe(enable)
	
		If enable
			glPolygonMode(GL_FRONT , GL_LINE)
			isWireframe = True
		Else
			glPolygonMode(GL_FRONT , GL_FILL)
			isWireframe = False
		EndIf

	End Function
	
	Function AmbientLight(r#,g#,b#)
	
		ambient_red#=r#/255.0
		ambient_green#=g#/255.0
		ambient_blue#=b#/255.0
	
	End Function
	
	Function ClearCollisions()
	
		ClearList(TCollision.List)
	
	End Function

	Function Collisions(src_no,dest_no,method_no,response_no=0)
	
		' method -
		' 1: dynamic sphere to dynamic sphere
		' 2: dynamic ellipsoid to static mesh (will handle all combinations of rotated entity and scaled ellipsoid - slower than method 4)
		' 3: ellipsoid to box (unavailable)
		' 4: dynamic ellipsoid to static mesh (limited ellipsoid - max one axis of rotation for source entity, max one axis of non-uniform scaling for ellipsoid, both axis must match.)

		' response - (not yet selectable - responses are 'pass-through' for sphere to sphere, 'slide' for sphere to polygon)
	
		Local col:TCollision=New TCollision
		col.src_type=src_no
		col.des_type=dest_no
		col.col_method=method_no
		col.response=response_no
		ListAddLast(TCollision.List,col)
	
	End Function
		
	Function UpdateWorld(anim_speed#=1.0)
		
		' collision
		
		TCollision.UpdateCollisions()
		
		' anim
	
		Local first
		Local last

		For Local mesh:TEntity=EachIn TEntity.entity_list
		
			If Mesh.ismd2 = False 
				If mesh.anim And mesh.anim_update=True
				
					First=mesh.anim_seqs_first[mesh.anim_seq]
					Last=mesh.anim_seqs_last[mesh.anim_seq]
			
					Local anim_start=False
	
					If mesh.anim_trans>0
						mesh.anim_trans=mesh.anim_trans-1
						If mesh.anim_trans=1 Then anim_start=True
					EndIf
					
					If mesh.anim_trans>0
					
						Local r#=1.0-mesh.anim_time#
						r#=r#/mesh.anim_trans
						mesh.anim_time#=mesh.anim_time+r#
										
						TAnimation.AnimateMesh2(mesh,mesh.anim_time#,First,Last)
						
												
						If anim_start=True Then mesh.anim_time#=First
				
					Else
					
						TAnimation.AnimateMesh(mesh,mesh.anim_time#,First,Last)
						
						
						If mesh.anim_mode=0 Then mesh.anim_update=False ' after updating animation so that animation is in final 'stop' pose - don't update again
			
						If mesh.anim_mode=1
				
							mesh.anim_time#=mesh.anim_time#+(mesh.anim_speed#*anim_speed#)
							If mesh.anim_time#>Last
								mesh.anim_time#=First+(mesh.anim_time#-Last)
							EndIf
						
						EndIf
						
						If mesh.anim_mode=2
						
							If mesh.anim_dir=1
								mesh.anim_time#=mesh.anim_time#+(mesh.anim_speed#*anim_speed#)
								If mesh.anim_time#>Last
									mesh.anim_time#=mesh.anim_time#-(mesh.anim_speed#*anim_speed#)
									mesh.anim_dir=-1
								EndIf
							EndIf
							
							If mesh.anim_dir=-1
								mesh.anim_time#=mesh.anim_time#-(mesh.anim_speed#*anim_speed#)
								If mesh.anim_time#<First
									mesh.anim_time#=mesh.anim_time#+(mesh.anim_speed#*anim_speed#)
									mesh.anim_dir=1
								EndIf
							EndIf
						
						EndIf
						
						If mesh.anim_mode=3
				
							mesh.anim_time#=mesh.anim_time#+(mesh.anim_speed#*anim_speed#)
							If mesh.anim_time#>Last
								mesh.anim_time#=Last
								mesh.anim_mode=0
							EndIf
						
						EndIf
						
					EndIf
								
				EndIf
			Else
				If mesh.md2_anim = True Then
					If mesh.md2_mode = 0 Then
						TMesh(mesh).SetMD2Frame()
					EndIf
					If mesh.md2_mode = 1 Then
						mesh.md2_time:+ mesh.md2_speed
						If mesh.md2_time > mesh.md2_end Then 
							mesh.md2_time = mesh.md2_start
						EndIf
						TMesh(mesh).SetMD2Frame()
					EndIf
					If mesh.md2_mode = 2 Then
						mesh.md2_time:+ mesh.md2_speed
						If mesh.md2_time > mesh.md2_end Or mesh.md2_time < mesh.md2_start Then 
							'mesh.md2_time = mesh.md2_start
							mesh.md2_Speed:*-1
						EndIf
						TMesh(mesh).SetMD2Frame()
					EndIf
					If mesh.md2_mode = 3 Then
						mesh.md2_time:+ mesh.md2_speed
						If mesh.md2_time > mesh.md2_end Then 
							mesh.md2_anim = False
						EndIf
						TMesh(mesh).SetMD2Frame()
					EndIf
				EndIf

			EndIf
		Next
	
		FPSStatic.Update()
	
	End Function
	
	Function GetFPS:Double()
		Return DeltaTime.FPS(FPSStatic)
	End Function
	
	Function GetDelta:Double()
		Return DeltaTime.CurrDelta(FPSStatic)
	End Function
	
	Function SetDeltaFPS(FPS:Int = 60)
		FPSStatic = DeltaTime.Create(FPS) 
	End Function
	
	Function TrisRendered:Int()
		Return RenderedTris
	End Function

	Function RenderWorld()
			
		' if anti-aliasing enabled then call RenderWorldAA
		If aa Then RenderWorldAA() ; Return
		
		
		RenderedTris:Int = 0
		
		glDisable(GL_TEXTURE_CUBE_MAP)
		glDisable(GL_TEXTURE_GEN_S)
		glDisable(GL_TEXTURE_GEN_T)
		glDisable(GL_TEXTURE_GEN_R)
	
		glDisable(GL_TEXTURE_2D)

		TGlobal.EnableStates()
	

		For Local cam:TCamera=EachIn TCamera.cam_list

			If cam.EntityHidden()=True Then Continue

			RenderCamera(cam)

		Next
		
		Local x,y,w,h
		GetViewport(x,y,w,h)
		
		glDisable(GL_LIGHTING)
		glDisable(GL_DEPTH_TEST)
		glDisable(GL_SCISSOR_TEST)
		glDisable(GL_FOG)
		glDisable(GL_CULL_FACE)

		glMatrixMode GL_TEXTURE
		glLoadIdentity
		
		glMatrixMode GL_PROJECTION
		glLoadIdentity
		glOrtho 0,GraphicsWidth(),GraphicsHeight(),0,-1,1
		
		glMatrixMode GL_MODELVIEW
		glLoadIdentity
		
		SetViewport x,y,w,h
		
		
		Local MaxTex:Int 
		glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))

		
		For Local Layer = 0 Until MaxTex
			glActiveTexture(GL_TEXTURE0+Layer)
					
			glDisable(GL_TEXTURE_CUBE_MAP)
			glDisable(GL_TEXTURE_GEN_S)
			glDisable(GL_TEXTURE_GEN_T)
			glDisable(GL_TEXTURE_GEN_R)
	
			glDisable(GL_TEXTURE_2D)
		Next
		
		glActiveTexture(GL_TEXTURE0)
		
		DrawRect - 10 , - 10 , 5 , 5
		
		glViewport(0,0,TGlobal.Width,TGlobal.Height)
		glScissor(0,0,TGlobal.Width,TGlobal.Height)
		
	End Function
	
	' Same as RenderWorld but with anti-aliasing
	Function RenderWorldAA()
	
		glClear(GL_ACCUM_BUFFER_BIT)
		
		
		RenderedTris:Int = 0
		
		glDisable(GL_TEXTURE_CUBE_MAP)
		glDisable(GL_TEXTURE_GEN_S)
		glDisable(GL_TEXTURE_GEN_T)
		glDisable(GL_TEXTURE_GEN_R)
	
		glDisable(GL_TEXTURE_2D)

		TGlobal.EnableStates()
	
	
		For jitter=0 Until ACSIZE
				
			For Local cam:TCamera=EachIn TCamera.cam_list
	
				If cam.EntityHidden()=True Then Continue
	
				RenderCamera(cam)
	
			Next
			
			glAccum(GL_ACCUM,1.0/ACSIZE)
	
		Next
		
		
		Local x,y,w,h
		GetViewport(x,y,w,h)
		
		glDisable(GL_LIGHTING)
		glDisable(GL_DEPTH_TEST)
		glDisable(GL_SCISSOR_TEST)
		glDisable(GL_FOG)
		glDisable(GL_CULL_FACE)

		glMatrixMode GL_TEXTURE
		glLoadIdentity
		
		glMatrixMode GL_PROJECTION
		glLoadIdentity
		glOrtho 0,GraphicsWidth(),GraphicsHeight(),0,-1,1
		
		glMatrixMode GL_MODELVIEW
		glLoadIdentity
		
		SetViewport x,y,w,h
		
		
		Local MaxTex:Int 
		glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))

		
		For Local Layer = 0 Until MaxTex
			glActiveTexture(GL_TEXTURE0+Layer)
					
			glDisable(GL_TEXTURE_CUBE_MAP)
			glDisable(GL_TEXTURE_GEN_S)
			glDisable(GL_TEXTURE_GEN_T)
			glDisable(GL_TEXTURE_GEN_R)
	
			glDisable(GL_TEXTURE_2D)
		Next
		
		glActiveTexture(GL_TEXTURE0)
		
		DrawRect -10,-10,5,5

		jitter=0
			
		glAccum(GL_RETURN,1.0)
		glFlush()
	
	End Function

	' MiniB3D functions

	' Extra - offers extra functionality that Blitz3D does not
	
	' Render camera - renders all meshes camera can see
	Function RenderCamera(cam:TCamera)
		
		If TGlobal.ActiveShadow = True 	Then
			DrawShadowShadowScene(cam)
			Return
		EndIf
		
		cam.Update()
	
		For Local light:TLight=EachIn TLight.light_list
	
			light.Update() ' EntityHidden code inside Update
			
		Next

		Local render_list:TList=CreateList:TList()
		
		For Local mesh:TMesh=EachIn TEntity.entity_list
		
			If mesh.EntityHidden()=True Then Continue
	
			' get new bounds
			mesh.GetBounds()
	
			' Perform frustum cull
			
			Local inview=cam.EntityInFrustum(mesh)

			If inview
			
				If mesh.auto_fade = True Then 
					AutoFade(cam , mesh)
					If mesh.Brush.Alpha - mesh.fade_alpha < 0.0001 Then 
						Continue
					EndIf
				EndIf
			
				If mesh.Alpha()
			
					mesh.alpha_order#=cam.EntityDistanceSquared#(mesh)
				
				Else
				
					mesh.alpha_order#=0.0
				
				EndIf
				If mesh.Name <> "Shadow" Then 
					RenderListAdd(mesh , render_list)
				EndIf				
			EndIf
	
		Next

		UpdateSprites(cam,render_list) ' rotate sprites with respect to current cam
		
	
		' Draw everything in render list
		For Local mesh2:TMesh=EachIn render_list
		
			mesh2.Update()
	
		Next
		
		If TGlobal.ActiveShadow = True And TGlobal.ShadowMode = 1
			For Local light:TLight = EachIn TLight.light_list
				EntityFX(light.Shadows.ShadowMesh,17)
				EntityFX(light.Shadows.VolumeCap,17)

				light.Shadows.ShadowMesh.Update()
				light.Shadows.VolumeCap.Update()
				
				EntityFX(light.Shadows.ShadowMesh,1)
				EntityFX(light.Shadows.VolumeCap,1)

			Next
		EndIf	
		
		
		If TPhysic.Debug = True Then
			glDisable (GL_LIGHTING)
			glDisable(GL_TEXTURE_2D)
			glLineWidth(2.0)
			glBegin(GL_LINES)
			glColor3f(1.0, 1.0, 0.0)
			NewtonWorldForEachBodyDo(TPhysic.World, RenderBodyCollision)
			glColor3f(1.0, 1.0, 1.0)
			glEnd
			glLineWidth(1.0)
		EndIf
		

	End Function
	
	Function RenderShadowToStencil_ZPASS() 
		
	glClearStencil(midStencilVal)
	glClear(GL_STENCIL_BUFFER_BIT)

	'Disable drawing To colour buffer, lighting And don't update depth buffer 
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
	glDisable(GL_LIGHTING)
	glDepthMask(GL_FALSE)

	'Z-pass approach 
	glStencilFunc(GL_ALWAYS, MidStencilVal, $ffffff)

	glCullFace(GL_FRONT)
	glStencilOp(GL_KEEP , GL_KEEP , GL_INCR)
			
		
	If TGlobal.ActiveShadow = True 		
			'DebugStop()	
			For Local light:TLight = EachIn TLight.light_list
				'If ShadowShader = Null Then 
				If light.shadows <> Null Then
				light.Shadows.ShadowMesh.ShadowUpdate()
				'light.Shadows.VolumeCap.ShadowUpdate()
				For Local M:TMesh = EachIn light.Shadows.animVolume
						M.Update()
				Next
			EndIf
			Rem
			Else
				ShadowShader.Activate()
				ShadowShader.SetUF3("uLightPos" , EntityX(Light) , EntityY(Light) , EntityZ(Light) )
				If light.Shadows <> Null Then 
				For Local M:TMesh = EachIn light.Shadows.Entity_List
						M.ShadowUpdate()
				Next
				EndIf
				ShadowShader.DeActivate()
			EndIf
			End Rem
		Next
	EndIf


	glCullFace(GL_BACK)
	glStencilOp(GL_KEEP , GL_KEEP , GL_DECR)
			
	If TGlobal.ActiveShadow = True 			
		For Local light:TLight = EachIn TLight.light_list
			'If ShadowShader = Null Then 
				If light.shadows <> Null Then
				light.Shadows.ShadowMesh.ShadowUpdate()
				'light.Shadows.VolumeCap.ShadowUpdate()
				For Local M:TMesh = EachIn light.Shadows.animVolume
						M.Update()
				Next
				EndIf
			Rem
			Else
				ShadowShader.Activate()
				ShadowShader.SetUF3("uLightPos" , EntityX(Light) , EntityY(Light) , EntityZ(Light) )
	
			If light.Shadows <> Null Then 

				For Local M:TMesh = EachIn light.Shadows.Entity_List
						M.ShadowUpdate()
				Next
			EndIf
				ShadowShader.DeActivate()
			EndIf
			End Rem
		
		Next
	EndIf


	'Enable colour buffer, lighting And depth buffer
	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
	glEnable(GL_LIGHTING)
	glDepthMask(GL_TRUE)
	'glDisable(GL_DEPTH_CLAMP_NV)	
	
	End Function
	
	Function RenderShadowToStencil_ZFAIL()
		
	
	glClearStencil(midStencilVal)
	glClear(GL_STENCIL_BUFFER_BIT)
	
	glDepthMask(GL_FALSE)
	glEnable(GL_STENCIL_TEST)
						
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
	glStencilFunc(GL_ALWAYS , midStencilVal, midStencilVal)
	glDepthFunc(GL_LEQUAL)
	
	glEnable(GL_CULL_FACE)
	'glFrontFace(GL_CCW)
		
	glCullFace(GL_BACK)
	glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP)				
		
	If TGlobal.ActiveShadow = True 			
			For Local light:TLight = EachIn TLight.light_list
				'If ShadowShader = Null Then 
					If light.shadows <> Null Then

					light.Shadows.ShadowMesh.ShadowUpdate()
					light.Shadows.VolumeCap.ShadowUpdate()
					For Local M:TMesh = EachIn light.Shadows.animVolume
							M.ShadowUpdate()
					Next
					
					EndIf
				Rem
				Else
					ShadowShader.Activate()
					ShadowShader.SetUF3("uLightPos" , EntityX(Light) , EntityY(Light) , EntityZ(Light) )
					If light.Shadows <> Null Then 
					For Local M:TMesh = EachIn light.Shadows.Entity_List
							M.ShadowUpdate()
					Next
					EndIf
					ShadowShader.DeActivate()
				EndIf
				End Rem

			Next
	EndIf
	
	glCullFace(GL_FRONT)
	glStencilOp(GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP)
				
	If TGlobal.ActiveShadow = True 			
		For Local light:TLight = EachIn TLight.light_list
			'If ShadowShader = Null Then 
				If light.shadows <> Null Then

				light.Shadows.ShadowMesh.ShadowUpdate()
				light.Shadows.VolumeCap.ShadowUpdate()
				For Local M:TMesh = EachIn light.Shadows.animVolume
						M.ShadowUpdate()
				Next
				
				EndIf
			Rem
			Else
				ShadowShader.Activate()
				ShadowShader.SetUF3("uLightPos" , EntityX(Light) , EntityY(Light) , EntityZ(Light) )
				If light.Shadows <> Null Then 
				For Local M:TMesh = EachIn light.Shadows.Entity_List
						M.ShadowUpdate()
				Next
				EndIf
				ShadowShader.DeActivate()
			EndIf

			End Rem
		Next
	EndIf
	
	glDisable(GL_CULL_FACE)
	glDepthFunc(GL_LESS)
	If TGLobal.ShadowMode = 1 Then
		glStencilFunc(GL_NOTEQUAL , midStencilVal, $FFFFFFFF)
	Else
		glStencilFunc(GL_EQUAL , midStencilVal, $FFFFFFFF)
	EndIf

	'glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
	glStencilOp(GL_ZERO , GL_KEEP , GL_KEEP)
	
	
	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
	glEnable(GL_LIGHTING)
	glDepthMask(GL_TRUE)


	End Function


	' Internal - not recommended for general use
	
	Function AutoFade(cam:TCamera,mesh:TMesh)

		Local dist#=cam.EntityDistance#(mesh)
		
		If dist>mesh.fade_near And dist<mesh.fade_far
		
			' fade_alpha will be in the range 0 (near) to 1 (far)
			mesh.fade_alpha=(dist-mesh.fade_near)/(mesh.fade_far-mesh.fade_near)
	
		Else
		
			' if entity outside near, far range then set min/max values
			If dist<mesh.fade_near Then mesh.fade_alpha#=0.0 Else mesh.fade_alpha#=1.0
			
		EndIf

	End Function

	Function GraphicsInit()
	
		TTexture.TextureFilter("",9)
	
		glewInit() ' required for glActiveTextureARB

		EnableStates()
		
		glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
		glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)

		glClearDepth(1.0)						
		glDepthFunc(GL_LEQUAL)
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)

		glAlphaFunc(GL_GEQUAL,0.5)

	End Function
	
	Function EnableStates()
	
		glEnable(GL_LIGHTING)
   		glEnable(GL_DEPTH_TEST)
		glEnable(GL_FOG)
		glEnable(GL_CULL_FACE)
		glEnable(GL_SCISSOR_TEST)
		
		glEnable(GL_NORMALIZE)
		
		glEnableClientState(GL_VERTEX_ARRAY)
		glEnableClientState(GL_COLOR_ARRAY)
		glEnableClientState(GL_NORMAL_ARRAY)
	
	End Function
	
	' Adds mesh to a render list, and inserts mesh into correct position within list depending on order and alpha values
	Function RenderListAdd(mesh:TMesh,List:TList)
	
		' if order>0, drawn first (will appear at back of scene)
		' if order<0, drawn last (will appear at front of scene)
	
		Local llink:TLink=List._head ' get start/end link (llink = local link, so as not to clash with entity's link var)
	
		If mesh.order>0

			' *** add first ***
		
			' add entity to start of list
			' entites with order>0 should be added to the start of the list
		
			' cycle fowards through list until we've passed all entities with order>0, or if entity itself has order>0,
			' it's own position within entities with order>0
			Repeat
				llink=llink._succ
			Until llink=List._head Or TEntity(llink.Value()).order<=mesh.order
	
			List.InsertBeforeLink(mesh,llink)
			Return
	
		Else If mesh.order<0 ' put entities with order<0 at back of list

			' *** add last ***
	
			' add entity to end of list
			' only entites with order<=0 should be added to the end of the list
		
			' cycle backwards through list until we've passed all entities with order<0, or if entity itself has order<0,
			' it's own position within entities with order<0
			Repeat
				llink=llink._pred
			Until llink=List._head Or TEntity(llink.Value()).order>=mesh.order
	
			List.InsertAfterLink(mesh,llink)
			Return

		EndIf
		
		' order=0
		
		If mesh.alpha_order#>0.0
		
			' add alpha entities to near end of list - before entities with order<0

			Repeat
				llink=llink._pred
				If llink=List._head Then Exit
			Until TEntity(llink.Value()).order>=0 And (TEntity(llink.Value()).alpha_order>=mesh.alpha_order Or TEntity(llink.Value()).alpha_order=0.0)

			List.InsertAfterLink(mesh,llink)
			Return
		
		Else
			
			' normal entities - add to list at start - after entities with order>0
		
			Repeat
				llink=llink._succ
			Until llink=List._head Or TEntity(llink.Value()).order<=0

			List.InsertBeforeLink(mesh,llink)
			Return
			
		EndIf
		
	End Function
	
	Function UpdateSprites(cam:TCamera,List:TList)
		
		Local rot_x#,rot_y#,rot_z#
		Local scale_x#,scale_y#
		
		For Local sprite:TSprite=EachIn List
		
			' fixed, upright1 and upright2 modes
			If sprite.view_mode<>2

				Select sprite.view_mode
					Case 1
						rot_x#=cam.EntityPitch(True)
						rot_y#=cam.EntityYaw(True)
						rot_z#=0
					Case 3
						rot_x#=cam.EntityPitch(True)
						rot_y#=cam.EntityYaw(True)
						rot_z#=cam.EntityRoll(True)
					Case 4
						rot_x#=0
						rot_y#=cam.EntityYaw(True)
						rot_z#=cam.EntityRoll(True)
				End Select
				
				scale_x#=sprite.scale_x#
				scale_y#=sprite.scale_y#
			
				If sprite.parent<>Null
				
					rot_x#=rot_x#-sprite.parent.EntityPitch(True)
					rot_y#=rot_y#-sprite.parent.EntityYaw(True)
					rot_z#=0
					
					scale_x#=scale_x#/sprite.EntityScaleX#(True)
					scale_y#=scale_y#/sprite.EntityScaleY#(True)
				
					sprite.mat_sp.Overwrite(sprite.parent.mat)
					
				Else
				
					sprite.mat_sp.LoadIdentity()
					
				EndIf
				
				sprite.mat_sp.Translate(sprite.px,sprite.py,sprite.pz)																																																																																																																																																																																																																																																																																																																																										
				sprite.mat_sp.RotateYaw(rot_y)
				sprite.mat_sp.RotatePitch(-rot_x)
				sprite.mat_sp.RotateRoll(rot_z+sprite.angle#)
				sprite.mat_sp.Scale(scale_x#,scale_y#,1.0)
				sprite.mat_sp.Translate(-sprite.handle_x#,-sprite.handle_y#,0.0)
				
			EndIf
		
			' free mode
			If sprite.view_mode=2
				sprite.mat_sp.Overwrite(sprite.mat)
			EndIf
	
		Next
	
	End Function
	
	Function DrawShadowShadowScene(cam:TCamera)
					
		cam.Update()
		
		For Local light:TLight=EachIn TLight.light_list
			If TGlobal.ShadowMode = 2 Then light.HideEntity()
			light.Update() ' EntityHidden code inside Update
			light.UpdateVolumes()
		Next
		

		Local render_list:TList = CreateList:TList()
				
		For Local mesh:TMesh = EachIn TEntity.entity_list
		
			If mesh.EntityHidden() = True Then Continue
			
				
			' get new mesh bounds if necessary
			mesh.GetBounds()
	
			' Perform frustum cull
			
			Local inview=cam.EntityInFrustum(mesh)

			If inview
			
				If mesh.auto_fade=True Then AutoFade(cam,mesh)
			
				If mesh.Alpha()
			
					mesh.alpha_order#=cam.EntityDistanceSquared#(mesh)
				
				Else
				
					mesh.alpha_order#=0.0
				
				EndIf
			
				If mesh.Name <> "Shadow" Then RenderListAdd(mesh,render_list)
				
			EndIf
	
		Next

		UpdateSprites(cam , render_list) ' rotate sprites with respect to current cam
		
		
		If TGLobal.ShadowRender= 1 Then
			'glClearStencil(0)
			'glStencilMask($FFFFFFFF)
			'glClear(GL_STENCIL_BUFFER_BIT)
		
			'glEnable(GL_DEPTH_TEST)
			'glDepthFunc(GL_LEQUAL)
		EndIf
		
		For Local mesh2:TMesh=EachIn render_list
			mesh2.Update()				
		Next
		
		
		If TGlobal.ActiveShadow = True Then
				If TGlobal.ShadowMode = 3 Then
					For Local light:TLight = EachIn TLight.light_list
						EntityFX(light.Shadows.ShadowMesh,17)
						EntityFX(light.Shadows.VolumeCap,17)
		
						light.Shadows.ShadowMesh.Update()
						light.Shadows.VolumeCap.Update() 
						For Local M:TMesh = EachIn light.Shadows.animVolume
								M.Update()
						Next			
						EntityFX(light.Shadows.ShadowMesh,17)
						EntityFX(light.Shadows.VolumeCap,17)
		
					Next
					
				ElseIf TGlobal.ShadowMode = 2
				
					If TGLobal.ShadowRender = 0
						glEnable(GL_STENCIL_TEST)
						RenderShadowToStencil_ZPass()
						'Pass 2: Redraw model, full light in non-shadowed areas 
						glStencilFunc(GL_EQUAL, MidStencilVal, $ffffff)
						glStencilOp(GL_KEEP , GL_KEEP , GL_KEEP) 
						glCullFace(GL_BACK)
						
					ElseIf TGlobal.ShadowRender = 1 Then
					
						RenderShadowtoStencil_ZFAIL()
						
						
						glStencilFunc(GL_EQUAL, MidStencilVal, $ffffff)
						glStencilOp(GL_REPLACE , GL_REPLACE , GL_REPLACE )
						glCullFace(GL_BACK)

					EndIf
					
					
					
					For Local light:TLight=EachIn TLight.light_list
						light.ShowEntity()
						light.Update() ' EntityHidden code inside Update
					Next
					
					
		
					For Local mesh2:TMesh=EachIn render_list
						mesh2.Update()				
					Next
					
					glDisable(GL_STENCIL_TEST)
				Else
							
					'Create shadow volume in stencil buffer
					
					If TGLobal.ShadowRender= 0
					glEnable(GL_STENCIL_TEST) ; 
				
					RenderShadowToStencil_ZPASS()
					'Pass 2: Redraw model, full light in non-shadowed areas	
					
					glStencilFunc(GL_NOTEQUAL, MidStencilVal, $ffffff)
					glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
					ElseIf TGlobal.ShadowRender= 1 Then			
						RenderShadowtoStencil_ZFAIL()
						glCullFace(GL_BACK)
						
						glStencilFunc(GL_NOTEQUAL, MidStencilVal, $ffffff)
						glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)

					EndIf
										
					
					glPushMatrix()
					glLoadIdentity()
					glMatrixMode(GL_PROJECTION)
					glPushMatrix()
					glLoadIdentity()
					glOrtho(0 , 1 , 1 , 0 , 0 , 1)
					
					glDisable(GL_DEPTH_TEST)
								
					glColor4f(0.0, 0.0, 0.0, 0.5)
					glBegin(GL_QUADS)
						glVertex2i(0, 0)
						glVertex2i(0, 1)
						glVertex2i(1, 1)
						glVertex2i(1, 0)
					glEnd()
					glColor4f(1.0,1.0,1.0,1.0)
				
					glEnable(GL_DEPTH_TEST)
					glPopMatrix()
					glMatrixMode(GL_MODELVIEW)
					glPopMatrix()
						
					glDisable(GL_STENCIL_TEST)
					
				EndIf
			EndIf		
		
		If TPhysic.Debug = True Then
			glDisable (GL_LIGHTING)
			glDisable(GL_TEXTURE_2D)
			
			glLineWidth(2.0)
			
			glBegin(GL_LINES)
			glColor3f(1.0, 1.0, 0.0)
			NewtonWorldForEachBodyDo(TPhysic.World, RenderBodyCollision)
			glColor3f(1.0, 1.0, 1.0)
			glEnd
			glLineWidth(1.0)
		EndIf
		
		
	
	End Function

			
End Type
