diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index ba9e5d81f2..d984120611 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -1951,6 +1951,13 @@ fn addCursor( .glyph_offset_y = render.glyph.offset_y, }); + // Update cursor uniforms only when custom shaders are loaded + if (self.gl_state) |*gl_state| { + if (gl_state.custom) |*custom_state| { + custom_state.addCursor(self.size, screen.cursor, cursor_style, render.glyph); + } + } + return &self.cells.items[self.cells.items.len - 1]; } diff --git a/src/renderer/opengl/custom.zig b/src/renderer/opengl/custom.zig index 859277ce51..52449ce6b6 100644 --- a/src/renderer/opengl/custom.zig +++ b/src/renderer/opengl/custom.zig @@ -1,6 +1,9 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +const CursorStyle = @import("../../renderer/cursor.zig").Style; const gl = @import("opengl"); +const Glyph = @import("../../font/Glyph.zig"); +const Screen = @import("../../terminal/Screen.zig"); const Size = @import("../size.zig").Size; const log = std.log.scoped(.opengl_custom); @@ -22,6 +25,9 @@ pub const Uniforms = extern struct { mouse: [4]f32 align(16) = .{ 0, 0, 0, 0 }, date: [4]f32 align(16) = .{ 0, 0, 0, 0 }, sample_rate: f32 align(4) = 1, + current_cursor: [4]f32 align(16) = .{ 0, 0, 0, 0 }, + previous_cursor: [4]f32 align(16) = .{ 0, 0, 0, 0 }, + cursor_change_time: f32 align(4) = 1 }; /// The state associated with custom shaders. This should only be initialized @@ -176,6 +182,37 @@ pub const State = struct { null, ); } + + // Update the cursor related uniforms + pub fn addCursor(self: *State, size: Size, cursor: Screen.Cursor, cursor_style: CursorStyle, glyph: Glyph) void { + // Converts the cursor's cell-based position to pixel coordinates. + // Additionally, the y-position is adjusted to account for the inverted Y-axis + // in the window coordinate system used by gl_FragCoord, where the origin is at the bottom-left. + // The offset from the glyph is also added to position the cursor correctly. + const current_x: f32 = @as(f32, @floatFromInt(cursor.x * size.cell.width + size.padding.left)) + @as(f32, @floatFromInt(glyph.offset_x)); + const current_y: f32 = @as(f32, @floatFromInt(size.screen.height - size.padding.top - (cursor.y + 1) * size.cell.height)) + @as(f32, @floatFromInt(glyph.offset_y)); + + // Determine the cursor's width and height based on the cursor style: + // - A bar-style cursor has a width of 1.0, while other cursor styles use the glyph's width. + const cursor_width: f32 = if (cursor_style == .bar) 1.0 else @floatFromInt(glyph.width); + const cursor_height: f32 = @floatFromInt(glyph.height); + + // Check if the cursor's position or size has changed compared to the previously set values. + const cursor_changed: bool = current_x != self.uniforms.current_cursor[0] or + current_y != self.uniforms.current_cursor[1] or + cursor_width != self.uniforms.current_cursor[2] or + cursor_height != self.uniforms.current_cursor[3]; + + if (cursor_changed) { + self.uniforms.previous_cursor = self.uniforms.current_cursor; + self.uniforms.current_cursor = .{ current_x, current_y, cursor_width, cursor_height }; + + // Calculate the time elapsed since the first frame to update the cursor change time. + const now = std.time.Instant.now() catch self.last_frame_time; + const since_ns: f32 = @floatFromInt(now.since(self.first_frame_time)); + self.uniforms.cursor_change_time = since_ns / std.time.ns_per_s; + } + } /// Call this prior to drawing a frame to update the time /// and synchronize the uniforms. This synchronizes uniforms diff --git a/src/renderer/shaders/shadertoy_prefix.glsl b/src/renderer/shaders/shadertoy_prefix.glsl index a1a220bd46..1e59767165 100644 --- a/src/renderer/shaders/shadertoy_prefix.glsl +++ b/src/renderer/shaders/shadertoy_prefix.glsl @@ -11,6 +11,9 @@ layout(binding = 0) uniform Globals { uniform vec4 iMouse; uniform vec4 iDate; uniform float iSampleRate; + uniform vec4 iCurrentCursor; + uniform vec4 iPreviousCursor; + uniform float iTimeCursorChange; }; layout(binding = 0) uniform sampler2D iChannel0;