Fast Extend library — Thread 2

Blitz3D Forums/Blitz3D Userlibs/Fast Extend library — Thread 2

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

I've been doing some tests on my own, and got to do a small shadow mapping system. But then, I quickly came to the conclusion that for correctly shadowing the reciever objects, you need to access the ZBuffer (as for the actual shadows being casted on objects that are infront of the caster), therefore there's no way to do it fast without shaders :/

If you want to test it out...
Include "FastExt.bb"
Include "ShadowMaps.bb"

Graphics3D(1024, 768, 0, 2)
InitExt()

	; --------------------------------
	AmbientLight(64, 64, 64)
	
	Local Plane = CreateSphere()
		ScaleEntity(Plane, 10, 0.1, 10)
		TranslateEntity(Plane, 0, -1, 0)
		
	Local Cube = CreateCube()
		ScaleEntity(Cube, 0.7, 0.7, 0.7)
		TranslateEntity(Cube, 0, 0.6, 0)

	Local Cone = CreateCone()
		ScaleEntity(Cone, 0.7, 0.7, 0.7)
		TranslateEntity(Cone, 0, 0, 2.5)
		
	Local Sphere = CreateSphere()
		ScaleEntity(Sphere, 0.7, 0.7, 0.7)
		TranslateEntity(Sphere, -1, 0, -2.5)
		
	Local Camera = CreateCamera()
		TranslateEntity(Camera, 0, 5, 10)
		PointEntity(Camera, Cube)
	
	Local Light.ShadowMap_Light = ShadowMap_CreateLight(1, 1000, 1024)
		TranslateEntity(Light\Light, 0, 8, 10)
		PointEntity(Light\Light, Cube)
		
	CubeCaster.ShadowMap_Caster = ShadowMap_AddCaster(Light, Cube)
	ShadowMap_AddReciever(Light, Cone)
	ShadowMap_AddReciever(Light, Sphere)
	ShadowMap_AddReciever(Light, Plane)
	
	; --------------------------------
	
	While(Not KeyHit(1))
		MouseLook(Camera)

		If (KeyDown(2)) Then TranslateEntity(Cube, -.1, 0, 0)
		If (KeyDown(3)) Then TranslateEntity(Cube, .1, 0, 0)
		If (KeyDown(4)) Then TranslateEntity(Cube, 0, -.1, 0)
		If (KeyDown(5)) Then TranslateEntity(Cube, 0, .1, 0)
		TurnEntity(Cube, 0.1, 0.2, 0.4)
				
		UpdateWorld()
			HideEntity(Camera)
			ShadowMap_Update(Light)
			ShowEntity(Camera)
		RenderWorld()
		Flip(True)
		
		FPS()
	Wend
	
	; --------------------------------

End

Global FPSCount = 0
Global FPSCountTemp = 0
Global FPSTime = 0
Function FPS()
	If (MilliSecs()-FPSTime)>=1000 Then
		FPSTime = MilliSecs()
		FPSCount = FPSCountTemp
		FPSCountTemp = 0
	EndIf
	FPSCountTemp = FPSCountTemp + 1
	AppTitle(Str$(FPSCount))
	Return FPSCount
End Function

Function MouseLook ( ent, mov# = 0.3 )
	mxspd#=MouseXSpeed()*0.25
	myspd#=MouseYSpeed()*0.25	
	campitch#=EntityPitch(ent)+myspd#
	If campitch#<-65 Then campitch#=-65
	If campitch#>65 Then campitch#=65
	RotateEntity ent,campitch#,EntityYaw(ent)-mxspd#,EntityRoll(ent)
	If KeyDown(17) MoveEntity ent,0,0,mov
	If KeyDown(31) MoveEntity ent,0,0,-mov
	If KeyDown(32) MoveEntity ent,mov,0,0
	If KeyDown(30) MoveEntity ent,-mov,0,0
	MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
End Function

	; ---------------------------------------------------------------------------------------------------------
	; RecursiveAnimate
	; ---------------------------------------------------------------------------------------------------------
	Function RecursiveAnimate(entity, mode=1, speed#=1.0, sequence=0, transition#=0.0)
		If (AnimLength(entity)<>-1) Then Animate(entity, mode, speed#, sequence, transition#)
		For i=1 To CountChildren(entity)	
			RecursiveAnimate(GetChild(entity, i), mode, speed#, sequence, transition#)
		Next
	End Function

	; ---------------------------------------------------------------------------------------------------------
	; RecursiveExtractAnimSeq
	; ---------------------------------------------------------------------------------------------------------
	Function RecursiveExtractAnimSeq(entity, first_frame, last_frame, anim_seq=0)
		If (AnimLength(entity)<>-1) Then ExtractAnimSeq(entity, first_frame, last_frame, anim_seq)
		For i=1 To CountChildren(entity)
			RecursiveExtractAnimSeq(GetChild(entity, i), first_frame, last_frame, anim_seq)
		Next
	End Function


Type ShadowMap_Light
	Field Light
	Field Camera
	Field Texture
End Type

Type ShadowMap_Caster
	Field Entity
	Field Shadow
End Type

Type ShadowMap_Reciever
	Field Entity
End Type

Global ShadowMap_Ambient, ShadowMap_Dot

Function ShadowMap_CreateLight.ShadowMap_Light(LightType=1, Radius# = 1000.0, MapQuality=512)
	Local Light.ShadowMap_Light = New ShadowMap_Light
		Light\Light  = CreateLight(LightType)
		Light\Camera = CreateCamera(Light\Light)
			CameraClsColor(Light\Camera, 255, 255, 255)
			CameraRange(Light\Camera, 1, Radius#)
			CameraProjMode(Light\Camera, 0)
			CameraViewport(Light\Camera, 0, 0, MapQuality, MapQuality)
			CameraZoom(Light\Camera, 0.1)
		Light\Texture = CreateTexture(MapQuality, MapQuality, 1+16+32+256+FE_ZRENDER)
		If (ShadowMap_Dot = 0) Then 
			ShadowMap_Ambient = CreateTexture(1, 1, 1)
			SetBuffer(TextureBuffer(ShadowMap_Ambient))
				Color(64, 64,64)
				Plot(0, 0)
			SetBuffer(BackBuffer())
			
			ShadowMap_Dot = CreateTexture(1, 1, 1)
			SetBuffer(TextureBuffer(ShadowMap_Dot))
				Color(255, 255,255)
				Plot(0, 0)
			SetBuffer(BackBuffer())
		End If
		TextureCoords(Light\Texture, 1)
	Return Light
End Function

Function ShadowMap_DestroyLight(Light.ShadowMap_Light)
	FreeEntity(Light\Camera)
	FreeTexture(Light\Texture)
	Delete Light
End Function	

Function ShadowMap_AddCaster.ShadowMap_Caster(Light.ShadowMap_Light, Entity)
	Local Caster.ShadowMap_Caster = New ShadowMap_Caster
		Caster\Entity = Entity
		Caster\Shadow = CopyEntity(Entity, Entity)
			Local Brush = CreateBrush()
			BrushFX(Brush, 1+8+16)
			BrushTexture(Brush, ShadowMap_Ambient, 0, 0)
			BrushTexture(Brush, ShadowMap_Dot, 0, 1)
			BrushTexture(Brush, ShadowMap_Dot, 0, 2)
			BrushTexture(Brush, ShadowMap_Dot, 0, 3)
			BrushTexture(Brush, ShadowMap_Dot, 0, 4)
			BrushTexture(Brush, ShadowMap_Dot, 0, 5)
			BrushTexture(Brush, ShadowMap_Dot, 0, 6)
			BrushTexture(Brush, ShadowMap_Dot, 0, 7)
			
			RecursivePaintEntity(Caster\Shadow, Brush)
			
	Return Caster
End Function

Function ShadowMap_AddReciever.ShadowMap_Reciever(Light.ShadowMap_Light, Entity)
	Local Reciever.ShadowMap_Reciever = New ShadowMap_Reciever
		Reciever\Entity = Entity
		EntityTexture(Entity, Light\Texture, 0, 0)
		
		; If the Reciever has childs, add them as recievers too
		Local i
		For i=1 To CountChildren(Entity)
			ShadowMap_AddReciever(Light, GetChild(Entity, i))
		Next
	Return Reciever
End Function

Function ShadowMap_Update(Light.ShadowMap_Light)
	; >>>>> STEP 1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	; Prepare light texture buffer to be rendered.
	DebugLog("")
	CameraProjMode(Light\Camera, 2)
	SetBuffer(TextureBuffer(Light\Texture))
		
		; Clear buffer
		ClsColor(255, 255, 255)
		Cls()
		
		; Render caster entities
		Local Caster.ShadowMap_Caster
		For Caster = Each ShadowMap_Caster
			ShowEntity(Caster\Shadow)
			RenderEntity(Light\Camera, Caster\Shadow)
			HideEntity(Caster\Shadow)
		Next

	; Done rendering the shadow map
	SetBuffer(BackBuffer())
	
	; >>>>> STEP 2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	; Calculate all UVs for the recievers
	Local Reciever.ShadowMap_Reciever
	For Reciever = Each ShadowMap_Reciever
		If (EntityInView(Reciever\Entity, Light\Camera)=False) Then Goto Skip
		
		Local Surface, i, j
		For i=1 To CountSurfaces(Reciever\Entity)
			Surface = GetSurface(Reciever\Entity, i)
			For j=0 To CountVertices(Surface)-1
				; Project vertex from local space to object space
				TFormPoint(VertexX#(Surface, j), VertexY#(Surface, j), VertexZ#(Surface, j), Reciever\Entity, 0)
				
				; Calculate UVs in camera space
				CameraProject(Light\Camera, TFormedX#(), TFormedY#(), TFormedZ#())
				VertexTexCoords(Surface, j, ProjectedX#()/Float#(TextureWidth(Light\Texture)), ProjectedY#()/Float#(TextureHeight(Light\Texture)), 0, 1)
			Next
		Next
		
		.Skip
	Next
	
	; Hide camera
	CameraProjMode(Light\Camera, 0)
End Function

	Function RecursivePaintEntity(entity, brush)
		If (EntityClass$(entity)="Mesh") Then PaintEntity(entity, brush)
		For i=1 To CountChildren(entity)
			RecursivePaintEntity(GetChild(entity, i), brush)
		Next
	End Function