Ylva And Malin
stb_rect_pack.h
Go to the documentation of this file.
1 
2 // stb_rect_pack.h - v0.11 - public domain - rectangle packing
3 // Sean Barrett 2014
4 //
5 // Useful for e.g. packing rectangular textures into an atlas.
6 // Does not do rotation.
7 //
8 // Not necessarily the awesomest packing method, but better than
9 // the totally naive one in stb_truetype (which is primarily what
10 // this is meant to replace).
11 //
12 // Has only had a few tests run, may have issues.
13 //
14 // More docs to come.
15 //
16 // No memory allocations; uses qsort() and assert() from stdlib.
17 // Can override those by defining STBRP_SORT and STBRP_ASSERT.
18 //
19 // This library currently uses the Skyline Bottom-Left algorithm.
20 //
21 // Please note: better rectangle packers are welcome! Please
22 // implement them to the same API, but with a different init
23 // function.
24 //
25 // Credits
26 //
27 // Library
28 // Sean Barrett
29 // Minor features
30 // Martins Mozeiko
31 // github:IntellectualKitty
32 //
33 // Bugfixes / warning fixes
34 // Jeremy Jaussaud
35 //
36 // Version history:
37 //
38 // 0.11 (2017-03-03) return packing success/fail result
39 // 0.10 (2016-10-25) remove cast-away-const to avoid warnings
40 // 0.09 (2016-08-27) fix compiler warnings
41 // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
42 // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
43 // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
44 // 0.05: added STBRP_ASSERT to allow replacing assert
45 // 0.04: fixed minor bug in STBRP_LARGE_RECTS support
46 // 0.01: initial release
47 //
48 // LICENSE
49 //
50 // See end of file for license information.
51 
53 //
54 // INCLUDE SECTION
55 //
56 
57 #ifndef STB_INCLUDE_STB_RECT_PACK_H
58 #define STB_INCLUDE_STB_RECT_PACK_H
59 
60 #define STB_RECT_PACK_VERSION 1
61 
62 #ifdef STBRP_STATIC
63 #define STBRP_DEF static
64 #else
65 #define STBRP_DEF extern
66 #endif
67 
68 #ifdef __cplusplus
69 extern "C" {
70 #endif
71 
73 typedef struct stbrp_node stbrp_node;
74 typedef struct stbrp_rect stbrp_rect;
75 
76 #ifdef STBRP_LARGE_RECTS
77 typedef int stbrp_coord;
78 #else
79 typedef unsigned short stbrp_coord;
80 #endif
81 
82 STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
83 // Assign packed locations to rectangles. The rectangles are of type
84 // 'stbrp_rect' defined below, stored in the array 'rects', and there
85 // are 'num_rects' many of them.
86 //
87 // Rectangles which are successfully packed have the 'was_packed' flag
88 // set to a non-zero value and 'x' and 'y' store the minimum location
89 // on each axis (i.e. bottom-left in cartesian coordinates, top-left
90 // if you imagine y increasing downwards). Rectangles which do not fit
91 // have the 'was_packed' flag set to 0.
92 //
93 // You should not try to access the 'rects' array from another thread
94 // while this function is running, as the function temporarily reorders
95 // the array while it executes.
96 //
97 // To pack into another rectangle, you need to call stbrp_init_target
98 // again. To continue packing into the same rectangle, you can call
99 // this function again. Calling this multiple times with multiple rect
100 // arrays will probably produce worse packing results than calling it
101 // a single time with the full rectangle array, but the option is
102 // available.
103 //
104 // The function returns 1 if all of the rectangles were successfully
105 // packed and 0 otherwise.
106 
108 {
109  // reserved for your use:
110  int id;
111 
112  // input:
113  stbrp_coord w, h;
114 
115  // output:
116  stbrp_coord x, y;
117  int was_packed; // non-zero if valid packing
118 
119 }; // 16 bytes, nominally
120 
121 
122 STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
123 // Initialize a rectangle packer to:
124 // pack a rectangle that is 'width' by 'height' in dimensions
125 // using temporary storage provided by the array 'nodes', which is 'num_nodes' long
126 //
127 // You must call this function every time you start packing into a new target.
128 //
129 // There is no "shutdown" function. The 'nodes' memory must stay valid for
130 // the following stbrp_pack_rects() call (or calls), but can be freed after
131 // the call (or calls) finish.
132 //
133 // Note: to guarantee best results, either:
134 // 1. make sure 'num_nodes' >= 'width'
135 // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
136 //
137 // If you don't do either of the above things, widths will be quantized to multiples
138 // of small integers to guarantee the algorithm doesn't run out of temporary storage.
139 //
140 // If you do #2, then the non-quantized algorithm will be used, but the algorithm
141 // may run out of temporary storage and be unable to pack some rectangles.
142 
143 STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
144 // Optionally call this function after init but before doing any packing to
145 // change the handling of the out-of-temp-memory scenario, described above.
146 // If you call init again, this will be reset to the default (false).
147 
148 
149 STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
150 // Optionally select which packing heuristic the library should use. Different
151 // heuristics will produce better/worse results for different data sets.
152 // If you call init again, this will be reset to the default.
153 
154 enum
155 {
159 };
160 
161 
163 //
164 // the details of the following structures don't matter to you, but they must
165 // be visible so you can handle the memory allocations for them
166 
168 {
169  stbrp_coord x,y;
171 };
172 
174 {
175  int width;
176  int height;
177  int align;
183  stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
184 };
185 
186 #ifdef __cplusplus
187 }
188 #endif
189 
190 #endif
191 
193 //
194 // IMPLEMENTATION SECTION
195 //
196 
197 #ifdef STB_RECT_PACK_IMPLEMENTATION
198 #ifndef STBRP_SORT
199 #include <stdlib.h>
200 #define STBRP_SORT qsort
201 #endif
202 
203 #ifndef STBRP_ASSERT
204 #include <assert.h>
205 #define STBRP_ASSERT assert
206 #endif
207 
208 #ifdef _MSC_VER
209 #define STBRP__NOTUSED(v) (void)(v)
210 #define STBRP__CDECL __cdecl
211 #else
212 #define STBRP__NOTUSED(v) (void)sizeof(v)
213 #define STBRP__CDECL
214 #endif
215 
216 enum
217 {
218  STBRP__INIT_skyline = 1
219 };
220 
221 STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
222 {
223  switch (context->init_mode) {
224  case STBRP__INIT_skyline:
226  context->heuristic = heuristic;
227  break;
228  default:
229  STBRP_ASSERT(0);
230  }
231 }
232 
233 STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
234 {
235  if (allow_out_of_mem)
236  // if it's ok to run out of memory, then don't bother aligning them;
237  // this gives better packing, but may fail due to OOM (even though
238  // the rectangles easily fit). @TODO a smarter approach would be to only
239  // quantize once we've hit OOM, then we could get rid of this parameter.
240  context->align = 1;
241  else {
242  // if it's not ok to run out of memory, then quantize the widths
243  // so that num_nodes is always enough nodes.
244  //
245  // I.e. num_nodes * align >= width
246  // align >= width / num_nodes
247  // align = ceil(width/num_nodes)
248 
249  context->align = (context->width + context->num_nodes-1) / context->num_nodes;
250  }
251 }
252 
253 STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
254 {
255  int i;
256 #ifndef STBRP_LARGE_RECTS
257  STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
258 #endif
259 
260  for (i=0; i < num_nodes-1; ++i)
261  nodes[i].next = &nodes[i+1];
262  nodes[i].next = NULL;
263  context->init_mode = STBRP__INIT_skyline;
265  context->free_head = &nodes[0];
266  context->active_head = &context->extra[0];
267  context->width = width;
268  context->height = height;
269  context->num_nodes = num_nodes;
270  stbrp_setup_allow_out_of_mem(context, 0);
271 
272  // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
273  context->extra[0].x = 0;
274  context->extra[0].y = 0;
275  context->extra[0].next = &context->extra[1];
276  context->extra[1].x = (stbrp_coord) width;
277 #ifdef STBRP_LARGE_RECTS
278  context->extra[1].y = (1<<30);
279 #else
280  context->extra[1].y = 65535;
281 #endif
282  context->extra[1].next = NULL;
283 }
284 
285 // find minimum y position if it starts at x1
286 static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
287 {
288  stbrp_node *node = first;
289  int x1 = x0 + width;
290  int min_y, visited_width, waste_area;
291 
292  STBRP__NOTUSED(c);
293 
294  STBRP_ASSERT(first->x <= x0);
295 
296  #if 0
297  // skip in case we're past the node
298  while (node->next->x <= x0)
299  ++node;
300  #else
301  STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
302  #endif
303 
304  STBRP_ASSERT(node->x <= x0);
305 
306  min_y = 0;
307  waste_area = 0;
308  visited_width = 0;
309  while (node->x < x1) {
310  if (node->y > min_y) {
311  // raise min_y higher.
312  // we've accounted for all waste up to min_y,
313  // but we'll now add more waste for everything we've visted
314  waste_area += visited_width * (node->y - min_y);
315  min_y = node->y;
316  // the first time through, visited_width might be reduced
317  if (node->x < x0)
318  visited_width += node->next->x - x0;
319  else
320  visited_width += node->next->x - node->x;
321  } else {
322  // add waste area
323  int under_width = node->next->x - node->x;
324  if (under_width + visited_width > width)
325  under_width = width - visited_width;
326  waste_area += under_width * (min_y - node->y);
327  visited_width += under_width;
328  }
329  node = node->next;
330  }
331 
332  *pwaste = waste_area;
333  return min_y;
334 }
335 
336 typedef struct
337 {
338  int x,y;
339  stbrp_node **prev_link;
340 } stbrp__findresult;
341 
342 static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
343 {
344  int best_waste = (1<<30), best_x, best_y = (1 << 30);
345  stbrp__findresult fr;
346  stbrp_node **prev, *node, *tail, **best = NULL;
347 
348  // align to multiple of c->align
349  width = (width + c->align - 1);
350  width -= width % c->align;
351  STBRP_ASSERT(width % c->align == 0);
352 
353  node = c->active_head;
354  prev = &c->active_head;
355  while (node->x + width <= c->width) {
356  int y,waste;
357  y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
358  if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
359  // bottom left
360  if (y < best_y) {
361  best_y = y;
362  best = prev;
363  }
364  } else {
365  // best-fit
366  if (y + height <= c->height) {
367  // can only use it if it first vertically
368  if (y < best_y || (y == best_y && waste < best_waste)) {
369  best_y = y;
370  best_waste = waste;
371  best = prev;
372  }
373  }
374  }
375  prev = &node->next;
376  node = node->next;
377  }
378 
379  best_x = (best == NULL) ? 0 : (*best)->x;
380 
381  // if doing best-fit (BF), we also have to try aligning right edge to each node position
382  //
383  // e.g, if fitting
384  //
385  // ____________________
386  // |____________________|
387  //
388  // into
389  //
390  // | |
391  // | ____________|
392  // |____________|
393  //
394  // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
395  //
396  // This makes BF take about 2x the time
397 
399  tail = c->active_head;
400  node = c->active_head;
401  prev = &c->active_head;
402  // find first node that's admissible
403  while (tail->x < width)
404  tail = tail->next;
405  while (tail) {
406  int xpos = tail->x - width;
407  int y,waste;
408  STBRP_ASSERT(xpos >= 0);
409  // find the left position that matches this
410  while (node->next->x <= xpos) {
411  prev = &node->next;
412  node = node->next;
413  }
414  STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
415  y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
416  if (y + height < c->height) {
417  if (y <= best_y) {
418  if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
419  best_x = xpos;
420  STBRP_ASSERT(y <= best_y);
421  best_y = y;
422  best_waste = waste;
423  best = prev;
424  }
425  }
426  }
427  tail = tail->next;
428  }
429  }
430 
431  fr.prev_link = best;
432  fr.x = best_x;
433  fr.y = best_y;
434  return fr;
435 }
436 
437 static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
438 {
439  // find best position according to heuristic
440  stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
441  stbrp_node *node, *cur;
442 
443  // bail if:
444  // 1. it failed
445  // 2. the best node doesn't fit (we don't always check this)
446  // 3. we're out of memory
447  if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
448  res.prev_link = NULL;
449  return res;
450  }
451 
452  // on success, create new node
453  node = context->free_head;
454  node->x = (stbrp_coord) res.x;
455  node->y = (stbrp_coord) (res.y + height);
456 
457  context->free_head = node->next;
458 
459  // insert the new node into the right starting point, and
460  // let 'cur' point to the remaining nodes needing to be
461  // stiched back in
462 
463  cur = *res.prev_link;
464  if (cur->x < res.x) {
465  // preserve the existing one, so start testing with the next one
466  stbrp_node *next = cur->next;
467  cur->next = node;
468  cur = next;
469  } else {
470  *res.prev_link = node;
471  }
472 
473  // from here, traverse cur and free the nodes, until we get to one
474  // that shouldn't be freed
475  while (cur->next && cur->next->x <= res.x + width) {
476  stbrp_node *next = cur->next;
477  // move the current node to the free list
478  cur->next = context->free_head;
479  context->free_head = cur;
480  cur = next;
481  }
482 
483  // stitch the list back in
484  node->next = cur;
485 
486  if (cur->x < res.x + width)
487  cur->x = (stbrp_coord) (res.x + width);
488 
489 #ifdef _DEBUG
490  cur = context->active_head;
491  while (cur->x < context->width) {
492  STBRP_ASSERT(cur->x < cur->next->x);
493  cur = cur->next;
494  }
495  STBRP_ASSERT(cur->next == NULL);
496 
497  {
498  int count=0;
499  cur = context->active_head;
500  while (cur) {
501  cur = cur->next;
502  ++count;
503  }
504  cur = context->free_head;
505  while (cur) {
506  cur = cur->next;
507  ++count;
508  }
509  STBRP_ASSERT(count == context->num_nodes+2);
510  }
511 #endif
512 
513  return res;
514 }
515 
516 static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
517 {
518  const stbrp_rect *p = (const stbrp_rect *) a;
519  const stbrp_rect *q = (const stbrp_rect *) b;
520  if (p->h > q->h)
521  return -1;
522  if (p->h < q->h)
523  return 1;
524  return (p->w > q->w) ? -1 : (p->w < q->w);
525 }
526 
527 static int STBRP__CDECL rect_original_order(const void *a, const void *b)
528 {
529  const stbrp_rect *p = (const stbrp_rect *) a;
530  const stbrp_rect *q = (const stbrp_rect *) b;
531  return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
532 }
533 
534 #ifdef STBRP_LARGE_RECTS
535 #define STBRP__MAXVAL 0xffffffff
536 #else
537 #define STBRP__MAXVAL 0xffff
538 #endif
539 
540 STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
541 {
542  int i, all_rects_packed = 1;
543 
544  // we use the 'was_packed' field internally to allow sorting/unsorting
545  for (i=0; i < num_rects; ++i) {
546  rects[i].was_packed = i;
547  #ifndef STBRP_LARGE_RECTS
548  STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
549  #endif
550  }
551 
552  // sort according to heuristic
553  STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
554 
555  for (i=0; i < num_rects; ++i) {
556  if (rects[i].w == 0 || rects[i].h == 0) {
557  rects[i].x = rects[i].y = 0; // empty rect needs no space
558  } else {
559  stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
560  if (fr.prev_link) {
561  rects[i].x = (stbrp_coord) fr.x;
562  rects[i].y = (stbrp_coord) fr.y;
563  } else {
564  rects[i].x = rects[i].y = STBRP__MAXVAL;
565  }
566  }
567  }
568 
569  // unsort
570  STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
571 
572  // set was_packed flags and all_rects_packed status
573  for (i=0; i < num_rects; ++i) {
574  rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
575  if (!rects[i].was_packed)
576  all_rects_packed = 0;
577  }
578 
579  // return the all_rects_packed status
580  return all_rects_packed;
581 }
582 #endif
583 
584 /*
585 ------------------------------------------------------------------------------
586 This software is available under 2 licenses -- choose whichever you prefer.
587 ------------------------------------------------------------------------------
588 ALTERNATIVE A - MIT License
589 Copyright (c) 2017 Sean Barrett
590 Permission is hereby granted, free of charge, to any person obtaining a copy of
591 this software and associated documentation files (the "Software"), to deal in
592 the Software without restriction, including without limitation the rights to
593 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
594 of the Software, and to permit persons to whom the Software is furnished to do
595 so, subject to the following conditions:
596 The above copyright notice and this permission notice shall be included in all
597 copies or substantial portions of the Software.
598 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
599 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
600 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
601 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
602 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
603 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
604 SOFTWARE.
605 ------------------------------------------------------------------------------
606 ALTERNATIVE B - Public Domain (www.unlicense.org)
607 This is free and unencumbered software released into the public domain.
608 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
609 software, either in source code form or as a compiled binary, for any purpose,
610 commercial or non-commercial, and by any means.
611 In jurisdictions that recognize copyright laws, the author or authors of this
612 software dedicate any and all copyright interest in the software to the public
613 domain. We make this dedication for the benefit of the public at large and to
614 the detriment of our heirs and successors. We intend this dedication to be an
615 overt act of relinquishment in perpetuity of all present and future rights to
616 this software under copyright law.
617 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
618 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
619 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
620 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
621 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
622 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
623 ------------------------------------------------------------------------------
624 */
stbrp_node extra[2]
Definition: stb_rect_pack.h:183
int int int int height
Definition: wglext.h:61
int height
Definition: stb_rect_pack.h:176
Definition: stb_rect_pack.h:107
Definition: stb_rect_pack.h:167
int int int width
Definition: wglext.h:61
#define STBRP_DEF
Definition: stb_rect_pack.h:65
unsigned short stbrp_coord
Definition: stb_rect_pack.h:79
stbrp_coord y
Definition: stb_rect_pack.h:169
void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
stbrp_coord y
Definition: stb_rect_pack.h:116
#define STBRP_ASSERT(x)
Definition: imgui_draw.cpp:101
int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
Definition: stb_rect_pack.h:157
int was_packed
Definition: stb_rect_pack.h:117
stbrp_node * next
Definition: stb_rect_pack.h:170
stbrp_coord x
Definition: stb_rect_pack.h:116
stbrp_node * free_head
Definition: stb_rect_pack.h:182
int align
Definition: stb_rect_pack.h:177
int init_mode
Definition: stb_rect_pack.h:178
Definition: stb_rect_pack.h:156
Definition: stb_rect_pack.h:158
stbrp_coord w
Definition: stb_rect_pack.h:113
int heuristic
Definition: stb_rect_pack.h:179
stbrp_node * active_head
Definition: stb_rect_pack.h:181
Definition: stb_rect_pack.h:173
int width
Definition: stb_rect_pack.h:175
stbrp_coord x
Definition: stb_rect_pack.h:169
stbrp_coord h
Definition: stb_rect_pack.h:113
int num_nodes
Definition: stb_rect_pack.h:180
int id
Definition: stb_rect_pack.h:110
void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
const HANDLE const LPVOID const DWORD UINT count
Definition: wglext.h:590