From 36a50a63666f4bb183c7f4051edcf0ac731ffa4b Mon Sep 17 00:00:00 2001 From: Minher0 Date: Tue, 27 Oct 2026 09:46:32 +0000 Subject: [PATCH] layer.create: the instance copy takes the source's Solo switch A soloed model keeps its Solo switch with its video off, and any_solo hides non-soloed layers: the copy was excluded and the comp rendered blank. The copy now takes the Solo over; the source's video stays off. Covered by instance3d_keeps_the_copy_visible_when_the_source_is_soloed. --- crates/engine/src/cmd/create.rs | 3 +++ crates/engine/src/tests/instance3d.rs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/crates/engine/src/cmd/create.rs b/crates/engine/src/cmd/create.rs index b9aa49424..246108371 100644 --- a/crates/engine/src/cmd/create.rs +++ b/crates/engine/src/cmd/create.rs @@ -52,6 +52,9 @@ fn create(s: &mut Session, p: &Value) -> Result { ItemKind::Solid(Solid { color: [1.0, 1.0, 1.0], width: comp.width, height: comp.height, pixel_aspect: 1.0 }), ); let mut l = build::layer(proj, &comp, &name, LayerSource::Solid { item: sid }, (comp.width, comp.height), None); + // A soloed source keeps its Solo switch with video off, and any_solo hides + // the non-soloed copy: the copy takes the Solo over to stay visible. + l.switches.solo = src.switches.solo; // CC Composite referencing the 3D layer: the solid shows its render (the 2D // copy). let fx = effectcraft_effects::find("ec.channel.cccomposite").ok_or_else(|| bad("layer.create", "the CC Composite effect is missing"))?; diff --git a/crates/engine/src/tests/instance3d.rs b/crates/engine/src/tests/instance3d.rs index aa31d3944..73577a0a8 100644 --- a/crates/engine/src/tests/instance3d.rs +++ b/crates/engine/src/tests/instance3d.rs @@ -231,3 +231,27 @@ fn instance3d_shows_nothing_outside_the_source_layer_range() { let outside = s.render(comp, Tick::from_seconds_f64(1.5), RenderOpts::default()); assert!(outside.data.iter().all(|p| p[3] < 1e-3), "transparent after the source's out point: {:?}", px(&outside, 320, 180)); } + +#[test] +fn instance3d_keeps_the_copy_visible_when_the_source_is_soloed() { + let mut s = session(); + let model = triangle_model(&mut s); + let comp = cid(&s); + // Solo the model, then create the instance: any_solo hides non-soloed layers and the + // source's video goes off, so the copy has to take the Solo over. + s.edit("solo", None, |p, _| { + p.comp_mut(comp).unwrap().layer_mut(LayerId(model)).unwrap().switches.solo = true; + Ok(()) + }) + .unwrap(); + let before = s.render(comp, Tick::ZERO, RenderOpts::default()); + assert!(px(&before, 320, 180)[3] > 0.9, "the soloed model shows: {:?}", px(&before, 320, 180)); + s.execute("layer.select", json!({"layers": [model]})).unwrap(); + let r = s.execute("layer.create", json!({"op": "instance3d"})).unwrap(); + let solid = r["layers"][0].as_u64().unwrap(); + assert!(layer_in(&s, comp, solid).switches.solo, "the copy takes the source's Solo switch"); + assert!(!layer_in(&s, comp, model).switches.video, "the source keeps its video off"); + let after = s.render(comp, Tick::ZERO, RenderOpts::default()); + assert!(px(&after, 320, 180)[3] > 0.9, "the soloed copy shows the model: {:?}", px(&after, 320, 180)); + assert!(close(&before, &after, 2e-2), "the comp renders the same through the copy:\n{:?}\n{:?}", px(&before, 320, 180), px(&after, 320, 180)); +}