mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 03:06:57 -06:00
Render: brush art is made again when a symbol or pattern it shows is renamed
The brush cache dropped brush art that can show a symbol or a pattern only when the art of the document's symbols or patterns changed. Renaming one, for example swapping the names of two symbols, left their art as it was, so a brush whose art holds an instance of one of those names kept drawing the old symbol. The cache now compares the names along with the art.
This commit is contained in:
@@ -46,9 +46,9 @@ fn shows_definitions(brush: &Brush, st: &StrokeLayer) -> bool {
|
||||
matches!(st.paint, vectorcraft_color::Paint::Pattern { .. }) || crate::fx::Reads::of_all(art.into_iter()).shows_definitions()
|
||||
}
|
||||
|
||||
/// The art of `doc`'s patterns and symbols, in order.
|
||||
fn definitions(doc: &Document) -> impl Iterator<Item = &Arc<Node>> {
|
||||
doc.patterns.iter().flat_map(|p| &p.art).chain(doc.symbols.iter().map(|s| &s.art))
|
||||
/// The names and art of `doc`'s patterns and symbols, in order.
|
||||
fn definitions(doc: &Document) -> impl Iterator<Item = (&str, &Arc<Node>)> {
|
||||
doc.patterns.iter().flat_map(|p| p.art.iter().map(|a| (p.name.as_str(), a))).chain(doc.symbols.iter().map(|s| (s.name.as_str(), &s.art)))
|
||||
}
|
||||
|
||||
/// Parsed brush library and generated brush art.
|
||||
@@ -61,9 +61,9 @@ pub(crate) struct BrushCache {
|
||||
/// (frame stamp, document address) the library was last validated for.
|
||||
checked: (u64, usize),
|
||||
lib: HashMap<String, Arc<Brush>>,
|
||||
/// The art of the document's patterns and symbols ([`definitions`]) when the library was last
|
||||
/// validated, held weakly as the pattern tiles hold theirs.
|
||||
definitions: Vec<Weak<Node>>,
|
||||
/// The names and art of the document's patterns and symbols ([`definitions`]) when the library
|
||||
/// was last validated, the art held weakly as the pattern tiles hold theirs.
|
||||
definitions: Vec<(String, Weak<Node>)>,
|
||||
/// Brush art per (node id, stroke item index, [`path_key`] of the stroked path).
|
||||
pub(crate) entries: FrameCache<(u64, usize, u64), Entry>,
|
||||
/// How many times [`Renderer::draw_brush`] made brush art.
|
||||
@@ -93,8 +93,8 @@ impl BrushCache {
|
||||
return;
|
||||
}
|
||||
self.checked = key;
|
||||
if !self.definitions.iter().map(Weak::as_ptr).eq(definitions(doc).map(Arc::as_ptr)) {
|
||||
self.definitions = definitions(doc).map(Arc::downgrade).collect();
|
||||
if !self.definitions.iter().map(|(n, a)| (n.as_str(), a.as_ptr())).eq(definitions(doc).map(|(n, a)| (n, Arc::as_ptr(a)))) {
|
||||
self.definitions = definitions(doc).map(|(n, a)| (n.to_string(), Arc::downgrade(a))).collect();
|
||||
self.entries.retain(|e| !e.definitions);
|
||||
}
|
||||
let cur = doc.unknown.get(vectorcraft_brush::DOC_KEY);
|
||||
|
||||
@@ -801,6 +801,68 @@ fn brush_art_draws_edits_of_the_symbols_and_patterns_it_shows() {
|
||||
}
|
||||
}
|
||||
|
||||
/// As above, with symbols `Dot` (a blue square) and `Other` (a red square with a brushed line),
|
||||
/// and patterns `Fill` (a green square) and `Spare` (a red square with a brushed line). After a
|
||||
/// frame, the next one draws as a new renderer does when two symbols or two patterns swap names,
|
||||
/// their art left as it is: the brush art's instance of `Dot` or its square painted with `Fill`
|
||||
/// then shows art that draws a brushed stroke.
|
||||
#[test]
|
||||
fn brush_art_draws_renamed_symbols_and_patterns_it_shows() {
|
||||
let _fonts = fonts_steady();
|
||||
use vectorcraft_brush::{Brush, BrushKind, Scatter};
|
||||
use vectorcraft_doc::pattern::{PatternDef, pattern_paint};
|
||||
use vectorcraft_geom::shapes::{line, rectangle};
|
||||
let square = |d: &mut Document, paint: Paint| filled(d, rectangle(Rect::new(-4.0, -4.0, 4.0, 4.0)), paint, vec![]);
|
||||
let art = |d: &mut Document, paint: Paint, brushed: bool| {
|
||||
let mut members = vec![Arc::new(square(d, paint))];
|
||||
if brushed {
|
||||
members.push(Arc::new(brushed_line(d)));
|
||||
}
|
||||
Node::group(d.alloc_id(), members)
|
||||
};
|
||||
let doc = || {
|
||||
let mut d = Document::new(200.0, 100.0);
|
||||
for (name, paint, brushed) in
|
||||
[("Dot", Paint::solid(Color::rgb(0.0, 0.0, 1.0)), false), ("Other", Paint::solid(Color::rgb(1.0, 0.0, 0.0)), true)]
|
||||
{
|
||||
let a = art(&mut d, paint, brushed);
|
||||
d.symbols.push(vectorcraft_doc::Symbol { name: name.into(), art: Arc::new(a) });
|
||||
}
|
||||
for (name, paint, brushed) in
|
||||
[("Fill", Paint::solid(Color::rgb(0.0, 0.6, 0.0)), false), ("Spare", Paint::solid(Color::rgb(1.0, 0.0, 0.0)), true)]
|
||||
{
|
||||
let a = art(&mut d, paint, brushed);
|
||||
let mut def = PatternDef::new(name, vec![Arc::new(a)]);
|
||||
def.tile = Rect::new(-6.0, -6.0, 6.0, 6.0);
|
||||
d.patterns.push(def);
|
||||
}
|
||||
let id = d.alloc_id();
|
||||
let instance = Node::new(id, NodeKind::SymbolInstance { symbol: "Dot".into(), xf: Affine::translate((0.0, -8.0)) });
|
||||
let mut painted = square(&mut d, pattern_paint("Fill"));
|
||||
painted.transform(Affine::translate((0.0, 8.0)), true);
|
||||
let scatter = Node::group(d.alloc_id(), vec![Arc::new(instance), Arc::new(painted)]);
|
||||
let mut lib = vectorcraft_brush::library(&d);
|
||||
lib.push(Brush { name: "Dots".into(), kind: BrushKind::Scatter(Scatter { art: scatter, spacing: (150.0, 150.0), ..Default::default() }) });
|
||||
vectorcraft_brush::store(&mut d, &lib);
|
||||
let mut ap = vectorcraft_doc::Appearance::basic(Paint::None, Paint::solid(Color::BLACK), 1.0);
|
||||
if let Some(s) = ap.stroke_mut() {
|
||||
s.brush = Some("Dots".into());
|
||||
}
|
||||
let path = Node::path(d.alloc_id(), line((20.0, 50.0).into(), (180.0, 50.0).into()), ap);
|
||||
let l = d.layers[0].id;
|
||||
d.insert(Some(l), usize::MAX, path).unwrap();
|
||||
d
|
||||
};
|
||||
edit_draws_as_new(doc(), |d| {
|
||||
d.symbols[0].name = "Other".into();
|
||||
d.symbols[1].name = "Dot".into();
|
||||
});
|
||||
edit_draws_as_new(doc(), |d| {
|
||||
d.patterns[0].name = "Spare".into();
|
||||
d.patterns[1].name = "Fill".into();
|
||||
});
|
||||
}
|
||||
|
||||
/// A path of the document and an instance of symbol `Wave` (a group holding another path) are
|
||||
/// stroked with scatter brush `Bent`, whose art is an arc envelope around a green band: the second
|
||||
/// frame evaluates none of the envelopes in their brush art again, and draws what the first drew
|
||||
|
||||
Reference in New Issue
Block a user