forked from 1b-agent/fieldcraft-upstream
UI: the CPU viewport image never exceeds the texture size limit
A Retina window 2300 pixels wide drew its CPU viewport (the offscreen capture's path) into a 2300 x 1412 texture, past egui's 2048 limit, and the app aborted. The image is now scaled to fit the context's max_texture_side and drawn stretched, as an image over the renderer's own limit already was. Fixes #237. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
0b6b6c966c
commit
7d689fb6a2
1 file changed
+33
-2
@@ -312,8 +312,9 @@ fn paint_gpu(app: &mut ModelApp, ui: &egui::Ui, painter: &egui::Painter, rect: R
|
||||
/// changes.
|
||||
fn paint_cpu(app: &mut ModelApp, ui: &egui::Ui, painter: &egui::Painter, rect: Rect) {
|
||||
let ppp = ui.ctx().pixels_per_point();
|
||||
// A window larger than the renderer's limit is drawn smaller and scaled up.
|
||||
let (w, h) = fieldcraft_render::fit_size((rect.width() * ppp) as usize, (rect.height() * ppp) as usize);
|
||||
// A window larger than the renderer's limit, or than the largest texture the context takes,
|
||||
// is drawn smaller and scaled up.
|
||||
let (w, h) = cpu_size((rect.width() * ppp) as usize, (rect.height() * ppp) as usize, ui.ctx().input(|i| i.max_texture_side));
|
||||
let size = [w, h];
|
||||
let cam = app.cam;
|
||||
let (overlay_key, overlay) = app.overlay();
|
||||
@@ -346,6 +347,19 @@ fn paint_cpu(app: &mut ModelApp, ui: &egui::Ui, painter: &egui::Painter, rect: R
|
||||
}
|
||||
}
|
||||
|
||||
/// The CPU viewport image's size for a viewport of `w` × `h` pixels: within the renderer's limits
|
||||
/// and no side above `max_side`, the aspect kept.
|
||||
fn cpu_size(w: usize, h: usize, max_side: usize) -> (usize, usize) {
|
||||
let (w, h) = fieldcraft_render::fit_size(w, h);
|
||||
let longest = w.max(h);
|
||||
if max_side == 0 || longest <= max_side {
|
||||
return (w, h);
|
||||
}
|
||||
let k = max_side as f64 / longest as f64;
|
||||
let fit = |v: usize| ((v as f64 * k).floor() as usize).clamp(1, max_side);
|
||||
(fit(w), fit(h))
|
||||
}
|
||||
|
||||
/// The scene's labels (reference point names) beside their points, with the interface's font.
|
||||
/// The CPU renderer draws them into its image.
|
||||
fn labels(app: &mut ModelApp, painter: &egui::Painter, t: &Tokens) {
|
||||
@@ -533,3 +547,20 @@ pub fn to_screen(app: &ModelApp, p: Vec3) -> Option<Pos2> {
|
||||
let (x, y, _) = app.cam.to_screen(p, f64::from(rect.width()), f64::from(rect.height()), app.scene.1.radius)?;
|
||||
Some(pos2(rect.left() + x as f32, rect.top() + y as f32))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::cpu_size;
|
||||
|
||||
/// The CPU viewport never asks for a texture larger than the context takes (#237: a Retina
|
||||
/// window 2300 pixels wide on a 2048 limit).
|
||||
#[test]
|
||||
fn the_cpu_image_fits_the_texture_limit() {
|
||||
assert_eq!(cpu_size(2300, 1412, 2048), (2048, 1257));
|
||||
assert_eq!(cpu_size(1412, 2300, 2048), (1257, 2048));
|
||||
assert_eq!(cpu_size(800, 600, 2048), (800, 600));
|
||||
assert_eq!(cpu_size(800, 600, 0), (800, 600));
|
||||
let (w, h) = cpu_size(100_000, 3, 2048);
|
||||
assert!(w <= 2048 && h >= 1);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user