graphic design tool
git clone https://git.lucas.co/cce-designer.git
fix: the point numbers keep their dimming across a scene rebuild
The 2D frame is painted before the stage pass works the dimming out, so
a rebuild that cleared it drew one frame of every number at full
strength, and a playing simulation rebuilds at every frame.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CLAUDE.md | 8 +++++++-
src/app.rs | 8 +++++++-
src/main.rs | 24 ++++++++++++++++++++++++
src/render.rs | 9 +++++++++
4 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index d5d69ed..07b5d7a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2513,7 +2513,13 @@ stage pass, for the eye being staged; a label under 2% is not drawn, so
behind an OPAQUE face a number is hidden, where until then every number
showed through everything. The wires are not counted against a number: a
line a pixel wide is not in front of a label in any way one alpha could
-show. `a_point_number_is_dimmed_by_the_fill_in_front_of_it` is the test;
+show. **A scene rebuild works the dimming out itself**, for the view the
+scene was last staged from (`last_scene_mvp`, `last_scene_eye`). The 2D
+frame is painted BEFORE the stage pass, so a rebuild that only cleared
+the alphas drew one frame of every number at full strength; a playing
+simulation rebuilds at every frame, and the numbers flickered
+(`a_scene_rebuild_keeps_the_point_numbers_dimmed`).
+`a_point_number_is_dimmed_by_the_fill_in_front_of_it` is the test;
the whiskers' order has none, being a draw list only a renderer reads, and
was checked in a shadow session before and after.
diff --git a/src/app.rs b/src/app.rs
index 35a13d1..b99bc07 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -2486,6 +2486,10 @@ pub struct State {
/// The raster scene's model-view-projection and the viewport pane rect in
/// LOGICAL px, cached at staging so the 2D pass can project 3D overlays.
pub last_scene_mvp: Option<Mat4>,
+ /// The eye the scene was last staged for, in mesh space, beside the
+ /// matrix: what a scene rebuild dims the numbers by until the stage
+ /// pass has staged the new geometry.
+ pub last_scene_eye: Vec3,
pub last_scene_view_rect: (f32, f32, f32, f32),
/// The active curve viewer state (viewport point editing), if any.
pub viewer_tool: Option<crate::viewer_state::ViewerTool>,
@@ -6989,6 +6993,7 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Detail) -> (Vec<String>, Vec<V
.unwrap_or(cce_ui::units::Unit::Mm),
pick_cache: None,
last_scene_mvp: None,
+ last_scene_eye: Vec3::ZERO,
last_scene_view_rect: (0.0, 0.0, 0.0, 0.0),
viewer_tool: None,
last_viewport_rt_mode: false,
@@ -11178,7 +11183,8 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Detail) -> (Vec<String>, Vec<V
self.last_scene_mvp = Some(mvp_mat);
self.last_scene_view_rect =
(sx as f32 / s, sy as f32 / s, cw as f32 / s, ch as f32 / s);
- self.sync_point_number_alpha(mvp_mat, (view_mat * model).inverse().transform_point3(Vec3::ZERO));
+ self.last_scene_eye = (view_mat * model).inverse().transform_point3(Vec3::ZERO);
+ self.sync_point_number_alpha(mvp_mat, self.last_scene_eye);
// The camera-pivot marker is WORLD-FIXED at the pivot point, like
// the origin gizmo. Its old yaw rotation existed to keep it glued
diff --git a/src/main.rs b/src/main.rs
index 381a946..57f19b1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1686,6 +1686,30 @@ mod tests {
let _ = fs::remove_dir_all(dir.parent().unwrap());
}
+ /// A scene rebuild leaves the numbers dimmed as they were: the 2D frame
+ /// is painted before the stage pass, so a rebuild that cleared the
+ /// dimming drew one frame of every number at full strength, and a
+ /// playing simulation rebuilds at every frame.
+ #[test]
+ fn a_scene_rebuild_keeps_the_point_numbers_dimmed() {
+ let mut state = State::new(false);
+ state.show_point_numbers = true;
+ state.rebuild_scene_geometry();
+ assert!(!state.overlay_number_labels.is_empty());
+ // The view the stage pass last staged: from +z, looking at the origin.
+ let view = Mat4::look_at_rh(Vec3::new(0.0, 0.0, 6.0), Vec3::ZERO, Vec3::Y);
+ let proj = Mat4::perspective_rh(0.9, 1.5, 0.1, 100.0);
+ state.last_scene_mvp = Some(proj * view);
+ state.last_scene_eye = Vec3::new(0.0, 0.0, 6.0);
+ state.sync_point_number_alpha(proj * view, state.last_scene_eye);
+ let staged = state.overlay_number_alpha.clone();
+ assert!(staged.iter().any(|a| *a < 0.02), "the far side's numbers are hidden: {staged:?}");
+ assert!(staged.iter().any(|a| *a > 0.98), "the near side's are shown");
+
+ state.rebuild_scene_geometry();
+ assert_eq!(state.overlay_number_alpha, staged, "the rebuild left the dimming as the view has it");
+ }
+
/// A point number is dimmed by the fill in front of its point, as a
/// marker drawn under that fill is: whole on the near side, one layer
/// down on the far side of a closed mesh (the faces that meet AT the
diff --git a/src/render.rs b/src/render.rs
index cb40d96..40fd455 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -1280,6 +1280,15 @@ impl State {
cce_ui::colors::to_linear_rgb,
));
self.overlay_dirty = true;
+ // The numbers' dimming, for the view the scene was last staged
+ // from. The 2D frame is painted BEFORE the stage pass, which works
+ // the dimming out: left cleared, the first frame after every
+ // rebuild drew each number at full strength, those behind the
+ // surface too, and a playing simulation rebuilds every frame — the
+ // numbers flickered between shown and dimmed.
+ if let Some(mvp) = self.last_scene_mvp {
+ self.sync_point_number_alpha(mvp, self.last_scene_eye);
+ }
// The pull arrows measure the selected node against this new
// geometry version; a playing simnet reaches here every frame.
self.sync_selection_readouts();