From 48738093b571322646247cfc91921aff804fce95 Mon Sep 17 00:00:00 2001 From: Vikram Bhaskaran Date: Wed, 14 Oct 2026 00:02:12 +1100 Subject: [PATCH] Shapes: Merge Paths keeps paint that belongs to a group above it (#1174) A Merge Paths item appended to a shape layer's Contents cleared every draw collected so far, including fills and strokes inside groups above it, so the layer's shapes vanished from the render. AE's rule is per group: only paint items in the merge's own group above it are dropped. Draws now record which contents level created them; the merge drops only its own group's paint, and the group-bubbled draws keep rendering. Adds a regression test (Merge Shapes and Add modes) that renders nothing without the fix. --- crates/render/src/shapes.rs | 13 +++++++++++-- crates/render/src/shapes/tests.rs | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/crates/render/src/shapes.rs b/crates/render/src/shapes.rs index aa46fa50..d5e1d5b8 100644 --- a/crates/render/src/shapes.rs +++ b/crates/render/src/shapes.rs @@ -57,6 +57,10 @@ struct Draw { blend: BlendMode, /// Front / Bevel / Side / Back colours of the paint's extrusion (Advanced 3D). surfaces: SurfaceColors, + /// Paint item of the contents group this draw was collected in (as opposed to one bubbled up + /// from a nested group). Merge Paths drops only these paints above it (#1174); a group's own + /// fill or stroke keeps rendering inside the group. + local: bool, } /// Straight RGB colours of an extrusion's surfaces, by [`effectcraft_model::extrude::Surface`] @@ -234,6 +238,7 @@ fn collect(ctx: &EvalCtx, layer: &Layer, contents: &PropGroup, arena: &mut Vec { @@ -247,6 +252,7 @@ fn collect(ctx: &EvalCtx, layer: &Layer, contents: &PropGroup, arena: &mut Vec { @@ -270,6 +276,7 @@ fn collect(ctx: &EvalCtx, layer: &Layer, contents: &PropGroup, arena: &mut Vec { @@ -328,8 +335,9 @@ fn collect(ctx: &EvalCtx, layer: &Layer, contents: &PropGroup, arena: &mut Vec { let Some(inner) = g.sub("contents") else { continue }; @@ -341,6 +349,7 @@ fn collect(ctx: &EvalCtx, layer: &Layer, contents: &PropGroup, arena: &mut Vec 0.99 && c[1] < 0.01 && c[3] > 0.99, "mode {mode}: group rectangle must still render, got {c:?}"); + assert!((coverage(&img) - 40.0 * 40.0).abs() < 20.0, "mode {mode}: {}", coverage(&img)); + } +} + #[test] fn merge_subtract_and_intersect() { let sub = |mode: u32| {