Skip to content

Commit bb576d1

Browse files
renderer: add custom shader cursor uniforms
Based on / supersedes PR ghostty-org#6912, implements discussion ghostty-org#6901 Co-authored-by: Krone Corylus <[email protected]>
1 parent c7a7474 commit bb576d1

File tree

6 files changed

+75
-5
lines changed

6 files changed

+75
-5
lines changed

src/font/sprite/cursor.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ pub fn renderGlyph(
5050
const region = try canvas.writeAtlas(alloc, atlas);
5151

5252
return font.Glyph{
53-
.width = width,
53+
// HACK: Set the width for the bar cursor to just the thickness,
54+
// this is just for the benefit of the custom shader cursor
55+
// uniform code. -- In the future code will be introduced to
56+
// auto-crop the canvas so that this isn't needed.
57+
.width = if (sprite == .cursor_bar) thickness else width,
5458
.height = height,
5559
.offset_x = 0,
5660
.offset_y = @intCast(height),

src/renderer/Metal.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pub const cellpkg = @import("metal/cell.zig");
3333
pub const imagepkg = @import("metal/image.zig");
3434

3535
pub const custom_shader_target: shadertoy.Target = .msl;
36+
// The fragCoord for Metal shaders is +Y = down.
37+
pub const custom_shader_y_is_down = true;
3638

3739
/// Triple buffering.
3840
pub const swap_chain_count = 3;

src/renderer/OpenGL.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub const cellpkg = @import("opengl/cell.zig");
2828
pub const imagepkg = @import("opengl/image.zig");
2929

3030
pub const custom_shader_target: shadertoy.Target = .glsl;
31+
// The fragCoord for OpenGL shaders is +Y = up.
32+
pub const custom_shader_y_is_down = false;
3133

3234
/// Because OpenGL's frame completion is always
3335
/// sync, we have no need for multi-buffering.

src/renderer/generic.zig

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,9 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
675675
.mouse = @splat(0), // not currently updated
676676
.date = @splat(0), // not currently updated
677677
.sample_rate = 0, // N/A, we don't have any audio
678+
.current_cursor = @splat(0),
679+
.previous_cursor = @splat(0),
680+
.cursor_change_time = 0,
678681
},
679682

680683
// Fonts
@@ -1966,17 +1969,70 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
19661969

19671970
self.custom_shader_uniforms.frame += 1;
19681971

1972+
const screen = self.size.screen;
1973+
const padding = self.size.padding;
1974+
const cell = self.size.cell;
1975+
19691976
self.custom_shader_uniforms.resolution = .{
1970-
@floatFromInt(self.size.screen.width),
1971-
@floatFromInt(self.size.screen.height),
1977+
@floatFromInt(screen.width),
1978+
@floatFromInt(screen.height),
19721979
1,
19731980
};
19741981
self.custom_shader_uniforms.channel_resolution[0] = .{
1975-
@floatFromInt(self.size.screen.width),
1976-
@floatFromInt(self.size.screen.height),
1982+
@floatFromInt(screen.width),
1983+
@floatFromInt(screen.height),
19771984
1,
19781985
0,
19791986
};
1987+
1988+
// Update custom cursor uniforms, if we have a cursor.
1989+
if (self.cells.fg_rows.lists[0].items.len > 0) {
1990+
const cursor: shaderpkg.CellText =
1991+
self.cells.fg_rows.lists[0].items[0];
1992+
1993+
const cursor_width: f32 = @floatFromInt(cursor.glyph_size[0]);
1994+
const cursor_height: f32 = @floatFromInt(cursor.glyph_size[1]);
1995+
1996+
var pixel_x: f32 = @floatFromInt(
1997+
cursor.grid_pos[0] * cell.width + padding.left,
1998+
);
1999+
var pixel_y: f32 = @floatFromInt(
2000+
cursor.grid_pos[1] * cell.height + padding.top,
2001+
);
2002+
2003+
pixel_x += @floatFromInt(cursor.bearings[0]);
2004+
pixel_y += @floatFromInt(cursor.bearings[1]);
2005+
2006+
// If +Y is up in our shaders, we need to flip the coordinate.
2007+
if (!GraphicsAPI.custom_shader_y_is_down) {
2008+
pixel_y = @as(f32, @floatFromInt(screen.height)) - pixel_y;
2009+
// We need to add the cursor height because we need the +Y
2010+
// edge for the Y coordinate, and flipping means that it's
2011+
// the -Y edge now.
2012+
pixel_y += cursor_height;
2013+
}
2014+
2015+
const cursor_changed: bool =
2016+
pixel_x != self.custom_shader_uniforms.current_cursor[0] or
2017+
pixel_y != self.custom_shader_uniforms.current_cursor[1] or
2018+
cursor_width != self.custom_shader_uniforms.current_cursor[2] or
2019+
cursor_height != self.custom_shader_uniforms.current_cursor[3];
2020+
2021+
if (cursor_changed) {
2022+
self.custom_shader_uniforms.previous_cursor =
2023+
self.custom_shader_uniforms.current_cursor;
2024+
2025+
self.custom_shader_uniforms.current_cursor = .{
2026+
pixel_x,
2027+
pixel_y,
2028+
cursor_width,
2029+
cursor_height,
2030+
};
2031+
2032+
self.custom_shader_uniforms.cursor_change_time =
2033+
self.custom_shader_uniforms.time;
2034+
}
2035+
}
19802036
}
19812037

19822038
/// Convert the terminal state to GPU cells stored in CPU memory. These

src/renderer/shaders/shadertoy_prefix.glsl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ layout(binding = 1, std140) uniform Globals {
1111
uniform vec4 iMouse;
1212
uniform vec4 iDate;
1313
uniform float iSampleRate;
14+
uniform vec4 iCurrentCursor;
15+
uniform vec4 iPreviousCursor;
16+
uniform float iTimeCursorChange;
1417
};
1518

1619
layout(binding = 0) uniform sampler2D iChannel0;

src/renderer/shadertoy.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ pub const Uniforms = extern struct {
2121
mouse: [4]f32 align(16),
2222
date: [4]f32 align(16),
2323
sample_rate: f32 align(4),
24+
current_cursor: [4]f32 align(16),
25+
previous_cursor: [4]f32 align(16),
26+
cursor_change_time: f32 align(4),
2427
};
2528

2629
/// The target to load shaders for.

0 commit comments

Comments
 (0)