a73x

430800c8

Improve glyph positioning

a73x   2026-04-08 11:58

Commit message
Improve glyph positioning

src/font.zig
Old New
@@ -138,6 +138,11 @@ pub const Face = struct {
138 const metrics = self.face.*.size.*.metrics; 138 const metrics = self.face.*.size.*.metrics;
139 return @intCast((metrics.ascender - metrics.descender) >> 6); 139 return @intCast((metrics.ascender - metrics.descender) >> 6);
140 } 140 }
141
142 pub fn baseline(self: *Face) u32 {
143 const metrics = self.face.*.size.*.metrics;
144 return @intCast(metrics.ascender >> 6);
145 }
141 }; 146 };
142 147
143 pub const GlyphUV = struct { 148 pub const GlyphUV = struct {
src/main.zig
Old New
@@ -56,6 +56,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
56 56
57 const cell_w = face.cellWidth(); 57 const cell_w = face.cellWidth();
58 const cell_h = face.cellHeight(); 58 const cell_h = face.cellHeight();
59 const baseline = face.baseline();
59 60
60 // === grid size === 61 // === grid size ===
61 const initial_grid: GridSize = .{ .cols = 80, .rows = 24 }; 62 const initial_grid: GridSize = .{ .cols = 80, .rows = 24 };
@@ -218,6 +219,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
218 col_idx, 219 col_idx,
219 cell_w, 220 cell_w,
220 cell_h, 221 cell_h,
222 baseline,
221 glyph_uv, 223 glyph_uv,
222 bg_uv, 224 bg_uv,
223 colors, 225 colors,
@@ -286,6 +288,7 @@ fn appendCellInstances(
286 col_idx: u32, 288 col_idx: u32,
287 cell_w: u32, 289 cell_w: u32,
288 cell_h: u32, 290 cell_h: u32,
291 baseline: u32,
289 glyph_uv: ?font.GlyphUV, 292 glyph_uv: ?font.GlyphUV,
290 bg_uv: font.GlyphUV, 293 bg_uv: font.GlyphUV,
291 colors: vt.CellColors, 294 colors: vt.CellColors,
@@ -308,7 +311,7 @@ fn appendCellInstances(
308 .glyph_size = .{ @floatFromInt(uv.width), @floatFromInt(uv.height) }, 311 .glyph_size = .{ @floatFromInt(uv.width), @floatFromInt(uv.height) },
309 .glyph_bearing = .{ 312 .glyph_bearing = .{
310 @floatFromInt(uv.bearing_x), 313 @floatFromInt(uv.bearing_x),
311 @as(f32, @floatFromInt(cell_h)) - @as(f32, @floatFromInt(uv.bearing_y)), 314 glyphTopOffset(baseline, uv.bearing_y),
312 }, 315 },
313 .uv_rect = .{ uv.u0, uv.v0, uv.u1, uv.v1 }, 316 .uv_rect = .{ uv.u0, uv.v0, uv.u1, uv.v1 },
314 .fg = colors.fg, 317 .fg = colors.fg,
@@ -316,6 +319,10 @@ fn appendCellInstances(
316 }); 319 });
317 } 320 }
318 321
322 fn glyphTopOffset(baseline: u32, bearing_y: i32) f32 {
323 return @as(f32, @floatFromInt(baseline)) - @as(f32, @floatFromInt(bearing_y));
324 }
325
319 fn encodeKeyboardEvent( 326 fn encodeKeyboardEvent(
320 term: *const vt.Terminal, 327 term: *const vt.Terminal,
321 ev: wayland_client.KeyboardEvent, 328 ev: wayland_client.KeyboardEvent,
@@ -416,6 +423,7 @@ fn runDrawSmokeTest(alloc: std.mem.Allocator) !void {
416 // Cell size from font metrics 423 // Cell size from font metrics
417 const cell_w: f32 = @floatFromInt(face.cellWidth()); 424 const cell_w: f32 = @floatFromInt(face.cellWidth());
418 const cell_h: f32 = @floatFromInt(face.cellHeight()); 425 const cell_h: f32 = @floatFromInt(face.cellHeight());
426 const baseline = face.baseline();
419 std.debug.print("cell size: {d}x{d}\n", .{ cell_w, cell_h }); 427 std.debug.print("cell size: {d}x{d}\n", .{ cell_w, cell_h });
420 428
421 // One Instance: 'M' at cell position (40, 12) — near center of 80x24 grid 429 // One Instance: 'M' at cell position (40, 12) — near center of 80x24 grid
@@ -425,7 +433,7 @@ fn runDrawSmokeTest(alloc: std.mem.Allocator) !void {
425 .glyph_size = .{ @floatFromInt(glyph_uv.width), @floatFromInt(glyph_uv.height) }, 433 .glyph_size = .{ @floatFromInt(glyph_uv.width), @floatFromInt(glyph_uv.height) },
426 .glyph_bearing = .{ 434 .glyph_bearing = .{
427 @floatFromInt(glyph_uv.bearing_x), 435 @floatFromInt(glyph_uv.bearing_x),
428 @as(f32, @floatFromInt(face.cellHeight())) - @as(f32, @floatFromInt(glyph_uv.bearing_y)), 436 glyphTopOffset(baseline, glyph_uv.bearing_y),
429 }, 437 },
430 .uv_rect = .{ glyph_uv.u0, glyph_uv.v0, glyph_uv.u1, glyph_uv.v1 }, 438 .uv_rect = .{ glyph_uv.u0, glyph_uv.v0, glyph_uv.u1, glyph_uv.v1 },
431 .fg = .{ 1.0, 1.0, 1.0, 1.0 }, 439 .fg = .{ 1.0, 1.0, 1.0, 1.0 },
@@ -503,6 +511,7 @@ test "appendCellInstances emits a background quad for colored space" {
503 3, 511 3,
504 8, 512 8,
505 16, 513 16,
514 12,
506 null, 515 null,
507 bg_uv, 516 bg_uv,
508 .{ 517 .{
@@ -552,6 +561,7 @@ test "appendCellInstances emits background before glyph" {
552 1, 561 1,
553 8, 562 8,
554 16, 563 16,
564 12,
555 glyph_uv, 565 glyph_uv,
556 bg_uv, 566 bg_uv,
557 .{ 567 .{
@@ -566,6 +576,11 @@ test "appendCellInstances emits background before glyph" {
566 try std.testing.expectEqualDeep([2]f32{ 7.0, 11.0 }, instances.items[1].glyph_size); 576 try std.testing.expectEqualDeep([2]f32{ 7.0, 11.0 }, instances.items[1].glyph_size);
567 try std.testing.expectEqualDeep([4]f32{ 0.1, 0.2, 0.3, 1.0 }, instances.items[0].fg); 577 try std.testing.expectEqualDeep([4]f32{ 0.1, 0.2, 0.3, 1.0 }, instances.items[0].fg);
568 try std.testing.expectEqualDeep([4]f32{ 0.9, 0.8, 0.7, 1.0 }, instances.items[1].fg); 578 try std.testing.expectEqualDeep([4]f32{ 0.9, 0.8, 0.7, 1.0 }, instances.items[1].fg);
579 try std.testing.expectEqualDeep([2]f32{ 1.0, -1.0 }, instances.items[1].glyph_bearing);
580 }
581
582 test "glyphTopOffset uses baseline rather than cell height" {
583 try std.testing.expectEqual(@as(f32, -3.0), glyphTopOffset(9, 12));
569 } 584 }
570 585
571 fn runRenderSmokeTest(alloc: std.mem.Allocator) !void { 586 fn runRenderSmokeTest(alloc: std.mem.Allocator) !void {