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