graphic design tool
git clone https://git.lucas.co/cce-designer.git
feat: Render utility node — render/display controls (Show Wireframe)
A second default-present utility subnet beside Main (ensured like Main
in ensure_menubar_subnets, applied in apply_settings_from_menubar_
subnets): its Show Wireframe toggle drives State::wireframe, staged
onto the node-geometry draw (SceneDraw::wireframe — grid/origin/cube
chrome stays filled) and keyed into the viewport restage cache.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/app.rs | 22 +++++++++++++++-------
src/project.rs | 32 ++++++++++++++++++++++++++++++++
src/vk_smoke.rs | 6 +++---
3 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index ac50c49..85ce924 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -948,6 +948,10 @@ pub struct State {
pub last_viewport_height: u32,
pub last_viewport_active_camera: String,
pub last_viewport_show_viewport: bool,
+ /// Wireframe display of the node geometry (the Render utility node's
+ /// "Show Wireframe" toggle).
+ pub wireframe: bool,
+ pub last_viewport_wireframe: bool,
pub last_viewport_rt_mode: bool,
/// Sphere-geometry cache for the path tracer (a copy of the last
/// `rebuild_scene_geometry` output, so entering RT mode never re-runs
@@ -2591,6 +2595,8 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
last_viewport_height: 0,
last_viewport_active_camera: String::new(),
last_viewport_show_viewport: false,
+ wireframe: false,
+ last_viewport_wireframe: false,
last_viewport_rt_mode: false,
rt_sphere_verts: Vec::new(),
rt_geometry_version: 0,
@@ -4973,7 +4979,8 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
|| self.last_viewport_width != cw
|| self.last_viewport_height != ch
|| self.last_viewport_active_camera != self.active_camera
- || self.last_viewport_show_viewport != self.show_viewport;
+ || self.last_viewport_show_viewport != self.show_viewport
+ || self.last_viewport_wireframe != self.wireframe;
if viewport_changed {
if !rt_mode {
@@ -4994,21 +5001,21 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
// Same draw order as the wgpu pass: bg quad, grid, origin,
// pivot, cube, spheres.
- let mut draws = vec![SceneDraw { mesh: meshes.viewport_bg, mvp }];
+ let mut draws = vec![SceneDraw { mesh: meshes.viewport_bg, mvp, wireframe: false }];
if self.viewport().show_grid {
- draws.push(SceneDraw { mesh: meshes.grid, mvp });
+ draws.push(SceneDraw { mesh: meshes.grid, mvp, wireframe: false });
}
if self.viewport().show_origin {
- draws.push(SceneDraw { mesh: meshes.origin, mvp });
+ draws.push(SceneDraw { mesh: meshes.origin, mvp, wireframe: false });
}
if self.viewport().show_camera_pivot {
- draws.push(SceneDraw { mesh: meshes.pivot, mvp: mvp_pivot });
+ draws.push(SceneDraw { mesh: meshes.pivot, mvp: mvp_pivot, wireframe: false });
}
if self.viewport().show_cube {
- draws.push(SceneDraw { mesh: meshes.cube, mvp });
+ draws.push(SceneDraw { mesh: meshes.cube, mvp, wireframe: false });
}
if self.vertex_count_spheres > 0 {
- draws.push(SceneDraw { mesh: meshes.spheres, mvp });
+ draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: self.wireframe });
}
renderer.stage_scene((sx, sy, cw, ch), draws);
}
@@ -5031,6 +5038,7 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
self.last_viewport_height = ch;
self.last_viewport_active_camera = self.active_camera.clone();
self.last_viewport_show_viewport = self.show_viewport;
+ self.last_viewport_wireframe = self.wireframe;
self.last_viewport_rt_mode = rt_mode;
self.viewport_dirty = false;
}
diff --git a/src/project.rs b/src/project.rs
index 76e499f..aabb396 100644
--- a/src/project.rs
+++ b/src/project.rs
@@ -269,6 +269,7 @@ impl State {
let show_parameters = self.show_parameters;
let show_spreadsheet = self.show_spreadsheet;
let show_playbar = self.show_playbar;
+ let wireframe = self.wireframe;
let bool_str = |b: bool| if b { "true" } else { "false" };
let camera_nodes: Vec<String> = self.current_dir().children.iter()
@@ -441,6 +442,27 @@ impl State {
}
}
}
+
+ // 2. Render subnet — render/display controls, present by default like
+ // Main. Toggles reflect live state so a reopened project shows real
+ // switches.
+ let render_node = find_or_create_subnet(&mut self.fs_root, "Render", "utility", (0.0, 1.0));
+ render_node.children.clear();
+
+ ensure_param(render_node, "Render Settings", "section", "", &[], None, None, None);
+ ensure_param(render_node, "Show Wireframe", "toggle", bool_str(wireframe), &[], None, None, None);
+
+ for p in render_node.params.iter_mut() {
+ match p.name.as_str() {
+ "Show Wireframe" => set_toggle(p, wireframe),
+ _ => {}
+ }
+ if p.param_type == "toggle" {
+ if let Some(rest) = p.name.strip_prefix("Show ") {
+ p.label = rest.to_string();
+ }
+ }
+ }
}
pub(crate) fn apply_settings_from_menubar_subnets(&mut self) {
@@ -476,5 +498,15 @@ impl State {
}
}
}
+
+ if let Some(render_idx) = self.fs_root.children.iter().position(|c| c.name == "Render") {
+ let params = self.fs_root.children[render_idx].params.clone();
+ for p in ¶ms {
+ match p.name.as_str() {
+ "Show Wireframe" => if let Ok(val) = p.default.parse::<bool>() { self.wireframe = val; }
+ _ => {}
+ }
+ }
+ }
}
}
diff --git a/src/vk_smoke.rs b/src/vk_smoke.rs
index bd463bd..a10c7cc 100644
--- a/src/vk_smoke.rs
+++ b/src/vk_smoke.rs
@@ -474,9 +474,9 @@ fn main() {
renderer.stage_scene(
pane,
vec![
- SceneDraw { mesh: bg_mesh, mvp: Mat4::IDENTITY.to_cols_array_2d() },
- SceneDraw { mesh: grid_mesh, mvp },
- SceneDraw { mesh: cube_mesh, mvp },
+ SceneDraw { mesh: bg_mesh, mvp: Mat4::IDENTITY.to_cols_array_2d(), wireframe: false },
+ SceneDraw { mesh: grid_mesh, mvp, wireframe: false },
+ SceneDraw { mesh: cube_mesh, mvp, wireframe: false },
],
);
}