scene.rs

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