Code archives/Graphics/Heightmap Toolbox

This code has been declared by its author to be Public Domain code.

Download source code

Heightmap Toolbox by Booticus2005
Hey all! I'm posting this for Shane since he already put this in the Blitzmax Programming Forum, I dont want anyone to miss out on this fantastic code! It generates heightmaps with different techniques; Fault, Perlin, Midpoint Displacement etc. Any questions or comments should be sent to Shane at impixi@...
Strict

Rem

HeightMap Toolbox
V0.1.0 BETA

By Shane Raffa
May 2005

Incorporating code (adapted) by 
 * Shawn C. Swift (Perlin noise stuff)
 * Simon Wetterlind (Midpoint displacement stuff)

PURPOSE

	A self-contained package of heightmap creating, processing, exporting, and 
	importing utilities.

TEST SYSTEM

	Athlon XP 1600+, 512MB, GeForce 3 Ti200 (64MB)
	Windows XP, BlitzMax

IMPLEMENTED METHODS AND FUNCTIONS:
	
	createRandomMap
	createHillMap
	createParticleSMap
	createParticleRMap
	createFaultMap
	createPerlinMap
	createMPDMap
		recurseMPD
		MPD
	
	fill
	resize
	normalise
	smoothen
	flatten
	makeCoast
	
	exportPNG
	importPNG
	exportX3D
	exportBin
	importBin

    blendMapsAdd	
    blendWithMapAdd
    blendMapsSub	
    blendWithMapSub
    blendMapsMul
    blendWithMapMul
    blendMapsDiv
    blendWithMapDiv
    blendMapsHi
    blendWithMapHi
    blendMapsLo
    blendWithMapLo
    blendMapsRep
    blendWithMapRep

	renderToBackBuffer
	renderToImage
	renderToPixmap
	
TODO: 

	makeRivers
	makeIsland
	importX3D
	{Mac OS 10.x port}
	{improve documentation}

End Rem

Type THeightMap

  Field Width = 128				'Width (units) > 0
  Field Height = 128			'Height (units) > 0
  Field Map#[Width, Height]  	'Matrix of height values (floats) >=0.0 <=1.0 normalised

  Rem fill(val# = 0.0)
  Set all heights to a specific value.
  val#: value to use. Use 0.0 to clear the map.
  End Rem
  Method fill(val# = 0.0)

    Local x, z

    For x = 0 To Width - 1
      For z = 0 To Height - 1
        Map#[x, z] = val#
      Next
    Next

  End Method
 
  Rem resize(w, h)
  Resize the map.
  w: width. > 0. Higher = slower performance and increased memory consumption. 
  h: height. > 0. Higher = slower performance and increased memory consumption.
  End Rem
  Method resize(w, h)
    
    If Not ((w > 0) And (h > 0)) Return 

    Map# = Null
    FlushMem

    Width = w
    Height = h
    Map# = New Float[Width, Height]

  End Method

  Rem createRandomMap(seed)
  Create a map of random height between 0.0 and 1.0.
  seed: random seed. Use Millisecs() to generate a different result every time.
  End Rem
  Method createRandomMap(seed)

    Local x, z

    SeedRnd(seed)

    For x = 0 To Width - 1
      For z = 0 To Height - 1
        Map#[x, z] = Rnd()
      Next
    Next

  End Method

  Rem createHillMap(seed, numhills, maxhsize)
  Create a map using the "hill algorithm".
  seed: random seed. Use Millisecs() to generate a different result every time.
  numhills: number of hills. (>1000) is best. Minimum 1.
  maxhsize: maximum hill radius. For best results, value should be significantly 
  less than the map's shortest dimension.
  End Rem
  Method createHillMap(seed, numhills, maxhsize)

    Local i, n, x, z, centrex, centrez, radius, startx, endx, startz, endz, ipos
    Local y#
  
    SeedRnd(seed)

    fill(0.0)
  
    For n = 1 To numhills

	  centrex = Rand(0, Width - 1)
	  centrez = Rand(0, Height - 1)
	  radius = Rand(0, Abs(maxhsize))

      startx = centrex - radius
      If startx < 0
	    startx = 0
      EndIf

      endx = centrex + radius
	  If endx > Width
	    endx = Width
      EndIf

      startz = centrez - radius
      If startz < 0
	    startz = 0
      EndIf

      endz = centrez + radius
      If endz > Height 
	    endz = Height
      EndIf

      For x = startx To endx - 1
        For z = startz To endz - 1
	   	  y# = (radius * radius) - (((x - centrex) * (x - centrex)) + ((z - centrez) * (z - centrez)))
	      If y# > 0.0
	        Map#[x, z] :+ y#
	      EndIf
	    Next
	  Next
    
    Next
  
    normalise()
  
  End Method

  Rem createParticleSMap(seed, particles, clusters)
  Create a map using the "sticky particle deposition" algorithm.
  seed: random seed. Use Millisecs() to generate a different result every time.
  particles: number of particles to calculate per cluster. Minimum 1.
  cluster: number of clusters: higher number gives greater map density. Minimum 1.
  End Rem
  Method createParticleSMap(seed, particles, clusters)

    Local m, n, x, z
    Local y#, disp# = 1.0
  
    SeedRnd(seed)

    fill(0.0)
  
    For m = 0 To clusters - 1
  
      x = Rand(0, Width - 1) 
      z = Rand(0, Height - 1)
	
      For n = 0 To particles - 1
	
        If ((x < Width) And (z < Height) And (x >= 0) And (z >= 0))
	      y# = Map#[x, z] + disp#
	      Map#[x, z] = y#
	    EndIf
	
	    Select Rand(0, 3)
          Case 0
            x :+ 1
          Case 1
            x :- 1
          Case 2
            z :+ 1
          Case 3
            z :- 1
        End Select

      Next

    Next

    normalise()
  
  End Method

  Rem createParticleRMap(seed, particles, clusters)
  Create a map using the "rolling particle deposition" algorithm.
  seed: random seed. Use Millisecs() to generate a different result every time.
  particles: number of particles to calculate per cluster. Minimum 1.
  cluster: number of clusters: higher number gives greater map density. Minimum 1.
  End Rem
  Method createParticleRMap(seed, particles, clusters)

    Local m, n, x, z, x2, z2, startx, endx, startz, endz
    Local y#, y2#, disp# = 1.0
  
    SeedRnd(seed)

    fill(0.0)
  
    For m = 0 To clusters - 1
  
      x = Rand(0, Width - 1) 
      z = Rand(0, Height - 1)
	
      For n = 0 To particles - 1
	
        If ((x < Width) And (z < Height) And (x >= 0) And (z >= 0))

	      y# = Map#[x, z] + disp#
	      Map#[x, z] = y#
	
	      startx = x - 1
          If startx < 0  
		    startx = 0
		  EndIf
          endx = x + 1
          If endx > Width 
  		    endx = Width
          EndIf

          startz = z - 1
          If startz < 0 
		    startz = 0
		  EndIf
          endz = z + 1
          If endz > Height
		    endz = Height
          EndIf

          For x2 = startx To endx - 1
            For z2 = startz To endz - 1
		      y2# = Map#[x2, z2]
              If y2# < y# 
                Map#[x2, z2] = y2# + disp#
              EndIf
            Next
          Next
	
	    EndIf
	
	    Select Rand(0, 3)
          Case 0
            x :+ 1
          Case 1
            x :- 1
          Case 2
            z :+ 1
          Case 3
            z :- 1
        End Select

      Next

    Next

    normalise()
  
  End Method
  
  Rem createFaultMap(seed, realism)
  Create a map using the "fault line" algorithm.
  seed: random seed. Use Millisecs() To generate a different result every time.
  realism: number of fault lines: higher number (> 1000) gives greater realism. Minimum 1.
  End Rem
  Method createFaultMap(seed, realism)

    Local n, x, z
    Local d#, disp#, v#, a#, b#, c#
  
    SeedRnd(seed)

    fill(0.0)
  
    d# = Sqr((Width * Width) + (Height * Height))
    disp# = 10.0

    For n = 1 To realism
  
      v# = Rnd(1,359)
	  a# = Sin(v#)
      b# = Cos(v#)
      c# = (RndFloat() * d#) - (d# / 2)

      For x = 0 To Width - 1
        For z = 0 To Height - 1
          If (((a# * x) + (b# * z) - c#) > 0.0)
            Map#[x, z] :+ disp#
          Else
            Map#[x, z] :- disp#
          EndIf
        Next
      Next

    Next

    normalise()

  End Method

  Rem createPerlinMap(seed, scale#, multiplier#)
  Create a map using the "perlin noise" alogorithm.
  ADAPTED from code obtained from the blitzbasic.com code archives.
  **** ORIGINAL AUTHOR: Shawn C. Swift ****
  IMPORTANT NOTE: This method will only work properly on maps with equal Width and 
  Height dimensions that are a power of two: eg 256 x 256.
  seed: random seed. Use Millisecs() To generate a different result every time.
  "scale# is the maximum height of the most frequent and smallest bumps in the terrain." - S. Swift.
  "multiplier# is how much each successive pass multiplies scale# by." - S. Swift.
  End Rem
  Method createPerlinMap(seed, scale#, multiplier#)

    If Not(Width = Height) Return

    SeedRnd(seed)

    Local size = Width
    Local x, z, ipos, ScaleDifference, Hx, Hz, Height_Z, Height_X,  Noise_Z, Noise_X
    Local max_height# = scale
    Local NoiseMapSize = Floor(size / 2)
 	Local i;
	Local NoiseMap#[NoiseMapSize + 1, NoiseMapSize + 1]

	Local StepSize#, N1#, N2#, N3#, N4#, Iy#, ICy#, Ix#, ICx#, Na#, Nb#, Nc#, Nd#, y#
	
	For x = 0 To size - 1
      For z = 0 To size - 1
        Map#[x, z] = RndFloat() * scale
	  Next
  	Next
  
    max_height# :* multiplier#
	
   Repeat
   
      For Noise_Z = 0 To NoiseMapSize
	    For Noise_X = 0 To NoiseMapSize
		    NoiseMap#[Noise_X, Noise_Z] = RndFloat() * max_height#
		Next
	  Next
	 
      ScaleDifference = size / NoiseMapSize
      StepSize = 1.0 / ScaleDifference
      	  
      For Noise_Z = 0 To NoiseMapSize - 1
	    For Noise_X = 0 To NoiseMapSize - 1
  	      N1# = NoiseMap#[Noise_X, Noise_Z]
		  N2# = NoiseMap#[(Noise_X + 1), Noise_Z]  
	      N3# = NoiseMap#[Noise_X, (Noise_Z + 1)]
	      N4# = NoiseMap#[(Noise_X + 1), (Noise_Z + 1)]
	      Hx = Noise_X * ScaleDifference
	      Hz = Noise_Z * ScaleDifference
	      Iy# = 0.0
	
	      For Height_Z = 0 To ScaleDifference - 1
			ICy# = 1.0 - ((Cos(Iy# * 180.0) + 1.0) / 2.0)
		    Ix# = 0.0			
            
		    For Height_X = 0 To ScaleDifference - 1
			   ICx = 1.0 - ((Cos(Ix * 180.0) + 1.0) / 2.0)
  		       Na# = N1# * (1.0 - ICx#)
		       Nb# = N2# * ICx#;
		       Nc# = N3# * (1.0 - ICx#)
	  	       Nd# = N4# * ICx#
							
		       y# = Map#[(Hx + Height_X), (Hz + Height_Z)]
		       Map#[(Hx + Height_X), (Hz + Height_Z)] = (y# + (Na# + Nb#) * (1.0 - ICy#) + (Nc# + Nd#) * ICy#)
		       Ix# = Ix# + StepSize;
		    Next
					
		    Iy# = Iy# + StepSize#	

	      Next
	
	    Next  	
      Next
				
    NoiseMapSize :/ 2
    max_height# :* multiplier
			
    Until (NoiseMapSize < 1)

	normalise()

  End Method

  Rem
  createMPDMap(seed, grain#)
  recurseMPD(x0, y0, x2, y2, grain#, level#)
  mpd#(x0, y0, x1, y1, x2, y2, grain#, level#)

  ADAPTED from code obtained from the BlitzCoder.com code database.
  **** ORIGINAL AUTHOR: Simon Wetterlind 13-08-2002 ****
  **** v.0.9.3 - Revised: 18-11-2002 by Simon Wetterlind. ****

  These methods are used to create a terrain map using the 
  Midpoint Displacement fractal algorithm (ie Plasma algorithm).
  grain# is the "graininess" i.e. the influence of randomness.

  seed: random seed. Use Millisecs() To generate a different result every time.
  End Rem
  Method createMPDMap(seed, grain#)

     fill(-1.0)

     SeedRnd(seed)

     Map#[0, 0] = RndFloat()
     Map#[(Width - 1), 0] = RndFloat()
     Map#[0, (Height - 1)]= RndFloat()
     Map#[(Width - 1), (Height - 1)] = RndFloat()

     recurseMPD(0, 0, Width - 1, Height - 1, grain#, 1.0)

     normalise()

  End Method

  Method recurseMPD(x0, z0, x2, z2, grain#, level#)

     If (x2 - x0 < 2) And (z2 - z0 < 2) Then Return
     
     Local v#, i#

     ' change the calculation of level# To (possibly) achieve 
     ' strange results
     level# = 2.0 * level#
     
     Local x1 = Ceil((x0 + x2) / 2.0)
     Local z1 = Ceil((z0 + z2) / 2.0)
     
     v# = Map#[x1, z0]
     If v# = -1.0 
       v# = MPD#(x0, z0, x1, z0, x2, z0, grain#, level#)
     EndIf
     i# = v#
     
     v# = Map#[x2, z1]
     If v# = -1.0 
       v# = MPD#(x2, z0, x2, z1, x2, z2, grain#, level#)
     EndIf
     i# :+ v#
     
     v# = Map#[x1, z2]
     If v# = -1.0 
       v# = MPD#(x0, z2, x1, z2, x2, z2, grain#, level#)
     EndIf
     i# :+ v#

     v# = Map#[x0, z1]
     If v# = -1.0 
       v# = MPD#(x0, z0, x0, z1, x0, z2, grain#, level#)
     EndIf
     i# :+ v#

     If Map#[x1, z1] = -1.0 
       Map#[x1, z1] = i# / 4.0 + Rnd(-grain#, grain#) / level#
     EndIf
 
     RecurseMPD(x0, z0, x1, z1, grain#, level#)
     RecurseMPD(x1, z0, x2, z1, grain#, level#)
     RecurseMPD(x1, z1, x2, z2, grain#, level#)
     RecurseMPD(x0, z1, x1, z2, grain#, level#)

  End Method

  Method MPD#(x0, z0, x1, z1, x2, z2, grain#, level#)

     Local r# = 0

     r# :+ (Map#[x0, z0] + Map#[x2, z2]) / 2.0
     
     If r# < 0.0 Then r# = 0.0
     If r# > 1.0 Then r# = 1.0
 
     Map#[x1, z1] = r#
     
     Return r#
     
  End Method

  Rem normalise()
    Normalise all map values to between 0 and 1.
  End Rem
  Method normalise()

   Local x, z;
   Local minv# = 10^38, maxv# = 10^-38, y#
  
   For x = 0 To Width - 1
     For z = 0 To Height - 1

       y# = Map#[x, z]
 	   If y# < minv#
	     minv# = y#
	   Else
	     If y# > maxv#
		   maxv# = y#
		 EndIf
	   EndIf
	  
     Next
   Next

   For x = 0 To Width - 1
     For z = 0 To Height - 1
       y# = (Map#[x, z] - minv#) / (maxv# - minv#)
	   Map#[x, z] = y#
	 Next
   Next	
	
  End Method

  Rem smoothen(k#) 
  Smooth the map values.
  Some maps require more smoothing than others to create more realistic terrains.
  k#: smoothing factor. Minumum 0.0 (extreme). Maxumum 1.0 (no smoothing).
  End Rem
  Method smoothen(k#)
 
    Local x, z
    Local y#, y2#

    For x = 1 To Width - 1
      For z = 0 To Height - 1
	    y# = Map#[x, z]
	    y2# = Map#[(x - 1), z]
	    Map#[x, z] = y2# * (1 - k#) + y# * k#
      Next
    Next

    For x = (Width - 3) To 0 Step -1
      For z = 0 To Height - 1
	    y# = Map#[x, z]
	    y2# = Map#[(x + 1), z]
	    Map#[x, z] = y2# * (1 - k#) + y# * k#
      Next
    Next

    For x = 0 To Width - 1
      For z = 1 To Height - 1
	    y# = Map#[x, z]
	    y2# = Map#[x, (z - 1)]
	    Map#[x, z] = y2# * (1 - k#) + y# * k#
      Next
    Next

    For x = 0 To Width - 1
      For z = (Height - 3) To 0 Step -1
	    y# = Map#[x, z]
	    y2# = Map#[x, (z + 1)]
	    Map#[x, z] = y2# * (1 - k#) + y# * k#
      Next
    Next

  End Method

  Rem flatten(value#)
  'Flatten' the map values.
  value#: flattening amount. 1 = no flattening. Minimum 1. Maximum (suggested) 4.
  End Rem
  Method flatten(value#)

    Local x, z
    Local y#
  
    For x = 0 To Width - 1
      For z = 0 To Height - 1
        y# = Map#[x, z] ^ value#
        Map#[x, z] = y#
      Next
    Next

  End Method
  
  Rem makeCoast(extent#, depth#)
  Create a crude coastline effect. For best results, smoothing should be applied 
  after this process.
  extent#: extent of coastilisation. 0.0 to 1.0 = None To 100%.
  depth#: depth. 0.0 To 1.0 = Shallow to deep.*/
  End Rem
  Method makeCoast(extent#, depth#)

    Local x, z
	Local y#, e#, d#, minv# = 10^38, maxv# = 10^-38
	
    For x = 0 To Width - 1
      For z = 0 To Height - 1
        y# = Map#[x, z]
	    If y# < minv#
	      minv# = y#
	    Else
	      If y# > maxv#
		    maxv# = y#
		  EndIf
	    EndIf
	  Next
	Next

	e# = (maxv# - minv#) * extent#
	d# = (maxv# - minv#) * depth#
	
    For x = 0 To Width - 1
      For z = 0 To Height - 1
 	    y# = Map#[x, z]
	    If y# <= (minv# + e#)
	      Map#[x, z] = y# - d#
	    EndIf
	  Next
	Next   
   
    normalise()

  End Method

  Rem exportToPNG(url$ = "test.png", clvl = 9)
    Save the map to a greyscale PNG file.
    url$: target file. 
    clvl: Compression level: 0 to 9: low to high. Higher = slower.
  End Rem
  Method exportPNG(url$ = "test.png", clvl = 9)

    Local result = False
    Local pmap:TPixmap = CreatePixmap(Width, Height, PF_RGBA8888)

    renderToPixmap(pmap)
    result = SavePixmapPNG(pmap, url$, clvl)

    pmap = Null
    FlushMem

    If result 
      Print url$ + " saved." 
    Else
      Print url$ + " could NOT be saved."
    EndIf

  End Method

  Rem importFromPNG(url$)
    Import from a PNG file.
    url$: source file. Only the blue component data is used.
  End Rem
  Method importPNG(url$)

    Local x, z, c

    Local pmap:TPixmap = LoadPixmapPNG(url$)

    If pmap = Null
      Print url$ + " could NOT be loaded."
      FlushMem
      Return
    Else
      Print url$ + " loaded."       
    EndIf

    resize(pmap.Width, pmap.Height)
   
    For x = 0 To Width - 1
      For z = 0 To Height - 1
        c = ReadPixel(pmap, x, z)
        c :| c Shr 24
        Map#[x, z] = $000000 | c
      Next
    Next

    normalise()

    pmap = Null
    FlushMem

  End Method

  Rem exportToX3D(url$ = "test.x3d", tpl$ = "", hmulti# = 10.0, xspacing# = 100.0, zspacing# = 100.0, prec = 4)
  Reads an X3d V3.0 file (used as a template) and generates a new X3d file 
  incorporating the original file and "ElevationGrid" data generated from the map data.
  url$: Target file name. Any existing file with the same name will be REPLACED.
  templ$ = source X3d file name: the "ElevationGrid" tag must be empty and start 
  on a new line ie: "<ElevationGrid />" without the quotes. If the template file is 
  not found then internal X3d code is used.
  hmulti# = height multiplyer: higher values will produce higher/steeper terrain elements.
  xSpacing# = corresponds to the x3d ElevationGrid xSpacing property.
  zSpacing# = corresponds to the x3d ElevationGrid zSpacing property.
  prec = precision (number of digits) for the exported height values. 1 to 8. eg 4 = 1.34 or 12.2 etc
  End Rem
  Method exportX3D(url$ = "test.x3d", tpl$ = "", hmulti# = 10.0, xspacing# = 100.0, zspacing# = 100.0, prec = 4)

    Local pre$ = ""
    Local post$ = ""
    Local tag$ = "<ElevationGrid ccw='true' "
    tag$ :+ "creaseAngle='0.76' "
    tag$ :+ "solid='false' "
    tag$ :+ "colorPerVertex='true' "
    tag$ :+ "normalPerVertex='true' "
    tag$ :+ "xDimension='" + Width + "' "
    tag$ :+ "xSpacing='" + xspacing# + "' "
    tag$ :+ "zDimension='" + Height + "' "
    tag$ :+ "zSpacing='" + zspacing# + "' height='~r"

    Local templ:TStream = OpenFile(tpl$)
    If Not templ
      Print "Template file " + tpl$ + " could NOT be opened. Using internal template..."
      pre$ = "<?xml version='1.0'?>~r"
      pre$ :+ "<!DOCTYPE X3D Public 'ISO//Web3D//DTD X3D 3.0//EN' 'http://www.web3d.org/specifications/x3d-3.0.dtd'>~r"
      pre$ :+ "<X3D profile='Immersive' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-3.0.xsd'>~r"
      pre$ :+ "<head><meta name='generator' content='Heightmap Toolbox V0.1'/></head>~r"
      pre$ :+ "<Scene><NavigationInfo Type='~qFLY~q ~qANY~q' speed='3.0' /><Viewpoint description='VP1' orientation='0 0 0 0' position='20 20 100' centerOfRotation='90 0 0'/>~r"
      pre$ :+ "<Shape><Appearance><Material diffuseColor='0.4 0.4 0.1' emissiveColor='0.3 0.3 0.3' /></Appearance>~r"
      post$ = "~r</Shape></Scene></X3D>"
    Else 
      Print "Using template file " + tpl$ + "."
    EndIf

    Local result = CreateFile(url$)

    If Not result  
      Print url$ + " could NOT be created."
      Return
    EndIf

    Local x, z, spos
    Local n$, t$, l$

    Local file:TStream = OpenFile(url$)

    Try

    If templ
      t$ = "<ElevationGrid />"
      l$ = ReadLine (templ)
      spos = Instr(l$, t$)
      While Not Eof(templ) 
        If spos > 0 Then Exit
        WriteLine file, l$
        l$ = ReadLine (templ)
        spos = Instr(l$, t$)
      Wend
      
    Else 
      WriteString(file, pre$)
    EndIf

    WriteString(file, tag$)

    For x = 0 To Width - 1
      For z = 0 To Height - 1
        n$ = String.FromFloat(Map#[x, z] * hmulti#)
        n$ = n$[..prec] + " "
        WriteString(file, n$)
      Next
    Next

    WriteString(file, "'/>")

    If templ
      While Not Eof(templ)
        l$ = ReadLine (templ)
        WriteLine file, l$
      Wend
    Else
      WriteString(file, post$)
    EndIf

    CloseFile(file)
    If templ CloseFile(templ)

    Catch ex:Object
      Print "File IO error."
      Return
    End Try

    Print "X3D file " + url$ + " saved."

  End Method

  Rem exportBin(url$ = "test.bin")
    Save heightmap data as a binary file. 
    File Structure:
    	1 * Int (Width)
    	1 * Int (Height) 
    	Width * Height * Floats (height values) 
    url$: target file name. 
  End Rem
  Method exportBin(url$ = "test.bin")

    Local result = False

    result = CreateFile(url$)

    If Not result  
      Print url$ + " could NOT be created."
      Return
    EndIf

    Local x, z

    Try

    Local file:TStream = OpenFile(url$)

    WriteInt(file, Width)
    WriteInt(file, Height)

    For x = 0 To Width - 1
      For z = 0 To Height - 1
        WriteFloat(file, Map#[x, z])
      Next
    Next
    
    CloseFile(file)

    Catch ex:Object
      Print "File IO error."
      Return
    End Try

    Print "Binary file " + url$ + " created."

  End Method

  Rem importBin(url$ = "test.bin")
    Load heightmap data from a binary file that was previously saved using exportBin. 
    url$: source file name. 
  End Rem
  Method importBin(url$ = "test.bin")

    Local x, z

    Local file = False

    file = OpenFile(url$)

    If Not file  
      Print url$ + " could NOT be opened."
      Return
    EndIf

    Try

    resize(Readint(file), Readint(file))

    For x = 0 To Width - 1
      For z = 0 To Height - 1
        Map#[x, z] = ReadFloat(file)
      Next
    Next

    Catch ex:Object
      Print "File IO error."
      Return
    End Try

    Print "Binary file " + url$ + " loaded."

  End Method

  Rem blendMapsAdd(src1:THeightMap, src2:THeightMap, outp:THeightMap)
  Blends two maps using an additive process.
  src1: source THeightMap instance #1.
  src2: source THeightMap instance #2.
  outp: output THeightMap instance into which the results will be stored.
  End Rem
  Function blendMapsAdd(src1:THeightMap, src2:THeightMap, outp:THeightMap)

    Local x, z
    Local y1#, y2#
    
    For x = 0 To outp.Width - 1
      For z = 0 To outp.Height - 1

         If (x < src1.Width) And (z < src1.Height)
           y1# = src1.Map#[x, z]
         Else
           y1# = 0.0
         EndIf  
         If (x < src2.Width) And (z < src2.Height)
           y2# = src2.Map#[x, z]
         Else
           y2# = 0.0
         EndIf  

         outp.Map#[x, z] = y1# + y2#

      Next
    Next
    
    outp.normalise()

  End Function

  Rem blendWithMapAdd(src:THeightMap)
  Blends the current THeightMap instance with another THeightMap instance using a 
  an additive process.
  src: THeightMap to blend with.
  End Rem
  Method blendWithMapAdd(src:THeightMap)

    blendMapsAdd(Self, src, Self)

  End Method

  Rem blendMapsSub(src1:THeightMap, src2:THeightMap, outp:THeightMap)
  Blends two maps using a subtractive process.
  src1: source THeightMap instance #1.
  src2: source THeightMap instance #2.
  outp: output THeightMap instance into which the results will be stored.
  End Rem
  Function blendMapsSub(src1:THeightMap, src2:THeightMap, outp:THeightMap)

    Local x, z
    Local y1#, y2#
    
    For x = 0 To outp.Width - 1
      For z = 0 To outp.Height - 1

         If (x < src1.Width) And (z < src1.Height)
           y1# = src1.Map#[x, z]
         Else
           y1# = 0.0
         EndIf  
         If (x < src2.Width) And (z < src2.Height)
           y2# = src2.Map#[x, z]
         Else
           y2# = 0.0
         EndIf  

         outp.Map#[x, z] = y1# - y2#

      Next
    Next
    
    outp.normalise()

  End Function

  Rem blendWithMapSub(src:THeightMap)
  Blends the current THeightMap instance with another THeightMap instance using a 
  a subtractive process.
  src: THeightMap to blend with.
  End Rem
  Method blendWithMapSub(src:THeightMap)

    blendMapsSub(Self, src, Self)

  End Method

  Rem blendMapsMul(src1:THeightMap, src2:THeightMap, outp:THeightMap)
  Blends two maps using an multiplicative process.
  src1: source THeightMap instance #1.
  src2: source THeightMap instance #2.
  outp: output THeightMap instance into which the results will be stored.
  End Rem
  Function blendMapsMul(src1:THeightMap, src2:THeightMap, outp:THeightMap)

    Local x, z
    Local y1#, y2#
    
    For x = 0 To outp.Width - 1
      For z = 0 To outp.Height - 1

         If (x < src1.Width) And (z < src1.Height)
           y1# = src1.Map#[x, z]
         Else
           y1# = 0.0
         EndIf  
         If (x < src2.Width) And (z < src2.Height)
           y2# = src2.Map#[x, z]
         Else
           y2# = 0.0
         EndIf  

         outp.Map#[x, z] = y1# * y2#

      Next
    Next
    
    outp.normalise()

  End Function

  Rem blendWithMapMul(src:THeightMap)
  Blends the current THeightMap instance with another THeightMap instance using a 
  an multiplicative process.
  src: THeightMap to blend with.
  End Rem
  Method blendWithMapMul(src:THeightMap)

    blendMapsMul(Self, src, Self)

  End Method

  Rem blendMapsDiv(src1:THeightMap, src2:THeightMap, outp:THeightMap)
  Blends two maps using a division process.
  src1: source THeightMap instance #1.
  src2: source THeightMap instance #2.
  outp: output THeightMap instance into which the results will be stored.
  End Rem
  Function blendMapsDiv(src1:THeightMap, src2:THeightMap, outp:THeightMap)

    Local x, z
    Local y1#, y2#
    
    For x = 0 To outp.Width - 1
      For z = 0 To outp.Height - 1

         If (x < src1.Width) And (z < src1.Height)
           y1# = src1.Map#[x, z]
         Else
           y1# = 0.0
         EndIf  
         If (x < src2.Width) And (z < src2.Height)
           y2# = src2.Map#[x, z]
         Else
           y2# = 0.0
         EndIf  

         outp.Map#[x, z] = y1# / y2#

      Next
    Next
    
    outp.normalise()

  End Function

  Rem blendWithMapDiv(src:THeightMap)
  Blends the current THeightMap instance with another THeightMap instance using a 
  an division process.
  src: THeightMap to blend with.
  End Rem
  Method blendWithMapDiv(src:THeightMap)

    blendMapsDiv(Self, src, Self)

  End Method

  Rem blendMapsHi(src1:THeightMap, src2:THeightMap, outp:THeightMap)
  Blends two maps, favouring the highest values.
  src1: source THeightMap instance #1.
  src2: source THeightMap instance #2.
  outp: output THeightMap instance into which the results will be stored.
  End Rem
  Function blendMapsHi(src1:THeightMap, src2:THeightMap, outp:THeightMap)

    Local x, z
    Local y1#, y2#
    
    For x = 0 To outp.Width - 1
      For z = 0 To outp.Height - 1

         If (x < src1.Width) And (z < src1.Height)
           y1# = src1.Map#[x, z]
         Else
           y1# = 0.0
         EndIf  
         If (x < src2.Width) And (z < src2.Height)
           y2# = src2.Map#[x, z]
         Else
           y2# = 0.0
         EndIf  

         If y1# > y2# Then
           outp.Map#[x, z] = y1#
         Else
           outp.Map#[x, z] = y2#
         EndIf

      Next
    Next
    
    outp.normalise()

  End Function

  Rem blendWithMapHi(src:THeightMap)
  Blends the current THeightMap instance with another THeightMap instance, 
  favouring the highest values.
  src: THeightMap to blend with.
  End Rem
  Method blendWithMapHi(src:THeightMap)

    blendMapsHi(Self, src, Self)

  End Method

  Rem blendMapsHi(src1:THeightMap, src2:THeightMap, outp:THeightMap)
  Blends two maps, favouring the lowest values.
  src1: source THeightMap instance #1.
  src2: source THeightMap instance #2.
  outp: output THeightMap instance into which the results will be stored.
  End Rem
  Function blendMapsLo(src1:THeightMap, src2:THeightMap, outp:THeightMap)

    Local x, z
    Local y1#, y2#
    
    For x = 0 To outp.Width - 1
      For z = 0 To outp.Height - 1

         If (x < src1.Width) And (z < src1.Height)
           y1# = src1.Map#[x, z]
         Else
           y1# = 0.0
         EndIf  
         If (x < src2.Width) And (z < src2.Height)
           y2# = src2.Map#[x, z]
         Else
           y2# = 0.0
         EndIf  

         If y1# < y2# Then
           outp.Map#[x, z] = y1#
         Else
           outp.Map#[x, z] = y2#
         EndIf

      Next
    Next
    
    outp.normalise()

  End Function

  Rem blendWithMapLo(src:THeightMap)
  Blends the current THeightMap instance with another THeightMap instance, 
  favouring the lowest values.
  src: THeightMap to blend with.
  End Rem
  Method blendWithMapLo(src:THeightMap)

    blendMapsLo(Self, src, Self)

  End Method

  Rem blendMapsRep(src1:THeightMap, src2:THeightMap, outp:THeightMap)
  Blends two maps, replacing outp's values with src1's values. ie copy src1 to outp.
  src1: source THeightMap instance #1.
  src2: source THeightMap instance #2.
  outp: output THeightMap instance into which the results will be stored.
  End Rem
  Function blendMapsRep(src1:THeightMap, src2:THeightMap, outp:THeightMap)

    Local x, z
    Local y1#, y2#
    
    For x = 0 To outp.Width - 1
      For z = 0 To outp.Height - 1

         If (x < src1.Width) And (z < src1.Height)
           y1# = src1.Map#[x, z]
         Else
           y1# = 0.0
         EndIf  
         If (x < src2.Width) And (z < src2.Height)
           y2# = src2.Map#[x, z]
         Else
           y2# = 0.0
         EndIf  

         outp.Map#[x, z] = y1#

      Next
    Next
    
    outp.normalise()

  End Function

  Rem blendWithMapRep(src:THeightMap)
  Replaces the current THeightMap values with those of another THeightMap instance. 
  src: THeightMap to blend with.
  End Rem
  Method blendWithMapRep(src:THeightMap)

    blendMapsRep(Self, src, Self)

  End Method

  Rem renderToImage(img:TImage, offx = 0, offz = 0)
  Render the map to a BlitzMax image object.
  img: Destination TImage object. Must be the same dimensions as the map.
  offx: x offset (pixels) into img. >=0 and <=img width.
  offz: z offset (pixels) into img. >=0 and <=img height.
  End Rem
  Method renderToImage(img:TImage, offx = 0, offz = 0)

    Local pm = LockImage(img)
    renderToPixmap(pm, offx, offz)
    UnlockImage(img)

  End Method

  Rem renderToPixmap(pm:TPixmap, offx = 0, offz = 0)
  Render the map to a BlitzMax pixmap object.
  pm: Destination TPixmap object. Must be the same dimensions as the 
  map. The pixmap format should be PF_RGBA8888
  offx: x offset (pixels) into pm. >=0 and <=pm width.
  offz: z offset (pixels) into pm. >=0 and <=pm height.
  End Rem
  Method renderToPixmap(pm:TPixmap, offx = 0, offz = 0)

    If Not ((offx >= 0) And (offx < pm.Width)) Return
    If Not ((offz >= 0) And (offz < pm.Height)) Return

    Local x, z, r, g, b, a = $FF000000

    For x = 0 To Width - 1
      For z = 0 To Height - 1
		If ((offx + x) < pm.Width) And ((offz + z) < pm.Height)
          r = Floor(Map#[x, z] * 255)
          g = r
          b = r
          WritePixel(pm, (offx + x), (offz + z), a Shl 24 | r Shl 16 | g Shl 8 | b Shl 0)
        EndIf
      Next
    Next

  End Method

  Rem renderToBackBuffer(offx = 0, offz = 0)
  Render the map directly to the backbuffer.
  offx: x offset (pixels) backbuffer. >=0 and <=screen width.
  offz: z offset (pixels) backbuffer. >=0 and <=screen height.
  TODO; Validate offx and offz.
  End Rem
  Method renderToBackBuffer(offx = 0, offz = 0)
    
    Local gw = GraphicsWidth()
    Local gh = GraphicsHeight()

    If Not ((offx >= 0) And (offx < gw)) Return
    If Not ((offz >= 0) And (offz < gh)) Return

    Local x, z, c

    For x = 0 To Width - 1
      For z = 0 To Height - 1
        If ((offx + x) < gw) And ((offz + z) < gh)
          c = Floor(Map#[x, z] * 255)
          SetColor c, c, c
          Plot (offx + x), (offz + z)
        EndIf
      Next
    Next

  End Method

End Type





'==================================
' Cut and paste this and save it 
' as hmaptest.bmx or whatever.
'==================================



Rem

Height Map Test
V0.1.0 BETA

By Shane Raffa
May 2005

PURPOSE

	A crude, non-gui heightmap editing program to demonstrate usage 
	of the THeightMap class. (See hmap010.bmx)

TEST SYSTEM

	Athlon XP 1600+, 512MB, GeForce 3 Ti200 (64MB)
	Windows XP, BlitzMax

End Rem

Strict

Import "hmap010.bmx"

Type THMapTest Extends THeightMap

  Field Img1:TImage

  Field ScrnX
  Field ScrnZ

  Method create(w, h, sx = 0, sz = 0)

    ScrnX = sx
    ScrnZ = sz
    resize(w, h)
    Img1:TImage = CreateImage(Width, Height, 1, DYNAMICIMAGE)
    generateMap()

  End Method
  
  Method destroy()

    Img1 = Null

  End Method

  Method generateMap()

    Local n = Rand(0, 5)

    DrawText "Generating Map... ", ScrnX, ScrnZ
    Flip

    Select n
      Case 0
        createPerlinMap(MilliSecs(), 0.25, 1.5)
      Case 1
        createMPDMap(MilliSecs(), 0.5)
      Case 2
        createHillMap(MilliSecs(), 1000, 30)
      Case 3
        createParticleSMap(MilliSecs(), 1000, 1000)
        smoothen(0.25)
      Case 4
        createParticleRMap(MilliSecs(), 1000, 1000)
        smoothen(0.25)
      Case 5
        createFaultMap(MilliSecs(), 500)
        smoothen(0.25)
    End Select
    
    renderToImage(Img1, 0, 0)

    render()
    Flip

  End Method

  Method render()

    DrawImage(Img1, ScrnX, ScrnZ)
    
  End Method

End Type


Graphics 800, 600

SetBlend(SOLIDBLEND)
SetLineWidth(2.0)

Global Menu = True
Global Active = 0

Global HMap:THMapTest[] = [New THMapTest, New THMapTest, New THMapTest]

HMap[0].create(256, 256, 0, 0)
HMap[1].create(256, 256, HMap[0].Width, 0)
HMap[2].create(256, 256, HMap[0].Width + HMap[1].Width, 0)

While Not KeyHit(KEY_ESCAPE)

  Cls

  For Local i:THMapTest = EachIn HMap
    i.render()
  Next

  If MouseDown(1)
    Local c = 0
    For Local i:THMapTest = EachIn HMap
      If (MouseX() >= i.ScrnX) And (MouseX() < (i.ScrnX + i.Width))
        If (MouseY() >= i.ScrnZ) And (MouseY() < (i.ScrnZ + i.Height))
          Active = c
        EndIf
      EndIf
      c :+ 1
    Next
  EndIf

  If Menu showMenu()

  drawActiveBox()

  processKeys()
  FlushKeys()

  Flip

Wend

For Local i:THMapTest = EachIn HMap
  i.destroy()
Next

FlushMem

EndGraphics

End

Function drawActiveBox()

  SetColor(0, 255, 0)
  DrawLine HMap[Active].ScrnX, HMap[Active].ScrnZ, HMap[Active].ScrnX + HMap[Active].Width - 1, HMap[Active].ScrnZ
  DrawLine HMap[Active].ScrnX + HMap[Active].Width - 1, HMap[Active].ScrnZ, HMap[Active].ScrnX + HMap[Active].Width - 1, HMap[Active].ScrnZ + HMap[Active].Height - 1
  DrawLine HMap[Active].ScrnX, HMap[Active].ScrnZ + HMap[Active].Height - 1, HMap[Active].ScrnX + HMap[Active].Width - 1, HMap[Active].ScrnZ + HMap[Active].Height - 1
  DrawLine HMap[Active].ScrnX, HMap[Active].ScrnZ, HMap[Active].ScrnX, HMap[Active].ScrnZ + HMap[Active].Height - 1
  SetColor(255, 255, 255)

End Function

Function showMenu()

  DrawText "SELECT", 5, 300
  DrawText "------", 5, 315
  DrawText "{Left Click} - Select", 5, 330
  DrawText "UP ARROW - Next", 5, 345
  DrawText "RIGHT ARROW - Next", 5, 360
  DrawText "DOWN ARROW - Previous", 5, 375
  DrawText "LEFT ARROW - Previous", 5, 390
  DrawText "ESC - Exit", 5, 405
  DrawText "TAB - Toggle Menu", 5, 420

  DrawText "CREATE", 200, 300
  DrawText "------", 200, 315
  DrawText "1 - Random", 200, 330
  DrawText "2 - Perlin", 200, 345
  DrawText "3 - Midpoint Disp.", 200, 360
  DrawText "4 - Hill", 200, 375
  DrawText "5 - Sticky Particle", 200, 390
  DrawText "6 - Rolling Particle", 200, 405
  DrawText "7 - Fault", 200, 420
  DrawText "0 - Clear", 200, 435

  DrawText "PROCESS", 400, 300
  DrawText "-------", 400, 315
  DrawText "SPACE - Smoothen", 400, 330
  DrawText "f - Flatten", 400, 345
  DrawText "c - Coast", 400, 360
  DrawText "a - Blend Add", 400, 375
  DrawText "s - Blend Subtract", 400, 390
  DrawText "m - Blend Multiply", 400, 405
  DrawText "d - Blend Divide", 400, 420
  DrawText "h - Blend Highest", 400, 435
  DrawText "l - Blend Lowest", 400, 450
  DrawText "r - Blend Replace", 400, 465

  DrawText "IMPORT/EXPORT", 600, 300
  DrawText "-------------", 600, 315
  DrawText "F1 - Export Binary", 600, 330
  DrawText "F2 - Export PNG", 600, 345
  DrawText "F3 - Export X3D", 600, 360
  DrawText "F5 - Import Binary", 600, 390
  DrawText "F6 - Import PNG", 600, 405
  DrawText "F10 - Export...", 600, 435
  DrawText "F12 - Import...", 600, 450

End Function

Function processKeys()
  
  If KeyDown(KEY_0)
    DrawText "Clearing... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].fill(0.0)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If
  If KeyDown(KEY_1)
    DrawText "Generating Random... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].createRandomMap(MilliSecs())
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If
  If KeyDown(KEY_2)
    DrawText "Generating Perlin... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].createPerlinMap(MilliSecs(), 0.25, 1.5)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If
  If KeyDown(KEY_3)
    DrawText "Generating MPD... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].createMPDMap(MilliSecs(), 0.5)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If
  If KeyDown(KEY_4)
    DrawText "Generating Hill... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].createHillMap(MilliSecs(), 1000, 30)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If
  If KeyDown(KEY_5)
    DrawText "Generating S Particle... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].createParticleSMap(MilliSecs(), 1000, 1000)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If
  If KeyDown(KEY_6)
    DrawText "Generating R Particle... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].createParticleRMap(MilliSecs(), 1000, 1000)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If
  If KeyDown(KEY_7)
    DrawText "Generating Fault... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].createFaultMap(MilliSecs(), 500)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  End If

  If KeyDown(KEY_UP) Or KeyDown(KEY_RIGHT)
    Active :+ 1
    If Active >= HMap.length Active = 0
  End If

  If KeyDown(KEY_DOWN) Or KeyDown(KEY_LEFT)
    Active :- 1
    If Active < 0 Active = HMap.length - 1
  End If

  If KeyDown(KEY_TAB) 
    Menu = Not Menu
  End If

  If KeyDown(KEY_SPACE)
    DrawText "Smoothing... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].smoothen(0.75)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf

  If KeyDown(KEY_F)
    DrawText "Flattening... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].flatten(2)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf

  If KeyDown(KEY_C)
    DrawText "Making Coast... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].makeCoast(0.5, 0.1)
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf

  If KeyDown(KEY_A)
    DrawText "Blending (Add)... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    Select Active
      Case 0
        THeightMap.blendMapsAdd(HMap[1], HMap[2], HMap[Active])
      Case 1
        THeightMap.blendMapsAdd(HMap[0], HMap[2], HMap[Active])
      Case 2
        THeightMap.blendMapsAdd(HMap[0], HMap[1], HMap[Active])
      End Select
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf

  If KeyDown(KEY_S)
    DrawText "Blending (Subtract)... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    Select Active
      Case 0
        THeightMap.blendMapsSub(HMap[1], HMap[2], HMap[Active])
      Case 1
        THeightMap.blendMapsSub(HMap[0], HMap[2], HMap[Active])
      Case 2
        THeightMap.blendMapsSub(HMap[0], HMap[1], HMap[Active])
      End Select
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_M)
    DrawText "Blending (Multiply)... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    Select Active
      Case 0
        THeightMap.blendMapsMul(HMap[1], HMap[2], HMap[Active])
      Case 1
        THeightMap.blendMapsMul(HMap[0], HMap[2], HMap[Active])
      Case 2
        THeightMap.blendMapsMul(HMap[0], HMap[1], HMap[Active])
      End Select
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_D)
    DrawText "Blending (Divide)... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    Select Active
      Case 0
        THeightMap.blendMapsDiv(HMap[1], HMap[2], HMap[Active])
      Case 1
        THeightMap.blendMapsDiv(HMap[0], HMap[2], HMap[Active])
      Case 2
        THeightMap.blendMapsDiv(HMap[0], HMap[1], HMap[Active])
      End Select
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_H)
    DrawText "Blending (Highest)... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    Select Active
      Case 0
        THeightMap.blendMapsHi(HMap[1], HMap[2], HMap[Active])
      Case 1
        THeightMap.blendMapsHi(HMap[0], HMap[2], HMap[Active])
      Case 2
        THeightMap.blendMapsHi(HMap[0], HMap[1], HMap[Active])
      End Select
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_L)
    DrawText "Blending (Lowest)... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    Select Active
      Case 0
        THeightMap.blendMapsLo(HMap[1], HMap[2], HMap[Active])
      Case 1
        THeightMap.blendMapsLo(HMap[0], HMap[2], HMap[Active])
      Case 2
        THeightMap.blendMapsLo(HMap[0], HMap[1], HMap[Active])
      End Select
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_R)
    DrawText "Blending (Replace)... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    Select Active
      Case 0
        THeightMap.blendMapsRep(HMap[1], HMap[2], HMap[Active])
      Case 1
        THeightMap.blendMapsRep(HMap[0], HMap[2], HMap[Active])
      Case 2
        THeightMap.blendMapsRep(HMap[0], HMap[1], HMap[Active])
      End Select
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf

  If KeyDown(KEY_F1)
    DrawText "Exporting test.bin... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].exportBin("test.bin")
  EndIf
  If KeyDown(KEY_F5)
    DrawText "Importing test.bin... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].importBin("test.bin")
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_F2)
    DrawText "Exporting test.png... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].exportPNG("test.png", 9)
  EndIf
  If KeyDown(KEY_F6)
    DrawText "Importing test.png... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].importPNG("test.png")
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_F3)
    DrawText "Exporting test.x3d... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
    Flip
    HMap[Active].exportX3d("test.x3d", "templ01.x3d", 40.0, 2.0, 2.0)
  EndIf
  If KeyDown(KEY_F12)
    Local fn$ = RequestFile("Import file...", "Supported Files:png,bin;All Files:*", False)
    If Right$(fn$, 4) = ".png"
      DrawText "Importing PNG: " + fn$ + "... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
      Flip
      HMap[Active].importPNG(fn$)
    Else
      If Right$(fn$, 4) = ".bin"
        DrawText "Importing Binary: " + fn$ + "... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
        Flip
        HMap[Active].importBin(fn$)
      EndIf
    EndIf
    HMap[Active].renderToImage(HMap[Active].Img1, 0, 0)
  EndIf
  If KeyDown(KEY_F10)
    Local fn$ = RequestFile("Export file...", "Supported Files:png,bin,x3d", True)
    If Right$(fn$, 4) = ".png"
      DrawText "Exporting PNG: " + fn$ + "... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
      Flip
      HMap[Active].exportPNG(fn$)
    Else
      If Right$(fn$, 4) = ".bin"
        DrawText "Exporting Binary: " + fn$ + "... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
        Flip
        HMap[Active].exportBin(fn$)
      Else 
        If Right$(fn$, 4) = ".x3d"
          DrawText "Exporting X3D: " + fn$ + "... ", HMap[Active].ScrnX, HMap[Active].ScrnZ
          Flip
          HMap[Active].exportX3d(fn$, "templ01.x3d", 40.0, 2.0, 2.0)
        EndIf
      EndIf
    EndIf
  EndIf

End Function

Comments

Booticus2005
Note its TWO files. I put a comment in there where you should cut and paste the section into a different file to run for testing it out. Forgive me for the slapdick way of posting. Is there a better way to post code that requires more than 1 source file?


impixi2005
...


DannyD2005
thanks.


impixi2006
...


SabataRH2006
I get errors, all sorts of errors. :(


impixi2006
New version: Heightmap Toolbox V0.3.6


Code Archives Forum