1use super::Packer;
2use crate::config::{MaxRectsHeuristic, PackerConfig};
3use crate::model::{Frame, Rect};
4
5pub struct MaxRectsPacker {
6 config: PackerConfig,
7 border: Rect,
8 free: Vec<Rect>,
9 used: Vec<Rect>,
10 heuristic: MaxRectsHeuristic,
11}
12
13impl MaxRectsPacker {
14 pub fn new(config: PackerConfig, heuristic: MaxRectsHeuristic) -> Self {
15 let pad = config.border_padding;
16 let w = config.max_width.saturating_sub(pad.saturating_mul(2));
17 let h = config.max_height.saturating_sub(pad.saturating_mul(2));
18 let border = Rect::new(pad, pad, w, h);
19 Self {
20 config,
21 border,
22 free: vec![border],
23 used: Vec::new(),
24 heuristic,
25 }
26 }
27
28 fn rect_right_ex(r: &Rect) -> u32 {
29 r.x + r.w
30 }
31 fn rect_bottom_ex(r: &Rect) -> u32 {
32 r.y + r.h
33 }
34
35 fn intersects(a: &Rect, b: &Rect) -> bool {
36 !(a.x >= Self::rect_right_ex(b)
37 || b.x >= Self::rect_right_ex(a)
38 || a.y >= Self::rect_bottom_ex(b)
39 || b.y >= Self::rect_bottom_ex(a))
40 }
41
42 fn place_rect(&mut self, node: &Rect) {
43 if self.config.mr_reference {
44 return self.place_rect_ref(node);
45 }
46 let mut new_free: Vec<Rect> = Vec::new();
48 for fr in self.free.iter() {
49 if !Self::intersects(fr, node) {
50 new_free.push(*fr);
51 continue;
52 }
53 let fr_x2 = fr.x + fr.w;
54 let fr_y2 = fr.y + fr.h;
55 let n_x2 = node.x + node.w;
56 let n_y2 = node.y + node.h;
57
58 let ix1 = fr.x.max(node.x);
59 let iy1 = fr.y.max(node.y);
60 let ix2 = fr_x2.min(n_x2);
61 let iy2 = fr_y2.min(n_y2);
62
63 if iy1 > fr.y {
65 let h = iy1 - fr.y;
66 new_free.push(Rect::new(fr.x, fr.y, fr.w, h));
67 }
68 if iy2 < fr_y2 {
70 let h = fr_y2 - iy2;
71 new_free.push(Rect::new(fr.x, iy2, fr.w, h));
72 }
73 if ix1 > fr.x {
75 let w = ix1 - fr.x;
76 let y = iy1;
77 let h = iy2.saturating_sub(iy1);
78 if h > 0 {
79 new_free.push(Rect::new(fr.x, y, w, h));
80 }
81 }
82 if ix2 < fr_x2 {
84 let w = fr_x2 - ix2;
85 let x = ix2;
86 let y = iy1;
87 let h = iy2.saturating_sub(iy1);
88 if h > 0 {
89 new_free.push(Rect::new(x, y, w, h));
90 }
91 }
92 }
93
94 self.free = new_free;
95 self.prune_free_list();
96 self.used.push(*node);
97 }
98
99 fn place_rect_ref(&mut self, node: &Rect) {
100 let mut new_free: Vec<Rect> = Vec::new();
101 let mut i = 0usize;
102 while i < self.free.len() {
103 let fr = self.free[i];
104 if Self::intersects(&fr, node) {
105 self.free.swap_remove(i);
107 self.split_free_node_ref(fr, node, &mut new_free);
108 } else {
109 i += 1;
110 }
111 }
112 self.prune_new_vs_old(&mut new_free);
114 self.prune_within(&mut new_free);
115 self.free.extend(new_free);
117 self.prune_free_list();
118 self.used.push(*node);
119 }
120
121 fn split_free_node_ref(&self, fr: Rect, node: &Rect, out: &mut Vec<Rect>) {
122 let fr_x2 = fr.x + fr.w;
123 let fr_y2 = fr.y + fr.h;
124 let n_x2 = node.x + node.w;
125 let n_y2 = node.y + node.h;
126
127 if node.x > fr.x && node.x < fr_x2 {
129 let w = node.x - fr.x;
130 out.push(Rect::new(fr.x, fr.y, w, fr.h));
131 }
132 if n_x2 < fr_x2 {
134 let x = n_x2;
135 let w = fr_x2 - n_x2;
136 out.push(Rect::new(x, fr.y, w, fr.h));
137 }
138 if node.y > fr.y && node.y < fr_y2 {
140 let h = node.y - fr.y;
141 out.push(Rect::new(fr.x, fr.y, fr.w, h));
142 }
143 if n_y2 < fr_y2 {
145 let y = n_y2;
146 let h = fr_y2 - n_y2;
147 out.push(Rect::new(fr.x, y, fr.w, h));
148 }
149 }
151
152 fn prune_new_vs_old(&mut self, new_free: &mut Vec<Rect>) {
153 new_free.retain(|nr| !self.free.iter().any(|of| of.contains(nr)) && nr.w > 0 && nr.h > 0);
155 let mut i = 0;
157 while i < self.free.len() {
158 if new_free.iter().any(|nr| nr.contains(&self.free[i])) {
159 self.free.swap_remove(i);
160 } else {
161 i += 1;
162 }
163 }
164 }
165
166 fn prune_within(&self, v: &mut Vec<Rect>) {
167 let mut i = 0;
168 while i < v.len() {
169 let a = v[i];
170 let a_x2 = a.x + a.w;
171 let a_y2 = a.y + a.h;
172 let mut remove_i = false;
173 let mut j = 0;
174 while j < v.len() {
175 if i == j {
176 j += 1;
177 continue;
178 }
179 let b = v[j];
180 let b_x2 = b.x + b.w;
181 let b_y2 = b.y + b.h;
182 if a.x >= b.x && a.y >= b.y && a_x2 <= b_x2 && a_y2 <= b_y2 {
183 remove_i = true;
184 break;
185 }
186 j += 1;
187 }
188 if remove_i {
189 v.swap_remove(i);
190 } else {
191 i += 1;
192 }
193 }
194 }
195
196 fn prune_free_list(&mut self) {
197 let mut i = 0;
198 while i < self.free.len() {
199 let mut j = i + 1;
200 let a = self.free[i];
201 let a_right = Self::rect_right_ex(&a);
202 let a_bottom = Self::rect_bottom_ex(&a);
203 let mut remove_i = false;
204 while j < self.free.len() {
205 let b = self.free[j];
206 let b_right = Self::rect_right_ex(&b);
207 let b_bottom = Self::rect_bottom_ex(&b);
208 if a.x >= b.x && a.y >= b.y && a_right <= b_right && a_bottom <= b_bottom {
210 remove_i = true;
211 break;
212 }
213 if b.x >= a.x && b.y >= a.y && b_right <= a_right && b_bottom <= a_bottom {
215 self.free.remove(j);
216 continue;
217 }
218 j += 1;
219 }
220 if remove_i {
221 self.free.remove(i);
222 } else {
223 i += 1;
224 }
225 }
226 }
227
228 fn score(&self, fr: &Rect, w: u32, h: u32) -> (i32, i32) {
229 let leftover_h = fr.w as i32 - w as i32;
230 let leftover_v = fr.h as i32 - h as i32;
231 let short_fit = leftover_h.abs().min(leftover_v.abs());
232 let long_fit = leftover_h.abs().max(leftover_v.abs());
233 let area_fit = (fr.w * fr.h) as i32 - (w * h) as i32;
234 match self.heuristic {
235 MaxRectsHeuristic::BestAreaFit => (area_fit, short_fit),
236 MaxRectsHeuristic::BestShortSideFit => (short_fit, long_fit),
237 MaxRectsHeuristic::BestLongSideFit => (long_fit, short_fit),
238 MaxRectsHeuristic::BottomLeft => (fr.y as i32, fr.x as i32),
239 MaxRectsHeuristic::ContactPoint => {
240 let contact = self.contact_point_score(fr.x, fr.y, w, h);
242 (-(contact as i32), area_fit)
243 }
244 }
245 }
246
247 fn find_position(&self, w: u32, h: u32) -> Option<(Rect, bool)> {
248 let mut best_score1 = i32::MAX;
249 let mut best_score2 = i32::MAX;
250 let mut best_rect = Rect::new(0, 0, 0, 0);
251 let mut best_rot = false;
252 let mut best_top = u32::MAX; let mut best_left = u32::MAX; for fr in &self.free {
256 if fr.w >= w && fr.h >= h {
258 let (s1, s2) = self.score(fr, w, h);
259 let top = fr.y.saturating_add(h);
260 if s1 < best_score1
261 || (s1 == best_score1
262 && (s2 < best_score2
263 || (s2 == best_score2
264 && (top < best_top || (top == best_top && fr.x < best_left)))))
265 {
266 best_score1 = s1;
267 best_score2 = s2;
268 best_top = top;
269 best_left = fr.x;
270 best_rect = Rect::new(fr.x, fr.y, w, h);
271 best_rot = false;
272 }
273 if fr.w == w && fr.h == h {
275 return Some((Rect::new(fr.x, fr.y, w, h), false));
276 }
277 }
278 if self.config.allow_rotation && fr.w >= h && fr.h >= w {
280 let (s1, s2) = self.score(fr, h, w);
281 let top = fr.y.saturating_add(w);
282 if s1 < best_score1
283 || (s1 == best_score1
284 && (s2 < best_score2
285 || (s2 == best_score2
286 && (top < best_top || (top == best_top && fr.x < best_left)))))
287 {
288 best_score1 = s1;
289 best_score2 = s2;
290 best_top = top;
291 best_left = fr.x;
292 best_rect = Rect::new(fr.x, fr.y, h, w);
293 best_rot = true;
294 }
295 if fr.w == h && fr.h == w {
297 return Some((Rect::new(fr.x, fr.y, h, w), true));
298 }
299 }
300 }
301
302 if best_rect.w == 0 || best_rect.h == 0 {
303 None
304 } else {
305 Some((best_rect, best_rot))
306 }
307 }
308
309 fn contact_point_score(&self, x: u32, y: u32, w: u32, h: u32) -> u32 {
310 let node = Rect::new(x, y, w, h);
311 let mut score = 0u32;
312 let border_right = self.border.x + self.border.w;
314 let border_bottom = self.border.y + self.border.h;
315 if node.x == self.border.x {
316 score += node.h;
317 }
318 if node.y == self.border.y {
319 score += node.w;
320 }
321 if node.x + node.w == border_right {
322 score += node.h;
323 }
324 if node.y + node.h == border_bottom {
325 score += node.w;
326 }
327
328 for u in &self.used {
330 if node.x == u.x + u.w || u.x == node.x + node.w {
332 let overlap = overlap_1d(node.y, node.y + node.h, u.y, u.y + u.h);
333 score += overlap;
334 }
335 if node.y == u.y + u.h || u.y == node.y + node.h {
337 let overlap = overlap_1d(node.x, node.x + node.w, u.x, u.x + u.w);
338 score += overlap;
339 }
340 }
341 score
342 }
343
344 pub fn free_list_len(&self) -> usize {
345 self.free.len()
346 }
347}
348
349fn overlap_1d(a1: u32, a2: u32, b1: u32, b2: u32) -> u32 {
350 let start = a1.max(b1);
351 let end = a2.min(b2);
352 end.saturating_sub(start)
353}
354
355impl<K: Clone> Packer<K> for MaxRectsPacker {
356 fn can_pack(&self, rect: &Rect) -> bool {
357 let w = rect.w + self.config.texture_padding + self.config.texture_extrusion * 2;
358 let h = rect.h + self.config.texture_padding + self.config.texture_extrusion * 2;
359 self.find_position(w, h).is_some()
360 }
361
362 fn pack(&mut self, key: K, rect: &Rect) -> Option<Frame<K>> {
363 let w = rect.w + self.config.texture_padding + self.config.texture_extrusion * 2;
364 let h = rect.h + self.config.texture_padding + self.config.texture_extrusion * 2;
365 if let Some((place, rotated)) = self.find_position(w, h) {
366 self.place_rect(&place);
367 let (fw, fh) = if rotated {
370 (rect.h, rect.w)
371 } else {
372 (rect.w, rect.h)
373 };
374 let pad_half = self.config.texture_padding / 2;
375 let off = self.config.texture_extrusion + pad_half;
376 let frame = Rect::new(
377 place.x.saturating_add(off),
378 place.y.saturating_add(off),
379 fw,
380 fh,
381 );
382 Some(Frame {
383 key,
384 frame,
385 rotated,
386 trimmed: false,
387 source: *rect,
388 source_size: (rect.w, rect.h),
389 })
390 } else {
391 None
392 }
393 }
394}