atlas.rs

  1use crate::geometry::vector::vec2i;
  2use crate::geometry::vector::Vector2I;
  3use anyhow::anyhow;
  4use etagere::BucketedAtlasAllocator;
  5use metal::{self, Device, TextureDescriptor};
  6
  7pub struct AtlasAllocator {
  8    device: Device,
  9    texture_descriptor: TextureDescriptor,
 10    atlasses: Vec<Atlas>,
 11    free_atlasses: Vec<Atlas>,
 12}
 13
 14impl AtlasAllocator {
 15    pub fn new(device: Device, texture_descriptor: TextureDescriptor) -> Self {
 16        let me = Self {
 17            device,
 18            texture_descriptor,
 19            atlasses: Vec::new(),
 20            free_atlasses: Vec::new(),
 21        };
 22        me.atlasses.push(me.new_atlas());
 23        me
 24    }
 25
 26    fn atlas_size(&self) -> Vector2I {
 27        vec2i(
 28            self.texture_descriptor.width() as i32,
 29            self.texture_descriptor.height() as i32,
 30        )
 31    }
 32
 33    pub fn allocate(&mut self, requested_size: Vector2I) -> anyhow::Result<(usize, Vector2I)> {
 34        let atlas_size = self.atlas_size();
 35        if requested_size.x() > atlas_size.x() || requested_size.y() > atlas_size.y() {
 36            return Err(anyhow!(
 37                "requested size {:?} too large for atlas {:?}",
 38                requested_size,
 39                atlas_size
 40            ));
 41        }
 42
 43        let origin = self
 44            .atlasses
 45            .last_mut()
 46            .unwrap()
 47            .allocate(requested_size)
 48            .unwrap_or_else(|| {
 49                let mut atlas = self.new_atlas();
 50                let origin = atlas.allocate(requested_size).unwrap();
 51                self.atlasses.push(atlas);
 52                origin
 53            });
 54
 55        Ok((self.atlasses.len() - 1, origin))
 56    }
 57
 58    pub fn clear(&mut self) {
 59        for atlas in &mut self.atlasses {
 60            atlas.clear();
 61        }
 62        self.free_atlasses.extend(self.atlasses.drain(1..));
 63    }
 64
 65    fn new_atlas(&mut self) -> Atlas {
 66        self.free_atlasses.pop().unwrap_or_else(|| {
 67            Atlas::new(
 68                self.atlas_size(),
 69                self.device.new_texture(&self.texture_descriptor),
 70            )
 71        })
 72    }
 73}
 74
 75struct Atlas {
 76    allocator: BucketedAtlasAllocator,
 77    texture: metal::Texture,
 78}
 79
 80impl Atlas {
 81    fn new(size: Vector2I, texture: metal::Texture) -> Self {
 82        Self {
 83            allocator: BucketedAtlasAllocator::new(etagere::Size::new(size.x(), size.y())),
 84            texture,
 85        }
 86    }
 87
 88    fn allocate(&mut self, size: Vector2I) -> Option<Vector2I> {
 89        let origin = self
 90            .allocator
 91            .allocate(etagere::Size::new(size.x(), size.y()))?
 92            .rectangle
 93            .min;
 94        Some(vec2i(origin.x, origin.y))
 95    }
 96
 97    fn clear(&mut self) {
 98        self.allocator.clear();
 99    }
100}