1use super::{Bounds, Hsla, Pixels, Point};
2use crate::{Corners, Edges, FontId, GlyphId};
3use bytemuck::{Pod, Zeroable};
4use plane_split::BspSplitter;
5
6pub struct Scene {
7 opaque_primitives: PrimitiveBatch,
8 transparent_primitives: slotmap::SlotMap<slotmap::DefaultKey, Primitive>,
9 splitter: BspSplitter<slotmap::DefaultKey>,
10}
11
12impl Scene {
13 pub fn new() -> Scene {
14 Scene {
15 opaque_primitives: PrimitiveBatch::default(),
16 transparent_primitives: slotmap::SlotMap::new(),
17 splitter: BspSplitter::new(),
18 }
19 }
20
21 pub fn insert(&mut self, primitive: impl Into<Primitive>, is_transparent: bool) {
22 if is_transparent {
23 self.transparent_primitives.insert(primitive.into());
24 } else {
25 match primitive.into() {
26 Primitive::Quad(quad) => self.opaque_primitives.quads.push(quad),
27 Primitive::Glyph(glyph) => self.opaque_primitives.glyphs.push(glyph),
28 Primitive::Underline(underline) => {
29 self.opaque_primitives.underlines.push(underline)
30 }
31 }
32 }
33 }
34
35 pub fn opaque_primitives(&self) -> &PrimitiveBatch {
36 &self.opaque_primitives
37 }
38}
39
40#[derive(Clone, Debug)]
41pub enum Primitive {
42 Quad(Quad),
43 Glyph(RenderedGlyph),
44 Underline(Underline),
45}
46
47impl Primitive {
48 pub fn is_transparent(&self) -> bool {
49 match self {
50 Primitive::Quad(quad) => {
51 quad.background.is_transparent() && quad.border_color.is_transparent()
52 }
53 Primitive::Glyph(glyph) => glyph.color.is_transparent(),
54 Primitive::Underline(underline) => underline.color.is_transparent(),
55 }
56 }
57}
58
59#[derive(Default)]
60pub struct PrimitiveBatch {
61 pub quads: Vec<Quad>,
62 pub glyphs: Vec<RenderedGlyph>,
63 pub underlines: Vec<Underline>,
64}
65
66#[derive(Debug, Clone, Copy)]
67#[repr(C)]
68pub struct Quad {
69 pub order: f32,
70 pub bounds: Bounds<Pixels>,
71 pub clip_bounds: Bounds<Pixels>,
72 pub clip_corner_radii: Corners<Pixels>,
73 pub background: Hsla,
74 pub border_color: Hsla,
75 pub corner_radii: Corners<Pixels>,
76 pub border_widths: Edges<Pixels>,
77}
78
79impl Quad {
80 pub fn vertices(&self) -> impl Iterator<Item = Point<Pixels>> {
81 let x1 = self.bounds.origin.x;
82 let y1 = self.bounds.origin.y;
83 let x2 = x1 + self.bounds.size.width;
84 let y2 = y1 + self.bounds.size.height;
85 [
86 Point::new(x1, y1),
87 Point::new(x2, y1),
88 Point::new(x2, y2),
89 Point::new(x1, y2),
90 ]
91 .into_iter()
92 }
93}
94
95unsafe impl Zeroable for Quad {}
96
97unsafe impl Pod for Quad {}
98
99impl From<Quad> for Primitive {
100 fn from(quad: Quad) -> Self {
101 Primitive::Quad(quad)
102 }
103}
104
105#[derive(Debug, Clone, Copy)]
106#[repr(C)]
107pub(crate) struct QuadUniforms {
108 viewport_size: [f32; 2],
109}
110
111unsafe impl Zeroable for QuadUniforms {}
112
113unsafe impl Pod for QuadUniforms {}
114
115#[derive(Debug, Clone, Copy)]
116#[repr(C)]
117pub struct RenderedGlyph {
118 pub font_id: FontId,
119 pub font_size: f32,
120 pub id: GlyphId,
121 pub origin: Point<Pixels>,
122 pub color: Hsla,
123}
124
125impl From<RenderedGlyph> for Primitive {
126 fn from(glyph: RenderedGlyph) -> Self {
127 Primitive::Glyph(glyph)
128 }
129}
130
131#[derive(Copy, Clone, Default, Debug)]
132#[repr(C)]
133pub struct Underline {
134 pub origin: Point<Pixels>,
135 pub width: Pixels,
136 pub thickness: Pixels,
137 pub color: Hsla,
138 pub squiggly: bool,
139}
140
141unsafe impl Zeroable for Underline {}
142
143unsafe impl Pod for Underline {}
144
145impl From<Underline> for Primitive {
146 fn from(underline: Underline) -> Self {
147 Primitive::Underline(underline)
148 }
149}