#[derive(Debug, Clone, Copy)]
pub struct PaneRenderGeometry {
pub window_width: f32,
pub window_height: f32,
pub pane_origin_x: f32,
pub pane_origin_y: f32,
}
#[allow(clippy::too_many_arguments)]
pub(super) fn compute_graphic_geometry(
tex_w: f32,
tex_h: f32,
crop: [u32; 4],
width_cells: usize,
height_cells: usize,
cell_w: f32,
cell_h: f32,
clip_px: f32,
has_cols: bool,
has_rows: bool,
preserve_aspect: bool,
is_virtual: bool,
window_w: f32,
window_h: f32,
) -> ([f32; 4], [f32; 2]) {
let has_crop = crop != [0, 0, 0, 0];
let (sx, sy, sw, sh) = if has_crop && tex_w > 0.0 && tex_h > 0.0 {
let x = (crop[0] as f32).min(tex_w);
let y = (crop[1] as f32).min(tex_h);
let w = if crop[2] > 0 {
(crop[2] as f32).min(tex_w - x)
} else {
tex_w - x
};
let h = if crop[3] > 0 {
(crop[3] as f32).min(tex_h - y)
} else {
tex_h - y
};
(x, y, w.max(0.0), h.max(0.0))
} else {
(0.0, 0.0, tex_w, tex_h)
};
if sw <= 0.0 || sh <= 0.0 {
return ([0.0, 0.0, 0.0, 0.0], [0.0, 0.0]);
}
let aspect = sw / sh;
let (dest_w, dest_h) = if is_virtual || (has_cols && has_rows) {
(width_cells as f32 * cell_w, height_cells as f32 * cell_h)
} else if has_cols && !has_rows {
let dw = width_cells as f32 * cell_w;
(dw, dw / aspect)
} else if has_rows && !has_cols {
let dh = height_cells as f32 * cell_h;
(dh * aspect, dh)
} else if has_crop && sw > 0.0 && sh > 0.0 {
(sw, sh)
} else if preserve_aspect && tex_w > 0.0 && tex_h > 0.0 {
(tex_w, tex_h)
} else {
(width_cells as f32 * cell_w, height_cells as f32 * cell_h)
};
let visible_frac = if dest_h > 0.0 {
((dest_h - clip_px) / dest_h).clamp(0.0, 1.0)
} else {
0.0
};
let scrolled_frac = if dest_h > 0.0 {
(clip_px / dest_h).clamp(0.0, 1.0)
} else {
0.0
};
let uv = if sw > 0.0 && sh > 0.0 && tex_w > 0.0 && tex_h > 0.0 {
[
sx / tex_w,
(sy + sh * scrolled_frac) / tex_h,
sw / tex_w,
(sh * visible_frac) / tex_h,
]
} else {
[0.0, 0.0, 1.0, 1.0]
};
let size = (dest_w / window_w, dest_h * visible_frac / window_h);
(uv, size.into())
}
#[cfg(test)]
mod geometry_tests {
use super::compute_graphic_geometry;
const WW: f32 = 800.0;
const WH: f32 = 600.0;
const CW: f32 = 10.0;
const CH: f32 = 20.0;
#[test]
fn no_crop_both_cells_uses_dest_fraction_for_uv() {
let (uv, size) = compute_graphic_geometry(
100.0,
100.0,
[0, 0, 0, 0],
10,
2,
CW,
CH,
20.0, true,
true, false,
false, WW,
WH,
);
let expected_uv_y = 50.0 / 100.0;
let expected_uv_h = 50.0 / 100.0;
assert!((uv[1] - expected_uv_y).abs() < 1e-5);
assert!((uv[3] - expected_uv_h).abs() < 1e-5);
assert!((size[1] - 20.0 / WH).abs() < 1e-5);
}
#[test]
fn natural_crop_without_cells_uses_crop_height_for_dest() {
let (uv, size) = compute_graphic_geometry(
100.0,
100.0,
[0, 0, 0, 25],
1,
1,
CW,
CH,
20.0,
false,
false,
false,
false,
WW,
WH,
);
let expected_uv_y = (0.0 + 25.0 * 0.8) / 100.0;
let expected_uv_h = (25.0 * 0.2) / 100.0;
assert!((uv[1] - expected_uv_y).abs() < 1e-5);
assert!((uv[3] - expected_uv_h).abs() < 1e-5);
assert!((size[1] - 5.0 / WH).abs() < 1e-5);
}
#[test]
fn y_offset_produces_sub_row_clip() {
let top_px = -CH + 5.0;
let clip_px = (-top_px).max(0.0);
assert_eq!(clip_px, 15.0);
let (uv, size) = compute_graphic_geometry(
100.0,
100.0,
[0, 0, 0, 0],
10,
3,
CW,
CH,
clip_px,
true,
true,
false,
false,
WW,
WH,
);
assert!((uv[1] - 25.0 / 100.0).abs() < 1e-5);
assert!((uv[3] - 75.0 / 100.0).abs() < 1e-5);
assert!((size[1] - 45.0 / WH).abs() < 1e-5);
}
#[test]
fn c_only_computes_exact_height_from_aspect() {
let (_uv, size) = compute_graphic_geometry(
100.0,
100.0,
[0, 0, 0, 0],
5,
3,
CW,
CH,
0.0,
true,
false, false,
false,
WW,
WH,
);
assert!((size[0] - 50.0 / WW).abs() < 1e-5);
assert!((size[1] - 50.0 / WH).abs() < 1e-5);
}
#[test]
fn r_only_computes_exact_width_from_aspect() {
let (_uv, size) = compute_graphic_geometry(
100.0,
100.0,
[0, 0, 0, 0],
4,
2,
CW,
CH,
0.0,
false,
true, false,
false,
WW,
WH,
);
assert!((size[0] - 40.0 / WW).abs() < 1e-5);
assert!((size[1] - 40.0 / WH).abs() < 1e-5);
}
#[test]
fn c_only_wide_source_computes_proportional_height() {
let (_uv, size) = compute_graphic_geometry(
100.0,
50.0,
[0, 0, 0, 0],
5,
1,
CW,
CH,
0.0,
true,
false,
false,
false,
WW,
WH,
);
assert!((size[0] - 50.0 / WW).abs() < 1e-5);
assert!((size[1] - 25.0 / WH).abs() < 1e-5);
}
#[test]
fn zero_size_crop_at_edge_returns_zero_output() {
let (uv, size) = compute_graphic_geometry(
100.0,
100.0,
[100, 0, 0, 0],
5,
3,
CW,
CH,
0.0,
true,
false,
false,
false,
WW,
WH,
);
assert_eq!(uv, [0.0, 0.0, 0.0, 0.0]);
assert_eq!(size, [0.0, 0.0]);
}
}