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