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