graphic design tool
git clone https://git.lucas.co/cce-designer.git
feat: wireframe draws atop the fill, with a single-color mode
Show Wireframe no longer replaces the filled geometry — the wire pass
always rides on top of it. Two new Render-node params control the wire
look: 'Wire Single Color' toggles between the geometry's vertex colors
(darkened 45% so the wires separate from the identical fill) and a flat
color; 'Wire Color' picks that color. Both respect the geometry
Opacity.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/app.rs | 37 ++++++++++++++++++++++++++++++++-----
src/project.rs | 8 ++++++++
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index ec9f839..3dcace1 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -985,12 +985,17 @@ pub struct State {
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).
+ /// "Show Wireframe" toggle): a wire pass drawn IN ADDITION to the filled
+ /// geometry, never instead of it.
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.
+ /// "Wire Single Color" toggle: on, the wires draw in `wire_color`; off,
+ /// they keep the geometry's vertex colors (darkened enough to separate
+ /// from the identical fill beneath).
+ pub wire_single_color: bool,
+ pub wire_color: [f32; 3],
+ pub last_viewport_wire_single_color: bool,
+ pub last_viewport_wire_color: [f32; 3],
/// Opacity of the rendered node geometry (the Render node's "Opacity"
/// slider): 1.0 opaque, straight-alpha blended toward the viewport bg.
pub geo_opacity: f32,
@@ -2822,6 +2827,10 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
last_viewport_show_viewport: false,
wireframe: false,
last_viewport_wireframe: false,
+ wire_single_color: false,
+ wire_color: [1.0, 1.0, 1.0],
+ last_viewport_wire_single_color: false,
+ last_viewport_wire_color: [1.0, 1.0, 1.0],
geo_opacity: 1.0,
last_viewport_geo_opacity: 1.0,
render_points: false,
@@ -5355,6 +5364,8 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
|| self.last_viewport_show_viewport != self.show_viewport
|| self.last_viewport_wireframe != self.wireframe
|| self.last_viewport_geo_opacity != self.geo_opacity
+ || self.last_viewport_wire_single_color != self.wire_single_color
+ || self.last_viewport_wire_color != self.wire_color
|| self.last_viewport_render_points != self.render_points
|| self.last_viewport_point_size != self.point_size
|| self.last_viewport_point_color != self.point_color;
@@ -5396,7 +5407,21 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
draws.push(SceneDraw { mesh: meshes.points, mvp, wireframe: false, wire_tint: NO_TINT, opacity: geo_opacity });
}
if self.vertex_count_spheres > 0 {
- draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: self.wireframe, wire_tint: NO_TINT, opacity: geo_opacity });
+ draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: false, wire_tint: NO_TINT, opacity: geo_opacity });
+ if self.wireframe {
+ // The wire pass rides ON TOP of the fill (never
+ // replaces it). Single-color mode replaces the
+ // fragment color outright; geometry-color mode
+ // keeps the vertex colors, darkened 45% so the
+ // wires separate from the identical fill beneath
+ // (a full-strength copy would vanish into it).
+ let tint = if self.wire_single_color {
+ [self.wire_color[0], self.wire_color[1], self.wire_color[2], 1.0]
+ } else {
+ [0.0, 0.0, 0.0, 0.45]
+ };
+ draws.push(SceneDraw { mesh: meshes.spheres, mvp, wireframe: true, wire_tint: tint, opacity: geo_opacity });
+ }
}
renderer.stage_scene((sx, sy, cw, ch), draws);
}
@@ -5421,6 +5446,8 @@ pub(crate) fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec
self.last_viewport_show_viewport = self.show_viewport;
self.last_viewport_wireframe = self.wireframe;
self.last_viewport_geo_opacity = self.geo_opacity;
+ self.last_viewport_wire_single_color = self.wire_single_color;
+ self.last_viewport_wire_color = self.wire_color;
self.last_viewport_render_points = self.render_points;
self.last_viewport_point_size = self.point_size;
self.last_viewport_point_color = self.point_color;
diff --git a/src/project.rs b/src/project.rs
index b2326a1..5d08a68 100644
--- a/src/project.rs
+++ b/src/project.rs
@@ -270,6 +270,8 @@ impl State {
let show_spreadsheet = self.show_spreadsheet;
let show_playbar = self.show_playbar;
let wireframe = self.wireframe;
+ let wire_single_color = self.wire_single_color;
+ let wire_color = self.wire_color;
let geo_opacity = self.geo_opacity;
let render_points = self.render_points;
let point_size = self.point_size;
@@ -526,6 +528,8 @@ 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, "Wire Single Color", "toggle", bool_str(wire_single_color), &[], None, None, None);
+ ensure_param(render_node, "Wire Color", "color", &color_to_hex(wire_color), &[], None, None, None);
ensure_param(render_node, "Opacity", "slider:0.00:1.00", &format!("{:.2}", geo_opacity), &[], Some(0.0), Some(1.0), None);
ensure_param(render_node, "Render Points", "toggle", bool_str(render_points), &[], None, None, None);
ensure_param(render_node, "Point Size", "slider:0.01:0.30", &format!("{:.2}", point_size), &[], Some(0.01), Some(0.30), None);
@@ -534,6 +538,8 @@ impl State {
for p in render_node.params.iter_mut() {
match p.name.as_str() {
"Show Wireframe" => set_toggle(p, wireframe),
+ "Wire Single Color" => set_toggle(p, wire_single_color),
+ "Wire Color" => p.default = color_to_hex(wire_color),
"Opacity" => p.default = format!("{:.2}", geo_opacity),
"Render Points" => set_toggle(p, render_points),
"Point Size" => p.default = format!("{:.2}", point_size),
@@ -673,6 +679,8 @@ impl State {
for p in ¶ms {
match p.name.as_str() {
"Show Wireframe" => if let Ok(val) = p.default.parse::<bool>() { self.wireframe = val; }
+ "Wire Single Color" => if let Ok(val) = p.default.parse::<bool>() { self.wire_single_color = val; }
+ "Wire Color" => if let Some(col) = hex_to_color(&p.default) { self.wire_color = col; }
"Opacity" => if let Ok(val) = p.default.parse::<f32>() { self.geo_opacity = val.clamp(0.0, 1.0); }
"Render Points" => if let Ok(val) = p.default.parse::<bool>() { self.render_points = val; }
"Point Size" => if let Ok(val) = p.default.parse::<f32>() { self.point_size = val.clamp(0.005, 1.0); }