use crate::core::{Bounds, Corners, Edges, Rgba};
use bytemuck::{Pod, Zeroable};
fn bounds_array(bounds: Bounds) -> [f32; 4] {
[bounds.origin.x.0, bounds.origin.y.0, bounds.size.width.0, bounds.size.height.0]
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct Quad {
pub bounds: [f32; 4],
pub clip: [f32; 4],
pub background: Rgba,
pub border_color: Rgba,
pub corner_radii: [f32; 4],
pub border_widths: [f32; 4],
pub gradient_end: Rgba,
pub gradient: [f32; 4],
}
impl Quad {
pub fn new(bounds: Bounds, clip: Bounds, background: Rgba) -> Self {
Self {
bounds: bounds_array(bounds),
clip: bounds_array(clip),
background,
border_color: Rgba::TRANSPARENT,
corner_radii: [0.0; 4],
border_widths: [0.0; 4],
gradient_end: Rgba::TRANSPARENT,
gradient: [0.0; 4],
}
}
pub fn gradient(mut self, angle_degrees: f32, end: Rgba) -> Self {
let radians = angle_degrees.to_radians();
self.gradient_end = end;
self.gradient = [radians.sin(), -radians.cos(), 1.0, 0.0];
self
}
pub fn corners(mut self, corners: Corners) -> Self {
self.corner_radii = [corners.top_left.0, corners.top_right.0, corners.bottom_right.0, corners.bottom_left.0];
self
}
pub fn border(mut self, widths: Edges, color: Rgba) -> Self {
self.border_widths = [widths.top.0, widths.right.0, widths.bottom.0, widths.left.0];
self.border_color = color;
self
}
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct Shadow {
pub bounds: [f32; 4],
pub clip: [f32; 4],
pub color: Rgba,
pub corner_radii: [f32; 4],
pub blur: f32,
pub padding: [f32; 3],
}
impl Shadow {
pub fn new(bounds: Bounds, clip: Bounds, color: Rgba, corners: Corners, blur: f32) -> Self {
Self {
bounds: bounds_array(bounds),
clip: bounds_array(clip),
color,
corner_radii: [corners.top_left.0, corners.top_right.0, corners.bottom_right.0, corners.bottom_left.0],
blur,
padding: [0.0; 3],
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct Underline {
pub bounds: [f32; 4],
pub clip: [f32; 4],
pub color: Rgba,
pub thickness: f32,
pub wavy: f32,
pub padding: [f32; 2],
}
impl Underline {
pub fn new(bounds: Bounds, clip: Bounds, color: Rgba, thickness: f32, wavy: bool) -> Self {
Self {
bounds: bounds_array(bounds),
clip: bounds_array(clip),
color,
thickness,
wavy: if wavy { 1.0 } else { 0.0 },
padding: [0.0; 2],
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct MonochromeSprite {
pub bounds: [f32; 4],
pub clip: [f32; 4],
pub uv: [f32; 4],
pub color: Rgba,
}
pub type PolychromeSprite = MonochromeSprite;
impl MonochromeSprite {
pub fn new(bounds: Bounds, clip: Bounds, uv: [f32; 4], color: Rgba) -> Self {
Self { bounds: bounds_array(bounds), clip: bounds_array(clip), uv, color }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PrimitiveKind {
Shadow,
Quad,
Underline,
Monochrome,
Polychrome,
}
#[derive(Clone, Debug)]
pub struct Batch {
pub kind: PrimitiveKind,
pub range: std::ops::Range<u32>,
}
#[derive(Default)]
pub struct Scene {
pub shadows: Vec<Shadow>,
pub quads: Vec<Quad>,
pub underlines: Vec<Underline>,
pub monochrome_sprites: Vec<MonochromeSprite>,
pub polychrome_sprites: Vec<PolychromeSprite>,
pub batches: Vec<Batch>,
}
impl Scene {
pub fn clear(&mut self) {
self.shadows.clear();
self.quads.clear();
self.underlines.clear();
self.monochrome_sprites.clear();
self.polychrome_sprites.clear();
self.batches.clear();
}
pub fn insert_shadow(&mut self, shadow: Shadow) {
self.shadows.push(shadow);
self.extend_batch(PrimitiveKind::Shadow, self.shadows.len() as u32);
}
pub fn insert_quad(&mut self, quad: Quad) {
self.quads.push(quad);
self.extend_batch(PrimitiveKind::Quad, self.quads.len() as u32);
}
pub fn insert_underline(&mut self, underline: Underline) {
self.underlines.push(underline);
self.extend_batch(PrimitiveKind::Underline, self.underlines.len() as u32);
}
pub fn insert_monochrome(&mut self, sprite: MonochromeSprite) {
self.monochrome_sprites.push(sprite);
self.extend_batch(PrimitiveKind::Monochrome, self.monochrome_sprites.len() as u32);
}
pub fn insert_polychrome(&mut self, sprite: PolychromeSprite) {
self.polychrome_sprites.push(sprite);
self.extend_batch(PrimitiveKind::Polychrome, self.polychrome_sprites.len() as u32);
}
fn extend_batch(&mut self, kind: PrimitiveKind, end: u32) {
match self.batches.last_mut() {
Some(batch) if batch.kind == kind => batch.range.end = end,
_ => self.batches.push(Batch { kind, range: end - 1..end }),
}
}
}