Carmack's Reverse - (stencil shadows) here it is.

Blitz3D Forums/Blitz3D Programming/Carmack's Reverse - (stencil shadows) here it is.

After a number of weeks of trying to optimize a number of different 'routines' i came up with for creating shadow volumes of unboned meshes, i concluded that a fast way of dynamicaly drawing a satisfactory number of shadows is not really possible using b3d commands alone. I only have partialy done a routine to build a volume with a minimum number of polys but this is for levels only - where the level and the light source is stationary. I don't think too many people would have a use for that. It (probably) IS possible to have fast stencil shadows in b3d but with help from a very good c++ coder who can make a number of DLLs that will work well with blitz3d.

Anyway, here is the code based on Tom's code, only now Depth-Fail (Carmacks reverse) technique is used. This way its very robust, and when you enter the volumes (in this example 2 cylinders) they dont disappear or get drawn incorrectly, as was the case with original Tom's code which used the Depth-Pass technique. I have included basic code to make shadow volumes in b3d so if you want to test around yourself, do it. It can be useful for very simple objects (if you get it to work like you want it).

EDIT: The first code i posted i forgot to include the ATI fix. This one should work, try it and tell me.

If youre interested in what problems i ran into, read on. If not, get the code from the box below and the needed userlibs from:
http://www.geocities.com/spirala7/dx7sshad.htm



The main problem is that commercial games which are written in c++ have a number of keywords and maths that are integral to the language. For example there is the D3DMATRIX which is used to take positions of vertices (directly using D3DVERTEXBUFFER... , CreateVertexBuffer() ) and simply extrude them by a vector, when the volume is capped as well. In Blitz however we have to use TFormPoint to even get the global position of a vertex, and then TFormVector to even stand a chance of checking where the edges are, or which triangles are facing the light source, etc. You COULD do it without TFormVector also perhaps, but the maths would be as slow as that command. I tried everything possible. It's not to blame blitz for not having this kind of thing, if it did it would be a considerably more complex language. Another thing which i find is pretty slow is creation of triangles. In C++ the vertexes are just copied and then "extruded" or projected, this includes creation of the triangles and is obviously faster.

In other words, Mark! Do something :D make us stencil shadows for blitz3d, you see how simple it is if you know c++? Yeah! COME ON!

Here's the code (should work on ATI?):


;This is a demo to show implementation of "Carmacks Reverse" way of drawing
;stencil shadows. It is also known as the Depth-Fail or the Z-Fail technique.
;
;			Lenn , 21.01.2005

;D3DCULL
Const D3DCULL_NONE				= 1
Const D3DCULL_CW					= 2
Const D3DCULL_CCW					= 3
		
;D3DSHADE_MODE
Const D3DSHADE_FLAT			= 1
Const D3DSHADE_GOURAUD	= 2
Const D3DSHADE_PHONG		= 3

;D3DFILL_MODE
Const D3DFILL_POINT			= 1
Const D3DFILL_WIREFRAME	= 2
Const D3DFILL_SOLID			= 3

;D3DSTENCILOP
Const D3DSTENCILOP_KEEP           = 1
Const D3DSTENCILOP_ZERO           = 2
Const D3DSTENCILOP_REPLACE        = 3
Const D3DSTENCILOP_INCRSAT        = 4
Const D3DSTENCILOP_DECRSAT        = 5
Const D3DSTENCILOP_INVERT         = 6
Const D3DSTENCILOP_INCR           = 7
Const D3DSTENCILOP_DECR           = 8
Const D3DSTENCILOP_FORCE_DWORD    = $7fffffff	;force 32-bit size enum

;D3DCMPFUNC
Const D3DCMP_NEVER               = 1
Const D3DCMP_LESS                = 2
Const D3DCMP_EQUAL               = 3
Const D3DCMP_LESSEQUAL           = 4
Const D3DCMP_GREATER             = 5
Const D3DCMP_NOTEQUAL            = 6
Const D3DCMP_GREATEREQUAL        = 7
Const D3DCMP_ALWAYS              = 8
Const D3DCMP_FORCE_DWORD         = $7fffffff	;force 32-bit size enum

;D3DBLEND
Const D3DBLEND_ZERO              = 1
Const D3DBLEND_ONE               = 2
Const D3DBLEND_SRCCOLOR          = 3
Const D3DBLEND_INVSRCCOLOR       = 4
Const D3DBLEND_SRCALPHA          = 5
Const D3DBLEND_INVSRCALPHA       = 6
Const D3DBLEND_DESTALPHA         = 7
Const D3DBLEND_INVDESTALPHA      = 8
Const D3DBLEND_DESTCOLOR         = 9
Const D3DBLEND_INVDESTCOLOR      = 10
Const D3DBLEND_SRCALPHASAT       = 11
Const D3DBLEND_BOTHSRCALPHA      = 12
Const D3DBLEND_BOTHINVSRCALPHA   = 13
Const D3DBLEND_FORCE_DWORD       = $7fffffff	;force 32-bit size enum



Const D3DRS_ANTIALIAS          = 2    ; D3DANTIALIASMODE */
Const D3DRS_TEXTUREPERSPECTIVE = 4    ; True For perspective correction */
Const D3DRS_ZENABLE            = 7    ; D3DZBUFFERTYPE (Or True/False For legacy) */
Const D3DRS_FILLMODE           = 8    ; D3DFILL_MODE        */
Const D3DRS_SHADEMODE          = 9    ; D3DFILL_MODE */
Const D3DRS_LINEPATTERN        = 10   ; D3DLINEPATTERN */
Const D3DRS_ZWRITEENABLE       = 14   ; True To enable z writes */
Const D3DRS_ALPHATESTENABLE    = 15   ; True To enable alpha tests */
Const D3DRS_LASTPIXEL          = 16   ; True For Last-pixel on lines */
Const D3DRS_SRCBLEND           = 19   ; D3DBLEND */
Const D3DRS_DESTBLEND          = 20   ; D3DBLEND */
Const D3DRS_CULLMODE           = 22   ; D3DCULL */
Const D3DRS_ZFUNC              = 23   ; D3DCMPFUNC */
Const D3DRS_ALPHAREF           = 24   ; D3DFIXED (long) */
Const D3DRS_ALPHAFUNC          = 25   ; D3DCMPFUNC */
Const D3DRS_DITHERENABLE       = 26   ; True To enable dithering */
Const D3DRS_ALPHABLENDENABLE   = 27   ; True To enable alpha blending */
Const D3DRS_FOGENABLE          = 28   ; True To enable fog blending */
Const D3DRS_SPECULARENABLE     = 29   ; True To enable specular */
Const D3DRS_ZVISIBLE           = 30   ; True To enable z checking */
Const D3DRS_STIPPLEDALPHA      = 33   ; True To enable stippled alpha (RGB device only) */
Const D3DRS_FOGCOLOR           = 34   ; D3DCOLOR */  INT (((a) << 24) Or ((r) << 16) Or ((g) << 8) Or (b)))
Const D3DRS_FOGTABLEMODE       = 35   ; D3DFOGMODE */
Const D3DRS_FOGSTART           = 36   ; Float Fog start (For both vertex And pixel fog) 
Const D3DRS_FOGEND             = 37   ; Float Fog End      */
Const D3DRS_FOGDENSITY         = 38   ; Fog density  */
Const D3DRS_EDGEANTIALIAS      = 40   ; True To enable edge antialiasing */
Const D3DRS_COLORKEYENABLE     = 41   ; True To enable source colorkeyed textures */
Const D3DRS_ZBIAS              = 47   ; LONG Z bias */
Const D3DRS_RANGEFOGENABLE     = 48   ; Enables range-based fog */

; *** STENCIL OPS ***
Const D3DRS_STENCILENABLE      = 52   ; BOOL enable/disable stenciling
Const D3DRS_STENCILFAIL        = 53   ; D3DSTENCILOP To do If stencil test fails
Const D3DRS_STENCILZFAIL       = 54   ; D3DSTENCILOP To do If stencil test passes And Z test fails
Const D3DRS_STENCILPASS        = 55   ; D3DSTENCILOP To do If both stencil And Z tests pass */
Const D3DRS_STENCILFUNC        = 56   ; D3DCMPFUNC fn.  Stencil Test passes If ((ref & mask) stencilfn (stencil & mask)) is True */
Const D3DRS_STENCILREF         = 57   ; INT Reference value used in stencil test */
Const D3DRS_STENCILMASK        = 58   ; Mask value used in stencil test  e.g (0xffffffff)
Const D3DRS_STENCILWRITEMASK   = 59   ; Write mask applied To values written To stencil buffer e.g (0xffffffff)
Const D3DRS_TEXTUREFACTOR      = 60   ; D3DCOLOR used For multi-texture blend */

Const D3DCLEAR_TARGET					= $00000001	;Clear target surface
Const D3DCLEAR_ZBUFFER				= $00000002	;Clear target z buffer
Const D3DCLEAR_STENCIL				= $00000004	;Clear Stencil


;ERRORS
Const D3DERR_ZBUFFER_NOTPRESENT					= 2070
Const D3DERR_STENCILBUFFER_NOTPRESENT		= 2071
Const D3DERR_VIEWPORTHASNODEVICE				= 774
Const DDERR_INVALIDOBJECT								= 130
Const DDERR_INVALIDPARAMS								= $80070057

Type BBRect
	Field x1%
	Field lX1%

	Field y1%
	Field lY1%

	Field x2%
	Field lX2%
	
	Field y2%
  Field lY2%
End Type

Graphics3D 1027,768,32,2

Direct3D7=SystemProperty$("Direct3D7")
Direct3DDevice7=SystemProperty$("Direct3DDevice7")
DirectDraw7=SystemProperty$("DirectDraw7")
DirectInput7=SystemProperty$("DirectInput7")
AppHWND=SystemProperty$("AppHWND")
AppHINSTANCE=SystemProperty$("AppHINSTANCE")




cam=CreateCamera()
piv=CreatePivot()
PositionEntity cam,-5,3,-5
PointEntity cam,piv
CameraRange cam,.1,50

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

tex=CreateTexture(512,512)
ScaleTexture tex,.2,.5
SetBuffer TextureBuffer(tex)
Color 100,100,100
Rect 0,0,512,512
Color 200,200,200
Rect 8,8,496,496
Color 255,255,255
SetBuffer BackBuffer()

cyl1=CreateCylinder()
EntityAlpha cyl1,.3
PositionEntity cyl1,2,0,0
ScaleEntity cyl1,3,3,3

cyl2=CreateCylinder()
EntityAlpha cyl2,.3
PositionEntity cyl2,2,0,5
ScaleEntity cyl2,3,3,3

cube=CreateCube()
PositionEntity cube,0,0,0
ScaleEntity cube,5,.2,10
EntityTexture cube,tex



spa#=.3
shadowplane=CreateCube() ; squished Z cube infront of cam
ScaleMesh shadowplane,10,10,.01
EntityParent shadowplane,cam,0
MoveEntity shadowplane,0,0,.2
EntityColor shadowplane,0,0,0
EntityAlpha shadowplane,spa#
;Shadow plane is the object infront of the screen which is drawn where
;the stencil shadow should be drawn (on certain pixels). It means that
;where the shadow volume and scenery intersect, that is where the plane
;will be drawn. Because the color is black, and alpha is spa# its darkness
;will depend on spa#. You can put any other object in its place...


sv=1

; AREA TO CLEAR
r.BBRect=New BBRect
r\lX1=0
r\lY1=0
;r\lX2=GraphicsWidth()/2 ; half the screen (used to show what happens if only half the screen is cleared)
r\lX2=GraphicsWidth() 
r\lY2=GraphicsHeight()


CameraClsMode cam,False,False

While Not KeyHit(1)

.start
	PositionEntity cyl1,(MouseX()-(GraphicsWidth()*.5)) * .01,-(MouseY()-(GraphicsWidth()*.5)) * .02,0
	PositionEntity cyl2,(MouseX()-(GraphicsWidth()*.5)) * .01,-(MouseY()-(GraphicsWidth()*.5)) * .02,2
	
	
	t=MilliSecs()

	;-----------------------------------------------------------------------------------render start	
	HideEntity shadowplane;1-hide plane
	;I =think= that it might be better to hide the volumes here
	HideEntity cyl1  ;1a-hide volumes
	HideEntity cyl2 
	ShowEntity cube  ;2-show scene

	SetRenderState(Direct3DDevice7, D3DRS_ZWRITEENABLE, True) 
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE, False)
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, False)


;	DeviceClear2(Direct3DDevice7, r, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER Or D3DCLEAR_STENCIL,$00008080,1.0,0)
;	RenderWorld 
DeviceClear(Direct3DDevice7, 7,$00008080,1,0)
CameraClsMode cam,True,True
RenderWorld
CameraClsMode cam,False,False


	ShowEntity cyl1 ;3-show volume
	ShowEntity cyl2
	HideEntity cube ;4-hide scene


; *** RenderShadow() START *** -------- << name of the function as found in C++ DX7SDK examples


	SetRenderState(Direct3DDevice7, D3DRS_ZWRITEENABLE,False)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE,True)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILFUNC, D3DCMP_ALWAYS)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILREF, 1)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILMASK,$ffffffff)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILWRITEMASK,$ffffffff)

	SetRenderState(Direct3DDevice7, D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR)
	
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, True)
	SetRenderState(Direct3DDevice7, D3DRS_SRCBLEND, D3DBLEND_ZERO)
	SetRenderState(Direct3DDevice7, D3DRS_DESTBLEND, D3DBLEND_ONE)
	
	RenderWorld	
	
	SetRenderState(Direct3DDevice7, D3DRS_CULLMODE, D3DCULL_CW)
	RenderWorld
	
	SetRenderState(Direct3DDevice7, D3DRS_CULLMODE, D3DCULL_CCW)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR)
	RenderWorld 
	
	SetRenderState(Direct3DDevice7, D3DRS_ZWRITEENABLE,     True )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE,    False )
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, False )			
	

	
; *** RenderShadow() END *** --------



; *** DrawShadow() START *** -----------  << name of the function as found in C++ DX7SDK examples
	SetRenderState(Direct3DDevice7, D3DRS_ZENABLE,       False )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE, True )
	SetRenderState(Direct3DDevice7, D3DRS_FOGENABLE, False)	

	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, True )
	SetRenderState(Direct3DDevice7, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA )
	SetRenderState(Direct3DDevice7, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA )

	SetRenderState(Direct3DDevice7, D3DRS_STENCILREF,  1 )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP )

	ShowEntity shadowplane ;5-show plane
	RenderWorld

	SetRenderState(Direct3DDevice7, D3DRS_ZENABLE,          True )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE,    False )
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, True )

; *** DrawShadow() END *** -----------

	HideEntity shadowplane ;6-hide plane

	RenderWorld;--------------------------------------------------------------------------render end
	

	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, False )
	Text 0,0,"Move cylinders (volumes) with mouse/"+"     MS: "+(MilliSecs() - t)
	Text 0,10,"Shadow Alpha: "+spa+ "    LMB/RMB to change value, SPACE to toggle visibility"
	Text 0,20, "A/Z to move back/forward. Enter the volumes and see that it works."

	If MouseDown(1)
		spa=spa-.01
		If spa<0 spa=0
		EntityAlpha shadowplane,spa
	Else If MouseDown(2)
		spa=spa+.01
		If spa>1.0 spa=1.0
		EntityAlpha shadowplane,spa
	End If
	
	If KeyHit(30)
		MoveEntity cam, 0,0,0.1
	End If
	
	If KeyHit(44)
		MoveEntity cam, 0,0,-0.1
	End If	
	

	If KeyHit(57)
		sv=Not sv
		If sv
			EntityAlpha cyl1,.3
			EntityAlpha cyl2,.3
		Else
			EntityAlpha cyl1,0.001
			EntityAlpha cyl2,0.001
		End If
	End If
	
	If KeyHit(24) tra=Not tra 


Flip

Wend


End








Type volumes
	Field mesh
End Type

Function CreateVolume(entity, light)
;entity - the entity that casts the shadow
;light - the light entity from which the light
;
;This function is included in case somebody wants to build shadow volumes and try stuff out.
;This is fairly slow because it extrudes and caps every triangle on a mesh. This means
;that 6 times more triangles need to be made for each one on the mesh.
;(I tried faster methods but trust me its not easy)
;It may be useful only for very basic geometry.


lx#=EntityX(light,True)
ly#=EntityY(light,True)
lz#=EntityZ(light,True)

	a_vol.volumes=New volumes
		a_vol\mesh=CreateMesh()
		
		;EntityBlend a_vol\mesh,2
		;EntityFX a_vol\mesh,1
		EntityColor a_vol\mesh,0,0,0
		EntityAlpha a_vol\mesh,0.001

		volsurf=CreateSurface(a_vol\mesh)
		numsurf=CountSurfaces(entity)		
		vpos=CreatePivot()
		vposend=CreatePivot()
		VolumeDepth#=1000
		
		
		
		;For surfcount=1 To numsurf-1
		surfcount=1

		While surfcount <= numsurf
			cursurface=GetSurface(entity, surfcount)
			maxtricount=CountTriangles (cursurface)
			;For tricount=0 To tricount-1
							
			While tricount < maxtricount
			v1x#=VertexX(cursurface, TriangleVertex(cursurface, tricount, 0))
			v1y#=VertexY(cursurface, TriangleVertex(cursurface, tricount, 0))
			v1z#=VertexZ(cursurface, TriangleVertex(cursurface, tricount, 0))
			TFormPoint v1x#,v1y#,v1z#, entity, 0
			v1x#=TFormedX()
			v1y#=TFormedY()
			v1z#=TFormedZ()
			
			v2x#=VertexX(cursurface, TriangleVertex(cursurface, tricount, 1))
			v2y#=VertexY(cursurface, TriangleVertex(cursurface, tricount, 1))
			v2z#=VertexZ(cursurface, TriangleVertex(cursurface, tricount, 1))			
			TFormPoint v2x#,v2y#,v2z#, entity, 0
			v2x#=TFormedX()
			v2y#=TFormedY()
			v2z#=TFormedZ()
			
			v3x#=VertexX(cursurface, TriangleVertex(cursurface, tricount, 2))
			v3y#=VertexY(cursurface, TriangleVertex(cursurface, tricount, 2))
			v3z#=VertexZ(cursurface, TriangleVertex(cursurface, tricount, 2))
			TFormPoint v3x#,v3y#,v3z#, entity, 0
			v3x#=TFormedX()
			v3y#=TFormedY()
			v3z#=TFormedZ()
			
			
			PositionEntity vpos,v1x#,v1y#,v1z#
			PositionEntity vposend, lx#,ly#,lz#,1
			PointEntity vposend, vpos
			MoveEntity vposend, 0,0,VolumeDepth#
			v1xe#=EntityX(vposend, True)
			v1ye#=EntityY(vposend, True)
			v1ze#=EntityZ(vposend, True)
			
			PositionEntity vpos,v2x#,v2y#,v2z#
			PositionEntity vposend, lx#,ly#,lz#,1
			PointEntity vposend, vpos
			MoveEntity vposend, 0,0,VolumeDepth#
			v2xe#=EntityX(vposend, True)
			v2ye#=EntityY(vposend, True)
			v2ze#=EntityZ(vposend, True)
			
			PositionEntity vpos,v3x#,v3y#,v3z#
			PositionEntity vposend, lx#,ly#,lz#,1
			PointEntity vposend, vpos
			MoveEntity vposend, 0,0,VolumeDepth#
			v3xe#=EntityX(vposend, True)
			v3ye#=EntityY(vposend, True)
			v3ze#=EntityZ(vposend, True)
			
			v1=AddVertex(volsurf,v1x#,v1y#,v1z#)
			v1e=AddVertex(volsurf,v1xe#,v1ye#,v1ze#)
			v2=AddVertex(volsurf,v2x#,v2y#,v2z#)
			v2e=AddVertex(volsurf,v2xe#,v2ye#,v2ze#)
			v3=AddVertex(volsurf,v3x#,v3y#,v3z#)
			v3e=AddVertex(volsurf,v3xe#,v3ye#,v3ze#)			

			AddTriangle (volsurf, v1,v1e,v2)
			AddTriangle (volsurf, v2,v1e,v2e)
			AddTriangle (volsurf, v1,v3,v1e)
			AddTriangle (volsurf, v3,v3e,v1e)
			AddTriangle (volsurf, v3,v2,v3e)
			AddTriangle (volsurf, v2,v2e,v3e)
			AddTriangle (volsurf, v1,v2,v3) 	;cap top
			AddTriangle (volsurf, v1e,v2e,v3e) 	;cap bottom			
			
			tricount=tricount+1
			Wend 
			;Next		
		surfcount=surfcount+1
		Wend
		;Next

FreeEntity vpos
FreeEntity vposend

End Function

Function HideVolumes()
	For a_vol.volumes=Each volumes
		HideEntity a_vol\mesh
	Next
End Function
Function ShowVolumes()
	For a_vol.volumes=Each volumes
		ShowEntity a_vol\mesh
	Next
End Function
Function DeleteVolumes()
	For a_vol.volumes=Each volumes
		FreeEntity a_vol\mesh
		Delete a_vol
	Next
End Function



Looks very corrupt on my machine.

hey, that's dead easy. just tell me what's this c++. Seriously - I'm looking forward to finally see smooth shadows with blitz3D. Especially something that would work nicely with an FPS enviroment.

Corrupt display here too, probably an ATI thing?

Function "SetRenderState" not found.

You have to download the userlibs.

I get a MAV on SetRenderState().

Um... I'm guessing that I do not see it properly. Basically all I am getting is a very white sort of thing that looks like garbag eand a ton of messed up charcters overlappig eachother at the top. I can still recognise and move about what I'm guessing is the cylinder, but that's about it.
I have a Radeon 9600 Pro as well, so I would guess that it very probably is an ATI thing.

I hope this can be made working across all platforms :D

Works here on my nVidia Geforce6800 GT....



I'm guessin card-compatiblity would be the biggest pain in te rear here, considerin alot of the people who posted received graphical glitches...

I think Tom (who made the original DLL) sorted any ATI glitch issues.

Yes, i just posted the wrong version which was not fixed. Here is the fixed version,it should work, tell me if it doesnt:


;This is a demo to show implementation of "Carmacks Reverse" way of drawing
;stencil shadows. It is also known as the Depth-Fail or the Z-Fail technique.
;
;			Lenn , 21.01.2005

;D3DCULL
Const D3DCULL_NONE				= 1
Const D3DCULL_CW					= 2
Const D3DCULL_CCW					= 3
		
;D3DSHADE_MODE
Const D3DSHADE_FLAT			= 1
Const D3DSHADE_GOURAUD	= 2
Const D3DSHADE_PHONG		= 3

;D3DFILL_MODE
Const D3DFILL_POINT			= 1
Const D3DFILL_WIREFRAME	= 2
Const D3DFILL_SOLID			= 3

;D3DSTENCILOP
Const D3DSTENCILOP_KEEP           = 1
Const D3DSTENCILOP_ZERO           = 2
Const D3DSTENCILOP_REPLACE        = 3
Const D3DSTENCILOP_INCRSAT        = 4
Const D3DSTENCILOP_DECRSAT        = 5
Const D3DSTENCILOP_INVERT         = 6
Const D3DSTENCILOP_INCR           = 7
Const D3DSTENCILOP_DECR           = 8
Const D3DSTENCILOP_FORCE_DWORD    = $7fffffff	;force 32-bit size enum

;D3DCMPFUNC
Const D3DCMP_NEVER               = 1
Const D3DCMP_LESS                = 2
Const D3DCMP_EQUAL               = 3
Const D3DCMP_LESSEQUAL           = 4
Const D3DCMP_GREATER             = 5
Const D3DCMP_NOTEQUAL            = 6
Const D3DCMP_GREATEREQUAL        = 7
Const D3DCMP_ALWAYS              = 8
Const D3DCMP_FORCE_DWORD         = $7fffffff	;force 32-bit size enum

;D3DBLEND
Const D3DBLEND_ZERO              = 1
Const D3DBLEND_ONE               = 2
Const D3DBLEND_SRCCOLOR          = 3
Const D3DBLEND_INVSRCCOLOR       = 4
Const D3DBLEND_SRCALPHA          = 5
Const D3DBLEND_INVSRCALPHA       = 6
Const D3DBLEND_DESTALPHA         = 7
Const D3DBLEND_INVDESTALPHA      = 8
Const D3DBLEND_DESTCOLOR         = 9
Const D3DBLEND_INVDESTCOLOR      = 10
Const D3DBLEND_SRCALPHASAT       = 11
Const D3DBLEND_BOTHSRCALPHA      = 12
Const D3DBLEND_BOTHINVSRCALPHA   = 13
Const D3DBLEND_FORCE_DWORD       = $7fffffff	;force 32-bit size enum



Const D3DRS_ANTIALIAS          = 2    ; D3DANTIALIASMODE */
Const D3DRS_TEXTUREPERSPECTIVE = 4    ; True For perspective correction */
Const D3DRS_ZENABLE            = 7    ; D3DZBUFFERTYPE (Or True/False For legacy) */
Const D3DRS_FILLMODE           = 8    ; D3DFILL_MODE        */
Const D3DRS_SHADEMODE          = 9    ; D3DFILL_MODE */
Const D3DRS_LINEPATTERN        = 10   ; D3DLINEPATTERN */
Const D3DRS_ZWRITEENABLE       = 14   ; True To enable z writes */
Const D3DRS_ALPHATESTENABLE    = 15   ; True To enable alpha tests */
Const D3DRS_LASTPIXEL          = 16   ; True For Last-pixel on lines */
Const D3DRS_SRCBLEND           = 19   ; D3DBLEND */
Const D3DRS_DESTBLEND          = 20   ; D3DBLEND */
Const D3DRS_CULLMODE           = 22   ; D3DCULL */
Const D3DRS_ZFUNC              = 23   ; D3DCMPFUNC */
Const D3DRS_ALPHAREF           = 24   ; D3DFIXED (long) */
Const D3DRS_ALPHAFUNC          = 25   ; D3DCMPFUNC */
Const D3DRS_DITHERENABLE       = 26   ; True To enable dithering */
Const D3DRS_ALPHABLENDENABLE   = 27   ; True To enable alpha blending */
Const D3DRS_FOGENABLE          = 28   ; True To enable fog blending */
Const D3DRS_SPECULARENABLE     = 29   ; True To enable specular */
Const D3DRS_ZVISIBLE           = 30   ; True To enable z checking */
Const D3DRS_STIPPLEDALPHA      = 33   ; True To enable stippled alpha (RGB device only) */
Const D3DRS_FOGCOLOR           = 34   ; D3DCOLOR */  INT (((a) << 24) Or ((r) << 16) Or ((g) << 8) Or (b)))
Const D3DRS_FOGTABLEMODE       = 35   ; D3DFOGMODE */
Const D3DRS_FOGSTART           = 36   ; Float Fog start (For both vertex And pixel fog) 
Const D3DRS_FOGEND             = 37   ; Float Fog End      */
Const D3DRS_FOGDENSITY         = 38   ; Fog density  */
Const D3DRS_EDGEANTIALIAS      = 40   ; True To enable edge antialiasing */
Const D3DRS_COLORKEYENABLE     = 41   ; True To enable source colorkeyed textures */
Const D3DRS_ZBIAS              = 47   ; LONG Z bias */
Const D3DRS_RANGEFOGENABLE     = 48   ; Enables range-based fog */

; *** STENCIL OPS ***
Const D3DRS_STENCILENABLE      = 52   ; BOOL enable/disable stenciling
Const D3DRS_STENCILFAIL        = 53   ; D3DSTENCILOP To do If stencil test fails
Const D3DRS_STENCILZFAIL       = 54   ; D3DSTENCILOP To do If stencil test passes And Z test fails
Const D3DRS_STENCILPASS        = 55   ; D3DSTENCILOP To do If both stencil And Z tests pass */
Const D3DRS_STENCILFUNC        = 56   ; D3DCMPFUNC fn.  Stencil Test passes If ((ref & mask) stencilfn (stencil & mask)) is True */
Const D3DRS_STENCILREF         = 57   ; INT Reference value used in stencil test */
Const D3DRS_STENCILMASK        = 58   ; Mask value used in stencil test  e.g (0xffffffff)
Const D3DRS_STENCILWRITEMASK   = 59   ; Write mask applied To values written To stencil buffer e.g (0xffffffff)
Const D3DRS_TEXTUREFACTOR      = 60   ; D3DCOLOR used For multi-texture blend */

Const D3DCLEAR_TARGET					= $00000001	;Clear target surface
Const D3DCLEAR_ZBUFFER				= $00000002	;Clear target z buffer
Const D3DCLEAR_STENCIL				= $00000004	;Clear Stencil


;ERRORS
Const D3DERR_ZBUFFER_NOTPRESENT					= 2070
Const D3DERR_STENCILBUFFER_NOTPRESENT		= 2071
Const D3DERR_VIEWPORTHASNODEVICE				= 774
Const DDERR_INVALIDOBJECT								= 130
Const DDERR_INVALIDPARAMS								= $80070057

Type BBRect
	Field x1%
	Field lX1%

	Field y1%
	Field lY1%

	Field x2%
	Field lX2%
	
	Field y2%
  Field lY2%
End Type

Graphics3D 1027,768,32,2

Direct3D7=SystemProperty$("Direct3D7")
Direct3DDevice7=SystemProperty$("Direct3DDevice7")
DirectDraw7=SystemProperty$("DirectDraw7")
DirectInput7=SystemProperty$("DirectInput7")
AppHWND=SystemProperty$("AppHWND")
AppHINSTANCE=SystemProperty$("AppHINSTANCE")




cam=CreateCamera()
piv=CreatePivot()
PositionEntity cam,-5,3,-5
PointEntity cam,piv
CameraRange cam,.1,50

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

tex=CreateTexture(512,512)
ScaleTexture tex,.2,.5
SetBuffer TextureBuffer(tex)
Color 100,100,100
Rect 0,0,512,512
Color 200,200,200
Rect 8,8,496,496
Color 255,255,255
SetBuffer BackBuffer()

cyl1=CreateCylinder()
EntityAlpha cyl1,.3
PositionEntity cyl1,2,0,0
ScaleEntity cyl1,3,3,3

cyl2=CreateCylinder()
EntityAlpha cyl2,.3
PositionEntity cyl2,2,0,5
ScaleEntity cyl2,3,3,3

cube=CreateCube()
PositionEntity cube,0,0,0
ScaleEntity cube,5,.2,10
EntityTexture cube,tex



spa#=.3
shadowplane=CreateCube() ; squished Z cube infront of cam
ScaleMesh shadowplane,10,10,.01
EntityParent shadowplane,cam,0
MoveEntity shadowplane,0,0,.2
EntityColor shadowplane,0,0,0
EntityAlpha shadowplane,spa#
;Shadow plane is the object infront of the screen which is drawn where
;the stencil shadow should be drawn (on certain pixels). It means that
;where the shadow volume and scenery intersect, that is where the plane
;will be drawn. Because the color is black, and alpha is spa# its darkness
;will depend on spa#. You can put any other object in its place...


sv=1

; AREA TO CLEAR
r.BBRect=New BBRect
r\lX1=0
r\lY1=0
;r\lX2=GraphicsWidth()/2 ; half the screen (used to show what happens if only half the screen is cleared)
r\lX2=GraphicsWidth() 
r\lY2=GraphicsHeight()


CameraClsMode cam,False,False

While Not KeyHit(1)

.start
	PositionEntity cyl1,(MouseX()-(GraphicsWidth()*.5)) * .01,-(MouseY()-(GraphicsWidth()*.5)) * .02,0
	PositionEntity cyl2,(MouseX()-(GraphicsWidth()*.5)) * .01,-(MouseY()-(GraphicsWidth()*.5)) * .02,2
	
	
	t=MilliSecs()

	;-----------------------------------------------------------------------------------render start	
	HideEntity shadowplane;1-hide plane
	;I =think= that it might be better to hide the volumes here
	HideEntity cyl1  ;1a-hide volumes
	HideEntity cyl2 
	ShowEntity cube  ;2-show scene

	SetRenderState(Direct3DDevice7, D3DRS_ZWRITEENABLE, True) 
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE, False)
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, False)


;	DeviceClear2(Direct3DDevice7, r, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER Or D3DCLEAR_STENCIL,$00008080,1.0,0)
;	RenderWorld 
DeviceClear(Direct3DDevice7, 7,$00008080,1,0)
CameraClsMode cam,True,True
RenderWorld
CameraClsMode cam,False,False


	ShowEntity cyl1 ;3-show volume
	ShowEntity cyl2
	HideEntity cube ;4-hide scene


; *** RenderShadow() START *** -------- << name of the function as found in C++ DX7SDK examples


	SetRenderState(Direct3DDevice7, D3DRS_ZWRITEENABLE,False)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE,True)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILFUNC, D3DCMP_ALWAYS)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILREF, 1)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILMASK,$ffffffff)
	SetRenderState(Direct3DDevice7, D3DRS_STENCILWRITEMASK,$ffffffff)

	SetRenderState(Direct3DDevice7, D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR)
	
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, True)
	SetRenderState(Direct3DDevice7, D3DRS_SRCBLEND, D3DBLEND_ZERO)
	SetRenderState(Direct3DDevice7, D3DRS_DESTBLEND, D3DBLEND_ONE)
	
	RenderWorld	
	
	SetRenderState(Direct3DDevice7, D3DRS_CULLMODE, D3DCULL_CW)
	RenderWorld
	
	SetRenderState(Direct3DDevice7, D3DRS_CULLMODE, D3DCULL_CCW)
	
	SetRenderState(Direct3DDevice7, D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR)
	RenderWorld 
	
	SetRenderState(Direct3DDevice7, D3DRS_ZWRITEENABLE,     True )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE,    False )
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, False )			
	

	
; *** RenderShadow() END *** --------



; *** DrawShadow() START *** -----------  << name of the function as found in C++ DX7SDK examples
	SetRenderState(Direct3DDevice7, D3DRS_ZENABLE,       False )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE, True )
	SetRenderState(Direct3DDevice7, D3DRS_FOGENABLE, False)	

	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, True )
	SetRenderState(Direct3DDevice7, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA )
	SetRenderState(Direct3DDevice7, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA )

	SetRenderState(Direct3DDevice7, D3DRS_STENCILREF,  1 )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP )

	ShowEntity shadowplane ;5-show plane
	RenderWorld

	SetRenderState(Direct3DDevice7, D3DRS_ZENABLE,          True )
	SetRenderState(Direct3DDevice7, D3DRS_STENCILENABLE,    False )
	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, True )

; *** DrawShadow() END *** -----------

	HideEntity shadowplane ;6-hide plane

	RenderWorld;--------------------------------------------------------------------------render end
	

	SetRenderState(Direct3DDevice7, D3DRS_ALPHABLENDENABLE, False )
	Text 0,0,"Move cylinders (volumes) with mouse/"+"     MS: "+(MilliSecs() - t)
	Text 0,10,"Shadow Alpha: "+spa+ "    LMB/RMB to change value, SPACE to toggle visibility"
	Text 0,20, "A/Z to move back/forward. Enter the volumes and see that it works."

	If MouseDown(1)
		spa=spa-.01
		If spa<0 spa=0
		EntityAlpha shadowplane,spa
	Else If MouseDown(2)
		spa=spa+.01
		If spa>1.0 spa=1.0
		EntityAlpha shadowplane,spa
	End If
	
	If KeyHit(30)
		MoveEntity cam, 0,0,0.1
	End If
	
	If KeyHit(44)
		MoveEntity cam, 0,0,-0.1
	End If	
	

	If KeyHit(57)
		sv=Not sv
		If sv
			EntityAlpha cyl1,.3
			EntityAlpha cyl2,.3
		Else
			EntityAlpha cyl1,0.001
			EntityAlpha cyl2,0.001
		End If
	End If
	
	If KeyHit(24) tra=Not tra 


Flip

Wend


End








Type volumes
	Field mesh
End Type

Function CreateVolume(entity, light)
;entity - the entity that casts the shadow
;light - the light entity from which the light
;
;This function is included in case somebody wants to build shadow volumes and try stuff out.
;This is fairly slow because it extrudes and caps every triangle on a mesh. This means
;that 6 times more triangles need to be made for each one on the mesh.
;(I tried faster methods but trust me its not easy)
;It may be useful only for very basic geometry.


lx#=EntityX(light,True)
ly#=EntityY(light,True)
lz#=EntityZ(light,True)

	a_vol.volumes=New volumes
		a_vol\mesh=CreateMesh()
		
		;EntityBlend a_vol\mesh,2
		;EntityFX a_vol\mesh,1
		EntityColor a_vol\mesh,0,0,0
		EntityAlpha a_vol\mesh,0.001

		volsurf=CreateSurface(a_vol\mesh)
		numsurf=CountSurfaces(entity)		
		vpos=CreatePivot()
		vposend=CreatePivot()
		VolumeDepth#=1000
		
		
		
		;For surfcount=1 To numsurf-1
		surfcount=1

		While surfcount <= numsurf
			cursurface=GetSurface(entity, surfcount)
			maxtricount=CountTriangles (cursurface)
			;For tricount=0 To tricount-1
							
			While tricount < maxtricount
			v1x#=VertexX(cursurface, TriangleVertex(cursurface, tricount, 0))
			v1y#=VertexY(cursurface, TriangleVertex(cursurface, tricount, 0))
			v1z#=VertexZ(cursurface, TriangleVertex(cursurface, tricount, 0))
			TFormPoint v1x#,v1y#,v1z#, entity, 0
			v1x#=TFormedX()
			v1y#=TFormedY()
			v1z#=TFormedZ()
			
			v2x#=VertexX(cursurface, TriangleVertex(cursurface, tricount, 1))
			v2y#=VertexY(cursurface, TriangleVertex(cursurface, tricount, 1))
			v2z#=VertexZ(cursurface, TriangleVertex(cursurface, tricount, 1))			
			TFormPoint v2x#,v2y#,v2z#, entity, 0
			v2x#=TFormedX()
			v2y#=TFormedY()
			v2z#=TFormedZ()
			
			v3x#=VertexX(cursurface, TriangleVertex(cursurface, tricount, 2))
			v3y#=VertexY(cursurface, TriangleVertex(cursurface, tricount, 2))
			v3z#=VertexZ(cursurface, TriangleVertex(cursurface, tricount, 2))
			TFormPoint v3x#,v3y#,v3z#, entity, 0
			v3x#=TFormedX()
			v3y#=TFormedY()
			v3z#=TFormedZ()
			
			
			PositionEntity vpos,v1x#,v1y#,v1z#
			PositionEntity vposend, lx#,ly#,lz#,1
			PointEntity vposend, vpos
			MoveEntity vposend, 0,0,VolumeDepth#
			v1xe#=EntityX(vposend, True)
			v1ye#=EntityY(vposend, True)
			v1ze#=EntityZ(vposend, True)
			
			PositionEntity vpos,v2x#,v2y#,v2z#
			PositionEntity vposend, lx#,ly#,lz#,1
			PointEntity vposend, vpos
			MoveEntity vposend, 0,0,VolumeDepth#
			v2xe#=EntityX(vposend, True)
			v2ye#=EntityY(vposend, True)
			v2ze#=EntityZ(vposend, True)
			
			PositionEntity vpos,v3x#,v3y#,v3z#
			PositionEntity vposend, lx#,ly#,lz#,1
			PointEntity vposend, vpos
			MoveEntity vposend, 0,0,VolumeDepth#
			v3xe#=EntityX(vposend, True)
			v3ye#=EntityY(vposend, True)
			v3ze#=EntityZ(vposend, True)
			
			v1=AddVertex(volsurf,v1x#,v1y#,v1z#)
			v1e=AddVertex(volsurf,v1xe#,v1ye#,v1ze#)
			v2=AddVertex(volsurf,v2x#,v2y#,v2z#)
			v2e=AddVertex(volsurf,v2xe#,v2ye#,v2ze#)
			v3=AddVertex(volsurf,v3x#,v3y#,v3z#)
			v3e=AddVertex(volsurf,v3xe#,v3ye#,v3ze#)			

			AddTriangle (volsurf, v1,v1e,v2)
			AddTriangle (volsurf, v2,v1e,v2e)
			AddTriangle (volsurf, v1,v3,v1e)
			AddTriangle (volsurf, v3,v3e,v1e)
			AddTriangle (volsurf, v3,v2,v3e)
			AddTriangle (volsurf, v2,v2e,v3e)
			AddTriangle (volsurf, v1,v2,v3) 	;cap top
			AddTriangle (volsurf, v1e,v2e,v3e) 	;cap bottom			
			
			tricount=tricount+1
			Wend 
			;Next		
		surfcount=surfcount+1
		Wend
		;Next

FreeEntity vpos
FreeEntity vposend

End Function

Function HideVolumes()
	For a_vol.volumes=Each volumes
		HideEntity a_vol\mesh
	Next
End Function
Function ShowVolumes()
	For a_vol.volumes=Each volumes
		ShowEntity a_vol\mesh
	Next
End Function
Function DeleteVolumes()
	For a_vol.volumes=Each volumes
		FreeEntity a_vol\mesh
		Delete a_vol
	Next
End Function



You also need V1.88 of blitz3d running.

jfk, i heard Mark may be working on stencil shadows for BMax and may just convert them to blitz3d so lets wait for a bit and see what he does. If you dont want to wait, email me (email provided in my details) and i'll reply to you with the stuff i think can be done.

Yep, that works here on ATI where the previous one didn't. Nice!

Good!

Lenn, thanks. Well, I think I'll wait and see :)

Works fine now.

Great stuff Lenn, works fine here now :)

wasn't someone trying to get this code working with animated *.B3d files? I'm still very interested in that... and I agree... this should be intergrated into Bitz3d... (that would make it faster, right?) Very kewl... it does remind me of the shadows in DOOM3... great work :D

Still gettin function "setrenderstate" no found.
:(

I think the important thing is :

Did you update your drivers for ATI?

I had no probs. I am using an ATI Radeon 7000 on a Athlon 64 3200+ with 1 gig...etc...

-RZ

Canali, you should read the first post completely and it says

get the code from the box below and the needed userlibs from:
www.geocities.com/spirala7/dx7sshad.htm


make sure you do that, and put the files into the userlibs folder

Rook, you should read the entire thread, it says...

Beaker: I think Tom (who made the original DLL) sorted any ATI glitch issues...

Lenn: Yes, i just posted the wrong version which was not fixed. Here is the fixed version...


Make sure you do that and you'll discover it was fixed well before you posted ;)

You also need V1.88 of blitz3d running.

Where does one get v1.88 from?

Check the forum called 'Blitz 3d Updates' - there's a post in there with the latest upgrades in.

I get a "function SetRenderState not found" error even after updating to 1.88

The example runs, but I don,t see shadows, like the screenshot has. I just see two alpha cylinders.
Prosavage graphics.

It works for me, i have geforce fx 5200 or something. just had to update blitz3d and put the dll and decls file in the userlib folder : )

@RiverRatt
Prosavage onboard video or (savage4 cards) , have a stencil buffer.
You may need to turn it on in the cards control panel.
and on some cards it wont work with a 32bit Zbuffer

Zmatrix

Hi there,

If you want to test my shadow contribution to this thread, please download the file.
http://www.spacemonkeys.dk/blitz/CVC-SDtest.rar

I want to improve my edge method before a release :)


First Anim Test... use key 1,2,3
http://www.spacemonkeys.dk/blitz/CVC-SDtestAnim.rar

This is what I see with the Amin Test



I have a Geforce 440mx so it should support stencil shadows .. at least all the other demos I tried worked?

@Spacemonkey
I have about the same picture as Stevie G - a green donut and a cute figure appears after long press on 2 running the Anim
The other shows 2 donuts (red and green) but the result on the floor looks as in the above picture.
The Demos above were working.

Strange! I use the same main loop as Lenn..
Is this the same all over?

hm... if i use this, the self-shadding looks a lil bit strange!?!
why is this so?

Very nice work here. I'm wondering though. Can that shader.dll be used to allow us tron glow effects that are stated here in this thread?

http://collective.valve-erc.com/index.php?go=tron2