graphic design tool
git clone https://git.lucas.co/cce-designer.git
feat: Wireframe Overlay render setting — wires over shaded prims
A new toggle in the Render node's Render Settings draws the node
geometry's wireframe on top of the filled primitives (dark-tinted
lines via SceneDraw::wire_tint), so prim edges are visible without
giving up the shaded view. Wins over Show Wireframe when both are on;
persists with the project like the other render toggles.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/app.rs | 33 ++++++++++++++++++++++++++-------
src/project.rs | 4 ++++
src/vk_smoke.rs | 6 +++---
3 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index ce64fa7..a40bfb7 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -958,6 +958,11 @@ pub struct State {
/// "Show Wireframe" toggle).
pub wireframe: bool,
pub last_viewport_wireframe: bool,
+ /// Draw the wireframe OVER the shaded geometry (the Render node's
+ /// "Wireframe Overlay" toggle) — edges visualized without giving up the
+ /// filled primitives. Wins over `wireframe` when both are set.
+ pub wireframe_overlay: bool,
+ pub last_viewport_wireframe_overlay: 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
@@ -2623,6 +2628,8 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
last_viewport_show_viewport: false,
wireframe: false,
last_viewport_wireframe: false,
+ wireframe_overlay: false,
+ last_viewport_wireframe_overlay: false,
last_viewport_rt_mode: false,
rt_sphere_verts: Vec::new(),
rt_geometry_version: 0,
@@ -5020,7 +5027,8 @@ 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
|| self.last_viewport_show_viewport != self.show_viewport
- || self.last_viewport_wireframe != self.wireframe;
+ || self.last_viewport_wireframe != self.wireframe
+ || self.last_viewport_wireframe_overlay != self.wireframe_overlay;
if viewport_changed {
if !rt_mode {
@@ -5041,21 +5049,31 @@ 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, wireframe: false }];
+ const NO_TINT: [f32; 4] = [0.0; 4];
+ let mut draws = vec![SceneDraw { mesh: meshes.viewport_bg, mvp, wireframe: false, wire_tint: NO_TINT }];
if self.viewport().show_grid {
- draws.push(SceneDraw { mesh: meshes.grid, mvp, wireframe: false });
+ draws.push(SceneDraw { mesh: meshes.grid, mvp, wireframe: false, wire_tint: NO_TINT });
}
if self.viewport().show_origin {
- draws.push(SceneDraw { mesh: meshes.origin, mvp, wireframe: false });
+ draws.push(SceneDraw { mesh: meshes.origin, mvp, wireframe: false, wire_tint: NO_TINT });
}
if self.viewport().show_camera_pivot {
- draws.push(SceneDraw { mesh: meshes.pivot, mvp: mvp_pivot, wireframe: false });
+ draws.push(SceneDraw { mesh: meshes.pivot, mvp: mvp_pivot, wireframe: false, wire_tint: NO_TINT });
}
if self.viewport().show_cube {
- draws.push(SceneDraw { mesh: meshes.cube, mvp, wireframe: false });
+ draws.push(SceneDraw { mesh: meshes.cube, mvp, wireframe: false, wire_tint: NO_TINT });
}
if self.vertex_count_spheres > 0 {
- draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: self.wireframe });
+ if self.wireframe_overlay {
+ // Shaded + wireframe: the filled mesh, then its
+ // wire pass darkened so the edges separate from
+ // the identical fill (the wire pipeline's depth
+ // bias keeps the lines above the coplanar fill).
+ draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: false, wire_tint: NO_TINT });
+ draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: true, wire_tint: [0.0, 0.0, 0.0, 0.75] });
+ } else {
+ draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: self.wireframe, wire_tint: NO_TINT });
+ }
}
renderer.stage_scene((sx, sy, cw, ch), draws);
}
@@ -5079,6 +5097,7 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
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_wireframe_overlay = self.wireframe_overlay;
self.last_viewport_rt_mode = rt_mode;
self.viewport_dirty = false;
}
diff --git a/src/project.rs b/src/project.rs
index 74baef1..4c30368 100644
--- a/src/project.rs
+++ b/src/project.rs
@@ -270,6 +270,7 @@ impl State {
let show_spreadsheet = self.show_spreadsheet;
let show_playbar = self.show_playbar;
let wireframe = self.wireframe;
+ let wireframe_overlay = self.wireframe_overlay;
let square_viewport = self.square_viewport;
let bool_str = |b: bool| if b { "true" } else { "false" };
@@ -491,10 +492,12 @@ impl State {
ensure_param(render_node, "Render Settings", "section", "", &[], None, None, None);
ensure_param(render_node, "Show Wireframe", "toggle", bool_str(wireframe), &[], None, None, None);
+ ensure_param(render_node, "Wireframe Overlay", "toggle", bool_str(wireframe_overlay), &[], None, None, None);
for p in render_node.params.iter_mut() {
match p.name.as_str() {
"Show Wireframe" => set_toggle(p, wireframe),
+ "Wireframe Overlay" => set_toggle(p, wireframe_overlay),
_ => {}
}
if p.param_type == "toggle" {
@@ -599,6 +602,7 @@ impl State {
for p in ¶ms {
match p.name.as_str() {
"Show Wireframe" => if let Ok(val) = p.default.parse::<bool>() { self.wireframe = val; }
+ "Wireframe Overlay" => if let Ok(val) = p.default.parse::<bool>() { self.wireframe_overlay = val; }
_ => {}
}
}
diff --git a/src/vk_smoke.rs b/src/vk_smoke.rs
index a10c7cc..8f40f0e 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(), wireframe: false },
- SceneDraw { mesh: grid_mesh, mvp, wireframe: false },
- SceneDraw { mesh: cube_mesh, mvp, wireframe: false },
+ SceneDraw { mesh: bg_mesh, mvp: Mat4::IDENTITY.to_cols_array_2d(), wireframe: false, wire_tint: [0.0; 4] },
+ SceneDraw { mesh: grid_mesh, mvp, wireframe: false, wire_tint: [0.0; 4] },
+ SceneDraw { mesh: cube_mesh, mvp, wireframe: false, wire_tint: [0.0; 4] },
],
);
}