Skip to main content

guillotiere/
allocator.rs

1#[cfg(test)]
2extern crate std;
3
4use alloc::vec;
5use alloc::vec::Vec;
6use crate::{Rectangle, Size};
7use euclid::{vec2, point2, size2};
8
9use core::num::Wrapping;
10
11const LARGE_BUCKET: usize = 2;
12const MEDIUM_BUCKET: usize = 1;
13const SMALL_BUCKET: usize = 0;
14const NUM_BUCKETS: usize = 3;
15
16fn free_list_for_size(small_threshold: i32, large_threshold: i32, size: &Size) -> usize {
17    if size.width >= large_threshold || size.height >= large_threshold {
18        LARGE_BUCKET
19    } else if size.width >= small_threshold || size.height >= small_threshold {
20        MEDIUM_BUCKET
21    } else {
22        SMALL_BUCKET
23    }
24}
25
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
28struct AllocIndex(u32);
29impl AllocIndex {
30    const NONE: AllocIndex = AllocIndex(u32::MAX);
31
32    fn index(self) -> usize {
33        self.0 as usize
34    }
35
36    fn is_none(self) -> bool {
37        self == AllocIndex::NONE
38    }
39
40    fn is_some(self) -> bool {
41        self != AllocIndex::NONE
42    }
43}
44
45/// ID referring to an allocated rectangle.
46#[repr(C)]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
49pub struct AllocId(pub(crate) u32);
50
51impl AllocId {
52    pub fn serialize(&self) -> u32 {
53        self.0
54    }
55
56    pub fn deserialize(bytes: u32) -> Self {
57        AllocId(bytes)
58    }
59}
60
61const GEN_MASK: u32 = 0xFF000000;
62const IDX_MASK: u32 = 0x00FFFFFF;
63
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
66enum Orientation {
67    Vertical,
68    Horizontal,
69}
70
71impl Orientation {
72    fn flipped(self) -> Self {
73        match self {
74            Orientation::Vertical => Orientation::Horizontal,
75            Orientation::Horizontal => Orientation::Vertical,
76        }
77    }
78}
79
80#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
81#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
82pub enum NodeKind {
83    Container,
84    Alloc,
85    Free,
86    Unused,
87}
88
89#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
90#[derive(Clone, Debug)]
91struct Node {
92    parent: AllocIndex,
93    next_sibling: AllocIndex,
94    prev_sibling: AllocIndex,
95    kind: NodeKind,
96    orientation: Orientation,
97    rect: Rectangle,
98}
99
100/// Options to tweak the behavior of the atlas allocator.
101#[repr(C)]
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
103#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
104pub struct AllocatorOptions {
105    /// Round the rectangle sizes up to a multiple of this value.
106    ///
107    /// Width and height alignments must be superior to zero.
108    ///
109    /// Default value: (1, 1),
110    pub alignment: Size,
111
112    /// Value below which a size is considered small.
113    ///
114    /// This is value is used to speed up the storage and lookup of free rectangles.
115    /// This value must be inferior or equal to `large_size_threshold`
116    ///
117    /// Default value: 32,
118    pub small_size_threshold: i32,
119
120    /// Value above which a size is considered large.
121    ///
122    /// This is value is used to speed up the storage and lookup of free rectangles.
123    /// This value must be inferior or equal to `large_size_threshold`
124    ///
125    /// Default value: 256,
126    pub large_size_threshold: i32,
127}
128
129pub const DEFAULT_OPTIONS: AllocatorOptions = AllocatorOptions {
130    alignment: size2(1,  1),
131    large_size_threshold: 256,
132    small_size_threshold: 32,
133};
134
135impl Default for AllocatorOptions {
136    fn default() -> Self {
137        DEFAULT_OPTIONS
138    }
139}
140
141/// A dynamic texture atlas allocator using the guillotine algorithm.
142///
143/// The guillotine algorithm is assisted by a data structure that keeps track of
144/// neighboring rectangles to provide fast deallocation and coalescing.
145///
146/// ## Goals
147///
148/// Coalescing free rectangles, in the context of dynamic atlas allocation can be
149/// prohibitively expensive under real-time constraints if the algorithm needs to
150/// visit a large amount of free rectangles to find merge candidates.
151///
152/// This implementation proposes a compromise with fast (constant time) search
153/// for merge candidates at the expense of some (constant time) bookkeeping overhead
154/// when allocating and removing rectangles and imperfect defragmentation (see the
155/// "Limitations" section below.
156///
157/// The subdivision scheme uses the worst fit variant of the guillotine algorithm
158/// for its simplicity and CPU efficiency.
159///
160/// ## The data structure
161///
162/// We maintain a tree with allocated and free rectangles as leaf nodes and
163/// containers as non-leaf nodes.
164///
165/// The direct children of a Containers's form an ordered horizontal or vertical
166/// sequence of rectangles that cover exactly their parent container's area.
167///
168/// For example, a subdivision such as this one:
169///
170/// ```ascii
171/// +-----------+----------+---+---+--+---------+---+
172/// |           |          | C | D |E | F       | G |
173/// |           |          +---+---+--+---------+---+
174/// |     A     |    B     |                        |
175/// |           |          |           H            |
176/// |           |          |                        |
177/// +------+----+----------+-+----------------------+
178/// |      |        J        |                      |
179/// |  I   +-----------------+          L           |
180/// |      |        K        |                      |
181/// +------+-----------------+----------------------+
182/// ```
183///
184/// Would have a tree of the form:
185///
186/// ```ascii
187///
188///  Tree                | Layout
189/// ---------------------+------------
190///                      |
191///           #          |
192///           |          |
193///      +----+----+. . .|. vertical
194///      |         |     |
195///      #         #     |
196///      |         |     |
197///    +-+-+ . . +-+-+. .|. horizontal
198///    | | |     | | |   |
199///    A B #     I # L   |
200///        |       |     |
201///      +-+-+ . +-+-+. .|. vertical
202///      |   |   |   |   |
203///      #   H   J   K   |
204///      |               |
205///  +-+-+-+-+. . . . . .|. horizontal
206///  | | | | |           |
207///  C D E F G           |
208/// ```
209///
210/// Where container nodes are represented with "#".
211///
212/// Note that if a horizontal container is the direct child of another
213/// horizontal container, we can merge the two into a single horizontal
214/// sequence.
215/// We use this property to always keep the tree in its simplest form.
216/// In practice this means that the orientation of a container is always
217/// the opposite of the orientation of its parent, if any.
218///
219/// The goal of this data structure is to quickly find neighboring free
220/// rectangles that can be coalesced into fewer rectangles.
221/// This structure guarantees that two consecutive children of the same
222/// container, if both rectangles are free, can be coalesced into a single
223/// one.
224///
225/// An important thing to note about this tree structure is that we only
226/// use it to visit neighbor and parent nodes. As a result we don't care
227/// about whether the tree is balanced, although flat sequences of children
228/// tend to offer more opportunity for coalescing than deeply nested structures
229/// Either way, the cost of finding potential merges is the same because
230/// each node stores the indices of their siblings, and we never have to
231/// traverse any global list of free rectangle nodes.
232///
233/// ### Merging siblings
234///
235/// As soon as two consecutive sibling nodes are marked as "free", they are coalesced
236/// into a single node.
237///
238/// In the example below, we just deallocated the rectangle `B`, which is a sibling of
239/// `A` which is free and `C` which is still allocated. `A` and `B` are merged and this
240/// change is reflected on the tree as shown below:
241///
242/// ```ascii
243/// +---+---+---+         #               +-------+---+         #
244/// |   |   |///|         |               |       |///|         |
245/// | A | B |/C/|     +---+---+           | AB    |/C/|     +---+---+
246/// |   |   |///|     |       |           |       |///|     |       |
247/// +---+---+---+     #       D           +-------+---+     #       D
248/// | D         |     |            ->     | D         |     |
249/// |           |   +-+-+                 |           |   +-+-+
250/// |           |   | | |                 |           |   |   |
251/// +-----------+   A B C                 +-----------+   AB  C
252/// ```
253///
254/// ### Merging unique children with their parents
255///
256/// In the previous example `C` was an allocated slot. Let's now deallocate it:
257///
258/// ```ascii
259/// +-------+---+         #               +-----------+         #                 #
260/// |       |   |         |               |           |         |                 |
261/// | AB    | C |     +---+---+           | ABC       |     +---+---+         +---+---+
262/// |       |   |     |       |           |           |     |       |         |       |
263/// +-------+---+     #       D           +-----------+     #       D        ABC      D
264/// | D         |     |            ->     | D         |     |           ->
265/// |           |   +-+-+                 |           |     +
266/// |           |   |   |                 |           |     |
267/// +-----------+   AB  C                 +-----------+    ABC
268/// ```
269///
270/// Deallocating `C` allowed it to merge with the free rectangle `AB`, making the
271/// resulting node `ABC` the only child of its parent container. As a result the
272/// node `ABC` was lifted up the tree to replace its parent.
273///
274/// In this example, assuming `D` to also be a free rectangle, `ABC` and `D` would
275/// be immediately merged and the resulting node `ABCD`, also being only child of
276/// its parent container, would replace its parent, turning the tree into a single
277/// node `ABCD`.
278///
279/// ### Limitations
280///
281/// This strategy can miss some opportunities for coalescing free rectangles
282/// when the two sibling containers are split exactly the same way.
283///
284/// For example:
285///
286/// ```ascii
287/// +---------+------+
288/// |    A    |  B   |
289/// |         |      |
290/// +---------+------+
291/// |    C    |  D   |
292/// |         |      |
293/// +---------+------+
294/// ```
295///
296/// Could be the result of either a vertical followed with two horizontal splits,
297/// or an horizontal then two vertical splits.
298///
299/// ```ascii
300///  Tree            | Layout             Tree            | Layout
301/// -----------------+------------       -----------------+------------
302///         #        |                           #        |
303///         |        |                           |        |
304///     +---+---+ . .|. Vertical             +---+---+ . .|. Horizontal
305///     |       |    |                       |       |    |
306///     #       #    |               or      #       #    |
307///     |       |    |                       |       |    |
308///   +-+-+ . +-+-+ .|. Horizontal         +-+-+ . +-+-+ .|. Vertical
309///   |   |   |   |  |                     |   |   |   |  |
310///   A   B   C   D  |                     A   C   B   D  |
311/// ```
312///
313/// In the former case A can't be merged with C nor B with D because they are not siblings.
314///
315/// For a lot of workloads it is rather rare for two consecutive sibling containers to be
316/// subdivided exactly the same way. In this situation losing the ability to merge rectangles
317/// that aren't under the same container is good compromise between the CPU cost of coalescing
318/// and the fragmentation of the atlas.
319///
320/// This algorithm is, however, not the best solution for very "structured" grid-like
321/// subdivision patterns where the ability to merge across containers would have provided
322/// frequent defragmentation opportunities.
323#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
324#[derive(Clone)]
325pub struct AtlasAllocator {
326    nodes: Vec<Node>,
327    /// Free lists are split into a small a medium and a large bucket for faster lookups.
328    free_lists: [Vec<AllocIndex>; NUM_BUCKETS],
329
330    /// Index of the first element of an intrusive linked list of unused nodes.
331    /// The `next_sibling` member of unused node serves as the linked list link.
332    unused_nodes: AllocIndex,
333
334    /// We keep a per-node generation counter to reduce the likelihood of ID reuse bugs
335    /// going unnoticed.
336    generations: Vec<Wrapping<u8>>,
337
338    /// See `AllocatorOptions`.
339    alignment: Size,
340
341    /// See `AllocatorOptions`.
342    small_size_threshold: i32,
343
344    /// See `AllocatorOptions`.
345    large_size_threshold: i32,
346
347    /// Total size of the atlas.
348    size: Size,
349
350    /// Index of one of the top-level nodes in the tree.
351    root_node: AllocIndex,
352}
353
354// Some notes about the atlas's tree data structure:
355//
356//      (AllocIndex::NONE)                (AllocIndex::NONE)
357//              ^                                 ^
358//              | parent                          | parent
359//           +---------+ next sibling         +---------+ next sibling
360// ... ------|Container|---------------------->|Free     |---> (AllocIndex::NONE)
361//     ----->|         |<----------------------|         |
362//           +---------+     previous sibling +---------+
363//              ^ ^
364//              |  \____________________________
365//              |                               \
366//              | parent                         \ parent
367//           +---------+ next sibling         +---------+ next sibling
368// ... ------|Alloc    |---------------------->|Container|---> (AllocIndex::NONE)
369//     ----->|         |<----------------------|         |
370//           +---------+     previous sibling +---------+
371//                                               ^ ^ ^
372//                                              /  |  \
373//                                                ...
374//
375// - Nodes are stored in a contiguous vector.
376// - Links between the nodes are indices in the vector (AllocIndex), with a magic value
377//   AllocIndex::NONE that means no link.
378// - Nodes have a link to their parent, but parents do not have a link to any of its children because
379//   we never need to traverse the structure from parent to child.
380// - All nodes with the same parent are "siblings". An intrusive linked list allows traversing siblings
381//   in order. Consecutive siblings share an edge and can be merged if they are both "free".
382// - There isn't necessarily a single root node. The top-most level of the tree can have several siblings
383//   and their parent index is equal to AllocIndex::NONE. AtlasAllocator::root_node only needs to refer
384//   to one of these top-level nodes.
385// - After a rectangle has been deallocated, the slot for its node in the vector is not part of the
386//   tree anymore in the sense that no node from the tree points to it with its sibling list or parent
387//   index. This unused node is available for reuse in a future allocation, and is placed in another
388//   linked list (also using AllocIndex), a singly linked list this time, which reuses the next_sibling
389//   member of the node. So depending on whether the node kind is Unused or not, the next_sibling
390//   member is used different things.
391// - We reuse nodes aggressively to avoid growing the vector whenever possible. This is important because
392//   the memory footprint of this data structure depends on the capacity of its vectors which don't
393//   get deallocated during the lifetime of the atlas.
394// - Because nodes are aggressively reused, the same node indices will come up often. To avoid id reuse
395//   bugs, a parallel vector of generation counters is maintained.
396// - The difference between AllocIndex and AllocId is that the latter embeds a generation ID to help
397//   finding id reuse bugs. AllocIndex however only contains the node offset. Internal links in the
398//   data structure use AllocIndex, and external users of the data structure only get to see AllocId.
399
400impl AtlasAllocator {
401    /// Create an atlas allocator.
402    pub fn new(size: Size) -> Self {
403        AtlasAllocator::with_options(size, &DEFAULT_OPTIONS)
404    }
405
406    /// Create an atlas allocator with the provided options.
407    pub fn with_options(size: Size, options: &AllocatorOptions) -> Self {
408        assert!(options.alignment.width > 0);
409        assert!(options.alignment.height > 0);
410        assert!(size.width > 0);
411        assert!(size.height > 0);
412        assert!(options.large_size_threshold >= options.small_size_threshold);
413
414        let mut free_lists = [Vec::new(), Vec::new(), Vec::new()];
415        let bucket = free_list_for_size(
416            options.small_size_threshold,
417            options.large_size_threshold,
418            &size,
419        );
420        free_lists[bucket].push(AllocIndex(0));
421
422        AtlasAllocator {
423            nodes: vec![Node {
424                parent: AllocIndex::NONE,
425                next_sibling: AllocIndex::NONE,
426                prev_sibling: AllocIndex::NONE,
427                rect: size.into(),
428                kind: NodeKind::Free,
429                orientation: Orientation::Vertical,
430            }],
431            free_lists,
432            generations: vec![Wrapping(0)],
433            unused_nodes: AllocIndex::NONE,
434            alignment: options.alignment,
435            small_size_threshold: options.small_size_threshold,
436            large_size_threshold: options.large_size_threshold,
437            size,
438            root_node: AllocIndex(0),
439        }
440    }
441
442    /// The total size of the atlas.
443    pub fn size(&self) -> Size {
444        self.size
445    }
446
447    /// Allocate a rectangle in the atlas.
448    pub fn allocate(&mut self, mut requested_size: Size) -> Option<Allocation> {
449        if requested_size.is_empty() {
450            return None;
451        }
452
453        adjust_size(self.alignment.width, &mut requested_size.width);
454        adjust_size(self.alignment.height, &mut requested_size.height);
455
456        // Find a suitable free rect.
457        let chosen_id = self.find_suitable_rect(&requested_size);
458
459        if chosen_id.is_none() {
460            // No suitable free rect!
461            return None;
462        }
463
464        let chosen_node = self.nodes[chosen_id.index()].clone();
465        let chosen_rect = chosen_node.rect;
466        let allocated_rect = Rectangle {
467            min: chosen_rect.min,
468            max: chosen_rect.min + requested_size.to_vector(),
469        };
470        let current_orientation = chosen_node.orientation;
471        assert_eq!(chosen_node.kind, NodeKind::Free);
472
473        let (split_rect, leftover_rect, orientation) =
474            guillotine_rect(&chosen_node.rect, requested_size, current_orientation);
475
476        // Update the tree.
477
478        let allocated_id;
479        let split_id;
480        let leftover_id;
481
482        if orientation == current_orientation {
483            if !split_rect.is_empty() {
484                let next_sibling = chosen_node.next_sibling;
485
486                split_id = self.new_node();
487                self.nodes[split_id.index()] = Node {
488                    parent: chosen_node.parent,
489                    next_sibling,
490                    prev_sibling: chosen_id,
491                    rect: split_rect,
492                    kind: NodeKind::Free,
493                    orientation: current_orientation,
494                };
495
496                self.nodes[chosen_id.index()].next_sibling = split_id;
497                if next_sibling.is_some() {
498                    self.nodes[next_sibling.index()].prev_sibling = split_id;
499                }
500            } else {
501                split_id = AllocIndex::NONE;
502            }
503
504            if !leftover_rect.is_empty() {
505                self.nodes[chosen_id.index()].kind = NodeKind::Container;
506
507                allocated_id = self.new_node();
508                leftover_id = self.new_node();
509
510                self.nodes[allocated_id.index()] = Node {
511                    parent: chosen_id,
512                    next_sibling: leftover_id,
513                    prev_sibling: AllocIndex::NONE,
514                    rect: allocated_rect,
515                    kind: NodeKind::Alloc,
516                    orientation: current_orientation.flipped(),
517                };
518
519                self.nodes[leftover_id.index()] = Node {
520                    parent: chosen_id,
521                    next_sibling: AllocIndex::NONE,
522                    prev_sibling: allocated_id,
523                    rect: leftover_rect,
524                    kind: NodeKind::Free,
525                    orientation: current_orientation.flipped(),
526                };
527            } else {
528                // No need to split for the leftover area, we can allocate directly in the chosen node.
529                allocated_id = chosen_id;
530                let node = &mut self.nodes[chosen_id.index()];
531                node.kind = NodeKind::Alloc;
532                node.rect = allocated_rect;
533
534                leftover_id = AllocIndex::NONE
535            }
536        } else {
537            self.nodes[chosen_id.index()].kind = NodeKind::Container;
538
539            if !split_rect.is_empty() {
540                split_id = self.new_node();
541                self.nodes[split_id.index()] = Node {
542                    parent: chosen_id,
543                    next_sibling: AllocIndex::NONE,
544                    prev_sibling: AllocIndex::NONE,
545                    rect: split_rect,
546                    kind: NodeKind::Free,
547                    orientation: current_orientation.flipped(),
548                };
549            } else {
550                split_id = AllocIndex::NONE;
551            }
552
553            if !leftover_rect.is_empty() {
554                let container_id = self.new_node();
555                self.nodes[container_id.index()] = Node {
556                    parent: chosen_id,
557                    next_sibling: split_id,
558                    prev_sibling: AllocIndex::NONE,
559                    rect: Rectangle::zero(),
560                    kind: NodeKind::Container,
561                    orientation: current_orientation.flipped(),
562                };
563
564                self.nodes[split_id.index()].prev_sibling = container_id;
565
566                allocated_id = self.new_node();
567                leftover_id = self.new_node();
568
569                self.nodes[allocated_id.index()] = Node {
570                    parent: container_id,
571                    next_sibling: leftover_id,
572                    prev_sibling: AllocIndex::NONE,
573                    rect: allocated_rect,
574                    kind: NodeKind::Alloc,
575                    orientation: current_orientation,
576                };
577
578                self.nodes[leftover_id.index()] = Node {
579                    parent: container_id,
580                    next_sibling: AllocIndex::NONE,
581                    prev_sibling: allocated_id,
582                    rect: leftover_rect,
583                    kind: NodeKind::Free,
584                    orientation: current_orientation,
585                };
586            } else {
587                allocated_id = self.new_node();
588                self.nodes[allocated_id.index()] = Node {
589                    parent: chosen_id,
590                    next_sibling: split_id,
591                    prev_sibling: AllocIndex::NONE,
592                    rect: allocated_rect,
593                    kind: NodeKind::Alloc,
594                    orientation: current_orientation.flipped(),
595                };
596
597                self.nodes[split_id.index()].prev_sibling = allocated_id;
598
599                leftover_id = AllocIndex::NONE;
600            }
601        }
602
603        assert_eq!(self.nodes[allocated_id.index()].kind, NodeKind::Alloc);
604
605        if split_id.is_some() {
606            self.add_free_rect(split_id, &split_rect.size());
607        }
608
609        if leftover_id.is_some() {
610            self.add_free_rect(leftover_id, &leftover_rect.size());
611        }
612
613        #[cfg(feature = "checks")]
614        self.check_tree();
615
616        Some(Allocation {
617            id: self.alloc_id(allocated_id),
618            rectangle: allocated_rect,
619        })
620    }
621
622    /// Deallocate a rectangle in the atlas.
623    pub fn deallocate(&mut self, node_id: AllocId) {
624        let mut node_id = self.get_index(node_id);
625
626        assert!(node_id.index() < self.nodes.len());
627        assert_eq!(self.nodes[node_id.index()].kind, NodeKind::Alloc);
628
629        self.nodes[node_id.index()].kind = NodeKind::Free;
630
631        loop {
632            let orientation = self.nodes[node_id.index()].orientation;
633
634            let next = self.nodes[node_id.index()].next_sibling;
635            let prev = self.nodes[node_id.index()].prev_sibling;
636
637            // Try to merge with the next node.
638            if next.is_some() && self.nodes[next.index()].kind == NodeKind::Free {
639                self.merge_siblings(node_id, next, orientation);
640            }
641
642            // Try to merge with the previous node.
643            if prev.is_some() && self.nodes[prev.index()].kind == NodeKind::Free {
644                self.merge_siblings(prev, node_id, orientation);
645                node_id = prev;
646            }
647
648            // If this node is now a unique child. We collapse it into its parent and try to merge
649            // again at the parent level.
650            let parent = self.nodes[node_id.index()].parent;
651            if self.nodes[node_id.index()].prev_sibling.is_none()
652                && self.nodes[node_id.index()].next_sibling.is_none()
653                && parent.is_some()
654            {
655                debug_assert_eq!(self.nodes[parent.index()].kind, NodeKind::Container);
656
657                // Replace the parent container with a free node.
658                self.nodes[parent.index()].rect = self.nodes[node_id.index()].rect;
659                self.nodes[parent.index()].kind = NodeKind::Free;
660                self.mark_node_unused(node_id);
661
662                // Start again at the parent level.
663                node_id = parent;
664            } else {
665                let size = self.nodes[node_id.index()].rect.size();
666                self.add_free_rect(node_id, &size);
667                break;
668            }
669        }
670
671        #[cfg(feature = "checks")]
672        self.check_tree();
673    }
674
675    pub fn is_empty(&self) -> bool {
676        let root = &self.nodes[self.root_node.index()];
677
678        root.kind == NodeKind::Free && root.next_sibling.is_none()
679    }
680
681    /// Drop all rectangles, clearing the atlas to its initial state.
682    pub fn clear(&mut self) {
683        self.nodes.clear();
684        self.nodes.push(Node {
685            parent: AllocIndex::NONE,
686            next_sibling: AllocIndex::NONE,
687            prev_sibling: AllocIndex::NONE,
688            rect: self.size.into(),
689            kind: NodeKind::Free,
690            orientation: Orientation::Vertical,
691        });
692
693        self.root_node = AllocIndex(0);
694
695        self.generations.clear();
696        self.generations.push(Wrapping(0));
697
698        self.unused_nodes = AllocIndex::NONE;
699
700        let bucket = free_list_for_size(
701            self.small_size_threshold,
702            self.large_size_threshold,
703            &self.size,
704        );
705        for i in 0..NUM_BUCKETS {
706            self.free_lists[i].clear();
707        }
708        self.free_lists[bucket].push(AllocIndex(0));
709    }
710
711    /// Clear the allocator and reset its size and options.
712    pub fn reset(&mut self, size: Size, options: &AllocatorOptions) {
713        self.alignment = options.alignment;
714        self.small_size_threshold = options.small_size_threshold;
715        self.large_size_threshold = options.large_size_threshold;
716        self.size = size;
717
718        self.clear();
719    }
720
721    /// Recompute the allocations in the atlas and returns a list of the changes.
722    ///
723    /// Previous ids and rectangles are not valid anymore after this operation as each id/rectangle
724    /// pair is assigned to new values which are communicated in the returned change list.
725    /// Rearranging the atlas can help reduce fragmentation.
726    pub fn rearrange(&mut self) -> ChangeList {
727        let size = self.size;
728        self.resize_and_rearrange(size)
729    }
730
731    /// Identical to `AtlasAllocator::rearrange`, also allowing to change the size of the atlas.
732    pub fn resize_and_rearrange(&mut self, new_size: Size) -> ChangeList {
733        let mut allocs = Vec::with_capacity(self.nodes.len());
734        for (i, node) in self.nodes.iter().enumerate() {
735            if node.kind != NodeKind::Alloc {
736                continue;
737            }
738            let id = self.alloc_id(AllocIndex(i as u32));
739            allocs.push(Allocation {
740                id,
741                rectangle: node.rect,
742            });
743        }
744
745        allocs.sort_by_key(|alloc| safe_area(&alloc.rectangle));
746        allocs.reverse();
747
748        self.size = new_size;
749        self.clear();
750
751        let mut changes = Vec::new();
752        let mut failures = Vec::new();
753
754        for old in allocs {
755            let size = old.rectangle.size();
756            if let Some(new) = self.allocate(size) {
757                changes.push(Change { old, new });
758            } else {
759                failures.push(old);
760            }
761        }
762
763        ChangeList { changes, failures }
764    }
765
766    /// Resize the atlas without changing the allocations.
767    ///
768    /// This method is not allowed to shrink the width or height of the atlas.
769    pub fn grow(&mut self, new_size: Size) {
770        assert!(new_size.width >= self.size.width);
771        assert!(new_size.height >= self.size.height);
772
773        let old_size = self.size;
774        self.size = new_size;
775
776        let dx = new_size.width - old_size.width;
777        let dy = new_size.height - old_size.height;
778
779        // If there is only one node and it is free, just grow it.
780        let root = &mut self.nodes[self.root_node.index()];
781        if root.kind == NodeKind::Free && root.rect.size() == old_size {
782            root.rect.max = root.rect.min + new_size.to_vector();
783            // The node's size changed, move it to the correct free list bucket.
784            self.update_free_list_bucket(self.root_node);
785            return;
786        }
787
788        let root_orientation = root.orientation;
789        let grows_in_root_orientation = match root_orientation {
790            Orientation::Horizontal => dx > 0,
791            Orientation::Vertical => dy > 0,
792        };
793
794        // If growing along the orientation of the root node, find the right-or-bottom-most sibling
795        // and either grow it (if it is free) or append a free node next.
796        if grows_in_root_orientation {
797            let mut sibling = self.root_node;
798            while self.nodes[sibling.index()].next_sibling != AllocIndex::NONE {
799                sibling = self.nodes[sibling.index()].next_sibling;
800            }
801            let node = &mut self.nodes[sibling.index()];
802            if node.kind == NodeKind::Free {
803                node.rect.max += match root_orientation {
804                    Orientation::Horizontal => vec2(dx, 0),
805                    Orientation::Vertical => vec2(0, dy),
806                };
807                // The node's size changed, move it to the correct free list bucket.
808                self.update_free_list_bucket(sibling);
809            } else {
810                let rect = match root_orientation {
811                    Orientation::Horizontal => {
812                        let min = point2(node.rect.max.x, node.rect.min.y);
813                        let max = min + vec2(dx, node.rect.height());
814                        Rectangle { min, max }
815                    }
816                    Orientation::Vertical => {
817                        let min = point2(node.rect.min.x, node.rect.max.y);
818                        let max = min + vec2(node.rect.width(), dy);
819                        Rectangle { min, max }
820                    }
821                };
822
823                let next = self.new_node();
824                self.nodes[sibling.index()].next_sibling = next;
825                self.nodes[next.index()] = Node {
826                    kind: NodeKind::Free,
827                    rect,
828                    prev_sibling: sibling,
829                    next_sibling: AllocIndex::NONE,
830                    parent: AllocIndex::NONE,
831                    orientation: root_orientation,
832                };
833
834                self.add_free_rect(next, &rect.size());
835            }
836        }
837
838        let grows_in_opposite_orientation = match root_orientation {
839            Orientation::Horizontal => dy > 0,
840            Orientation::Vertical => dx > 0,
841        };
842
843        if grows_in_opposite_orientation {
844            let free_node = self.new_node();
845            let new_root = self.new_node();
846
847            let old_root = self.root_node;
848            self.root_node = new_root;
849
850            let new_root_orientation = root_orientation.flipped();
851
852            let min = match new_root_orientation {
853                Orientation::Horizontal => point2(old_size.width, 0),
854                Orientation::Vertical => point2(0, old_size.height),
855            };
856            let max = point2(new_size.width, new_size.height);
857            let rect = Rectangle { min, max };
858
859            self.nodes[free_node.index()] = Node {
860                parent: AllocIndex::NONE,
861                prev_sibling: new_root,
862                next_sibling: AllocIndex::NONE,
863                kind: NodeKind::Free,
864                rect,
865                orientation: new_root_orientation,
866            };
867
868            self.nodes[new_root.index()] = Node {
869                parent: AllocIndex::NONE,
870                prev_sibling: AllocIndex::NONE,
871                next_sibling: free_node,
872                kind: NodeKind::Container,
873                rect: Rectangle::zero(),
874                orientation: new_root_orientation,
875            };
876
877            self.add_free_rect(free_node, &rect.size());
878
879            // Update the nodes that need to be re-parented to the new-root.
880
881            let mut iter = old_root;
882            while iter != AllocIndex::NONE {
883                self.nodes[iter.index()].parent = new_root;
884                iter = self.nodes[iter.index()].next_sibling;
885            }
886
887            // That second loop might not be necessary, I think that the root is always the first
888            // sibling.
889            let mut iter = self.nodes[old_root.index()].next_sibling;
890            while iter != AllocIndex::NONE {
891                self.nodes[iter.index()].parent = new_root;
892                iter = self.nodes[iter.index()].prev_sibling;
893            }
894        }
895
896        #[cfg(feature = "checks")]
897        self.check_tree();
898    }
899
900    /// Invoke a callback for each free rectangle in the atlas.
901    pub fn for_each_free_rectangle<F>(&self, mut callback: F)
902    where
903        F: FnMut(&Rectangle),
904    {
905        for node in &self.nodes {
906            if node.kind == NodeKind::Free {
907                callback(&node.rect);
908            }
909        }
910    }
911
912    /// Invoke a callback for each allocated rectangle in the atlas.
913    pub fn for_each_allocated_rectangle<F>(&self, mut callback: F)
914    where
915        F: FnMut(AllocId, &Rectangle),
916    {
917        for (i, node) in self.nodes.iter().enumerate() {
918            if node.kind != NodeKind::Alloc {
919                continue;
920            }
921
922            let id = self.alloc_id(AllocIndex(i as u32));
923
924            callback(id, &node.rect);
925        }
926    }
927
928    fn find_suitable_rect(&mut self, requested_size: &Size) -> AllocIndex {
929        let ideal_bucket = free_list_for_size(
930            self.small_size_threshold,
931            self.large_size_threshold,
932            requested_size,
933        );
934
935        let use_worst_fit = ideal_bucket == LARGE_BUCKET;
936        for bucket in ideal_bucket..NUM_BUCKETS {
937            let mut candidate_score = if use_worst_fit { 0 } else { i32::MAX };
938            let mut candidate = None;
939
940            let mut freelist_idx = 0;
941            while freelist_idx < self.free_lists[bucket].len() {
942                let id = self.free_lists[bucket][freelist_idx];
943
944                // During tree simplification we don't remove merged nodes from the free list, so we have
945                // to handle it here.
946                // This is a tad awkward, but lets us avoid having to maintain a doubly linked list for
947                // the free list (which would be needed to remove nodes during tree simplification).
948                if self.nodes[id.index()].kind != NodeKind::Free {
949                    // remove the element from the free list
950                    self.free_lists[bucket].swap_remove(freelist_idx);
951                    continue;
952                }
953
954                let size = self.nodes[id.index()].rect.size();
955                let dx = size.width - requested_size.width;
956                let dy = size.height - requested_size.height;
957
958                if dx >= 0 && dy >= 0 {
959                    if dx == 0 || dy == 0 {
960                        // Perfect fit!
961                        candidate = Some((id, freelist_idx));
962                        break;
963                    }
964
965                    // Favor the largest minimum dimension, except for small
966                    // allocations.
967                    let score = i32::min(dx, dy);
968                    if (use_worst_fit && score > candidate_score)
969                        || (!use_worst_fit && score < candidate_score)
970                    {
971                        candidate_score = score;
972                        candidate = Some((id, freelist_idx));
973                    }
974                }
975
976                freelist_idx += 1;
977            }
978
979            if let Some((id, freelist_idx)) = candidate {
980                self.free_lists[bucket].swap_remove(freelist_idx);
981                return id;
982            }
983        }
984
985        AllocIndex::NONE
986    }
987
988    fn new_node(&mut self) -> AllocIndex {
989        let idx = self.unused_nodes;
990        if idx.index() < self.nodes.len() {
991            self.unused_nodes = self.nodes[idx.index()].next_sibling;
992            self.generations[idx.index()] += Wrapping(1);
993            debug_assert_eq!(self.nodes[idx.index()].kind, NodeKind::Unused);
994            return idx;
995        }
996
997        self.nodes.push(Node {
998            parent: AllocIndex::NONE,
999            next_sibling: AllocIndex::NONE,
1000            prev_sibling: AllocIndex::NONE,
1001            rect: Rectangle::zero(),
1002            kind: NodeKind::Unused,
1003            orientation: Orientation::Horizontal,
1004        });
1005
1006        self.generations.push(Wrapping(0));
1007
1008        AllocIndex(self.nodes.len() as u32 - 1)
1009    }
1010
1011    fn mark_node_unused(&mut self, id: AllocIndex) {
1012        debug_assert!(self.nodes[id.index()].kind != NodeKind::Unused);
1013        self.nodes[id.index()].kind = NodeKind::Unused;
1014        self.nodes[id.index()].next_sibling = self.unused_nodes;
1015        self.unused_nodes = id;
1016    }
1017
1018    #[cfg(feature = "checks")]
1019    fn check_siblings(&self, id: AllocIndex, next: AllocIndex, orientation: Orientation) {
1020        if next.is_none() {
1021            return;
1022        }
1023
1024        if self.nodes[next.index()].prev_sibling != id {
1025            panic!("error: #{:?}'s next sibling #{:?} has prev sibling #{:?}", id, next, self.nodes[next.index()].prev_sibling);
1026        }
1027        assert_eq!(self.nodes[next.index()].prev_sibling, id);
1028
1029        match self.nodes[id.index()].kind {
1030            NodeKind::Container | NodeKind::Unused => {
1031                return;
1032            }
1033            _ => {}
1034        }
1035        match self.nodes[next.index()].kind {
1036            NodeKind::Container | NodeKind::Unused => {
1037                return;
1038            }
1039            _ => {}
1040        }
1041
1042        let r1 = self.nodes[id.index()].rect;
1043        let r2 = self.nodes[next.index()].rect;
1044        match orientation {
1045            Orientation::Horizontal => {
1046                assert_eq!(r1.min.y, r2.min.y);
1047                assert_eq!(r1.max.y, r2.max.y);
1048            }
1049            Orientation::Vertical => {
1050                assert_eq!(r1.min.x, r2.min.x);
1051                assert_eq!(r1.max.x, r2.max.x);
1052            }
1053        }
1054    }
1055
1056    #[cfg(feature = "checks")]
1057    fn check_tree(&self) {
1058        for node_idx in 0..self.nodes.len() {
1059            let node = &self.nodes[node_idx];
1060
1061            if node.kind == NodeKind::Unused {
1062                if node.next_sibling.is_some() {
1063                    assert_eq!(self.nodes[node.next_sibling.index()].kind, NodeKind::Unused);
1064                }
1065                continue;
1066            }
1067
1068            let mut iter = node.next_sibling;
1069            while iter.is_some() {
1070                assert_eq!(self.nodes[iter.index()].orientation, node.orientation);
1071                assert_eq!(self.nodes[iter.index()].parent, node.parent);
1072                assert!(self.nodes[iter.index()].kind != NodeKind::Unused);
1073                let next = self.nodes[iter.index()].next_sibling;
1074
1075                #[cfg(feature = "checks")]
1076                self.check_siblings(iter, next, node.orientation);
1077
1078                iter = next;
1079            }
1080
1081            if node.parent.is_some() {
1082                if self.nodes[node.parent.index()].kind != NodeKind::Container {
1083                    panic!("error: child: {:?} parent: {:?}", node_idx, node.parent);
1084                }
1085                assert_eq!(
1086                    self.nodes[node.parent.index()].orientation,
1087                    node.orientation.flipped()
1088                );
1089                assert_eq!(self.nodes[node.parent.index()].kind, NodeKind::Container);
1090            }
1091        }
1092    }
1093
1094    fn add_free_rect(&mut self, id: AllocIndex, size: &Size) {
1095        debug_assert_eq!(self.nodes[id.index()].kind, NodeKind::Free);
1096        let bucket = free_list_for_size(self.small_size_threshold, self.large_size_threshold, size);
1097        self.free_lists[bucket].push(id);
1098    }
1099
1100    /// Remove a free node from its current bucket (if present) and re-add it to the
1101    /// bucket that matches its current size. Used when a free node is resized in-place.
1102    fn update_free_list_bucket(&mut self, id: AllocIndex) {
1103        debug_assert_eq!(self.nodes[id.index()].kind, NodeKind::Free);
1104
1105        // Remove from whichever bucket currently holds this id.
1106        for bucket in 0..NUM_BUCKETS {
1107            if let Some(pos) = self.free_lists[bucket].iter().position(|&i| i == id) {
1108                self.free_lists[bucket].swap_remove(pos);
1109                break;
1110            }
1111        }
1112
1113        let size = self.nodes[id.index()].rect.size();
1114        self.add_free_rect(id, &size);
1115    }
1116
1117    // Merge `next` into `node` and append `next` to a list of available `nodes`vector slots.
1118    fn merge_siblings(&mut self, node: AllocIndex, next: AllocIndex, orientation: Orientation) {
1119        debug_assert_eq!(self.nodes[node.index()].kind, NodeKind::Free);
1120        debug_assert_eq!(self.nodes[next.index()].kind, NodeKind::Free);
1121        let r1 = self.nodes[node.index()].rect;
1122        let r2 = self.nodes[next.index()].rect;
1123        let merge_size = self.nodes[next.index()].rect.size();
1124        match orientation {
1125            Orientation::Horizontal => {
1126                debug_assert_eq!(r1.min.y, r2.min.y);
1127                debug_assert_eq!(r1.max.y, r2.max.y);
1128                self.nodes[node.index()].rect.max.x += merge_size.width;
1129            }
1130            Orientation::Vertical => {
1131                debug_assert_eq!(r1.min.x, r2.min.x);
1132                debug_assert_eq!(r1.max.x, r2.max.x);
1133                self.nodes[node.index()].rect.max.y += merge_size.height;
1134            }
1135        }
1136
1137        // Remove the merged node from the sibling list.
1138        let next_next = self.nodes[next.index()].next_sibling;
1139        self.nodes[node.index()].next_sibling = next_next;
1140        if next_next.is_some() {
1141            self.nodes[next_next.index()].prev_sibling = node;
1142        }
1143
1144        // Add the merged node to the list of available slots in the nodes vector.
1145        self.mark_node_unused(next);
1146    }
1147
1148    fn alloc_id(&self, index: AllocIndex) -> AllocId {
1149        let generation = self.generations[index.index()].0 as u32;
1150        debug_assert!(index.0 & IDX_MASK == index.0);
1151        AllocId(index.0 + (generation << 24))
1152    }
1153
1154    fn get_index(&self, id: AllocId) -> AllocIndex {
1155        let idx = id.0 & IDX_MASK;
1156        let expected_generation = (self.generations[idx as usize].0 as u32) << 24;
1157        assert_eq!(id.0 & GEN_MASK, expected_generation);
1158        AllocIndex(idx)
1159    }
1160}
1161
1162impl core::ops::Index<AllocId> for AtlasAllocator {
1163    type Output = Rectangle;
1164    fn index(&self, index: AllocId) -> &Rectangle {
1165        let idx = self.get_index(index);
1166
1167        &self.nodes[idx.index()].rect
1168    }
1169}
1170
1171/// A simpler atlas allocator implementation that can allocate rectangles but not deallocate them.
1172pub struct SimpleAtlasAllocator {
1173    free_rects: [Vec<Rectangle>; 3],
1174    alignment: Size,
1175    small_size_threshold: i32,
1176    large_size_threshold: i32,
1177    size: Size,
1178}
1179
1180impl SimpleAtlasAllocator {
1181    /// Create a simple atlas allocator with default options.
1182    pub fn new(size: Size) -> Self {
1183        Self::with_options(size, &DEFAULT_OPTIONS)
1184    }
1185
1186    /// Create a simple atlas allocator with the provided options.
1187    pub fn with_options(size: Size, options: &AllocatorOptions) -> Self {
1188        let bucket = free_list_for_size(
1189            options.small_size_threshold,
1190            options.large_size_threshold,
1191            &size,
1192        );
1193
1194        let mut free_rects = [Vec::new(), Vec::new(), Vec::new()];
1195        free_rects[bucket].push(size.into());
1196
1197        SimpleAtlasAllocator {
1198            free_rects,
1199            alignment: options.alignment,
1200            small_size_threshold: options.small_size_threshold,
1201            large_size_threshold: options.large_size_threshold,
1202            size,
1203        }
1204    }
1205
1206    /// Drop all rectangles, clearing the atlas to its initial state.
1207    pub fn clear(&mut self) {
1208
1209        for i in 0..NUM_BUCKETS {
1210            self.free_rects[i].clear();
1211        }
1212
1213        let bucket = free_list_for_size(
1214            self.small_size_threshold,
1215            self.large_size_threshold,
1216            &self.size,
1217        );
1218
1219        self.free_rects[bucket].push(self.size.into());
1220    }
1221
1222    /// Clear the allocator and reset its size and options.
1223    pub fn reset(&mut self, size: Size, options: &AllocatorOptions) {
1224        self.alignment = options.alignment;
1225        self.small_size_threshold = options.small_size_threshold;
1226        self.large_size_threshold = options.large_size_threshold;
1227        self.size = size;
1228
1229        self.clear();
1230    }
1231
1232    pub fn is_empty(&self) -> bool {
1233        for b in 0..NUM_BUCKETS {
1234            for rect in &self.free_rects[b] {
1235                return rect.size() == self.size;
1236            }
1237        }
1238
1239        // This should be unreachable.
1240        return false;
1241    }
1242
1243    /// The total size of the atlas.
1244    pub fn size(&self) -> Size {
1245        self.size
1246    }
1247
1248    /// Allocate a rectangle in the atlas.
1249    pub fn allocate(&mut self, mut requested_size: Size) -> Option<Rectangle> {
1250        if requested_size.is_empty() {
1251            return None;
1252        }
1253
1254        adjust_size(self.alignment.width, &mut requested_size.width);
1255        adjust_size(self.alignment.height, &mut requested_size.height);
1256
1257        let ideal_bucket = free_list_for_size(
1258            self.small_size_threshold,
1259            self.large_size_threshold,
1260            &requested_size,
1261        );
1262
1263        let use_worst_fit = ideal_bucket == LARGE_BUCKET;
1264
1265        let mut chosen_rect = None;
1266        for bucket in ideal_bucket..NUM_BUCKETS {
1267            let mut candidate_score = if use_worst_fit { 0 } else { i32::MAX };
1268            let mut candidate = None;
1269
1270            for (index, rect) in self.free_rects[bucket].iter().enumerate() {
1271                let dx = rect.width() - requested_size.width;
1272                let dy = rect.height() - requested_size.height;
1273
1274                if dx >= 0 && dy >= 0 {
1275                    if dx == 0 || dy == 0 {
1276                        // Perfect fit!
1277                        candidate = Some(index);
1278                        break;
1279                    }
1280
1281                    let score = i32::min(dx, dy);
1282                    if (use_worst_fit && score > candidate_score)
1283                        || (!use_worst_fit && score < candidate_score)
1284                    {
1285                        candidate_score = score;
1286                        candidate = Some(index);
1287                    }
1288                }
1289            }
1290
1291            if let Some(index) = candidate {
1292                let rect = self.free_rects[bucket].remove(index);
1293                chosen_rect = Some(rect);
1294                break;
1295            }
1296        }
1297
1298        if let Some(rect) = chosen_rect {
1299            let (split_rect, leftover_rect, _) =
1300                guillotine_rect(&rect, requested_size, Orientation::Vertical);
1301            self.add_free_rect(&split_rect);
1302            self.add_free_rect(&leftover_rect);
1303
1304            return Some(Rectangle {
1305                min: rect.min,
1306                max: rect.min + requested_size.to_vector(),
1307            });
1308        }
1309
1310        None
1311    }
1312
1313    /// Resize the atlas without changing the allocations.
1314    ///
1315    /// This method is not allowed to shrink the width or height of the atlas.
1316    pub fn grow(&mut self, new_size: Size) {
1317        assert!(new_size.width >= self.size.width);
1318        assert!(new_size.height >= self.size.height);
1319
1320        let (split_rect, leftover_rect, _) =
1321            guillotine_rect(&new_size.into(), self.size, Orientation::Vertical);
1322
1323        self.size = new_size;
1324
1325        self.add_free_rect(&split_rect);
1326        self.add_free_rect(&leftover_rect);
1327    }
1328
1329    /// Initialize this simple allocator with the content of an atlas allocator.
1330    pub fn init_from_allocator(&mut self, src: &AtlasAllocator) {
1331        self.size = src.size;
1332        self.alignment = src.alignment;
1333        self.small_size_threshold = src.small_size_threshold;
1334        self.large_size_threshold = src.large_size_threshold;
1335
1336        for bucket in 0..NUM_BUCKETS {
1337            self.free_rects[bucket].clear();
1338
1339            for id in src.free_lists[bucket].iter() {
1340                // During tree simplification we don't remove merged nodes from the free list, so we have
1341                // to handle it here.
1342                // This is a tad awkward, but lets us avoid having to maintain a doubly linked list for
1343                // the free list (which would be needed to remove nodes during tree simplification).
1344                if src.nodes[id.index()].kind != NodeKind::Free {
1345                    continue;
1346                }
1347
1348                self.free_rects[bucket].push(src.nodes[id.index()].rect);
1349            }
1350        }
1351    }
1352
1353    fn add_free_rect(&mut self, rect: &Rectangle) {
1354        if rect.width() < self.alignment.width || rect.height() < self.alignment.height {
1355            return;
1356        }
1357
1358        let bucket = free_list_for_size(
1359            self.small_size_threshold,
1360            self.large_size_threshold,
1361            &rect.size(),
1362        );
1363
1364        self.free_rects[bucket].push(*rect);
1365    }
1366}
1367
1368fn adjust_size(alignment: i32, size: &mut i32) {
1369    let rem = *size % alignment;
1370    if rem > 0 {
1371        *size += alignment - rem;
1372    }
1373}
1374
1375/// Compute the area, saturating at i32::MAX instead of overflowing.
1376fn safe_area(rect: &Rectangle) -> i32 {
1377    rect.width().checked_mul(rect.height()).unwrap_or(i32::MAX)
1378}
1379
1380fn guillotine_rect(
1381    chosen_rect: &Rectangle,
1382    requested_size: Size,
1383    default_orientation: Orientation,
1384) -> (Rectangle, Rectangle, Orientation) {
1385    // Decide whether to split horizontally or vertically.
1386    //
1387    // If the chosen free rectangle is bigger than the requested size, we subdivide it
1388    // into an allocated rectangle, a split rectangle and a leftover rectangle:
1389    //
1390    // +-----------+-------------+
1391    // |///////////|             |
1392    // |/allocated/|             |
1393    // |///////////|             |
1394    // +-----------+             |
1395    // |                         |
1396    // |          chosen         |
1397    // |                         |
1398    // +-------------------------+
1399    //
1400    // Will be split into either:
1401    //
1402    // +-----------+-------------+
1403    // |///////////|             |
1404    // |/allocated/|  leftover   |
1405    // |///////////|             |
1406    // +-----------+-------------+
1407    // |                         |
1408    // |          split          |
1409    // |                         |
1410    // +-------------------------+
1411    //
1412    // or:
1413    //
1414    // +-----------+-------------+
1415    // |///////////|             |
1416    // |/allocated/|             |
1417    // |///////////|    split    |
1418    // +-----------+             |
1419    // |           |             |
1420    // | leftover  |             |
1421    // |           |             |
1422    // +-----------+-------------+
1423
1424    let candidate_leftover_rect_to_right = Rectangle {
1425        min: chosen_rect.min + vec2(requested_size.width, 0),
1426        max: point2(chosen_rect.max.x, chosen_rect.min.y + requested_size.height),
1427    };
1428    let candidate_leftover_rect_to_bottom = Rectangle {
1429        min: chosen_rect.min + vec2(0, requested_size.height),
1430        max: point2(chosen_rect.min.x + requested_size.width, chosen_rect.max.y),
1431    };
1432
1433    let split_rect;
1434    let leftover_rect;
1435    let orientation;
1436    if requested_size == chosen_rect.size() {
1437        // Perfect fit.
1438        orientation = default_orientation;
1439        split_rect = Rectangle::zero();
1440        leftover_rect = Rectangle::zero();
1441    } else if safe_area(&candidate_leftover_rect_to_right) > safe_area(&candidate_leftover_rect_to_bottom) {
1442        leftover_rect = candidate_leftover_rect_to_bottom;
1443        split_rect = Rectangle {
1444            min: candidate_leftover_rect_to_right.min,
1445            max: point2(candidate_leftover_rect_to_right.max.x, chosen_rect.max.y),
1446        };
1447        orientation = Orientation::Horizontal;
1448    } else {
1449        leftover_rect = candidate_leftover_rect_to_right;
1450        split_rect = Rectangle {
1451            min: candidate_leftover_rect_to_bottom.min,
1452            max: point2(chosen_rect.max.x, candidate_leftover_rect_to_bottom.max.y),
1453        };
1454        orientation = Orientation::Vertical;
1455    }
1456
1457    (split_rect, leftover_rect, orientation)
1458}
1459
1460#[repr(C)]
1461#[derive(Copy, Clone, Debug, PartialEq)]
1462pub struct Allocation {
1463    pub id: AllocId,
1464    pub rectangle: Rectangle,
1465}
1466
1467#[repr(C)]
1468#[derive(Copy, Clone, Debug, PartialEq)]
1469pub struct Change {
1470    pub old: Allocation,
1471    pub new: Allocation,
1472}
1473
1474#[derive(Clone, Debug, PartialEq)]
1475pub struct ChangeList {
1476    pub changes: Vec<Change>,
1477    pub failures: Vec<Allocation>,
1478}
1479
1480impl ChangeList {
1481    pub fn empty() -> Self {
1482        ChangeList {
1483            changes: Vec::new(),
1484            failures: Vec::new(),
1485        }
1486    }
1487}
1488
1489/// Dump a visual representation of the atlas in SVG format.
1490#[cfg(feature = "std")]
1491pub fn dump_svg(atlas: &AtlasAllocator, output: &mut dyn std::io::Write) -> std::io::Result<()> {
1492    use svg_fmt::*;
1493
1494    writeln!(
1495        output,
1496        "{}",
1497        BeginSvg {
1498            w: atlas.size.width as f32,
1499            h: atlas.size.height as f32
1500        }
1501    )?;
1502
1503    dump_into_svg(atlas, None, output)?;
1504
1505    writeln!(output, "{}", EndSvg)
1506}
1507
1508/// Dump a visual representation of the atlas in SVG, omitting the beginning and end of the
1509/// SVG document, so that it can be included in a larger document.
1510///
1511/// If a rectangle is provided, translate and scale the output to fit it.
1512#[cfg(feature = "std")]
1513pub fn dump_into_svg(atlas: &AtlasAllocator, rect: Option<&Rectangle>, output: &mut dyn std::io::Write) -> std::io::Result<()> {
1514    use svg_fmt::*;
1515
1516    let (sx, sy, tx, ty) = if let Some(rect) = rect {
1517        (
1518            rect.width() as f32 / atlas.size.width as f32,
1519            rect.height() as f32 / atlas.size.height as f32,
1520            rect.min.x as f32,
1521            rect.min.y as f32,
1522        )
1523    } else {
1524        (1.0, 1.0, 0.0, 0.0)
1525    };
1526
1527    for node in &atlas.nodes {
1528        let color = match node.kind {
1529            NodeKind::Free => rgb(50, 50, 50),
1530            NodeKind::Alloc => rgb(70, 70, 180),
1531            _ => {
1532                continue;
1533            }
1534        };
1535
1536        let (x, y) = node.rect.min.to_f32().to_tuple();
1537        let (w, h) = node.rect.size().to_f32().to_tuple();
1538
1539        writeln!(
1540            output,
1541            r#"    {}"#,
1542            rectangle(tx + x * sx, ty + y * sy, w * sx, h * sy)
1543                .fill(color)
1544                .stroke(Stroke::Color(black(), 1.0))
1545        )?;
1546    }
1547
1548    Ok(())
1549}
1550
1551#[test]
1552fn atlas_basic() {
1553    let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1554
1555    let full = atlas.allocate(size2(1000, 1000)).unwrap().id;
1556    assert!(atlas.allocate(size2(1, 1)).is_none());
1557
1558    atlas.deallocate(full);
1559
1560    let a = atlas.allocate(size2(100, 1000)).unwrap().id;
1561    let b = atlas.allocate(size2(900, 200)).unwrap().id;
1562    let c = atlas.allocate(size2(300, 200)).unwrap().id;
1563    let d = atlas.allocate(size2(200, 300)).unwrap().id;
1564    let e = atlas.allocate(size2(100, 300)).unwrap().id;
1565    let f = atlas.allocate(size2(100, 300)).unwrap().id;
1566    let g = atlas.allocate(size2(100, 300)).unwrap().id;
1567
1568    atlas.deallocate(b);
1569    atlas.deallocate(f);
1570    atlas.deallocate(c);
1571    atlas.deallocate(e);
1572    let h = atlas.allocate(size2(500, 200)).unwrap().id;
1573    atlas.deallocate(a);
1574    let i = atlas.allocate(size2(500, 200)).unwrap().id;
1575    atlas.deallocate(g);
1576    atlas.deallocate(h);
1577    atlas.deallocate(d);
1578    atlas.deallocate(i);
1579
1580    let full = atlas.allocate(size2(1000, 1000)).unwrap().id;
1581    assert!(atlas.allocate(size2(1, 1)).is_none());
1582    atlas.deallocate(full);
1583}
1584
1585#[test]
1586fn atlas_random_test() {
1587    let mut atlas = AtlasAllocator::with_options(
1588        size2(1000, 1000),
1589        &AllocatorOptions {
1590            alignment: size2(5, 2),
1591            ..DEFAULT_OPTIONS
1592        },
1593    );
1594
1595    let a = 1103515245;
1596    let c = 12345;
1597    let m = usize::pow(2, 31);
1598    let mut seed: usize = 37;
1599
1600    let mut rand = || {
1601        seed = (a * seed + c) % m;
1602        seed
1603    };
1604
1605    let mut n: usize = 0;
1606    let mut misses: usize = 0;
1607
1608    let mut allocated = Vec::new();
1609    for _ in 0..500000 {
1610        if rand() % 5 > 2 && !allocated.is_empty() {
1611            // deallocate something
1612            let nth = rand() % allocated.len();
1613            let id = allocated[nth];
1614            allocated.remove(nth);
1615
1616            atlas.deallocate(id);
1617        } else {
1618            // allocate something
1619            let size = size2((rand() % 300) as i32 + 5, (rand() % 300) as i32 + 5);
1620
1621            if let Some(alloc) = atlas.allocate(size) {
1622                allocated.push(alloc.id);
1623                n += 1;
1624            } else {
1625                misses += 1;
1626            }
1627        }
1628    }
1629
1630    while let Some(id) = allocated.pop() {
1631        atlas.deallocate(id);
1632    }
1633
1634    std::println!("added/removed {} rectangles, {} misses", n, misses);
1635    std::println!(
1636        "nodes.cap: {}, free_list.cap: {}/{}/{}",
1637        atlas.nodes.capacity(),
1638        atlas.free_lists[LARGE_BUCKET].capacity(),
1639        atlas.free_lists[MEDIUM_BUCKET].capacity(),
1640        atlas.free_lists[SMALL_BUCKET].capacity(),
1641    );
1642
1643    let full = atlas.allocate(size2(1000, 1000)).unwrap().id;
1644    assert!(atlas.allocate(size2(1, 1)).is_none());
1645    atlas.deallocate(full);
1646}
1647
1648#[test]
1649fn test_grow() {
1650    let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1651
1652    atlas.grow(size2(2000, 2000));
1653
1654    let full = atlas.allocate(size2(2000, 2000)).unwrap().id;
1655    assert!(atlas.allocate(size2(1, 1)).is_none());
1656    atlas.deallocate(full);
1657
1658    let a = atlas.allocate(size2(100, 100)).unwrap().id;
1659
1660    atlas.grow(size2(3000, 3000));
1661
1662    let b = atlas.allocate(size2(1000, 2900)).unwrap().id;
1663
1664    atlas.grow(size2(4000, 4000));
1665
1666    atlas.deallocate(b);
1667    atlas.deallocate(a);
1668
1669    let full = atlas.allocate(size2(4000, 4000)).unwrap().id;
1670    assert!(atlas.allocate(size2(1, 1)).is_none());
1671    atlas.deallocate(full);
1672}
1673
1674#[test]
1675fn clear_empty() {
1676    let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1677
1678    assert!(atlas.is_empty());
1679
1680    assert!(atlas.allocate(size2(10, 10)).is_some());
1681    assert!(!atlas.is_empty());
1682
1683    atlas.clear();
1684    assert!(atlas.is_empty());
1685
1686    let a = atlas.allocate(size2(10, 10)).unwrap().id;
1687    let b = atlas.allocate(size2(20, 20)).unwrap().id;
1688    assert!(!atlas.is_empty());
1689
1690    atlas.deallocate(b);
1691    atlas.deallocate(a);
1692    assert!(atlas.is_empty());
1693
1694    atlas.clear();
1695    assert!(atlas.is_empty());
1696
1697    atlas.clear();
1698    assert!(atlas.is_empty());
1699}
1700
1701#[test]
1702fn simple_atlas() {
1703    let mut atlas = SimpleAtlasAllocator::new(size2(1000, 1000));
1704
1705    assert!(atlas.allocate(size2(1, 1001)).is_none());
1706    assert!(atlas.allocate(size2(1001, 1)).is_none());
1707
1708    let mut rectangles = Vec::new();
1709    rectangles.push(atlas.allocate(size2(100, 1000)).unwrap());
1710    rectangles.push(atlas.allocate(size2(900, 200)).unwrap());
1711    rectangles.push(atlas.allocate(size2(300, 200)).unwrap());
1712    rectangles.push(atlas.allocate(size2(200, 300)).unwrap());
1713    rectangles.push(atlas.allocate(size2(100, 300)).unwrap());
1714    rectangles.push(atlas.allocate(size2(100, 300)).unwrap());
1715    rectangles.push(atlas.allocate(size2(100, 300)).unwrap());
1716    assert!(atlas.allocate(size2(800, 800)).is_none());
1717
1718    for i in 0..rectangles.len() {
1719        for j in 0..rectangles.len() {
1720            if i == j {
1721                continue;
1722            }
1723
1724            assert!(!rectangles[i].intersects(&rectangles[j]));
1725        }
1726    }
1727}
1728
1729#[test]
1730fn allocate_zero() {
1731    let mut atlas = SimpleAtlasAllocator::new(size2(1000, 1000));
1732
1733    assert!(atlas.allocate(size2(0, 0)).is_none());
1734}
1735
1736#[test]
1737fn allocate_negative() {
1738    let mut atlas = SimpleAtlasAllocator::new(size2(1000, 1000));
1739
1740    assert!(atlas.allocate(size2(-1, 1)).is_none());
1741    assert!(atlas.allocate(size2(1, -1)).is_none());
1742    assert!(atlas.allocate(size2(-1, -1)).is_none());
1743
1744    assert!(atlas.allocate(size2(-167114179, -718142)).is_none());
1745}
1746
1747#[test]
1748fn issue_25() {
1749    let mut allocator = AtlasAllocator::new(Size::new(65536, 65536));
1750    allocator.allocate(Size::new(2,2));
1751    allocator.allocate(Size::new(65500,2));
1752    allocator.allocate(Size::new(2, 65500));
1753}
1754
1755#[test]
1756fn grow_free_list_bucket() {
1757    // Regression test: growing a free node in-place must move it to the correct
1758    // free list bucket, otherwise allocations searching a higher bucket won't find it.
1759
1760    let mut atlas = AtlasAllocator::with_options(
1761        size2(100, 100),
1762        &AllocatorOptions {
1763            small_size_threshold: 32,
1764            large_size_threshold: 256,
1765            ..DEFAULT_OPTIONS
1766        },
1767    );
1768
1769    // Allocate most of the atlas, leaving a thin free strip along the bottom.
1770    // The strip's min dimension (10) is below small_size_threshold (32), so it
1771    // lands in the SMALL_BUCKET.
1772    let a = atlas.allocate(size2(100, 90)).unwrap().id;
1773
1774    // Grow the atlas so that the free strip extends from 10 to 1010 pixels tall.
1775    // Its min dimension is now 100 (>= small_threshold), so it should move out of
1776    // SMALL_BUCKET. Before the fix it stayed in SMALL_BUCKET and large allocations
1777    // could not find it.
1778    atlas.grow(size2(100, 1100));
1779
1780    // This allocation needs a rect of 100x500. The ideal bucket is LARGE_BUCKET
1781    // (500 >= 256). Without the bucket fix the 100x1010 free strip would still be
1782    // in SMALL_BUCKET and this allocation would fail.
1783    assert!(
1784        atlas.allocate(size2(100, 500)).is_some(),
1785        "Should find the grown free strip in the correct bucket"
1786    );
1787
1788    atlas.deallocate(a);
1789
1790    // Also test the single-root early-return path in grow().
1791    let mut atlas2 = AtlasAllocator::with_options(
1792        size2(20, 20),
1793        &AllocatorOptions {
1794            small_size_threshold: 32,
1795            large_size_threshold: 256,
1796            ..DEFAULT_OPTIONS
1797        },
1798    );
1799    // Atlas is a single free root node in SMALL_BUCKET (20 < 32).
1800    // Grow it past the large threshold.
1801    atlas2.grow(size2(512, 512));
1802
1803    // Allocate something that searches LARGE_BUCKET.
1804    assert!(
1805        atlas2.allocate(size2(500, 500)).is_some(),
1806        "Single-root grow should update the free list bucket"
1807    );
1808}