mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 04:57:54 -06:00
Lottie: import every Dash/Gap pair of a stroke, not only the first dash and the last gap
This commit is contained in:
+27
-12
@@ -3,8 +3,8 @@
|
||||
|
||||
use effectcraft_color::BlendMode;
|
||||
use effectcraft_keyframe::{Gradient, ShapePath, Value};
|
||||
use effectcraft_project::build::{self, Ids};
|
||||
use effectcraft_project::{Node, PropGroup};
|
||||
use effectcraft_project::build::{self, EXTRA_DASHES, Ids};
|
||||
use effectcraft_project::{Node, ParamUi, PropGroup};
|
||||
use serde_json::{Map, Value as Json, json};
|
||||
|
||||
use crate::anim::{self, Ex, Im, export_prop, import_prop};
|
||||
@@ -356,7 +356,7 @@ fn import_blend(j: &Json, g: &mut PropGroup) {
|
||||
}
|
||||
}
|
||||
|
||||
fn import_stroke(im: &Im, j: &Json, g: &mut PropGroup) {
|
||||
fn import_stroke(im: &Im, ids: &mut Ids, j: &Json, g: &mut PropGroup) {
|
||||
set(im, g, "width", j.get("w"), &anim::to_scalar);
|
||||
if let Some(lc) = int(j, "lc") {
|
||||
set_enum(g, "cap", lc.saturating_sub(1).clamp(0, 2) as u32);
|
||||
@@ -374,17 +374,32 @@ fn import_stroke(im: &Im, j: &Json, g: &mut PropGroup) {
|
||||
if let Some(list) = j.get("d").and_then(Json::as_array)
|
||||
&& let Some(d) = g.sub_mut("dashes")
|
||||
{
|
||||
let mut seen_dash = false;
|
||||
// The n-th `d` and `g` are the n-th Dash/Gap pair; the extra pairs are created as the Dashes "+" does.
|
||||
let (mut dashes, mut gaps) = (0, 0);
|
||||
for e in list {
|
||||
let m = match e.get("n").and_then(Json::as_str) {
|
||||
Some("d") if !seen_dash => {
|
||||
seen_dash = true;
|
||||
"dash"
|
||||
let (n, pair) = match e.get("n").and_then(Json::as_str) {
|
||||
Some("d") => (&mut dashes, 0),
|
||||
Some("g") => (&mut gaps, 1),
|
||||
Some("o") => {
|
||||
set(im, d, "offset", e.get("v"), &anim::to_scalar);
|
||||
continue;
|
||||
}
|
||||
Some("g") => "gap",
|
||||
Some("o") => "offset",
|
||||
_ => continue,
|
||||
};
|
||||
let k = *n;
|
||||
*n += 1;
|
||||
let m = match k {
|
||||
0 => ["dash", "gap"][pair],
|
||||
_ => {
|
||||
let Some(&(dm, gm)) = EXTRA_DASHES.get(k - 1) else { continue };
|
||||
if d.get(dm).is_none() {
|
||||
let at = d.children.iter().position(|c| c.match_id() == "offset").unwrap_or(d.children.len());
|
||||
d.children.insert(at, ids.prop(gm, &format!("Gap {}", k + 1), Value::Scalar(0.0)).with_ui(ParamUi::Pixels).into());
|
||||
d.children.insert(at, ids.prop(dm, &format!("Dash {}", k + 1), Value::Scalar(0.0)).with_ui(ParamUi::Pixels).into());
|
||||
}
|
||||
[dm, gm][pair]
|
||||
}
|
||||
};
|
||||
set(im, d, m, e.get("v"), &anim::to_scalar);
|
||||
}
|
||||
}
|
||||
@@ -474,7 +489,7 @@ pub(crate) fn import_items(im: &mut Im, ids: &mut Ids, items: &[Json]) -> Vec<Pr
|
||||
let mut g = build::shape_stroke(ids, [1.0, 1.0, 1.0, 1.0], 2.0);
|
||||
set(im, &mut g, "color", j.get("c"), &anim::to_color);
|
||||
set(im, &mut g, "opacity", j.get("o"), &anim::to_scalar);
|
||||
import_stroke(im, j, &mut g);
|
||||
import_stroke(im, ids, j, &mut g);
|
||||
import_blend(j, &mut g);
|
||||
g
|
||||
}
|
||||
@@ -501,7 +516,7 @@ pub(crate) fn import_items(im: &mut Im, ids: &mut Ids, items: &[Json]) -> Vec<Pr
|
||||
set_enum(&mut g, "rule", 1);
|
||||
}
|
||||
} else {
|
||||
import_stroke(im, j, &mut g);
|
||||
import_stroke(im, ids, j, &mut g);
|
||||
}
|
||||
import_blend(j, &mut g);
|
||||
g
|
||||
|
||||
@@ -407,6 +407,30 @@ fn offset_paths_miter_uses_animatable_lottie_value() {
|
||||
assert_eq!(second.get("miter").unwrap().value, Value::Scalar(6.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extra_dash_gap_pairs_survive_a_roundtrip() {
|
||||
let (mut p, cid) = setup();
|
||||
let l = shape_layer(&mut p, cid, |ids| {
|
||||
let mut stroke = build::shape_stroke(ids, [0.0, 0.0, 1.0, 1.0], 3.0);
|
||||
let d = stroke.sub_mut("dashes").unwrap();
|
||||
d.get_mut("dash").unwrap().value = Value::Scalar(10.0);
|
||||
d.get_mut("gap").unwrap().value = Value::Scalar(5.0);
|
||||
let at = d.children.iter().position(|n| n.match_id() == "offset").unwrap();
|
||||
d.children.insert(at, ids.prop("gap2", "Gap 2", Value::Scalar(3.0)).into());
|
||||
d.children.insert(at, ids.prop("dash2", "Dash 2", Value::Scalar(20.0)).into());
|
||||
let rect = build::shape_rect(ids, [60.0, 40.0], [0.0, 0.0], 0.0);
|
||||
vec![build::shape_group(ids, "G", vec![rect, stroke])]
|
||||
});
|
||||
push(&mut p, cid, l);
|
||||
let (q, nc, _, _) = roundtrip(&p, cid, &ExportOptions::default());
|
||||
let c = q.comp(nc).unwrap();
|
||||
let g = c.layers[0].props.sub("contents").unwrap().groups().next().unwrap();
|
||||
let stroke = g.sub("contents").unwrap().groups().find(|g| g.match_id == "stroke").unwrap();
|
||||
let d = stroke.sub("dashes").unwrap();
|
||||
let v = |m: &str| d.get(m).map(|p| p.value.as_f64());
|
||||
assert_eq!((v("dash"), v("gap"), v("dash2"), v("gap2")), (Some(10.0), Some(5.0), Some(20.0), Some(3.0)));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- layers
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user