From 0197df5ee29e7dcd633b11ac899ac48575a53db8 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Sun, 24 Mar 2024 15:49:41 +0100 Subject: [PATCH] svg-filters: add turbulence and displacement map --- .../src/types/graph/abstracted_inputs.rs | 43 ++++++++++++++++++- crates/svg-filters/src/types/nodes.rs | 27 ++++++++++++ .../svg-filters/src/types/nodes/primitives.rs | 6 +-- .../nodes/primitives/displacement_map.rs | 29 ++++++++++--- .../src/types/nodes/primitives/flood.rs | 2 + 5 files changed, 98 insertions(+), 9 deletions(-) diff --git a/crates/svg-filters/src/types/graph/abstracted_inputs.rs b/crates/svg-filters/src/types/graph/abstracted_inputs.rs index ca576c5..8d84707 100644 --- a/crates/svg-filters/src/types/graph/abstracted_inputs.rs +++ b/crates/svg-filters/src/types/graph/abstracted_inputs.rs @@ -3,7 +3,11 @@ use petgraph::{data::Build, prelude::NodeIndex}; use crate::{ types::nodes::primitives::{ - blend::BlendMode, color_matrix::ColorMatrixType, component_transfer::TransferFn, + blend::BlendMode, + color_matrix::ColorMatrixType, + component_transfer::TransferFn, + displacement_map::Channel, + turbulence::{NoiseType, StitchTiles}, }, Node, }; @@ -152,4 +156,41 @@ impl FilterGraph { pub fn flood_opaque(&mut self, flood_color: Color) -> NodeIndex { self.dag.add_node(Node::flood_opaque(flood_color)) } + + pub fn turbulence( + &mut self, + base_freq_x: f32, + base_freq_y: f32, + num_octaves: u16, + seed: u32, + stitch_tiles: StitchTiles, + noise_type: NoiseType, + ) -> NodeIndex { + self.dag.add_node(Node::turbulence( + base_freq_x, + base_freq_y, + num_octaves, + seed, + stitch_tiles, + noise_type, + )) + } + + pub fn displacement_map( + &mut self, + source_image: impl Into, + displacement_map: impl Into, + scale: f32, + x_channel: Channel, + y_channel: Channel, + ) -> NodeIndex { + let node_idx = self + .dag + .add_node(Node::displacement_map(scale, x_channel, y_channel)); + self.dag + .add_edge(self.resolve_input(source_image.into()), node_idx, ()); + self.dag + .add_edge(self.resolve_input(displacement_map.into()), node_idx, ()); + node_idx + } } diff --git a/crates/svg-filters/src/types/nodes.rs b/crates/svg-filters/src/types/nodes.rs index ba0340b..797e7e4 100644 --- a/crates/svg-filters/src/types/nodes.rs +++ b/crates/svg-filters/src/types/nodes.rs @@ -9,9 +9,11 @@ use self::{ color_matrix::{ColorMatrix, ColorMatrixType}, component_transfer::{ComponentTransfer, TransferFn}, composite::{Composite, CompositeOperator}, + displacement_map::{Channel, DisplacementMap}, flood::Flood, gaussian_blur::GaussianBlur, offset::Offset, + turbulence::{NoiseType, StitchTiles, Turbulence}, FePrimitive, }, standard_input::StandardInput, @@ -207,4 +209,29 @@ impl Node { pub fn flood_opaque(flood_color: Color) -> Self { Self::flood(flood_color, 1.) } + + pub fn turbulence( + base_freq_x: f32, + base_freq_y: f32, + num_octaves: u16, + seed: u32, + stitch_tiles: StitchTiles, + noise_type: NoiseType, + ) -> Self { + Self::simple(FePrimitive::Turbulence(Turbulence { + base_frequency: (base_freq_x, base_freq_y), + num_octaves, + seed, + stitch_tiles, + noise_type, + })) + } + + pub fn displacement_map(scale: f32, x_channel: Channel, y_channel: Channel) -> Self { + Self::simple(FePrimitive::DisplacementMap(DisplacementMap { + scale, + x_channel_selector: x_channel, + y_channel_selector: y_channel, + })) + } } diff --git a/crates/svg-filters/src/types/nodes/primitives.rs b/crates/svg-filters/src/types/nodes/primitives.rs index a46ee9b..171314f 100644 --- a/crates/svg-filters/src/types/nodes/primitives.rs +++ b/crates/svg-filters/src/types/nodes/primitives.rs @@ -90,7 +90,7 @@ impl WriteElement for FePrimitive { FePrimitive::Turbulence(el) => el.attrs(), FePrimitive::ConvolveMatrix(_) => todo!(), FePrimitive::DiffuseLighting(_) => todo!(), - FePrimitive::DisplacementMap(_) => todo!(), + FePrimitive::DisplacementMap(el) => el.attrs(), FePrimitive::Flood(el) => el.attrs(), FePrimitive::Image(_) => todo!(), FePrimitive::Merge(_) => todo!(), @@ -111,7 +111,7 @@ impl WriteElement for FePrimitive { FePrimitive::Turbulence(el) => el.tag_name(), FePrimitive::ConvolveMatrix(_) => todo!(), FePrimitive::DiffuseLighting(_) => todo!(), - FePrimitive::DisplacementMap(_) => todo!(), + FePrimitive::DisplacementMap(el) => el.tag_name(), FePrimitive::Flood(el) => el.tag_name(), FePrimitive::Image(_) => todo!(), FePrimitive::Merge(_) => todo!(), @@ -138,7 +138,7 @@ impl WriteElement for FePrimitive { FePrimitive::Offset(el) => el.element_writer(writer, common, inputs, output), FePrimitive::ConvolveMatrix(_) => todo!(), FePrimitive::DiffuseLighting(_) => todo!(), - FePrimitive::DisplacementMap(_) => todo!(), + FePrimitive::DisplacementMap(el) => el.element_writer(writer, common, inputs, output), FePrimitive::Flood(el) => el.element_writer(writer, common, inputs, output), FePrimitive::Image(_) => todo!(), FePrimitive::Merge(_) => todo!(), diff --git a/crates/svg-filters/src/types/nodes/primitives/displacement_map.rs b/crates/svg-filters/src/types/nodes/primitives/displacement_map.rs index b6485ac..189291e 100644 --- a/crates/svg-filters/src/types/nodes/primitives/displacement_map.rs +++ b/crates/svg-filters/src/types/nodes/primitives/displacement_map.rs @@ -1,13 +1,32 @@ +use super::WriteElement; + /// [feDisplacementMap](https://www.w3.org/TR/SVG11/filters.html#feDisplacementMapElement) #[derive(Debug)] pub struct DisplacementMap { - scale: f32, - x_channel_selector: Channel, - y_channel_selector: Channel, + pub scale: f32, + pub x_channel_selector: Channel, + pub y_channel_selector: Channel, } -#[derive(Debug)] -enum Channel { +impl WriteElement for DisplacementMap { + fn attrs(&self) -> Vec { + let mut r = Vec::new(); + gen_attrs![ + r; + self.scale != 0. => b"scale": self.scale, + self.x_channel_selector != Channel::A => b"xChannelSelector": format!("{:?}", self.x_channel_selector), + self.y_channel_selector != Channel::A => b"yChannelSelector": format!("{:?}", self.y_channel_selector) + ]; + r + } + + fn tag_name(&self) -> &'static str { + "feDisplacementMap" + } +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Channel { A, R, G, diff --git a/crates/svg-filters/src/types/nodes/primitives/flood.rs b/crates/svg-filters/src/types/nodes/primitives/flood.rs index df912ef..3f10658 100644 --- a/crates/svg-filters/src/types/nodes/primitives/flood.rs +++ b/crates/svg-filters/src/types/nodes/primitives/flood.rs @@ -3,6 +3,8 @@ use csscolorparser::Color; use super::WriteElement; /// [feFlood](https://www.w3.org/TR/SVG11/filters.html#feFloodElement) +// NOTE: this doesn't work for some reason, but the examples from mdn don't either. +// might be a browser bug, def worth investigating #[derive(Debug)] pub struct Flood { pub flood_color: Color,