1use crate::{AllocId, Allocation, AllocatorOptions, DEFAULT_OPTIONS, Size, Rectangle, point2, size2};
2
3const SHELF_SPLIT_THRESHOLD: u16 = 8;
4const ITEM_SPLIT_THRESHOLD: u16 = 8;
5
6#[repr(transparent)]
7#[derive(Copy, Clone, Debug, PartialEq, Eq)]
8#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
9struct ShelfIndex(u16);
10
11impl ShelfIndex {
12 const NONE: Self = ShelfIndex(std::u16::MAX);
13
14 fn index(self) -> usize { self.0 as usize }
15
16 fn is_some(self) -> bool { self.0 != std::u16::MAX }
17
18 fn is_none(self) -> bool { self.0 == std::u16::MAX }
19}
20
21#[repr(transparent)]
22#[derive(Copy, Clone, Debug, PartialEq, Eq)]
23#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
24struct ItemIndex(u16);
25
26impl ItemIndex {
27 const NONE: Self = ItemIndex(std::u16::MAX);
28
29 fn index(self) -> usize { self.0 as usize }
30
31 fn is_some(self) -> bool { self.0 != std::u16::MAX }
32
33 fn is_none(self) -> bool { self.0 == std::u16::MAX }
34}
35
36#[derive(Clone)]
37#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
38struct Shelf {
39 x: u16,
40 y: u16,
41 height: u16,
42 prev: ShelfIndex,
43 next: ShelfIndex,
44 first_item: ItemIndex,
45 first_unallocated: ItemIndex,
46 is_empty: bool,
47}
48
49#[derive(Clone)]
50#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
51struct Item {
52 x: u16,
53 width: u16,
54 prev: ItemIndex,
55 next: ItemIndex,
56 prev_unallocated: ItemIndex,
57 next_unallocated: ItemIndex,
58 shelf: ShelfIndex,
59 allocated: bool,
60 generation: u16,
61}
62
63#[derive(Clone)]
69#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
70pub struct AtlasAllocator {
71 shelves: Vec<Shelf>,
72 items: Vec<Item>,
73 alignment: Size,
74 flip_xy: bool,
75 size: Size,
76 first_shelf: ShelfIndex,
77 free_items: ItemIndex,
78 free_shelves: ShelfIndex,
79 shelf_width: u16,
80 allocated_space: i32,
81}
82
83impl AtlasAllocator {
84 pub fn with_options(size: Size, options: &AllocatorOptions) -> Self {
86 let (shelf_alignment, width, height) = if options.vertical_shelves {
87 (options.alignment.height, size.height, size.width)
88 } else {
89 (options.alignment.width, size.width, size.height)
90 };
91 let mut shelf_width = width / options.num_columns;
92 shelf_width -= shelf_width % shelf_alignment;
93
94 let mut atlas = AtlasAllocator {
95 shelves: Vec::new(),
96 items: Vec::new(),
97 size: size2(width, height),
98 alignment: options.alignment,
99 flip_xy: options.vertical_shelves,
100 first_shelf: ShelfIndex(0),
101 free_items: ItemIndex::NONE,
102 free_shelves: ShelfIndex::NONE,
103 shelf_width: shelf_width as u16,
104 allocated_space: 0,
105 };
106
107 atlas.init();
108
109 atlas
110 }
111
112 pub fn new(size: Size) -> Self {
114 Self::with_options(size, &DEFAULT_OPTIONS)
115 }
116
117 pub fn clear(&mut self) {
118 self.init();
119 }
120
121 fn init(&mut self) {
122 assert!(self.size.width > 0);
123 assert!(self.size.height > 0);
124 assert!(self.size.width <= std::u16::MAX as i32);
125 assert!(self.size.height <= std::u16::MAX as i32);
126 assert!(
127 self.size.width.checked_mul(self.size.height).is_some(),
128 "The area of the atlas must fit in a i32 value"
129 );
130
131 assert!(self.alignment.width > 0);
132 assert!(self.alignment.height > 0);
133
134 self.shelves.clear();
135 self.items.clear();
136
137 let num_columns = self.size.width as u16 / self.shelf_width;
138
139 let mut prev = ShelfIndex::NONE;
140 for i in 0..num_columns {
141 let first_item = ItemIndex(self.items.len() as u16);
142 let x = i * self.shelf_width;
143 let current = ShelfIndex(i);
144 let next = if i + 1 < num_columns { ShelfIndex(i + 1) } else { ShelfIndex::NONE };
145
146 self.shelves.push(Shelf {
147 x,
148 y: 0,
149 height: self.size.height as u16,
150 prev,
151 next,
152 is_empty: true,
153 first_item,
154 first_unallocated: first_item,
155 });
156
157 self.items.push(Item {
158 x,
159 width: self.shelf_width,
160 prev: ItemIndex::NONE,
161 next: ItemIndex::NONE,
162 prev_unallocated: ItemIndex::NONE,
163 next_unallocated: ItemIndex::NONE,
164 shelf: current,
165 allocated: false,
166 generation: 1,
167 });
168
169 prev = current;
170 }
171
172 self.first_shelf = ShelfIndex(0);
173 self.free_items = ItemIndex::NONE;
174 self.free_shelves = ShelfIndex::NONE;
175 self.allocated_space = 0;
176 }
177
178 pub fn size(&self) -> Size {
179 if self.flip_xy {
180 size2(self.size.height, self.size.width)
181 } else {
182 self.size
183 }
184 }
185
186 pub fn allocate(&mut self, mut size: Size) -> Option<Allocation> {
188 if size.is_empty()
189 || size.width > std::u16::MAX as i32
190 || size.height > std::u16::MAX as i32 {
191 return None;
192 }
193
194 adjust_size(self.alignment.width, &mut size.width);
195 adjust_size(self.alignment.height, &mut size.height);
196
197 let (width, height) = convert_coordinates(self.flip_xy, size.width, size.height);
198
199 if width > self.shelf_width as i32 || height > self.size.height {
200 return None;
201 }
202
203 let height = shelf_height(height, self.size.height);
204
205 let mut width = width as u16;
206 let mut height = height as u16;
207
208 let bad_fit_threshold = height.saturating_add(height / 2);
212 let mut selected_shelf_height = std::u16::MAX;
213 let mut selected_shelf = ShelfIndex::NONE;
214 let mut selected_item = ItemIndex::NONE;
215 let mut shelf_idx = self.first_shelf;
216 while shelf_idx.is_some() {
217 let shelf = &self.shelves[shelf_idx.index()];
218
219 if shelf.height < height
220 || shelf.height >= selected_shelf_height {
221 shelf_idx = shelf.next;
222 continue;
223 }
224
225 let bad_fit = !shelf.is_empty && shelf.height > bad_fit_threshold;
226 if bad_fit && selected_shelf.is_some() {
227 shelf_idx = shelf.next;
234 continue;
235 }
236
237 let mut item_idx = shelf.first_unallocated;
238 while item_idx.is_some() {
239 let item = &self.items[item_idx.index()];
240 if !item.allocated && item.width >= width {
241 break;
242 }
243
244 item_idx = item.next_unallocated;
245 }
246
247 if item_idx.is_some() {
248 selected_shelf = shelf_idx;
249 selected_item = item_idx;
250 if !bad_fit {
251 selected_shelf_height = shelf.height;
255 }
256
257 if shelf.height == height {
258 break;
260 }
261 }
262
263 shelf_idx = shelf.next;
264 }
265
266 if selected_shelf.is_none() {
267 return None;
268 }
269
270 let shelf = self.shelves[selected_shelf.index()].clone();
271 if shelf.is_empty {
272 self.shelves[selected_shelf.index()].is_empty = false;
273 }
274
275 if shelf.is_empty && shelf.height > height + SHELF_SPLIT_THRESHOLD {
276 let new_shelf_idx = self.add_shelf(Shelf {
280 x: shelf.x,
281 y: shelf.y + height,
282 height: shelf.height - height,
283 prev: selected_shelf,
284 next: shelf.next,
285 first_item: ItemIndex::NONE,
286 first_unallocated: ItemIndex::NONE,
287 is_empty: true,
288 });
289
290 let new_item_idx = self.add_item(Item {
291 x: shelf.x,
292 width: self.shelf_width,
293 prev: ItemIndex::NONE,
294 next: ItemIndex::NONE,
295 prev_unallocated: ItemIndex::NONE,
296 next_unallocated: ItemIndex::NONE,
297 shelf: new_shelf_idx,
298 allocated: false,
299 generation: 1,
300 });
301
302 self.shelves[new_shelf_idx.index()].first_item = new_item_idx;
303 self.shelves[new_shelf_idx.index()].first_unallocated = new_item_idx;
304
305 let next = self.shelves[selected_shelf.index()].next;
306 self.shelves[selected_shelf.index()].height = height;
307 self.shelves[selected_shelf.index()].next = new_shelf_idx;
308
309 if next.is_some() {
310 self.shelves[next.index()].prev = new_shelf_idx;
311 }
312 } else {
313 height = shelf.height;
314 }
315
316 let item = self.items[selected_item.index()].clone();
317
318 if item.width - width > ITEM_SPLIT_THRESHOLD {
319
320 let new_item_idx = self.add_item(Item {
321 x: item.x + width,
322 width: item.width - width,
323 prev: selected_item,
324 next: item.next,
325 prev_unallocated: item.prev_unallocated,
326 next_unallocated: item.next_unallocated,
327 shelf: item.shelf,
328 allocated: false,
329 generation: 1,
330 });
331
332 self.items[selected_item.index()].width = width;
333 self.items[selected_item.index()].next = new_item_idx;
334
335 if item.next.is_some() {
336 self.items[item.next.index()].prev = new_item_idx;
337 }
338
339 let shelf = &mut self.shelves[selected_shelf.index()];
341 if shelf.first_unallocated == selected_item {
342 shelf.first_unallocated = new_item_idx;
343 }
344 if item.prev_unallocated.is_some() {
345 self.items[item.prev_unallocated.index()].next_unallocated = new_item_idx;
346 }
347 if item.next_unallocated.is_some() {
348 self.items[item.next_unallocated.index()].prev_unallocated = new_item_idx;
349 }
350 } else {
351 let shelf = &mut self.shelves[selected_shelf.index()];
353 if shelf.first_unallocated == selected_item {
354 shelf.first_unallocated = item.next_unallocated;
355 }
356 if item.prev_unallocated.is_some() {
357 self.items[item.prev_unallocated.index()].next_unallocated = item.next_unallocated;
358 }
359 if item.next_unallocated.is_some() {
360 self.items[item.next_unallocated.index()].prev_unallocated = item.prev_unallocated;
361 }
362
363 width = item.width;
364 }
365
366 self.items[selected_item.index()].allocated = true;
367 let generation = self.items[selected_item.index()].generation;
368
369 let x0 = item.x;
370 let y0 = shelf.y;
371 let x1 = x0 + width;
372 let y1 = y0 + height;
373
374 let (x0, y0) = convert_coordinates(self.flip_xy, x0 as i32, y0 as i32);
375 let (x1, y1) = convert_coordinates(self.flip_xy, x1 as i32, y1 as i32);
376
377 self.check();
378
379 let rectangle = Rectangle {
380 min: point2(x0, y0),
381 max: point2(x1, y1),
382 };
383
384 self.allocated_space += rectangle.area();
385
386 Some(Allocation {
387 id: AllocId::new(selected_item.0, generation),
388 rectangle,
389 })
390 }
391
392 pub fn deallocate(&mut self, id: AllocId) {
394 let item_idx = ItemIndex(id.index());
395
396 let Item { mut prev, mut next, mut width, allocated, shelf, generation, .. } = self.items[item_idx.index()];
397 assert!(allocated);
398 assert_eq!(generation, id.generation(), "Invalid AllocId");
399
400 self.items[item_idx.index()].allocated = false;
401 self.allocated_space -= width as i32 * self.shelves[shelf.index()].height as i32;
402
403 if next.is_some() && !self.items[next.index()].allocated {
404 let next_next = self.items[next.index()].next;
407 let next_width = self.items[next.index()].width;
408 let next_unallocated = self.items[next.index()].next_unallocated;
410 let prev_unallocated = self.items[next.index()].prev_unallocated;
411 if self.shelves[shelf.index()].first_unallocated == next {
412 self.shelves[shelf.index()].first_unallocated = next_unallocated;
413 }
414 if prev_unallocated.is_some() {
415 self.items[prev_unallocated.index()].next_unallocated = next_unallocated;
416 }
417 if next_unallocated.is_some() {
418 self.items[next_unallocated.index()].prev_unallocated = prev_unallocated;
419 }
420
421 self.items[item_idx.index()].next = next_next;
422 self.items[item_idx.index()].width += next_width;
423 width = self.items[item_idx.index()].width;
424
425 if next_next.is_some() {
426 self.items[next_next.index()].prev = item_idx;
427 }
428
429 self.remove_item(next);
431
432 next = next_next
433 }
434
435 if prev.is_some() && !self.items[prev.index()].allocated {
436 self.items[prev.index()].next = next;
441 self.items[prev.index()].width += width;
442
443 if next.is_some() {
444 self.items[next.index()].prev = prev;
445 }
446
447 self.remove_item(item_idx);
449
450 prev = self.items[prev.index()].prev;
451 } else {
452 let first = self.shelves[shelf.index()].first_unallocated;
454 if first.is_some() {
455 self.items[first.index()].prev_unallocated = item_idx;
456 }
457 self.items[item_idx.index()].next_unallocated = first;
458 self.items[item_idx.index()].prev_unallocated = ItemIndex::NONE;
459 self.shelves[shelf.index()].first_unallocated = item_idx;
460 }
461
462 if prev.is_none() && next.is_none() {
463 let shelf_idx = shelf;
464 self.shelves[shelf_idx.index()].is_empty = true;
466
467 let x = self.shelves[shelf_idx.index()].x;
469
470 let next_shelf = self.shelves[shelf_idx.index()].next;
471 if next_shelf.is_some()
472 && self.shelves[next_shelf.index()].is_empty
473 && self.shelves[next_shelf.index()].x == x {
474 let next_next = self.shelves[next_shelf.index()].next;
477 let next_height = self.shelves[next_shelf.index()].height;
478
479 self.shelves[shelf_idx.index()].next = next_next;
480 self.shelves[shelf_idx.index()].height += next_height;
481
482 if next_next.is_some() {
483 self.shelves[next_next.index()].prev = shelf_idx;
484 }
485
486 self.remove_shelf(next_shelf);
488 }
489
490 let prev_shelf = self.shelves[shelf_idx.index()].prev;
491 if prev_shelf.is_some()
492 && self.shelves[prev_shelf.index()].is_empty
493 && self.shelves[prev_shelf.index()].x == x {
494 let next_shelf = self.shelves[shelf_idx.index()].next;
497 self.shelves[prev_shelf.index()].next = next_shelf;
498 self.shelves[prev_shelf.index()].height += self.shelves[shelf_idx.index()].height;
499
500 self.shelves[prev_shelf.index()].next = self.shelves[shelf_idx.index()].next;
501 if next_shelf.is_some() {
502 self.shelves[next_shelf.index()].prev = prev_shelf;
503 }
504
505 self.remove_shelf(shelf_idx);
507 }
508 }
509
510 self.check();
511 }
512
513 pub fn is_empty(&self) -> bool {
514 let mut shelf_idx = self.first_shelf;
515
516 while shelf_idx.is_some() {
517 let shelf = &self.shelves[shelf_idx.index()];
518 if !shelf.is_empty {
519 return false;
520 }
521
522 shelf_idx = shelf.next;
523 }
524
525 true
526 }
527
528 pub fn allocated_space(&self) -> i32 {
530 self.allocated_space
531 }
532
533 pub fn free_space(&self) -> i32 {
535 self.size.area() - self.allocated_space
536 }
537
538 pub fn iter(&self) -> Iter {
539 Iter {
540 atlas: self,
541 idx: 0,
542 }
543 }
544
545 fn remove_item(&mut self, idx: ItemIndex) {
546 self.items[idx.index()].next = self.free_items;
547 self.free_items = idx;
548 }
549
550 fn remove_shelf(&mut self, idx: ShelfIndex) {
551 self.remove_item(self.shelves[idx.index()].first_item);
553
554 self.shelves[idx.index()].next = self.free_shelves;
555 self.free_shelves = idx;
556 }
557
558 fn add_item(&mut self, mut item: Item) -> ItemIndex {
559 if self.free_items.is_some() {
560 let idx = self.free_items;
561 item.generation = self.items[idx.index()].generation.wrapping_add(1);
562 self.free_items = self.items[idx.index()].next;
563 self.items[idx.index()] = item;
564
565 return idx;
566 }
567
568 let idx = ItemIndex(self.items.len() as u16);
569 self.items.push(item);
570
571 idx
572 }
573
574 fn add_shelf(&mut self, shelf: Shelf) -> ShelfIndex {
575 if self.free_shelves.is_some() {
576 let idx = self.free_shelves;
577 self.free_shelves = self.shelves[idx.index()].next;
578 self.shelves[idx.index()] = shelf;
579
580 return idx;
581 }
582
583 let idx = ShelfIndex(self.shelves.len() as u16);
584 self.shelves.push(shelf);
585
586 idx
587 }
588
589 #[cfg(not(feature = "checks"))]
590 fn check(&self) {}
591
592 #[cfg(feature = "checks")]
593 fn check(&self) {
594 let mut prev_empty = false;
595 let mut accum_h = 0;
596 let mut shelf_idx = self.first_shelf;
597 let mut shelf_x = 0;
598 while shelf_idx.is_some() {
599 let shelf = &self.shelves[shelf_idx.index()];
600 let new_column = shelf_x != shelf.x;
601 if new_column {
602 assert_eq!(accum_h as i32, self.size.height);
603 accum_h = 0;
604 }
605 shelf_x = shelf.x;
606 accum_h += shelf.height;
607 if prev_empty && !new_column {
608 assert!(!shelf.is_empty);
609 }
610 if shelf.is_empty {
611 assert!(!self.items[shelf.first_item.index()].allocated);
612 assert!(self.items[shelf.first_item.index()].next.is_none());
613 }
614 prev_empty = shelf.is_empty;
615
616 let mut accum_w = 0;
617 let mut accum_unallocated_w = 0;
618 let mut prev_allocated = true;
619 let mut item_idx = shelf.first_item;
620 let mut prev_item_idx = ItemIndex::NONE;
621 while item_idx.is_some() {
622 let item = &self.items[item_idx.index()];
623 accum_w += item.width;
624 if !item.allocated {
625 accum_unallocated_w += item.width;
626 }
627
628 assert_eq!(item.prev, prev_item_idx);
629
630 if !prev_allocated {
631 assert!(item.allocated, "item {:?} should be allocated", item_idx.0);
632 }
633 prev_allocated = item.allocated;
634
635 prev_item_idx = item_idx;
636 item_idx = item.next;
637 }
638
639 assert_eq!(accum_w, self.shelf_width);
640
641 accum_w = 0;
644 let mut item_idx = shelf.first_unallocated;
645 let mut prev_unallocated_idx = ItemIndex::NONE;
646 while item_idx.is_some() {
647 let item = &self.items[item_idx.index()];
648 assert!(!item.allocated);
649
650 assert_eq!(item.prev_unallocated, prev_unallocated_idx);
651 accum_w += item.width;
652
653 prev_unallocated_idx = item_idx;
654 item_idx = item.next_unallocated;
655 }
656
657 assert_eq!(accum_w, accum_unallocated_w, "items missing from the unallocated list?");
658
659 shelf_idx = shelf.next;
660 }
661 }
662
663 pub fn get_index(&self, id: AllocId) -> u32 {
676 let index = id.index();
677 debug_assert_eq!(self.items[index as usize].generation, id.generation());
678
679 index as u32
680 }
681
682 pub fn get(&self, id: AllocId) -> Rectangle {
686 let index = id.index()as usize;
687 let item = &self.items[index];
688
689 assert!(item.allocated);
690 assert_eq!(item.generation, id.generation(), "Invalid AllocId");
691
692 let shelf = &self.shelves[item.shelf.index()];
693
694 let mut rectangle = Rectangle {
695 min: point2(
696 item.x as i32,
697 shelf.y as i32,
698 ),
699 max: point2(
700 (item.x + item.width) as i32,
701 (shelf.y + shelf.height) as i32,
702 ),
703 };
704
705 if self.flip_xy {
706 std::mem::swap(&mut rectangle.min.x, &mut rectangle.min.y);
707 std::mem::swap(&mut rectangle.max.x, &mut rectangle.max.y);
708 }
709
710 rectangle
711 }
712
713 pub fn dump_svg(&self, output: &mut dyn std::io::Write) -> std::io::Result<()> {
715 use svg_fmt::*;
716
717 writeln!(
718 output,
719 "{}",
720 BeginSvg {
721 w: self.size.width as f32,
722 h: self.size.height as f32
723 }
724 )?;
725
726 self.dump_into_svg(None, output)?;
727
728 writeln!(output, "{}", EndSvg)
729 }
730
731 pub fn dump_into_svg(&self, rect: Option<&Rectangle>, output: &mut dyn std::io::Write) -> std::io::Result<()> {
736 use svg_fmt::*;
737
738 let (sx, sy, tx, ty) = if let Some(rect) = rect {
739 (
740 rect.size().width as f32 / self.size.width as f32,
741 rect.size().height as f32 / self.size.height as f32,
742 rect.min.x as f32,
743 rect.min.y as f32,
744 )
745 } else {
746 (1.0, 1.0, 0.0, 0.0)
747 };
748
749 writeln!(
750 output,
751 r#" {}"#,
752 rectangle(tx, ty, self.size.width as f32 * sx, self.size.height as f32 * sy)
753 .fill(rgb(40, 40, 40))
754 .stroke(Stroke::Color(black(), 1.0))
755 )?;
756
757 let mut shelf_idx = self.first_shelf;
758 while shelf_idx.is_some() {
759 let shelf = &self.shelves[shelf_idx.index()];
760
761 let y = shelf.y as f32 * sy;
762 let h = shelf.height as f32 * sy;
763
764 let mut item_idx = shelf.first_item;
765 while item_idx.is_some() {
766 let item = &self.items[item_idx.index()];
767
768 let x = item.x as f32 * sx;
769 let w = item.width as f32 * sx;
770
771 let color = if item.allocated {
772 rgb(70, 70, 180)
773 } else {
774 rgb(50, 50, 50)
775 };
776
777 let (x, y) = if self.flip_xy { (y, x) } else { (x, y) };
778 let (w, h) = if self.flip_xy { (h, w) } else { (w, h) };
779
780 writeln!(
781 output,
782 r#" {}"#,
783 rectangle(x + tx, y + ty, w, h).fill(color).stroke(Stroke::Color(black(), 1.0))
784 )?;
785
786 item_idx = item.next;
787 }
788
789 shelf_idx = shelf.next;
790 }
791
792 Ok(())
793 }
794
795}
796
797
798fn adjust_size(alignment: i32, size: &mut i32) {
799 let rem = *size % alignment;
800 if rem > 0 {
801 *size += alignment - rem;
802 }
803}
804
805fn convert_coordinates(flip_xy: bool, x: i32, y: i32) -> (i32, i32) {
806 if flip_xy {
807 (y, x)
808 } else {
809 (x, y)
810 }
811}
812
813fn shelf_height(size: i32, atlas_height: i32) -> i32 {
814 let alignment = match size {
815 0 ..= 31 => 8,
816 32 ..= 127 => 16,
817 128 ..= 511 => 32,
818 _ => 64,
819 };
820
821 let mut adjusted_size = size;
822 let rem = size % alignment;
823 if rem > 0 {
824 adjusted_size = size + alignment - rem;
825 if adjusted_size > atlas_height {
826 adjusted_size = size;
827 }
828 }
829
830 adjusted_size
831}
832
833pub struct Iter<'l> {
835 atlas: &'l AtlasAllocator,
836 idx: usize,
837}
838
839impl<'l> Iterator for Iter<'l> {
840 type Item = Allocation;
841
842 fn next(&mut self) -> Option<Allocation> {
843 if self.idx >= self.atlas.items.len() {
844 return None;
845 }
846
847 while !self.atlas.items[self.idx].allocated {
848 self.idx += 1;
849 if self.idx >= self.atlas.items.len() {
850 return None;
851 }
852 }
853
854 let item = &self.atlas.items[self.idx];
855 let shelf = &self.atlas.shelves[item.shelf.index()];
856
857 let mut alloc = Allocation {
858 rectangle: Rectangle {
859 min: point2(
860 item.x as i32,
861 shelf.y as i32,
862 ),
863 max: point2(
864 (item.x + item.width) as i32,
865 (shelf.y + shelf.height) as i32,
866 ),
867 },
868 id: AllocId::new(self.idx as u16, item.generation),
869 };
870
871 if self.atlas.flip_xy {
872 std::mem::swap(&mut alloc.rectangle.min.x, &mut alloc.rectangle.min.y);
873 std::mem::swap(&mut alloc.rectangle.max.x, &mut alloc.rectangle.max.y);
874 }
875
876 self.idx += 1;
877
878 Some(alloc)
879 }
880}
881
882impl<'l> std::iter::IntoIterator for &'l AtlasAllocator {
883 type Item = Allocation;
884 type IntoIter = Iter<'l>;
885 fn into_iter(self) -> Iter<'l> {
886 self.iter()
887 }
888}
889
890#[test]
891fn test_simple() {
892 let mut atlas = AtlasAllocator::with_options(
893 size2(2048, 2048),
894 &AllocatorOptions {
895 alignment: size2(4, 8),
896 vertical_shelves: false,
897 num_columns: 2,
898 },
899 );
900
901 assert!(atlas.is_empty());
902 assert_eq!(atlas.allocated_space(), 0);
903
904 let a1 = atlas.allocate(size2(20, 30)).unwrap();
905 let a2 = atlas.allocate(size2(30, 40)).unwrap();
906 let a3 = atlas.allocate(size2(20, 30)).unwrap();
907
908 assert!(a1.id != a2.id);
909 assert!(a1.id != a3.id);
910 assert!(!atlas.is_empty());
911
912 atlas.deallocate(a1.id);
915 atlas.deallocate(a2.id);
916 atlas.deallocate(a3.id);
917
918 assert!(atlas.is_empty());
919 assert_eq!(atlas.allocated_space(), 0);
920}
921
922#[test]
923fn test_options() {
924 let alignment = size2(8, 16);
925
926 let mut atlas = AtlasAllocator::with_options(
927 size2(2000, 1000),
928 &AllocatorOptions {
929 alignment,
930 vertical_shelves: true,
931 num_columns: 1,
932 },
933 );
934 assert!(atlas.is_empty());
935 assert_eq!(atlas.allocated_space(), 0);
936
937 let a1 = atlas.allocate(size2(20, 30)).unwrap();
938 let a2 = atlas.allocate(size2(30, 40)).unwrap();
939 let a3 = atlas.allocate(size2(20, 30)).unwrap();
940
941 assert!(a1.id != a2.id);
942 assert!(a1.id != a3.id);
943 assert!(!atlas.is_empty());
944
945 for id in &atlas {
946 assert!(id == a1 || id == a2 || id == a3);
947 }
948
949 assert_eq!(a1.rectangle.min.x % alignment.width, 0);
950 assert_eq!(a1.rectangle.min.y % alignment.height, 0);
951 assert_eq!(a2.rectangle.min.x % alignment.width, 0);
952 assert_eq!(a2.rectangle.min.y % alignment.height, 0);
953 assert_eq!(a3.rectangle.min.x % alignment.width, 0);
954 assert_eq!(a3.rectangle.min.y % alignment.height, 0);
955
956 assert!(a1.rectangle.size().width >= 20);
957 assert!(a1.rectangle.size().height >= 30);
958 assert!(a2.rectangle.size().width >= 30);
959 assert!(a2.rectangle.size().height >= 40);
960 assert!(a3.rectangle.size().width >= 20);
961 assert!(a3.rectangle.size().height >= 30);
962
963
964 atlas.deallocate(a1.id);
967 atlas.deallocate(a2.id);
968 atlas.deallocate(a3.id);
969
970 assert!(atlas.is_empty());
971 assert_eq!(atlas.allocated_space(), 0);
972}
973
974#[test]
975fn vertical() {
976 let mut atlas = AtlasAllocator::with_options(size2(128, 256), &AllocatorOptions {
977 num_columns: 2,
978 vertical_shelves: true,
979 ..DEFAULT_OPTIONS
980 });
981
982 assert_eq!(atlas.size(), size2(128, 256));
983
984 let a = atlas.allocate(size2(32, 16)).unwrap();
985 let b = atlas.allocate(size2(16, 32)).unwrap();
986
987 assert!(a.rectangle.size().width >= 32);
988 assert!(a.rectangle.size().height >= 16);
989
990 assert!(b.rectangle.size().width >= 16);
991 assert!(b.rectangle.size().height >= 32);
992
993 let c = atlas.allocate(size2(128, 128)).unwrap();
994
995 for _ in &atlas {}
996
997 atlas.deallocate(a.id);
998 atlas.deallocate(b.id);
999 atlas.deallocate(c.id);
1000
1001 for _ in &atlas {}
1002
1003 assert!(atlas.is_empty());
1004 assert_eq!(atlas.allocated_space(), 0);
1005}
1006
1007
1008#[test]
1009fn clear() {
1010 let mut atlas = AtlasAllocator::new(size2(2048, 2048));
1011
1012 for _ in 0..500 {
1014 atlas.clear();
1015 assert_eq!(atlas.allocated_space(), 0);
1016
1017 atlas.allocate(size2(8, 2)).unwrap();
1018 atlas.allocate(size2(2, 8)).unwrap();
1019 atlas.allocate(size2(16, 512)).unwrap();
1020 atlas.allocate(size2(34, 34)).unwrap();
1021 atlas.allocate(size2(34, 34)).unwrap();
1022 atlas.allocate(size2(34, 34)).unwrap();
1023 atlas.allocate(size2(34, 34)).unwrap();
1024 atlas.allocate(size2(2, 8)).unwrap();
1025 atlas.allocate(size2(2, 8)).unwrap();
1026 atlas.allocate(size2(8, 2)).unwrap();
1027 atlas.allocate(size2(2, 8)).unwrap();
1028 atlas.allocate(size2(8, 2)).unwrap();
1029 atlas.allocate(size2(8, 8)).unwrap();
1030 atlas.allocate(size2(8, 8)).unwrap();
1031 atlas.allocate(size2(8, 8)).unwrap();
1032 atlas.allocate(size2(8, 8)).unwrap();
1033 atlas.allocate(size2(82, 80)).unwrap();
1034 atlas.allocate(size2(56, 56)).unwrap();
1035 atlas.allocate(size2(64, 66)).unwrap();
1036 atlas.allocate(size2(32, 32)).unwrap();
1037 atlas.allocate(size2(32, 32)).unwrap();
1038 atlas.allocate(size2(32, 32)).unwrap();
1039 atlas.allocate(size2(32, 32)).unwrap();
1040 atlas.allocate(size2(32, 32)).unwrap();
1041 atlas.allocate(size2(32, 32)).unwrap();
1042 atlas.allocate(size2(32, 32)).unwrap();
1043 atlas.allocate(size2(32, 32)).unwrap();
1044 atlas.allocate(size2(32, 32)).unwrap();
1045 atlas.allocate(size2(40, 40)).unwrap();
1046 atlas.allocate(size2(32, 32)).unwrap();
1047 atlas.allocate(size2(256, 52)).unwrap();
1048 atlas.allocate(size2(32, 32)).unwrap();
1049 atlas.allocate(size2(256, 52)).unwrap();
1050 atlas.allocate(size2(256, 52)).unwrap();
1051 atlas.allocate(size2(256, 52)).unwrap();
1052 atlas.allocate(size2(256, 52)).unwrap();
1053 atlas.allocate(size2(256, 52)).unwrap();
1054 atlas.allocate(size2(256, 52)).unwrap();
1055 atlas.allocate(size2(155, 52)).unwrap();
1056 atlas.allocate(size2(256, 52)).unwrap();
1057 atlas.allocate(size2(32, 32)).unwrap();
1058 atlas.allocate(size2(32, 32)).unwrap();
1059 atlas.allocate(size2(32, 32)).unwrap();
1060 atlas.allocate(size2(24, 24)).unwrap();
1061 atlas.allocate(size2(64, 64)).unwrap();
1062 atlas.allocate(size2(32, 32)).unwrap();
1063 atlas.allocate(size2(84, 84)).unwrap();
1064 atlas.allocate(size2(32, 32)).unwrap();
1065 atlas.allocate(size2(8, 2)).unwrap();
1066 atlas.allocate(size2(34, 34)).unwrap();
1067 atlas.allocate(size2(34, 34)).unwrap();
1068 atlas.allocate(size2(192, 192)).unwrap();
1069 atlas.allocate(size2(192, 192)).unwrap();
1070 atlas.allocate(size2(52, 52)).unwrap();
1071 atlas.allocate(size2(144, 144)).unwrap();
1072 atlas.allocate(size2(192, 192)).unwrap();
1073 atlas.allocate(size2(32, 32)).unwrap();
1074 atlas.allocate(size2(144, 144)).unwrap();
1075 atlas.allocate(size2(24, 24)).unwrap();
1076 atlas.allocate(size2(192, 192)).unwrap();
1077 atlas.allocate(size2(192, 192)).unwrap();
1078 atlas.allocate(size2(432, 243)).unwrap();
1079 atlas.allocate(size2(32, 32)).unwrap();
1080 atlas.allocate(size2(8, 2)).unwrap();
1081 atlas.allocate(size2(2, 8)).unwrap();
1082 atlas.allocate(size2(9, 9)).unwrap();
1083 atlas.allocate(size2(14, 14)).unwrap();
1084 atlas.allocate(size2(14, 14)).unwrap();
1085 atlas.allocate(size2(14, 14)).unwrap();
1086 atlas.allocate(size2(14, 14)).unwrap();
1087 atlas.allocate(size2(8, 8)).unwrap();
1088 atlas.allocate(size2(27, 27)).unwrap();
1089 atlas.allocate(size2(27, 27)).unwrap();
1090 atlas.allocate(size2(27, 27)).unwrap();
1091 atlas.allocate(size2(27, 27)).unwrap();
1092 atlas.allocate(size2(11, 12)).unwrap();
1093 atlas.allocate(size2(29, 28)).unwrap();
1094 atlas.allocate(size2(32, 32)).unwrap();
1095
1096 for _ in &atlas {}
1097 }
1098}
1099
1100#[test]
1101fn fuzz_01() {
1102 let s = 65472;
1103
1104 let mut atlas = AtlasAllocator::new(size2(s, 64));
1105 let alloc = atlas.allocate(size2(s, 64)).unwrap();
1106 assert_eq!(alloc.rectangle.size().width, s);
1107 assert_eq!(alloc.rectangle.size().height, 64);
1108
1109 let mut atlas = AtlasAllocator::new(size2(64, s));
1110 let alloc = atlas.allocate(size2(64, s)).unwrap();
1111 assert_eq!(alloc.rectangle.size().width, 64);
1112 assert_eq!(alloc.rectangle.size().height, s);
1113
1114 let mut atlas = AtlasAllocator::new(size2(s, 64));
1115 let alloc = atlas.allocate(size2(s - 1, 64)).unwrap();
1116 assert_eq!(alloc.rectangle.size().width, s);
1117 assert_eq!(alloc.rectangle.size().height, 64);
1118
1119 let mut atlas = AtlasAllocator::new(size2(64, s));
1120 let alloc = atlas.allocate(size2(64, s - 1)).unwrap();
1121 assert_eq!(alloc.rectangle.size().width, 64);
1122 assert_eq!(alloc.rectangle.size().height, s);
1123
1124 let s = std::u16::MAX as i32;
1127
1128 let mut atlas = AtlasAllocator::new(size2(s, 64));
1129 if let Some(alloc) = atlas.allocate(size2(s, 64)) {
1130 assert_eq!(alloc.rectangle.size().width, s);
1131 assert_eq!(alloc.rectangle.size().height, 64);
1132 }
1133
1134 let mut atlas = AtlasAllocator::new(size2(64, s));
1135 if let Some(alloc) = atlas.allocate(size2(64, s)) {
1136 assert_eq!(alloc.rectangle.size().width, 64);
1137 assert_eq!(alloc.rectangle.size().height, s);
1138 }
1139}
1140
1141
1142#[test]
1143fn fuzz_02() {
1144 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1145
1146 assert!(atlas.allocate(size2(255, 65599)).is_none());
1147}
1148
1149#[test]
1150fn fuzz_03() {
1151 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1152
1153 let sizes = &[
1154 size2(999, 128),
1155 size2(168492810, 10),
1156 size2(45, 96),
1157 size2(-16711926, 0),
1158 ];
1159
1160 let mut allocations = Vec::new();
1161 let mut allocated_space = 0;
1162
1163 for size in sizes {
1164 if let Some(alloc) = atlas.allocate(*size) {
1165 allocations.push(alloc);
1166 allocated_space += alloc.rectangle.area();
1167 assert_eq!(allocated_space, atlas.allocated_space());
1168 }
1169 }
1170
1171 for alloc in &allocations {
1172 atlas.deallocate(alloc.id);
1173
1174 allocated_space -= alloc.rectangle.area();
1175 assert_eq!(allocated_space, atlas.allocated_space());
1176 }
1177
1178 assert_eq!(atlas.allocated_space(), 0);
1179}
1180
1181#[test]
1182fn fuzz_04() {
1183 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1184
1185 assert!(atlas.allocate(size2(2560, 2147483647)).is_none());
1186}
1187
1188#[test]
1189fn issue_17_1() {
1190 let mut atlas = AtlasAllocator::new(size2(1024, 1024));
1191
1192 let a = atlas.allocate(size2(100, 300)).unwrap();
1193 let b = atlas.allocate(size2(500, 200)).unwrap();
1194
1195 assert_eq!(a.rectangle, atlas.get(a.id));
1196 assert_eq!(b.rectangle, atlas.get(b.id));
1197
1198 atlas.deallocate(a.id);
1199
1200 let c = atlas.allocate(size2(300, 200)).unwrap();
1201
1202 assert_eq!(b.rectangle, atlas.get(b.id));
1203 assert_eq!(c.rectangle, atlas.get(c.id));
1204
1205 atlas.deallocate(c.id);
1206 atlas.deallocate(b.id);
1207}
1208
1209#[test]
1210fn issue_17_2() {
1211 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1212
1213 assert!(atlas.allocate(size2(100, 1001)).is_none());
1214 assert!(atlas.allocate(size2(1001, 1000)).is_none());
1215 let a = atlas.allocate(size2(1000, 1000)).unwrap();
1216
1217 assert_eq!(a.rectangle, atlas.get(a.id));
1218
1219 atlas.deallocate(a.id);
1220}
1221
1222#[test]
1223fn issue_35() {
1224 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1225 let a = atlas.allocate(size2(100, 1000)).unwrap();
1228 let b = atlas.allocate(size2(900, 200)).unwrap();
1232
1233 atlas.deallocate(a.id);
1234 atlas.deallocate(b.id);
1235}
1236
1237#[test]
1238fn bad_fit() {
1239 let a = size2(100, 300);
1243 let b = size2(100, 100);
1244 let c = size2(100, 30);
1245 for (s1, s2, s3) in [(a, b, c), (c, b, a), (a, c, b), (c, a, b), (b, a, c), (b, c, a)] {
1247 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1248
1249 let a1 = atlas.allocate(s1).unwrap();
1250 let a2 = atlas.allocate(s2).unwrap();
1251 let a3 = atlas.allocate(s3).unwrap();
1252
1253 assert!(a1.rectangle.min.y != a2.rectangle.min.y);
1254 assert!(a2.rectangle.min.y != a3.rectangle.min.y);
1255 assert!(a1.rectangle.min.y != a3.rectangle.min.y);
1256 assert!(a1.rectangle.max.y != a2.rectangle.max.y);
1257 assert!(a2.rectangle.max.y != a3.rectangle.max.y);
1258 assert!(a1.rectangle.max.y != a3.rectangle.max.y);
1259
1260 atlas.deallocate(a1.id);
1261 atlas.deallocate(a2.id);
1262 atlas.deallocate(a3.id);
1263 }
1264}