diff --git a/src/font/sprite.zig b/src/font/sprite.zig index 16c307554..027456b7c 100644 --- a/src/font/sprite.zig +++ b/src/font/sprite.zig @@ -18,6 +18,7 @@ pub const Sprite = enum(u32) { underline_double = start + 1, underline_dotted = start + 2, underline_dashed = start + 3, + underline_curly = start + 4, // Note: we don't currently put the box drawing glyphs in here because // there are a LOT and I'm lazy. What I want to do is spend more time diff --git a/src/font/sprite/Face.zig b/src/font/sprite/Face.zig index 60c356548..b8829e4f5 100644 --- a/src/font/sprite/Face.zig +++ b/src/font/sprite/Face.zig @@ -87,6 +87,7 @@ const Kind = enum { .underline_double, .underline_dotted, .underline_dashed, + .underline_curly, => .underline, }, diff --git a/src/font/sprite/underline.zig b/src/font/sprite/underline.zig index 87c25a9d5..5e1deddef 100644 --- a/src/font/sprite/underline.zig +++ b/src/font/sprite/underline.zig @@ -71,6 +71,7 @@ const Draw = struct { .underline_double => self.drawDouble(canvas), .underline_dotted => self.drawDotted(canvas), .underline_dashed => self.drawDashed(canvas), + .underline_curly => self.drawCurly(canvas), } } @@ -130,6 +131,41 @@ const Draw = struct { }, .on); } } + + /// Draw a curly underline. Thanks to Wez Furlong for providing + /// the basic math structure for this since I was lazy with the + /// geometry. + fn drawCurly(self: Draw, canvas: *font.sprite.Canvas) void { + // This is the lowest that the curl can go. + const y_max = self.height - 1; + + // The full heightof the wave can be from the bottom to the + // underline position. We also calculate our starting y which is + // slightly below our descender since our wave will move about that. + const wave_height = @intToFloat(f64, y_max - self.pos); + const half_height = wave_height / 4; + const y = self.pos + @floatToInt(u32, half_height); + + const x_factor = (2 * std.math.pi) / @intToFloat(f64, self.width); + var x: u32 = 0; + while (x < self.width) : (x += 1) { + const vertical = @floatToInt( + u32, + (-1 * half_height) * @sin(@intToFloat(f64, x) * x_factor) + half_height, + ); + + var row: u32 = 0; + while (row < self.thickness) : (row += 1) { + const y1 = @min(row + y + vertical, y_max); + canvas.rect(.{ + .x = x, + .y = y1, + .width = 1, + .height = 1, + }, .on); + } + } + } }; test "single" { @@ -149,3 +185,21 @@ test "single" { 2, ); } + +test "curly" { + const testing = std.testing; + const alloc = testing.allocator; + + var atlas_greyscale = try Atlas.init(alloc, 512, .greyscale); + defer atlas_greyscale.deinit(alloc); + + _ = try renderGlyph( + alloc, + &atlas_greyscale, + .underline_curly, + 36, + 18, + 9, + 2, + ); +} diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index b83f746cb..fa4877a1a 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -1011,7 +1011,7 @@ pub fn updateCell( .double => .underline_double, .dotted => .underline_dotted, .dashed => .underline_dashed, - else => .underline, + .curly => .underline_curly, }; const underline_glyph = try self.font_group.renderGlyph( diff --git a/src/terminal/sgr.zig b/src/terminal/sgr.zig index a68eed90e..eda08ac8c 100644 --- a/src/terminal/sgr.zig +++ b/src/terminal/sgr.zig @@ -137,6 +137,7 @@ pub const Parser = struct { 0 => return Attribute{ .reset_underline = {} }, 1 => return Attribute{ .underline = .single }, 2 => return Attribute{ .underline = .double }, + 3 => return Attribute{ .underline = .curly }, 4 => return Attribute{ .underline = .dotted }, 5 => return Attribute{ .underline = .dashed },