use crate::asset::register_owned;
use crate::schema::{AssetKind, Color, Paint, TileMode};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Stop {
pub at: f32,
pub color: Color,
}
impl Stop {
pub const fn new(at: f32, color: Color) -> Self {
Self { at, color }
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Brush {
Linear {
start: (f32, f32),
end: (f32, f32),
stops: Vec<Stop>,
tile: TileMode,
},
Radial {
center: (f32, f32),
radius: f32,
stops: Vec<Stop>,
tile: TileMode,
},
Image { asset: u32, tile: TileMode },
}
const KIND_LINEAR: u16 = 1;
const KIND_RADIAL: u16 = 2;
const KIND_IMAGE: u16 = 3;
impl Brush {
pub fn vertical(stops: Vec<Stop>) -> Self {
Self::Linear {
start: (0.5, 0.0),
end: (0.5, 1.0),
stops,
tile: TileMode::Clamp,
}
}
pub fn horizontal(stops: Vec<Stop>) -> Self {
Self::Linear {
start: (0.0, 0.5),
end: (1.0, 0.5),
stops,
tile: TileMode::Clamp,
}
}
pub fn radial(stops: Vec<Stop>) -> Self {
Self::Radial {
center: (0.5, 0.5),
radius: 0.5,
stops,
tile: TileMode::Clamp,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let (kind, coordinates, stops, tile) = match self {
Self::Linear {
start,
end,
stops,
tile,
} => (
KIND_LINEAR,
[start.0, start.1, end.0, end.1],
stops.as_slice(),
*tile,
),
Self::Radial {
center,
radius,
stops,
tile,
} => (
KIND_RADIAL,
[center.0, center.1, *radius, 0.0],
stops.as_slice(),
*tile,
),
Self::Image { asset, tile } => (
KIND_IMAGE,
[f32::from_bits(*asset), 0.0, 0.0, 0.0],
&[][..],
*tile,
),
};
let mut bytes = Vec::with_capacity(HEADER_LEN + stops.len() * STOP_LEN);
bytes.extend_from_slice(&kind.to_le_bytes());
bytes.extend_from_slice(&(stops.len() as u16).to_le_bytes());
bytes.extend_from_slice(&(tile as u16).to_le_bytes());
bytes.extend_from_slice(&0u16.to_le_bytes());
for coordinate in coordinates {
bytes.extend_from_slice(&coordinate.to_bits().to_le_bytes());
}
for stop in stops {
bytes.extend_from_slice(&stop.at.to_bits().to_le_bytes());
bytes.extend_from_slice(&stop.color.0.to_le_bytes());
}
bytes
}
}
pub const HEADER_LEN: usize = 24;
pub const STOP_LEN: usize = 8;
pub fn brush(brush: Brush) -> Paint {
Paint::Asset(register_owned(AssetKind::Brush, brush.to_bytes()))
}