Skip to content

Commit 34d0b76

Browse files
snskarKeavon
andauthored
Fix drawing over erased Brush tool paths (#3262)
fix draw over erased behaviour Co-authored-by: Keavon Chambers <keavon@keavon.com>
1 parent 497758c commit 34d0b76

File tree

1 file changed

+17
-26
lines changed

1 file changed

+17
-26
lines changed

node-graph/gbrush/src/brush.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
194194
let background_bounds = bbox.to_transform();
195195

196196
let mut draw_strokes: Vec<_> = strokes.iter().filter(|&s| !matches!(s.style.blend_mode, BlendMode::Erase | BlendMode::Restore)).cloned().collect();
197-
let erase_restore_strokes: Vec<_> = strokes.iter().filter(|&s| matches!(s.style.blend_mode, BlendMode::Erase | BlendMode::Restore)).cloned().collect();
198197

199198
let mut brush_plan = cache.compute_brush_plan(table_row, &draw_strokes);
200199

@@ -258,16 +257,16 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
258257
actual_image = blend_with_mode(actual_image, stroke_texture, stroke.style.blend_mode, (stroke.style.color.a() * 100.) as f64);
259258
}
260259

261-
let has_erase_strokes = strokes.iter().any(|s| s.style.blend_mode == BlendMode::Erase);
262-
if has_erase_strokes {
260+
let has_erase_or_restore_strokes = strokes.iter().any(|s| matches!(s.style.blend_mode, BlendMode::Erase | BlendMode::Restore));
261+
if has_erase_or_restore_strokes {
263262
let opaque_image = Image::new(bbox.size().x as u32, bbox.size().y as u32, Color::WHITE);
264263
let mut erase_restore_mask = TableRow {
265264
element: Raster::new_cpu(opaque_image),
266265
transform: background_bounds,
267266
..Default::default()
268267
};
269268

270-
for stroke in erase_restore_strokes {
269+
for stroke in strokes {
271270
let mut brush_texture = cache.get_cached_brush(&stroke.style);
272271
if brush_texture.is_none() {
273272
let tex = create_brush_texture(&stroke.style).await;
@@ -277,28 +276,20 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
277276
let brush_texture = brush_texture.unwrap();
278277
let positions: Vec<_> = stroke.compute_blit_points().into_iter().collect();
279278

280-
match stroke.style.blend_mode {
281-
BlendMode::Erase => {
282-
let blend_params = FnNode::new(|(a, b)| blend_colors(a, b, BlendMode::Erase, 1.));
283-
let blit_node = BlitNode::new(
284-
FutureWrapperNode::new(ClonedNode::new(brush_texture)),
285-
FutureWrapperNode::new(ClonedNode::new(positions)),
286-
FutureWrapperNode::new(ClonedNode::new(blend_params)),
287-
);
288-
erase_restore_mask = blit_node.eval(Table::new_from_row(erase_restore_mask)).await.into_iter().next().unwrap_or_default();
289-
}
290-
// Yes, this is essentially the same as the above, but we duplicate to inline the blend mode.
291-
BlendMode::Restore => {
292-
let blend_params = FnNode::new(|(a, b)| blend_colors(a, b, BlendMode::Restore, 1.));
293-
let blit_node = BlitNode::new(
294-
FutureWrapperNode::new(ClonedNode::new(brush_texture)),
295-
FutureWrapperNode::new(ClonedNode::new(positions)),
296-
FutureWrapperNode::new(ClonedNode::new(blend_params)),
297-
);
298-
erase_restore_mask = blit_node.eval(Table::new_from_row(erase_restore_mask)).await.into_iter().next().unwrap_or_default();
299-
}
300-
_ => unreachable!(),
301-
}
279+
// For mask composition: Erase subtracts alpha, Restore adds alpha, and Draw acts like Restore to allow repainting erased areas.
280+
let mask_blend_mode = match stroke.style.blend_mode {
281+
BlendMode::Erase => BlendMode::Erase,
282+
BlendMode::Restore => BlendMode::Restore,
283+
_ => BlendMode::Restore,
284+
};
285+
286+
let blend_params = FnNode::new(move |(a, b)| blend_colors(a, b, mask_blend_mode, 1.));
287+
let blit_node = BlitNode::new(
288+
FutureWrapperNode::new(ClonedNode::new(brush_texture)),
289+
FutureWrapperNode::new(ClonedNode::new(positions)),
290+
FutureWrapperNode::new(ClonedNode::new(blend_params)),
291+
);
292+
erase_restore_mask = blit_node.eval(Table::new_from_row(erase_restore_mask)).await.into_iter().next().unwrap_or_default();
302293
}
303294

304295
let blend_params = FnNode::new(|(a, b)| blend_colors(a, b, BlendMode::MultiplyAlpha, 1.));

0 commit comments

Comments
 (0)