git.lucas.co / cce-gallery
widget gallery and compositor test bench

commita4ae2b385a3351d88a6492a5f5b29065e9988fcf
parentf25e2c0513
authorLucas Galante <[email protected]>
date2026-07-04 20:13
Change bevel shape editor to use float Ramp and implement slope shading

 src/main.rs | 114 ++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 60 insertions(+), 54 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index f53a140..d95bb87 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
 use cce_ui::widget::{
     Button, Checkbox, ContentBg, Dropdown, Label, Paginator, Panel, ProgressBar, RangeSlider, Slider, Spinbox, StatusBar,
     TextLabel, Toggle, Element, Trackpad, hover_animation, TextBox, Plate, CornerRadii, Backplate, MenuBar, SectionContainer,
-    Ramp, ColorRamp, ColorRampKey,
+    Ramp, RampKey, ColorRamp,
 };
 use cce_ui::engine::{Vertex, quad_vertices, push_rounded_rect_vertices_corners};
 
@@ -97,22 +97,22 @@ struct State {
     border_bevel: bool,
     child_type: Option<String>,
     ui_context: cce_ui::context::UiContext,
-    bevel_ramp: Vec<ColorRampKey>,
+    bevel_ramp: Vec<RampKey>,
     last_ramp_mod: Option<std::time::SystemTime>,
 }
 
-fn save_bevel_ramp(keys: &[ColorRampKey]) {
+fn save_bevel_ramp(keys: &[RampKey]) {
     let mut s = String::new();
     s.push_str("keys {\n");
     for k in keys {
-        s.push_str(&format!("    key pos={} r={} g={} b={}\n", k.pos, k.color[0], k.color[1], k.color[2]));
+        s.push_str(&format!("    key pos={} val={}\n", k.pos, k.value));
     }
     s.push_str("}\n");
     let path = cce_ui::config::get_config_path().parent().unwrap().join("bevel_ramp.kdl");
     let _ = std::fs::write(path, s);
 }
 
-fn load_bevel_ramp() -> Vec<ColorRampKey> {
+fn load_bevel_ramp() -> Vec<RampKey> {
     let path = cce_ui::config::get_config_path().parent().unwrap().join("bevel_ramp.kdl");
     if let Ok(content) = std::fs::read_to_string(path) {
         let mut keys = Vec::new();
@@ -120,21 +120,15 @@ fn load_bevel_ramp() -> Vec<ColorRampKey> {
             let line = line.trim();
             if line.starts_with("key ") {
                 let mut pos = 0.0;
-                let mut r = 0.0;
-                let mut g = 0.0;
-                let mut b = 0.0;
+                let mut val = 0.5;
                 for part in line.split_whitespace() {
                     if let Some(rest) = part.strip_prefix("pos=") {
                         pos = rest.parse().unwrap_or(0.0);
-                    } else if let Some(rest) = part.strip_prefix("r=") {
-                        r = rest.parse().unwrap_or(0.0);
-                    } else if let Some(rest) = part.strip_prefix("g=") {
-                        g = rest.parse().unwrap_or(0.0);
-                    } else if let Some(rest) = part.strip_prefix("b=") {
-                        b = rest.parse().unwrap_or(0.0);
+                    } else if let Some(rest) = part.strip_prefix("val=") {
+                        val = rest.parse().unwrap_or(0.5);
                     }
                 }
-                keys.push(ColorRampKey { pos, color: [r, g, b] });
+                keys.push(RampKey { pos, value: val });
             }
         }
         if !keys.is_empty() {
@@ -142,22 +136,24 @@ fn load_bevel_ramp() -> Vec<ColorRampKey> {
             return keys;
         }
     }
-    // Default keys
+    // Default keys: raised bevel profile (starts/ends at backplate level 0.5, peaks at 1.0)
     vec![
-        ColorRampKey { pos: 0.0, color: [0.0, 0.0, 0.0] },
-        ColorRampKey { pos: 1.0, color: [1.0, 1.0, 1.0] },
+        RampKey { pos: 0.0, value: 0.5 },
+        RampKey { pos: 0.2, value: 1.0 },
+        RampKey { pos: 0.8, value: 1.0 },
+        RampKey { pos: 1.0, value: 0.5 },
     ]
 }
 
-fn interpolate_ramp_color(keys: &[ColorRampKey], u: f32) -> [f32; 3] {
+fn interpolate_ramp_value(keys: &[RampKey], u: f32) -> f32 {
     if keys.is_empty() {
-        return [0.0, 0.0, 0.0];
+        return 0.5;
     }
     if u <= keys[0].pos {
-        return keys[0].color;
+        return keys[0].value;
     }
     if u >= keys[keys.len() - 1].pos {
-        return keys[keys.len() - 1].color;
+        return keys[keys.len() - 1].value;
     }
     for i in 0..keys.len() - 1 {
         let k1 = &keys[i];
@@ -165,17 +161,13 @@ fn interpolate_ramp_color(keys: &[ColorRampKey], u: f32) -> [f32; 3] {
         if u >= k1.pos && u <= k2.pos {
             let range = k2.pos - k1.pos;
             if range.abs() < 0.0001 {
-                return k1.color;
+                return k1.value;
             }
             let w = (u - k1.pos) / range;
-            return [
-                k1.color[0] * (1.0 - w) + k2.color[0] * w,
-                k1.color[1] * (1.0 - w) + k2.color[1] * w,
-                k1.color[2] * (1.0 - w) + k2.color[2] * w,
-            ];
+            return k1.value * (1.0 - w) + k2.value * w;
         }
     }
-    keys[0].color
+    keys[0].value
 }
 
 impl State {
@@ -344,11 +336,7 @@ impl State {
             if child_type.as_deref() == Some("ColorRamp") {
                 vec![
                     bg,                      // 0
-                    Box::new({
-                        let mut ramp = ColorRamp::new();
-                        ramp.keys = load_bevel_ramp();
-                        ramp
-                    }), // 1
+                    Box::new(ColorRamp::new()), // 1
                     Box::new(Button::new(0.0, 0.0, 100.0, 35.0).with_label("Close")), // 2
                     Box::new(Label::new("").with_font_size(12.0)), // 3
                     Box::new(Label::new("").with_font_size(12.0)), // 4
@@ -356,7 +344,11 @@ impl State {
             } else if child_type.as_deref() == Some("Ramp") {
                 vec![
                     bg,                      // 0
-                    Box::new(Ramp::new()), // 1
+                    Box::new({
+                        let mut ramp = Ramp::new();
+                        ramp.keys = load_bevel_ramp();
+                        ramp
+                    }), // 1
                     Box::new(Button::new(0.0, 0.0, 100.0, 35.0).with_label("Close")), // 2
                     Box::new(Label::new("").with_font_size(12.0)), // 3
                     Box::new(Label::new("").with_font_size(12.0)), // 4
@@ -812,18 +804,25 @@ cascades in cce."
                         let slices = 5;
                         let slice_w = t / slices as f32;
                         for i in 0..slices {
-                            let u = i as f32 / (slices - 1).max(1) as f32;
-                            let col = interpolate_ramp_color(&self.bevel_ramp, u);
+                            let u_curr = i as f32 / slices as f32;
+                            let u_next = (i + 1) as f32 / slices as f32;
+                            
+                            let h_outer = if i == 0 { 0.5 } else { interpolate_ramp_value(&self.bevel_ramp, u_curr) };
+                            let h_inner = if i == slices - 1 { 0.5 } else { interpolate_ramp_value(&self.bevel_ramp, u_next) };
+                            
+                            let d_h = h_inner - h_outer;
+                            let color_offset = d_h * 0.4;
+                            
                             let light_color = [
-                                (border_color[0] + 0.35 * col[0]).min(1.0),
-                                (border_color[1] + 0.35 * col[1]).min(1.0),
-                                (border_color[2] + 0.35 * col[2]).min(1.0),
+                                (border_color[0] + color_offset).clamp(0.0, 1.0),
+                                (border_color[1] + color_offset).clamp(0.0, 1.0),
+                                (border_color[2] + color_offset).clamp(0.0, 1.0),
                                 border_color[3]
                             ];
                             let dark_color = [
-                                (border_color[0] - 0.35 * col[0]).max(0.0),
-                                (border_color[1] - 0.35 * col[1]).max(0.0),
-                                (border_color[2] - 0.35 * col[2]).max(0.0),
+                                (border_color[0] - color_offset).clamp(0.0, 1.0),
+                                (border_color[1] - color_offset).clamp(0.0, 1.0),
+                                (border_color[2] - color_offset).clamp(0.0, 1.0),
                                 border_color[3]
                             ];
                             let offset = i as f32 * slice_w;
@@ -839,18 +838,25 @@ cascades in cce."
                         let slices = 5;
                         let slice_w = t / slices as f32;
                         for i in 0..slices {
-                            let u = i as f32 / (slices - 1).max(1) as f32;
-                            let col = interpolate_ramp_color(&self.bevel_ramp, u);
+                            let u_curr = i as f32 / slices as f32;
+                            let u_next = (i + 1) as f32 / slices as f32;
+                            
+                            let h_outer = if i == 0 { 0.5 } else { interpolate_ramp_value(&self.bevel_ramp, u_curr) };
+                            let h_inner = if i == slices - 1 { 0.5 } else { interpolate_ramp_value(&self.bevel_ramp, u_next) };
+                            
+                            let d_h = h_inner - h_outer;
+                            let color_offset = d_h * 0.4;
+                            
                             let light_color = [
-                                (border_color[0] + 0.35 * col[0]).min(1.0),
-                                (border_color[1] + 0.35 * col[1]).min(1.0),
-                                (border_color[2] + 0.35 * col[2]).min(1.0),
+                                (border_color[0] + color_offset).clamp(0.0, 1.0),
+                                (border_color[1] + color_offset).clamp(0.0, 1.0),
+                                (border_color[2] + color_offset).clamp(0.0, 1.0),
                                 border_color[3]
                             ];
                             let dark_color = [
-                                (border_color[0] - 0.35 * col[0]).max(0.0),
-                                (border_color[1] - 0.35 * col[1]).max(0.0),
-                                (border_color[2] - 0.35 * col[2]).max(0.0),
+                                (border_color[0] - color_offset).clamp(0.0, 1.0),
+                                (border_color[1] - color_offset).clamp(0.0, 1.0),
+                                (border_color[2] - color_offset).clamp(0.0, 1.0),
                                 border_color[3]
                             ];
                             let offset = i as f32 * slice_w;
@@ -1231,8 +1237,8 @@ cascades in cce."
             if is_visible(i) {
                 if w.tick(dt, &mut self.ui_context) {
                     changed = true;
-                    if self.is_child && self.child_type.as_deref() == Some("ColorRamp") && i == 1 {
-                        if let Some(ramp) = w.as_any().downcast_ref::<ColorRamp>() {
+                    if self.is_child && self.child_type.as_deref() == Some("Ramp") && i == 1 {
+                        if let Some(ramp) = w.as_any().downcast_ref::<Ramp>() {
                             save_bevel_ramp(&ramp.keys);
                         }
                     }
@@ -1931,7 +1937,7 @@ impl PointerHandler for AppState {
                                             let mut cmd = std::process::Command::new(exe);
                                             cmd.arg("--child")
                                                .arg("--type")
-                                               .arg("ColorRamp")
+                                               .arg("Ramp")
                                                .arg("--width")
                                                .arg("450")
                                                .arg("--height")