scene.rs

  1use std::{iter::Peekable, mem, slice};
  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        self.polychrome_sprites.sort_unstable();
 67        BatchIterator {
 68            quads: &self.quads,
 69            quads_start: 0,
 70            quads_iter: self.quads.iter().peekable(),
 71            monochrome_sprites: &self.monochrome_sprites,
 72            monochrome_sprites_start: 0,
 73            monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
 74            polychrome_sprites: &self.polychrome_sprites,
 75            polychrome_sprites_start: 0,
 76            polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(),
 77        }
 78    }
 79}
 80
 81struct BatchIterator<'a> {
 82    quads: &'a [Quad],
 83    quads_start: usize,
 84    quads_iter: Peekable<slice::Iter<'a, Quad>>,
 85    monochrome_sprites: &'a [MonochromeSprite],
 86    monochrome_sprites_start: usize,
 87    monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
 88    polychrome_sprites: &'a [PolychromeSprite],
 89    polychrome_sprites_start: usize,
 90    polychrome_sprites_iter: Peekable<slice::Iter<'a, PolychromeSprite>>,
 91}
 92
 93impl<'a> Iterator for BatchIterator<'a> {
 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::MonochromeSprite,
101                self.monochrome_sprites_iter.peek().map(|s| s.order),
102            ),
103            (
104                PrimitiveKind::PolychromeSprite,
105                self.polychrome_sprites_iter.peek().map(|s| s.order),
106            ),
107        ];
108        kinds_and_orders.sort_by_key(|(_, order)| order.unwrap_or(u32::MAX));
109
110        let first = kinds_and_orders[0];
111        let second = kinds_and_orders[1];
112        let (batch_kind, max_order) = if first.1.is_some() {
113            (first.0, second.1.unwrap_or(u32::MAX))
114        } else {
115            return None;
116        };
117
118        match batch_kind {
119            PrimitiveKind::Quad => {
120                let quads_start = self.quads_start;
121                let quads_end = quads_start
122                    + self
123                        .quads_iter
124                        .by_ref()
125                        .take_while(|quad| quad.order <= max_order)
126                        .count();
127                self.quads_start = quads_end;
128                Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
129            }
130            PrimitiveKind::MonochromeSprite => {
131                let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
132                let sprites_start = self.monochrome_sprites_start;
133                let sprites_end = sprites_start
134                    + self
135                        .monochrome_sprites_iter
136                        .by_ref()
137                        .take_while(|sprite| {
138                            sprite.order <= max_order && sprite.tile.texture_id == texture_id
139                        })
140                        .count();
141                self.monochrome_sprites_start = sprites_end;
142                Some(PrimitiveBatch::MonochromeSprites {
143                    texture_id,
144                    sprites: &self.monochrome_sprites[sprites_start..sprites_end],
145                })
146            }
147            PrimitiveKind::PolychromeSprite => {
148                let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
149                let sprites_start = self.polychrome_sprites_start;
150                let sprites_end = sprites_start
151                    + self
152                        .polychrome_sprites_iter
153                        .by_ref()
154                        .take_while(|sprite| {
155                            sprite.order <= max_order && sprite.tile.texture_id == texture_id
156                        })
157                        .count();
158                self.polychrome_sprites_start = sprites_end;
159                Some(PrimitiveBatch::PolychromeSprites {
160                    texture_id,
161                    sprites: &self.polychrome_sprites[sprites_start..sprites_end],
162                })
163            }
164        }
165    }
166}
167
168#[derive(Clone, Copy, Debug, Eq, PartialEq)]
169pub enum PrimitiveKind {
170    Quad,
171    MonochromeSprite,
172    PolychromeSprite,
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    pub grayscale: bool,
280}
281
282impl Ord for PolychromeSprite {
283    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
284        match self.order.cmp(&other.order) {
285            std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
286            order => order,
287        }
288    }
289}
290
291impl PartialOrd for PolychromeSprite {
292    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
293        Some(self.cmp(other))
294    }
295}
296
297impl From<PolychromeSprite> for Primitive {
298    fn from(sprite: PolychromeSprite) -> Self {
299        Primitive::PolychromeSprite(sprite)
300    }
301}
302
303#[derive(Copy, Clone, Debug)]
304pub struct AtlasId(pub(crate) usize);