// Project: shadows
// Created: 2016-08-16 by Jan Bögemann

type ShadowItemData
	Castshadow
	ObjectID
endtype

function Shadow_PointLight_Init(Near#,Far#)
	global Shadow_List as ShadowItemData[]
	global Shadow_ShadowStaticShaderID
	global Shadow_ShadowBoneShaderID
	global Shadow_DepthShaderID
	global Shadow_DepthBoneShaderID
	global Shadow_DepthRenderImageID
	global Shadow_DepthSpriteID
	global Shadow_CameraNear#
	global Shadow_CameraFar#
	global Shadow_Distance#
	global Shadow_CubeTexture as integer[5]
	global QuadID
	global Shadow_LightPosX#
	global Shadow_LightPosY#
	global Shadow_LightPosZ#
	global Shadow_LightRadius#
	
	Shadow_CameraNear#=Near#
	Shadow_CameraFar#=Far#
	
	SetDefaultMinFilter(1)
	SetDefaultMagFilter(1)
	SetDefaultWrapU(1)
	SetDefaultWrapV(1)

	Shadow_ShadowStaticShaderID=LoadShader("ShadowStatic.vs","ShadowStatic.ps")
	Shadow_ShadowBoneShaderID=LoadShader("ShadowBone.vs","ShadowStatic.ps")
	
	Shadow_DepthShaderID=LoadShader("Depth.vs","Depth.ps")
	Shadow_DepthBoneShaderID=LoadShader("DepthBone.vs","Depth.ps")
	
//~	Shadow_DepthRenderImageID=CreateRenderImage(GetImageWidth(Shadow_CubeTexture[0])*4,GetImageHeight(Shadow_CubeTexture[0])*2,0,0)
	Shadow_DepthRenderImageID=CreateRenderImage(256*4,256*2,1,0)

	Shadow_DepthSpriteID=CreateSprite(Shadow_DepthRenderImageID)
	SetSpriteSize(Shadow_DepthSpriteID,-1,256)
endfunction

function Shadow_PointLight_Update(LightID,PosX#,PosY#,PosZ#,Radius#)
	SetShaderConstantByName(Shadow_ShadowStaticShaderID,"lightPos",PosX#,PosY#,PosZ#,Radius#)
	SetShaderConstantByName(Shadow_ShadowBoneShaderID,"lightPos",PosX#,PosY#,PosZ#,Radius#)
	SetShaderConstantByName(Shadow_DepthShaderID,"lightPos",PosX#,PosY#,PosZ#,Radius#)
	SetShaderConstantByName(Shadow_DepthBoneShaderID,"lightPos",PosX#,PosY#,PosZ#,Radius#)
	SetPointLightPosition(1,PosX#,PosY#,PosZ#)
	SetPointLightRadius(1,Radius#)
	
	CameraX#=GetCameraX(1)
	CameraY#=GetCameraY(1)
	CameraZ#=GetCameraZ(1)
	CameraAngleX#=GetCameraAngleX(1)
	CameraAngleY#=GetCameraAngleY(1)
	CameraAngleZ#=GetCameraAngleZ(1)
	CameraFOV#=GetCameraFOV(1)
	Width#=GetDeviceWidth()
	Height#=GetDeviceHeight()
	
	Shadow_LightRadius#=Radius#
	SetShaderConstantByName(Shadow_ShadowStaticShaderID,"cameraRange",Shadow_CameraNear#,Shadow_LightRadius#,0,0)
	SetShaderConstantByName(Shadow_ShadowBoneShaderID,"cameraRange",Shadow_CameraNear#,Shadow_LightRadius#,0,0)
	SetShaderConstantByName(Shadow_DepthShaderID,"cameraRange",Shadow_CameraNear#,Shadow_LightRadius#,0,0)
	SetShaderConstantByName(Shadow_DepthBoneShaderID,"cameraRange",Shadow_CameraNear#,Shadow_LightRadius#,0,0)
	
	SetCameraFOV(1,90)
	SetCameraAspect(1,1)
	SetCameraRange(1,Shadow_CameraNear#,Shadow_LightRadius#)
	SetCameraPosition(1,PosX#,PosY#,PosZ#)
	
	SetRenderToCube(0,Shadow_DepthRenderImageID,Shadow_CameraNear#,Shadow_LightRadius#)
	
	SetCameraAspect(1,Width#/Height#)
	SetCameraFOV(1,CameraFOV#)
	SetCameraRange(1,Shadow_CameraNear#,Shadow_CameraFar#)
	SetCameraRotation(1,CameraAngleX#,CameraAngleY#,CameraAngleZ#)
	SetCameraPosition(1,CameraX#,CameraY#,CameraZ#)
endfunction

function Shadow_AddObject(ObjectID,Castshadow)
	SetObjectImage(ObjectID,Shadow_DepthRenderImageID,1)
	Shadow_SetShadowShader(ObjectID)
	
	tempShadowItem as ShadowItemData
	tempShadowItem.ObjectID=ObjectID
	tempShadowItem.Castshadow=Castshadow
	Shadow_List.insert(tempShadowItem)
endfunction

function Shadow_SetShadowShader(ObjectID)
	if GetObjectNumBones(ObjectID)=0
		SetObjectShader(ObjectID,Shadow_ShadowStaticShaderID)
	else
		SetObjectShader(ObjectID,Shadow_ShadowBoneShaderID)
	endif
endfunction

function Shadow_SetDepthShader(ObjectID)
	if GetObjectNumBones(ObjectID)=0
		SetObjectShader(ObjectID,Shadow_DepthShaderID)
	else
		SetObjectShader(ObjectID,Shadow_DepthBoneShaderID)
	endif
endfunction

function Shadow_RemoveObject(ObjectID)
	if GetObjectExists(ObjectID)
		SetObjectShader(ObjectID,0)
		SetObjectScreenCulling(ObjectID,1)

		ShadowID=Shadow_List.find(ObjectID)
		if ShadowID>=0 then Shadow_List.remove(ShadowID)
	endif
endfunction

function Shadow_GetListLength()
endfunction Shadow_List.length

function Shadow_GetListObject(ID)
endfunction Shadow_List[ID].ObjectID

function Shadow_RemoveAllObjects()
	for ID=0 to Shadow_List.length
		SetObjectShader(Shadow_List[ID].ObjectID,0)
		SetObjectScreenCulling(Shadow_List[ID].ObjectID,1)

		Shadow_List.remove(ID)
	next ID
endfunction

function SetRenderToCube(CubeColorImageID,CubeDepthImageID,CameraNear#,CameraFar#)
	CameraX#=GetCameraAngleX(1)
	CameraY#=GetCameraAngleY(1)
	CameraZ#=GetCameraAngleZ(1)
	CameraFOV#=GetCameraFOV(1)
	Width#=GetDeviceWidth()
	Height#=GetDeviceHeight()
	VirtualWidth#=GetVirtualWidth()
	VirtualHeight#=GetVirtualHeight()	
	
	SetVirtualResolution(Width#,Height#)
	SetCameraAspect(1,1)
	SetCameraFOV(1,90)

	SetRenderToImage(CubeColorImageID,CubeDepthImageID)
	ClearScreen()
	
	SetCameraToScissor(0,0,Width#*0.25,Height#*0.5,CameraNear#,CameraFar#)
	SetCameraRotation(1,0,270,0) //Left
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow
			Shadow_SetDepthShader(Shadow_List[ShadowID].ObjectID)
			SetObjectCullMode(Shadow_List[ShadowID].ObjectID,2)
		endif
	next ShadowID
	Render3D()

	SetCameraToScissor(Width#*0.25,0,Width#*0.5,Height#*0.5,CameraNear#,CameraFar#)
	SetCameraRotation(1,0,0,0) //Front
	Render3D()

	SetCameraToScissor(Width#*0.5,0,Width#*0.75,Height#*0.5,CameraNear#,CameraFar#)
	SetCameraRotation(1,0,90,0) //Right
	Render3D()

	SetCameraToScissor(Width#*0.75,0,Width#,Height#*0.5,CameraNear#,CameraFar#)
	SetCameraRotation(1,0,180,0) //Back
	Render3D()

	SetCameraToScissor(Width#*0.75,Height#*0.5,Width#,Height#,CameraNear#,CameraFar#)
	SetCameraRotation(1,-90,0,0) //Top
	Render3D()

	SetCameraToScissor(Width#*0.25,Height#*0.5,Width#*0.5,Height#,CameraNear#,CameraFar#)
	SetCameraRotation(1,90,0,0) //Bottom
	Render3D()
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow
//~			DrawObject(Shadow_List[ShadowID].ObjectID)
			SetObjectCullMode(Shadow_List[ShadowID].ObjectID,1)
			Shadow_SetShadowShader(Shadow_List[ShadowID].ObjectID)
		endif
	next ShadowID

	SetScissor(0,0,0,0)
	SetCameraOffCenter(1,0)
	SetCameraRotation(1,CameraX#,CameraY#,CameraZ#)
	SetCameraFOV(1,CameraFOV#)
	SetCameraAspect(1,Width#/Height#)
	SetVirtualResolution(VirtualWidth#,VirtualHeight#)
endfunction

function SetCameraToScissor(Left#,Top#,Right#,Bottom#,CameraNear#,CameraFar#)
	CameraFOV#=GetCameraFOV(1)
	Width#=GetVirtualWidth()
	Height#=GetVirtualHeight()
	ScissorWidth#=Right#-Left#
	ScissorHeight#=Bottom#-Top#
	ScaleX#=2.0/ScissorWidth#
	ScaleY#=2.0/ScissorHeight#
	
	BoundsLeft#=-CameraNear#+ScaleX#*Left#*-CameraNear#
	BoundsRight#=CameraNear#+(Width#-Right#)*ScaleX#*CameraNear#
	BoundsTop#=CameraNear#+Top#*ScaleY#*CameraNear#
	BoundsBottom#=-CameraNear#+(Height#-Bottom#)*ScaleY#*-CameraNear#
	
	SetCameraOffCenter(1,1)
	SetCameraBounds(1,BoundsLeft#,BoundsRight#,BoundsTop#,BoundsBottom#)
	SetCameraRange(1,CameraNear#,CameraFar#)
	SetScissor(Left#,Top#,Right#,Bottom#)
endfunction

/*
function SetRenderDepthToCube(CubeTexture ref as integer[])
//~	SetRenderToImage(CubeTexture[0],-1)
	SetRenderToImage(0,CubeTexture[0])
	SetCameraRotation(1,0,-90,0) //Left
	ClearScreen()
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow
//~			Shadow_SetDepthShader(Shadow_List[ShadowID].ObjectID)
			SetObjectCullMode(Shadow_List[ShadowID].ObjectID,2)
			DrawObject(Shadow_List[ShadowID].ObjectID)
		endif
	next ShadowID

//~	SetRenderToImage(CubeTexture[1],-1)
	SetRenderToImage(0,CubeTexture[1])
	SetCameraRotation(1,0,0,0) //Front
	ClearScreen()
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow then DrawObject(Shadow_List[ShadowID].ObjectID)
	next ShadowID

//~	SetRenderToImage(CubeTexture[2],-1)
	SetRenderToImage(0,CubeTexture[2])
	SetCameraRotation(1,0,90,0) //Right
	ClearScreen()
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow then DrawObject(Shadow_List[ShadowID].ObjectID)
	next ShadowID

//~	SetRenderToImage(CubeTexture[3],-1)
	SetRenderToImage(0,CubeTexture[3])
	SetCameraRotation(1,0,-180,0) //Back
	ClearScreen()
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow then DrawObject(Shadow_List[ShadowID].ObjectID)
	next ShadowID

//~	SetRenderToImage(CubeTexture[4],-1)
	SetRenderToImage(0,CubeTexture[4])
	SetCameraRotation(1,-90,0,0) //Top
	ClearScreen()
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow then DrawObject(Shadow_List[ShadowID].ObjectID)
	next ShadowID

//~	SetRenderToImage(CubeTexture[5],-1)
	SetRenderToImage(0,CubeTexture[5])
	SetCameraRotation(1,90,0,0) //Bottom
	ClearScreen()
	for ShadowID=0 to Shadow_List.length
		if Shadow_List[ShadowID].Castshadow
			DrawObject(Shadow_List[ShadowID].ObjectID)
			SetObjectCullMode(Shadow_List[ShadowID].ObjectID,1)
//~			Shadow_SetShadowShader(Shadow_List[ShadowID].ObjectID)
		endif
	next ShadowID
endfunction
*/
