2d lanscape generator Blitz3d to BMAX

BlitzMax Forums/BlitzMax Programming/2d lanscape generator Blitz3d to BMAX

Hi i am messing around with random land generation, i took this piece of code of an archive here , it used to make a square heightmap image, i just took one x position and used the heights it genearated to make the 2d version, simple yes....anyway this seems to owrk all fine here is the code in blit3d
;modified 19/4/2008 by DREAM
; added scrolling capability to do more than one landscape for parralax.
; little bit of tidying up.

;Tomis first Blitz progi
;Thanks to Hugo Elias for his nice and very, very informative webpage
;http://freespace.virgin.net/hugo.elias/
;Thanks to Mark for Blitz 
;look at Hugo Elias webpage it's very nice and his pseudo code is nearly cut&paste to blitz !
;http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
;thanks to Bernd Hey he helps in the UAE project i'am proud to know him  

;main
;2 dimensional perlin noise
;very slow couse after searching to long for a bug (uncomen behavior of blitz int() function ) i'am to lazy to optimize
;At the moment each octave uses the same random generator thats poor but if someone likes to change



Global xsize=1024 ;change graphics here
Global ysize=768


Global mapco=3,gy=50
Dim map(xsize,mapco)
Dim mapht(mapco)

Graphics xsize,ysize,0

Global bias#=40		;steeper hills go bigger shalklower ones go smaller
For i=0 To mapco
	mapht(i)=Rand(0,10000)
	generateland(i)
Next
SetBuffer BackBuffer()
Color 20,255,20
Global v=0
Repeat
	Cls
	For v=0 To mapco-1
		drawmap(v)
		movemap(1,v)
	Next
	Flip 0
Until KeyHit(1)

Function movemap(xx,v)
	For x=1 To xsize-xx
		map(x,v)=map(x+xx,v)
	Next
	For x=xsize-xx To xsize
		map(x,v)=nextpoint(v)
	Next
End Function

Function nextpoint(v)
	mapht(v)=mapht(v)+1
	au# = PerlinNoise_2D#(mapht(v),gy)
	r#=au#*bias#
	g#=au#*bias#
	b#=au#*bias
	val=gy-r-b-g
	Return val
End Function

Function drawmap(v)
	For x=1 To xsize
		Line x,map(x,v)+v*100,x,gy+(v*100)+50;400
	Next
End Function

Function generateland(v)
	For x=1 To xsize    
		map(x,v)=nextpoint(v)
	Next
End Function

			
Function Noise#(x#,y#,oktave#) 
	n = x# + y# * 57
	n = (n Shl 13 - x# Mod y#) -x# -y# -n   
	Return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) And 2147483647) / 1073741824.0)
End Function 

;smooth the random numbers
Function SmoothNoise#(xl#,yl#,oktave#)
	corners# = ( Noise#(xl#-1, yl#-1,oktave#)+Noise#(xl#+1, yl#-1,oktave#)+Noise#(xl#-1, yl#+1,oktave#)+Noise#(xl#+1, yl#+1,oktave#) ) / 16 
	sides#   = ( Noise#(xl#-1, yl#,oktave#)  +Noise#(xl#+1, yl#,oktave#)  +Noise#(xl#, yl#-1,oktave#)  +Noise#(xl#, yl#+1,oktave#) ) /  8
	center#  =  Noise#(xl#, yl#,oktave#)/4  
	Return (corners# + sides# + center#)
End Function

;interpolate between points
Function InterpolateNoise#(xo#,yo#,oktave#)
	integer_x#    = Floor(xo#)
	fractional_x# = xo# - integer_x#
	integer_y#    = Floor(yo#)
	fractional_y# = yo# - integer_y#
	v1# = SmoothNoise#(integer_x#,integer_y#,oktave#)
	v2# = SmoothNoise#(integer_x#+1 ,integer_y#,oktave#)
	v3# = SmoothNoise#(integer_x#,integer_y#+1 ,oktave#)
	v4# = SmoothNoise#(integer_x#+1 ,integer_y#+1 ,oktave#)
	i1# = Cosine_Interpolate#(v1# , v2# , fractional_x#)
	i2# = Cosine_Interpolate#(v3# , v4# , fractional_x#)
    Return Cosine_Interpolate#(i1# , i2# , fractional_y#)
End Function


Function PerlinNoise_2D#(x#,y#)
	total# = 0
	p# = 0.15    ;persistance                Try 0.1 to 1
	n# = 1		 ; number of ovtaves         Try 1  to 7
	For oktave# = 0 To n#
		frequency# = (2^oktave#)/40
		amplitude# = (p#^oktave#)
		total# = total# + (InterpolateNoise#(x# * frequency#, y# * frequency#,oktave) * amplitude#)
	Next 
	Return total#
	
End Function


Function Cosine_Interpolate#(a#, b#, x#)
	ft# = x# * 180
	f# = (1 - Cos(ft#)) * 0.5
	Return  (a#*(1-f#) + b#*f#)
End Function



Function linear_Interpolate#(az#, bz#, xz#) 
	Return az#*(1-xz#) + bz#*xz# 
End Function



so now i thought i got the basic idea of whats actually going on nice curvy landscapes rather than the general jerky stuff, i thought i would try and convert it to BMAX

SuperStrict


Global xsize:Int = 1024
Global ysize:Int = 768


Global mapco:Int = 3, gy:Int = 200
Global map:Float[xsize, mapco] 
Global mapht:Int[mapco] 

Graphics xsize,ysize,0

Global bias:Float = 40		'steeper hills go bigger shalklower ones go smaller
For Local i:Int = 0 To mapco - 1
	mapht[i] = Rand(0, 10000) 
	generateland(i)
Next

SetColor 20, 255, 20

Repeat
	Cls
	For Local v:Int = 0 To mapco - 1
		drawmap(v)
		movemap(1,v)
	Next
	Flip
Until KeyHit(KEY_ESCAPE) 

Function movemap(xx:Int, v:Int) 
	For Local x:Int = 1 To xsize - xx
		map[x, v] = map[x + xx, v] 
	Next
	For Local x:Int = xsize - xx To xsize
		map[x, v] = nextpoint(v) 
	Next
End Function

Function nextpoint:Float(v:Int) 
	mapht[v] = mapht[v] + 1
	Local au:Float = PerlinNoise_2D:Float(mapht[v] , gy) 
	Print au
	Local r:Float = au:Float * bias:Float
	Local g:Float = au:Float * bias:Float
	Local b:Float = au:Float * bias
	Local val:Float = gy - r - b - g
	Return val
End Function

Function drawmap(v:Int) 
	For Local x:Int = 1 To xsize
		DrawLine x, map[x, v] + v * 100, x, gy + (v * 100) + 50
	Next
End Function

Function generateland(v:Int) 
	For Local x:Int = 1 To xsize
		map[x, v] = nextpoint(v) 
	Next
End Function

			
'Pseudo random 
Function Noise#(x#,y#,oktave#) 
	Local n:Float = x + y * 57
	Local m%=Int(n)
	m=m Shl 13
	n = (n - x:Float Mod y:Float) - x:Float - y:Float - n
	Return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) And 2147483647) / 1073741824.0)
End Function 

'smooth the random numbers
Function SmoothNoise#(xl#,yl#,oktave#)
	Local corners:Float = (Noise:Float(xl:Float - 1, yl:Float - 1, oktave:Float) + Noise:Float(xl:Float + 1, yl:Float - 1, oktave:Float) + Noise:Float(xl:Float - 1, yl:Float + 1, oktave:Float) + Noise:Float(xl:Float + 1, yl:Float + 1, oktave:Float)) / 16
	Local sides:Float = (Noise:Float(xl:Float - 1, yl:Float, oktave:Float) + Noise:Float(xl:Float + 1, yl:Float, oktave:Float) + Noise:Float(xl:Float, yl:Float - 1, oktave:Float) + Noise:Float(xl:Float, yl:Float + 1, oktave:Float)) / 8
	Local center:Float = Noise:Float(xl:Float, yl:Float, oktave:Float) / 4
	Return (corners# + sides# + center#)
End Function

'interpolate between points
Function InterpolateNoise#(xo#,yo#,oktave#)
	Local integer_x:Float = Floor(xo:Float) 
	Local fractional_x:Float = xo:Float - integer_x:Float
	Local integer_y:Float = Floor(yo:Float) 
	Local fractional_y:Float = yo:Float - integer_y:Float
	Local v1:Float = SmoothNoise:Float(integer_x:Float, integer_y:Float, oktave:Float) 
	Local v2:Float = SmoothNoise:Float(integer_x:Float + 1, integer_y:Float, oktave:Float) 
	Local v3:Float = SmoothNoise:Float(integer_x:Float, integer_y:Float + 1, oktave:Float) 
	Local v4:Float = SmoothNoise:Float(integer_x:Float + 1, integer_y:Float + 1, oktave:Float) 
	Local i1:Float = Cosine_Interpolate:Float(v1:Float, v2:Float, fractional_x:Float) 
	Local i2:Float = Cosine_Interpolate:Float(v3:Float, v4:Float, fractional_x:Float) 
    Return Cosine_Interpolate#(i1# , i2# , fractional_y#)
End Function

Function PerlinNoise_2D#(x#,y#)
	Local total:Float = 0
	Local p:Float = 0.15   'persistance                Try 0.1 to 1
	Local n:Float = 7		 ' number of ovtaves         Try 1  to 7
	For Local oktave:Float = 0 To n
		
		Local frequency:Float = (2 ^ oktave) / 40
		Local amplitude:Float = (p:Float ^ oktave) 
		
		total = total + (InterpolateNoise:Float(x:Float * frequency:Float, y:Float * frequency:Float, oktave) * amplitude:Float) 
		
	Next 
	Return total#
	
End Function

Function Cosine_Interpolate:Float(a:Float, b:Float, x:Float) 
	Local ft:Float = x:Float * 180
	Local f# = (1 - Cos(ft#)) * 0.5
	Return  (a#*(1-f#) + b#*f#)
End Function

Function linear_Interpolate#(az#, bz#, xz#) 
	Return az#*(1-xz#) + bz#*xz# 
End Function


it generates 3 perfectly flat landscapes....

I know it has something to do with the perlin noise as the au value is the same no matter what....anybody got any ideas....its something brain achingly simple i just cant see it.......

I get an unhandled memory exception when compiling in debug mode, complaining about accessing an array out of bounds on the line
map[x, v] = nextpoint(v)


Compiling in debug mode can often steer you to the right direction.

After fixing the issue I also noticed that your pseudo random noise function doesn't seem to use the bitshifted variable 'm' for anything.

I wish I had more time to look into this. I'm also currently implementing procedurally generated content to my game.

One thing that immediately springs to mind is that BlitzMax arrays are zero-indexed, and so you have to go from 0 to size-1 not from 1 to size. ( Blitz3D is very lax in this regard as they are zero indexed still but it creates the array one bigger than you require just in case you forget.)

Possibly And should be changed to & because BlitzMax uses that for bitwise operations.

Anyway, I quickly hacked up a conversion, and got this:

'modified 19/4/2008 by DREAM
' added scrolling capability To do more than one landscape For parralax.
' little bit of tidying up.

'Tomis first Blitz progi
'Thanks To Hugo Elias For his nice And very, very informative webpage
'http://freespace.virgin.net/hugo.elias/
'Thanks To Mark For Blitz 
'look at Hugo Elias webpage it's very nice and his pseudo code is nearly cut&paste to blitz !
'http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
'thanks To Bernd Hey he helps in the UAE project i'am proud to know him  

'main
'2 dimensional perlin noise
'very slow couse after searching To Long For a bug (uncomen behavior of blitz Int() Function ) i'am to lazy to optimize
'At the moment each octave uses the same random generator thats poor but If someone likes To change


SuperStrict


Global xsize:Int=1024 'change Graphics here
Global ysize:Int=768


Global mapco:Int=3,gy:Int=50
Global map:Int[xsize,mapco]
Global mapht:Int[mapco]

Graphics xsize,ysize,0

Global bias:Float=40		'steeper hills go bigger shalklower ones go smaller
For Local i:Int=0 To mapco-1
	mapht[i]=Rand(0,10000)
	generateland(i)
Next
SetColor 20,255,20
Global v:Int=0
Repeat
	Cls
	For v=0 To mapco-1
		drawmap(v)
		movemap(1,v)
	Next
	Flip 0
Until KeyHit(1)

Function movemap(xx:Int,v:Int)
	For Local x:Int=1 To xsize-xx-1
		map[x,v]=map[x+xx,v]
	Next
	For Local x:Int=xsize-xx To xsize-1
		map[x,v]=nextpoint(v)
	Next
End Function

Function nextpoint:Int(v:Int)
	mapht[v]=mapht[v]+1
	Local au:Float = PerlinNoise_2D#(mapht[v],gy)
	Local r:Float=au*bias
	Local g:Float=au*bias
	Local b:Float=au*bias
	Return gy-r-b-g
End Function

Function drawmap(v:Int)
	For Local x:Int=0 To xsize-1
		DrawLine(x,map[x,v]+v*100,x,gy+(v*100)+50) '400
	Next
End Function

Function generateland(v:Int)
	For Local x:Int=0 To xsize-1
		map[x,v]=nextpoint(v)
	Next
End Function

			
Function Noise:Float(x:Float,y:Float,oktave:Float) 
	Local n:Int = x + y * 57
	n = (n Shl 13 - x Mod y) -x -y -n   
	Return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 2147483647) / 1073741824.0)
End Function 

'smooth the random numbers
Function SmoothNoise:Float(xl:Float,yl:Float,oktave:Float)
	Local corners:Float = ( Noise(xl-1, yl-1,oktave)+Noise(xl+1, yl-1,oktave)+Noise(xl-1, yl+1,oktave)+Noise(xl+1, yl+1,oktave) ) / 16 
	Local sides:Float   = ( Noise(xl-1, yl,oktave)  +Noise(xl+1, yl,oktave)  +Noise(xl, yl-1,oktave)  +Noise(xl, yl+1,oktave) ) /  8
	Local center:Float  =  Noise#(xl, yl,oktave)/4  
	Return (corners + sides + center)
End Function

'interpolate between points
Function InterpolateNoise:Float(xo:Float,yo:Float,oktave:Float)
	Local integer_x:Float    = Floor(xo)
	Local fractional_x:Float = xo - integer_x
	Local integer_y:Float    = Floor(yo)
	Local fractional_y:Float = yo - integer_y
	Local v1:Float = SmoothNoise(integer_x,integer_y,oktave)
	Local v2:Float = SmoothNoise(integer_x+1 ,integer_y,oktave)
	Local v3:Float = SmoothNoise(integer_x,integer_y+1 ,oktave)
	Local v4:Float = SmoothNoise(integer_x+1 ,integer_y+1 ,oktave)
	Local i1:Float = Cosine_Interpolate(v1 , v2 , fractional_x)
	Local i2:Float = Cosine_Interpolate(v3 , v4 , fractional_x)
    Return Cosine_Interpolate(i1 , i2 , fractional_y)
End Function


Function PerlinNoise_2D:Float(x:Float,y:Float)
	Local total:Float = 0
	Local p:Float = 0.15    'persistance                Try 0.1 To 1
	Local n:Float = 1		 ' number of ovtaves         Try 1  To 7
	For Local oktave:Float = 0 To n
		Local frequency:Float = (2^oktave)/40
		Local amplitude:Float = (p^oktave)
		total = total + (InterpolateNoise(x * frequency, y * frequency,oktave) * amplitude)
	Next 
	Return total
End Function


Function Cosine_Interpolate:Float(a:Float, b:Float, x:Float)
	Local ft:Float = x * 180
	Local f:Float = (1 - Cos(ft)) * 0.5
	Return  (a*(1-f) + b*f)
End Function



Function linear_Interpolate#(az:Float, bz:Float, xz:Float) 
	Return az*(1-xz) + bz*xz 
End Function




Is that what it's supposed to look like? I don't have B3D installed so I can't compare.

yep this is what it is supposed to do thanks, seem apart from the array issue it was a few int to float and vice versa conversions that had me stumped, elsewise its pretty much the same......think we should add it to the archives as a 2d land geneartion, as its stored in an array i imagine it could be used to make destructible aka worms style landscapes.....