Blender V4.3
boxpack_2d.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <math.h> /* for fabsf */
10#include <stdlib.h> /* for qsort */
11
12#include "MEM_guardedalloc.h"
13
14#include "BLI_boxpack_2d.h" /* own include */
15#include "BLI_listbase.h"
16#include "BLI_utildefines.h"
17
18#include "BLI_sort.h" /* qsort_r */
19#define qsort_r BLI_qsort_r
20
21#include "BLI_strict_flags.h" /* Keep last. */
22
23#ifdef __GNUC__
24# pragma GCC diagnostic error "-Wpadded"
25#endif
26
27/* de-duplicate as we pack */
28#define USE_MERGE
29/* use strip-free */
30#define USE_FREE_STRIP
31/* slight bias, needed when packing many boxes the _exact_ same size */
32#define USE_PACK_BIAS
33
34/* BoxPacker for backing 2D rectangles into a square
35 *
36 * The defined Below are for internal use only */
37typedef struct BoxVert {
38 float x;
39 float y;
40
41 int free : 8; /* vert status */
43 uint _pad : 23;
45
46 BoxPack *trb; /* top right box */
47 BoxPack *blb; /* bottom left box */
48 BoxPack *brb; /* bottom right box */
49 BoxPack *tlb; /* top left box */
50
51 /* Store last intersecting boxes here
52 * speedup intersection testing */
54
55#ifdef USE_PACK_BIAS
56 float bias;
57 int _pad2;
58#endif
60
61#ifdef __GNUC__
62# pragma GCC diagnostic ignored "-Wpadded"
63#endif
64
65/* free vert flags */
66#define EPSILON 0.0000001f
67#define EPSILON_MERGE 0.00001f
68#ifdef USE_PACK_BIAS
69# define EPSILON_BIAS 0.000001f
70#endif
71#define BLF 1
72#define TRF 2
73#define TLF 4
74#define BRF 8
75#define CORNERFLAGS (BLF | TRF | TLF | BRF)
76
78{
79 BLI_assert(q < 4);
80 return (1 << q);
81}
82
83#define BL 0
84#define TR 1
85#define TL 2
86#define BR 3
87
88/* -------------------------------------------------------------------- */
92static float box_xmin_get(const BoxPack *box)
93{
94 return box->v[BL]->x;
95}
96
97static float box_xmax_get(const BoxPack *box)
98{
99 return box->v[TR]->x;
100}
101
102static float box_ymin_get(const BoxPack *box)
103{
104 return box->v[BL]->y;
105}
106
107static float box_ymax_get(const BoxPack *box)
108{
109 return box->v[TR]->y;
110}
111
114/* -------------------------------------------------------------------- */
119{
120 box->v[TL]->x = box->v[BL]->x;
121 box->v[BR]->x = box->v[TR]->x;
122}
123
125{
126 box->v[TL]->y = box->v[TR]->y;
127 box->v[BR]->y = box->v[BL]->y;
128}
129
130static void box_xmin_set(BoxPack *box, const float f)
131{
132 box->v[TR]->x = f + box->w;
133 box->v[BL]->x = f;
134 box_v34x_update(box);
135}
136
137static void box_xmax_set(BoxPack *box, const float f)
138{
139 box->v[BL]->x = f - box->w;
140 box->v[TR]->x = f;
141 box_v34x_update(box);
142}
143
144static void box_ymin_set(BoxPack *box, const float f)
145{
146 box->v[TR]->y = f + box->h;
147 box->v[BL]->y = f;
148 box_v34y_update(box);
149}
150
151static void box_ymax_set(BoxPack *box, const float f)
152{
153 box->v[BL]->y = f - box->h;
154 box->v[TR]->y = f;
155 box_v34y_update(box);
156}
157
160/* -------------------------------------------------------------------- */
164static float box_area(const BoxPack *box)
165{
166 return box->w * box->h;
167}
168
169static bool box_isect(const BoxPack *box_a, const BoxPack *box_b)
170{
171 return !(box_xmin_get(box_a) + EPSILON >= box_xmax_get(box_b) ||
172 box_ymin_get(box_a) + EPSILON >= box_ymax_get(box_b) ||
173 box_xmax_get(box_a) - EPSILON <= box_xmin_get(box_b) ||
174 box_ymax_get(box_a) - EPSILON <= box_ymin_get(box_b));
175}
176
179/* compiler should inline */
180static float max_ff(const float a, const float b)
181{
182 return b > a ? b : a;
183}
184
185#ifdef USE_PACK_BIAS
186/* set when used is enabled */
188{
189 BLI_assert(v->used);
190 v->bias = (v->x * v->y) * EPSILON_BIAS;
191}
192#endif
193
194#if 0
195# define BOXDEBUG(b) \
196 printf("\tBox Debug i %i, w:%.3f h:%.3f x:%.3f y:%.3f\n", b->index, b->w, b->h, b->x, b->y)
197#endif
198
199/* -------------------------------------------------------------------- */
203/* qsort function - sort largest to smallest */
204static int box_areasort(const void *p1, const void *p2)
205{
206 const BoxPack *b1 = p1, *b2 = p2;
207 const float a1 = box_area(b1);
208 const float a2 = box_area(b2);
209
210 if (a1 < a2) {
211 return 1;
212 }
213 if (a1 > a2) {
214 return -1;
215 }
216 return 0;
217}
218
219/* qsort vertex sorting function
220 * sorts from lower left to top right It uses the current box's width and height
221 * as offsets when sorting, this has the result of not placing boxes outside
222 * the bounds of the existing backed area where possible
223 */
228
229static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
230{
231 const struct VertSortContext *vs_ctx = vs_ctx_p;
232 const BoxVert *v1, *v2;
233 float a1, a2;
234
235 v1 = &vs_ctx->vertarray[*((const uint *)p1)];
236 v2 = &vs_ctx->vertarray[*((const uint *)p2)];
237
238#ifdef USE_FREE_STRIP
239 /* push free verts to the end so we can strip */
240 if (UNLIKELY(v1->free == 0 && v2->free == 0)) {
241 return 0;
242 }
243 if (UNLIKELY(v1->free == 0)) {
244 return 1;
245 }
246 if (UNLIKELY(v2->free == 0)) {
247 return -1;
248 }
249#endif
250
251 a1 = max_ff(v1->x + vs_ctx->box_width, v1->y + vs_ctx->box_height);
252 a2 = max_ff(v2->x + vs_ctx->box_width, v2->y + vs_ctx->box_height);
253
254#ifdef USE_PACK_BIAS
255 a1 += v1->bias;
256 a2 += v2->bias;
257#endif
258
259 /* sort largest to smallest */
260 if (a1 > a2) {
261 return 1;
262 }
263 if (a1 < a2) {
264 return -1;
265 }
266 return 0;
267}
268
272 BoxPack *boxarray, const uint len, const bool sort_boxes, float *r_tot_x, float *r_tot_y)
273{
274 uint box_index, verts_pack_len, i, j, k;
275 uint *vertex_pack_indices; /* an array of indices used for sorting verts */
276 bool isect;
277 float tot_x = 0.0f, tot_y = 0.0f;
278
279 BoxPack *box, *box_test; /* Current box and another for intersection tests. */
280 BoxVert *vert; /* The current vert. */
281
282 struct VertSortContext vs_ctx;
283
284 if (!len) {
285 *r_tot_x = tot_x;
286 *r_tot_y = tot_y;
287 return;
288 }
289
290 if (sort_boxes) {
291 /* Sort boxes, biggest first.
292 * Be careful, qsort is not deterministic! */
293 qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort);
294 }
295
296 /* Add verts to the boxes, these are only used internally. */
297 vert = MEM_mallocN(sizeof(BoxVert[4]) * (size_t)len, "BoxPack Verts");
298 vertex_pack_indices = MEM_mallocN(sizeof(int[3]) * (size_t)len, "BoxPack Indices");
299
300 vs_ctx.vertarray = vert;
301
302 for (box = boxarray, box_index = 0, i = 0; box_index < len; box_index++, box++) {
303
304 vert->blb = vert->brb = vert->tlb = vert->isect_cache[0] = vert->isect_cache[1] =
305 vert->isect_cache[2] = vert->isect_cache[3] = NULL;
306 vert->free = CORNERFLAGS & ~TRF;
307 vert->trb = box;
308 vert->used = false;
309 vert->index = i++;
310 box->v[BL] = vert++;
311
312 vert->trb = vert->brb = vert->tlb = vert->isect_cache[0] = vert->isect_cache[1] =
313 vert->isect_cache[2] = vert->isect_cache[3] = NULL;
314 vert->free = CORNERFLAGS & ~BLF;
315 vert->blb = box;
316 vert->used = false;
317 vert->index = i++;
318 box->v[TR] = vert++;
319
320 vert->trb = vert->blb = vert->tlb = vert->isect_cache[0] = vert->isect_cache[1] =
321 vert->isect_cache[2] = vert->isect_cache[3] = NULL;
322 vert->free = CORNERFLAGS & ~BRF;
323 vert->brb = box;
324 vert->used = false;
325 vert->index = i++;
326 box->v[TL] = vert++;
327
328 vert->trb = vert->blb = vert->brb = vert->isect_cache[0] = vert->isect_cache[1] =
329 vert->isect_cache[2] = vert->isect_cache[3] = NULL;
330 vert->free = CORNERFLAGS & ~TLF;
331 vert->tlb = box;
332 vert->used = false;
333 vert->index = i++;
334 box->v[BR] = vert++;
335 }
336 vert = NULL;
337
338 /* Pack the First box!
339 * then enter the main box-packing loop */
340
341 box = boxarray; /* Get the first box. */
342 /* First time, no boxes packed */
343 box->v[BL]->free = 0; /* Can't use any if these */
344 box->v[BR]->free &= ~(BLF | BRF);
345 box->v[TL]->free &= ~(BLF | TLF);
346
347 tot_x = box->w;
348 tot_y = box->h;
349
350 /* This sets all the vertex locations */
351 box_xmin_set(box, 0.0f);
352 box_ymin_set(box, 0.0f);
353 box->x = box->y = 0.0f;
354
355 for (i = 0; i < 4; i++) {
356 box->v[i]->used = true;
357#ifdef USE_PACK_BIAS
358 vert_bias_update(box->v[i]);
359#endif
360 }
361
362 for (i = 0; i < 3; i++) {
363 vertex_pack_indices[i] = box->v[i + 1]->index;
364 }
365 verts_pack_len = 3;
366 box++; /* next box, needed for the loop below */
367 /* ...done packing the first box */
368
369 /* Main box-packing loop */
370 for (box_index = 1; box_index < len; box_index++, box++) {
371
372 /* These floats are used for sorting re-sorting */
373 vs_ctx.box_width = box->w;
374 vs_ctx.box_height = box->h;
375
376 qsort_r(vertex_pack_indices, (size_t)verts_pack_len, sizeof(int), vertex_sort, &vs_ctx);
377
378#ifdef USE_FREE_STRIP
379 /* strip free vertices */
380 i = verts_pack_len - 1;
381 while ((i != 0) && vs_ctx.vertarray[vertex_pack_indices[i]].free == 0) {
382 i--;
383 }
384 verts_pack_len = i + 1;
385#endif
386
387 /* Pack the box in with the others */
388 /* sort the verts */
389 isect = true;
390
391 for (i = 0; i < verts_pack_len && isect; i++) {
392 vert = &vs_ctx.vertarray[vertex_pack_indices[i]];
393 // printf("\ttesting vert %i %i %i %f %f\n", i,
394 // vert->free, verts_pack_len, vert->x, vert->y);
395
396 /* This vert has a free quadrant
397 * Test if we can place the box here
398 * `vert->free & quad_flags[j]` - Checks. */
399
400 for (j = 0; (j < 4) && isect; j++) {
401 if (vert->free & quad_flag(j)) {
402 switch (j) {
403 case BL:
404 box_xmax_set(box, vert->x);
405 box_ymax_set(box, vert->y);
406 break;
407 case TR:
408 box_xmin_set(box, vert->x);
409 box_ymin_set(box, vert->y);
410 break;
411 case TL:
412 box_xmax_set(box, vert->x);
413 box_ymin_set(box, vert->y);
414 break;
415 case BR:
416 box_xmin_set(box, vert->x);
417 box_ymax_set(box, vert->y);
418 break;
419 }
420
421 /* Now we need to check that the box intersects
422 * with any other boxes
423 * Assume no intersection... */
424 isect = false;
425
426 if (/* Constrain boxes to positive X/Y values */
427 box_xmin_get(box) < 0.0f || box_ymin_get(box) < 0.0f ||
428 /* check for last intersected */
429 (vert->isect_cache[j] && box_isect(box, vert->isect_cache[j])))
430 {
431 /* Here we check that the last intersected
432 * box will intersect with this one using
433 * isect_cache that can store a pointer to a
434 * box for each quadrant
435 * big speedup */
436 isect = true;
437 }
438 else {
439 /* do a full search for colliding box
440 * this is really slow, some spatially divided
441 * data-structure would be better */
442 for (box_test = boxarray; box_test != box; box_test++) {
443 if (box_isect(box, box_test)) {
444 /* Store the last intersecting here as cache
445 * for faster checking next time around */
446 vert->isect_cache[j] = box_test;
447 isect = true;
448 break;
449 }
450 }
451 }
452
453 if (!isect) {
454
455 /* maintain the total width and height */
456 tot_x = max_ff(box_xmax_get(box), tot_x);
457 tot_y = max_ff(box_ymax_get(box), tot_y);
458
459 /* Place the box */
460 vert->free &= (signed char)~quad_flag(j);
461
462 switch (j) {
463 case TR:
464 box->v[BL] = vert;
465 vert->trb = box;
466 break;
467 case TL:
468 box->v[BR] = vert;
469 vert->tlb = box;
470 break;
471 case BR:
472 box->v[TL] = vert;
473 vert->brb = box;
474 break;
475 case BL:
476 box->v[TR] = vert;
477 vert->blb = box;
478 break;
479 }
480
481 /* Mask free flags for verts that are
482 * on the bottom or side so we don't get
483 * boxes outside the given rectangle ares
484 *
485 * We can do an else/if here because only the first
486 * box can be at the very bottom left corner */
487 if (box_xmin_get(box) <= 0) {
488 box->v[TL]->free &= ~(TLF | BLF);
489 box->v[BL]->free &= ~(TLF | BLF);
490 }
491 else if (box_ymin_get(box) <= 0) {
492 box->v[BL]->free &= ~(BRF | BLF);
493 box->v[BR]->free &= ~(BRF | BLF);
494 }
495
496 /* The following block of code does a logical
497 * check with 2 adjacent boxes, its possible to
498 * flag verts on one or both of the boxes
499 * as being used by checking the width or
500 * height of both boxes */
501 if (vert->tlb && vert->trb && ELEM(box, vert->tlb, vert->trb)) {
502 if (UNLIKELY(fabsf(vert->tlb->h - vert->trb->h) < EPSILON_MERGE)) {
503#ifdef USE_MERGE
504# define A (vert->trb->v[TL])
505# define B (vert->tlb->v[TR])
506# define MASK (BLF | BRF)
507 BLI_assert(A->used != B->used);
508 if (A->used) {
509 A->free &= B->free & ~MASK;
510 B = A;
511 }
512 else {
513 B->free &= A->free & ~MASK;
514 A = B;
515 }
516 BLI_assert((A->free & MASK) == 0);
517# undef A
518# undef B
519# undef MASK
520#else
521 vert->tlb->v[TR]->free &= ~BLF;
522 vert->trb->v[TL]->free &= ~BRF;
523#endif
524 }
525 else if (vert->tlb->h > vert->trb->h) {
526 vert->trb->v[TL]->free &= ~(TLF | BLF);
527 }
528 else /* if (vert->tlb->h < vert->trb->h) */ {
529 vert->tlb->v[TR]->free &= ~(TRF | BRF);
530 }
531 }
532 else if (vert->blb && vert->brb && ELEM(box, vert->blb, vert->brb)) {
533 if (UNLIKELY(fabsf(vert->blb->h - vert->brb->h) < EPSILON_MERGE)) {
534#ifdef USE_MERGE
535# define A (vert->blb->v[BR])
536# define B (vert->brb->v[BL])
537# define MASK (TRF | TLF)
538 BLI_assert(A->used != B->used);
539 if (A->used) {
540 A->free &= B->free & ~MASK;
541 B = A;
542 }
543 else {
544 B->free &= A->free & ~MASK;
545 A = B;
546 }
547 BLI_assert((A->free & MASK) == 0);
548# undef A
549# undef B
550# undef MASK
551#else
552 vert->blb->v[BR]->free &= ~TRF;
553 vert->brb->v[BL]->free &= ~TLF;
554#endif
555 }
556 else if (vert->blb->h > vert->brb->h) {
557 vert->brb->v[BL]->free &= ~(TLF | BLF);
558 }
559 else /* if (vert->blb->h < vert->brb->h) */ {
560 vert->blb->v[BR]->free &= ~(TRF | BRF);
561 }
562 }
563 /* Horizontal */
564 if (vert->tlb && vert->blb && ELEM(box, vert->tlb, vert->blb)) {
565 if (UNLIKELY(fabsf(vert->tlb->w - vert->blb->w) < EPSILON_MERGE)) {
566#ifdef USE_MERGE
567# define A (vert->blb->v[TL])
568# define B (vert->tlb->v[BL])
569# define MASK (TRF | BRF)
570 BLI_assert(A->used != B->used);
571 if (A->used) {
572 A->free &= B->free & ~MASK;
573 B = A;
574 }
575 else {
576 B->free &= A->free & ~MASK;
577 A = B;
578 }
579 BLI_assert((A->free & MASK) == 0);
580# undef A
581# undef B
582# undef MASK
583#else
584 vert->blb->v[TL]->free &= ~TRF;
585 vert->tlb->v[BL]->free &= ~BRF;
586#endif
587 }
588 else if (vert->tlb->w > vert->blb->w) {
589 vert->blb->v[TL]->free &= ~(TLF | TRF);
590 }
591 else /* if (vert->tlb->w < vert->blb->w) */ {
592 vert->tlb->v[BL]->free &= ~(BLF | BRF);
593 }
594 }
595 else if (vert->trb && vert->brb && ELEM(box, vert->trb, vert->brb)) {
596 if (UNLIKELY(fabsf(vert->trb->w - vert->brb->w) < EPSILON_MERGE)) {
597
598#ifdef USE_MERGE
599# define A (vert->brb->v[TR])
600# define B (vert->trb->v[BR])
601# define MASK (TLF | BLF)
602 BLI_assert(A->used != B->used);
603 if (A->used) {
604 A->free &= B->free & ~MASK;
605 B = A;
606 }
607 else {
608 B->free &= A->free & ~MASK;
609 A = B;
610 }
611 BLI_assert((A->free & MASK) == 0);
612# undef A
613# undef B
614# undef MASK
615#else
616 vert->brb->v[TR]->free &= ~TLF;
617 vert->trb->v[BR]->free &= ~BLF;
618#endif
619 }
620 else if (vert->trb->w > vert->brb->w) {
621 vert->brb->v[TR]->free &= ~(TLF | TRF);
622 }
623 else /* if (vert->trb->w < vert->brb->w) */ {
624 vert->trb->v[BR]->free &= ~(BLF | BRF);
625 }
626 }
627 /* End logical check */
628
629 for (k = 0; k < 4; k++) {
630 if (box->v[k]->used == false) {
631 box->v[k]->used = true;
632#ifdef USE_PACK_BIAS
633 vert_bias_update(box->v[k]);
634#endif
635 vertex_pack_indices[verts_pack_len] = box->v[k]->index;
636 verts_pack_len++;
637 }
638 }
639 /* The Box verts are only used internally
640 * Update the box x and y since that's what external
641 * functions will see */
642 box->x = box_xmin_get(box);
643 box->y = box_ymin_get(box);
644 }
645 }
646 }
647 }
648 }
649
650 *r_tot_x = tot_x;
651 *r_tot_y = tot_y;
652
653 /* free all the verts, not really needed because they shouldn't be
654 * touched anymore but accessing the pointers would crash blender */
655 for (box_index = 0; box_index < len; box_index++) {
656 box = boxarray + box_index;
657 box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL;
658 }
659 MEM_freeN(vertex_pack_indices);
660 MEM_freeN(vs_ctx.vertarray);
661}
662
663void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed)
664{
665 ListBase spaces = {NULL};
666 FixedSizeBoxPack *full_rect = MEM_callocN(sizeof(FixedSizeBoxPack), __func__);
667 full_rect->w = width;
668 full_rect->h = height;
669
670 BLI_addhead(&spaces, full_rect);
671
672 /* The basic idea of the algorithm is to keep a list of free spaces in the packing area.
673 * Then, for each box to be packed, we try to find a space that can contain it.
674 * The found space is then split into the area that is occupied by the box and the
675 * remaining area, which is reinserted into the free space list.
676 * By inserting the smaller remaining spaces first, the algorithm tries to use these
677 * smaller spaces first instead of "wasting" a large space. */
679 LISTBASE_FOREACH (FixedSizeBoxPack *, space, &spaces) {
680 /* Skip this space if it's too small. */
681 if (box->w > space->w || box->h > space->h) {
682 continue;
683 }
684
685 /* Pack this box into this space. */
686 box->x = space->x;
687 box->y = space->y;
688 BLI_remlink(boxes, box);
689 BLI_addtail(packed, box);
690
691 if (box->w == space->w && box->h == space->h) {
692 /* Box exactly fills space, so just remove the space. */
693 BLI_remlink(&spaces, space);
694 MEM_freeN(space);
695 }
696 else if (box->w == space->w) {
697 /* Box fills the entire width, so we can just contract the box
698 * to the upper part that remains. */
699 space->y += box->h;
700 space->h -= box->h;
701 }
702 else if (box->h == space->h) {
703 /* Box fills the entire height, so we can just contract the box
704 * to the right part that remains. */
705 space->x += box->w;
706 space->w -= box->w;
707 }
708 else {
709 /* Split the remaining L-shaped space into two spaces.
710 * There are two ways to do so, we pick the one that produces the biggest
711 * remaining space:
712 *
713 * Horizontal Split Vertical Split
714 * ################### ###################
715 * # # # - #
716 * # Large # # Small - #
717 * # # # - #
718 * #********---------# #******** Large #
719 * # Box * Small # # Box * #
720 * # * # # * #
721 * ################### ###################
722 */
723 int area_hsplit_large = space->w * (space->h - box->h);
724 int area_vsplit_large = (space->w - box->w) * space->h;
725
726 /* Perform split. This space becomes the larger space,
727 * while the new smaller space is inserted _before_ it. */
728 FixedSizeBoxPack *new_space = MEM_callocN(sizeof(FixedSizeBoxPack), __func__);
729 if (area_hsplit_large > area_vsplit_large) {
730 new_space->x = space->x + box->w;
731 new_space->y = space->y;
732 new_space->w = space->w - box->w;
733 new_space->h = box->h;
734
735 space->y += box->h;
736 space->h -= box->h;
737 }
738 else {
739 new_space->x = space->x;
740 new_space->y = space->y + box->h;
741 new_space->w = box->w;
742 new_space->h = space->h - box->h;
743
744 space->x += box->w;
745 space->w -= box->w;
746 }
747 BLI_addhead(&spaces, new_space);
748 }
749
750 break;
751 }
752 }
753
754 BLI_freelistN(&spaces);
755}
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
unsigned int uint
#define UNLIKELY(x)
#define ELEM(...)
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define EPSILON
Definition boxpack_2d.c:66
BLI_INLINE void box_v34x_update(BoxPack *box)
Definition boxpack_2d.c:118
#define B
BLI_INLINE void box_v34y_update(BoxPack *box)
Definition boxpack_2d.c:124
static int box_areasort(const void *p1, const void *p2)
Definition boxpack_2d.c:204
#define qsort_r
Definition boxpack_2d.c:19
static void vert_bias_update(BoxVert *v)
Definition boxpack_2d.c:187
struct BoxVert BoxVert
#define TL
Definition boxpack_2d.c:85
static float box_xmax_get(const BoxPack *box)
Definition boxpack_2d.c:97
#define TR
Definition boxpack_2d.c:84
#define TRF
Definition boxpack_2d.c:72
#define TLF
Definition boxpack_2d.c:73
void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed)
Definition boxpack_2d.c:663
static bool box_isect(const BoxPack *box_a, const BoxPack *box_b)
Definition boxpack_2d.c:169
static float box_ymax_get(const BoxPack *box)
Definition boxpack_2d.c:107
static float box_ymin_get(const BoxPack *box)
Definition boxpack_2d.c:102
void BLI_box_pack_2d(BoxPack *boxarray, const uint len, const bool sort_boxes, float *r_tot_x, float *r_tot_y)
Definition boxpack_2d.c:271
static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
Definition boxpack_2d.c:229
#define CORNERFLAGS
Definition boxpack_2d.c:75
#define A
static void box_xmin_set(BoxPack *box, const float f)
Definition boxpack_2d.c:130
static void box_ymin_set(BoxPack *box, const float f)
Definition boxpack_2d.c:144
static float max_ff(const float a, const float b)
Definition boxpack_2d.c:180
static void box_ymax_set(BoxPack *box, const float f)
Definition boxpack_2d.c:151
static float box_xmin_get(const BoxPack *box)
Definition boxpack_2d.c:92
BLI_INLINE int quad_flag(uint q)
Definition boxpack_2d.c:77
#define BLF
Definition boxpack_2d.c:71
#define BRF
Definition boxpack_2d.c:74
#define EPSILON_BIAS
Definition boxpack_2d.c:69
static float box_area(const BoxPack *box)
Definition boxpack_2d.c:164
static void box_xmax_set(BoxPack *box, const float f)
Definition boxpack_2d.c:137
#define BL
Definition boxpack_2d.c:83
#define EPSILON_MERGE
Definition boxpack_2d.c:67
#define BR
Definition boxpack_2d.c:86
local_group_size(16, 16) .push_constant(Type b
#define NULL
#define fabsf(x)
int len
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
struct BoxVert * v[4]
BoxPack * blb
Definition boxpack_2d.c:47
BoxPack * tlb
Definition boxpack_2d.c:49
float x
Definition boxpack_2d.c:38
float y
Definition boxpack_2d.c:39
int free
Definition boxpack_2d.c:41
BoxPack * trb
Definition boxpack_2d.c:46
int _pad2
Definition boxpack_2d.c:57
float bias
Definition boxpack_2d.c:56
uint index
Definition boxpack_2d.c:44
BoxPack * brb
Definition boxpack_2d.c:48
BoxPack * isect_cache[4]
Definition boxpack_2d.c:53
uint used
Definition boxpack_2d.c:42
uint _pad
Definition boxpack_2d.c:43
BoxVert * vertarray
Definition boxpack_2d.c:225