From 487434a0b55fa7cf479f39481b51da0a7eda79e1 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Sun, 2 Aug 2026 13:13:53 -0300 Subject: gui: draw image surfaces as GPU quads via glsl shaders --- src/pardes.zig | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'src/pardes.zig') diff --git a/src/pardes.zig b/src/pardes.zig index 0c7c0363..956b0e25 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -391,9 +391,12 @@ pub const Cell = struct { }; /// A pixel image riding the surface: the shell transmits/places it over the -/// given cell rect (tty: kitty graphics; SDL: texture blit). +/// given cell rect (tty: Kitty graphics; SDL: alpha-blended GPU texture). pub const ImagePlace = struct { - pane: u8, // stable key for the shell's transmit-once cache + pane: u8, // cache slot + /// Pane slots are reused. This generation makes a cached GPU texture or + /// kitty image unambiguously belong to the pane which supplied the bytes. + serial: u32, x: u16, y: u16, w: u16, @@ -1172,9 +1175,10 @@ pub const Pardes = struct { /// the Crt builtin's CRT post-process, rendered by the gui shell only /// (the tty and web shells never read it) crt_on: bool = false, - /// kitty graphics support, reported by the shell (image panes fall back - /// to the petscii matcher without it) - kitty_ok: bool = false, + /// Native pixel attachments supported by the shell (Kitty graphics in a + /// terminal, GPU textures in SDL). Image panes dynamically fall back to + /// the PETSCII matcher without it. + native_images: bool = false, quit: bool = false, drag: Drag = .none, hover_col: u16 = 0, @@ -1260,7 +1264,7 @@ pub const Pardes = struct { // FILE argv boot: the doc focused in the left column, a terminal // on the launch directory in the right (files left, shells right) _ = if (look.isImagePath(path)) - try p.openImageView(0, path, !p.kitty_ok) + try p.openImageView(0, path) else try file_pane.open(p, 0, path, opts.file_line); const sh = try p.newPane(1); @@ -6250,11 +6254,15 @@ pub const Pardes = struct { return pane; } - fn openImageView(p: *Pardes, id: usize, path: []const u8, petscii: bool) !*Pane { + fn openImageView(p: *Pardes, id: usize, path: []const u8) !*Pane { const path_copy = try p.gpa.dupe(u8, path); errdefer p.gpa.free(path_copy); const pane = try p.newDocPane(id); - pane.image = .{ .path = path_copy, .petscii = petscii }; + // Native pixels are the preference, not a capability observed at open + // time. drawImage dynamically falls back while a shell has no native + // image support; this matters because kitty detection finishes after + // argv images and restored panes have already been constructed. + pane.image = .{ .path = path_copy }; return pane; } @@ -6489,8 +6497,7 @@ pub const Pardes = struct { .image => |target| { if (p.focusPaneByPath(target.path, .{})) return; const free = p.freeSlot() orelse return; - // petscii by default when the host has no kitty graphics - const nt = p.openImageView(free, target.path, !p.kitty_ok) catch return; + const nt = p.openImageView(free, target.path) catch return; p.placeDoc(id, free, nt); }, } @@ -6866,7 +6873,7 @@ pub const Pardes = struct { dump.decodeBytes(gpa, im.bytes_b64) catch &.{} else &.{}; - pane.image = .{ .path = path, .petscii = true, .raw = raw }; + pane.image = .{ .path = path, .raw = raw }; pane.cols = @max(1, src.cols); pane.rows = @max(1, src.rows); }, @@ -7553,12 +7560,13 @@ pub const Pardes = struct { if (iv.rgba.len == 0 or r.h <= BOX_H) return; const body_cols = tw; const body_rows = r.h - BOX_H; - const use_petscii = iv.petscii or !p.kitty_ok; + const use_petscii = iv.petscii or !p.native_images; if (!use_petscii) { s.images[s.nimages] = .{ .pane = @intCast(for (p.panes, 0..) |slot, i| { if (slot == pane) break i; } else 0), + .serial = pane.serial, .x = tx, .y = r.y + BOX_H, .w = body_cols, -- cgit v1.3