app: create a fucking power curve to do a linear gradient

This commit is contained in:
jkds
2026-01-15 09:20:23 +01:00
parent 141ad27841
commit 6557ca9cf7
2 changed files with 83 additions and 4 deletions

View File

@@ -276,12 +276,17 @@ pub async fn make(
cc.compile("h + 1").unwrap(),
sep_color,
);
shape.add_gradient_box(
let color1 = [0., 0.17, 0.18, 0.3];
let color2 = [0., 0.88, 1., 0.];
shape.add_smooth_vertical_gradient(
expr::const_f32(EMOJI_BG_W + 1.),
expr::const_f32(0.),
expr::load_var("w"),
expr::load_var("h"),
[[0., 1., 0.64, 0.3], [0., 1., 0.64, 0.3], [0., 0.88, 1., 0.], [0., 0.88, 1., 0.]],
cc.compile("h / 2").unwrap(),
color1,
color2,
8,
0.2,
);
let node = node.setup(|me| VectorArt::new(me, shape, app.render_api.clone())).await;
@@ -652,7 +657,7 @@ pub async fn make(
std::f32::consts::PI,
2. * std::f32::consts::PI,
// Color
[0., 0.4, 0., 1.],
[0., 0.28, 0.2, 1.],
);
// Bottom line
//shape.add_filled_box(

View File

@@ -136,6 +136,80 @@ impl VectorShape {
self.indices.append(&mut indices);
}
/// Create a smooth vertical gradient by subdividing into multiple strips.
/// This provides a more linear-looking fade than add_gradient_box with 2 colors.
///
/// # Arguments
/// * `x1, y1` - Top-left corner
/// * `x2, y2` - Bottom-right corner
/// * `top_color` - Color at the top edge
/// * `bottom_color` - Color at the bottom edge
/// * `strips` - Number of horizontal strips (more = smoother gradient, try 8-16)
/// * `gamma` - Low gamma below 0.5 is good
pub fn add_smooth_vertical_gradient(
&mut self,
mut x1: SExprCode,
mut y1: SExprCode,
mut x2: SExprCode,
mut y2: SExprCode,
top_color: Color,
bottom_color: Color,
strips: usize,
gamma: f32,
) {
let x1 = x1.pop().unwrap();
let y1 = y1.pop().unwrap();
let x2 = x2.pop().unwrap();
let y2 = y2.pop().unwrap();
// Use inverse power curve for perceptually smooth alpha blending
// This puts more strips where alpha is high (visible changes)
for i in 0..strips {
// Linear strip positions (equal height strips)
let t0 = i as f32 / strips as f32;
let t1 = (i + 1) as f32 / strips as f32;
// Apply inverse gamma to COLOR interpolation (not positions!)
// This makes color changes more perceptually uniform
let t0_color = t0.powf(gamma);
let t1_color = t1.powf(gamma);
// Interpolate colors with gamma correction
let color_top = [
top_color[0] + (bottom_color[0] - top_color[0]) * t0_color,
top_color[1] + (bottom_color[1] - top_color[1]) * t0_color,
top_color[2] + (bottom_color[2] - top_color[2]) * t0_color,
top_color[3] + (bottom_color[3] - top_color[3]) * t0_color,
];
let color_bottom = [
top_color[0] + (bottom_color[0] - top_color[0]) * t1_color,
top_color[1] + (bottom_color[1] - top_color[1]) * t1_color,
top_color[2] + (bottom_color[2] - top_color[2]) * t1_color,
top_color[3] + (bottom_color[3] - top_color[3]) * t1_color,
];
// Y coordinates use LINEAR spacing (equal strip heights)
let y_top = vec![Op::Add((
Box::new(Op::Mul((Box::new(Op::ConstFloat32(1.0 - t0)), Box::new(y1.clone())))),
Box::new(Op::Mul((Box::new(Op::ConstFloat32(t0)), Box::new(y2.clone())))),
))];
let y_bottom = vec![Op::Add((
Box::new(Op::Mul((Box::new(Op::ConstFloat32(1.0 - t1)), Box::new(y1.clone())))),
Box::new(Op::Mul((Box::new(Op::ConstFloat32(t1)), Box::new(y2.clone())))),
))];
self.add_gradient_box(
vec![x1.clone()],
y_top,
vec![x2.clone()],
y_bottom,
[color_top, color_top, color_bottom, color_bottom],
);
}
}
pub fn add_outline(
&mut self,
x1: SExprCode,