svg-filters: add turbulence and displacement map

This commit is contained in:
Schrottkatze 2024-03-24 15:49:41 +01:00
parent 919a3bb377
commit 0197df5ee2
Signed by: schrottkatze
SSH key fingerprint: SHA256:hXb3t1vINBFCiDCmhRABHX5ocdbLiKyCdKI4HK2Rbbc
5 changed files with 98 additions and 9 deletions

View file

@ -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<NodeInput>,
displacement_map: impl Into<NodeInput>,
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
}
}

View file

@ -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,
}))
}
}

View file

@ -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!(),

View file

@ -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<quick_xml::events::attributes::Attribute> {
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,

View file

@ -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,