DEV Community

Andy Maleh
Andy Maleh

Posted on • Updated on

Glimmer DSL for SWT Mandelbrot Fractal

For the hardcore Computer Scientists out there who have strong interest in graphical algorithms, the Mandelbrot Set is a very well known Computer Science/Math algorithm that renders a fractal at various zoom levels, demonstrating the repetitive nature of fractals. During my bachelor of Computer Science at McGill University (Montreal, QC, Canada) over two decades ago, I remember spending very long and tiring nights at the computer lab to implement an Assembly language renderer of the Mandelbrot Fractal. Much has changed since then. We have multi-core processors today, let alone the wonderful Ruby programming language, so I wrote this with Glimmer DSL for SWT by taking advantage of the multi-threaded JRuby and saturating all CPU cores to finish calculating Mandelbrot points in less than 10 seconds on 4 CPU cores. The sample supports unlimited zooming, pre-calculated in the background with the window title bar notifying you once higher zooms are available. It also allows panning with scrollbars or mouse dragging.

Glimmer DSL for SWT Mandelbrot Fractal

The initial version's Glimmer GUI DSL (domain specific language) code was so simple, this was all of it:

  body {
    shell {
      text 'Mandelbrot Fractal'
      minimum_size @width, @height + 12
      image @image

      canvas {
        image(@image, 0, 0)
      }
    }
  }
Enter fullscreen mode Exit fullscreen mode

Below is the multi-threaded model code and Glimmer GUI DSL code of the Mandelbrot Fractal initial version (without zooming or menus). The Glimmer DSL for SWT GUI simply paints an image as a form of image buffering (to avoid Mandelbrot pixel repaints on GUI repaints) and then puts it inside a canvas to display.

require 'glimmer-dsl-swt'
require 'complex'
require 'concurrent-ruby'

class Mandelbrot
  attr_accessor :max_iterations

  def initialize(max_iterations)
    @max_iterations = max_iterations
  end

  def calculate_all(x_array, y_array)
    thread_pool = Concurrent::FixedThreadPool.new(Concurrent.processor_count)
    width = x_array.size
    height = y_array.size
    pixel_rows_array = Concurrent::Array.new(height)
    height.times do |y|
      pixel_rows_array[y] ||= Concurrent::Array.new(width)
      width.times do |x|
        thread_pool.post do
          pixel_rows_array[y][x] = calculate(x_array[x], y_array[y]).last
        end
      end
    end
    thread_pool.shutdown
    thread_pool.wait_for_termination
    pixel_rows_array
  end

  # Mandelbrot point calculation implementation
  # Courtesy of open-source code at:
  # https://github.com/gotbadger/ruby-mandelbrot
  def calculate(x,y)
    base_case = [Complex(x,y), 0]
    Array.new(max_iterations, base_case).inject(base_case) do |prev ,base|
      z, itr = prev
      c, _ = base
      val = z*z + c
      itr += 1 unless val.abs < 2
      [val, itr]
    end
  end
end

class MandelbrotFractal
  include Glimmer::UI::CustomShell

  before_body {
    @colors = [[0, 0, 0]] + 40.times.map { |i| [255 - i*5, 255 - i*5, 55 + i*5] }
    @colors = @colors.map {|color_data| rgb(*color_data).swt_color}
    mandelbrot = Mandelbrot.new(@colors.size - 1)
    @y_array = (1.0).step(-1,-0.0030).to_a
    @x_array = (-2.0).step(0.5,0.0030).to_a
    @height = @y_array.size
    @width = @x_array.size
    @pixel_rows_array = mandelbrot.calculate_all(@x_array, @y_array)
    @image = Image.new(display.swt_display, @width, @height)
    image_gc = org.eclipse.swt.graphics.GC.new(@image)
    @height.times { |y|
      @width.times { |x|
        new_foreground = @colors[@pixel_rows_array[y][x]]
        image_gc.foreground = @current_foreground = new_foreground unless new_foreground == @current_foreground
        image_gc.draw_point x, y
      }
    }
  }

  body {
    shell {
      text 'Mandelbrot Fractal'
      minimum_size @width, @height + 12
      image @image

      canvas {
        image(@image, 0, 0)
      }
    }
  }
end

MandelbrotFractal.launch
Enter fullscreen mode Exit fullscreen mode

Learn more at this blog post:
https://andymaleh.blogspot.com/2021/02/glimmer-dsl-for-swt-mandelbrot-fractal.html

Top comments (0)