1
0
Fork 0
forked from AbleOS/ableos
ableos/sysdata/programs/render_example/src/examples/mandelbrot.hb
2024-12-15 22:05:06 +00:00

173 lines
3.9 KiB
Plaintext

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
scale := @as(f64, 0.0)
scaled_x := x
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");
.{log} := @use("stn")
// full mandelbrot
// $X_MIN := -2.0
// $X_MAX := 0.47
// $Y_MIN := -1.12
// $Y_MAX := 1.12
// a minibrot
$X_MIN := -0.94
$X_MAX := -0.93
$Y_MIN := 0.31
$Y_MAX := 0.306
$MAX_ITERATION := 300
$USE_SUNSET := false
$COLOUR_R := 200
$COLOUR_G := 100
$COLOUR_B := 255
$LOG_2 := 0.693147180559945309417232121458176568
$E := 2.71828182845904523536028747135266250
$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)
window := @as(?sunset.Window, null)
if USE_SUNSET {
sunset.client.find_server()
window = sunset.client.new(.(.(400, 140), .(400, 400), "Mandelbrot Set\0"))
if window == null {
log.error("got no window\0")
return
}
screen = window.surface
} else {
screen = render.init(false)
}
screen.clear(INTERIOR_COLOUR)
x_scale := @as(f64, X_MAX - X_MIN) / @itf(@bitcast(screen.width))
y_scale := @as(f64, Y_MAX - Y_MIN) / @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
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 := @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)
}
}