diff --git a/build.zig.zon b/build.zig.zon index 0a209385f..30a07ba2a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -61,8 +61,8 @@ .hash = "1220edc3b8d8bedbb50555947987e5e8e2f93871ca3c8e8d4cc8f1377c15b5dd35e8", }, .z2d = .{ - .url = "git+https://github.com/vancluever/z2d?ref=main#285a796eb9c25a2389f087d008f0e60faf0b8eda", - .hash = "12206445aa45bcf0170ace371905f705aec1d8d4f61e7dd77839c6621b8c407680a5", + .url = "git+https://github.com/vancluever/z2d?ref=v0.4.0#4638bb02a9dc41cc2fb811f092811f6a951c752a", + .hash = "12201f0d542e7541cf492a001d4d0d0155c92f58212fbcb0d224e95edeba06b5416a", }, }, } diff --git a/nix/zigCacheHash.nix b/nix/zigCacheHash.nix index 0eebdee76..18602d987 100644 --- a/nix/zigCacheHash.nix +++ b/nix/zigCacheHash.nix @@ -1,3 +1,3 @@ # This file is auto-generated! check build-support/check-zig-cache-hash.sh for # more details. -"sha256-vP8f8KQyM4CwKlw7Esmxv1q4ANu8pDXXsnVorgpWCr4=" +"sha256-lS5v5VdFCLnIyCq9mp7fd2pXhQmkkDFHHVdg4pf37PA=" diff --git a/src/font/sprite/Box.zig b/src/font/sprite/Box.zig index f48b50598..f64665622 100644 --- a/src/font/sprite/Box.zig +++ b/src/font/sprite/Box.zig @@ -220,7 +220,7 @@ pub fn renderGlyph( metrics.cell_width, metrics.cell_height, ); - defer canvas.deinit(alloc); + defer canvas.deinit(); // Perform the actual drawing try self.draw(alloc, &canvas, cp); @@ -2233,18 +2233,10 @@ fn draw_branch_node( @min(float_width - cx, float_height - cy), ); - var ctx: z2d.Context = .{ - .surface = canvas.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, - }, - }, - .line_width = float_thick, - }; - - var path = z2d.Path.init(canvas.alloc); - defer path.deinit(); + var ctx = canvas.getContext() catch return; + defer ctx.deinit(); + ctx.setSource(.{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }); + ctx.setLineWidth(float_thick); // These @intFromFloat casts shouldn't ever fail since r can never // be greater than cx or cy, so when subtracting it from them the @@ -2259,13 +2251,13 @@ fn draw_branch_node( self.rect(canvas, 0, h_top, @intFromFloat(@ceil(cx - r)), h_bottom); if (node.filled) { - path.arc(cx, cy, r, 0, std.math.pi * 2, false, null) catch return; - path.close() catch return; - ctx.fill(canvas.alloc, path) catch return; + ctx.arc(cx, cy, r, 0, std.math.pi * 2) catch return; + ctx.closePath() catch return; + ctx.fill() catch return; } else { - path.arc(cx, cy, r - float_thick / 2, 0, std.math.pi * 2, false, null) catch return; - path.close() catch return; - ctx.stroke(canvas.alloc, path) catch return; + ctx.arc(cx, cy, r - float_thick / 2, 0, std.math.pi * 2) catch return; + ctx.closePath() catch return; + ctx.stroke() catch return; } } @@ -2290,27 +2282,21 @@ fn draw_circle( }; const r: f64 = 0.5 * @min(float_width, float_height); - var ctx: z2d.Context = .{ - .surface = canvas.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, - }, - }, - .line_width = @floatFromInt(Thickness.light.height(self.metrics.box_thickness)), - }; - - var path = z2d.Path.init(canvas.alloc); - defer path.deinit(); + var ctx = canvas.getContext() catch return; + defer ctx.deinit(); + ctx.setSource(.{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }); + ctx.setLineWidth( + @floatFromInt(Thickness.light.height(self.metrics.box_thickness)), + ); if (filled) { - path.arc(x, y, r, 0, std.math.pi * 2, false, null) catch return; - path.close() catch return; - ctx.fill(canvas.alloc, path) catch return; + ctx.arc(x, y, r, 0, std.math.pi * 2) catch return; + ctx.closePath() catch return; + ctx.fill() catch return; } else { - path.arc(x, y, r - ctx.line_width / 2, 0, std.math.pi * 2, false, null) catch return; - path.close() catch return; - ctx.stroke(canvas.alloc, path) catch return; + ctx.arc(x, y, r - ctx.line_width / 2, 0, std.math.pi * 2) catch return; + ctx.closePath() catch return; + ctx.stroke() catch return; } } @@ -2528,31 +2514,30 @@ fn draw_smooth_mosaic( const center: f64 = @round(@as(f64, @floatFromInt(self.metrics.cell_width)) / 2); const right: f64 = @floatFromInt(self.metrics.cell_width); - var path = z2d.Path.init(canvas.alloc); - defer path.deinit(); + var path: z2d.StaticPath(12) = .{}; + path.init(); - if (mosaic.tl) try path.lineTo(left, top); - if (mosaic.ul) try path.lineTo(left, upper); - if (mosaic.ll) try path.lineTo(left, lower); - if (mosaic.bl) try path.lineTo(left, bottom); - if (mosaic.bc) try path.lineTo(center, bottom); - if (mosaic.br) try path.lineTo(right, bottom); - if (mosaic.lr) try path.lineTo(right, lower); - if (mosaic.ur) try path.lineTo(right, upper); - if (mosaic.tr) try path.lineTo(right, top); - if (mosaic.tc) try path.lineTo(center, top); - try path.close(); + if (mosaic.tl) path.lineTo(left, top); + if (mosaic.ul) path.lineTo(left, upper); + if (mosaic.ll) path.lineTo(left, lower); + if (mosaic.bl) path.lineTo(left, bottom); + if (mosaic.bc) path.lineTo(center, bottom); + if (mosaic.br) path.lineTo(right, bottom); + if (mosaic.lr) path.lineTo(right, lower); + if (mosaic.ur) path.lineTo(right, upper); + if (mosaic.tr) path.lineTo(right, top); + if (mosaic.tc) path.lineTo(center, top); + path.close(); - var ctx: z2d.Context = .{ - .surface = canvas.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, - }, - }, - }; - - try ctx.fill(canvas.alloc, path); + try z2d.painter.fill( + canvas.alloc, + &canvas.sfc, + &.{ .opaque_pattern = .{ + .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, + } }, + &path.nodes, + .{}, + ); } fn draw_edge_triangle( @@ -2567,9 +2552,6 @@ fn draw_edge_triangle( const center: f64 = @round(@as(f64, @floatFromInt(self.metrics.cell_width)) / 2); const right: f64 = @floatFromInt(self.metrics.cell_width); - var path = z2d.Path.init(canvas.alloc); - defer path.deinit(); - const x0, const y0, const x1, const y1 = switch (edge) { .top => .{ right, upper, left, upper }, .left => .{ left, upper, left, lower }, @@ -2577,21 +2559,23 @@ fn draw_edge_triangle( .right => .{ right, lower, right, upper }, }; - try path.moveTo(center, middle); - try path.lineTo(x0, y0); - try path.lineTo(x1, y1); - try path.close(); + var path: z2d.StaticPath(5) = .{}; + path.init(); - var ctx: z2d.Context = .{ - .surface = canvas.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, - }, - }, - }; + path.moveTo(center, middle); + path.lineTo(x0, y0); + path.lineTo(x1, y1); + path.close(); - try ctx.fill(canvas.alloc, path); + try z2d.painter.fill( + canvas.alloc, + &canvas.sfc, + &.{ .opaque_pattern = .{ + .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, + } }, + &path.nodes, + .{}, + ); } fn draw_arc( @@ -2612,25 +2596,17 @@ fn draw_arc( // Fraction away from the center to place the middle control points, const s: f64 = 0.25; - var ctx: z2d.Context = .{ - .surface = canvas.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, - }, - }, - .line_width = float_thick, - .line_cap_mode = .round, - }; - - var path = z2d.Path.init(canvas.alloc); - defer path.deinit(); + var ctx = try canvas.getContext(); + defer ctx.deinit(); + ctx.setSource(.{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }); + ctx.setLineWidth(float_thick); + ctx.setLineCapMode(.round); switch (corner) { .tl => { - try path.moveTo(center_x, 0); - try path.lineTo(center_x, center_y - r); - try path.curveTo( + try ctx.moveTo(center_x, 0); + try ctx.lineTo(center_x, center_y - r); + try ctx.curveTo( center_x, center_y - s * r, center_x - s * r, @@ -2638,12 +2614,12 @@ fn draw_arc( center_x - r, center_y, ); - try path.lineTo(0, center_y); + try ctx.lineTo(0, center_y); }, .tr => { - try path.moveTo(center_x, 0); - try path.lineTo(center_x, center_y - r); - try path.curveTo( + try ctx.moveTo(center_x, 0); + try ctx.lineTo(center_x, center_y - r); + try ctx.curveTo( center_x, center_y - s * r, center_x + s * r, @@ -2651,12 +2627,12 @@ fn draw_arc( center_x + r, center_y, ); - try path.lineTo(float_width, center_y); + try ctx.lineTo(float_width, center_y); }, .bl => { - try path.moveTo(center_x, float_height); - try path.lineTo(center_x, center_y + r); - try path.curveTo( + try ctx.moveTo(center_x, float_height); + try ctx.lineTo(center_x, center_y + r); + try ctx.curveTo( center_x, center_y + s * r, center_x - s * r, @@ -2664,12 +2640,12 @@ fn draw_arc( center_x - r, center_y, ); - try path.lineTo(0, center_y); + try ctx.lineTo(0, center_y); }, .br => { - try path.moveTo(center_x, float_height); - try path.lineTo(center_x, center_y + r); - try path.curveTo( + try ctx.moveTo(center_x, float_height); + try ctx.lineTo(center_x, center_y + r); + try ctx.curveTo( center_x, center_y + s * r, center_x + s * r, @@ -2677,10 +2653,10 @@ fn draw_arc( center_x + r, center_y, ); - try path.lineTo(float_width, center_y); + try ctx.lineTo(float_width, center_y); }, } - try ctx.stroke(canvas.alloc, path); + try ctx.stroke(); } fn draw_dash_horizontal( @@ -2912,14 +2888,9 @@ fn draw_separated_block_quadrant(self: Box, canvas: *font.sprite.Canvas, comptim } } - var ctx: z2d.Context = .{ - .surface = canvas.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }, - }, - }, - }; + var ctx = try canvas.getContext(); + defer ctx.deinit(); + ctx.setSource(.{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } }); const gap: f64 = @max(1.0, @as(f64, @floatFromInt(self.metrics.cell_width)) * 0.10) / 2.0; const left: f64 = gap; @@ -2953,15 +2924,14 @@ fn draw_separated_block_quadrant(self: Box, canvas: *font.sprite.Canvas, comptim }, else => unreachable, }; - var path = z2d.Path.init(canvas.alloc); - defer path.deinit(); - try path.moveTo(x1, y1); - try path.lineTo(x2, y1); - try path.lineTo(x2, y2); - try path.lineTo(x1, y2); - try path.close(); - try ctx.fill(canvas.alloc, path); + try ctx.moveTo(x1, y1); + try ctx.lineTo(x2, y1); + try ctx.lineTo(x2, y2); + try ctx.lineTo(x1, y2); + try ctx.closePath(); } + + try ctx.fill(); } test "all" { diff --git a/src/font/sprite/Powerline.zig b/src/font/sprite/Powerline.zig index 8a435a3e8..904eae957 100644 --- a/src/font/sprite/Powerline.zig +++ b/src/font/sprite/Powerline.zig @@ -58,7 +58,7 @@ pub fn renderGlyph( ) !font.Glyph { // Create the canvas we'll use to draw var canvas = try font.sprite.Canvas.init(alloc, self.width, self.height); - defer canvas.deinit(alloc); + defer canvas.deinit(); // Perform the actual drawing try self.draw(alloc, &canvas, cp); diff --git a/src/font/sprite/canvas.zig b/src/font/sprite/canvas.zig index 3d472538c..be7bdf8cc 100644 --- a/src/font/sprite/canvas.zig +++ b/src/font/sprite/canvas.zig @@ -74,6 +74,9 @@ pub const Color = enum(u8) { _, }; +/// This is a managed struct, it keeps a reference to the allocator that is +/// used to initialize it, and the same allocator is used for any further +/// necessary allocations when drawing. pub const Canvas = struct { /// The underlying z2d surface. sfc: z2d.Surface, @@ -88,16 +91,13 @@ pub const Canvas = struct { @intCast(width), @intCast(height), ); + errdefer sfc.deinit(alloc); - return .{ - .sfc = sfc, - .alloc = alloc, - }; + return .{ .sfc = sfc, .alloc = alloc }; } - pub fn deinit(self: *Canvas, alloc: Allocator) void { - _ = alloc; - self.sfc.deinit(); + pub fn deinit(self: *Canvas) void { + self.sfc.deinit(self.alloc); self.* = undefined; } @@ -148,27 +148,18 @@ pub const Canvas = struct { return region; } + /// Acquires a z2d drawing context, caller MUST deinit context. + pub fn getContext(self: *Canvas) Allocator.Error!z2d.Context { + return try z2d.Context.init(self.alloc, &self.sfc); + } + /// Draw and fill a single pixel pub fn pixel(self: *Canvas, x: u32, y: u32, color: Color) void { self.sfc.putPixel( @intCast(x), @intCast(y), .{ .alpha8 = .{ .a = @intFromEnum(color) } }, - ) catch |e| switch (e) { - error.OutOfRange => { - // If we try to set out of range this will fail. We just silently - // ignore it, so that this method (and `rect` which uses it) have - // implicit bounds clipping. - }, - - error.InvalidHeight, - error.InvalidWidth, - error.InvalidPixelFormat, - => { - std.log.err("unexpected (considered impossible) error err={}", .{e}); - unreachable; // This shouldn't be possible. - }, - }; + ); } /// Draw and fill a rectangle. This is the main primitive for drawing @@ -192,94 +183,89 @@ pub const Canvas = struct { /// Draw and fill a quad. pub fn quad(self: *Canvas, q: Quad(f64), color: Color) !void { - var ctx: z2d.Context = .{ - .surface = self.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, - }, - }, - }; + var path: z2d.StaticPath(6) = .{}; + path.init(); - var path = z2d.Path.init(self.alloc); - defer path.deinit(); + path.moveTo(q.p0.x, q.p0.y); + path.lineTo(q.p1.x, q.p1.y); + path.lineTo(q.p2.x, q.p2.y); + path.lineTo(q.p3.x, q.p3.y); + path.close(); - try path.moveTo(q.p0.x, q.p0.y); - try path.lineTo(q.p1.x, q.p1.y); - try path.lineTo(q.p2.x, q.p2.y); - try path.lineTo(q.p3.x, q.p3.y); - try path.close(); - - try ctx.fill(self.alloc, path); + try z2d.painter.fill( + self.alloc, + &self.sfc, + &.{ .opaque_pattern = .{ + .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, + } }, + &path.nodes, + .{}, + ); } /// Draw and fill a triangle. pub fn triangle(self: *Canvas, t: Triangle(f64), color: Color) !void { - var ctx: z2d.Context = .{ - .surface = self.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, - }, - }, - }; + var path: z2d.StaticPath(5) = .{}; + path.init(); - var path = z2d.Path.init(self.alloc); - defer path.deinit(); + path.moveTo(t.p0.x, t.p0.y); + path.lineTo(t.p1.x, t.p1.y); + path.lineTo(t.p2.x, t.p2.y); + path.close(); - try path.moveTo(t.p0.x, t.p0.y); - try path.lineTo(t.p1.x, t.p1.y); - try path.lineTo(t.p2.x, t.p2.y); - try path.close(); - - try ctx.fill(self.alloc, path); + try z2d.painter.fill( + self.alloc, + &self.sfc, + &.{ .opaque_pattern = .{ + .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, + } }, + &path.nodes, + .{}, + ); } pub fn triangle_outline(self: *Canvas, t: Triangle(f64), thickness: f64, color: Color) !void { - var ctx: z2d.Context = .{ - .surface = self.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, - }, + var path: z2d.StaticPath(5) = .{}; + path.init(); + + path.moveTo(t.p0.x, t.p0.y); + path.lineTo(t.p1.x, t.p1.y); + path.lineTo(t.p2.x, t.p2.y); + + try z2d.painter.stroke( + self.alloc, + &self.sfc, + &.{ .opaque_pattern = .{ + .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, + } }, + &path.nodes, + .{ + .line_cap_mode = .round, + .line_width = thickness, }, - .line_width = thickness, - .line_cap_mode = .round, - }; - - var path = z2d.Path.init(self.alloc); - defer path.deinit(); - - try path.moveTo(t.p0.x, t.p0.y); - try path.lineTo(t.p1.x, t.p1.y); - try path.lineTo(t.p2.x, t.p2.y); - // try path.close(); - - try ctx.stroke(self.alloc, path); - // try ctx.fill(self.alloc, path); - + ); } /// Stroke a line. pub fn line(self: *Canvas, l: Line(f64), thickness: f64, color: Color) !void { - var ctx: z2d.Context = .{ - .surface = self.sfc, - .pattern = .{ - .opaque_pattern = .{ - .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, - }, + var path: z2d.StaticPath(3) = .{}; + path.init(); + + path.moveTo(l.p0.x, l.p0.y); + path.lineTo(l.p1.x, l.p1.y); + + try z2d.painter.stroke( + self.alloc, + &self.sfc, + &.{ .opaque_pattern = .{ + .pixel = .{ .alpha8 = .{ .a = @intFromEnum(color) } }, + } }, + &path.nodes, + .{ + .line_cap_mode = .round, + .line_width = thickness, }, - .line_width = thickness, - .line_cap_mode = .round, - }; - - var path = z2d.Path.init(self.alloc); - defer path.deinit(); - - try path.moveTo(l.p0.x, l.p0.y); - try path.lineTo(l.p1.x, l.p1.y); - - try ctx.stroke(self.alloc, path); + ); } pub fn invert(self: *Canvas) void { diff --git a/src/font/sprite/cursor.zig b/src/font/sprite/cursor.zig index b20b6c531..62195316e 100644 --- a/src/font/sprite/cursor.zig +++ b/src/font/sprite/cursor.zig @@ -17,7 +17,7 @@ pub fn renderGlyph( ) !font.Glyph { // Make a canvas of the desired size var canvas = try font.sprite.Canvas.init(alloc, width, height); - defer canvas.deinit(alloc); + defer canvas.deinit(); // Draw the appropriate sprite switch (sprite) { diff --git a/src/font/sprite/testdata/Box.ppm b/src/font/sprite/testdata/Box.ppm index 56d190842..36519a1e9 100644 Binary files a/src/font/sprite/testdata/Box.ppm and b/src/font/sprite/testdata/Box.ppm differ diff --git a/src/font/sprite/underline.zig b/src/font/sprite/underline.zig index e54807bc1..d2e439e6a 100644 --- a/src/font/sprite/underline.zig +++ b/src/font/sprite/underline.zig @@ -38,7 +38,7 @@ pub fn renderGlyph( .strikethrough => try drawSingle(alloc, width, line_thickness), else => unreachable, }; - defer canvas.deinit(alloc); + defer canvas.deinit(); // Write the drawing to the atlas const region = try canvas.writeAtlas(alloc, atlas);