From 0d30f859bdcb47c84f2381591beae18df94a80af Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 31 Aug 2025 11:43:10 -0600 Subject: [PATCH] renderer: clarify and correct custom shader cursor position math This math was incorrect from the start, the previous fix helped OpenGL but broke positioning under Metal; this commit fixes the math to be correct under both backends and adds comments explaining exactly what's going on. --- src/renderer/generic.zig | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/renderer/generic.zig b/src/renderer/generic.zig index 578ab1779..476aa31ec 100644 --- a/src/renderer/generic.zig +++ b/src/renderer/generic.zig @@ -2225,23 +2225,46 @@ pub fn Renderer(comptime GraphicsAPI: type) type { const cursor_width: f32 = @floatFromInt(cursor.glyph_size[0]); const cursor_height: f32 = @floatFromInt(cursor.glyph_size[1]); + // Left edge of the cell the cursor is in. var pixel_x: f32 = @floatFromInt( cursor.grid_pos[0] * cell.width + padding.left, ); + // Top edge, relative to the top of the + // screen, of the cell the cursor is in. var pixel_y: f32 = @floatFromInt( cursor.grid_pos[1] * cell.height + padding.top, ); - pixel_x += @floatFromInt(cursor.bearings[0]); - // Convert the Y coordinate from bottom-to-top to top-to-bottom. - // Otherwise we end up with glyphs like underline at the top of the cell. - pixel_y += @floatFromInt(@as(i32, @intCast(cell.height)) - cursor.bearings[1]); - - // If +Y is up in our shaders, we need to flip the coordinate. + // If +Y is up in our shaders, we need to flip the coordinate + // so that it's instead the top edge of the cell relative to + // the *bottom* of the screen. if (!GraphicsAPI.custom_shader_y_is_down) { pixel_y = @as(f32, @floatFromInt(screen.height)) - pixel_y; } + // Add the X bearing to get the -X (left) edge of the cursor. + pixel_x += @floatFromInt(cursor.bearings[0]); + + // How we deal with the Y bearing depends on which direction + // is "up", since we want our final `pixel_y` value to be the + // +Y edge of the cursor. + if (GraphicsAPI.custom_shader_y_is_down) { + // As a reminder, the Y bearing is the distance from the + // bottom of the cell to the top of the glyph, so to get + // the +Y edge we need to add the cell height, subtract + // the Y bearing, and add the glyph height to get the +Y + // (bottom) edge of the cursor. + pixel_y += @floatFromInt(cell.height); + pixel_y -= @floatFromInt(cursor.bearings[1]); + pixel_y += @floatFromInt(cursor.glyph_size[1]); + } else { + // If the Y direction is reversed though, we instead want + // the *top* edge of the cursor, which means we just need + // to subtract the cell height and add the Y bearing. + pixel_y -= @floatFromInt(cell.height); + pixel_y += @floatFromInt(cursor.bearings[1]); + } + const new_cursor: [4]f32 = .{ pixel_x, pixel_y,