rkgk/crates/haku2/src/render.zig
リキ萌 5de4f9d7c6 hotwire haku2 into rkgk
really a bodge job right now and it crashes but it's a start
2025-06-04 00:28:43 +02:00

59 lines
2.1 KiB
Zig

const std = @import("std");
const Canvas = @import("canvas.zig").Canvas;
const value = @import("value.zig");
const Value = value.Value;
const Vm = @import("vm.zig");
fn notAScribble(vm: *Vm, val: Value) Vm.Error {
return vm.throw(
"the brush returned a {s}, which cannot be drawn. return a scribble (e.g. fill, stroke, list) instead",
.{val.typeName()},
);
}
fn renderRec(vm: *Vm, canvas: *Canvas, val: Value, depth: usize, max_depth: usize) !void {
if (depth > max_depth) {
return vm.throw(
"the brush returned a scribble that's nested too deep ({} levels). try generating lists that aren't as deep using the (map (range min max) f) idiom, or flatten your lists using the flatten function",
.{max_depth},
);
}
if (val != .ref) return notAScribble(vm, val);
switch (val.ref.*) {
.scribble => {
try canvas.begin();
switch (val.ref.scribble.shape) {
.point => |point| try canvas.line(point, point),
.line => |line| try canvas.line(line.start, line.end),
.rect => |rect| try canvas.rect(rect.top_left, rect.size),
.circle => |circle| try canvas.circle(circle.center, circle.radius),
}
switch (val.ref.scribble.action) {
.stroke => |stroke| try canvas.stroke(value.rgbaTo8(stroke.color), stroke.thickness),
.fill => |fill| try canvas.fill(value.rgbaTo8(fill.color)),
}
},
.list => {
for (val.ref.list) |nested| {
try vm.consumeFuel(&vm.fuel, 1);
try renderRec(vm, canvas, nested, depth + 1, max_depth);
}
},
.shape => {
return vm.throw("the brush returned a bare shape, which cannot be drawn. try wrapping your shape in a fill or a stroke: (fill #000 <shape>)", .{});
},
else => return notAScribble(vm, val),
}
}
pub fn render(vm: *Vm, canvas: *Canvas, max_depth: usize) !void {
const val = vm.stack[vm.stack_top - 1];
try renderRec(vm, canvas, val, 0, max_depth);
}