mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-28 19:57:05 -06:00
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};
|
||
#[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;
|