From 642b0b74b5d9f79280cc1d2663d6e172e7d2a802 Mon Sep 17 00:00:00 2001 From: koniifer Date: Sun, 15 Dec 2024 22:05:06 +0000 Subject: [PATCH] cooler mandelbrot --- Cargo.lock | 14 +- .../render_example/src/examples/mandelbrot.hb | 238 +++++++++--------- sysdata/system_config.toml | 8 +- 3 files changed, 135 insertions(+), 125 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d181906..5ee0f13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,18 +88,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "derive_more" @@ -213,12 +213,12 @@ dependencies = [ [[package]] name = "hbbytecode" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#dc96c8b10ae85af7a11bd1e8ca2cd29e2c42a033" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#9f43e3bb925534f613cb2089df6e5fe315fc851a" [[package]] name = "hblang" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#dc96c8b10ae85af7a11bd1e8ca2cd29e2c42a033" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#9f43e3bb925534f613cb2089df6e5fe315fc851a" dependencies = [ "hashbrown", "hbbytecode", @@ -229,7 +229,7 @@ dependencies = [ [[package]] name = "hbvm" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#dc96c8b10ae85af7a11bd1e8ca2cd29e2c42a033" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#9f43e3bb925534f613cb2089df6e5fe315fc851a" dependencies = [ "hbbytecode", ] diff --git a/sysdata/programs/render_example/src/examples/mandelbrot.hb b/sysdata/programs/render_example/src/examples/mandelbrot.hb index 391bcc1..15c5548 100644 --- a/sysdata/programs/render_example/src/examples/mandelbrot.hb +++ b/sysdata/programs/render_example/src/examples/mandelbrot.hb @@ -1,45 +1,66 @@ -// ln_f32 := fn(x: f32): f32 { -// if x <= 0 { -// return -1000000000000000.0 -// } -// approx := x - 1.0 -// i := 0 -// loop if i == 10 break else { -// exp_approx := exp_f32(approx) -// approx -= (exp_approx - x) / exp_approx -// i += 1 -// } -// return approx -// } +ln_f64 := fn(x: f64): f64 { + if x <= 0.0 return -100000000000000000000000.0 + if x == 1.0 return 0.0 + if x == E return 1.0 -// exp_f32 := fn(x: f32): f32 { -// sum := 1.0 -// term := 1.0 -// n := @as(int, 1) -// loop if n == 20 break else { -// term *= x / @floatcast(@itf(n)) -// sum += term -// if term < 0.000006 break -// n += 1 -// } -// return sum -// } + scale := @as(f64, 0.0) + scaled_x := x -// sqrt_f32 := fn(x: f32): f32 { -// if x <= 0 { -// return 0.0 -// } -// guess := x / 2.0 -// tolerance := 0.000001 -// loop { -// new_guess := (guess + x / guess) / 2.0 -// if guess - new_guess < tolerance { -// break -// } -// guess = new_guess -// } -// return guess -// } + if scaled_x > 2.0 { + loop if scaled_x <= 2.0 break else { + scaled_x = scaled_x / E + scale += 1.0 + } + } else if scaled_x < 1.0 { + loop if scaled_x >= 1.0 { + scaled_x = scaled_x * E + scale -= 1.0 + } + } + + guess := (scaled_x - 1.0) / (scaled_x + 1.0) + + max_iter := 30 + i := 0 + loop if i == max_iter break else { + exp_g := exp_f64(guess) + f := exp_g - scaled_x + f_prime := exp_g + + delta := f / (f_prime * (1.0 - 0.5 * f * f_prime / (f_prime * f_prime))) + + guess = guess - delta + + if abs_f64(delta) < 0.0000000001 break + i += 1 + } + + return guess + scale +} + +exp_f64 := fn(x: f64): f64 { + result := @as(f64, 1.0) + term := @as(f64, 1.0) + n := @as(int, 1) + + loop if n == 20 break else { + term = term * x / @itf(n) + result += term + + if abs_f64(term) < 0.0000000001 break + n += 1 + } + + return result +} + +abs_f64 := fn(x: f64): f64 { + if x < 0 return -x else return x +} + +lerp_f64 := fn(v0: f64, v1: f64, t: f64): f64 { + return v0 + t * (v1 - v0) +} render := @use("lib:render") sunset := @use("lib:sunset_proto"); @@ -57,22 +78,21 @@ $X_MAX := -0.93 $Y_MIN := 0.31 $Y_MAX := 0.306 -// if you use the minibrot this should be at least 100 to actually see the minibrot, -// if you use the mandelbrot it looks best under 30 -$MAX_MAX_ITERATION := 30000000 +$MAX_ITERATION := 300 -$USE_SUNSET := true +$USE_SUNSET := false $COLOUR_R := 200 $COLOUR_G := 100 $COLOUR_B := 255 -// $COLOUR_R := 255 -// $COLOUR_G := 255 -// $COLOUR_B := 255 +$LOG_2 := 0.693147180559945309417232121458176568 +$E := 2.71828182845904523536028747135266250 -// $INTERIOR_COLOUR := render.WHITE -$INTERIOR_COLOUR := render.Color.{r: COLOUR_R, g: COLOUR_G, b: COLOUR_B, a: 255} +$INTERIOR_COLOUR := render.BLACK + +palette := [render.Color].(render.RED, render.YELLOW, render.GREEN, render.CYAN, render.BLUE, render.MAGENTA) +$LEN_PALETTE := @sizeof(@TypeOf(palette)) / @sizeof(render.Color) example := fn(): void { screen := @as(render.Surface, idk) @@ -90,74 +110,64 @@ example := fn(): void { } screen.clear(INTERIOR_COLOUR) - max_iteration := 0 - prev_max_iteration := 0 + x_scale := @as(f64, X_MAX - X_MIN) / @itf(@bitcast(screen.width)) + y_scale := @as(f64, Y_MAX - Y_MIN) / @itf(@bitcast(screen.height)) - x_scale := (X_MAX - X_MIN) / @floatcast(@itf(@bitcast(screen.width))) - y_scale := (Y_MAX - Y_MIN) / @floatcast(@itf(@bitcast(screen.height))) + py := 0 + loop if py == screen.height break else { + px := 0 + loop if px >= screen.width break else { + x0 := @as(f64, X_MIN) + @itf(@bitcast(px)) * x_scale + y0 := @as(f64, Y_MIN) + @itf(@bitcast(py)) * y_scale - loop if max_iteration >= MAX_MAX_ITERATION break else { - py := 0 - loop if py == screen.height break else { - px := 0 - loop if px >= screen.width break else { - x0 := X_MIN + @floatcast(@itf(@bitcast(px))) * x_scale - y0 := Y_MIN + @floatcast(@itf(@bitcast(py))) * y_scale - - q := (x0 - 0.25) * (x0 - 0.25) + y0 * y0 - if q * (q + x0 - 0.25) <= 0.25 * y0 * y0 { - px += 1 - continue - } - - if (x0 + 1.0) * (x0 + 1.0) + y0 * y0 <= 0.0625 { - px += 1 - continue - } - - x := 0.0 - y := 0.0 - iteration := 0 - x2 := x * x - y2 := y * y - loop if iteration == max_iteration break else { - if x2 + y2 > 4.0 break - y = 2.0 * x * y + y0 - x = x2 - y2 + x0 - iteration += 1 - x2 = x * x - y2 = y * y - } - - smooth_value := @itf(@bitcast(iteration - prev_max_iteration / 10)) / @itf(@bitcast(max_iteration)) - smooth_value *= smooth_value * (3 - 2 * smooth_value) - if iteration < max_iteration & iteration > prev_max_iteration / 10 { - colour := render.Color.{ - r: @intcast(@fti(smooth_value * COLOUR_R)), - g: @intcast(@fti(smooth_value * COLOUR_G)), - b: @intcast(@fti(smooth_value * COLOUR_B)), - a: 0, - } - screen.put_pixel(.(px, py), colour) - } - // faster - if iteration >= max_iteration { - px += 2 - } else if iteration < 5 { - screen.put_hline(py, px, px + 5, .(0, 0, 0, 0)) - px += 5 - } else { - px += 1 - } - // slower but more slightly more accurate - // px += 1 + q := (x0 - 0.25) * (x0 - 0.25) + y0 * y0 + if q * (q + x0 - 0.25) <= 0.25 * y0 * y0 { + px += 1 + continue } - py += 1 - } - prev_max_iteration = max_iteration - max_iteration += 5 - if USE_SUNSET { - _ = sunset.client.send_frame(window) + + if (x0 + 1.0) * (x0 + 1.0) + y0 * y0 <= 0.0625 { + px += 1 + continue + } + + x := @as(f64, 0.0) + y := @as(f64, 0.0) + iteration := 0 + + loop if x * x + y * y > @itf(1 << 16) | iteration == MAX_ITERATION break else { + x_temp := x * x - y * y + x0 + y = 2 * x * y + y0 + x = x_temp + iteration += 1 + } + + c := *screen.indexptr(px, py) + if c.r != INTERIOR_COLOUR.r | c.b != INTERIOR_COLOUR.b | c.g != INTERIOR_COLOUR.g { + px += 1 + continue + } + if iteration < MAX_ITERATION { + log_zn := ln_f64(x * x + y * y) / 2.0 + nu := ln_f64(log_zn / LOG_2) / LOG_2 + smoothed := @itf(@bitcast(iteration + 1)) - nu + smoothed_int := @fti(smoothed) + normalised := smoothed - @itf(smoothed_int) + colour0 := palette[@bitcast(smoothed_int) % LEN_PALETTE] + colour1 := palette[@bitcast(smoothed_int + 1) % LEN_PALETTE] + colour := render.Color.{ + r: @intcast(@fti(lerp_f64(@itf(@intcast(colour0.r)), @itf(@intcast(colour1.r)), normalised))), + g: @intcast(@fti(lerp_f64(@itf(@intcast(colour0.g)), @itf(@intcast(colour1.g)), normalised))), + b: @intcast(@fti(lerp_f64(@itf(@intcast(colour0.b)), @itf(@intcast(colour1.b)), normalised))), + a: 0, + } + screen.put_pixel(.(px, py), colour) + } + px += 1 } + py += 1 + } + if USE_SUNSET loop { + _ = sunset.client.send_frame(window) } } \ No newline at end of file diff --git a/sysdata/system_config.toml b/sysdata/system_config.toml index 8df697f..a811525 100644 --- a/sysdata/system_config.toml +++ b/sysdata/system_config.toml @@ -25,11 +25,11 @@ resolution = "1024x768x24" [boot.limine.ableos.modules.render_example] path = "boot:///render_example.hbf" -[boot.limine.ableos.modules.sunset_server] -path = "boot:///sunset_server.hbf" +# [boot.limine.ableos.modules.sunset_server] +# path = "boot:///sunset_server.hbf" -[boot.limine.ableos.modules.ps2_mouse_driver] -path = "boot:///ps2_mouse_driver.hbf" +# [boot.limine.ableos.modules.ps2_mouse_driver] +# path = "boot:///ps2_mouse_driver.hbf" # [boot.limine.ableos.modules.ps2_keyboard_driver] # path = "boot:///ps2_keyboard_driver.hbf"