Plotting Fractals in WebAssembly

Previous Top Next
3: Basic WAT Implementation 4: Optimised WAT Implementation 5: Plotting a Julia Set
  4.1: Check for Early Bailout 4.2 Modify Render Loop

4.1: Check for Early Bailout

Main Cardioid Check

To check whether the current location on the complex plane falls within the Mandelbrot Set’s main cardioid, we must first derive an intermediate value q from the x and y coordinates of the current pixel. In JavaScript, we do that as follows:

q = (x - 0.25)^2 + y^2

Then test the following equality:

q * (q + (x - 0.25)) <= y^2 / 4

If this returns true, then the point lies within the main cardioid and there is no point running the escape-time algorithm.

So, let’s now write a WAT function that implements this check.

If you’ve read the Introduction to WebAssembly Text, you’ll remember that in §7 we saw how WebAssembly uses i32 values as Booleans: where zero means false, and any non-zero value means true. Hence, the i32 returned by this function can be treated as a Boolean:

;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Main cardioid check
(func $is_in_main_cardioid
      (param $x f64)
      (param $y f64)
      (result i32)

  (local $x_minus_qtr f64)
  (local $y_sqrd f64)
  (local $q f64)

  (local.set $x_minus_qtr (f64.sub (local.get $x) (f64.const 0.25)))
  (local.set $y_sqrd      (f64.mul (local.get $y) (local.get $y)))

  ;; Intermediate value $q = ($x - 0.25)^2 + $y^2
  (local.set $q
    (f64.add (f64.mul (local.get $x_minus_qtr) (local.get $x_minus_qtr))
             (local.get $y_sqrd)
    )
  )

  ;; Main cardioid check: $q * ($q + ($x - 0.25)) <= $y^2 / 4
  (f64.le
    (f64.mul (local.get $q) (f64.add (local.get $q) (local.get $x_minus_qtr)))
    (f64.mul (f64.const 0.25) (local.get $y_sqrd))
  )
)

Period 2 Bulb Check

To check whether the current location on the complex plane falls within the period 2 bulb, we test the following equality. Again, in JavaScript, this is:

(x + 1)^2 + y^2 <= 0.0625

Here’s the WebAssembly function that implements this check:

;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Period 2 bulb check: ($x + 1)^2 + $y^2 <= 0.0625
(func $is_in_period_two_bulb
      (param $x f64)
      (param $y f64)
      (result i32)
  (local $x_plus_1 f64)
  (local.set $x_plus_1 (f64.add (local.get $x) (f64.const 1.0)))

  (f64.le
    (f64.add
      (f64.mul (local.get $x_plus_1) (local.get $x_plus_1))
      (f64.mul (local.get $y) (local.get $y))
    )
    (f64.const 0.0625)
  )
)

Early Bailout Check

Finally, we can combine these two functions into a simple check for early bailout

;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Check for early bailout
(func $early_bailout
      (param $x f64)
      (param $y f64)
      (result i32)
  (i32.or
    (call $is_in_main_cardioid   (local.get $x) (local.get $y))
    (call $is_in_period_two_bulb (local.get $x) (local.get $y))
  )
)