After i ported my soundlib and the ODE package to Basic4GL
Tom the author of Basic4GL added subs and functions here my test for stencil shadows.
Joshy
http://shiny3d.de/public/stencilshadow.exe
The speed is not bad for a virtual machine.
Basic4GL used "#" to declare function that will return a SINGLE value
"%" is the mod oparator and pointers are declared as '&'
the rest locks same as FreeBASIC.
Code: Select all
' stencil buffer shadows
' example of using functions and sub's and pointers
' use menu Basic4GL->Options...Advanced->Enabled Stencil buffer[x]
const MaxObjectsPerWorld=20
const MaxPointsPerObject=30
const MaxFacesPerObject =40
type Plane_t
a as single
b as single
c as single
d as single
end type
type Face_t
PointIndex(2) as integer
Normale(2) as single
Neighbors(2) as integer
Plane as Plane_t
Visible as integer
end type
type Object_t
strType as String
Position(2) as single
Rotation(2) as single
Size(2) as single
ColorRGBA(3) as single
nPoints as integer
nFaces as integer
Points(MaxPointsPerObject-1,2) as single
Faces (MaxFacesPerObject -1) as Face_t
end type
type World_t
nObjects as integer
Objects(MaxObjectsPerWorld-1) as Object_t
end type
' prototypes
declare function GetInvers#(o as OBJECT_T,v() as single)()
declare sub CastShadow(o as OBJECT_T,v() as single,IsLastObject as integer)
declare sub InitObject(&o as OBJECT_T)
declare sub BuildNormals(&o as OBJECT_T)
declare sub BuildPlane(&o as OBJECT_T,&f as FACE_T)
declare sub DrawObject(o as OBJECT_T)
declare Sub DrawRoom()
declare sub DrawLights()
LabelWorld3D:
' number of objects
data 12
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
data "BOX3D"
LabelUnitBox3D:
' number of points
data 8
' front side
data -0.5, 0.5,0.5
data -0.5,-0.5,0.5
data 0.5,-0.5,0.5
data 0.5, 0.5,0.5
' back side
data 0.5, 0.5,-0.5
data 0.5,-0.5,-0.5
data -0.5,-0.5,-0.5
data -0.5, 0.5,-0.5
LabelBox3D:
' number of faces
data 12
' faces
data 0,1,2 ' front
data 0,2,3
data 3,2,5 ' right
data 3,5,4
data 4,5,6 ' back
data 4,6,7
data 7,6,1 ' left
data 7,1,0
data 7,0,3 ' top
data 7,3,4
data 1,6,5 ' bottom
data 1,5,2
LabelObjects3D:
' 3x3 raster with 9 boxes
data -4,-5,-20 ' object position
data 2, 2, 2 ' object size
data 0,-5,-20 ' ...
data 2, 2, 2 ' ...
data 4,-5,-20
data 2, 2, 2
data -4,-6,-15
data 2, 2, 2
data 0,-6,-15
data 2, 2, 2
data 4,-6,-15
data 2, 2, 2
data -4,-7,-10
data 2, 2, 2
data 0,-7,-10
data 2, 2, 2
data 4,-7,-10
data 2, 2, 2
' 3 boxes
data -5,-1,-20 ' box1 position
data 1,2,3 ' size
data 0,-1,-17 ' box2 position
data 5, 2,0.5 ' size
data 5,-1,-14 ' box3 position
data 2,2,2 ' size
const camz#=20
dim World as World_t
dim &pObject as OBJECT_T
dim &pFace as Face_t
dim Point(2) as single
dim Vector(3) as single
' counters object, points, faces, lights
dim oc as integer
dim pc as integer
dim fc as integer
dim lc as integer
dim i as integer
dim LastObject as integer
dim LightAmb(2,3) as single
dim LightDif(2,3) as single
dim LightSpc(2,3) as single
dim LightPos(2,3) as single
dim LightTexture as integer
dim wStep as single
dim MatAmb(3) as single
dim MatDif(3) as single
dim MatSpc(3) as single
dim MatShn as single
' try to get the texture
LightTexture = LoadTexture("star.bmp")
if LightTexture=0 then
LightTexture = LoadTexture("data/star.bmp")
if LightTexture=0 then
LightTexture = LoadTexture("Programs/data/star.bmp")
end if
end if
' lights and material properties
LightAmb(0)=Vec4(0.3,0.3,0.3 ,1)
LightDif(0)=Vec4(0.5,0.5,0.5, 1)
LightSpc(0)=Vec4(1,0,0, 1)
LightPos(0)=Vec4(-7,6,-10,1)
LightAmb(1)=Vec4(0.3,0.3,0.3 ,1)
LightDif(1)=Vec4(0.5,0.5,0.5, 1)
LightSpc(1)=Vec4(0,1,0, 1)
LightPos(1)=Vec4(0,6,-10,1)
LightAmb(2)=Vec4(0.3,0.3,0.3 ,1)
LightDif(2)=Vec4(0.5,0.5,0.5, 1)
LightSpc(2)=Vec4(0,0,1, 1)
LightPos(2)=Vec4( 7,6,-10,0)
MatAmb =Vec4(0.01, 0.01, 0.01, 1.0)
MatDif =Vec4(0.5, 0.5, 0.5, 1.0)
MatSpc =Vec4(0.75, 0.75, 0.75, 1.0)
MatShn =15.0
' a short world
' in this case simple from DATA statements
reset LabelWorld3D
read World.nObjects
for oc=0 to World.nObjects-1
read World.Objects(oc).strType
next
for oc=0 to World.nObjects-1
reset LabelUnitBox3D
&pObject=&World.Objects(oc)
read pObject.nPoints
for pc=0 to pObject.nPoints-1
for i=0 to 2:read pObject.Points(pc,i):next
next
if pObject.strType="BOX3D" then
reset LabelBox3D
end if
read pObject.nFaces
for fc=0 to pObject.nFaces-1
for i=0 to 2:read pObject.Faces(fc).PointIndex(i):next
next
next
reset LabelObjects3D
for oc=0 to World.nObjects-1
&pObject=&World.Objects(oc)
for i=0 to 2:read pObject.Position(i):next
for i=0 to 2:read pObject.Size(i):next
for pc=0 to pObject.nPoints-1
for i=0 to 2
pObject.Points(pc,i)=pObject.Points(pc,i)*pObject.Size(i)
next
next
InitObject(pObject)
for fc=0 to pObject.nFaces-1
&pFace=&pObject.Faces(fc)
BuildPlane(pObject,pFace)
next
BuildNormals(pObject)
next
'
' main
'
glMatrixMode (GL_PROJECTION)
glLoadIdentity()
gluPerspective(50.0, WindowWidth()/WindowHeight(), 0.1, 10000.0)
glMatrixMode (GL_MODELVIEW)
glShadeModel (GL_SMOOTH)
glClearColor (0,0,0,1)
glClearDepth (1)
glClearStencil(0)
glEnable (GL_DEPTH_TEST)
glDepthFunc (GL_LEQUAL)
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
for lc=0 to 2
glLightfv(GL_LIGHT0+lc, GL_AMBIENT ,LightAmb(lc))
glLightfv(GL_LIGHT0+lc, GL_DIFFUSE ,LightDif(lc))
glLightfv(GL_LIGHT0+lc, GL_SPECULAR,LightSpc(lc))
glEnable (GL_LIGHT0+lc)
next
glEnable (GL_LIGHTING)
glMaterialfv(GL_FRONT, GL_AMBIENT ,MatAmb)
glMaterialfv(GL_FRONT, GL_DIFFUSE ,MatDif)
glMaterialfv(GL_FRONT, GL_SPECULAR ,MatSpc)
glMaterialf (GL_FRONT, GL_SHININESS,MatShn)
glCullFace(GL_BACK)
glEnable (GL_CULL_FACE)
while True
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0.0, 0.0, -camz#)
' animate the lights
for lc=0 to 2
LightPos(lc,0)= cos(wStep+lc*1.57)*6
LightPos(lc,1)= 4+sin(wStep*3)
LightPos(lc,2)=-camz#*0.5+ sin(wStep+lc*1.57)*10
glLightfv(GL_LIGHT0+lc, GL_POSITION, LightPos(lc))
wStep=wStep+0.01
next
' draw the world
glLoadIdentity()
glTranslatef(0.0, 0.0, -camz#)
DrawRoom()
for oc=0 to World.nObjects-1
&pObject=&World.Objects(oc)
glLoadIdentity()
glTranslatef(0,0,-camz#)
DrawObject(pObject)
' animate the objects
for i=0 to 2
pObject.Rotation(i)=pObject.Rotation(i)+(1+oc)*((i+1)*0.1)
next
next
' build and draw shadow volumes for every light
for oc=0 to World.nObjects-1
&pObject=&World.Objects(oc)
glLoadIdentity()
glTranslatef(0,0,-camz#)
glTranslatef(pObject.Position(0),pObject.Position(1),pObject.Position(2))
glRotatef (pObject.Rotation(0), 1,0,0)
glRotatef (pObject.Rotation(1), 0,1,0)
glRotatef (pObject.Rotation(2), 0,0,1)
for lc=0 to 2
Vector=GetInvers#(pObject,LightPos(lc))
LastObject=((World.nObjects-1)=oc) and (lc=2)
CastShadow(pObject,Vector,LastObject)
next
next
DrawLights()
SwapBuffers()
wend
end
' calc face Neighbors from Object
' based on Gamasutra's article
sub InitObject(&o as OBJECT_T)
dim p1i as integer
dim p2i as integer
dim p1j as integer
dim p2j as integer
dim b1i as integer
dim b2i as integer
dim b1j as integer
dim b2j as integer
dim p1i_p_p2i as integer
dim p1i_m_p2i as integer
dim p1j_p_p2j as integer
dim p1j_m_p2j as integer
dim Face1 as integer
dim Face2 as integer
dim Edge1 as integer
dim Edge2 as integer
for Face1=0 to o.nFaces-2
for Face2=Face1+1 to o.nFaces-1
for Edge1=0 to 2
if o.Faces(Face1).Neighbors(Edge1) = 0 then
for Edge2=0 to 2
p1i=o.Faces(Face1).PointIndex(Edge1)
p2i=o.Faces(Face1).PointIndex((Edge1+1) % 3)
p1j=o.Faces(Face2).PointIndex(Edge2)
p2j=o.Faces(Face2).PointIndex((Edge2+1) % 3)
p1i_p_p2i=p1i+p2i
p1i_m_p2i=abs(p1i-p2i)
p1j_p_p2j=p1j+p2j
p1j_m_p2j=abs(p1j-p2j)
b1i=(p1i_p_p2i-p1i_m_p2i)
b1j=(p1j_p_p2j-p1j_m_p2j)
'' they are neighbours
if (b1i=b1j) then
b2i=(p1i_p_p2i+p1i_m_p2i)
b2j=(p1j_p_p2j+p1j_m_p2j)
if (b2i=b2j) then
o.Faces(Face1).Neighbors(Edge1)=Face2+1
o.Faces(Face2).Neighbors(Edge2)=Face1+1
end if
end if
next
end if
next
next
next
end sub
' calc plane equation from Object and Face
sub BuildPlane(&o as OBJECT_T,&f as FACE_T)
dim v(2,2) as single
dim pc as integer
for pc=0 to 2
v(pc)=o.Points(o.Faces(fc).PointIndex(pc))
next
f.Plane.a =v(0,1)*(v(1,2)-v(2,2))+v(1,1)*(v(2,2)-v(0,2))+v(2,1)*(v(0,2)-v(1,2))
f.Plane.b =v(0,2)*(v(1,0)-v(2,0))+v(1,2)*(v(2,0)-v(0,0))+v(2,2)*(v(0,0)-v(1,0))
f.Plane.c =v(0,0)*(v(1,1)-v(2,1))+v(1,0)*(v(2,1)-v(0,1))+v(2,0)*(v(0,1)-v(1,1))
f.Plane.d = v(0,0)*(v(1,1)*v(2,2)-v(2,1)*v(1,2))
f.Plane.d = f.Plane.d + v(1,0)*(v(2,1)*v(0,2)-v(0,1)*v(2,2))
f.Plane.d = f.Plane.d + v(2,0)*(v(0,1)*v(1,2)-v(1,1)*v(0,2))
f.Plane.d =-f.Plane.d
end sub
' calc normals from Object.Faces
sub BuildNormals(&o as OBJECT_T)
dim a(2) as single
dim b(2) as single
dim fc as integer
for fc=0 to o.nFaces-1
a=o.Points(o.Faces(fc).PointIndex(1))-o.Points(o.Faces(fc).PointIndex(0))
b=o.Points(o.Faces(fc).PointIndex(2))-o.Points(o.Faces(fc).PointIndex(0))
o.Faces(fc).Normale=Normalize(CrossProduct(a,b))
next
end sub
' Draw Object with curent position and rotation
sub DrawObject(o as OBJECT_T)
dim fc as integer
dim pc as integer
glTranslatef(o.Position(0),o.Position(1),o.Position(2))
glRotatef (o.Rotation(0), 1,0,0)
glRotatef (o.Rotation(1), 0,1,0)
glRotatef (o.Rotation(2), 0,0,1)
glBegin(GL_TRIANGLES)
for fc=0 to o.nFaces-1
glNormal3fv(o.Faces(fc).Normale)
for pc=0 to 2
glVertex3fv(o.Points(o.Faces(fc).PointIndex(pc)))
next
next
glEnd()
end sub
' Multiply vector with invers matrix
function GetInvers#(o as OBJECT_T,v() as single)()
dim m(3,3) as single
dim t( 3) as single
glPushMatrix()
glLoadIdentity()
' now in reverse z,y,x order and negative position
glRotatef(-o.Rotation(2), 0.0, 0.0, 1.0)
glRotatef(-o.Rotation(1), 0.0, 1.0, 0.0)
glRotatef(-o.Rotation(0), 1.0, 0.0, 0.0)
glGetFloatv(GL_MODELVIEW_MATRIX,m)
' light position in worldspace
t=m*v
glTranslatef(-o.Position(0),-o.Position(1),-o.Position(2))
glGetFloatv(GL_MODELVIEW_MATRIX,m)
' light position in objectspace
t=m*Vec4(0,0,0,1)+t
glPopMatrix()
return t
end function
' Draw shadow volume from Object and Light position
sub CastShadow(o as OBJECT_T,v() as single,IsLastObject as integer)
dim v1(2) as single
dim v2(2) as single
dim p as PLANE_T
dim fc as integer
dim pi as integer
dim side as single
dim flag as integer
dim r as integer
dim i as integer
dim j as integer
dim k as integer
' faces visible from point of light?
for fc=0 to o.nFaces-1
p=o.Faces(fc).Plane
side=p.a*v(0)+p.b*v(1)+p.c*v(2)+p.d*v(3)
o.Faces(fc).Visible = (side>0.0)
next
glDisable (GL_LIGHTING)
glDepthMask (GL_FALSE)
glDepthFunc (GL_LEQUAL)
glEnable (GL_STENCIL_TEST)
glColorMask (0,0,0,0)
glStencilFunc(GL_ALWAYS, 1, -1)
glFrontFace (GL_CCW)
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR)
' render two times the shadow volume
' 1 * backside + 1 * frontside
for r=0 to 1
' draw the silouette from view of the light
for fc=0 to o.nFaces-1
if (o.Faces(fc).Visible<>0) then
for i=0 to 2
k = o.Faces(fc).Neighbors(i)
flag=(k=0)
if (flag=0) then
flag=(o.Faces(k-1).Visible=0)
end if
if flag then
' draw the polygon
glBegin(GL_TRIANGLE_STRIP)
for j=0 to 1
pi = o.Faces(fc).PointIndex((i+j) % 3)
'' calculate the length of the vectors
v1=o.Points(pi)
v2(0)=(v1(0)-v(0))*1000
v2(1)=(v1(1)-v(1))*1000
v2(2)=(v1(2)-v(2))*1000
glVertex3fv(v1)
glVertex3fv(v2)
next
glEnd()
end if
next
end if
next
glFrontFace(GL_CW)
glStencilOp(GL_KEEP,GL_KEEP,GL_DECR)
next
glFrontFace(GL_CCW)
glColorMask(1,1,1,1)
' only if it was the last object
if (IsLastObject<>0) then
glColor4fv(Vec4(0,0,0,0.1))
glEnable (GL_BLEND)
glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
glStencilFunc(GL_NOTEQUAL,0,-1)
glStencilOp (GL_KEEP,GL_KEEP,GL_KEEP)
glPushMatrix ()
glLoadIdentity()
glBegin(GL_TRIANGLE_STRIP)
glVertex3fv(Vec3(-0.1, 0.1,-0.1))
glVertex3fv(Vec3(-0.1,-0.1,-0.1))
glVertex3fv(Vec3( 0.1, 0.1,-0.1))
glVertex3fv(Vec3( 0.1,-0.1,-0.1))
glEnd()
glPopMatrix()
glDisable(GL_BLEND)
end if
' restore old render mode
glDepthFunc (GL_LEQUAL)
glDepthMask (GL_TRUE)
glEnable (GL_LIGHTING)
glDisable (GL_STENCIL_TEST)
glShadeModel(GL_SMOOTH)
glCullFace (GL_BACK)
glEnable (GL_CULL_FACE)
end sub
Sub DrawRoom()
glBegin(GL_QUADS)
' Floor
glNormal3f(0.0, 1.0, 0.0)
glVertex3f(-10,-10,-30)
glVertex3f(-10,-10, 10)
glVertex3f( 10,-10, 10)
glVertex3f( 10,-10,-30)
' Ceiling
glNormal3f(0.0,-1.0, 0.0)
glVertex3f(-10, 10, 10)
glVertex3f(-10, 10,-30)
glVertex3f( 10, 10,-30)
glVertex3f( 10, 10, 10)
' Front Wall
glNormal3f(0.0, 0.0, 1.0)
glVertex3f(-10, 10,-30)
glVertex3f(-10,-10,-30)
glVertex3f( 10,-10,-30)
glVertex3f( 10, 10,-30)
' Back Wall
glNormal3f(0.0, 0.0,-1.0)
glVertex3f( 10, 10, 10)
glVertex3f( 10,-10, 10)
glVertex3f(-10,-10, 10)
glVertex3f(-10, 10, 10)
' Left Wall
glNormal3f(1.0, 0.0, 0.0)
glVertex3f(-10, 10, 10)
glVertex3f(-10,-10, 10)
glVertex3f(-10,-10,-30)
glVertex3f(-10, 10,-30)
' Right Wall
glNormal3f(-1.0, 0.0, 0.0)
glVertex3f( 10, 10,-30)
glVertex3f( 10,-10,-30)
glVertex3f( 10,-10, 10)
glVertex3f( 10, 10, 10)
glEnd()
end sub
sub DrawLights()
dim lc as integer
dim m(3,3) as single
glDisable (GL_LIGHTING)
glDepthMask (0)
glBlendFunc (GL_SRC_COLOR, GL_ONE)
glEnable (GL_BLEND)
glEnable (GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, LightTexture)
glDisable (GL_CULL_FACE)
glPushMatrix()
for lc=0 to 2
glLoadIdentity()
glTranslatef(0,0,-camz#)
glTranslatef(LightPos(lc,0),LightPos(lc,1),LightPos(lc,2))
glGetFloatv(GL_MODELVIEW_MATRIX,m)
m(0)=Vec4(1,0,0,0)
m(1)=Vec4(0,1,0,0)
m(2)=Vec4(0,0,1,0)
glLoadMatrixf(m)
glScalef(3,3,3)
glBegin(GL_QUADS)
glColor4fv(LightSpc(lc))
glTexCoord2f(0,0): glVertex3f(-.5,-.5,0)
glTexCoord2f(1,0): glVertex3f( .5,-.5,0)
glTexCoord2f(1,1): glVertex3f( .5, .5,0)
glTexCoord2f(0,1): glVertex3f(-.5, .5,0)
glTexCoord2f(0,0): glVertex3f(0,-.5,-.5)
glTexCoord2f(1,0): glVertex3f(0, .5,-.5)
glTexCoord2f(1,1): glVertex3f(0, .5, .5)
glTexCoord2f(0,1): glVertex3f(0,-.5, .5)
glEnd()
glScalef(0.75,0.75,0.75)
glBegin(GL_QUADS)
glColor4fv(Vec4(1,1,1,1))
glTexCoord2f(0,0): glVertex3f(-.5,0,-.5)
glTexCoord2f(1,0): glVertex3f(-.5,0, .5)
glTexCoord2f(1,1): glVertex3f( .5,0, .5)
glTexCoord2f(0,1): glVertex3f( .5,0,-.5)
glTexCoord2f(0,0): glVertex3f(0, .5,-.5)
glTexCoord2f(1,0): glVertex3f(0,-.5,-.5)
glTexCoord2f(1,1): glVertex3f(0,-.5, .5)
glTexCoord2f(0,1): glVertex3f(0, .5, .5)
glEnd()
next
glPopMatrix()
glDepthMask(1)
glDisable(GL_BLEND)
glDisable(GL_TEXTURE_2D)
glEnable (GL_LIGHTING)
glEnable (GL_CULL_FACE)
end sub