1
0
Fork 0
forked from AbleOS/ableos
ableos/sysdata/programs/render_example/src/examples/mandelbrot.hb
2024-12-16 07:58:04 -06:00

170 lines
3.7 KiB
Plaintext

// 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
// }
// 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
// }
// 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
// }
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
// 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 := 100
$USE_SUNSET := true
$COLOUR_R := 200
$COLOUR_G := 100
$COLOUR_B := 255
// $COLOUR_R := 255
// $COLOUR_G := 255
// $COLOUR_B := 255
// $INTERIOR_COLOUR := render.white
$INTERIOR_COLOUR := render.Color.{r: COLOUR_R, g: COLOUR_G, b: COLOUR_B, a: 255}
example := fn(): void {
screen := @as(render.Surface, idk)
window := @as(?sunset.Window, null)
if USE_SUNSET {
sunset.client.find_server()
window = sunset.client.new(.(.(450, 140), .(400, 400), "Mandelbrot Set\0"))
if window == null {
log.error("got no window\0")
return
}
screen = window.surface
} else {
screen = render.init(false)
}
render.clear(screen, INTERIOR_COLOUR)
max_iteration := 0
prev_max_iteration := 0
x_scale := (X_MAX - X_MIN) / @floatcast(@itf(@bitcast(screen.width)))
y_scale := (Y_MAX - Y_MIN) / @floatcast(@itf(@bitcast(screen.height)))
loop if max_iteration >= MAX_MAX_ITERATION break else {
log.info("Iteration complete.\0")
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,
}
render.put_pixel(screen, .(px, py), colour)
}
// faster
if iteration >= max_iteration {
px += 2
} else if iteration < 5 {
render.put_hline(screen, py, px, px + 5, .(0, 0, 0, 0))
px += 5
} else {
px += 1
}
// slower but more slightly more accurate
// px += 1
}
py += 1
}
prev_max_iteration = max_iteration
max_iteration += 5
if USE_SUNSET {
_ = sunset.client.send_frame(window)
}
}
// if USE_SUNSET {
// loop {
// _ = sunset.client.send_frame(window)
// }
// }
}