render := @use("lib:render")
sunset := @use("lib:sunset_proto");
.{math, 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

// zoom into that weird curve part of the main cardioid
// $X_MIN := 0.25
// $X_MAX := 0.34
// $Y_MIN := -0.075
// $Y_MAX := 0.075

$MAX_ITERATION := 300

$USE_SUNSET := true

palette := render.Color.[.(50, 0, 60, 0), .(93, 0, 157, 0), .(140, 98, 229, 0), .(191, 190, 255, 0), .(226, 234, 255, 0), .(242, 250, 255, 0), .(226, 234, 255, 0), .(191, 190, 255, 0), .(140, 98, 229, 0), .(93, 0, 157, 0), .(50, 0, 60, 0)]
$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(.(.(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)
	}

	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 | (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
			// arbitrary, i cant tell the difference between 32 and 1 << 16
			loop if x * x + y * y > 32.0 | iteration == MAX_ITERATION break else {
				x_temp := x * x - y * y + x0
				y = 2 * x * y + y0
				x = x_temp
				iteration += 1
			}

			if iteration < MAX_ITERATION {
				log_zn := math.ln(f64, x * x + y * y) / 2
				nu := math.ln(f64, log_zn / math.LN_2) / math.LN_2
				smoothed := @as(f64, @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(math.lerp(f64, @itf(colour0.r), @itf(colour1.r), normalised))),
					g: @intcast(@fti(math.lerp(f64, @itf(colour0.g), @itf(colour1.g), normalised))),
					b: @intcast(@fti(math.lerp(f64, @itf(colour0.b), @itf(colour1.b), normalised))),
					a: 0,
				}
				screen.put_pixel(.(px, py), colour)
			}
			px += 1
		}
		py += 1
		if USE_SUNSET {
			_ = sunset.client.send_frame(window)
		}
	}
	if USE_SUNSET loop {
		_ = sunset.client.send_frame(window)
	}
}