This is something I made a while ago. It is rather versitile, as you can apply shadow properties with a simple function and it is easy to implement and has support for colored shadows and transparent object shadows. Unfortunately, however, it is slow. It is kinda a modified version of Halo's demo that uses types instead of arrays plus some other goodies to make it more portable (and practical). The other problem is it can take a while to load a mesh with a large number of tris because of the algorithm it uses. It is in desperate need for a rewrite but you can use it for whatever you want.
;;;;;;;;;;;;;;;;;;;;; ;Shadows............; ;Michael Scherer....; ;[Tainted Instinct].; ;;;;;;;;;;;;;;;;;;;;; Global FPS,LastCheck,Frames Function GetFPS() Frames = Frames + 1 If MilliSecs() > LastCheck+1000 Then LastCheck = MilliSecs() FPS = Frames Frames = 0 EndIf Return FPS End Function Graphics3D 800,600 AntiAlias True ;COLLISON TYPES Const shadowCOL = 1, terrainCOL = 2 ;SHADOWMESH/SHADOWVERTEX TYPES Type shadowmesh Field entity,shadow ;the entity handle and its shadow Field alpha# ;for meshes that are see-through End Type Type shadowvertex Field surf,tri,index ;exact location of vertex Field entity ;the pivot Field parent ;which shadowmesh this vertex belongs to End Type ;CREATE A SHADOWMESH Function shadowmesh(mesh,alpha#,r,g,b) s.shadowmesh = New shadowmesh s\entity = mesh s\shadow = CopyMesh(mesh) EntityFX s\shadow,1 EntityColor s\shadow,r,g,b EntityAlpha s\shadow,.5 ;changes based on distance from light s\alpha# = alpha# ;get all vertex positions For sf = 1 To CountSurfaces(s\entity) surf = GetSurface(s\entity,sf) For t = 0 To CountTriangles(surf)-1 For i = 0 To 2 ;vert = TriangleVertex(surf,t,i) sv.shadowvertex = New shadowvertex sv\surf = sf : sv\tri = t : sv\index = TriangleVertex(surf,t,i) ;sv\x# = VertexX#(surf,i) : sv\y# = VertexY#(surf,i) : sv\z# = VertexZ#(surf,i) sv\entity = CreatePivot() PositionEntity sv\entity, VertexX#(surf,sv\index), VertexY#(surf,sv\index), VertexZ#(surf,sv\index) EntityType sv\entity,shadowCOL ;EntityRadius sv\entity,.001 sv\parent = Handle(s) Next Next Next ;eliminate redundant vertices For s1.shadowvertex = Each shadowvertex For s2.shadowvertex = Each shadowvertex If Handle(s1) <> Handle(s2) If s1\parent = s2\parent And s1\surf = s2\surf And s1\index = s2\index FreeEntity s2\entity Delete s2 EndIf EndIf Next Next Return Handle(s) ;return the shadowmesh handle just in case End Function ;THE LIGHT TYPE Type shadowlight Field entity Field x#,y#,z# Field range# End Type ;BUILD A LIGHT Function shadowlight(x#,y#,z#,range#) l.shadowlight = New shadowlight l\entity = CreateLight(2) LightRange l\entity,range# PositionEntity l\entity,x#,y#,z# l\x# = x# : l\y# = y# : l\z# = z# l\range# = range# Return Handle(l) ;return the lights handle just in case End Function ;a shadow mesh cube = CreateSphere() ;ScaleMesh cube,.2,.2,.2 EntityColor cube,255,0,0 EntityAlpha cube,.5 shadowmesh(cube,.5,255,0,0) ;set it as a shadow mesh PositionEntity cube,0,0,0 cube2 = CreateCube() PositionEntity cube2,3,0,-3 shadowmesh(cube2,1,0,0,0) cube3 = CreateSphere(3) PositionEntity cube3,-3,0,-3 shadowmesh(cube3,1,0,0,0) ;a light light = shadowlight(2,5,2,10) lightspright = CreateSprite() ;he he lightspright, get it? just a placemarker PositionEntity lightspright,2,5,2 tex=CreateTexture(128,128) SetBuffer TextureBuffer(tex) Rect 0,0,28,128 Rect 0,100,128,28 SetBuffer BackBuffer() EntityTexture lightspright,tex FreeTexture tex ;plane to put the shadows on plane = CreatePlane(16) EntityType plane,terrainCOL PositionEntity plane,0,-5,0 tex=CreateTexture(128,128) SetBuffer TextureBuffer(tex) Color 0,128,0 Rect 0,0,128,128 SetBuffer BackBuffer() EntityTexture plane,tex FreeTexture tex ;camera to see the shadows with Global cam = CreateCamera() RotateEntity cam,15,0,0 PositionEntity cam,0,5,-20 ;LET THE VERTICES COLLIDE WITH TERRAIN Collisions shadowCOL,terrainCOL,2,1 SetBuffer BackBuffer() CameraClsColor cam,0,255,255 Color 255,255,255 While Not KeyDown(1) PositionShadows() UpdateWorld RenderWorld UpdateShadows() l.shadowlight = Object.shadowlight(light) If KeyDown(205) Then MoveEntity l\entity, .1,0,0 If KeyDown(203) Then MoveEntity l\entity,-.1,0,0 If KeyDown(208) Then MoveEntity l\entity,0,0,-.1 If KeyDown(200) Then MoveEntity l\entity,0,0, .1 PositionEntity lightspright, EntityX#(l\entity),EntityY#(l\entity),EntityZ#(l\entity) TurnEntity cube2,.1,.2,.3 TurnEntity cube3,.2,.3,.4 ;debugging------------------ If CommandLine$() = "/debug" For l.shadowlight = Each shadowlight CameraProject cam,l\x#,l\y#,l\z# x# = ProjectedX() : y# = ProjectedY() WritePixel ProjectedX(),ProjectedY(),$ffff00 For sv.shadowvertex = Each shadowvertex CameraProject cam,EntityX#(sv\entity, True),EntityY#(sv\entity, True),EntityZ#(sv\entity, True) Line x#,y#,ProjectedX(),ProjectedY() Next Next EndIf Text 0,0,GetFPS() ;Screen Shot If KeyHit(88) SaveBuffer(BackBuffer(),"screen"+s+".bmp") s = s + 1 EndIf Flip Wend ;POSITION ALL SHADOW'S VERTICES Function PositionShadows() ;hide the shadows For s.shadowmesh = Each shadowmesh HideEntity s\shadow Next piv = CreatePivot() For l.shadowlight = Each shadowlight l\x# = EntityX#(l\entity, True) : l\y# = EntityY#(l\entity, True) : l\z# = EntityZ#(l\entity, True) PositionEntity piv,l\x#,l\y#,l\z# For s.shadowmesh = Each shadowmesh entdist# = EntityDistance#(s\entity,piv) If entdist# <= l\range# ;since we are in the light range, show the shadow ShowEntity s\shadow ;apply appropriate alpha level EntityAlpha s\shadow, (1-(entdist#/l\range#))*s\alpha# ;now we position its vertices For sv.shadowvertex = Each shadowvertex If sv\parent = Handle(s) ;Make sure the vertex belongs to this mesh PositionEntity sv\entity,l\x#,l\y#,l\z# ;put the vertex at the light surf = GetSurface(s\entity,sv\surf) x# = VertexX#(surf,sv\index) : y# = VertexY#(surf,sv\index) : z# = VertexZ#(surf,sv\index) TFormPoint( x#, y#, z#, s\entity, 0 ) x# = TFormedX#() : y# = TFormedY#() : z# = TFormedZ#() PositionEntity piv,x#,y#,z# PointEntity sv\entity,piv ResetEntity sv\entity MoveEntity sv\entity,0,0,99999 EndIf Next EndIf Next If CommandLine$() = "/debug" CameraProject cam,l\x#,l\y#,l\z# WritePixel ProjectedX(),ProjectedY(),$ffff00,FrontBuffer() EndIf Next FreeEntity piv End Function ;UPDATE ALL SHADOWS Function UpdateShadows() For s.shadowmesh = Each shadowmesh For sv.shadowvertex = Each shadowvertex If sv\parent = Handle(s) surf = GetSurface(s\shadow,sv\surf) VertexCoords( surf,sv\index, EntityX#(sv\entity, True), EntityY#(sv\entity, True), EntityZ#(sv\entity, True) ) If CommandLine$() = "/debug" CameraProject cam,EntityX#(sv\entity),EntityY#(sv\entity),EntityZ#(sv\entity) WritePixel ProjectedX(),ProjectedY(),$ff0000,BackBuffer() verts = verts+1 EndIf EndIf Next UpdateNormals s\shadow Next If CommandLine$() = "/debug" Text 0,0,verts EndIf End Function