73e2fd1c
cursor: extract cursorInstance helper with DECSCUSR shape dispatch
a73x 2026-04-19 06:57
Commit message
build.zig
| Old | New | ||
|---|---|---|---|
| @@ -328,7 +328,9 @@ pub fn build(b: *std.Build) void { | |||
| 328 | }); | 328 | }); |
| 329 | vk_sync_mod.addImport("vulkan", vulkan_module); | 329 | vk_sync_mod.addImport("vulkan", vulkan_module); |
| 330 | renderer_mod.addImport("vk_sync", vk_sync_mod); | 330 | renderer_mod.addImport("vk_sync", vk_sync_mod); |
| 331 | renderer_mod.addImport("font", font_mod); | ||
| 331 | renderer_test_mod.addImport("vk_sync", vk_sync_mod); | 332 | renderer_test_mod.addImport("vk_sync", vk_sync_mod); |
| 333 | renderer_test_mod.addImport("font", font_mod); | ||
| 332 | exe_mod.addImport("vk_sync", vk_sync_mod); | 334 | exe_mod.addImport("vk_sync", vk_sync_mod); |
| 333 | main_test_mod.addImport("vk_sync", vk_sync_mod); | 335 | main_test_mod.addImport("vk_sync", vk_sync_mod); |
| 334 | 336 | ||
src/main.zig
| Old | New | ||
|---|---|---|---|
| @@ -554,26 +554,23 @@ fn runTerminal(alloc: std.mem.Allocator) !void { | |||
| 554 | var cursor_instances_buf: [1]renderer.Instance = undefined; | 554 | var cursor_instances_buf: [1]renderer.Instance = undefined; |
| 555 | var cursor_instances: []const renderer.Instance = &.{}; | 555 | var cursor_instances: []const renderer.Instance = &.{}; |
| 556 | if (term.render_state.cursor.viewport) |cursor| { | 556 | if (term.render_state.cursor.viewport) |cursor| { |
| 557 | const cursor_uv = atlas.cursorUV(); | 557 | const shape: renderer.CursorShape = switch (term.render_state.cursor.visual_style) { |
| 558 | cursor_instances_buf[0] = .{ | 558 | .block, .block_hollow => .block, |
| 559 | .cell_pos = .{ | 559 | .underline => .underline, |
| 560 | @floatFromInt(cursor.x), | 560 | .bar => .bar, |
| 561 | @floatFromInt(cursor.y), | 561 | }; |
| 562 | }, | 562 | var inst = renderer.cursorInstance( |
| 563 | .glyph_size = .{ | 563 | shape, |
| 564 | @floatFromInt(cell_w), | 564 | cell_w, |
| 565 | @floatFromInt(cell_h), | 565 | cell_h, |
| 566 | }, | 566 | @as(u32, @intCast(geom.buffer_scale)), |
| 567 | .glyph_bearing = .{ 0, 0 }, | 567 | atlas.cursorUV(), |
| 568 | .uv_rect = .{ | 568 | ); |
| 569 | cursor_uv.u0, | 569 | inst.cell_pos = .{ |
| 570 | cursor_uv.v0, | 570 | @floatFromInt(cursor.x), |
| 571 | cursor_uv.u1, | 571 | @floatFromInt(cursor.y), |
| 572 | cursor_uv.v1, | ||
| 573 | }, | ||
| 574 | .fg = .{ 1.0, 1.0, 1.0, 0.5 }, | ||
| 575 | .bg = .{ 0, 0, 0, 0 }, | ||
| 576 | }; | 572 | }; |
| 573 | cursor_instances_buf[0] = inst; | ||
| 577 | cursor_instances = cursor_instances_buf[0..1]; | 574 | cursor_instances = cursor_instances_buf[0..1]; |
| 578 | } | 575 | } |
| 579 | const previous_total_instance_count = render_cache.total_instance_count; | 576 | const previous_total_instance_count = render_cache.total_instance_count; |
src/renderer.zig
| Old | New | ||
|---|---|---|---|
| @@ -2,6 +2,8 @@ const std = @import("std"); | |||
| 2 | const vk = @import("vulkan"); | 2 | const vk = @import("vulkan"); |
| 3 | const vk_sync = @import("vk_sync"); | 3 | const vk_sync = @import("vk_sync"); |
| 4 | 4 | ||
| 5 | const GlyphUV = @import("font").GlyphUV; | ||
| 6 | |||
| 5 | const dl = @cImport({ | 7 | const dl = @cImport({ |
| 6 | @cInclude("dlfcn.h"); | 8 | @cInclude("dlfcn.h"); |
| 7 | }); | 9 | }); |
| @@ -2192,3 +2194,79 @@ test "uploadInstanceRange contract reports invalid ranges explicitly" { | |||
| 2192 | const action = planUploadInstanceRangeAction(std.math.maxInt(u32), std.math.maxInt(u32), 1); | 2194 | const action = planUploadInstanceRangeAction(std.math.maxInt(u32), std.math.maxInt(u32), 1); |
| 2193 | try std.testing.expectEqual(InstanceRangeUploadAction.invalid_range, action); | 2195 | try std.testing.expectEqual(InstanceRangeUploadAction.invalid_range, action); |
| 2194 | } | 2196 | } |
| 2197 | |||
| 2198 | // --- cursor instance (pure, unit-tested) --- | ||
| 2199 | |||
| 2200 | pub const CursorShape = enum { block, underline, bar }; | ||
| 2201 | |||
| 2202 | pub fn cursorInstance( | ||
| 2203 | shape: CursorShape, | ||
| 2204 | cell_w: u32, | ||
| 2205 | cell_h: u32, | ||
| 2206 | buffer_scale: u32, | ||
| 2207 | uv: GlyphUV, | ||
| 2208 | ) Instance { | ||
| 2209 | const cell_w_f: f32 = @floatFromInt(cell_w); | ||
| 2210 | const cell_h_f: f32 = @floatFromInt(cell_h); | ||
| 2211 | const line_w_f: f32 = @floatFromInt(2 * buffer_scale); | ||
| 2212 | |||
| 2213 | const size_xy: [2]f32 = switch (shape) { | ||
| 2214 | .block => .{ cell_w_f, cell_h_f }, | ||
| 2215 | .underline => .{ cell_w_f, line_w_f }, | ||
| 2216 | .bar => .{ line_w_f, cell_h_f }, | ||
| 2217 | }; | ||
| 2218 | const bearing_xy: [2]f32 = switch (shape) { | ||
| 2219 | .block, .bar => .{ 0, 0 }, | ||
| 2220 | .underline => .{ 0, cell_h_f - line_w_f }, | ||
| 2221 | }; | ||
| 2222 | |||
| 2223 | return .{ | ||
| 2224 | .cell_pos = .{ 0, 0 }, // caller overwrites with actual grid position | ||
| 2225 | .glyph_size = size_xy, | ||
| 2226 | .glyph_bearing = bearing_xy, | ||
| 2227 | .uv_rect = .{ uv.u0, uv.v0, uv.u1, uv.v1 }, | ||
| 2228 | .fg = .{ 1.0, 1.0, 1.0, 0.5 }, | ||
| 2229 | .bg = .{ 0, 0, 0, 0 }, | ||
| 2230 | }; | ||
| 2231 | } | ||
| 2232 | |||
| 2233 | test "cursorInstance: block fills the whole cell at scale 1" { | ||
| 2234 | const uv: GlyphUV = .{ .u0 = 0, .v0 = 0, .u1 = 0.01, .v1 = 0.01, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1 }; | ||
| 2235 | const inst = cursorInstance(.block, 10, 20, 1, uv); | ||
| 2236 | try std.testing.expectEqualSlices(f32, &[_]f32{ 10.0, 20.0 }, &inst.glyph_size); | ||
| 2237 | try std.testing.expectEqualSlices(f32, &[_]f32{ 0.0, 0.0 }, &inst.glyph_bearing); | ||
| 2238 | } | ||
| 2239 | |||
| 2240 | test "cursorInstance: underline is a 2px bar at the cell bottom (scale 1)" { | ||
| 2241 | const uv: GlyphUV = .{ .u0 = 0, .v0 = 0, .u1 = 0.01, .v1 = 0.01, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1 }; | ||
| 2242 | const inst = cursorInstance(.underline, 10, 20, 1, uv); | ||
| 2243 | try std.testing.expectEqualSlices(f32, &[_]f32{ 10.0, 2.0 }, &inst.glyph_size); | ||
| 2244 | try std.testing.expectEqualSlices(f32, &[_]f32{ 0.0, 18.0 }, &inst.glyph_bearing); | ||
| 2245 | } | ||
| 2246 | |||
| 2247 | test "cursorInstance: bar is a 2px column at cell left (scale 1)" { | ||
| 2248 | const uv: GlyphUV = .{ .u0 = 0, .v0 = 0, .u1 = 0.01, .v1 = 0.01, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1 }; | ||
| 2249 | const inst = cursorInstance(.bar, 10, 20, 1, uv); | ||
| 2250 | try std.testing.expectEqualSlices(f32, &[_]f32{ 2.0, 20.0 }, &inst.glyph_size); | ||
| 2251 | try std.testing.expectEqualSlices(f32, &[_]f32{ 0.0, 0.0 }, &inst.glyph_bearing); | ||
| 2252 | } | ||
| 2253 | |||
| 2254 | test "cursorInstance: underline line width scales with buffer_scale" { | ||
| 2255 | const uv: GlyphUV = .{ .u0 = 0, .v0 = 0, .u1 = 0.01, .v1 = 0.01, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1 }; | ||
| 2256 | const inst = cursorInstance(.underline, 20, 40, 2, uv); | ||
| 2257 | try std.testing.expectEqualSlices(f32, &[_]f32{ 20.0, 4.0 }, &inst.glyph_size); | ||
| 2258 | try std.testing.expectEqualSlices(f32, &[_]f32{ 0.0, 36.0 }, &inst.glyph_bearing); | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | test "cursorInstance: bar line width scales with buffer_scale" { | ||
| 2262 | const uv: GlyphUV = .{ .u0 = 0, .v0 = 0, .u1 = 0.01, .v1 = 0.01, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1 }; | ||
| 2263 | const inst = cursorInstance(.bar, 20, 40, 2, uv); | ||
| 2264 | try std.testing.expectEqualSlices(f32, &[_]f32{ 4.0, 40.0 }, &inst.glyph_size); | ||
| 2265 | try std.testing.expectEqualSlices(f32, &[_]f32{ 0.0, 0.0 }, &inst.glyph_bearing); | ||
| 2266 | } | ||
| 2267 | |||
| 2268 | test "cursorInstance: uv_rect comes from the provided UV" { | ||
| 2269 | const uv: GlyphUV = .{ .u0 = 0.1, .v0 = 0.2, .u1 = 0.3, .v1 = 0.4, .width = 1, .height = 1, .bearing_x = 0, .bearing_y = 0, .advance_x = 1 }; | ||
| 2270 | const inst = cursorInstance(.block, 10, 20, 1, uv); | ||
| 2271 | try std.testing.expectEqualSlices(f32, &[_]f32{ 0.1, 0.2, 0.3, 0.4 }, &inst.uv_rect); | ||
| 2272 | } | ||