diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index acb4b4df56..3f24c3d2dd 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1821,6 +1821,21 @@ fn prepKittyPlacement( break :offset_y @intCast(offset_pixels); } else 0; + // If we specify `rows` then our offset above is in viewport space + // and not in the coordinate space of the source image. Without `rows` + // that's one and the same. + const source_offset_y: u32 = if (p.rows > 0) source_offset_y: { + // Determine the scale factor to apply for this row height. + const image_height: f64 = @floatFromInt(image.height); + const viewport_height: f64 = @floatFromInt(p.rows * self.grid_metrics.cell_height); + const scale: f64 = image_height / viewport_height; + + // Apply the scale to the offset + const offset_y_f64: f64 = @floatFromInt(offset_y); + const source_offset_y_f64: f64 = offset_y_f64 * scale; + break :source_offset_y @intFromFloat(@round(source_offset_y_f64)); + } else offset_y; + // We need to prep this image for upload if it isn't in the cache OR // it is in the cache but the transmit time doesn't match meaning this // image is different. @@ -1834,7 +1849,7 @@ fn prepKittyPlacement( // Calculate the source rectangle const source_x = @min(image.width, p.source_x); - const source_y = @min(image.height, p.source_y + offset_y); + const source_y = @min(image.height, p.source_y + source_offset_y); const source_width = if (p.source_width > 0) @min(image.width - source_x, p.source_width) else @@ -1846,7 +1861,11 @@ fn prepKittyPlacement( // Calculate the width/height of our image. const dest_width = if (p.columns > 0) p.columns * self.grid_metrics.cell_width else source_width; - const dest_height = if (p.rows > 0) p.rows * self.grid_metrics.cell_height else source_height; + const dest_height = if (p.rows > 0) rows: { + // Clip to the viewport to handle scrolling. offset_y is already in + // viewport scale so we can subtract it directly. + break :rows (p.rows * self.grid_metrics.cell_height) - offset_y; + } else source_height; // Accumulate the placement if (image.width > 0 and image.height > 0) { diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 0a5179b564..19843062ca 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -1052,6 +1052,21 @@ fn prepKittyPlacement( break :offset_y @intCast(offset_pixels); } else 0; + // If we specify `rows` then our offset above is in viewport space + // and not in the coordinate space of the source image. Without `rows` + // that's one and the same. + const source_offset_y: u32 = if (p.rows > 0) source_offset_y: { + // Determine the scale factor to apply for this row height. + const image_height: f64 = @floatFromInt(image.height); + const viewport_height: f64 = @floatFromInt(p.rows * self.grid_metrics.cell_height); + const scale: f64 = image_height / viewport_height; + + // Apply the scale to the offset + const offset_y_f64: f64 = @floatFromInt(offset_y); + const source_offset_y_f64: f64 = offset_y_f64 * scale; + break :source_offset_y @intFromFloat(@round(source_offset_y_f64)); + } else offset_y; + // We need to prep this image for upload if it isn't in the cache OR // it is in the cache but the transmit time doesn't match meaning this // image is different. @@ -1065,7 +1080,7 @@ fn prepKittyPlacement( // Calculate the source rectangle const source_x = @min(image.width, p.source_x); - const source_y = @min(image.height, p.source_y + offset_y); + const source_y = @min(image.height, p.source_y + source_offset_y); const source_width = if (p.source_width > 0) @min(image.width - source_x, p.source_width) else @@ -1077,7 +1092,11 @@ fn prepKittyPlacement( // Calculate the width/height of our image. const dest_width = if (p.columns > 0) p.columns * self.grid_metrics.cell_width else source_width; - const dest_height = if (p.rows > 0) p.rows * self.grid_metrics.cell_height else source_height; + const dest_height = if (p.rows > 0) rows: { + // Clip to the viewport to handle scrolling. offset_y is already in + // viewport scale so we can subtract it directly. + break :rows (p.rows * self.grid_metrics.cell_height) - offset_y; + } else source_height; // Accumulate the placement if (image.width > 0 and image.height > 0) {