Skip to content

Commit a8ccfe3

Browse files
committed
renderer: added cursor style and visibility uniforms
Specifically: iCurrentCursorStyle iPreviousCursorStyle iCurrentCursorVisible iPreviousCursorVisible Visibility calculated and updated independently from the typical cursor unifrom updates to preserve cursor style even when not in the viewport or set to be hidden
1 parent 049b882 commit a8ccfe3

File tree

4 files changed

+127
-68
lines changed

4 files changed

+127
-68
lines changed

src/config/Config.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2652,6 +2652,22 @@ keybind: Keybinds = .{},
26522652
///
26532653
/// * `vec4 iPreviousCursorColor` - Color of the previous terminal cursor.
26542654
///
2655+
/// * `vec4 iCurrentCursorStyle` - Style of the terminal cursor
2656+
///
2657+
/// Macros simplified use are defined for the various cursor styles:
2658+
///
2659+
/// - `CURSORSTYLE_BLOCK` or `0`
2660+
/// - `CURSORSTYLE_BLOCK_HOLLOW` or `1`
2661+
/// - `CURSORSTYLE_BAR` or `2`
2662+
/// - `CURSORSTYLE_UNDERLINE` or `3`
2663+
/// - `CURSORSTYLE_LOCK` or `4`
2664+
///
2665+
/// * `vec4 iPreviousCursorStyle` - Style of the previous terminal cursor
2666+
///
2667+
/// * `vec4 iCurrentCursorVisible` - Visibility of the terminal cursor.
2668+
///
2669+
/// * `vec4 iPreviousCursorVisible` - Visibility of the previous terminal cursor.
2670+
///
26552671
/// * `float iTimeCursorChange` - Timestamp of terminal cursor change.
26562672
///
26572673
/// When the terminal cursor changes position or color, this is set to

src/renderer/generic.zig

Lines changed: 97 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,10 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
740740
.previous_cursor = @splat(0),
741741
.current_cursor_color = @splat(0),
742742
.previous_cursor_color = @splat(0),
743+
.current_cursor_style = 0,
744+
.previous_cursor_style = 0,
745+
.current_cursor_visible = 0,
746+
.previous_cursor_visible = 0,
743747
.cursor_change_time = 0,
744748
},
745749
.bg_image_buffer = undefined,
@@ -2239,6 +2243,8 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
22392243
// We only need to do this if we have custom shaders.
22402244
if (!self.has_custom_shaders) return;
22412245

2246+
const uniforms = &self.custom_shader_uniforms;
2247+
22422248
const now = try std.time.Instant.now();
22432249
defer self.last_frame_time = now;
22442250
const first_frame_time = self.first_frame_time orelse t: {
@@ -2248,99 +2254,122 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
22482254
const last_frame_time = self.last_frame_time orelse now;
22492255

22502256
const since_ns: f32 = @floatFromInt(now.since(first_frame_time));
2251-
self.custom_shader_uniforms.time = since_ns / std.time.ns_per_s;
2257+
uniforms.time = since_ns / std.time.ns_per_s;
22522258

22532259
const delta_ns: f32 = @floatFromInt(now.since(last_frame_time));
2254-
self.custom_shader_uniforms.time_delta = delta_ns / std.time.ns_per_s;
2260+
uniforms.time_delta = delta_ns / std.time.ns_per_s;
22552261

2256-
self.custom_shader_uniforms.frame += 1;
2262+
uniforms.frame += 1;
22572263

22582264
const screen = self.size.screen;
22592265
const padding = self.size.padding;
22602266
const cell = self.size.cell;
22612267

2262-
self.custom_shader_uniforms.resolution = .{
2268+
uniforms.resolution = .{
22632269
@floatFromInt(screen.width),
22642270
@floatFromInt(screen.height),
22652271
1,
22662272
};
2267-
self.custom_shader_uniforms.channel_resolution[0] = .{
2273+
uniforms.channel_resolution[0] = .{
22682274
@floatFromInt(screen.width),
22692275
@floatFromInt(screen.height),
22702276
1,
22712277
0,
22722278
};
22732279

2274-
// Update custom cursor uniforms, if we have a cursor.
2275-
if (self.cells.getCursorGlyph()) |cursor| {
2276-
const cursor_width: f32 = @floatFromInt(cursor.glyph_size[0]);
2277-
const cursor_height: f32 = @floatFromInt(cursor.glyph_size[1]);
2280+
// Always check the visibility
2281+
const current_cursor_visible: bool = self.terminal_state.cursor.visible;
22782282

2279-
// Left edge of the cell the cursor is in.
2280-
var pixel_x: f32 = @floatFromInt(
2281-
cursor.grid_pos[0] * cell.width + padding.left,
2282-
);
2283-
// Top edge, relative to the top of the
2284-
// screen, of the cell the cursor is in.
2285-
var pixel_y: f32 = @floatFromInt(
2286-
cursor.grid_pos[1] * cell.height + padding.top,
2287-
);
2283+
// Always update the visibility.
2284+
// If we check for a change then the current and previous uniforms
2285+
// will always be the opposite of one another
2286+
//
2287+
// This allows for cases where the use might want to know the exact frame
2288+
// where the visibility changes
2289+
uniforms.previous_cursor_visible = uniforms.current_cursor_visible;
2290+
uniforms.current_cursor_visible = @intFromBool(current_cursor_visible);
22882291

2289-
// If +Y is up in our shaders, we need to flip the coordinate
2290-
// so that it's instead the top edge of the cell relative to
2291-
// the *bottom* of the screen.
2292-
if (!GraphicsAPI.custom_shader_y_is_down) {
2293-
pixel_y = @as(f32, @floatFromInt(screen.height)) - pixel_y;
2294-
}
2292+
if (current_cursor_visible) {
2293+
// If we have a cursor in the fg cells.
2294+
//
2295+
// * Similar check to see if the cursor does in fact exist
2296+
if (self.cells.getCursorGlyph()) |cursor| {
2297+
const cursor_width: f32 = @floatFromInt(cursor.glyph_size[0]);
2298+
const cursor_height: f32 = @floatFromInt(cursor.glyph_size[1]);
2299+
2300+
// Left edge of the cell the cursor is in.
2301+
var pixel_x: f32 = @floatFromInt(
2302+
cursor.grid_pos[0] * cell.width + padding.left,
2303+
);
2304+
// Top edge, relative to the top of the
2305+
// screen, of the cell the cursor is in.
2306+
var pixel_y: f32 = @floatFromInt(
2307+
cursor.grid_pos[1] * cell.height + padding.top,
2308+
);
22952309

2296-
// Add the X bearing to get the -X (left) edge of the cursor.
2297-
pixel_x += @floatFromInt(cursor.bearings[0]);
2298-
2299-
// How we deal with the Y bearing depends on which direction
2300-
// is "up", since we want our final `pixel_y` value to be the
2301-
// +Y edge of the cursor.
2302-
if (GraphicsAPI.custom_shader_y_is_down) {
2303-
// As a reminder, the Y bearing is the distance from the
2304-
// bottom of the cell to the top of the glyph, so to get
2305-
// the +Y edge we need to add the cell height, subtract
2306-
// the Y bearing, and add the glyph height to get the +Y
2307-
// (bottom) edge of the cursor.
2308-
pixel_y += @floatFromInt(cell.height);
2309-
pixel_y -= @floatFromInt(cursor.bearings[1]);
2310-
pixel_y += @floatFromInt(cursor.glyph_size[1]);
2311-
} else {
2312-
// If the Y direction is reversed though, we instead want
2313-
// the *top* edge of the cursor, which means we just need
2314-
// to subtract the cell height and add the Y bearing.
2315-
pixel_y -= @floatFromInt(cell.height);
2316-
pixel_y += @floatFromInt(cursor.bearings[1]);
2317-
}
2310+
// If +Y is up in our shaders, we need to flip the coordinate
2311+
// so that it's instead the top edge of the cell relative to
2312+
// the *bottom* of the screen.
2313+
if (!GraphicsAPI.custom_shader_y_is_down) {
2314+
pixel_y = @as(f32, @floatFromInt(screen.height)) - pixel_y;
2315+
}
23182316

2319-
const new_cursor: [4]f32 = .{
2320-
pixel_x,
2321-
pixel_y,
2322-
cursor_width,
2323-
cursor_height,
2324-
};
2325-
const cursor_color: [4]f32 = .{
2326-
@as(f32, @floatFromInt(cursor.color[0])) / 255.0,
2327-
@as(f32, @floatFromInt(cursor.color[1])) / 255.0,
2328-
@as(f32, @floatFromInt(cursor.color[2])) / 255.0,
2329-
@as(f32, @floatFromInt(cursor.color[3])) / 255.0,
2330-
};
2317+
// Add the X bearing to get the -X (left) edge of the cursor.
2318+
pixel_x += @floatFromInt(cursor.bearings[0]);
2319+
2320+
// How we deal with the Y bearing depends on which direction
2321+
// is "up", since we want our final `pixel_y` value to be the
2322+
// +Y edge of the cursor.
2323+
if (GraphicsAPI.custom_shader_y_is_down) {
2324+
// As a reminder, the Y bearing is the distance from the
2325+
// bottom of the cell to the top of the glyph, so to get
2326+
// the +Y edge we need to add the cell height, subtract
2327+
// the Y bearing, and add the glyph height to get the +Y
2328+
// (bottom) edge of the cursor.
2329+
pixel_y += @floatFromInt(cell.height);
2330+
pixel_y -= @floatFromInt(cursor.bearings[1]);
2331+
pixel_y += @floatFromInt(cursor.glyph_size[1]);
2332+
} else {
2333+
// If the Y direction is reversed though, we instead want
2334+
// the *top* edge of the cursor, which means we just need
2335+
// to subtract the cell height and add the Y bearing.
2336+
pixel_y -= @floatFromInt(cell.height);
2337+
pixel_y += @floatFromInt(cursor.bearings[1]);
2338+
}
2339+
2340+
const new_cursor: [4]f32 = .{
2341+
pixel_x,
2342+
pixel_y,
2343+
cursor_width,
2344+
cursor_height,
2345+
};
2346+
const cursor_color: [4]f32 = .{
2347+
@as(f32, @floatFromInt(cursor.color[0])) / 255.0,
2348+
@as(f32, @floatFromInt(cursor.color[1])) / 255.0,
2349+
@as(f32, @floatFromInt(cursor.color[2])) / 255.0,
2350+
@as(f32, @floatFromInt(cursor.color[3])) / 255.0,
2351+
};
2352+
2353+
// Update custom cursor uniforms
2354+
const cursor_style = renderer.CursorStyle.fromTerminal(self.terminal_state.cursor.visual_style).?;
2355+
const current_cursor_style = @as(i32, @intFromEnum(cursor_style));
23312356

2332-
const uniforms = &self.custom_shader_uniforms;
2357+
const cursor_changed: bool =
2358+
!std.meta.eql(new_cursor, uniforms.current_cursor) or
2359+
!std.meta.eql(cursor_color, uniforms.current_cursor_color) or
2360+
current_cursor_style != uniforms.current_cursor_style;
23332361

2334-
const cursor_changed: bool =
2335-
!std.meta.eql(new_cursor, uniforms.current_cursor) or
2336-
!std.meta.eql(cursor_color, uniforms.current_cursor_color);
2362+
if (cursor_changed) {
2363+
uniforms.previous_cursor = uniforms.current_cursor;
2364+
uniforms.previous_cursor_color = uniforms.current_cursor_color;
2365+
uniforms.current_cursor = new_cursor;
2366+
uniforms.current_cursor_color = cursor_color;
23372367

2338-
if (cursor_changed) {
2339-
uniforms.previous_cursor = uniforms.current_cursor;
2340-
uniforms.previous_cursor_color = uniforms.current_cursor_color;
2341-
uniforms.current_cursor = new_cursor;
2342-
uniforms.current_cursor_color = cursor_color;
2343-
uniforms.cursor_change_time = uniforms.time;
2368+
uniforms.previous_cursor_style = uniforms.current_cursor_style;
2369+
uniforms.current_cursor_style = current_cursor_style;
2370+
2371+
uniforms.cursor_change_time = uniforms.time;
2372+
}
23442373
}
23452374
}
23462375
}

src/renderer/shaders/shadertoy_prefix.glsl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,19 @@ layout(binding = 1, std140) uniform Globals {
1515
uniform vec4 iPreviousCursor;
1616
uniform vec4 iCurrentCursorColor;
1717
uniform vec4 iPreviousCursorColor;
18+
uniform int iCurrentCursorStyle;
19+
uniform int iPreviousCursorStyle;
20+
uniform int iCurrentCursorVisible;
21+
uniform int iPreviousCursorVisible;
1822
uniform float iTimeCursorChange;
1923
};
2024

25+
#define CURSORSTYLE_BLOCK 0
26+
#define CURSORSTYLE_BLOCK_HOLLOW 1
27+
#define CURSORSTYLE_BAR 2
28+
#define CURSORSTYLE_UNDERLINE 3
29+
#define CURSORSTYLE_LOCK 4
30+
2131
layout(binding = 0) uniform sampler2D iChannel0;
2232

2333
// These are unused currently by Ghostty:

src/renderer/shadertoy.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ pub const Uniforms = extern struct {
2424
previous_cursor: [4]f32 align(16),
2525
current_cursor_color: [4]f32 align(16),
2626
previous_cursor_color: [4]f32 align(16),
27+
current_cursor_style: i32 align(4),
28+
previous_cursor_style: i32 align(4),
29+
current_cursor_visible: i32 align(4),
30+
previous_cursor_visible: i32 align(4),
2731
cursor_change_time: f32 align(4),
2832
};
2933

0 commit comments

Comments
 (0)