git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commita8574ae107aa0cc9298f7efe39d06940a0de6cd6
parente4e47bf69a
authorLucas Galante <[email protected]>
date2026-07-04 21:56
Support window_manager.light_source_position configuration and evaluate dynamic bevel shading in push_plate_bevel_vertices

 src/backend/window_runner.rs | 86 ++++++++++++++++++++++----------------------
 src/layout.rs                |  5 +++
 2 files changed, 48 insertions(+), 43 deletions(-)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index d4cc7bc..e15590c 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -637,55 +637,55 @@ pub fn push_plate_bevel_vertices(
     out: &mut Vec<Vertex>,
 ) {
     let r = r.min(ww * 0.5).min(h * 0.5);
-    let highlight_color = [1.0, 1.0, 1.0, 0.15];
-    let shadow_color = [0.0, 0.0, 0.0, 0.25];
 
-    out.extend_from_slice(&quad_vertices_with_clip(x + r, y, ww - 2.0 * r, t, sw, sh, highlight_color, clip_circle));
-    out.extend_from_slice(&quad_vertices_with_clip(x, y + r, t, h - 2.0 * r, sw, sh, highlight_color, clip_circle));
-    out.extend_from_slice(&quad_vertices_with_clip(x + r, y + h - t, ww - 2.0 * r, t, sw, sh, shadow_color, clip_circle));
-    out.extend_from_slice(&quad_vertices_with_clip(x + ww - t, y + r, t, h - 2.0 * r, sw, sh, shadow_color, clip_circle));
+    let light_angle = crate::layout::light_source_position();
+    let rad = light_angle.to_radians();
+    let lx = rad.cos();
+    let ly = -rad.sin();
 
-    let segments = 16;
+    let edge_color = |factor: f32| -> [f32; 4] {
+        if factor >= 0.0 {
+            [1.0, 1.0, 1.0, 0.15 * factor]
+        } else {
+            [0.0, 0.0, 0.0, 0.25 * (-factor)]
+        }
+    };
 
-    push_arc_background_vertices(
-        x + r, y + r, r, t,
-        std::f32::consts::PI, 1.5 * std::f32::consts::PI,
-        sw, sh, highlight_color, segments, clip_circle,
-        out,
-    );
+    let top_color = edge_color(-ly);
+    let left_color = edge_color(-lx);
+    let bottom_color = edge_color(ly);
+    let right_color = edge_color(lx);
 
-    push_arc_background_vertices(
-        x + ww - r, y + r, r, t,
-        1.5 * std::f32::consts::PI, 1.75 * std::f32::consts::PI,
-        sw, sh, highlight_color, segments / 2, clip_circle,
-        out,
-    );
-    push_arc_background_vertices(
-        x + ww - r, y + r, r, t,
-        1.75 * std::f32::consts::PI, 2.0 * std::f32::consts::PI,
-        sw, sh, shadow_color, segments / 2, clip_circle,
-        out,
-    );
+    out.extend_from_slice(&quad_vertices_with_clip(x + r, y, ww - 2.0 * r, t, sw, sh, top_color, clip_circle));
+    out.extend_from_slice(&quad_vertices_with_clip(x, y + r, t, h - 2.0 * r, sw, sh, left_color, clip_circle));
+    out.extend_from_slice(&quad_vertices_with_clip(x + r, y + h - t, ww - 2.0 * r, t, sw, sh, bottom_color, clip_circle));
+    out.extend_from_slice(&quad_vertices_with_clip(x + ww - t, y + r, t, h - 2.0 * r, sw, sh, right_color, clip_circle));
 
-    push_arc_background_vertices(
-        x + ww - r, y + h - r, r, t,
-        0.0, 0.5 * std::f32::consts::PI,
-        sw, sh, shadow_color, segments, clip_circle,
-        out,
-    );
+    let segments = 16;
+    let corners = [
+        (x + r, y + r, std::f32::consts::PI, 1.5 * std::f32::consts::PI), // Top-Left
+        (x + ww - r, y + r, 1.5 * std::f32::consts::PI, 2.0 * std::f32::consts::PI), // Top-Right
+        (x + ww - r, y + h - r, 0.0, 0.5 * std::f32::consts::PI), // Bottom-Right
+        (x + r, y + h - r, 0.5 * std::f32::consts::PI, std::f32::consts::PI), // Bottom-Left
+    ];
 
-    push_arc_background_vertices(
-        x + r, y + h - r, r, t,
-        0.5 * std::f32::consts::PI, 0.75 * std::f32::consts::PI,
-        sw, sh, shadow_color, segments / 2, clip_circle,
-        out,
-    );
-    push_arc_background_vertices(
-        x + r, y + h - r, r, t,
-        0.75 * std::f32::consts::PI, std::f32::consts::PI,
-        sw, sh, highlight_color, segments / 2, clip_circle,
-        out,
-    );
+    for &(cx, cy, start_angle, end_angle) in &corners {
+        for j in 0..segments {
+            let theta1 = start_angle + (j as f32) * (end_angle - start_angle) / (segments as f32);
+            let theta2 = start_angle + ((j + 1) as f32) * (end_angle - start_angle) / (segments as f32);
+            let theta_mid = 0.5 * (theta1 + theta2);
+
+            let factor = (theta_mid.cos() * lx + theta_mid.sin() * ly).clamp(-1.0, 1.0);
+            let segment_color = edge_color(factor);
+
+            push_arc_background_vertices(
+                cx, cy, r, t,
+                theta1, theta2,
+                sw, sh, segment_color, 1, clip_circle,
+                out,
+            );
+        }
+    }
 }
 
 pub fn push_plate_solid_border_vertices(
diff --git a/src/layout.rs b/src/layout.rs
index e60403d..63c9893 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -105,6 +105,7 @@ fn flatten_json_to_flat_props(val: &serde_json::Value, prefix: &str, flat_props:
                 "style.control.toggle.disabled_color" => "toggle_disabled_color",
                 "style.control.toggle.border_color" => "toggle_border_color",
                 "style.control.toggle.corner_radius" => "toggle_corner_radius",
+                "window_manager.light_source_position" => "light_source_position",
                 "style.control.ramp.height" => "ramp_height",
                 "style.status.normal_color" => "status_normal_color",
                 "style.status.background_color" => "status_background_color",
@@ -1412,6 +1413,10 @@ pub fn set_toggle_height(height: f32) {
     }
 }
 
+pub fn light_source_position() -> f32 {
+    get_style_registry().read().unwrap().get_float("light_source_position").unwrap_or(135.0)
+}
+
 pub fn toggle_corner_radius() -> f32 {
     lazy_init_style_registry();
     get_style_registry().read().unwrap().get_float("toggle_corner_radius").unwrap_or(4.0)