9c669d38
Draw cell backgrounds
a73x 2026-04-08 11:57
diff --git a/build.zig b/build.zig index 97ded6d..1fb9743 100644 --- a/build.zig +++ b/build.zig @@ -182,6 +182,8 @@ pub fn build(b: *std.Build) void { renderer_mod.addImport("vulkan", vulkan_module); renderer_mod.linkSystemLibrary("dl", .{}); exe_mod.addImport("renderer", renderer_mod); main_test_mod.addImport("renderer", renderer_mod); main_test_mod.addImport("font", font_mod); // Test renderer.zig const renderer_test_mod = b.createModule(.{ diff --git a/src/main.zig b/src/main.zig index 02f4d78..591cb85 100644 --- a/src/main.zig +++ b/src/main.zig @@ -194,6 +194,8 @@ fn runTerminal(alloc: std.mem.Allocator) !void { try term.snapshot(); instances.clearRetainingCapacity(); const default_bg = term.backgroundColor(); const bg_uv = atlas.cursorUV(); const term_rows = term.render_state.row_data.items(.cells); var row_idx: u32 = 0; @@ -203,24 +205,24 @@ fn runTerminal(alloc: std.mem.Allocator) !void { var col_idx: u32 = 0; while (col_idx < raw_cells.len) : (col_idx += 1) { const cp = raw_cells[col_idx].codepoint(); if (cp == 0 or cp == ' ') continue; const uv = atlas.getOrInsert(&face, @intCast(cp)) catch continue; const colors = term.cellColors(row_cells.get(col_idx)); try instances.append(alloc, .{ .cell_pos = .{ @floatFromInt(col_idx), @floatFromInt(row_idx) }, .glyph_size = .{ @floatFromInt(uv.width), @floatFromInt(uv.height) }, .glyph_bearing = .{ @floatFromInt(uv.bearing_x), // bearing_y in freetype is from baseline going up; our quad origin is top-left going down // cell_h - bearing_y gives the offset from the top of the cell @as(f32, @floatFromInt(cell_h)) - @as(f32, @floatFromInt(uv.bearing_y)), }, .uv_rect = .{ uv.u0, uv.v0, uv.u1, uv.v1 }, .fg = colors.fg, .bg = colors.bg, }); const glyph_uv = if (cp == 0 or cp == ' ') null else atlas.getOrInsert(&face, @intCast(cp)) catch null; try appendCellInstances( alloc, &instances, row_idx, col_idx, cell_w, cell_h, glyph_uv, bg_uv, colors, default_bg, ); } } @@ -277,6 +279,43 @@ fn gridSizeForWindow(window_w: u32, window_h: u32, cell_w: u32, cell_h: u32) Gri }; } fn appendCellInstances( alloc: std.mem.Allocator, instances: *std.ArrayListUnmanaged(renderer.Instance), row_idx: u32, col_idx: u32, cell_w: u32, cell_h: u32, glyph_uv: ?font.GlyphUV, bg_uv: font.GlyphUV, colors: vt.CellColors, default_bg: [4]f32, ) !void { if (!std.meta.eql(colors.bg, default_bg)) { try instances.append(alloc, .{ .cell_pos = .{ @floatFromInt(col_idx), @floatFromInt(row_idx) }, .glyph_size = .{ @floatFromInt(cell_w), @floatFromInt(cell_h) }, .glyph_bearing = .{ 0, 0 }, .uv_rect = .{ bg_uv.u0, bg_uv.v0, bg_uv.u1, bg_uv.v1 }, .fg = colors.bg, .bg = colors.bg, }); } const uv = glyph_uv orelse return; try instances.append(alloc, .{ .cell_pos = .{ @floatFromInt(col_idx), @floatFromInt(row_idx) }, .glyph_size = .{ @floatFromInt(uv.width), @floatFromInt(uv.height) }, .glyph_bearing = .{ @floatFromInt(uv.bearing_x), @as(f32, @floatFromInt(cell_h)) - @as(f32, @floatFromInt(uv.bearing_y)), }, .uv_rect = .{ uv.u0, uv.v0, uv.u1, uv.v1 }, .fg = colors.fg, .bg = colors.bg, }); } fn encodeKeyboardEvent( term: *const vt.Terminal, ev: wayland_client.KeyboardEvent, @@ -441,6 +480,94 @@ test "gridSizeForWindow clamps to at least one cell" { try std.testing.expectEqual(@as(u16, 1), grid.rows); } test "appendCellInstances emits a background quad for colored space" { var instances: std.ArrayListUnmanaged(renderer.Instance) = .empty; defer instances.deinit(std.testing.allocator); const bg_uv: font.GlyphUV = .{ .u0 = 0.0, .v0 = 0.0, .u1 = 0.1, .v1 = 0.1, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1, }; try appendCellInstances( std.testing.allocator, &instances, 2, 3, 8, 16, null, bg_uv, .{ .fg = .{ 1.0, 1.0, 1.0, 1.0 }, .bg = .{ 0.2, 0.3, 0.4, 1.0 }, }, .{ 0.0, 0.0, 0.0, 1.0 }, ); try std.testing.expectEqual(@as(usize, 1), instances.items.len); try std.testing.expectEqualDeep([4]f32{ 0.2, 0.3, 0.4, 1.0 }, instances.items[0].fg); try std.testing.expectEqualDeep([4]f32{ 0.2, 0.3, 0.4, 1.0 }, instances.items[0].bg); try std.testing.expectEqualDeep([2]f32{ 8.0, 16.0 }, instances.items[0].glyph_size); } test "appendCellInstances emits background before glyph" { var instances: std.ArrayListUnmanaged(renderer.Instance) = .empty; defer instances.deinit(std.testing.allocator); const bg_uv: font.GlyphUV = .{ .u0 = 0.0, .v0 = 0.0, .u1 = 0.1, .v1 = 0.1, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1, }; const glyph_uv: font.GlyphUV = .{ .u0 = 0.2, .v0 = 0.3, .u1 = 0.4, .v1 = 0.5, .width = 7, .height = 11, .bearing_x = 1, .bearing_y = 13, .advance_x = 8, }; try appendCellInstances( std.testing.allocator, &instances, 0, 1, 8, 16, glyph_uv, bg_uv, .{ .fg = .{ 0.9, 0.8, 0.7, 1.0 }, .bg = .{ 0.1, 0.2, 0.3, 1.0 }, }, .{ 0.0, 0.0, 0.0, 1.0 }, ); try std.testing.expectEqual(@as(usize, 2), instances.items.len); try std.testing.expectEqualDeep([2]f32{ 8.0, 16.0 }, instances.items[0].glyph_size); try std.testing.expectEqualDeep([2]f32{ 7.0, 11.0 }, instances.items[1].glyph_size); try std.testing.expectEqualDeep([4]f32{ 0.1, 0.2, 0.3, 1.0 }, instances.items[0].fg); try std.testing.expectEqualDeep([4]f32{ 0.9, 0.8, 0.7, 1.0 }, instances.items[1].fg); } fn runRenderSmokeTest(alloc: std.mem.Allocator) !void { var conn = try wayland_client.Connection.init(); defer conn.deinit(); diff --git a/src/vt.zig b/src/vt.zig index cf18589..e0f67b4 100644 --- a/src/vt.zig +++ b/src/vt.zig @@ -158,6 +158,10 @@ pub const Terminal = struct { try self.render_state.update(self.alloc, &self.inner); } pub fn backgroundColor(self: *const Terminal) [4]f32 { return rgbToFloat4(self.render_state.colors.background); } /// Number of columns in the terminal grid. pub fn cols(self: *const Terminal) u16 { return @intCast(self.render_state.cols);