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