Skip to content

Commit

Permalink
kittygfx: placement with rows (r) param scrolls properly out of viewp…
Browse files Browse the repository at this point in the history
…ort (#3094)

Fixes #2332

Two bugs fixed to fix this behavior:

1. Our destination height didn't account for the top-left being
offscreen.

2. We were using the wrong height for the source rectangle. When a rows
param (r=) is specified, the image height and destination height are at
different scales. We were using the viewport scale for the offset but it
should be the image scale.
  • Loading branch information
mitchellh authored Dec 23, 2024
2 parents cecf2d8 + bd90a6d commit 4f10b13
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
23 changes: 21 additions & 2 deletions src/renderer/Metal.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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) {
Expand Down
23 changes: 21 additions & 2 deletions src/renderer/OpenGL.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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) {
Expand Down

0 comments on commit 4f10b13

Please sign in to comment.