1use crate::{
2 color::ColorU,
3 fonts::{FontId, GlyphId},
4 geometry::{rect::RectF, vector::Vector2F},
5};
6
7pub struct Scene {
8 scale_factor: f32,
9 layers: Vec<Layer>,
10 active_layer_stack: Vec<usize>,
11}
12
13#[derive(Default, Debug)]
14pub struct Layer {
15 clip_bounds: Option<RectF>,
16 quads: Vec<Quad>,
17 shadows: Vec<Shadow>,
18 glyphs: Vec<Glyph>,
19 paths: Vec<Path>,
20}
21
22#[derive(Default, Debug)]
23pub struct Quad {
24 pub bounds: RectF,
25 pub background: Option<ColorU>,
26 pub border: Border,
27 pub corner_radius: f32,
28}
29
30#[derive(Debug)]
31pub struct Shadow {
32 pub bounds: RectF,
33 pub corner_radius: f32,
34 pub sigma: f32,
35 pub color: ColorU,
36}
37
38#[derive(Debug)]
39pub struct Glyph {
40 pub font_id: FontId,
41 pub font_size: f32,
42 pub id: GlyphId,
43 pub origin: Vector2F,
44 pub color: ColorU,
45}
46
47#[derive(Clone, Copy, Default, Debug)]
48pub struct Border {
49 pub width: f32,
50 pub color: Option<ColorU>,
51 pub top: bool,
52 pub right: bool,
53 pub bottom: bool,
54 pub left: bool,
55}
56
57#[derive(Debug)]
58pub struct Path {
59 pub bounds: RectF,
60 pub color: ColorU,
61 pub vertices: Vec<PathVertex>,
62}
63
64#[derive(Debug)]
65pub struct PathVertex {
66 pub xy_position: Vector2F,
67 pub st_position: Vector2F,
68}
69
70impl Scene {
71 pub fn new(scale_factor: f32) -> Self {
72 Scene {
73 scale_factor,
74 layers: vec![Layer::new(None)],
75 active_layer_stack: vec![0],
76 }
77 }
78
79 pub fn scale_factor(&self) -> f32 {
80 self.scale_factor
81 }
82
83 pub fn layers(&self) -> &[Layer] {
84 self.layers.as_slice()
85 }
86
87 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
88 let ix = self.layers.len();
89 self.layers.push(Layer::new(clip_bounds));
90 self.active_layer_stack.push(ix);
91 }
92
93 pub fn pop_layer(&mut self) {
94 assert!(self.active_layer_stack.len() > 1);
95 self.active_layer_stack.pop();
96 }
97
98 pub fn push_quad(&mut self, quad: Quad) {
99 self.active_layer().push_quad(quad)
100 }
101
102 pub fn push_shadow(&mut self, shadow: Shadow) {
103 self.active_layer().push_shadow(shadow)
104 }
105
106 pub fn push_glyph(&mut self, glyph: Glyph) {
107 self.active_layer().push_glyph(glyph)
108 }
109
110 pub fn push_path(&mut self, path: Path) {
111 self.active_layer().push_path(path);
112 }
113
114 fn active_layer(&mut self) -> &mut Layer {
115 &mut self.layers[*self.active_layer_stack.last().unwrap()]
116 }
117}
118
119impl Layer {
120 pub fn new(clip_bounds: Option<RectF>) -> Self {
121 Self {
122 clip_bounds,
123 quads: Vec::new(),
124 shadows: Vec::new(),
125 glyphs: Vec::new(),
126 paths: Vec::new(),
127 }
128 }
129
130 pub fn clip_bounds(&self) -> Option<RectF> {
131 self.clip_bounds
132 }
133
134 fn push_quad(&mut self, quad: Quad) {
135 self.quads.push(quad);
136 }
137
138 pub fn quads(&self) -> &[Quad] {
139 self.quads.as_slice()
140 }
141
142 fn push_shadow(&mut self, shadow: Shadow) {
143 self.shadows.push(shadow);
144 }
145
146 pub fn shadows(&self) -> &[Shadow] {
147 self.shadows.as_slice()
148 }
149
150 fn push_glyph(&mut self, glyph: Glyph) {
151 self.glyphs.push(glyph);
152 }
153
154 pub fn glyphs(&self) -> &[Glyph] {
155 self.glyphs.as_slice()
156 }
157
158 fn push_path(&mut self, path: Path) {
159 if !path.bounds.is_empty() {
160 self.paths.push(path);
161 }
162 }
163
164 pub fn paths(&self) -> &[Path] {
165 self.paths.as_slice()
166 }
167}
168
169impl Border {
170 pub fn new(width: f32, color: impl Into<ColorU>) -> Self {
171 Self {
172 width,
173 color: Some(color.into()),
174 top: false,
175 left: false,
176 bottom: false,
177 right: false,
178 }
179 }
180
181 pub fn all(width: f32, color: impl Into<ColorU>) -> Self {
182 Self {
183 width,
184 color: Some(color.into()),
185 top: true,
186 left: true,
187 bottom: true,
188 right: true,
189 }
190 }
191
192 pub fn top(width: f32, color: impl Into<ColorU>) -> Self {
193 let mut border = Self::new(width, color);
194 border.top = true;
195 border
196 }
197
198 pub fn left(width: f32, color: impl Into<ColorU>) -> Self {
199 let mut border = Self::new(width, color);
200 border.left = true;
201 border
202 }
203
204 pub fn bottom(width: f32, color: impl Into<ColorU>) -> Self {
205 let mut border = Self::new(width, color);
206 border.bottom = true;
207 border
208 }
209
210 pub fn right(width: f32, color: impl Into<ColorU>) -> Self {
211 let mut border = Self::new(width, color);
212 border.right = true;
213 border
214 }
215
216 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
217 self.top = top;
218 self.left = left;
219 self.bottom = bottom;
220 self.right = right;
221 self
222 }
223
224 fn all_sides(&self) -> bool {
225 self.top && self.left && self.bottom && self.right
226 }
227
228 pub fn top_width(&self) -> f32 {
229 if self.top {
230 self.width
231 } else {
232 0.0
233 }
234 }
235
236 pub fn left_width(&self) -> f32 {
237 if self.left {
238 self.width
239 } else {
240 0.0
241 }
242 }
243}