1#![no_std]
4
5extern crate alloc;
6
7use alloc::{vec, vec::Vec};
8use core::cmp::Ordering;
9
10pub use skyline_packer::SkylinePacker;
11pub use split_packer::SplitPacker;
12pub use strip_packer::StripPacker;
13
14mod skyline_packer;
16mod split_packer;
17mod strip_packer;
18
19#[derive(Debug, Copy, Clone)]
21pub struct PackerConfig {
22 pub max_width: u32,
24 pub max_height: u32,
26 pub allow_flipping: bool,
29}
30
31impl Default for PackerConfig {
32 fn default() -> PackerConfig {
33 PackerConfig {
34 max_width: 1024,
35 max_height: 1024,
36 allow_flipping: true,
37 }
38 }
39}
40
41#[derive(Default, Copy, Clone, Debug)]
43#[repr(C)]
44pub struct Rect {
45 pub x: u32,
46 pub y: u32,
47 pub w: u32,
48 pub h: u32,
49}
50
51impl Rect {
52 pub fn new(x: u32, y: u32, w: u32, h: u32) -> Rect {
54 Rect { x, y, w, h }
55 }
56
57 pub const fn area(&self) -> u64 {
58 self.w as u64 * self.h as u64
59 }
60
61 pub const fn size(&self) -> Size {
62 Size {
63 w: self.w,
64 h: self.h,
65 }
66 }
67
68 #[inline(always)]
70 pub fn top(&self) -> u32 {
71 self.y
72 }
73
74 #[inline(always)]
76 pub fn bottom(&self) -> u32 {
77 self.y + self.h - 1
79 }
80
81 #[inline(always)]
83 pub fn left(&self) -> u32 {
84 self.x
85 }
86
87 #[inline(always)]
89 pub fn right(&self) -> u32 {
90 self.x + self.w - 1
92 }
93
94 pub fn contains(&self, other: &Rect) -> bool {
96 self.left() <= other.left()
97 && self.right() >= other.right()
98 && self.top() <= other.top()
99 && self.bottom() >= other.bottom()
100 }
101}
102
103#[derive(Default, Clone, Copy, Debug)]
105#[repr(C)]
106pub struct Rectf {
107 pub x: u32,
108 pub y: u32,
109 pub w: u32,
110 pub h: u32,
111 pub flipped: bool,
112}
113
114impl Rectf {
115 pub fn from_rect(Rect { x, y, w, h }: Rect, flipped: bool) -> Self {
116 Self {
117 x,
118 y,
119 w,
120 h,
121 flipped,
122 }
123 }
124}
125
126impl core::ops::Deref for Rectf {
127 type Target = Rect;
128
129 fn deref(&self) -> &Self::Target {
130 unsafe { core::mem::transmute(self) }
132 }
133}
134
135#[derive(Default, Clone, Copy)]
136pub struct Size {
137 pub w: u32,
138 pub h: u32,
139}
140
141impl Size {
142 pub const ZERO: Size = Size::new(0, 0);
143
144 pub const fn new(w: u32, h: u32) -> Self {
145 Self { w, h }
146 }
147
148 pub fn flip(&mut self) -> &Self {
149 core::mem::swap(&mut self.w, &mut self.h);
150 self
151 }
152
153 pub const fn max_side(&self) -> u32 {
154 if self.h > self.w {
155 self.h
156 } else {
157 self.w
158 }
159 }
160
161 pub const fn min_side(&self) -> u32 {
162 if self.h < self.w {
163 self.h
164 } else {
165 self.w
166 }
167 }
168
169 pub const fn area(&self) -> u64 {
170 self.w as u64 * self.h as u64
171 }
172
173 pub const fn perimeter(&self) -> u64 {
174 2 * (self.w as u64) + 2 * (self.h as u64)
175 }
176
177 pub fn pathological_mult(&self) -> f32 {
178 self.max_side() as f32 / self.min_side() as f32 * self.area() as f32
179 }
180
181 pub fn expand_with(&mut self, r: &Rect) {
182 self.w = self.w.max(r.x + r.w);
183 self.h = self.h.max(r.y + r.h);
184 }
185}
186
187pub trait Packer {
188 fn insert(&mut self, w: u32, h: u32) -> Option<Rectf>;
189 fn reset(&mut self, resize: Option<Size>);
190 fn used_area(&self) -> Size;
191}
192
193#[derive(Clone, Copy)]
194pub struct RectInput<K> {
195 pub size: Size,
196 pub key: K,
197}
198
199#[derive(Clone, Copy)]
200pub struct RectOutput<K> {
201 pub rect: Rectf,
202 pub atlas: usize,
203 pub key: K,
204}
205
206pub const RECT_SORT_FUNCTIONS: [fn(Size, Size) -> Ordering; 6] = [
207 |a: Size, b: Size| b.area().cmp(&a.area()),
208 |a: Size, b: Size| b.perimeter().cmp(&a.perimeter()),
209 |a: Size, b: Size| (b.w.max(b.h)).cmp(&(a.w.max(a.h))),
210 |a: Size, b: Size| b.w.cmp(&a.w),
211 |a: Size, b: Size| b.h.cmp(&a.h),
212 |a: Size, b: Size| {
213 if b.pathological_mult() < a.pathological_mult() {
214 Ordering::Less
215 } else {
216 Ordering::Greater
217 }
218 },
219];
220
221pub fn pack<P: Packer, K: Copy>(
226 inputs: &mut Vec<RectInput<K>>,
227 mut packer: P,
228) -> Vec<RectOutput<K>> {
229 let mut output = vec![];
230 let mut output_area = core::u64::MAX;
231
232 let mut current = vec![];
233 let mut current_area;
234
235 for cmp in RECT_SORT_FUNCTIONS {
236 current.clear();
237 current_area = 0;
238
239 inputs.sort_by(|a, b| (cmp)(a.size, b.size));
240 let mut iterator = inputs.iter();
241
242 let mut atlas = 0;
244 'atlasing: loop {
245 packer.reset(None);
246
247 loop {
248 if let Some(input) = iterator.next() {
249 if let Some(rect) = packer.insert(input.size.w, input.size.h) {
250 current.push(RectOutput {
251 rect,
252 atlas,
253 key: input.key,
254 });
255 } else {
256 current_area += packer.used_area().area();
258 atlas += 1;
259 break;
260 }
261 } else {
262 break 'atlasing;
263 }
264 }
265 }
266
267 current_area += packer.used_area().area();
268
269 if current_area < output_area {
270 output_area = current_area;
271 core::mem::swap(&mut current, &mut output);
272 }
273 }
274
275 output
276}