mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 08:29:14 +00:00
Effects: an object's Transform effect moves its fills' raster effects beside a fill's 3D effect
When only a fill or stroke has an Extrude & Bevel, Inflate, Rotate or Revolve effect, the object's Transform effects reshape the path, and now the raster effects of every fill and stroke follow them too, as they do on an object without a 3D effect: a shadow after the fill's 3D effect and another fill's shadow scale and turn with the art.
This commit is contained in:
@@ -5,7 +5,7 @@ use std::borrow::Cow;
|
||||
use serde_json::{Map, Value, json};
|
||||
use vectorcraft_doc::color::{BlendMode, Color};
|
||||
use vectorcraft_doc::rastersettings::MAX_ADD_AROUND;
|
||||
use vectorcraft_doc::{Effect, Node, RasterColorModel, RasterEffectsSettings};
|
||||
use vectorcraft_doc::{AppearanceItem, Effect, Node, RasterColorModel, RasterEffectsSettings};
|
||||
|
||||
use vectorcraft_geom::{Affine, Point, Rect, Vec2};
|
||||
|
||||
@@ -553,6 +553,16 @@ fn follow_items_by(n: &mut Node, a: Affine) -> bool {
|
||||
changed
|
||||
}
|
||||
|
||||
/// Make the raster effects of `items`, the fills and strokes of an object whose own effects are
|
||||
/// `owner`, follow the Transform effects of `owner` ([`follow_contents`]): for art that applies
|
||||
/// those effects to the object's path and draws each fill and stroke on it as a node of its own.
|
||||
pub(crate) fn follow_paints(items: &mut [AppearanceItem], owner: &[Effect]) {
|
||||
let Some(a) = contents_step(owner) else { return };
|
||||
for item in items {
|
||||
follow_contents(item.effects_mut(), a, Affine::IDENTITY);
|
||||
}
|
||||
}
|
||||
|
||||
/// `effects`, those of a fill or stroke of an object whose own effects are `owner`, with each
|
||||
/// raster effect following the Transform effects of `owner` as well ([`follow_contents`]): the
|
||||
/// list to draw that fill's or stroke's raster effects from ([`raster_effects`]). Borrowed when
|
||||
|
||||
@@ -565,9 +565,13 @@ fn art(doc: Option<&Document>, n: &Node, expand: bool) -> Option<Node> {
|
||||
} else {
|
||||
let path = geometry(&path, &n.appearance.effects, &ctx);
|
||||
remaining = crate::without_geometry(&remaining);
|
||||
// The object's Transform effects, applied to the path above, transform the items' raster
|
||||
// effects too.
|
||||
let mut items: Vec<AppearanceItem> = n.appearance.items.iter().filter(|i| crate::paints(i)).cloned().collect();
|
||||
crate::raster::follow_paints(&mut items, &n.appearance.effects);
|
||||
// Every item's shadow goes behind every item's art.
|
||||
let mut shadows = vec![];
|
||||
for item in n.appearance.items.iter().filter(|i| crate::paints(i)) {
|
||||
for item in &items {
|
||||
if let Some(index) = item.effects().iter().position(|e| e.visible && is_revolve(&e.id)) {
|
||||
let fx = item.effects().get(index)?;
|
||||
let p = geometry(&path, item.effects().get(..index)?, &ctx.item(item));
|
||||
|
||||
@@ -982,6 +982,10 @@ pub fn solid_art_in(doc: Option<&Document>, n: &Node) -> Option<Node> {
|
||||
} else {
|
||||
let path = geometry(&path, &n.appearance.effects, &ctx);
|
||||
remaining = crate::without_geometry(&n.appearance.effects);
|
||||
// The object's Transform effects, applied to the path above, transform the items' raster
|
||||
// effects too.
|
||||
let mut paints = paints;
|
||||
crate::raster::follow_paints(&mut paints, &n.appearance.effects);
|
||||
// Every item's shadow goes behind every item's art.
|
||||
let mut shadows = vec![];
|
||||
for item in &paints {
|
||||
|
||||
@@ -241,6 +241,23 @@ fn a_shadow_before_a_transform_follows_it_into_3d_art() {
|
||||
}
|
||||
}
|
||||
|
||||
/// An object's Transform effect transforms the raster effects of its fills when only a fill has a
|
||||
/// 3D effect: the shadow after that fill's 3D effect and another fill's shadow, as it does without
|
||||
/// the 3D effect.
|
||||
#[test]
|
||||
fn an_objects_transform_moves_its_fills_shadows_beside_a_fills_3d_effect() {
|
||||
for three_d in [crate::EXTRUDE, crate::REVOLVE] {
|
||||
let art = |n: &Node| if three_d == crate::EXTRUDE { crate::solid_art(n) } else { crate::revolve_art(n) };
|
||||
let mut n = fill_square(18, vec![fx(three_d, json!({})), shadow(10.0, 10.0, 0.0)]);
|
||||
let mut other = n.appearance.items[0].clone();
|
||||
*other.effects_mut() = vec![shadow(10.0, 10.0, 0.0)];
|
||||
n.appearance.items.push(other);
|
||||
n.appearance.effects = vec![transform(json!({"scaleH": 200, "scaleV": 100}))];
|
||||
let drawn = shadows_in(&art(&n).unwrap());
|
||||
assert!(drawn.len() > 1 && near(&drawn, &vec![(20.0, 10.0); drawn.len()]), "{three_d}: {drawn:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glows_blurs_and_feathers_scale_with_the_transform_after_them() {
|
||||
let effects = [
|
||||
|
||||
Reference in New Issue
Block a user