mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			189 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Pony
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Pony
		
	
	
	
	
	
use "files"
 | 
						|
use "options"
 | 
						|
use "collections"
 | 
						|
 | 
						|
actor Worker
 | 
						|
  new mandelbrot(main: Main, x: U64, y: U64, width: U64, iterations: U64,
 | 
						|
    limit: F32, real: Array[F32] val, imaginary: Array[F32] val)
 | 
						|
  =>
 | 
						|
    var view: Array[U8] iso =
 | 
						|
      recover
 | 
						|
        Array[U8]((y - x) * (width >> 3))
 | 
						|
      end
 | 
						|
 | 
						|
    let group_r = Array[F32].undefined(8)
 | 
						|
    let group_i = Array[F32].undefined(8)
 | 
						|
 | 
						|
    var row = x
 | 
						|
 | 
						|
    try
 | 
						|
      while row < y do
 | 
						|
        let prefetch_i = imaginary(row)
 | 
						|
 | 
						|
        var col: U64 = 0
 | 
						|
 | 
						|
        while col < width do
 | 
						|
          var j: U64 = 0
 | 
						|
 | 
						|
          while j < 8 do
 | 
						|
            group_r.update(j, real(col + j))
 | 
						|
            group_i.update(j, prefetch_i)
 | 
						|
            j = j + 1
 | 
						|
          end
 | 
						|
 | 
						|
          var bitmap: U8 = 0xFF
 | 
						|
          var n = iterations
 | 
						|
 | 
						|
          repeat
 | 
						|
            var mask: U8 = 0x80
 | 
						|
            var k: U64 = 0
 | 
						|
 | 
						|
            while k < 8 do
 | 
						|
              let r = group_r(k)
 | 
						|
              let i = group_i(k)
 | 
						|
 | 
						|
              group_r.update(k, ((r * r) - (i * i)) + real(col + k))
 | 
						|
              group_i.update(k, (2.0 * r * i) + prefetch_i)
 | 
						|
 | 
						|
              if ((r * r) + (i * i)) > limit then
 | 
						|
                bitmap = bitmap and not mask
 | 
						|
              end
 | 
						|
 | 
						|
              mask = mask >> 1
 | 
						|
              k = k + 1
 | 
						|
            end
 | 
						|
          until (bitmap == 0) or ((n = n - 1) == 1) end
 | 
						|
 | 
						|
          view.push(bitmap)
 | 
						|
 | 
						|
          col = col + 8
 | 
						|
        end
 | 
						|
        row = row + 1
 | 
						|
      end
 | 
						|
 | 
						|
      main.draw(x * (width >> 3), consume view)
 | 
						|
    end
 | 
						|
 | 
						|
actor Main
 | 
						|
  var iterations: U64 = 50
 | 
						|
  var limit: F32 = 4.0
 | 
						|
  var chunks: U64 = 16
 | 
						|
  var width: U64 = 16000
 | 
						|
  var actors: U64 = 0
 | 
						|
  var header: U64 = 0
 | 
						|
  var real: Array[F32] val = recover Array[F32] end
 | 
						|
  var imaginary: Array[F32] val = recover Array[F32] end
 | 
						|
  var outfile: (File | None) = None
 | 
						|
 | 
						|
  new create(env: Env) =>
 | 
						|
    try
 | 
						|
      arguments(env)
 | 
						|
 | 
						|
      let length = width
 | 
						|
      let recip_width = 2.0 / width.f32()
 | 
						|
 | 
						|
      var r = recover Array[F32](length) end
 | 
						|
      var i = recover Array[F32](length) end
 | 
						|
 | 
						|
      for j in Range(0, width) do
 | 
						|
        r.push((recip_width * j.f32()) - 1.5)
 | 
						|
        i.push((recip_width * j.f32()) - 1.0)
 | 
						|
      end
 | 
						|
 | 
						|
      real = consume r
 | 
						|
      imaginary = consume i
 | 
						|
 | 
						|
      spawn_actors()
 | 
						|
      create_outfile()
 | 
						|
    end
 | 
						|
 | 
						|
  be draw(offset: U64, pixels: Array[U8] val) =>
 | 
						|
    match outfile
 | 
						|
    | var out: File =>
 | 
						|
      out.seek_start(header + offset)
 | 
						|
      out.write(pixels)
 | 
						|
      if (actors = actors - 1) == 1 then
 | 
						|
        out.dispose()
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
  fun ref create_outfile() =>
 | 
						|
    match outfile
 | 
						|
    | var f: File =>
 | 
						|
      f.print("P4\n " + width.string() + " " + width.string() + "\n")
 | 
						|
      header = f.size()
 | 
						|
      f.set_length((width * (width >> 3)) + header)
 | 
						|
    end
 | 
						|
 | 
						|
  fun ref spawn_actors() =>
 | 
						|
    actors = ((width + (chunks - 1)) / chunks)
 | 
						|
 | 
						|
    var rest = width % chunks
 | 
						|
 | 
						|
    if rest == 0 then rest = chunks end
 | 
						|
 | 
						|
    var x: U64 = 0
 | 
						|
    var y: U64 = 0
 | 
						|
 | 
						|
    for i in Range(0, actors - 1) do
 | 
						|
      x = i * chunks
 | 
						|
      y = x + chunks
 | 
						|
      Worker.mandelbrot(this, x, y, width, iterations, limit, real, imaginary)
 | 
						|
    end
 | 
						|
 | 
						|
    Worker.mandelbrot(this, y, y + rest, width, iterations, limit, real,
 | 
						|
      imaginary)
 | 
						|
 | 
						|
  fun ref arguments(env: Env) ? =>
 | 
						|
    let options = Options(env)
 | 
						|
 | 
						|
    options
 | 
						|
      .add("iterations", "i", I64Argument)
 | 
						|
      .add("limit", "l", F64Argument)
 | 
						|
      .add("chunks", "c", I64Argument)
 | 
						|
      .add("width", "w", I64Argument)
 | 
						|
      .add("output", "o", StringArgument)
 | 
						|
 | 
						|
    for option in options do
 | 
						|
      match option
 | 
						|
      | ("iterations", var arg: I64) => iterations = arg.u64()
 | 
						|
      | ("limit", var arg: F64) => limit = arg.f32()
 | 
						|
      | ("chunks", var arg: I64) => chunks = arg.u64()
 | 
						|
      | ("width", var arg: I64) => width = arg.u64()
 | 
						|
      | ("output", var arg: String) =>
 | 
						|
        outfile = try File(FilePath(env.root, arg)) end
 | 
						|
      | let err: ParseError => err.report(env.out) ; usage(env) ; error
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
  fun tag usage(env: Env) =>
 | 
						|
    env.out.print(
 | 
						|
      """
 | 
						|
      mandelbrot [OPTIONS]
 | 
						|
 | 
						|
      The binary output can be converted to a BMP with the following command
 | 
						|
      (ImageMagick Tools required):
 | 
						|
 | 
						|
        convert <output> JPEG:<output>.jpg
 | 
						|
 | 
						|
      Available options:
 | 
						|
 | 
						|
      --iterations, -i  Maximum amount of iterations to be done for each pixel.
 | 
						|
                        Defaults to 50.
 | 
						|
 | 
						|
      --limit, -l       Square of the limit that pixels need to exceed in order
 | 
						|
                        to escape from the Mandelbrot set.
 | 
						|
                        Defaults to 4.0.
 | 
						|
 | 
						|
      --chunks, -c      Maximum line count of chunks the image should be
 | 
						|
                        divided into for divide & conquer processing.
 | 
						|
                        Defaults to 16.
 | 
						|
 | 
						|
      --width, -w       Lateral length of the resulting mandelbrot image.
 | 
						|
                        Defaults to 16000.
 | 
						|
 | 
						|
      --output, -o      File to write the output to.
 | 
						|
 | 
						|
      """
 | 
						|
      )
 |