Files
vectorcraft/crates/render/src/fx.rs
T

86 lines
4.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 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;