ETS : Eole Terrain System

Miscellaneous Forums/Blitz Showcase/ETS : Eole Terrain System

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.

Hi all !

I decide ti give my terrain system without occulusion system in a speciale License Agreement version.

The heightmap must be in n^2+1 width 129,257,513,1025 ..

Look at the code to use it

; ------------------------------------------------------------------------------------
; Project Title	: QTS : Quadtree Terrain System
;
; Author		: Poursin Nicolas
; Email			: Nicolas.poursin@...
;
; Version		: 1.0.0          
; Date			: 05.04.2004
; ------------------------------------------------------------------------------------


; ------------------------------------------------------------------------------------
; Terms of Use License
;
; This is a legal agreement ("License Agreement") between you And Poursin Nicolas.

;	You are permitted To:

;   - Create For free or commercial games 
;   - Free Tool
;	 
;	You are Not permitted To: 
;
;	1) Sell, resell it
;	2) Use it, in commercial tool 
;	3) Modify the products And sell it                   
; ------------------------------------------------------------------------------------


; The global who contain the terrain mesh
Global QTS_Terrain 


; Set collission state for the terrain
Const QTS_TerrainCollision = 800	


; Type that contain the patch of the terrain
Type QTS_TPatch

	Field mesh
	Field x#
	Field y#
	Field z#
	Field inView
	
End Type



; Bank used to create the terrain
Global QTS_QuadTree
Global QTS_HeightMap
Global QTS_Vertex
Global QTS_Tile

; Global information  on the terrain
Global QTS_BlockSize		; Size of Terrain Patch = 16 * QTS_BlockSize
Global QTS_HeightMapSize	; Size of the heightmap must = 2^n+1 ( 129,257,513,1025 etc ...)


;********************************************** PUBLIC FONCTION **************************************************************



;------------------------------------------------------------------------------------
; Name: 				QTS_CreateTerrain
;
; Description: Create the terrain m
;
; Arguments:	- filename$ : path to the heightmap
;				- Blocksize	: Size of the terrain patch = 16 * QTS_BlockSize
;				- EdgeError	: The Error lenght to set the number of polygons
; -----------------------------------------------------------------------------------
Function QTS_CreateTerrain( filename$ , BlockSize , EdgeError   )

	QTS_Terrain = CreateMesh()
	QTS_LoadHeightMap( filename$  )

	QTS_BlockSize = BlockSize
	QTS_NbPatch = QTS_HeightMapSize/( QTS_BlockSize*16)
	QTS_Tile = CreateBank( 64*64*4 )
	
	QTS_Roughness(EdgeError)
	QTS_CreatePatch( QTS_BlockSize )

	QTS_Texture()
	
	FreeBank QTS_QuadTree
	FreeBank QTS_HeightMap
	FreeBank QTS_Vertex

End Function

;------------------------------------------------------------------------------------
; Name: 				QTS_FreeTerrain
;
; Description: Free the terrain and all attach object
; -----------------------------------------------------------------------------------
Function QTS_FreeTerrain()

	FreeEntity QTS_Terrain
	For tt.QTS_TPatch = Each QTS_TPatch
		Delete tt
	Next
	
End Function

;------------------------------------------------------------------------------------
; Name: 				QTS_UpdateTerrain
;
; Description: Free the terrain and all attach object
;
; Arguments:	- Cam : Camera handle
;				- ViewDistance# : Distance in front of camera that terrain pathc is still visible 
; -----------------------------------------------------------------------------------
Function QTS_UpdateTerrain( cam , ViewDistance# )


	For tile.QTS_TPatch = Each QTS_TPatch

			If EntityDistance( cam, tile\mesh ) < ViewDistance# Then

				If  EntityInView( tile\mesh ,cam) Then

					ShowEntity 	tile\mesh
		
				Else
					HideEntity tile\mesh

				EndIf
			Else
				HideEntity tile\mesh
		EndIf
		
	Next
	
End Function

; This fonction return the patch mesh at one position
Function QTS_GetMesh( x,z , scalevalue# )

	patchsize# = (QTS_BlockSize * 16/2 ) * scalevalue#
 	
	For tile.QTS_TPatch = Each QTS_TPatch
		xx = EntityX( tile\mesh,True)
		zz= EntityZ( tile\mesh,True)
	
		If x>= xx - patchsize# And x < xx+ patchsize# And z>= zz - patchsize# And z < zz+ patchsize# Then
			Return tile\mesh
		EndIf
		
	Next

	Return False
	
	
End Function


; REturn the height of the terrain
Function QTS_TerrainY#(x#,z#)

	pick=LinePick(x#,200000,z#,0,-2000000,0)

	Return (PickedY())

End Function

; TExture the terrain
Function QTS_TextureTerrain( hTexture,scale#=1,level=0,BlendMode=2)

	TextureBlend hTexture,BlendMode
	ScaleTexture hTexture,scale#,scale#
	
	For tile.QTS_TPatch = Each QTS_TPatch
		EntityTexture tile\mesh,hTexture,0,level
	Next
	
End Function






;********************************************** PRIVATE FONCTION **************************************************************

Function QTS_Roughness( Error )

	
	EdgeLength = 3
	
	While EdgeLength <=17

		EdgeOffset = (EdgeLength-1)/2
		ChildOffset = (Edgelength-1)/4

		z= EdgeOffset
		While z < QTS_HeightMapSize 

			x= EdgeOffset
			While x < QTS_HeightMapSize 

				node = 0
				kill=0


				If EdgeLength>3 Then
					; top edge
					Node = QTS_GetMatrixValue( x-ChildOffset , z-ChildOffset)
					Node = QTS_MAX( Node , QTS_GetMatrixValue( x+ChildOffset , z-ChildOffset))
					Node = QTS_MAX( Node , QTS_GetMatrixValue( x+ChildOffset , z+ChildOffset))
					Node = QTS_MAX( Node , QTS_GetMatrixValue( x-ChildOffset , z+ChildOffset))
				EndIf
				

				
				If EdgeLength = 3 Or node=0 Then

					QTS_SetMatrixValue( x-EdgeOffset , z-EdgeOffset , 1)
					QTS_SetMatrixValue( x+EdgeOffset , z-EdgeOffset , 1)
					QTS_SetMatrixValue( x+EdgeOffset , z+EdgeOffset , 1)
					QTS_SetMatrixValue( x-EdgeOffset , z+EdgeOffset , 1)
				
					; top edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x,z-EdgeOffset) - ((QTS_TrueHeightAtPoint#(x-EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x+EdgeOffset,z-EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue(  x,z-EdgeOffset, 1 )
					Else
						
						If EdgeLength>3 Then


								QTS_SetMatrixValue( x,z-EdgeOffset ,  0)

						EndIf

						
						kill = kill +1
					EndIf


					; right edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x+EdgeOffset,z) - ((QTS_TrueHeightAtPoint#(x+EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x+EdgeOffset,z+EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue( x+EdgeOffset,z , 1 )
					Else
						If EdgeLength>3 Then	
							QTS_SetMatrixValue( x+EdgeOffset,z , 0 )
						EndIf
						
						
						kill = kill +1
					EndIf

	
					; bottom edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x,z+EdgeOffset) - ((QTS_TrueHeightAtPoint#(x+EdgeOffset,z+EdgeOffset) + QTS_TrueHeightAtPoint#( x-EdgeOffset,z+EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue( x,z+EdgeOffset, 1 )
					Else
						If EdgeLength>3 Then

								QTS_SetMatrixValue( x,z+EdgeOffset , 0 )
							
						EndIf
						kill = kill +1
					EndIf					


					; left Edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x-EdgeOffset,z) - ((QTS_TrueHeightAtPoint#(x-EdgeOffset,z+EdgeOffset) + QTS_TrueHeightAtPoint#( x-EdgeOffset,z-EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue( x-EdgeOffset,z, 1)
					Else
						If EdgeLength>3 Then
							QTS_SetMatrixValue( x-EdgeOffset,z , 0)
						EndIf
						kill = kill +1
					EndIf

					QTS_SetMatrixValue( x,z, 1)
					
					If kill=4 Then	
				  		; top Left To bottom Right
						morph# = Abs(QTS_TrueHeightAtPoint#(x,z) - ((QTS_TrueHeightAtPoint#(x-EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x+EdgeOffset,z+EdgeOffset) ) /2))
						If morph#<= Error Then
							morph# = Abs(QTS_TrueHeightAtPoint#(x,z) - ((QTS_TrueHeightAtPoint#(x+EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x-EdgeOffset,z+EdgeOffset) ) /2))
							If morph#<= Error Then
								QTS_SetMatrixValue( x,z , 0 )
							EndIf
						EndIf
					EndIf
						
				Else If EdgeLength>3
				
					QTS_SetMatrixValue( x , z-EdgeOffset , 1 )
					QTS_SetMatrixValue( x+EdgeOffset , z , 1 )
					QTS_SetMatrixValue( x , z+EdgeOffset , 1 )
					QTS_SetMatrixValue( x-EdgeOffset , z , 1 )	

				EndIf

				x = x + EdgeLength-1
				
			Wend

			
			z = z + EdgeLength-1
		Wend

		EdgeLength = (EdgeLength Shl 1 ) - 1

		
	Wend

	; Propagation
	For z=16 To 513-1 Step 32
		For x=16 To 513-1 Step 32
			QTS_ProcessNode( x,z, 33, False , False )
		Next
	Next
			
End Function

; Create a node of a terrain patch
Function QTS_RenderNode( x,z,EdgeLength , EdgeOffset ,surf , bRender )

	 
	; top
	If bRender Then	VC = QTS_AddVertex( x,z,surf)

	
	If bRender Then  V1 = QTS_AddVertex( x-EdgeOffset , z-EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z-EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x+EdgeOffset , z-EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z-EdgeOffset )
	
	
	zz = z-EdgeOffset
	xstart = x-EdgeOffset+1
	xend = x-EdgeOffset+EdgeLength -1 - 1
	
	For xx=xstart To xend

		If QTS_GetMatrixValue(xx,zz)>0 Then
		
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V1,V2,VC
			V1=V2
		EndIf
		
	Next

	If bRender Then AddTriangle surf,v1,ve,vc

	
	; bottom
	If bRender Then VC = QTS_AddVertex( x,z,surf)

	If bRender Then V1 = QTS_AddVertex( x-EdgeOffset , z+EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z+EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x+EdgeOffset , z+EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z+EdgeOffset )
	
	
	zz = z+EdgeOffset
	xstart = x-EdgeOffset+1
	xend = x-EdgeOffset+EdgeLength -1 - 1
	
	For xx=xstart To xend

		If QTS_GetMatrixValue(xx,zz)>0 Then
		
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V2,V1,VC
			V1=V2
		EndIf
	Next

	If bRender Then AddTriangle surf,ve,v1,vc


	; right
	If bRender Then VC = QTS_AddVertex( x,z,surf)

	If bRender Then V1 = QTS_AddVertex( x+EdgeOffset , z-EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z-EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x+EdgeOffset , z+EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z+EdgeOffset )
	
	
	xx = x+EdgeOffset
	zstart = z-EdgeOffset+1
	zend = z-EdgeOffset+EdgeLength -1 - 1
	
	For zz=zstart To zend

		If QTS_GetMatrixValue(xx,zz)>0 Then
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V1,V2,VC
			V1=V2
		EndIf
	Next

	If bRender Then AddTriangle surf,v1,ve,vc

	; left
	If bRender Then VC = QTS_AddVertex( x,z,surf)

	If bRender Then V1 = QTS_AddVertex( x-EdgeOffset , z-EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z-EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x-EdgeOffset , z+EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z+EdgeOffset )
	
	xx = x-EdgeOffset
	zstart = z-EdgeOffset+1
	zend = z-EdgeOffset+EdgeLength -1 - 1
	
	For zz=zstart To zend

		If QTS_GetMatrixValue(xx,zz)>0 Then
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V2,V1,VC
			V1=V2
		EndIf
	Next

	If bRender Then AddTriangle surf,ve,v1,vc

	
End Function

; Create a terrain patch
Function QTS_CreatePatch( BlockSize )

	QTS_NbPatch=0
	
	qts=CreateBank( 64*64*4)
	
	z=0
	ztab=0
	While z <=  QTS_HeightMapSize

		x=0
		xtab=0
		While x <= QTS_HeightMapSize

			PatchNumer = PatchNumer + 1
			
			xx# = x  + (BlockSize * 16/2 )
			zz# = z  + (BlockSize * 16/2 )

				
			TerrainPatch = CreateMesh()

			
			TerrainPatchSurface = CreateSurface( TerrainPatch )

			QTS_Vertex = CreateBank( (QTS_HeightMapSize) * (QTS_HeightMapSize) * 4)
			
			For bz=8 To Blocksize*16 Step 16
				For bx=8 To Blocksize*16 Step 16
					cx = x+bx
					cz = z+bz
					If cx<QTS_HeightMapSize And cz<QTS_HeightMapSize Then		
						QTS_ProcessNode( cx,cz, 17 , TerrainPatchSurface ,True )
					EndIf
				Next
			Next

			QTS_NbPatch = QTS_NbPatch +1
			
			FreeBank QTS_Vertex
			UpdateNormals TerrainPatch

			
			
			PositionMesh terrainpatch,-xx#,-MeshHeight(terrainpatch)/2,zz#

			
			
			EntityParent TerrainPatch,QTS_Terrain
			EntityType TerrainPatch,QTS_TerrainCollision

			
			tile.QTS_TPatch = New QTS_TPatch
			
			tile\mesh = TerrainPatch
			tile\x# = xtab * (BlockSize * 16/2 ) *2
			tile\y# = MeshHeight(terrainpatch)/2
			tile\z# = -ztab *(BlockSize * 16/2 ) *2 
 			tile\inView = False
			
			PositionEntity tile\mesh,tile\x#,tile\y#,tile\z#
			EntityPickMode tile\mesh,2

			EntityColor tile\mesh,250,250,250
			
			PokeInt QTS_Tile, ((ztab*64 + xtab)*4),Handle( tile )
			
			x = x + (BlockSize * 16)
			xtab=xtab+1
		Wend
		z = z + (BlockSize * 16)
		ztab=ztab+1
	Wend
	
End Function


; Check a Node of a terrain patch
Function QTS_ProcessNode( x,z, EdgeLength, surf , bRender )

	EdgeOffset = (EdgeLength-1)/2
	ChildOffset = (Edgelength-1)/4
		
	node = QTS_GetMatrixValue( x,z )
	
	If node=1   Then
		
		If  EdgeLength=3 Then
			QTS_RenderNode( x,z,EdgeLength , EdgeOffset ,surf ,bRender)
		Else
			; top left child
			If QTS_GetMatrixValue( x-ChildOffset,z-ChildOffset ) > 0 Then
				QTS_ProcessNode( x-ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2), surf ,bRender)
			Else
				 QTS_RenderNode(  x-ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)
			EndIf

			; top right child
			If QTS_GetMatrixValue( x+ChildOffset,z-ChildOffset ) > 0 Then
				QTS_ProcessNode( x+ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2), surf ,bRender)
			Else
		
			 QTS_RenderNode(  x+ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)

			EndIf

			; bottom left child
			If QTS_GetMatrixValue( x-ChildOffset,z+ChildOffset ) > 0 Then
				QTS_ProcessNode( x-ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2), surf,bRender)
			Else
		
			 QTS_RenderNode(  x-ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)
			EndIf

			; bottom right child
			If QTS_GetMatrixValue( x+ChildOffset,z+ChildOffset ) > 0 Then
				QTS_ProcessNode( x+ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2), surf,bRender)
			Else
			
				 QTS_RenderNode(  x+ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)
			EndIf

		EndIf
	
	Else
		
		QTS_RenderNode( x,z,EdgeLength , EdgeOffset ,surf,bRender)
		
	EndIf


	
End Function

Function QTS_AddVertex( x,z,surf)


	If PeekInt( QTS_Vertex, QTS_MatrixIndex( x,z)*4)=0 Then
		y# = QTS_TrueHeightAtPoint(x,z) *0.1
		vertex = AddVertex( surf,x,y#,-z,0,0)
		PokeInt QTS_Vertex, QTS_MatrixIndex( x,z)*4 , vertex+1

	Else
		vertex = PeekInt( QTS_Vertex, QTS_MatrixIndex( x,z)*4)-1
	EndIf
	

	
	Return Vertex
	
End Function


Function QTS_LoadHeightMap(filename$ ,shadow=False)

	
	heightmap = LoadImage( filename$ )
	
	QTS_HeightMapSize = ImageWidth( heightmap )

	QTS_HeightMap = CreateBank( (QTS_HeightMapSize) * (QTS_HeightMapSize) )
	If Not shadow Then
		QTS_QuadTree = CreateBank( (QTS_HeightMapSize) * (QTS_HeightMapSize) )
	EndIf
	

	LockBuffer ImageBuffer( heightmap)

	For z=0 To QTS_HeightMapSize-1
		For x=0 To QTS_HeightMapSize-1
			pixel = ReadPixelFast( x,z, ImageBuffer(heightmap) ) And 255
			offset = z * QTS_HeightMapSize + x
			PokeByte QTS_HeightMap, offset , pixel
			If Not shadow Then	
				PokeByte QTS_QuadTree, offset , 0
			EndIf
		Next
		
	Next

	UnlockBuffer ImageBuffer( heightmap)
	FreeImage heightmap
		
End Function

Function QTS_Texture()


	size = QTS_HeightMapSize 

	For z=0 To 63
		For x=0 To 63
			obj = PeekInt( QTS_Tile, (z*64+x)*4)
			If obj>0
				tile.QTS_TPatch = Object.QTS_TPatch( obj)
				If tile\mesh <>-1 Then

					Surface = GetSurface(tile\mesh, 1)
					Vertices = CountVertices(Surface)

					For Vertex = 0 To Vertices-1

						VX# = EntityX#(tile\mesh) +  (VertexX#(Surface, Vertex) + (4 * 16 )/2)
						VZ# = EntityZ#(tile\mesh) +  (VertexZ#(Surface, Vertex) -  (4 * 16 )/2)
						VertexTexCoords Surface, Vertex, VX#/size, -VZ#/size, 0,0
						
					Next
			
				EndIf					
			EndIf
		Next
	Next
	
	
End Function

Function QTS_GetMatrixValue( x,z )

	value=PeekByte(QTS_QuadTree, QTS_MatrixIndex( x,z))
	
	Return value
	
End Function

Function QTS_SetMatrixValue( x,z , value=1 )

		
	PokeByte QTS_QuadTree , QTS_MatrixIndex( x , z) , value


End Function

Function QTS_MatrixIndex( x,z)

	Return (( z * QTS_HeightMapSize) + x)
	
End Function

Function QTS_Max#(v1#,v2#)

	If v1#>V2# Then
		Return v1#
	Else
		Return v2#
	EndIf
	
End Function

Function QTS_TrueHeightAtPoint#( x, z)

	value#=PeekByte(QTS_HeightMap, (z * QTS_HeightMapSize) + x)
	
	Return value#
	
End Function