scene.rs

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