use valo_geometry::{Color, Matrix, Point};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum Shader {
Linear {
start: Point,
end: Point,
stops: Vec<GradientStop>,
spread: SpreadMode,
local: Matrix,
},
Radial {
center: Point,
radius: f32,
stops: Vec<GradientStop>,
spread: SpreadMode,
focus: Option<FocalCircle>,
local: Matrix,
},
Sweep {
center: Point,
start_angle: f32,
stops: Vec<GradientStop>,
local: Matrix,
},
Image {
image: crate::Image,
sampling: crate::Sampling,
local: Matrix,
},
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SpreadMode {
#[default]
Pad,
Repeat,
Reflect,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GradientStop {
pub offset: f32,
pub color: Color,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FocalCircle {
pub center: Point,
pub radius: f32,
}
impl FocalCircle {
pub fn point(center: Point) -> Self {
Self {
center,
radius: 0.0,
}
}
}
pub const MAX_GRADIENT_STOPS: usize = 8;
impl Shader {
pub fn stops(&self) -> &[GradientStop] {
match self {
Shader::Linear { stops, .. }
| Shader::Radial { stops, .. }
| Shader::Sweep { stops, .. } => stops,
Shader::Image { .. } => &[],
}
}
pub fn fold_color_filter(&mut self, filter: &crate::ColorFilter) -> bool {
let stops = match self {
Shader::Linear { stops, .. }
| Shader::Radial { stops, .. }
| Shader::Sweep { stops, .. } => stops,
Shader::Image { .. } => return false,
};
let mut folded = Vec::with_capacity(stops.len());
for stop in stops.iter() {
match filter.folded_into(stop.color) {
Some(color) => folded.push(GradientStop { color, ..*stop }),
None => return false,
}
}
*stops = folded;
true
}
pub fn linear(start: Point, end: Point, from: Color, to: Color) -> Self {
Shader::Linear {
start,
end,
stops: vec![
GradientStop {
offset: 0.0,
color: from,
},
GradientStop {
offset: 1.0,
color: to,
},
],
spread: SpreadMode::Pad,
local: Matrix::IDENTITY,
}
}
}