1use std::{iter::Peekable, mem};
2
3use super::{Bounds, Hsla, Point};
4use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledContentMask, ScaledPixels};
5use collections::BTreeMap;
6use smallvec::SmallVec;
7
8// Exported to metal
9pub type PointF = Point<f32>;
10pub type LayerId = SmallVec<[u32; 16]>;
11
12#[derive(Debug)]
13pub struct Scene {
14 pub(crate) scale_factor: f32,
15 pub(crate) layers: BTreeMap<LayerId, SceneLayer>,
16}
17
18impl Scene {
19 pub fn new(scale_factor: f32) -> Scene {
20 Scene {
21 scale_factor,
22 layers: BTreeMap::new(),
23 }
24 }
25
26 pub fn take(&mut self) -> Scene {
27 Scene {
28 scale_factor: self.scale_factor,
29 layers: mem::take(&mut self.layers),
30 }
31 }
32
33 pub fn insert(&mut self, stacking_order: LayerId, primitive: impl Into<Primitive>) {
34 let layer = self.layers.entry(stacking_order).or_default();
35
36 let primitive = primitive.into();
37 match primitive {
38 Primitive::Quad(quad) => {
39 layer.quads.push(quad);
40 }
41 Primitive::MonochromeSprite(sprite) => {
42 layer.monochrome_sprites.push(sprite);
43 }
44 Primitive::PolychromeSprite(sprite) => {
45 layer.polychrome_sprites.push(sprite);
46 }
47 }
48 }
49
50 pub(crate) fn layers(&mut self) -> impl Iterator<Item = &mut SceneLayer> {
51 self.layers.values_mut()
52 }
53}
54
55#[derive(Debug, Default)]
56pub(crate) struct SceneLayer {
57 pub quads: Vec<Quad>,
58 pub monochrome_sprites: Vec<MonochromeSprite>,
59 pub polychrome_sprites: Vec<PolychromeSprite>,
60}
61
62impl SceneLayer {
63 pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
64 self.quads.sort_unstable();
65 self.monochrome_sprites.sort_unstable();
66
67 BatchIterator::new(
68 &self.quads,
69 self.quads.iter().peekable(),
70 &self.monochrome_sprites,
71 self.monochrome_sprites.iter().peekable(),
72 )
73 }
74}
75
76struct BatchIterator<'a, Q, S>
77where
78 Q: Iterator<Item = &'a Quad>,
79 S: Iterator<Item = &'a MonochromeSprite>,
80{
81 quads: &'a [Quad],
82 sprites: &'a [MonochromeSprite],
83 quads_start: usize,
84 sprites_start: usize,
85 quads_iter: Peekable<Q>,
86 sprites_iter: Peekable<S>,
87}
88
89impl<'a, Q: 'a, S: 'a> Iterator for BatchIterator<'a, Q, S>
90where
91 Q: Iterator<Item = &'a Quad>,
92 S: Iterator<Item = &'a MonochromeSprite>,
93{
94 type Item = PrimitiveBatch<'a>;
95
96 fn next(&mut self) -> Option<Self::Item> {
97 let mut kinds_and_orders = [
98 (PrimitiveKind::Quad, self.quads_iter.peek().map(|q| q.order)),
99 (
100 PrimitiveKind::Sprite,
101 self.sprites_iter.peek().map(|s| s.order),
102 ),
103 ];
104 kinds_and_orders.sort_by_key(|(_, order)| order.unwrap_or(u32::MAX));
105
106 let first = kinds_and_orders[0];
107 let second = kinds_and_orders[1];
108 let (batch_kind, max_order) = if first.1.is_some() {
109 (first.0, second.1.unwrap_or(u32::MAX))
110 } else {
111 return None;
112 };
113
114 match batch_kind {
115 PrimitiveKind::Quad => {
116 let quads_start = self.quads_start;
117 let quads_end = quads_start
118 + self
119 .quads_iter
120 .by_ref()
121 .take_while(|quad| quad.order <= max_order)
122 .count();
123 self.quads_start = quads_end;
124 Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
125 }
126 PrimitiveKind::Sprite => {
127 let texture_id = self.sprites_iter.peek().unwrap().tile.texture_id;
128 let sprites_start = self.sprites_start;
129 let sprites_end = sprites_start
130 + self
131 .sprites_iter
132 .by_ref()
133 .take_while(|sprite| {
134 sprite.order <= max_order && sprite.tile.texture_id == texture_id
135 })
136 .count();
137 self.sprites_start = sprites_end;
138 Some(PrimitiveBatch::MonochromeSprites {
139 texture_id,
140 sprites: &self.sprites[sprites_start..sprites_end],
141 })
142 }
143 }
144 }
145}
146
147impl<'a, Q: 'a, S: 'a> BatchIterator<'a, Q, S>
148where
149 Q: Iterator<Item = &'a Quad>,
150 S: Iterator<Item = &'a MonochromeSprite>,
151{
152 fn new(
153 quads: &'a [Quad],
154 quads_iter: Peekable<Q>,
155 sprites: &'a [MonochromeSprite],
156 sprites_iter: Peekable<S>,
157 ) -> Self {
158 Self {
159 quads,
160 quads_start: 0,
161 quads_iter,
162 sprites,
163 sprites_start: 0,
164 sprites_iter,
165 }
166 }
167}
168
169#[derive(Clone, Copy, Debug, Eq, PartialEq)]
170pub enum PrimitiveKind {
171 Quad,
172 Sprite,
173}
174
175#[derive(Clone, Debug)]
176pub enum Primitive {
177 Quad(Quad),
178 MonochromeSprite(MonochromeSprite),
179 PolychromeSprite(PolychromeSprite),
180}
181
182pub(crate) enum PrimitiveBatch<'a> {
183 Quads(&'a [Quad]),
184 MonochromeSprites {
185 texture_id: AtlasTextureId,
186 sprites: &'a [MonochromeSprite],
187 },
188 PolychromeSprites {
189 texture_id: AtlasTextureId,
190 sprites: &'a [PolychromeSprite],
191 },
192}
193
194#[derive(Debug, Copy, Clone, Eq, PartialEq)]
195#[repr(C)]
196pub struct Quad {
197 pub order: u32,
198 pub bounds: Bounds<ScaledPixels>,
199 pub clip_bounds: Bounds<ScaledPixels>,
200 pub clip_corner_radii: Corners<ScaledPixels>,
201 pub background: Hsla,
202 pub border_color: Hsla,
203 pub corner_radii: Corners<ScaledPixels>,
204 pub border_widths: Edges<ScaledPixels>,
205}
206
207impl Quad {
208 pub fn vertices(&self) -> impl Iterator<Item = Point<ScaledPixels>> {
209 let x1 = self.bounds.origin.x;
210 let y1 = self.bounds.origin.y;
211 let x2 = x1 + self.bounds.size.width;
212 let y2 = y1 + self.bounds.size.height;
213 [
214 Point::new(x1, y1),
215 Point::new(x2, y1),
216 Point::new(x2, y2),
217 Point::new(x1, y2),
218 ]
219 .into_iter()
220 }
221}
222
223impl Ord for Quad {
224 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
225 self.order.cmp(&other.order)
226 }
227}
228
229impl PartialOrd for Quad {
230 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
231 Some(self.cmp(other))
232 }
233}
234
235impl From<Quad> for Primitive {
236 fn from(quad: Quad) -> Self {
237 Primitive::Quad(quad)
238 }
239}
240
241#[derive(Clone, Debug, Eq, PartialEq)]
242#[repr(C)]
243pub struct MonochromeSprite {
244 pub order: u32,
245 pub bounds: Bounds<ScaledPixels>,
246 pub content_mask: ScaledContentMask,
247 pub color: Hsla,
248 pub tile: AtlasTile,
249}
250
251impl Ord for MonochromeSprite {
252 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
253 match self.order.cmp(&other.order) {
254 std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
255 order => order,
256 }
257 }
258}
259
260impl PartialOrd for MonochromeSprite {
261 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
262 Some(self.cmp(other))
263 }
264}
265
266impl From<MonochromeSprite> for Primitive {
267 fn from(sprite: MonochromeSprite) -> Self {
268 Primitive::MonochromeSprite(sprite)
269 }
270}
271
272#[derive(Clone, Debug, Eq, PartialEq)]
273#[repr(C)]
274pub struct PolychromeSprite {
275 pub order: u32,
276 pub bounds: Bounds<ScaledPixels>,
277 pub content_mask: ScaledContentMask,
278 pub tile: AtlasTile,
279}
280
281impl Ord for PolychromeSprite {
282 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
283 match self.order.cmp(&other.order) {
284 std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
285 order => order,
286 }
287 }
288}
289
290impl PartialOrd for PolychromeSprite {
291 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
292 Some(self.cmp(other))
293 }
294}
295
296impl From<PolychromeSprite> for Primitive {
297 fn from(sprite: PolychromeSprite) -> Self {
298 Primitive::PolychromeSprite(sprite)
299 }
300}
301
302#[derive(Copy, Clone, Debug)]
303pub struct AtlasId(pub(crate) usize);