mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 16:26:08 +03:00
font/sprite: address PR review feedback
- Make canvas geometry primitives generic, use `Rect(u32)` for `rect` function, so that we don't have to worry about negatives or rounding. - Make `Quads` struct packed just in case it gets non-comptime use in the future. - Clarify comment on why we're discarding out of range pixels + runtime unreachable for any other type of error which we shouldn't ever see. - Move z2d import above in-tree imports.
This commit is contained in:
@ -20,11 +20,11 @@ const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const z2d = @import("z2d");
|
||||
|
||||
const font = @import("../main.zig");
|
||||
const Sprite = @import("../sprite.zig").Sprite;
|
||||
|
||||
const z2d = @import("z2d");
|
||||
|
||||
const log = std.log.scoped(.box_font);
|
||||
|
||||
/// The cell width and height because the boxes are fit perfectly
|
||||
@ -72,7 +72,7 @@ const Lines = packed struct(u8) {
|
||||
|
||||
/// Specification of a quadrants char, which has each of the
|
||||
/// 4 quadrants of the character cell either filled or empty.
|
||||
const Quads = struct {
|
||||
const Quads = packed struct(u4) {
|
||||
tl: bool = false,
|
||||
tr: bool = false,
|
||||
bl: bool = false,
|
||||
@ -1621,10 +1621,10 @@ fn draw_block_shade(
|
||||
};
|
||||
|
||||
canvas.rect(.{
|
||||
.x = @floatFromInt(x),
|
||||
.y = @floatFromInt(y),
|
||||
.width = @floatFromInt(w),
|
||||
.height = @floatFromInt(h),
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = w,
|
||||
.height = h,
|
||||
}, @as(font.sprite.Color, @enumFromInt(@intFromEnum(shade))));
|
||||
}
|
||||
|
||||
@ -1671,10 +1671,10 @@ fn draw_checkerboard_fill(self: Box, canvas: *font.sprite.Canvas, parity: u1) vo
|
||||
const y1 = (self.height * (y + 1)) / y_size;
|
||||
if ((x + y) % 2 == parity) {
|
||||
canvas.rect(.{
|
||||
.x = @floatFromInt(x0),
|
||||
.y = @floatFromInt(y0),
|
||||
.width = @floatFromInt(x1 -| x0),
|
||||
.height = @floatFromInt(y1 -| y0),
|
||||
.x = @intCast(x0),
|
||||
.y = @intCast(y0),
|
||||
.width = @intCast(x1 -| x0),
|
||||
.height = @intCast(y1 -| y0),
|
||||
}, .on);
|
||||
}
|
||||
}
|
||||
@ -1841,8 +1841,8 @@ fn draw_circle(
|
||||
fn draw_line(
|
||||
self: Box,
|
||||
canvas: *font.sprite.Canvas,
|
||||
p0: font.sprite.Point,
|
||||
p1: font.sprite.Point,
|
||||
p0: font.sprite.Point(f64),
|
||||
p1: font.sprite.Point(f64),
|
||||
comptime thickness: Thickness,
|
||||
) !void {
|
||||
canvas.line(
|
||||
@ -1853,11 +1853,11 @@ fn draw_line(
|
||||
}
|
||||
|
||||
fn draw_shade(self: Box, canvas: *font.sprite.Canvas, v: u16) void {
|
||||
canvas.rect((font.sprite.Box{
|
||||
canvas.rect((font.sprite.Box(u32){
|
||||
.p0 = .{ .x = 0, .y = 0 },
|
||||
.p1 = .{
|
||||
.x = @floatFromInt(self.width),
|
||||
.y = @floatFromInt(self.height),
|
||||
.x = self.width,
|
||||
.y = self.height,
|
||||
},
|
||||
}).rect(), @as(font.sprite.Color, @enumFromInt(v)));
|
||||
}
|
||||
@ -2395,12 +2395,12 @@ fn vline(
|
||||
x: u32,
|
||||
thickness_px: u32,
|
||||
) void {
|
||||
canvas.rect((font.sprite.Box{ .p0 = .{
|
||||
.x = @floatFromInt(@min(@max(x, 0), self.width)),
|
||||
.y = @floatFromInt(@min(@max(y1, 0), self.height)),
|
||||
canvas.rect((font.sprite.Box(u32){ .p0 = .{
|
||||
.x = @min(@max(x, 0), self.width),
|
||||
.y = @min(@max(y1, 0), self.height),
|
||||
}, .p1 = .{
|
||||
.x = @floatFromInt(@min(@max(x + thickness_px, 0), self.width)),
|
||||
.y = @floatFromInt(@min(@max(y2, 0), self.height)),
|
||||
.x = @min(@max(x + thickness_px, 0), self.width),
|
||||
.y = @min(@max(y2, 0), self.height),
|
||||
} }).rect(), .on);
|
||||
}
|
||||
|
||||
@ -2412,12 +2412,12 @@ fn hline(
|
||||
y: u32,
|
||||
thickness_px: u32,
|
||||
) void {
|
||||
canvas.rect((font.sprite.Box{ .p0 = .{
|
||||
.x = @floatFromInt(@min(@max(x1, 0), self.width)),
|
||||
.y = @floatFromInt(@min(@max(y, 0), self.height)),
|
||||
canvas.rect((font.sprite.Box(u32){ .p0 = .{
|
||||
.x = @min(@max(x1, 0), self.width),
|
||||
.y = @min(@max(y, 0), self.height),
|
||||
}, .p1 = .{
|
||||
.x = @floatFromInt(@min(@max(x2, 0), self.width)),
|
||||
.y = @floatFromInt(@min(@max(y + thickness_px, 0), self.height)),
|
||||
.x = @min(@max(x2, 0), self.width),
|
||||
.y = @min(@max(y + thickness_px, 0), self.height),
|
||||
} }).rect(), .on);
|
||||
}
|
||||
|
||||
@ -2429,12 +2429,12 @@ fn rect(
|
||||
x2: u32,
|
||||
y2: u32,
|
||||
) void {
|
||||
canvas.rect((font.sprite.Box{ .p0 = .{
|
||||
.x = @floatFromInt(@min(@max(x1, 0), self.width)),
|
||||
.y = @floatFromInt(@min(@max(y1, 0), self.height)),
|
||||
canvas.rect((font.sprite.Box(u32){ .p0 = .{
|
||||
.x = @min(@max(x1, 0), self.width),
|
||||
.y = @min(@max(y1, 0), self.height),
|
||||
}, .p1 = .{
|
||||
.x = @floatFromInt(@min(@max(x2, 0), self.width)),
|
||||
.y = @floatFromInt(@min(@max(y2, 0), self.height)),
|
||||
.x = @min(@max(x2, 0), self.width),
|
||||
.y = @min(@max(y2, 0), self.height),
|
||||
} }).rect(), .on);
|
||||
}
|
||||
|
||||
|
@ -391,8 +391,8 @@ fn draw_half_circle(self: Powerline, alloc: Allocator, canvas: *font.sprite.Canv
|
||||
const average = @as(u8, @intCast(@min(total / (supersample * supersample), 0xFF)));
|
||||
canvas.rect(
|
||||
.{
|
||||
.x = @floatFromInt(c),
|
||||
.y = @floatFromInt(r),
|
||||
.x = @intCast(c),
|
||||
.y = @intCast(r),
|
||||
.width = 1,
|
||||
.height = 1,
|
||||
},
|
||||
@ -404,7 +404,7 @@ fn draw_half_circle(self: Powerline, alloc: Allocator, canvas: *font.sprite.Canv
|
||||
}
|
||||
|
||||
fn draw_trapezoid_top_bottom(self: Powerline, canvas: *font.sprite.Canvas, cp: u32) !void {
|
||||
const t_top: Quad = if (cp == 0xE0D4)
|
||||
const t_top: Quad(f64) = if (cp == 0xE0D4)
|
||||
.{
|
||||
.p0 = .{
|
||||
.x = 0,
|
||||
@ -443,7 +443,7 @@ fn draw_trapezoid_top_bottom(self: Powerline, canvas: *font.sprite.Canvas, cp: u
|
||||
},
|
||||
};
|
||||
|
||||
const t_bottom: Quad = if (cp == 0xE0D4)
|
||||
const t_bottom: Quad(f64) = if (cp == 0xE0D4)
|
||||
.{
|
||||
.p0 = .{
|
||||
.x = @floatFromInt(self.width - self.width / 3),
|
||||
|
@ -6,53 +6,66 @@ const Allocator = std.mem.Allocator;
|
||||
const z2d = @import("z2d");
|
||||
const font = @import("../main.zig");
|
||||
|
||||
pub const Point = struct {
|
||||
x: f64,
|
||||
y: f64,
|
||||
};
|
||||
pub fn Point(comptime T: type) type {
|
||||
return struct {
|
||||
x: T,
|
||||
y: T,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Line = struct {
|
||||
p0: Point,
|
||||
p1: Point,
|
||||
};
|
||||
pub fn Line(comptime T: type) type {
|
||||
return struct {
|
||||
p0: Point(T),
|
||||
p1: Point(T),
|
||||
};
|
||||
}
|
||||
|
||||
pub const Box = struct {
|
||||
p0: Point,
|
||||
p1: Point,
|
||||
pub fn Box(comptime T: type) type {
|
||||
return struct {
|
||||
p0: Point(T),
|
||||
p1: Point(T),
|
||||
|
||||
pub fn rect(self: Box) Rect {
|
||||
const tl_x = @min(self.p0.x, self.p1.x);
|
||||
const tl_y = @min(self.p0.y, self.p1.y);
|
||||
const br_x = @max(self.p0.x, self.p1.x);
|
||||
const br_y = @max(self.p0.y, self.p1.y);
|
||||
return .{
|
||||
.x = tl_x,
|
||||
.y = tl_y,
|
||||
.width = br_x - tl_x,
|
||||
.height = br_y - tl_y,
|
||||
};
|
||||
}
|
||||
};
|
||||
pub fn rect(self: Box(T)) Rect(T) {
|
||||
const tl_x = @min(self.p0.x, self.p1.x);
|
||||
const tl_y = @min(self.p0.y, self.p1.y);
|
||||
const br_x = @max(self.p0.x, self.p1.x);
|
||||
const br_y = @max(self.p0.y, self.p1.y);
|
||||
|
||||
pub const Rect = struct {
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
};
|
||||
return .{
|
||||
.x = tl_x,
|
||||
.y = tl_y,
|
||||
.width = br_x - tl_x,
|
||||
.height = br_y - tl_y,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const Triangle = struct {
|
||||
p0: Point,
|
||||
p1: Point,
|
||||
p2: Point,
|
||||
};
|
||||
pub fn Rect(comptime T: type) type {
|
||||
return struct {
|
||||
x: T,
|
||||
y: T,
|
||||
width: T,
|
||||
height: T,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Quad = struct {
|
||||
p0: Point,
|
||||
p1: Point,
|
||||
p2: Point,
|
||||
p3: Point,
|
||||
};
|
||||
pub fn Triangle(comptime T: type) type {
|
||||
return struct {
|
||||
p0: Point(T),
|
||||
p1: Point(T),
|
||||
p2: Point(T),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn Quad(comptime T: type) type {
|
||||
return struct {
|
||||
p0: Point(T),
|
||||
p1: Point(T),
|
||||
p2: Point(T),
|
||||
p3: Point(T),
|
||||
};
|
||||
}
|
||||
|
||||
/// We only use alpha-channel so a pixel can only be "on" or "off".
|
||||
pub const Color = enum(u8) {
|
||||
@ -137,19 +150,26 @@ pub const Canvas = struct {
|
||||
@intCast(x),
|
||||
@intCast(y),
|
||||
.{ .alpha8 = .{ .a = @intFromEnum(color) } },
|
||||
) catch {
|
||||
// If we try to set out of range this will fail.
|
||||
// We just silently ignore that.
|
||||
) 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.
|
||||
},
|
||||
else => {
|
||||
std.log.err("Wtf? err={}", .{e});
|
||||
unreachable; // This shouldn't be possible.
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Draw and fill a rectangle. This is the main primitive for drawing
|
||||
/// lines as well (which are just generally skinny rectangles...)
|
||||
pub fn rect(self: *Canvas, v: Rect, color: Color) void {
|
||||
const x0: usize = @intFromFloat(v.x);
|
||||
const x1: usize = @intFromFloat(v.x + v.width);
|
||||
const y0: usize = @intFromFloat(v.y);
|
||||
const y1: usize = @intFromFloat(v.y + v.height);
|
||||
pub fn rect(self: *Canvas, v: Rect(u32), color: Color) void {
|
||||
const x0 = v.x;
|
||||
const x1 = v.x + v.width;
|
||||
const y0 = v.y;
|
||||
const y1 = v.y + v.height;
|
||||
|
||||
for (y0..y1) |y| {
|
||||
for (x0..x1) |x| {
|
||||
@ -163,7 +183,7 @@ pub const Canvas = struct {
|
||||
}
|
||||
|
||||
/// Draw and fill a quad.
|
||||
pub fn quad(self: *Canvas, q: Quad, color: Color) !void {
|
||||
pub fn quad(self: *Canvas, q: Quad(f64), color: Color) !void {
|
||||
var ctx: z2d.Context = .{
|
||||
.surface = self.sfc,
|
||||
.pattern = .{
|
||||
@ -186,7 +206,7 @@ pub const Canvas = struct {
|
||||
}
|
||||
|
||||
/// Draw and fill a triangle.
|
||||
pub fn triangle(self: *Canvas, t: Triangle, color: Color) !void {
|
||||
pub fn triangle(self: *Canvas, t: Triangle(f64), color: Color) !void {
|
||||
var ctx: z2d.Context = .{
|
||||
.surface = self.sfc,
|
||||
.pattern = .{
|
||||
@ -208,7 +228,7 @@ pub const Canvas = struct {
|
||||
}
|
||||
|
||||
/// Stroke a line.
|
||||
pub fn line(self: *Canvas, l: Line, thickness: f64, color: Color) !void {
|
||||
pub fn line(self: *Canvas, l: Line(f64), thickness: f64, color: Color) !void {
|
||||
var ctx: z2d.Context = .{
|
||||
.surface = self.sfc,
|
||||
.pattern = .{
|
||||
|
@ -70,8 +70,8 @@ fn drawSingle(alloc: Allocator, width: u32, thickness: u32) !CanvasAndOffset {
|
||||
canvas.rect(.{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = @floatFromInt(width),
|
||||
.height = @floatFromInt(thickness),
|
||||
.width = width,
|
||||
.height = thickness,
|
||||
}, .on);
|
||||
|
||||
const offset_y: i32 = 0;
|
||||
@ -91,15 +91,15 @@ fn drawDouble(alloc: Allocator, width: u32, thickness: u32) !CanvasAndOffset {
|
||||
canvas.rect(.{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = @floatFromInt(width),
|
||||
.height = @floatFromInt(thickness),
|
||||
.width = width,
|
||||
.height = thickness,
|
||||
}, .on);
|
||||
|
||||
canvas.rect(.{
|
||||
.x = 0,
|
||||
.y = @floatFromInt(thickness * 2),
|
||||
.width = @floatFromInt(width),
|
||||
.height = @floatFromInt(thickness),
|
||||
.y = thickness * 2,
|
||||
.width = width,
|
||||
.height = thickness,
|
||||
}, .on);
|
||||
|
||||
const offset_y: i32 = -@as(i32, @intCast(thickness));
|
||||
@ -121,10 +121,10 @@ fn drawDotted(alloc: Allocator, width: u32, thickness: u32) !CanvasAndOffset {
|
||||
const x = @min(i * (dot_width + gap_width), width - 1);
|
||||
const rect_width = @min(width - x, dot_width);
|
||||
canvas.rect(.{
|
||||
.x = @floatFromInt(x),
|
||||
.x = @intCast(x),
|
||||
.y = 0,
|
||||
.width = @floatFromInt(rect_width),
|
||||
.height = @floatFromInt(thickness),
|
||||
.width = rect_width,
|
||||
.height = thickness,
|
||||
}, .on);
|
||||
}
|
||||
|
||||
@ -146,10 +146,10 @@ fn drawDashed(alloc: Allocator, width: u32, thickness: u32) !CanvasAndOffset {
|
||||
const x = @min(i * dash_width, width - 1);
|
||||
const rect_width = @min(width - x, dash_width);
|
||||
canvas.rect(.{
|
||||
.x = @floatFromInt(x),
|
||||
.x = @intCast(x),
|
||||
.y = 0,
|
||||
.width = @floatFromInt(rect_width),
|
||||
.height = @floatFromInt(thickness),
|
||||
.width = rect_width,
|
||||
.height = thickness,
|
||||
}, .on);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user