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}