scene.rs

  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);