From 8d5ecdef51fee55b4a81531e14ad3cea0536a93d Mon Sep 17 00:00:00 2001 From: Hakan Date: Thu, 14 May 2026 14:02:48 +0300 Subject: [PATCH] fix(scene): correct view_world_aabb space + guard initial render MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs in the new frustum culler that left the GUI rendering nothing on file open: 1. `cam.target` is already in **local** f32 space — `fit_to_bounds` populates it from local wire coords — so subtracting `world_offset` again pushed the view rect to the negated centroid, with the actual geometry far outside. 2. The first call to `entity_wires()` after open comes from `fit_all()` itself, while `camera_generation` is still 0 and the camera is at its default origin. Culling against that rect discarded every wire → fit_all saw an empty list → camera never moved → the user-visible render stayed empty forever. `view_world_aabb` now returns `None` until `camera_generation > 0` (letting fit_all collect a real extent), then derives the view rect directly from `cam.target` in local space. Co-Authored-By: Claude Opus 4.7 --- src/scene/mod.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/scene/mod.rs b/src/scene/mod.rs index ce38c12fe..d6fb14bb5 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -343,16 +343,23 @@ impl Scene { // top-level paper canvas is small enough not to need it. return None; } + // Until the first explicit camera move (typically `fit_all()` after + // file open), the camera sits at the default origin while geometry + // lives at large local offsets — culling against the default rect + // would discard everything and starve fit_all of points to fit to. + if self.camera_generation == 0 { + return None; + } let cam = self.camera.borrow(); let aspect = self.last_render_aspect.get().max(0.01); let h = cam.ortho_size(); let w = h * aspect; - // Generous margin: in 3D / perspective the projection actually covers - // more than the orthographic-equivalent rect, and pan inertia briefly - // moves geometry past the visible edge before camera_generation bumps. let margin = 1.25_f32; - let cx = (cam.target.x - self.world_offset[0] as f32) as f32; - let cy = (cam.target.y - self.world_offset[1] as f32) as f32; + // `cam.target` is in the same local f32 space as emitted wire points + // (fit_to_bounds populates it from local wire coords). No further + // `world_offset` subtraction is needed. + let cx = cam.target.x; + let cy = cam.target.y; Some([ cx - w * margin, cy - h * margin,