Merge pull request #1265

This commit is contained in:
Brandon Thomas
2026-10-18 09:35:32 -04:00
3 changed files with 30 additions and 3 deletions
+18 -2
View File
@@ -164,7 +164,10 @@ fn wave_warp(ctx: &EffectCtx, mut b: Buf) -> Buf {
let kind = ctx.params.e("waveType");
let pin = ctx.params.e("pinning");
let seed = ctx.seed ^ 0x3a7e;
let (dx, dy) = (dir.sin(), -dir.cos());
// Cardinal directions must not acquire a tiny perpendicular slope: at a square-wave
// boundary cos(90°)'s rounding residue can flip a whole column on CPU but not GPU.
let axis = |v: f64| if v.abs() < 4.0 * f64::EPSILON { 0.0 } else { v };
let (dx, dy) = (axis(dir.sin()), -axis(dir.cos()));
if !ctx.adjustment {
b.pad(h.abs().ceil() as u32 + 1);
}
@@ -556,8 +559,21 @@ mod tests {
let (a, b) = (o.img.get(pad, y + pad), im.get(0, y));
assert!((0..4).all(|i| (a[i] - b[i]).abs() < 0.01), "row {y}: {a:?} vs {b:?}");
}
let free = run("ec.distort.wavewarp", &[("direction", num(0.0)), ("height", num(5.0))], im);
let free = run("ec.distort.wavewarp", &[("direction", num(0.0)), ("height", num(5.0))], im.clone());
assert!(free.img.data.iter().zip(&o.img.data).any(|(a, b)| differs(*a, *b)));
// #1181: direction 90° → vertical displacement. Top Edge (4) holds the first row,
// Bottom Edge (6) the last, and the rest of the layer still moves.
for (pin, edge_row) in [(Value::Enum(4), 0i64), (Value::Enum(6), 29i64)] {
let set = [("direction", num(90.0)), ("height", num(5.0)), ("pinning", pin)];
let o = run("ec.distort.wavewarp", &set, im.clone());
let pad = ((o.img.width - im.width) / 2) as i64;
for x in 0..40 {
let (a, b) = (o.img.get(x + pad, edge_row + pad), im.get(x, edge_row));
assert!((0..4).all(|i| (a[i] - b[i]).abs() < 0.01), "pin {edge_row} col {x}: {a:?} vs {b:?}");
}
let mid = 15;
assert!((0..40).any(|x| differs(o.img.get(x + pad, mid + pad), im.get(x, mid))), "pin {edge_row}: the middle of the layer must still distort");
}
}
#[test]
+4 -1
View File
@@ -111,7 +111,10 @@ fn wave_warp(e: &mut Enc, ctx: &EffectCtx, mut b: GBuf) -> Option<GBuf> {
let dir = ctx.params.f("direction").to_radians();
let speed = ctx.params.f("speed");
let phase = ctx.params.f("phase").to_radians() + ctx.time * speed * TAU;
let (dx, dy) = (dir.sin(), -dir.cos());
// Cardinal directions must not acquire a tiny perpendicular slope: at a square-wave
// boundary cos(90°)'s rounding residue can flip a whole column on CPU but not GPU.
let axis = |v: f64| if v.abs() < 4.0 * f64::EPSILON { 0.0 } else { v };
let (dx, dy) = (axis(dir.sin()), -axis(dir.cos()));
if !ctx.adjustment {
b.pad(e, h.abs().ceil() as u32 + 1)?;
}
+8
View File
@@ -28,6 +28,11 @@ fn twirl_bulge_ripple_wave_warp() {
effect_case("ec.distort.wavewarp", &[("waveType", e(2)), ("pinning", e(1)), ("phase", n(400.0)), ("speed", n(-2.0))]);
effect_case("ec.distort.wavewarp", &[("waveType", e(8)), ("pinning", e(2)), ("height", n(-5.0)), ("direction", n(200.0))]);
effect_case("ec.distort.wavewarp", &[("waveType", e(4)), ("pinning", e(7)), ("width", n(33.0))]);
// #1181: the single-edge pinning paths, with the default vertical displacement direction.
effect_case("ec.distort.wavewarp", &[("direction", n(90.0)), ("height", n(7.0)), ("width", n(25.0)), ("pinning", e(4))]);
effect_case("ec.distort.wavewarp", &[("direction", n(90.0)), ("height", n(7.0)), ("width", n(19.0)), ("pinning", e(6)), ("waveType", e(1))]);
effect_case("ec.distort.wavewarp", &[("direction", n(45.0)), ("height", n(-6.0)), ("pinning", e(4)), ("speed", n(2.0))]);
effect_case("ec.distort.wavewarp", &[("direction", n(45.0)), ("height", n(-6.0)), ("pinning", e(6)), ("speed", n(2.0))]);
}
#[test]
@@ -79,6 +84,9 @@ fn shape_case(id: &str, vals: &[(&str, Value)]) {
fn edge_pinning_on_a_shape_layer() {
shape_case("ec.distort.turbulentdisplace", &[("size", n(30.0)), ("amount", n(20.0))]);
shape_case("ec.distort.wavewarp", &[("pinning", e(1)), ("height", n(6.0)), ("width", n(25.0))]);
// #1181: single-edge pinning over the layer rect, not just All Edges.
shape_case("ec.distort.wavewarp", &[("pinning", e(4)), ("direction", n(90.0)), ("height", n(6.0)), ("width", n(25.0))]);
shape_case("ec.distort.wavewarp", &[("pinning", e(6)), ("direction", n(90.0)), ("height", n(6.0)), ("width", n(25.0))]);
shape_case(
"ec.distort.bulge",
&[("pinAllEdges", on()), ("height", n(2.0)), ("hradius", n(40.0)), ("vradius", n(30.0)), ("center", Value::Vec2([28.5, 20.5]))],