;*************************************************************************
;Fast Tree System
; Written by John Judnich
;*************************************************************************
;Note: This tree system may perform poorly in debug mode
Const MAXLAYERS=100
Global TS_bank,TS_xtiles,TS_ztiles,TS_layers,TS_x1#,TS_x2#,TS_z1#,TS_z2#,TS_LOD=1,TS_morph=True,TS_camera=-1
Dim TS_layertexture(MAXLAYERS)
Dim TS_layerFX(MAXLAYERS)
;Dim TS_layerLOD(MAXLAYERS)
Const XPROP=1 ;Two polygons forming an 'X'
Const IPROP=2 ;One polygon for flat props, sprites, etc.
Type PropGroup
Field mesh
Field props
Field propbank
Field polycount
End Type
Type Prop
Field vertex,verts
Field surface
Field x#,y#,z#,yaw#,xs#,ys#,zs#
Field r,g,b,alpha#
End Type
;This function must be called before any of the tree system functions
;can be used. x1,z1,x2, And z2 are the bounds of the tree system. layers
;is the number of different trees that can be used (you can't texture Each
;tree individually). xtiles and ztiles are settings used for the occlusion
Function InitTreeSystem(x1#,z1#,x2#,z2#,layers,xtiles=10,ztiles=10)
;Setup variables
TS_xtiles=xtiles-1:TS_ztiles=ztiles-1:TS_layers=layers-1
TS_x1=x1:TS_x2=x2:TS_z1=z1:TS_z2=z2
;Create prop group handle bank
TS_bank=CreateBank((TS_xtiles+1)*(TS_ztiles+1)*(TS_layers+1)*5)
;Make all the prop groups needed
For z=0 To TS_ztiles
For x=0 To TS_xtiles
For l=0 To TS_layers
group=CreatePropGroup()
WriteTSBank(x,z,l,group)
WriteTSBank2(x,z,l,IPROP) ;Default groups to low detail for faster loading
HideEntity group ;Hide until used
Next
Next
Next
For l=1 To TS_layers+1
LayerFX(l,2+16)
;LayerViewDist(l,10)
Next
End Function
;This function sets the camera to use for LOD calculations. Use this
;function to set the tree system camera to the main camera in your program.
;If no camera is set when UpdateTreeSystemLOD is called
Function SetTreeSystemCamera(camera)
TS_camera=camera
End Function
;This function sets the level of detail for the tree system. The
;detail_level is actually the radius (in tiles) where trees will change
;to their higher detail level. Morph can be set to true or false, setting
;"morphing" on or off. Morphing actually just slowly changes trees from
;one detail level to another, instead of changing all that need to be
;changed at once (this smoothes out temporary frame rate drops when moving
;from one "tile" to another).
Function SetTreeSystemLOD(detail_level,morph=True)
TS_LOD=detail_level
TS_morph=morph
End Function
;Use this function if you want to delete all trees for any reason
Function DestroyTreeSystem()
;Delete all the prop groups
For z=0 To TS_ztiles
For x=0 To TS_xtiles
For l=0 To TS_layers
DestroyPropGroup(ReadTSBank(x,z,l))
Next
Next
Next
;Delete prop group bank
FreeBank TS_bank
End Function
;This textures a layer in the tree system
Function LayerTexture(layer,texture)
TS_layertexture(layer-1)=texture
For z=0 To TS_ztiles
For x=0 To TS_xtiles
EntityTexture ReadTSBank(x,z,layer-1),texture
Next
Next
End Function
;This sets the EntityFX for a layer in the tree system
Function LayerFX(layer,fx)
TS_layerFX(layer-1)=fx
For z=0 To TS_ztiles
For x=0 To TS_xtiles
EntityFX ReadTSBank(x,z,layer-1),fx
Next
Next
End Function
;This sets the maximum viewing distance (in tiles) for trees in a layer
;Function LayerViewDist(layer,dist)
; TS_layerLOD(layer-1)=dist
;End Function
;This makes a tree at the coordinates x,y,z with the specified layer. The
;x and z coordinates are permanent, but the y coordinate can be changed
Function CreateTree(x#,y#,z#,layer)
;Locate grid square to put tree
xg=TSXGridLoc(x)
zg=TSZGridLoc(z)
;Read group to put tree in and group detail level
group=ReadTSBank(xg,zg,layer-1)
detail=ReadTSBank2(xg,zg,layer-1)
;Create the prop with in the group with it's detail level
prop=CreateProp(group,detail)
;Position the tree at it's correction location
PositionProp(prop,x#,y#,z#)
;Randomly rotate the tree
RotateProp(prop,Rnd#(0,360))
;Show used group (by default groups are hidden to increase performance)
ShowEntity group
Return prop
End Function
;This positions a tree along the y axis
Function TreePositionY(tree,y#)
tmp.Prop=Object.Prop(tree)
MoveProp(tree,0,y#-tmpy,0)
End Function
;This scales a tree according to xs,ys, and zs
Function ScaleTree(tree,xs#,ys#,zs#)
ScaleProp(tree,xs#,ys#,zs#)
End Function
;This colors a tree
Function ColorTree(tree,r,g,b)
ColorProp(tree,r,g,b)
End Function
;This sets a tree's alpha (opacity)
Function TreeAlpha(tree,alpha#)
PropAlpha(tree,alpha#)
End Function
;This rotates a tree along the y axis (yaw) relative to it's last rotation
;Function TurnTree(tree,yaw#)
;TurnProp(tree,yaw#)
;End Function
;Call this function just before the RenderWorld command. This function
;dynamicly updates trees' LOD (level of detail). This command will fail
;if no tree system camera has been set (see SetTreeSystemCamera)
Function UpdateTreeSystem()
;tx=MilliSecs()
;Check camera
If TS_camera=-1 Then RuntimeError "Error: UpdateTreeSystemLOD() function has been called, and no tree system camera has been set yet."
;Locate grid squares that the camera is in
xg=TSXGridLoc(EntityX(TS_camera,True))
zg=TSZGridLoc(EntityZ(TS_camera,True))
;Calculate the level of detail for each grid square and update it if it has changed
For z=0 To TS_ztiles
For x=0 To TS_xtiles
;Calculate level of detail
xd=Abs(x-xg)
zd=Abs(z-zg)
If xd<=TS_LOD And zd<=TS_LOD Then detail=XPROP Else detail=IPROP
;Hide tiles out of range
;For l=0 To TS_layers
;If TS_LayerLOD(l)<>False And (xd>TS_LayerLOD(l) Or zd>TS_LayerLOD(l)) Then HideEntity ReadTSBank(x,z,l) Else ShowEntity ReadTSBank(x,z,l)
;Next
;Check if grid tile needs updating
If ReadTSBank2(x,z,0)<>detail Then
;Update grid tile
For l=0 To TS_layers
RegenerateGroup(x,z,l,detail)
Next
WriteTSBank2(x,z,0,detail)
If TS_morph=True Then Return ;Don't change all at once
End If
Next
Next
;If MilliSecs()-tx>10 then DebugLog MilliSecs()-tx
End Function
;(Internal functions:)
Function TSXGridLoc(x#)
n#=(x#-TS_x1#)/(TS_x2#-TS_x1#)
rtn=n#*TS_xtiles
Return rtn
End Function
Function TSZGridLoc(z#)
n#=(z#-TS_z1#)/(TS_z2#-TS_z1#)
rtn=n#*TS_ztiles
Return rtn
End Function
Function WriteTSBank(x,z,l,value)
pos=(l*(TS_xtiles+1)*(TS_ztiles+1))+(z*(TS_xtiles+1)+x)
PokeInt TS_bank,pos*5,value
End Function
Function WriteTSBank2(x,z,l,value)
pos=(l*(TS_xtiles+1)*(TS_ztiles+1))+(z*(TS_xtiles+1)+x)
PokeByte TS_bank,(pos*5)+4,value
End Function
Function ReadTSBank(x,z,l)
pos=(l*(TS_xtiles+1)*(TS_ztiles+1))+(z*(TS_xtiles+1)+x)
Return PeekInt(TS_bank,pos*5)
End Function
Function ReadTSBank2(x,z,l)
pos=(l*(TS_xtiles+1)*(TS_ztiles+1))+(z*(TS_xtiles+1)+x)
Return PeekByte(TS_bank,(pos*5)+4)
End Function
Function RegenerateGroup(x,z,l,detail)
;Get the group from the bank
group=ReadTSBank(x,z,l)
grp.PropGroup=Object.PropGroup(EntityName(group))
;Create a new group
group2=CreatePropGroup()
grp2.PropGroup=Object.PropGroup(EntityName(group2))
;Copy all the trees from the old group to the new group, with the new detail level
props=BankSize(grppropbank)/4
For i=1 To props
;Get the old and new prop
oldprop=PeekInt(grppropbank,(i*4)-4)
oldprp.Prop=Object.Prop(oldprop)
prop=CreateProp(group2,detail)
prp.Prop=Object.Prop(prop)
PositionProp(prop,oldprpx,oldprpy,oldprpz) ;Copy position
TurnProp(prop,oldprpyaw) ;Copy rotation
ScaleProp(prop,oldprpxs,oldprpys,oldprpzs) ;Copy scale
ColorProp(prop,oldprp
,oldprpg,oldprp) ;Copy color
PropAlpha(prop,oldprpalpha) ;Copy alpha
Next
;Copy texture and EntityFX
EntityFX group2,TS_layerFX(l)
EntityTexture group2,TS_layertexture(l)
;Delete the old group
DestroyPropGroup(group)
;Put the new prop group handle into the bank in place of the old one
WriteTSBank(x,z,l,group2)
End Function
Function CreatePropGroup()
;Create the new group
grp.PropGroup=New PropGroup
;Set up it's mesh with one surface
grpmesh=CreateMesh()
surface=CreateSurface(grpmesh)
NameEntity grpmesh,Handle(grp)
EntityFX grpmesh,2+16 ;Vert. colors + no culling
;Create the prop list bank
grppropbank=CreateBank()
;Return the mesh's handle
Return grpmesh
End Function
Function DestroyPropGroup(group)
grp.PropGroup=Object.PropGroup(EntityName(group))
FreeBank grppropbank
FreeEntity grpmesh
Delete grp.PropGroup
End Function
Function GetPropCount(group)
grp.PropGroup=Object.PropGroup(EntityName(group))
Return grpprops
End Function
Function GetProp(group,indx)
grp.PropGroup=Object.PropGroup(EntityName(group))
Return PeekInt(grppropbank,(indx*4)-4)
End Function
Function CreateProp(group,proptype=XPROP)
;Get the group's surface
grp.PropGroup=Object.PropGroup(EntityName(group))
surface=GetSurface(grpmesh,1)
;Resize the bank
grpprops=grpprops+1
ResizeBank grppropbank,grpprops*4
;Create the new prop
prop.Prop=New Prop
propxs=1.0:propys=1.0:propzs=1.0
;Side 1
propvertex=AddVertex(surface,0,-.54,0 ,.5,1.7) ;bottom
AddVertex(surface,-1,.76,0 ,-.65,0) ;right
AddVertex(surface,1,.76,0 ,1.65,0) ;left
AddTriangle(surface,propvertex+2,propvertex+1,propvertex+0)
;Side 2
If proptype=XPROP Then
AddVertex(surface,0,-.54,0 ,.5,1.7) ;bottom
AddVertex(surface,0,.76,-1 ,-.65,0) ;front
AddVertex(surface,0,.76,1 ,1.65,0) ;back
AddTriangle(surface,propvertex+5,propvertex+4,propvertex+3)
End If
propsurface=surface
If proptype=XPROP Then propverts=5
If proptype=IPROP Then propverts=2
;Put the new prop into the group's bank
PokeInt grppropbank,(grpprops*4)-4,Handle(prop)
grppolycount=grppolycount+2
prop
=255:propg=255:prop=255
propalpha#=1
;Return the prop's handle
Return Handle(prop)
End Function
Function ColorProp(prop,r,g,b)
tmp.Prop=Object.Prop(prop)
tmp
=r:tmpg=g:tmp=b
For i=0 To tmpverts
VertexColor tmpsurface,tmpvertex+i,r,g,b
Next
End Function
Function PropAlpha(prop,alpha#)
tmp.Prop=Object.Prop(prop)
tmpalpha#=alpha#
For i=0 To tmpverts
VertexColor tmpsurface,tmpvertex+i,VertexRed(tmpsurface,tmpvertex+i),VertexGreen(tmpsurface,tmpvertex+i),VertexBlue(tmpsurface,tmpvertex+i),alpha#
Next
End Function
Function PropTexCoords(prop,u1#,v1#,u2#,v2#)
tmp.Prop=Object.Prop(prop)
End Function
Function MoveProp(prop,mx#,my#,mz#)
tmp.Prop=Object.Prop(prop)
For i=0 To tmpverts
x#=VertexX(tmpsurface,tmpvertex+i)
y#=VertexY(tmpsurface,tmpvertex+i)
z#=VertexZ(tmpsurface,tmpvertex+i)
VertexCoords tmpsurface,tmpvertex+i,x#+mx#,y#+my#,z#+mz#
Next
tmpx=tmpx+mx#
tmpy=tmpy+my#
tmpz=tmpz+mz#
End Function
Function PositionProp(prop,x#,y#,z#)
tmp.Prop=Object.Prop(prop)
MoveProp(prop,x#-tmpx,y#-tmpy,z#-tmpz)
End Function
Function ScaleProp(prop,xs#,ys#,zs#)
tmp.Prop=Object.Prop(prop)
tmpxs=tmpxs*xs:tmpys=tmpys*ys:tmpzs=tmpzs*zs
For i=0 To tmpverts
dx#=VertexX(tmpsurface,tmpvertex+i)-tmpx
dy#=VertexY(tmpsurface,tmpvertex+i)-tmpy
dz#=VertexZ(tmpsurface,tmpvertex+i)-tmpz
x#=tmpx+dx#*xs#
y#=tmpy+dy#*ys#
z#=tmpz+dz#*zs#
VertexCoords tmpsurface,tmpvertex+i,x#,y#,z#
Next
End Function
Function TurnProp(prop,yaw#)
tmp.Prop=Object.Prop(prop)
tmpyaw=tmpyaw+yaw#
CosAY#=Cos(yaw)
SinAY#=Sin(yaw)
For i=0 To tmpverts
x#=VertexX(tmpsurface,tmpvertex+i)-tmpx
y#=VertexY(tmpsurface,tmpvertex+i)-tmpy
z#=VertexZ(tmpsurface,tmpvertex+i)-tmpz
;Rotate around y axis
tx#=x*cosAY+z*sinAY
z=z*cosAY-x*sinAY
x=tx
x=x+tmpx
y=y+tmpy
z=z+tmpz
VertexCoords tmpsurface,tmpvertex+i,x,y,z
Next
End Function
Function RotateProp(prop,yaw#)
tmp.Prop=Object.Prop(prop)
TurnProp(prop,yaw#-tmpyaw#)
End Function
Function UpdatePropGroupNormals(group)
grp.PropGroup=Object.PropGroup(EntityName(group))
UpdateNormals grpMesh
End Function