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