diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index d0a3144f1..b7be691b4 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -737,6 +737,11 @@ fn drawImagePlacement( @as(f32, @floatFromInt(p.y)), }, + .cell_offset = .{ + @as(f32, @floatFromInt(p.cell_offset_x)), + @as(f32, @floatFromInt(p.cell_offset_y)), + }, + .offset_y = p.offset_y, }}); defer buf.deinit(); @@ -929,6 +934,8 @@ fn prepKittyGraphics( .image_id = kv.key_ptr.image_id, .x = @intCast(kv.value_ptr.point.x), .y = @intCast(viewport.y), + .cell_offset_x = kv.value_ptr.x_offset, + .cell_offset_y = kv.value_ptr.y_offset, .offset_y = offset_y, }); } diff --git a/src/renderer/metal/image.zig b/src/renderer/metal/image.zig index 7971f3c5c..3a028f9e9 100644 --- a/src/renderer/metal/image.zig +++ b/src/renderer/metal/image.zig @@ -15,6 +15,11 @@ pub const Placement = struct { x: u32, y: u32, + /// The offset in pixels from the top left of the cell. This is + /// clamped to the size of a cell. + cell_offset_x: u32, + cell_offset_y: u32, + /// The offset of the top of the image texture in case we are clipping /// the top. We don't need an offset_x because we don't support any /// horizontal scrolling so the width is never clipped from the left. diff --git a/src/renderer/metal/shaders.zig b/src/renderer/metal/shaders.zig index 4119456bb..b080bfb89 100644 --- a/src/renderer/metal/shaders.zig +++ b/src/renderer/metal/shaders.zig @@ -60,6 +60,7 @@ pub const Cell = extern struct { /// Single parameter for the image shader. See shader for field details. pub const Image = extern struct { grid_pos: [2]f32, + cell_offset: [2]f32, offset_y: u32, }; @@ -344,6 +345,17 @@ fn initImagePipeline(device: objc.Object, library: objc.Object) !objc.Object { .{@as(c_ulong, 2)}, ); + attr.setProperty("format", @intFromEnum(mtl.MTLVertexFormat.float2)); + attr.setProperty("offset", @as(c_ulong, @offsetOf(Image, "cell_offset"))); + attr.setProperty("bufferIndex", @as(c_ulong, 0)); + } + { + const attr = attrs.msgSend( + objc.Object, + objc.sel("objectAtIndexedSubscript:"), + .{@as(c_ulong, 3)}, + ); + attr.setProperty("format", @intFromEnum(mtl.MTLVertexFormat.uint)); attr.setProperty("offset", @as(c_ulong, @offsetOf(Image, "offset_y"))); attr.setProperty("bufferIndex", @as(c_ulong, 0)); diff --git a/src/renderer/shaders/cell.metal b/src/renderer/shaders/cell.metal index 5a405356c..cc533bf42 100644 --- a/src/renderer/shaders/cell.metal +++ b/src/renderer/shaders/cell.metal @@ -195,8 +195,12 @@ struct ImageVertexIn { // the image will be rendered. It will be rendered from the top left. float2 grid_pos [[ attribute(1) ]]; + // Offset in pixels from the top-left of the cell to make the top-left + // corner of the image. + float2 cell_offset [[ attribute(2) ]]; + // The offset for the texture coordinates. - uint offset_y [[ attribute(2) ]]; + uint offset_y [[ attribute(3) ]]; }; struct ImageVertexOut { @@ -235,7 +239,7 @@ vertex ImageVertexOut image_vertex( ImageVertexOut out; // The position of our image starts at the top-left of the grid cell. - float2 image_pos = uniforms.cell_size * input.grid_pos; + float2 image_pos = (uniforms.cell_size * input.grid_pos) + input.cell_offset; // We need to adjust the bottom y of the image by offset y otherwise // as we scroll the full image will be rendered and stretched. diff --git a/src/terminal/kitty/graphics_exec.zig b/src/terminal/kitty/graphics_exec.zig index aeb250733..c37ee2f54 100644 --- a/src/terminal/kitty/graphics_exec.zig +++ b/src/terminal/kitty/graphics_exec.zig @@ -168,7 +168,11 @@ fn display( }).toScreen(&terminal.screen); // Add the placement - const p: ImageStorage.Placement = .{ .point = placement_point }; + const p: ImageStorage.Placement = .{ + .point = placement_point, + .x_offset = d.x_offset, + .y_offset = d.y_offset, + }; storage.addPlacement(alloc, img.id, d.placement_id, p) catch |err| { encodeError(&result, err); return result; diff --git a/src/terminal/kitty/graphics_storage.zig b/src/terminal/kitty/graphics_storage.zig index 9f516562f..6d14e7757 100644 --- a/src/terminal/kitty/graphics_storage.zig +++ b/src/terminal/kitty/graphics_storage.zig @@ -156,6 +156,10 @@ pub const ImageStorage = struct { /// The location of the image on the screen. point: ScreenPoint, + /// Offset of the x/y from the top-left of the cell. + x_offset: u32 = 0, + y_offset: u32 = 0, + /// Returns a selection of the entire rectangle this placement /// occupies within the screen. pub fn selection(