[bb] Random Tileable Terrain Generator by Delerna [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:43

Previous topic - Next topic

BlitzBot

Title : Random Tileable Terrain Generator
Author : Delerna
Posted : 1+ years ago

Description : Uses the diamond square methodology to generate random terrain meshes that are completely tileable in all four directions. You can vary the number of vertices in the terrain as well as the ruggedness and the evenness of the transitions in the ruggedness,if that senetence makes sense!!!   Use it/change it   however you like,  I give it to the Blitz community.

Code :
Code: blitzbasic
;Changeable Parameters
GridSize%=9; Must be a 2^n+1
Landform#=10;The bigger the number the greater the difference in heights between highspots and lowspots
Smoothness#=6;The bigger the number the more smoothly the transition between highspots and low spots will occur


;Setup the 3D environment
Graphics3D 1024,700,16,2
SetBuffer BackBuffer()
Dim vert(GridSize,GridSize)
WireFrame True
AmbientLight(255,255,255)
cam=CreateCamera()
MoveEntity cam, 0, 50, -140 ; Our camera...
CameraRange cam,1,10000

;Create 4 copies of the same terrain and position them to show that they are tileable
RandomTerrain=TileableRandomDiamondSquareTerrain(GridSize,Landform,Smoothness)
RandomTerrain2=CopyMesh(RandomTerrain,RandomTerrain)
PositionEntity(RandomTerrain2,-45,0,0)
RandomTerrain3=CopyMesh(RandomTerrain,RandomTerrain)
PositionEntity(RandomTerrain3,-45,0,45)
RandomTerrain4=CopyMesh(RandomTerrain,RandomTerrain)
PositionEntity(RandomTerrain4,0,0,45)


While Not KeyDown(1)
	Cls
	TurnEntity RandomTerrain,0,0.5,0
	RenderWorld 
	Flip 
Wend
End
Function TileableRandomDiamondSquareTerrain(GridSize,Range#,Smoothness#)
	NumSquares=1; We start with 1 square that is the size of the mesh
	XS=1
	Iterations#=Log2(GridSize-1) ;In the loops we work with progressively smaller and smaller squares
											  ;This is the number of times to execute the loops to get to the smallest
											  ;possible square defined by the vertices.
	Terrain=CreateGrid(GridSize,GridSize)
	surf=GetSurface(Terrain,1)
	SeedRnd (MilliSecs()) 
	For i= 1 To iterations
		s=((GridSize-1)/XS)
		For z=1 To NumSquares/XS
		For x=1 To NumSquares/XS
			;Get the corner vertices of the square defined by z,x
			v1=0+(s*(x-1))+s*(z-1)*GridSize  :  v2=v1+s  :  v3=v1+s*GridSize  :  v4=v3+s
			;Now get the centre vertice of the z,x square and raise or lower it by a random amount
			vc=v1+s/2+(s/2)* GridSize
			AvgHeight=(VertexY(surf,v1)+VertexY(surf,v2)+VertexY(surf,v3)+VertexY(surf,v4))/4
			VertexCoords surf,vc,VertexX(surf,vc),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,vc)
			
			;next we get the centre vertice of the left edge of the z.x square and raise or lower it by a random amount
			v5=vc-s/2  :  v15=v5-(s/2)*GridSize  :  v25=v15+(s/2)  :  v35=v5+(s/2)
			AvgHeight=(VertexY(surf,v15)+VertexY(surf,v25)+VertexY(surf,v35))/3
			VertexCoords surf,v5,VertexX(surf,v5),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v5)
			;if the vertex is on the left edge of the mesh then set the vertex on the right edge to the same height to ensure tileability
			If v5*1.0/gridsize*1.0=Int(v5/gridsize) Then
				ve=v5+gridsize-1:VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v5),VertexZ(surf,ve)
			End If
			
			;next we get the centre vertice of the top edge of the z.x square and raise or lower it by a random amount
			v6=vc-(s/2)*GridSize  :  v16=v6+(s/2)   :  v26=v16+(s/2)*GridSize  :  v36=v26-(s/2)			
			AvgHeight=(VertexY(surf,v16)+VertexY(surf,v26)+VertexY(surf,v36))/3
			VertexCoords surf,v6,VertexX(surf,v6),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v6)
			;if the vertex is on the top edge of the mesh then set the vertex on the bottom edge to the same height to ensure tileability
			If v6<GridSize Then
				ve=v6+gridsize*(gridsize-1):VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v6),VertexZ(surf,ve)
			End If

			;next we get the centre vertice of the right edge of the z.x square and raise or lower it by a random amount
			v7=vc+s/2  :  v17=v7-(s/2)   :  v27=v17+(s/2)*GridSize  :  v37=v27+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v7,VertexX(surf,v7),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v7)
			;if the vertex is on the right edge of the mesh then set the vertex on the left edge to the same height to ensure tileability
			If ((v7-gridsize+1)*1.0)/(gridsize*1.0)=Int((v7-gridsize+1)/(gridsize-1))  Then
				ve=v7-gridsize+1:VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v7),VertexZ(surf,ve)
			End If
			
			;next we get the centre vertice of the bottom edge of the z.x square and raise or lower it by a random amount
			v8=vc+(s/2)*GridSize  :  v18=v8-(s/2)*GridSize  :  v28=v18+(s/2)  :  v38=v8+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v8,VertexX(surf,v8),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v8)
			;if the vertex is on the top edge of the mesh then set the vertex on the bottom edge to the same height to ensure tileability
			If v8>GridSize*(gridsize-1) Then
				ve=v8-gridsize*(gridsize-1):VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v8),VertexZ(surf,ve)
			End If
			Next
		Next
		NumSquares=NumSquares*4
		xs=xs*2
		Print numsquares
		range=range/smoothness
	Next
	Return terrain
End Function
Function CreateGrid(x=9,z=9,w=5,h=5)
	mesh=CreateMesh()
	surf=CreateSurface(mesh)
	
	For xl=0 To x-1
		v=AddVertex(surf,xl*w,0,0)
		vert(xl,0)=v
	Next
	
	For zl=1 To z-1
		For xl=0 To x-1
			v=AddVertex(surf,xl*w,0,zl*-h)
			vert(xl,zl)=v
			If xl>0 Then
				AddTriangle surf,vert(xl,zl),vert(xl-1,zl),vert(xl,zl-1)
				AddTriangle surf,vert(xl,zl-1),vert(xl-1,zl),vert(xl-1,zl-1)					
			End If
			
		Next
	Next
	Return mesh
End Function
Function Log2# ( x# )
	Return Log( x ) / Log( 2 ) 
End Function


Comments :


Delerna(Posted 1+ years ago)

 IMPROVED1) Previous version didn't really work as intended. This has been corrected2) The grid of 2X2 meshes now automatically position themselves automatically to suit the size of the idividual meshes3) Previous version could produce jagged terrains. A smothing function has been added to even out the transitions from high spots to low spots4) The vertices are now colored in relation to their height. Black for lowest vertices through shades of green then yellow and on to white for the highest verticesThe terrains are random so you may need to run the program a few times to get a good one. Also a mesh save function might be a good addition, i'll get around to writing one someday, just experimenting at the moment.If you like this, or it is usefull, or you have suggestions then make a comment and I will continue to post improvements
Code: BASIC
;Changeable Parameters
GridSize%=129; Must be a 2^n+1
Landform#=600;The bigger the number the greater the difference in heights between highspots and lowspots
Smoothness#=50;The bigger the number the more smoothly the transition between highspots and low spots will occur


;Setup the 3D environment
Graphics3D 1024,700,16,2
SetBuffer BackBuffer()
Dim vert(GridSize,GridSize)
WireFrame False
AmbientLight(255,255,255)
cam=CreateCamera()
MoveEntity cam, 0, (GridSize-1)*3, -(GridSize-1)*10 ; Our camera...
;MoveEntity cam, 0, 10, 0 ; Our camera...
CameraRange cam,1,10000

;Create 4 copies of the same terrain and position them to show that they are tileable
RandomTerrain=TileableRandomDiamondSquareTerrain(GridSize,Landform,Smoothness)
SmoothTerrain(RandomTerrain,Gridsize)
SmoothTerrain(RandomTerrain,Gridsize)
SmoothTerrain(RandomTerrain,Gridsize)
spacing=(GridSize-1)*5;+5
RandomTerrain2=CopyMesh(RandomTerrain,RandomTerrain)
EntityFX RandomTerrain2,2
PositionEntity(RandomTerrain2,-spacing,0,0)

RandomTerrain3=CopyMesh(RandomTerrain,RandomTerrain)
EntityFX RandomTerrain3,2
PositionEntity(RandomTerrain3,-spacing,0,spacing)

RandomTerrain4=CopyMesh(RandomTerrain,RandomTerrain)
PositionEntity(RandomTerrain4,0,0,spacing)
EntityFX RandomTerrain4,2

While Not KeyDown(1)
	Cls
	TurnEntity RandomTerrain,0,0.5,0
	RenderWorld 
	Flip 
Wend
End

Function SmoothTerrain(Terrain,Gridsize)
	EntityFX Terrain,2
	surf=GetSurface(Terrain,1)
	For r=0 To Gridsize-1
		fv=r*Gridsize
		For c= 1 To Gridsize-2
			v1=fv+c-1 : v2=fv+c : v3=fv+c+1
			h1=VertexY(surf,v1) : h2=VertexY(surf,v2) : h3=VertexY(surf,v3)
			h2=h1+((h3-h1)/2)
			cr=255-(255-h2)
			cg=255-(255-h2)+90
			cb=255-(255-(h2-200))
			If cr>255 Then cr=255
			If cg>255 Then cg=255
			If cb>255 Then cb=255
			VertexCoords surf,v2,VertexX(surf,v2),h2,VertexZ(surf,v2)
			VertexColor surf,v2,cr,cg,cb
		Next
	Next

	For c=0 To Gridsize-1
		For r= 1 To Gridsize-2
			v1=c+r*Gridsize-Gridsize : v2=c+r*Gridsize : v3=c+r*Gridsize+Gridsize
			h1=VertexY(surf,v1) : h2=VertexY(surf,v2) : h3=VertexY(surf,v3)
			h2=h1+((h3-h1)/2)
			VertexCoords surf,v2,VertexX(surf,v2),h2,VertexZ(surf,v2)
			cr=255-(255-h2)
			cg=255-(255-h2)+90
			cb=255-(255-(h2-200))
			If cr>255 Then cr=255
			If cg>255 Then cg=255
			If cb>255 Then cb=255
			VertexColor surf,v2,cr,cg,cb
		Next
	Next

End Function


Function TileableRandomDiamondSquareTerrain(GridSize,Range#,Smoothness#)
	NumSquares=1; We start with 1 square that is the size of the mesh
	XS=1
	Iterations#=Log2(GridSize-1) ;In the loops we work with progressively smaller and smaller squares
											  ;This is the number of times to execute the loops to get to the smallest
											  ;possible square defined by the vertices.

		Terrain=CreateGrid(GridSize,GridSize)

	surf=GetSurface(Terrain,1)
	SeedRnd (MilliSecs()) 
	For i= 1 To iterations
		s=((GridSize-1)/XS)
		For z=1 To NumSquares/XS
		For x=1 To NumSquares/XS
			;Get the corner vertices of the square defined by z,x
			v1=0+(s*(x-1))+s*(z-1)*GridSize  :  v2=v1+s  :  v3=v1+s*GridSize  :  v4=v3+s
			;Now get the centre vertice of the z,x square and raise or lower it by a random amount
			vc=v1+s/2+(s/2)* GridSize
			AvgHeight=(VertexY(surf,v1)+VertexY(surf,v2)+VertexY(surf,v3)+VertexY(surf,v4))/4
			VertexCoords surf,vc,VertexX(surf,vc),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,vc)
			
			;next we get the centre vertice of the left edge of the z.x square and raise or lower it by a random amount
			v5=vc-s/2  :  v15=v5-(s/2)*GridSize  :  v25=v15+(s/2)  :  v35=v5+(s/2)
			AvgHeight=(VertexY(surf,v15)+VertexY(surf,v25)+VertexY(surf,v35))/3
			VertexCoords surf,v5,VertexX(surf,v5),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v5)
			;if the vertex is on the left edge of the mesh then set the vertex on the right edge to the same height to ensure tileability
			If v5*1.0/gridsize*1.0=Int(v5/gridsize) Then
				ve=v5+gridsize-1:VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v5),VertexZ(surf,ve)
			End If
			
			;next we get the centre vertice of the top edge of the z.x square and raise or lower it by a random amount
			v6=vc-(s/2)*GridSize  :  v16=v6+(s/2)   :  v26=v16+(s/2)*GridSize  :  v36=v26-(s/2)			
			AvgHeight=(VertexY(surf,v16)+VertexY(surf,v26)+VertexY(surf,v36))/3
			VertexCoords surf,v6,VertexX(surf,v6),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v6)
			;if the vertex is on the top edge of the mesh then set the vertex on the bottom edge to the same height to ensure tileability
			If v6<GridSize Then
				ve=v6+gridsize*(gridsize-1):VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v6),VertexZ(surf,ve)
			End If

			;next we get the centre vertice of the right edge of the z.x square and raise or lower it by a random amount
			v7=vc+s/2  :  v17=v7-(s/2)   :  v27=v17+(s/2)*GridSize  :  v37=v27+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v7,VertexX(surf,v7),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v7)
			;if the vertex is on the right edge of the mesh then set the vertex on the left edge to the same height to ensure tileability
			If ((v7-gridsize+1)*1.0)/(gridsize*1.0)=Int((v7-gridsize+1)/(gridsize-1))  Then
				ve=v7-gridsize+1:VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v7),VertexZ(surf,ve)
			End If
			
			;next we get the centre vertice of the bottom edge of the z.x square and raise or lower it by a random amount
			v8=vc+(s/2)*GridSize  :  v18=v8-(s/2)*GridSize  :  v28=v18+(s/2)  :  v38=v8+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v8,VertexX(surf,v8),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v8)
			;if the vertex is on the top edge of the mesh then set the vertex on the bottom edge to the same height to ensure tileability
			If v8>GridSize*(gridsize-1) Then
				ve=v8-gridsize*(gridsize-1):VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v8),VertexZ(surf,ve)
			End If
			Next
		Next
		NumSquares=NumSquares*4
		xs=xs*2

		range=range/smoothness
	Next
	Return terrain
End Function
Function CreateGrid(x=9,z=9,w=5,h=5)
	mesh=CreateMesh()
	surf=CreateSurface(mesh)
	
	For xl=0 To x-1
		v=AddVertex(surf,xl*w,0,0)
		vert(xl,0)=v
	Next
	
	For zl=1 To z-1
		For xl=0 To x-1
			v=AddVertex(surf,xl*w,0,zl*-h)
			vert(xl,zl)=v
			If xl>0 Then
				AddTriangle surf,vert(xl,zl),vert(xl-1,zl),vert(xl,zl-1)
				AddTriangle surf,vert(xl,zl-1),vert(xl-1,zl),vert(xl-1,zl-1)					
			End If
			
		Next
	Next
	Return mesh
End Function
Function Log2# ( x# )
	Return Log( x ) / Log( 2 ) 
End Function







Function RandomDiamondSquareTerrain(GridSize,Range#,Smoothness#)
	NumSquares=1; We start with 1 square that is the size of the mesh
	XS=1
	Iterations#=Log2(GridSize-1) ;In the loops we work with progressively smaller and smaller squares
											  ;This is the number of times to execute the loops to get to the smallest
											  ;possible square defined by the vertices.
	Terrain=CreateGrid(GridSize,GridSize)
	surf=GetSurface(Terrain,1)
	SeedRnd (MilliSecs()) 
	For i= 1 To iterations
		s=((GridSize-1)/XS)
		For z=1 To NumSquares/XS
		For x=1 To NumSquares/XS
			;Get the corner vertices of the square defined by z,x
			v1=0+(s*(x-1))+s*(z-1)*GridSize  :  v2=v1+s  :  v3=v1+s*GridSize  :  v4=v3+s
			;Now get the centre vertice of the z,x square and raise or lower it by a random amount
			vc=v1+s/2+(s/2)* GridSize
			AvgHeight=(VertexY(surf,v1)+VertexY(surf,v2)+VertexY(surf,v3)+VertexY(surf,v4))/4
			VertexCoords surf,vc,VertexX(surf,vc),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,vc)
			;next we get the centre vertice of the left edge of the z.x square
			v5=vc-s/2  :  v15=v5-(s/2)*GridSize  :  v25=v15+(s/2)  :  v35=v5+(s/2)
			AvgHeight=(VertexY(surf,v15)+VertexY(surf,v25)+VertexY(surf,v35))/3
			VertexCoords surf,v5,VertexX(surf,v5),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v5)
			
			v6=vc-(s/2)*GridSize  :  v16=v6+(s/2)   :  v26=v16+(s/2)*GridSize  :  v36=v26-(s/2)			
			AvgHeight=(VertexY(surf,v16)+VertexY(surf,v26)+VertexY(surf,v36))/3
			VertexCoords surf,v6,VertexX(surf,v6),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v6)			
			v7=vc+s/2  :  v17=v7-(s/2)   :  v27=v17+(s/2)*GridSize  :  v37=v27+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v7,VertexX(surf,v7),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v7)

			v8=vc+(s/2)*GridSize  :  v18=v8-(s/2)*GridSize  :  v28=v18+(s/2)  :  v38=v8+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v8,VertexX(surf,v8),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v8)
			Next
		Next
		NumSquares=NumSquares*4
		xs=xs*2
		Print numsquares
		range=range/smoothness
	Next
	Return terrain
End Function



Ryudin(Posted 1+ years ago)

 Great code! I'm going to try to add a heightmap saving function to it to export the good maps and use them in my games.


plash(Posted 1+ years ago)

 blitzmax, non-superstrict (minib3d):
Code: BASIC
Import sidesign.minib3d
'Changeable Parameters
GridSize:Int = 129' Must be a 2^n+1
Landform:Float = 600'The bigger the number the greater the difference in heights between highspots And lowspots
Smoothness:Float = 50'The bigger the number the more smoothly the transition between highspots And low spots will occur


'Setup the 3D environment
Graphics3D 1024, 700, 16, 2

Global vert:Int[GridSize, GridSize] 
Wireframe False
AmbientLight(255, 255, 255) 

Local Cam:TCamera = createCamera() 
	MoveEntity Cam, 0, (GridSize - 1) * 3, - (GridSize - 1) * 10 ' Our camera...
	'MoveEntity cam, 0, 10, 0 ' Our camera...
	CameraRange cam,1,10000

'Create 4 copies of the same terrain And position them To show that they are tileable
RandomTerrain = TileableRandomDiamondSquareTerrain(GridSize, Landform, Smoothness) 
'ScaleEntity randomterrain, 5.0, 5.0, 5.0
SmoothTerrain(RandomTerrain, Gridsize) 
SmoothTerrain(RandomTerrain, Gridsize) 
SmoothTerrain(RandomTerrain, Gridsize) 
spacing = (GridSize - 1) * 5'+5 
'RandomTerrain2 = CopyMesh(RandomTerrain, RandomTerrain) 
'EntityFX RandomTerrain2, 2
'PositionEntity(RandomTerrain2, - spacing, 0, 0) 

'RandomTerrain3 = CopyMesh(RandomTerrain, RandomTerrain) 
'EntityFX RandomTerrain3, 2
'PositionEntity(RandomTerrain3, - spacing, 0, spacing) 

'RandomTerrain4 = CopyMesh(RandomTerrain, RandomTerrain) 
'PositionEntity(RandomTerrain4, 0, 0, spacing) 
'EntityFX RandomTerrain4, 2

While Not KeyHit(KEY_ESCAPE) 
   Cls
	If KeyHit(KEY_W) Wireframe True
	TurnEntity RandomTerrain, 0, 1.0, 0
	RenderWorld
	
   Flip
   Delay 20
Wend
End

Function SmoothTerrain(TERRAIN:TMesh, Gridsize) 
 EntityFX TERRAIN, 2
	
  Local surf:TSurface = getSurface(TERRAIN, 1) 
	
	For r = 0 To Gridsize - 1
		fv = r * Gridsize
		For c = 1 To Gridsize - 2
			v1 = fv + c - 1;v2 = fv + c;v3 = fv + c + 1
			h1 = VertexY(surf, v1) ;h2 = VertexY(surf, v2) ;h3 = VertexY(surf, v3) 
			h2 = h1 + ((h3 - h1) / 2) 
			cr = 255 - (255 - h2) 
			cg = 255 - (255 - h2) + 90
			cb = 255 - (255 - (h2 - 200)) 
			If cr > 255 Then cr = 255
			If cg > 255 Then cg = 255
			If cb > 255 Then cb = 255
			VertexCoords surf, v2, VertexX(surf, v2), h2, VertexZ(surf, v2) 
			VertexColor surf, v2, cr, cg, cb
		Next
	Next

	For c = 0 To Gridsize - 1
		For r = 1 To Gridsize - 2
			v1 = c + r * Gridsize - Gridsize;v2 = c + r * Gridsize;v3 = c + r * Gridsize + Gridsize
			h1 = VertexY(surf, v1) ;h2 = VertexY(surf, v2) ;h3 = VertexY(surf, v3) 
			h2 = h1 + ((h3 - h1) / 2) 
			VertexCoords surf, v2, VertexX(surf, v2), h2, VertexZ(surf, v2) 
			cr = 255 - (255 - h2) 
			cg = 255 - (255 - h2) + 90
			cb = 255 - (255 - (h2 - 200)) 
			If cr > 255 Then cr = 255
			If cg > 255 Then cg = 255
			If cb > 255 Then cb = 255
			VertexColor surf, v2, cr, cg, cb
		Next
	Next

End Function


Function TileableRandomDiamondSquareTerrain:TMesh(GridSize:Int, Range:Float, Smoothness:Float) 
	NumSquares:Int = 1' We Start with 1 square that is the size of the MESH 
	XS:Int = 1
	Iterations:Float = Log2(GridSize - 1)    'In the loops we work with progressively smaller And smaller squares 
											  'This is the number of times To execute the loops To get To the smallest
											  'possible square defined by the vertices.

	Local TERRAIN:TMesh = CreateGrid(GridSize, GridSize) 
	surf = getSurface(TERRAIN, 1) 
	SeedRnd (MilliSecs()) 
	For i = 1 To iterations
		s = ((GridSize - 1) / XS) 
		For Z = 1 To NumSquares / XS
		For X = 1 To NumSquares / XS
			'Get the corner vertices of the square defined by z,x
			v1 = 0 + (s * (X - 1)) + s * (Z - 1) * GridSize ; v2 = v1 + s ; v3 = v1 + s * GridSize ; v4 = v3 + s
			'Now get the centre vertice of the z,x square And raise Or Lower it by a random amount
			vc=v1+s/2+(s/2)* GridSize
			AvgHeight = (VertexY(surf, v1) + VertexY(surf, v2) + VertexY(surf, v3) + VertexY(surf, v4)) / 4
			VertexCoords surf, vc, VertexX(surf, vc), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, vc) 
			
			'Next we get the centre vertice of the Left edge of the z.x square And raise Or Lower it by a random amount
			v5 = vc - s / 2 ; v15 = v5 - (s / 2) * GridSize ; v25 = v15 + (s / 2) ; v35 = v5 + (s / 2) 
			AvgHeight = (VertexY(surf, v15) + VertexY(surf, v25) + VertexY(surf, v35)) / 3
			VertexCoords surf, v5, VertexX(surf, v5), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v5) 
			'If the vertex is on the Left edge of the mesh Then set the vertex on the Right edge To the same height To ensure tileability
			If v5 * 1.0 / gridsize * 1.0 = Int(v5 / gridsize) Then
				ve = v5 + gridsize - 1;VertexCoords surf, ve, VertexX(surf, ve), VertexY(surf, v5), VertexZ(surf, ve) 
			End If
			
			'Next we get the centre vertice of the top edge of the z.x square And raise Or Lower it by a random amount
			v6 = vc - (s / 2) * GridSize ; v16 = v6 + (s / 2) ; v26 = v16 + (s / 2) * GridSize ; v36 = v26 - (s / 2) 
			AvgHeight = (VertexY(surf, v16) + VertexY(surf, v26) + VertexY(surf, v36)) / 3
			VertexCoords surf, v6, VertexX(surf, v6), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v6) 
			'If the vertex is on the top edge of the mesh Then set the vertex on the bottom edge To the same height To ensure tileability
			If v6 < GridSize Then
				ve = v6 + gridsize * (gridsize - 1) ;VertexCoords surf, ve, VertexX(surf, ve), VertexY(surf, v6), VertexZ(surf, ve) 
			End If

			'Next we get the centre vertice of the Right edge of the z.x square And raise Or Lower it by a random amount
			v7 = vc + s / 2 ; v17 = v7 - (s / 2) ; v27 = v17 + (s / 2) * GridSize ; v37 = v27 + (s / 2) 
			AvgHeight = (VertexY(surf, v17) + VertexY(surf, v27) + VertexY(surf, v37)) / 3
			VertexCoords surf, v7, VertexX(surf, v7), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v7) 
			'If the vertex is on the Right edge of the mesh Then set the vertex on the Left edge To the same height To ensure tileability
			If ((v7 - gridsize + 1) * 1.0) / (gridsize * 1.0) = Int((v7 - gridsize + 1) / (gridsize - 1)) Then
				ve = v7 - gridsize + 1;VertexCoords surf, ve, VertexX(surf, ve), VertexY(surf, v7), VertexZ(surf, ve) 
			End If
			
			'Next we get the centre vertice of the bottom edge of the z.x square And raise Or Lower it by a random amount
			v8 = vc + (s / 2) * GridSize ; v18 = v8 - (s / 2) * GridSize ; v28 = v18 + (s / 2) ; v38 = v8 + (s / 2) 
			AvgHeight = (VertexY(surf, v17) + VertexY(surf, v27) + VertexY(surf, v37)) / 3
			VertexCoords surf, v8, VertexX(surf, v8), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v8) 
			'If the vertex is on the top edge of the mesh Then set the vertex on the bottom edge To the same height To ensure tileability
			If v8 > GridSize * (gridsize - 1) Then
				ve = v8 - gridsize * (gridsize - 1) ; VertexCoords surf, ve, VertexX(surf, ve), VertexY(surf, v8), VertexZ(surf, ve) 
			End If
			Next
		Next
		NumSquares = NumSquares * 4
		xs = xs * 2

		Range = Range / smoothness
	Next
	
	Return TERRAIN
	
End Function

Function CreateGrid:TMesh(X = 9, Z = 9, W = 5, h = 5) 
  Local MESH:TMesh = createMesh() 
  Local surf:TSurface = CreateSurface(MESH) 
	
	For xl = 0 To X - 1
		v = addVertex(surf, xl * W, 0, 0) 
		vert(xl, 0) = v
	Next
	
	For zl=1 To z-1
		For xl=0 To x-1
			v = addVertex(surf, xl * W, 0, zl * -h) 
			vert[xl, zl] = v
			
			If xl > 0 Then
				addTriangle surf, vert(xl, zl), vert(xl - 1, zl), vert(xl, zl - 1) 
				addTriangle surf, vert(xl, zl - 1), vert(xl - 1, zl), vert(xl - 1, zl - 1) 
				
			End If
			
		Next
	Next
	
   Return MESH
	
End Function

Function Log2:Float(X:Float) 
	Return Log(X) / Log(2) 
	 
End Function

Function RandomDiamondSquareTerrain:Tmesh(GridSize:Int, Range:Float, Smoothness:Float) 
  Local NumSquares:Int = 1' We start with 1 square that is the size of the mesh
  Local XS:Int = 1
  Local Iterations:Float = Log2(GridSize - 1) 'In the loops we work with progressively smaller And smaller squares
											  'This is the number of times To execute the loops To get To the smallest
											  'possible square defined by the vertices.
  Local TERRAIN:TMesh = CreateGrid(GridSize, GridSize) 
  Local surf:TSurface = getSurface(TERRAIN, 1) 
	
	SeedRnd (MilliSecs()) 
	For i = 1 To iterations
		s = ((GridSize - 1) / XS) 
		For Z:Int = 1 To NumSquares / XS
			For X:Int = 1 To NumSquares / XS
				'Get the corner vertices of the square defined by z,x 
				v1 = 0 + (s * (X - 1)) + s * (Z - 1) * GridSize ; v2 = v1 + s ; v3 = v1 + s * GridSize ; v4 = v3 + s
				'Now get the centre vertice of the z,x square And raise Or Lower it by a random amount
				vc = v1 + s / 2 + (s / 2) * GridSize
				AvgHeight = (VertexY(surf, v1) + VertexY(surf, v2) + VertexY(surf, v3) + VertexY(surf, v4)) / 4
				VertexCoords surf, vc, VertexX(surf, vc), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, vc) 
				'Next we get the centre vertice of the Left edge of the z.x square
				v5 = vc - s / 2 ; v15 = v5 - (s / 2) * GridSize ; v25 = v15 + (s / 2) ; v35 = v5 + (s / 2) 
				AvgHeight = (VertexY(surf, v15) + VertexY(surf, v25) + VertexY(surf, v35)) / 3
				VertexCoords surf, v5, VertexX(surf, v5), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v5) 
				
				v6 = vc - (s / 2) * GridSize ; v16 = v6 + (s / 2) ; v26 = v16 + (s / 2) * GridSize ; v36 = v26 - (s / 2) 
				AvgHeight = (VertexY(surf, v16) + VertexY(surf, v26) + VertexY(surf, v36)) / 3
				VertexCoords surf, v6, VertexX(surf, v6), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v6) 
				v7 = vc + s / 2 ; v17 = v7 - (s / 2) ; v27 = v17 + (s / 2) * GridSize ; v37 = v27 + (s / 2) 
				AvgHeight = (VertexY(surf, v17) + VertexY(surf, v27) + VertexY(surf, v37)) / 3
				VertexCoords surf, v7, VertexX(surf, v7), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v7) 
	
				v8 = vc + (s / 2) * GridSize ; v18 = v8 - (s / 2) * GridSize ; v28 = v18 + (s / 2) ; v38 = v8 + (s / 2) 
				AvgHeight = (VertexY(surf, v17) + VertexY(surf, v27) + VertexY(surf, v37)) / 3
				VertexCoords surf, v8, VertexX(surf, v8), Rand(AvgHeight - Range, AvgHeight + Range), VertexZ(surf, v8) 
			Next
		Next
		NumSquares = NumSquares * 4
		xs = xs * 2
		Print numsquares
		Range = Range / smoothness
	Next
	
   Return TERRAIN
   
End Function