a73x

52554a17

Render terminal cursor

a73x   2026-04-08 11:44


diff --git a/src/font.zig b/src/font.zig
index ff94d0a..ed0f60d 100644
--- a/src/font.zig
+++ b/src/font.zig
@@ -166,14 +166,15 @@ pub const Atlas = struct {
    pub fn init(alloc: std.mem.Allocator, width: u32, height: u32) !Atlas {
        const pixels = try alloc.alloc(u8, @as(usize, width) * @as(usize, height));
        @memset(pixels, 0);
        pixels[0] = 255;
        return .{
            .alloc = alloc,
            .width = width,
            .height = height,
            .pixels = pixels,
            .cursor_x = 0,
            .cursor_x = 1,
            .cursor_y = 0,
            .row_height = 0,
            .row_height = 1,
            .cache = std.AutoHashMap(u21, GlyphUV).init(alloc),
            .dirty = true,
        };
@@ -184,6 +185,20 @@ pub const Atlas = struct {
        self.cache.deinit();
    }

    pub fn cursorUV(self: *const Atlas) GlyphUV {
        return .{
            .u0 = 0,
            .v0 = 0,
            .u1 = 1.0 / @as(f32, @floatFromInt(self.width)),
            .v1 = 1.0 / @as(f32, @floatFromInt(self.height)),
            .width = 1,
            .height = 1,
            .bearing_x = 0,
            .bearing_y = 0,
            .advance_x = 1,
        };
    }

    pub fn getOrInsert(self: *Atlas, face: *Face, codepoint: u21) !GlyphUV {
        if (self.cache.get(codepoint)) |uv| return uv;

@@ -270,3 +285,13 @@ test "Atlas packs multiple glyphs and returns UVs" {
    try std.testing.expectEqual(uv_m.u0, uv_m2.u0);
    try std.testing.expectEqual(uv_m.v0, uv_m2.v0);
}

test "Atlas reserves a white pixel for cursor rendering" {
    var atlas = try Atlas.init(std.testing.allocator, 16, 16);
    defer atlas.deinit();

    const uv = atlas.cursorUV();
    try std.testing.expectEqual(@as(u8, 255), atlas.pixels[0]);
    try std.testing.expectEqual(@as(f32, 0), uv.u0);
    try std.testing.expectEqual(@as(f32, 0), uv.v0);
}
diff --git a/src/main.zig b/src/main.zig
index 2096ccc..abb172e 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -222,6 +222,31 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
            }
        }

        if (term.render_state.cursor.visible) {
            if (term.render_state.cursor.viewport) |cursor| {
                const cursor_uv = atlas.cursorUV();
                try instances.append(alloc, .{
                    .cell_pos = .{
                        @floatFromInt(cursor.x),
                        @floatFromInt(cursor.y),
                    },
                    .glyph_size = .{
                        @floatFromInt(cell_w),
                        @floatFromInt(cell_h),
                    },
                    .glyph_bearing = .{ 0, 0 },
                    .uv_rect = .{
                        cursor_uv.u0,
                        cursor_uv.v0,
                        cursor_uv.u1,
                        cursor_uv.v1,
                    },
                    .fg = .{ 1.0, 1.0, 1.0, 0.5 },
                    .bg = .{ 0, 0, 0, 0 },
                });
            }
        }

        // Re-upload atlas if new glyphs were added
        if (atlas.dirty) {
            try ctx.uploadAtlas(atlas.pixels);