mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-24 10:09:32 -06:00
Merge pull request #1302 from vbasky/fix/1194-liquify-offset
Liquify: expose Distortion Mesh Offset in Effect Controls (#1194)
This commit is contained in:
@@ -589,7 +589,7 @@ pub fn specs() -> Vec<EffectSpec> {
|
||||
p("meshColor", "Mesh Color", col(0.5, 0.5, 0.5), ParamUi::Color),
|
||||
// The strokes (see `LiquifyStroke`); written by the `liquify.stroke` command.
|
||||
p("distortionMesh", "Distortion Mesh", Value::Str(String::new()), ParamUi::Hidden),
|
||||
p("distortionMeshOffset", "Distortion Mesh Offset", Value::Vec2([0.0, 0.0]), ParamUi::Hidden),
|
||||
p("distortionMeshOffset", "Distortion Mesh Offset", Value::Vec2([0.0, 0.0]), ParamUi::Point),
|
||||
p("distortionPercentage", "Distortion Percentage", num(100.0), slider(0.0, 200.0, 0.0, 200.0, 1)),
|
||||
p("distortionDisplayQuality", "Distortion Display Quality", Value::Enum(1), popup(&["Draft", "Smooth"])),
|
||||
],
|
||||
@@ -672,6 +672,35 @@ mod tests {
|
||||
assert_eq!(zero.img.data, img.data);
|
||||
let again = run_fx("ec.distort.liquify", &[("distortionMesh", Value::Str(s.to_line()))], img.clone(), 0.0, EffectEnv::default());
|
||||
assert_eq!(out.img.data, again.img.data);
|
||||
// #1194: Distortion Mesh Offset is an exposed, editable control (AE's Distortion ▸
|
||||
// Offset) and it moves the mesh: the pattern rendered at x renders at x + offset.
|
||||
let spec = crate::find("ec.distort.liquify").unwrap();
|
||||
assert!(
|
||||
spec.params.iter().any(|ps| ps.id == "distortionMeshOffset" && ps.ui == effectcraft_project::ParamUi::Point),
|
||||
"offset is shown in Effect Controls"
|
||||
);
|
||||
let shifted = run_fx(
|
||||
"ec.distort.liquify",
|
||||
&[("distortionMesh", Value::Str(s.to_line())), ("distortionMeshOffset", Value::Vec2([20.0, 0.0]))],
|
||||
img.clone(),
|
||||
0.0,
|
||||
EffectEnv::default(),
|
||||
);
|
||||
assert_ne!(shifted.img.data, out.img.data, "the offset changes the render");
|
||||
// The displaced region's centroid moves right by the offset (the mesh is sampled at
|
||||
// layer minus offset), and the row far left of the shifted mesh is back to untouched.
|
||||
let centroid = |o: &Image| -> f32 {
|
||||
let (mut wsum, mut msum) = (0.0f32, 0.0f32);
|
||||
for (i, (p, q)) in o.data.iter().zip(img.data.iter()).enumerate() {
|
||||
let d: f32 = (0..4).map(|k| (p[k] - q[k]).abs()).sum();
|
||||
wsum += d;
|
||||
msum += d * (i % 64) as f32;
|
||||
}
|
||||
if wsum > 1e-6 { msum / wsum } else { 0.0 }
|
||||
};
|
||||
let (co, cs) = (centroid(&out.img), centroid(&shifted.img));
|
||||
assert!((cs - co - 20.0).abs() < 5.0, "centroids {co} -> {cs}");
|
||||
assert_eq!(shifted.img.get(5, 32), img.get(5, 32), "left of the shifted mesh: untouched");
|
||||
// Reconstruction undoes the warp; freeze protects.
|
||||
let mut rec = s.clone();
|
||||
rec.tool = 9;
|
||||
|
||||
@@ -239,6 +239,8 @@ fn refresh(pr: &mut Property, ps: &ParamSpec, spec: &EffectSpec) {
|
||||
// A path typed as text, or set only by commands, that got a Choose… button (Apply Color
|
||||
// LUT's LUT, the OCIO files, #514).
|
||||
(ParamUi::Hidden | ParamUi::Text, ParamUi::File { .. }) => pr.ui = ps.ui.clone(),
|
||||
// An internal point that became a control (Liquify's Distortion Mesh Offset, #1194).
|
||||
(ParamUi::Hidden, ParamUi::Point) => pr.ui = ParamUi::Point,
|
||||
// Same kind of value: take the spec's hints (units, ranges).
|
||||
(a, b) if std::mem::discriminant(a) == std::mem::discriminant(b) || is_numeric_ui(a) && is_numeric_ui(b) => pr.ui = ps.ui.clone(),
|
||||
_ => {}
|
||||
@@ -514,6 +516,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// #1194: Liquify's Distortion Mesh Offset was hidden; old projects show it, keeping its value.
|
||||
#[test]
|
||||
fn a_hidden_point_that_became_a_control_is_shown() {
|
||||
let mut next = 1;
|
||||
let (spec, mut g) = instance("ec.distort.liquify", &mut next);
|
||||
let pr = g.get_mut("distortionMeshOffset").unwrap();
|
||||
pr.ui = ParamUi::Hidden;
|
||||
pr.value = Value::Vec2([20.0, -5.0]);
|
||||
assert!(upgrade_instance(spec, &mut g, &mut Ids(&mut next), [100.0, 100.0]));
|
||||
let pr = g.get("distortionMeshOffset").unwrap();
|
||||
assert_eq!((&pr.ui, &pr.value), (&ParamUi::Point, &Value::Vec2([20.0, -5.0])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upgrade_moves_params_into_twirl_down_groups() {
|
||||
let spec = find(crate::warp_stab::ID).unwrap();
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ Effects are addressed by id (`ec.<category>.<name>`) or display name in commands
|
||||
| Corner Pin | `ec.distort.cornerpin` | 4 | GPU | 32 | Implemented |
|
||||
| Detail-preserving Upscale | `ec.distort.upscale` | 4 | | 32 | Implemented |
|
||||
| Displacement Map | `ec.distort.displacementmap` | 8 | GPU | 32 | Implemented |
|
||||
| Liquify | `ec.distort.liquify` | 12 | GPU | 32 | Implemented |
|
||||
| Liquify | `ec.distort.liquify` | 13 | GPU | 32 | Implemented |
|
||||
| Magnify | `ec.distort.magnify` | 10 | GPU | 32 | Implemented |
|
||||
| Mesh Warp | `ec.distort.meshwarp` | 3 | GPU | 32 | Implemented |
|
||||
| Mirror | `ec.distort.mirror` | 2 | GPU | 32 | Implemented |
|
||||
|
||||
Reference in New Issue
Block a user