mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46: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 assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const z2d = @import("z2d");
|
||||||
|
|
||||||
const font = @import("../main.zig");
|
const font = @import("../main.zig");
|
||||||
const Sprite = @import("../sprite.zig").Sprite;
|
const Sprite = @import("../sprite.zig").Sprite;
|
||||||
|
|
||||||
const z2d = @import("z2d");
|
|
||||||
|
|
||||||
const log = std.log.scoped(.box_font);
|
const log = std.log.scoped(.box_font);
|
||||||
|
|
||||||
/// The cell width and height because the boxes are fit perfectly
|
/// 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
|
/// Specification of a quadrants char, which has each of the
|
||||||
/// 4 quadrants of the character cell either filled or empty.
|
/// 4 quadrants of the character cell either filled or empty.
|
||||||
const Quads = struct {
|
const Quads = packed struct(u4) {
|
||||||
tl: bool = false,
|
tl: bool = false,
|
||||||
tr: bool = false,
|
tr: bool = false,
|
||||||
bl: bool = false,
|
bl: bool = false,
|
||||||
@ -1621,10 +1621,10 @@ fn draw_block_shade(
|
|||||||
};
|
};
|
||||||
|
|
||||||
canvas.rect(.{
|
canvas.rect(.{
|
||||||
.x = @floatFromInt(x),
|
.x = x,
|
||||||
.y = @floatFromInt(y),
|
.y = y,
|
||||||
.width = @floatFromInt(w),
|
.width = w,
|
||||||
.height = @floatFromInt(h),
|
.height = h,
|
||||||
}, @as(font.sprite.Color, @enumFromInt(@intFromEnum(shade))));
|
}, @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;
|
const y1 = (self.height * (y + 1)) / y_size;
|
||||||
if ((x + y) % 2 == parity) {
|
if ((x + y) % 2 == parity) {
|
||||||
canvas.rect(.{
|
canvas.rect(.{
|
||||||
.x = @floatFromInt(x0),
|
.x = @intCast(x0),
|
||||||
.y = @floatFromInt(y0),
|
.y = @intCast(y0),
|
||||||
.width = @floatFromInt(x1 -| x0),
|
.width = @intCast(x1 -| x0),
|
||||||
.height = @floatFromInt(y1 -| y0),
|
.height = @intCast(y1 -| y0),
|
||||||
}, .on);
|
}, .on);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1841,8 +1841,8 @@ fn draw_circle(
|
|||||||
fn draw_line(
|
fn draw_line(
|
||||||
self: Box,
|
self: Box,
|
||||||
canvas: *font.sprite.Canvas,
|
canvas: *font.sprite.Canvas,
|
||||||
p0: font.sprite.Point,
|
p0: font.sprite.Point(f64),
|
||||||
p1: font.sprite.Point,
|
p1: font.sprite.Point(f64),
|
||||||
comptime thickness: Thickness,
|
comptime thickness: Thickness,
|
||||||
) !void {
|
) !void {
|
||||||
canvas.line(
|
canvas.line(
|
||||||
@ -1853,11 +1853,11 @@ fn draw_line(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_shade(self: Box, canvas: *font.sprite.Canvas, v: u16) void {
|
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 },
|
.p0 = .{ .x = 0, .y = 0 },
|
||||||
.p1 = .{
|
.p1 = .{
|
||||||
.x = @floatFromInt(self.width),
|
.x = self.width,
|
||||||
.y = @floatFromInt(self.height),
|
.y = self.height,
|
||||||
},
|
},
|
||||||
}).rect(), @as(font.sprite.Color, @enumFromInt(v)));
|
}).rect(), @as(font.sprite.Color, @enumFromInt(v)));
|
||||||
}
|
}
|
||||||
@ -2395,12 +2395,12 @@ fn vline(
|
|||||||
x: u32,
|
x: u32,
|
||||||
thickness_px: u32,
|
thickness_px: u32,
|
||||||
) void {
|
) void {
|
||||||
canvas.rect((font.sprite.Box{ .p0 = .{
|
canvas.rect((font.sprite.Box(u32){ .p0 = .{
|
||||||
.x = @floatFromInt(@min(@max(x, 0), self.width)),
|
.x = @min(@max(x, 0), self.width),
|
||||||
.y = @floatFromInt(@min(@max(y1, 0), self.height)),
|
.y = @min(@max(y1, 0), self.height),
|
||||||
}, .p1 = .{
|
}, .p1 = .{
|
||||||
.x = @floatFromInt(@min(@max(x + thickness_px, 0), self.width)),
|
.x = @min(@max(x + thickness_px, 0), self.width),
|
||||||
.y = @floatFromInt(@min(@max(y2, 0), self.height)),
|
.y = @min(@max(y2, 0), self.height),
|
||||||
} }).rect(), .on);
|
} }).rect(), .on);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2412,12 +2412,12 @@ fn hline(
|
|||||||
y: u32,
|
y: u32,
|
||||||
thickness_px: u32,
|
thickness_px: u32,
|
||||||
) void {
|
) void {
|
||||||
canvas.rect((font.sprite.Box{ .p0 = .{
|
canvas.rect((font.sprite.Box(u32){ .p0 = .{
|
||||||
.x = @floatFromInt(@min(@max(x1, 0), self.width)),
|
.x = @min(@max(x1, 0), self.width),
|
||||||
.y = @floatFromInt(@min(@max(y, 0), self.height)),
|
.y = @min(@max(y, 0), self.height),
|
||||||
}, .p1 = .{
|
}, .p1 = .{
|
||||||
.x = @floatFromInt(@min(@max(x2, 0), self.width)),
|
.x = @min(@max(x2, 0), self.width),
|
||||||
.y = @floatFromInt(@min(@max(y + thickness_px, 0), self.height)),
|
.y = @min(@max(y + thickness_px, 0), self.height),
|
||||||
} }).rect(), .on);
|
} }).rect(), .on);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2429,12 +2429,12 @@ fn rect(
|
|||||||
x2: u32,
|
x2: u32,
|
||||||
y2: u32,
|
y2: u32,
|
||||||
) void {
|
) void {
|
||||||
canvas.rect((font.sprite.Box{ .p0 = .{
|
canvas.rect((font.sprite.Box(u32){ .p0 = .{
|
||||||
.x = @floatFromInt(@min(@max(x1, 0), self.width)),
|
.x = @min(@max(x1, 0), self.width),
|
||||||
.y = @floatFromInt(@min(@max(y1, 0), self.height)),
|
.y = @min(@max(y1, 0), self.height),
|
||||||
}, .p1 = .{
|
}, .p1 = .{
|
||||||
.x = @floatFromInt(@min(@max(x2, 0), self.width)),
|
.x = @min(@max(x2, 0), self.width),
|
||||||
.y = @floatFromInt(@min(@max(y2, 0), self.height)),
|
.y = @min(@max(y2, 0), self.height),
|
||||||
} }).rect(), .on);
|
} }).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)));
|
const average = @as(u8, @intCast(@min(total / (supersample * supersample), 0xFF)));
|
||||||
canvas.rect(
|
canvas.rect(
|
||||||
.{
|
.{
|
||||||
.x = @floatFromInt(c),
|
.x = @intCast(c),
|
||||||
.y = @floatFromInt(r),
|
.y = @intCast(r),
|
||||||
.width = 1,
|
.width = 1,
|
||||||
.height = 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 {
|
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 = .{
|
.p0 = .{
|
||||||
.x = 0,
|
.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 = .{
|
.p0 = .{
|
||||||
.x = @floatFromInt(self.width - self.width / 3),
|
.x = @floatFromInt(self.width - self.width / 3),
|
||||||
|
@ -6,53 +6,66 @@ const Allocator = std.mem.Allocator;
|
|||||||
const z2d = @import("z2d");
|
const z2d = @import("z2d");
|
||||||
const font = @import("../main.zig");
|
const font = @import("../main.zig");
|
||||||
|
|
||||||
pub const Point = struct {
|
pub fn Point(comptime T: type) type {
|
||||||
x: f64,
|
return struct {
|
||||||
y: f64,
|
x: T,
|
||||||
};
|
y: T,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Line = struct {
|
pub fn Line(comptime T: type) type {
|
||||||
p0: Point,
|
return struct {
|
||||||
p1: Point,
|
p0: Point(T),
|
||||||
};
|
p1: Point(T),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Box = struct {
|
pub fn Box(comptime T: type) type {
|
||||||
p0: Point,
|
return struct {
|
||||||
p1: Point,
|
p0: Point(T),
|
||||||
|
p1: Point(T),
|
||||||
|
|
||||||
pub fn rect(self: Box) Rect {
|
pub fn rect(self: Box(T)) Rect(T) {
|
||||||
const tl_x = @min(self.p0.x, self.p1.x);
|
const tl_x = @min(self.p0.x, self.p1.x);
|
||||||
const tl_y = @min(self.p0.y, self.p1.y);
|
const tl_y = @min(self.p0.y, self.p1.y);
|
||||||
const br_x = @max(self.p0.x, self.p1.x);
|
const br_x = @max(self.p0.x, self.p1.x);
|
||||||
const br_y = @max(self.p0.y, self.p1.y);
|
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 const Rect = struct {
|
return .{
|
||||||
x: f64,
|
.x = tl_x,
|
||||||
y: f64,
|
.y = tl_y,
|
||||||
width: f64,
|
.width = br_x - tl_x,
|
||||||
height: f64,
|
.height = br_y - tl_y,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Triangle = struct {
|
pub fn Rect(comptime T: type) type {
|
||||||
p0: Point,
|
return struct {
|
||||||
p1: Point,
|
x: T,
|
||||||
p2: Point,
|
y: T,
|
||||||
};
|
width: T,
|
||||||
|
height: T,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Quad = struct {
|
pub fn Triangle(comptime T: type) type {
|
||||||
p0: Point,
|
return struct {
|
||||||
p1: Point,
|
p0: Point(T),
|
||||||
p2: Point,
|
p1: Point(T),
|
||||||
p3: Point,
|
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".
|
/// We only use alpha-channel so a pixel can only be "on" or "off".
|
||||||
pub const Color = enum(u8) {
|
pub const Color = enum(u8) {
|
||||||
@ -137,19 +150,26 @@ pub const Canvas = struct {
|
|||||||
@intCast(x),
|
@intCast(x),
|
||||||
@intCast(y),
|
@intCast(y),
|
||||||
.{ .alpha8 = .{ .a = @intFromEnum(color) } },
|
.{ .alpha8 = .{ .a = @intFromEnum(color) } },
|
||||||
) catch {
|
) catch |e| switch (e) {
|
||||||
// If we try to set out of range this will fail.
|
error.OutOfRange => {
|
||||||
// We just silently ignore that.
|
// 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
|
/// Draw and fill a rectangle. This is the main primitive for drawing
|
||||||
/// lines as well (which are just generally skinny rectangles...)
|
/// lines as well (which are just generally skinny rectangles...)
|
||||||
pub fn rect(self: *Canvas, v: Rect, color: Color) void {
|
pub fn rect(self: *Canvas, v: Rect(u32), color: Color) void {
|
||||||
const x0: usize = @intFromFloat(v.x);
|
const x0 = v.x;
|
||||||
const x1: usize = @intFromFloat(v.x + v.width);
|
const x1 = v.x + v.width;
|
||||||
const y0: usize = @intFromFloat(v.y);
|
const y0 = v.y;
|
||||||
const y1: usize = @intFromFloat(v.y + v.height);
|
const y1 = v.y + v.height;
|
||||||
|
|
||||||
for (y0..y1) |y| {
|
for (y0..y1) |y| {
|
||||||
for (x0..x1) |x| {
|
for (x0..x1) |x| {
|
||||||
@ -163,7 +183,7 @@ pub const Canvas = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw and fill a quad.
|
/// 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 = .{
|
var ctx: z2d.Context = .{
|
||||||
.surface = self.sfc,
|
.surface = self.sfc,
|
||||||
.pattern = .{
|
.pattern = .{
|
||||||
@ -186,7 +206,7 @@ pub const Canvas = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw and fill a triangle.
|
/// 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 = .{
|
var ctx: z2d.Context = .{
|
||||||
.surface = self.sfc,
|
.surface = self.sfc,
|
||||||
.pattern = .{
|
.pattern = .{
|
||||||
@ -208,7 +228,7 @@ pub const Canvas = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Stroke a line.
|
/// 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 = .{
|
var ctx: z2d.Context = .{
|
||||||
.surface = self.sfc,
|
.surface = self.sfc,
|
||||||
.pattern = .{
|
.pattern = .{
|
||||||
|
@ -70,8 +70,8 @@ fn drawSingle(alloc: Allocator, width: u32, thickness: u32) !CanvasAndOffset {
|
|||||||
canvas.rect(.{
|
canvas.rect(.{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
.width = @floatFromInt(width),
|
.width = width,
|
||||||
.height = @floatFromInt(thickness),
|
.height = thickness,
|
||||||
}, .on);
|
}, .on);
|
||||||
|
|
||||||
const offset_y: i32 = 0;
|
const offset_y: i32 = 0;
|
||||||
@ -91,15 +91,15 @@ fn drawDouble(alloc: Allocator, width: u32, thickness: u32) !CanvasAndOffset {
|
|||||||
canvas.rect(.{
|
canvas.rect(.{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
.width = @floatFromInt(width),
|
.width = width,
|
||||||
.height = @floatFromInt(thickness),
|
.height = thickness,
|
||||||
}, .on);
|
}, .on);
|
||||||
|
|
||||||
canvas.rect(.{
|
canvas.rect(.{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = @floatFromInt(thickness * 2),
|
.y = thickness * 2,
|
||||||
.width = @floatFromInt(width),
|
.width = width,
|
||||||
.height = @floatFromInt(thickness),
|
.height = thickness,
|
||||||
}, .on);
|
}, .on);
|
||||||
|
|
||||||
const offset_y: i32 = -@as(i32, @intCast(thickness));
|
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 x = @min(i * (dot_width + gap_width), width - 1);
|
||||||
const rect_width = @min(width - x, dot_width);
|
const rect_width = @min(width - x, dot_width);
|
||||||
canvas.rect(.{
|
canvas.rect(.{
|
||||||
.x = @floatFromInt(x),
|
.x = @intCast(x),
|
||||||
.y = 0,
|
.y = 0,
|
||||||
.width = @floatFromInt(rect_width),
|
.width = rect_width,
|
||||||
.height = @floatFromInt(thickness),
|
.height = thickness,
|
||||||
}, .on);
|
}, .on);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,10 +146,10 @@ fn drawDashed(alloc: Allocator, width: u32, thickness: u32) !CanvasAndOffset {
|
|||||||
const x = @min(i * dash_width, width - 1);
|
const x = @min(i * dash_width, width - 1);
|
||||||
const rect_width = @min(width - x, dash_width);
|
const rect_width = @min(width - x, dash_width);
|
||||||
canvas.rect(.{
|
canvas.rect(.{
|
||||||
.x = @floatFromInt(x),
|
.x = @intCast(x),
|
||||||
.y = 0,
|
.y = 0,
|
||||||
.width = @floatFromInt(rect_width),
|
.width = rect_width,
|
||||||
.height = @floatFromInt(thickness),
|
.height = thickness,
|
||||||
}, .on);
|
}, .on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user