initial implementation of WebGL-based brush renderer
This commit is contained in:
parent
b4c3260f49
commit
bb55e23979
14 changed files with 385 additions and 247 deletions
|
@ -77,13 +77,7 @@ pub fn resolve(arity: SystemFnArity, name: &str) -> Option<u8> {
|
|||
(Nary, "reduce") => 0x95,
|
||||
(Nary, "flatten") => 0x96,
|
||||
|
||||
(Nary, "toShape") => 0xc0,
|
||||
(Nary, "line") => 0xc1,
|
||||
(Nary, "rect") => 0xc2,
|
||||
(Nary, "circle") => 0xc3,
|
||||
|
||||
(Nary, "stroke") => 0xe0,
|
||||
(Nary, "fill") => 0xe1,
|
||||
|
||||
(Nary, "withDotter") => 0xf0,
|
||||
|
||||
|
|
|
@ -8,41 +8,21 @@ pub const Canvas = opaque {
|
|||
if (!status) return error.Draw;
|
||||
}
|
||||
|
||||
pub fn begin(c: *Canvas) !void {
|
||||
try wrap(__haku2_canvas_begin(c));
|
||||
}
|
||||
|
||||
pub fn line(c: *Canvas, start: value.Vec2, end: value.Vec2) !void {
|
||||
const x1, const y1 = start;
|
||||
const x2, const y2 = end;
|
||||
try wrap(__haku2_canvas_line(c, x1, y1, x2, y2));
|
||||
}
|
||||
|
||||
pub fn rect(c: *Canvas, top_left: value.Vec2, size: value.Vec2) !void {
|
||||
const x, const y = top_left;
|
||||
const width, const height = size;
|
||||
try wrap(__haku2_canvas_rectangle(c, x, y, width, height));
|
||||
}
|
||||
|
||||
pub fn circle(c: *Canvas, center: value.Vec2, r: f32) !void {
|
||||
const x, const y = center;
|
||||
try wrap(__haku2_canvas_circle(c, x, y, r));
|
||||
}
|
||||
|
||||
pub fn fill(c: *Canvas, color: value.Rgba8) !void {
|
||||
pub fn stroke(c: *Canvas, color: value.Rgba8, thickness: f32, from: value.Vec2, to: value.Vec2) !void {
|
||||
const r, const g, const b, const a = color;
|
||||
try wrap(__haku2_canvas_fill(c, r, g, b, a));
|
||||
}
|
||||
|
||||
pub fn stroke(c: *Canvas, color: value.Rgba8, thickness: f32) !void {
|
||||
const r, const g, const b, const a = color;
|
||||
try wrap(__haku2_canvas_stroke(c, r, g, b, a, thickness));
|
||||
try wrap(__haku2_canvas_stroke(c, r, g, b, a, thickness, from[0], from[1], to[0], to[1]));
|
||||
}
|
||||
};
|
||||
|
||||
extern fn __haku2_canvas_begin(c: *Canvas) bool;
|
||||
extern fn __haku2_canvas_line(c: *Canvas, x1: f32, y1: f32, x2: f32, y2: f32) bool;
|
||||
extern fn __haku2_canvas_rectangle(c: *Canvas, x: f32, y: f32, width: f32, height: f32) bool;
|
||||
extern fn __haku2_canvas_circle(c: *Canvas, x: f32, y: f32, r: f32) bool;
|
||||
extern fn __haku2_canvas_fill(c: *Canvas, r: u8, g: u8, b: u8, a: u8) bool;
|
||||
extern fn __haku2_canvas_stroke(c: *Canvas, r: u8, g: u8, b: u8, a: u8, thickness: f32) bool;
|
||||
extern fn __haku2_canvas_stroke(
|
||||
c: *Canvas,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
thickness: f32,
|
||||
from_x: f32,
|
||||
from_y: f32,
|
||||
to_x: f32,
|
||||
to_y: f32,
|
||||
) bool;
|
||||
|
|
|
@ -24,18 +24,13 @@ fn renderRec(vm: *Vm, canvas: *Canvas, val: Value, depth: usize, max_depth: usiz
|
|||
|
||||
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)),
|
||||
switch (val.ref.scribble) {
|
||||
.stroke => |stroke| try canvas.stroke(
|
||||
value.rgbaTo8(stroke.color),
|
||||
stroke.thickness,
|
||||
value.vec2From4(stroke.from),
|
||||
value.vec2From4(stroke.to),
|
||||
),
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -46,10 +41,6 @@ fn renderRec(vm: *Vm, canvas: *Canvas, val: Value, depth: usize, max_depth: usiz
|
|||
}
|
||||
},
|
||||
|
||||
.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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,14 +118,6 @@ fn fromArgument(cx: Context, comptime T: type, i: usize) Vm.Error!T {
|
|||
if (val != .ref or val.ref.* != .list) return typeError(cx.vm, val, i, "list");
|
||||
return val.ref.list;
|
||||
},
|
||||
value.Shape => {
|
||||
const val = cx.args[i];
|
||||
if (toShape(val)) |shape| {
|
||||
return shape;
|
||||
} else {
|
||||
return typeError(cx.vm, val, i, "shape");
|
||||
}
|
||||
},
|
||||
*const value.Closure => {
|
||||
const val = cx.args[i];
|
||||
if (val != .ref or val.ref.* != .closure) return typeError(cx.vm, val, i, "function");
|
||||
|
@ -282,12 +274,7 @@ pub const fns = makeFnTable(&[_]SparseFn{
|
|||
.{ 0x94, erase("filter", filter) },
|
||||
.{ 0x95, erase("reduce", reduce) },
|
||||
.{ 0x96, erase("flatten", flatten) },
|
||||
.{ 0xc0, erase("toShape", valueToShape) },
|
||||
.{ 0xc1, erase("line", line) },
|
||||
.{ 0xc2, erase("rect", rect) },
|
||||
.{ 0xc3, erase("circle", circle) },
|
||||
.{ 0xe0, erase("stroke", stroke) },
|
||||
.{ 0xe1, erase("fill", fill) },
|
||||
.{ 0xf0, erase("withDotter", withDotter) },
|
||||
});
|
||||
|
||||
|
@ -738,51 +725,14 @@ fn flatten(list: value.List, cx: Context) Vm.Error!value.Ref {
|
|||
return .{ .list = flattened_list };
|
||||
}
|
||||
|
||||
fn toShape(val: value.Value) ?value.Shape {
|
||||
return switch (val) {
|
||||
.nil, .false, .true, .tag, .number, .rgba => null,
|
||||
.vec4 => |v| .{ .point = value.vec2From4(v) },
|
||||
.ref => |r| if (r.* == .shape) r.shape else null,
|
||||
};
|
||||
}
|
||||
|
||||
/// `toShape`
|
||||
fn valueToShape(val: value.Value) ?value.Ref {
|
||||
if (toShape(val)) |shape| {
|
||||
return .{ .shape = shape };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn line(start: Vec4, end: Vec4) value.Ref {
|
||||
return .{ .shape = .{ .line = .{
|
||||
.start = value.vec2From4(start.value),
|
||||
.end = value.vec2From4(end.value),
|
||||
} } };
|
||||
}
|
||||
|
||||
fn rect(top_left: Vec4, size: Vec4) value.Ref {
|
||||
return .{ .shape = .{ .rect = .{
|
||||
.top_left = value.vec2From4(top_left.value),
|
||||
.size = value.vec2From4(size.value),
|
||||
} } };
|
||||
}
|
||||
|
||||
fn circle(center: Vec4, radius: f32) value.Ref {
|
||||
return .{ .shape = .{ .circle = .{
|
||||
.center = value.vec2From4(center.value),
|
||||
.radius = radius,
|
||||
} } };
|
||||
}
|
||||
|
||||
fn stroke(thickness: f32, color: Rgba, shape: value.Shape) value.Ref {
|
||||
fn stroke(thickness: f32, color: Rgba, from: Vec4, to: Vec4) value.Ref {
|
||||
return .{ .scribble = .{
|
||||
.shape = shape,
|
||||
.action = .{ .stroke = .{
|
||||
.stroke = .{
|
||||
.thickness = thickness,
|
||||
.color = color.value,
|
||||
} },
|
||||
.from = from.value,
|
||||
.to = to.value,
|
||||
},
|
||||
} };
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ pub const Value = union(enum) {
|
|||
.ref => |r| switch (r.*) {
|
||||
.closure => "function",
|
||||
.list => "list",
|
||||
.shape => "shape",
|
||||
.scribble => "scribble",
|
||||
.reticle => "reticle",
|
||||
},
|
||||
|
@ -86,7 +85,7 @@ pub const Value = union(enum) {
|
|||
}
|
||||
try writer.writeAll("]");
|
||||
},
|
||||
inline .shape, .scribble, .reticle => |x| try writer.print("{}", .{x}),
|
||||
inline .scribble, .reticle => |x| try writer.print("{}", .{x}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +121,6 @@ pub fn rgbaTo8(rgba: Rgba) Rgba8 {
|
|||
pub const Ref = union(enum) {
|
||||
closure: Closure,
|
||||
list: List,
|
||||
shape: Shape,
|
||||
scribble: Scribble,
|
||||
reticle: Reticle,
|
||||
};
|
||||
|
@ -161,44 +159,14 @@ pub const Closure = struct {
|
|||
|
||||
pub const List = []Value;
|
||||
|
||||
pub const Shape = union(enum) {
|
||||
point: Vec2,
|
||||
line: Line,
|
||||
rect: Rect,
|
||||
circle: Circle,
|
||||
pub const Scribble = union(enum) {
|
||||
stroke: Stroke,
|
||||
|
||||
pub const Line = struct {
|
||||
start: Vec2,
|
||||
end: Vec2,
|
||||
};
|
||||
|
||||
pub const Rect = struct {
|
||||
top_left: Vec2,
|
||||
size: Vec2,
|
||||
};
|
||||
|
||||
pub const Circle = struct {
|
||||
center: Vec2,
|
||||
radius: f32,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Scribble = struct {
|
||||
shape: Shape,
|
||||
action: Action,
|
||||
|
||||
pub const Action = union(enum) {
|
||||
stroke: Stroke,
|
||||
fill: Fill,
|
||||
|
||||
pub const Stroke = struct {
|
||||
thickness: f32,
|
||||
color: Rgba,
|
||||
};
|
||||
|
||||
pub const Fill = struct {
|
||||
color: Rgba,
|
||||
};
|
||||
pub const Stroke = struct {
|
||||
thickness: f32,
|
||||
color: Rgba,
|
||||
from: Vec4,
|
||||
to: Vec4,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue