From f24f15ac7231a4b785dbc9b63dead51a62be3f40 Mon Sep 17 00:00:00 2001 From: Aaron Muir Hamilton Date: Sun, 10 Mar 2024 18:48:57 -0400 Subject: [PATCH] Remove vello_svg. --- ARCHITECTURE.md | 1 - Cargo.toml | 2 - README.md | 10 +- examples/scenes/Cargo.toml | 1 - examples/scenes/src/pico_svg.rs | 1 + integrations/vello_svg/Cargo.toml | 16 -- integrations/vello_svg/src/lib.rs | 301 ------------------------------ 7 files changed, 2 insertions(+), 330 deletions(-) delete mode 100644 integrations/vello_svg/Cargo.toml delete mode 100644 integrations/vello_svg/src/lib.rs diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4d28da71c..74d45fe52 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -38,7 +38,6 @@ The repository is structured as such: - `tests/` - Helper code for writing tests; current has a single smoke test and not much else. - `doc/` - Various documents detailing the vision for Vello as it was developed. This directory should probably be refactored away; adding to it not recommended. - `examples/` - Example projects using Vello. Each example is its own crate, with its own dependencies. The simplest example is the `shapes` one. -- `integrations/vello_svg` - An SVG rendered based on Vello and usvg. Used in examples. May be moved to `crates/` in the future. - `shader/` - This is where the magic happens. WGSL shaders that define the compute operations (often variations of prefix sum) that Vello does to render a scene. - `shared/` - Shared types, functions and constants included in other shaders through non-standard `#import` preprocessor directives (see "Shader templating"). - `src/` - Code for the main `vello` crate. diff --git a/Cargo.toml b/Cargo.toml index 7c5cbc8f8..31d04bd49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,6 @@ members = [ "crates/shaders", "crates/tests", - "integrations/vello_svg", - "examples/headless", "examples/with_winit", "examples/with_bevy", diff --git a/README.md b/README.md index 63d4b9b73..47f0575af 100644 --- a/README.md +++ b/README.md @@ -120,14 +120,6 @@ More formal benchmarks are on their way. ## Integrations -### SVG - -This repository also includes [`vello_svg`](./integrations/vello_svg/), which supports converting a [`usvg`](https://crates.io/crates/usvg) `Tree` into a Vello scene. - -This is currently incomplete; see its crate level documentation for more information. - -This is used in the [winit](#winit) example for the SVG rendering. - ### Lottie A separate integration for playing Lottie animations is available through the [`velato`](https://github.com/linebender/velato) crate. @@ -141,7 +133,7 @@ Examples must be selected using the `--package` (or `-p`) Cargo flag. ### Winit Our [winit] example ([examples/with_winit](https://github.com/linebender/vello/tree/main/examples/with_winit)) demonstrates rendering to a [winit] window. -By default, this renders the [GhostScript Tiger] as well as all SVG files you add in the [examples/assets/downloads/](https://github.com/linebender/vello/tree/main/examples/assets/downloads) directory using [`vello_svg`](#svg). +By default, this renders the [GhostScript Tiger] as well as all SVG files you add in the [examples/assets/downloads/](https://github.com/linebender/vello/tree/main/examples/assets/downloads) directory. A custom list of SVG file paths (and directories to render all SVG files from) can be provided as arguments instead. It also includes a collection of test scenes showing the capabilities of `vello`, which can be shown with `--test-scenes`. diff --git a/examples/scenes/Cargo.toml b/examples/scenes/Cargo.toml index dcf1e1419..77c323948 100644 --- a/examples/scenes/Cargo.toml +++ b/examples/scenes/Cargo.toml @@ -11,7 +11,6 @@ workspace = true [dependencies] vello = { path = "../../" } -vello_svg = { path = "../../integrations/vello_svg" } anyhow = { workspace = true } clap = { workspace = true, features = ["derive"] } image = "0.24.9" diff --git a/examples/scenes/src/pico_svg.rs b/examples/scenes/src/pico_svg.rs index 3dcecdf78..8bf23317c 100644 --- a/examples/scenes/src/pico_svg.rs +++ b/examples/scenes/src/pico_svg.rs @@ -1,5 +1,6 @@ // Copyright 2024 the Vello Authors // SPDX-License-Identifier: Apache-2.0 OR MIT + //! A loader for a tiny fragment of SVG use std::{num::ParseFloatError, str::FromStr}; diff --git a/integrations/vello_svg/Cargo.toml b/integrations/vello_svg/Cargo.toml deleted file mode 100644 index 9693712fb..000000000 --- a/integrations/vello_svg/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "vello_svg" -description = "Render a usvg document to a Vello scene" -categories = ["rendering", "graphics"] -keywords = ["2d", "vector-graphics", "vello"] -edition.workspace = true -license.workspace = true -repository.workspace = true -publish = false - -[lints] -workspace = true - -[dependencies] -vello = { path = "../../" } -usvg = "0.37.0" diff --git a/integrations/vello_svg/src/lib.rs b/integrations/vello_svg/src/lib.rs deleted file mode 100644 index 2a00055a6..000000000 --- a/integrations/vello_svg/src/lib.rs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2023 the Vello Authors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! Append a [`usvg::Tree`] to a Vello [`Scene`] -//! -//! This currently lacks support for a [number of important](crate#unsupported-features) SVG features. -//! This is because this integration was developed for examples, which only need to support enough SVG -//! to demonstrate Vello. -//! -//! However, this is also intended to be the preferred integration between Vello and [usvg], so [consider -//! contributing](https://github.com/linebender/vello) if you need a feature which is missing. -//! -//! [`render_tree_with`] is the primary entry point function, which supports choosing the behaviour -//! when [unsupported features](crate#unsupported-features) are detected. In a future release where there are -//! no unsupported features, this may be phased out -//! -//! [`render_tree`] is a convenience wrapper around [`render_tree_with`] which renders an indicator around not -//! yet supported features -//! -//! This crate also re-exports [`usvg`], to make handling dependency versions easier -//! -//! # Unsupported features -//! -//! Missing features include: -//! - embedded images -//! - text -//! - group opacity -//! - mix-blend-modes -//! - clipping -//! - masking -//! - filter effects -//! - group background -//! - path visibility -//! - path paint order -//! - path shape-rendering -//! - patterns - -use std::convert::Infallible; -use usvg::NodeExt; -use vello::kurbo::{Affine, BezPath, Point, Rect, Stroke}; -use vello::peniko::{Brush, Color, Fill}; -use vello::Scene; - -/// Re-export vello. -pub use vello; - -/// Re-export usvg. -pub use usvg; - -/// Append a [`usvg::Tree`] into a Vello [`Scene`], with default error handling -/// This will draw a red box over (some) unsupported elements -/// -/// Calls [`render_tree_with`] with an error handler implementing the above. -/// -/// See the [module level documentation](crate#unsupported-features) for a list of some unsupported svg features -pub fn render_tree(scene: &mut Scene, svg: &usvg::Tree) { - render_tree_with(scene, svg, default_error_handler).unwrap_or_else(|e| match e {}); -} - -/// Append a [`usvg::Tree`] into a Vello [`Scene`]. -/// -/// Calls [`render_tree_with`] with [`default_error_handler`]. -/// This will draw a red box over unsupported element types. -/// -/// See the [module level documentation](crate#unsupported-features) for a list of some unsupported svg features -pub fn render_tree_with Result<(), E>, E>( - scene: &mut Scene, - svg: &usvg::Tree, - mut on_err: F, -) -> Result<(), E> { - for elt in svg.root.descendants() { - let transform = { - let usvg::Transform { - sx, - kx, - ky, - sy, - tx, - ty, - } = elt.abs_transform(); - Affine::new([sx, kx, ky, sy, tx, ty].map(f64::from)) - }; - match &*elt.borrow() { - usvg::NodeKind::Group(_) => {} - usvg::NodeKind::Path(path) => { - let mut local_path = BezPath::new(); - // The semantics of SVG paths don't line up with `BezPath`; we - // must manually track initial points - let mut just_closed = false; - let mut most_recent_initial = (0., 0.); - for elt in path.data.segments() { - match elt { - usvg::tiny_skia_path::PathSegment::MoveTo(p) => { - if std::mem::take(&mut just_closed) { - local_path.move_to(most_recent_initial); - } - most_recent_initial = (p.x.into(), p.y.into()); - local_path.move_to(most_recent_initial); - } - usvg::tiny_skia_path::PathSegment::LineTo(p) => { - if std::mem::take(&mut just_closed) { - local_path.move_to(most_recent_initial); - } - local_path.line_to(Point::new(p.x as f64, p.y as f64)); - } - usvg::tiny_skia_path::PathSegment::QuadTo(p1, p2) => { - if std::mem::take(&mut just_closed) { - local_path.move_to(most_recent_initial); - } - local_path.quad_to( - Point::new(p1.x as f64, p1.y as f64), - Point::new(p2.x as f64, p2.y as f64), - ); - } - usvg::tiny_skia_path::PathSegment::CubicTo(p1, p2, p3) => { - if std::mem::take(&mut just_closed) { - local_path.move_to(most_recent_initial); - } - local_path.curve_to( - Point::new(p1.x as f64, p1.y as f64), - Point::new(p2.x as f64, p2.y as f64), - Point::new(p3.x as f64, p3.y as f64), - ); - } - usvg::tiny_skia_path::PathSegment::Close => { - just_closed = true; - local_path.close_path(); - } - } - } - - // FIXME: let path.paint_order determine the fill/stroke order. - - if let Some(fill) = &path.fill { - if let Some((brush, brush_transform)) = - paint_to_brush(&fill.paint, fill.opacity) - { - scene.fill( - match fill.rule { - usvg::FillRule::NonZero => Fill::NonZero, - usvg::FillRule::EvenOdd => Fill::EvenOdd, - }, - transform, - &brush, - Some(brush_transform), - &local_path, - ); - } else { - on_err(scene, &elt)?; - } - } - if let Some(stroke) = &path.stroke { - if let Some((brush, brush_transform)) = - paint_to_brush(&stroke.paint, stroke.opacity) - { - let mut conv_stroke = Stroke::new(stroke.width.get() as f64) - .with_caps(match stroke.linecap { - usvg::LineCap::Butt => vello::kurbo::Cap::Butt, - usvg::LineCap::Round => vello::kurbo::Cap::Round, - usvg::LineCap::Square => vello::kurbo::Cap::Square, - }) - .with_join(match stroke.linejoin { - usvg::LineJoin::Miter | usvg::LineJoin::MiterClip => { - vello::kurbo::Join::Miter - } - usvg::LineJoin::Round => vello::kurbo::Join::Round, - usvg::LineJoin::Bevel => vello::kurbo::Join::Bevel, - }) - .with_miter_limit(stroke.miterlimit.get() as f64); - if let Some(dash_array) = stroke.dasharray.as_ref() { - conv_stroke = conv_stroke.with_dashes( - stroke.dashoffset as f64, - dash_array.iter().map(|x| *x as f64), - ); - } - scene.stroke( - &conv_stroke, - transform, - &brush, - Some(brush_transform), - &local_path, - ); - } else { - on_err(scene, &elt)?; - } - } - } - usvg::NodeKind::Image(_) => { - on_err(scene, &elt)?; - } - usvg::NodeKind::Text(_) => { - on_err(scene, &elt)?; - } - } - } - Ok(()) -} - -/// Error handler function for [`render_tree_with`] which draws a transparent red box -/// instead of unsupported SVG features -pub fn default_error_handler(scene: &mut Scene, node: &usvg::Node) -> Result<(), Infallible> { - if let Some(bb) = node.calculate_bbox() { - let rect = Rect { - x0: bb.left() as f64, - y0: bb.top() as f64, - x1: bb.right() as f64, - y1: bb.bottom() as f64, - }; - scene.fill( - Fill::NonZero, - Affine::IDENTITY, - Color::RED.with_alpha_factor(0.5), - None, - &rect, - ); - } - Ok(()) -} - -fn paint_to_brush(paint: &usvg::Paint, opacity: usvg::Opacity) -> Option<(Brush, Affine)> { - match paint { - usvg::Paint::Color(color) => Some(( - Brush::Solid(Color::rgba8( - color.red, - color.green, - color.blue, - opacity.to_u8(), - )), - Affine::IDENTITY, - )), - usvg::Paint::LinearGradient(gr) => { - let stops: Vec = gr - .stops - .iter() - .map(|stop| { - let mut cstop = vello::peniko::ColorStop::default(); - cstop.color.r = stop.color.red; - cstop.color.g = stop.color.green; - cstop.color.b = stop.color.blue; - cstop.color.a = (stop.opacity * opacity).to_u8(); - cstop.offset = stop.offset.get(); - cstop - }) - .collect(); - let start = Point::new(gr.x1 as f64, gr.y1 as f64); - let end = Point::new(gr.x2 as f64, gr.y2 as f64); - let arr = [ - gr.transform.sx, - gr.transform.ky, - gr.transform.kx, - gr.transform.sy, - gr.transform.tx, - gr.transform.ty, - ] - .map(f64::from); - let transform = Affine::new(arr); - let gradient = - vello::peniko::Gradient::new_linear(start, end).with_stops(stops.as_slice()); - Some((Brush::Gradient(gradient), transform)) - } - usvg::Paint::RadialGradient(gr) => { - let stops: Vec = gr - .stops - .iter() - .map(|stop| { - let mut cstop = vello::peniko::ColorStop::default(); - cstop.color.r = stop.color.red; - cstop.color.g = stop.color.green; - cstop.color.b = stop.color.blue; - cstop.color.a = (stop.opacity * opacity).to_u8(); - cstop.offset = stop.offset.get(); - cstop - }) - .collect(); - - let start_center = Point::new(gr.cx as f64, gr.cy as f64); - let end_center = Point::new(gr.fx as f64, gr.fy as f64); - let start_radius = 0_f32; - let end_radius = gr.r.get(); - let arr = [ - gr.transform.sx, - gr.transform.ky, - gr.transform.kx, - gr.transform.sy, - gr.transform.tx, - gr.transform.ty, - ] - .map(f64::from); - let transform = Affine::new(arr); - let gradient = vello::peniko::Gradient::new_two_point_radial( - start_center, - start_radius, - end_center, - end_radius, - ) - .with_stops(stops.as_slice()); - Some((Brush::Gradient(gradient), transform)) - } - usvg::Paint::Pattern(_) => None, - } -}