From 28c63ce72807015de358d39f4c4c99cee09d3149 Mon Sep 17 00:00:00 2001 From: arnav-hiwarkar Date: Thu, 12 Nov 2026 16:30:24 +0530 Subject: [PATCH] #3535: the analysis key leaves out the effects above while the Effects switch is off The renderer skips the whole effect stack then, so editing those effects doesn't change the analysed frames. Roto Brush Input Keys keep their text. --- crates/engine/src/analysis/frames_key.rs | 11 +++++++---- crates/engine/src/tests/analysis_inputs.rs | 7 +++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/engine/src/analysis/frames_key.rs b/crates/engine/src/analysis/frames_key.rs index c43b3e92b..abbafde67 100644 --- a/crates/engine/src/analysis/frames_key.rs +++ b/crates/engine/src/analysis/frames_key.rs @@ -88,7 +88,7 @@ pub(crate) fn input_key_of(signature: String, layer: &Layer, uid: Uid) -> String let mut t = Text::new(); t.word(VERSION); t.word(&signature); - t.inputs_above(layer, uid); + t.inputs_above(layer, uid, true); hex(&t.0) } @@ -107,7 +107,8 @@ pub(crate) fn analysis_key(p: &Project, comp: ItemId, layer: &Layer, uid: Uid) - if layer.effects().and_then(|fx| fx.groups().next()).is_some_and(|g| g.uid != uid) { t.field("effectsSwitch", layer.switches.effects); } - t.inputs_above(layer, uid); + // While it is off the renderer skips the whole effect stack: the effects above draw nothing. + t.inputs_above(layer, uid, layer.switches.effects); t.precomp(p, comp, layer); hex(&t.0) } @@ -392,14 +393,16 @@ impl Text { /// The layer's masks and the effects above the instance `uid`: what the effect's input is /// made of besides the layer's frames. - fn inputs_above(&mut self, layer: &Layer, uid: Uid) { + /// `effects`: whether to write the effects (a Roto Brush Input Key always does: frozen mattes + /// hash the saved key, so it keeps its text). + fn inputs_above(&mut self, layer: &Layer, uid: Uid, effects: bool) { if let Some(m) = layer.masks() { self.word("masks"); self.group(m, 0); } if let Some(fx) = layer.effects() { self.word("effects"); - for g in fx.groups().take_while(|g| g.uid != uid) { + for g in fx.groups().take_while(|g| effects && g.uid != uid) { self.group(g, 0); } } diff --git a/crates/engine/src/tests/analysis_inputs.rs b/crates/engine/src/tests/analysis_inputs.rs index a6722a731..b45b38eda 100644 --- a/crates/engine/src/tests/analysis_inputs.rs +++ b/crates/engine/src/tests/analysis_inputs.rs @@ -107,6 +107,13 @@ fn masks_and_effects_above(saved: Saved) { assert_eq!(analysed(&s), [true, true]); // The Effects switch turns the Warp Stabilizer (above the tracker) off. check(&mut s, "layer.setSwitch", json!({"layers": [CLIP.0], "switch": "effects", "value": false}), [true, false]); + // While it is off, the effects above draw nothing: editing them keeps the analyses. + run(&mut s, "layer.setSwitch", json!({"layers": [CLIP.0], "switch": "effects", "value": false})); + analyse(&mut s, saved); + check(&mut s, "prop.set", json!({"layer": CLIP.0, "path": "effects/#1/stabilization/smoothness", "value": 20}), [true, true]); + run(&mut s, "layer.setSwitch", json!({"layers": [CLIP.0], "switch": "effects", "value": true})); + assert_eq!(analysed(&s), [true, false]); + analyse(&mut s, saved); // An effect moved above the Warp Stabilizer is part of both inputs, and its settings too. s.edit("blur first", None, |p, _| {