mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 14:14:11 +00:00
The renderer keeps the path of a path or compound path of 1,024 anchors or more by object id, with the bounds of its segments and of its miter spikes in runs of 128 segments. When anchors move and the subpaths and anchor counts stay the same, the next frame rewrites only the path elements of the segments that start or end at a moved anchor, and measures again only the runs that hold them and the runs of the segments with length before them. Other edits make the path again as before. The pixels and the cull bounds are the same. - StrokeLayer::bounds_on is unchanged. The miter tip of one joint (miter_tip) and the stroke box with given tips (bounds_with_tips) are new functions beside it, and Appearance::stroked_bounds_by takes the box of each shaped stroke, so the cull bounds of a kept path use the kept tips. - geom::bez::has_length is the predicate reach.rs used for segments that draw, made public. Docs: docs/target-app-parity.md.
86 lines
4.6 KiB
Rust
86 lines
4.6 KiB
Rust
//! Live effects in the renderer.
|
||
//!
|
||
//! Geometry effects (object-level, then per fill/stroke) rewrite the path before painting via
|
||
//! `vectorcraft-effects`. Raster effects use vello_cpu filter layers. Those only work in
|
||
//! single-threaded contexts, so on the multithreaded pipeline each filter layer is rendered
|
||
//! offscreen on the calling thread (cropped to its reach) and composited back with the same blend
|
||
//! mode and opacity ([`Renderer::with_filters`]):
|
||
//!
|
||
//! - Drop Shadow / Outer Glow: the object's silhouette in a `DropShadowOnly` filter layer, painted
|
||
//! below the object with the effect's blend mode and opacity;
|
||
//! - Gaussian Blur: the object painted inside a Gaussian filter layer;
|
||
//! - Feather: like Gaussian Blur but clipped to the shape, so the edge fades inward;
|
||
//! - Inner Glow: a blurred inverse silhouette (Edge) or the blurred silhouette (Center), clipped
|
||
//! to the shape and painted above it;
|
||
//! - Photoshop-style filters (Radial Blur, Smart Blur, Unsharp Mask…): the content is rendered
|
||
//! offscreen and its pixels run through the content-changing effects in stack order (those
|
||
//! filters, Gaussian Blur and Feather, see [`effects::pixel`]), then drawn back
|
||
//! ([`Renderer::pixel_content`]). The result is cached per object while it and the zoom don't
|
||
//! change.
|
||
//! - Rasterize: the content drawn again on the image's own grid, as Object › Rasterize draws it
|
||
//! ([`Renderer::rasterize_image`]), then into the content's raster
|
||
//! ([`effects::Rasterize::compose`]; an image too large for that is made from the content's
|
||
//! raster, [`effects::Rasterize::apply`]), clipped to its outline with Create Clipping Mask. The
|
||
//! effects before it in the stack, and the shadows and glows after it, are drawn around it by
|
||
//! splitting the stack there ([`Renderer::raster_fx`]).
|
||
//!
|
||
//! While [`crate::RenderOptions::interacting`], an object whose content only moved draws its
|
||
//! cached shadows, glows and filtered content at its new place instead of running the effects
|
||
//! again ([`Renderer::move_shadow`], [`Renderer::move_pixel_content`]).
|
||
//!
|
||
//! While [`crate::RenderOptions::dragging`] is set, the renderer draws filtered content that runs
|
||
//! its effects within [`DRAG_PIXEL_BUDGET`] pixels, at a lower resolution where it would need more,
|
||
//! and keeps no raster made that way. On the multithreaded pipeline it does the same for shadows
|
||
//! and glows. The frame after the drag renders them as a still frame does.
|
||
//!
|
||
//! A cached raster is made again when something its content reads from outside the object
|
||
//! changes ([`Inputs`]): the pattern definitions, symbols, images and brushes it uses, the
|
||
//! document's raster resolution and color mode, the substitution highlights, the knockout its
|
||
//! object inherits, the color settings and fonts, the plug-ins its plug-in effects run, and the options
|
||
//! and layer settings it is drawn with.
|
||
//!
|
||
//! The same applies to one fill or stroke's own raster effects (around that item alone) and to
|
||
//! type, images, symbol instances and live objects ([`Renderer::draw_object_fx`]): their art is
|
||
//! drawn offscreen in the filter layers, reshaped first by their geometry effects. Groups and
|
||
//! layers with an appearance of their own take the same path with their evaluated art
|
||
//! ([`effects::evaluate_container`]: their fills and strokes painting the members, their geometry
|
||
//! effects reshaping them), so their raster effects apply to the composite (one combined shadow).
|
||
|
||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||
use std::sync::{Arc, Weak};
|
||
|
||
use vectorcraft_color::cms::Cms;
|
||
use vectorcraft_doc::{AppearanceItem, Document, Effect, Node, NodeId, NodeKind, SymbolBoxes};
|
||
use vectorcraft_effects::pixel::{Channels, PixelFx};
|
||
use vectorcraft_effects::{self as effects, GeomContext, RasterFx};
|
||
use vectorcraft_geom::{Affine, BezPath, FillRule, PathEl, Point, Rect, Shape, Size, Vec2};
|
||
use vello_common::filter_effects::{EdgeMode, Filter, FilterPrimitive};
|
||
use vello_cpu::RenderContext;
|
||
use vello_cpu::peniko;
|
||
|
||
use crate::ink::Ink;
|
||
use crate::{Frame, Renderer, blend_mode, fill_rule, paint};
|
||
|
||
mod bounds;
|
||
mod entries;
|
||
mod pixels;
|
||
mod predicates;
|
||
mod raster;
|
||
mod renderer;
|
||
|
||
#[cfg(test)]
|
||
pub(crate) use bounds::visual_bounds;
|
||
pub(crate) use bounds::{cull_bounds, drawn_outline, painted_reach, path_cull_bounds};
|
||
#[cfg(test)]
|
||
pub(crate) use entries::Drawn;
|
||
pub(crate) use entries::{DocInputs, FxGeom, Reads, ShadowEntry};
|
||
pub(crate) use predicates::{has_fx, has_object_fx};
|
||
pub(crate) use raster::PixelEntry;
|
||
#[cfg(test)]
|
||
pub(crate) use raster::RASTERIZED;
|
||
#[cfg(test)]
|
||
use raster::{DRAG_PIXEL_BUDGET, PIXEL_BUDGET, drag_scale, filter_region, filter_region_within, pan_margin};
|
||
|
||
#[cfg(test)]
|
||
mod tests;
|