19f464c52Smaya// [DEAR IMGUI]
29f464c52Smaya// This is a slightly modified version of stb_rect_pack.h 0.99.
39f464c52Smaya// Those changes would need to be pushed into nothings/stb:
49f464c52Smaya// - Added STBRP__CDECL
59f464c52Smaya// Grep for [DEAR IMGUI] to find the changes.
69f464c52Smaya
79f464c52Smaya// stb_rect_pack.h - v0.99 - public domain - rectangle packing
89f464c52Smaya// Sean Barrett 2014
99f464c52Smaya//
109f464c52Smaya// Useful for e.g. packing rectangular textures into an atlas.
119f464c52Smaya// Does not do rotation.
129f464c52Smaya//
139f464c52Smaya// Not necessarily the awesomest packing method, but better than
149f464c52Smaya// the totally naive one in stb_truetype (which is primarily what
159f464c52Smaya// this is meant to replace).
169f464c52Smaya//
179f464c52Smaya// Has only had a few tests run, may have issues.
189f464c52Smaya//
199f464c52Smaya// More docs to come.
209f464c52Smaya//
219f464c52Smaya// No memory allocations; uses qsort() and assert() from stdlib.
229f464c52Smaya// Can override those by defining STBRP_SORT and STBRP_ASSERT.
239f464c52Smaya//
249f464c52Smaya// This library currently uses the Skyline Bottom-Left algorithm.
259f464c52Smaya//
269f464c52Smaya// Please note: better rectangle packers are welcome! Please
279f464c52Smaya// implement them to the same API, but with a different init
289f464c52Smaya// function.
299f464c52Smaya//
309f464c52Smaya// Credits
319f464c52Smaya//
329f464c52Smaya//  Library
339f464c52Smaya//    Sean Barrett
349f464c52Smaya//  Minor features
359f464c52Smaya//    Martins Mozeiko
369f464c52Smaya//    github:IntellectualKitty
379f464c52Smaya//
389f464c52Smaya//  Bugfixes / warning fixes
399f464c52Smaya//    Jeremy Jaussaud
409f464c52Smaya//
419f464c52Smaya// Version history:
429f464c52Smaya//
439f464c52Smaya//     0.99  (2019-02-07)  warning fixes
449f464c52Smaya//     0.11  (2017-03-03)  return packing success/fail result
459f464c52Smaya//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings
469f464c52Smaya//     0.09  (2016-08-27)  fix compiler warnings
479f464c52Smaya//     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0)
489f464c52Smaya//     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0)
499f464c52Smaya//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort
509f464c52Smaya//     0.05:  added STBRP_ASSERT to allow replacing assert
519f464c52Smaya//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support
529f464c52Smaya//     0.01:  initial release
539f464c52Smaya//
549f464c52Smaya// LICENSE
559f464c52Smaya//
569f464c52Smaya//   See end of file for license information.
579f464c52Smaya
589f464c52Smaya//////////////////////////////////////////////////////////////////////////////
599f464c52Smaya//
609f464c52Smaya//       INCLUDE SECTION
619f464c52Smaya//
629f464c52Smaya
639f464c52Smaya#ifndef STB_INCLUDE_STB_RECT_PACK_H
649f464c52Smaya#define STB_INCLUDE_STB_RECT_PACK_H
659f464c52Smaya
669f464c52Smaya#define STB_RECT_PACK_VERSION  1
679f464c52Smaya
689f464c52Smaya#ifdef STBRP_STATIC
699f464c52Smaya#define STBRP_DEF static
709f464c52Smaya#else
719f464c52Smaya#define STBRP_DEF extern
729f464c52Smaya#endif
739f464c52Smaya
749f464c52Smaya#ifdef __cplusplus
759f464c52Smayaextern "C" {
769f464c52Smaya#endif
779f464c52Smaya
789f464c52Smayatypedef struct stbrp_context stbrp_context;
799f464c52Smayatypedef struct stbrp_node    stbrp_node;
809f464c52Smayatypedef struct stbrp_rect    stbrp_rect;
819f464c52Smaya
829f464c52Smaya#ifdef STBRP_LARGE_RECTS
839f464c52Smayatypedef int            stbrp_coord;
849f464c52Smaya#else
859f464c52Smayatypedef unsigned short stbrp_coord;
869f464c52Smaya#endif
879f464c52Smaya
889f464c52SmayaSTBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
899f464c52Smaya// Assign packed locations to rectangles. The rectangles are of type
909f464c52Smaya// 'stbrp_rect' defined below, stored in the array 'rects', and there
919f464c52Smaya// are 'num_rects' many of them.
929f464c52Smaya//
939f464c52Smaya// Rectangles which are successfully packed have the 'was_packed' flag
949f464c52Smaya// set to a non-zero value and 'x' and 'y' store the minimum location
959f464c52Smaya// on each axis (i.e. bottom-left in cartesian coordinates, top-left
969f464c52Smaya// if you imagine y increasing downwards). Rectangles which do not fit
979f464c52Smaya// have the 'was_packed' flag set to 0.
989f464c52Smaya//
999f464c52Smaya// You should not try to access the 'rects' array from another thread
1009f464c52Smaya// while this function is running, as the function temporarily reorders
1019f464c52Smaya// the array while it executes.
1029f464c52Smaya//
1039f464c52Smaya// To pack into another rectangle, you need to call stbrp_init_target
1049f464c52Smaya// again. To continue packing into the same rectangle, you can call
1059f464c52Smaya// this function again. Calling this multiple times with multiple rect
1069f464c52Smaya// arrays will probably produce worse packing results than calling it
1079f464c52Smaya// a single time with the full rectangle array, but the option is
1089f464c52Smaya// available.
1099f464c52Smaya//
1109f464c52Smaya// The function returns 1 if all of the rectangles were successfully
1119f464c52Smaya// packed and 0 otherwise.
1129f464c52Smaya
1139f464c52Smayastruct stbrp_rect
1149f464c52Smaya{
1159f464c52Smaya   // reserved for your use:
1169f464c52Smaya   int            id;
1179f464c52Smaya
1189f464c52Smaya   // input:
1199f464c52Smaya   stbrp_coord    w, h;
1209f464c52Smaya
1219f464c52Smaya   // output:
1229f464c52Smaya   stbrp_coord    x, y;
1239f464c52Smaya   int            was_packed;  // non-zero if valid packing
1249f464c52Smaya
1259f464c52Smaya}; // 16 bytes, nominally
1269f464c52Smaya
1279f464c52Smaya
1289f464c52SmayaSTBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
1299f464c52Smaya// Initialize a rectangle packer to:
1309f464c52Smaya//    pack a rectangle that is 'width' by 'height' in dimensions
1319f464c52Smaya//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long
1329f464c52Smaya//
1339f464c52Smaya// You must call this function every time you start packing into a new target.
1349f464c52Smaya//
1359f464c52Smaya// There is no "shutdown" function. The 'nodes' memory must stay valid for
1369f464c52Smaya// the following stbrp_pack_rects() call (or calls), but can be freed after
1379f464c52Smaya// the call (or calls) finish.
1389f464c52Smaya//
1399f464c52Smaya// Note: to guarantee best results, either:
1409f464c52Smaya//       1. make sure 'num_nodes' >= 'width'
1419f464c52Smaya//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
1429f464c52Smaya//
1439f464c52Smaya// If you don't do either of the above things, widths will be quantized to multiples
1449f464c52Smaya// of small integers to guarantee the algorithm doesn't run out of temporary storage.
1459f464c52Smaya//
1469f464c52Smaya// If you do #2, then the non-quantized algorithm will be used, but the algorithm
1479f464c52Smaya// may run out of temporary storage and be unable to pack some rectangles.
1489f464c52Smaya
1499f464c52SmayaSTBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
1509f464c52Smaya// Optionally call this function after init but before doing any packing to
1519f464c52Smaya// change the handling of the out-of-temp-memory scenario, described above.
1529f464c52Smaya// If you call init again, this will be reset to the default (false).
1539f464c52Smaya
1549f464c52Smaya
1559f464c52SmayaSTBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
1569f464c52Smaya// Optionally select which packing heuristic the library should use. Different
1579f464c52Smaya// heuristics will produce better/worse results for different data sets.
1589f464c52Smaya// If you call init again, this will be reset to the default.
1599f464c52Smaya
1609f464c52Smayaenum
1619f464c52Smaya{
1629f464c52Smaya   STBRP_HEURISTIC_Skyline_default=0,
1639f464c52Smaya   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
1649f464c52Smaya   STBRP_HEURISTIC_Skyline_BF_sortHeight
1659f464c52Smaya};
1669f464c52Smaya
1679f464c52Smaya
1689f464c52Smaya//////////////////////////////////////////////////////////////////////////////
1699f464c52Smaya//
1709f464c52Smaya// the details of the following structures don't matter to you, but they must
1719f464c52Smaya// be visible so you can handle the memory allocations for them
1729f464c52Smaya
1739f464c52Smayastruct stbrp_node
1749f464c52Smaya{
1759f464c52Smaya   stbrp_coord  x,y;
1769f464c52Smaya   stbrp_node  *next;
1779f464c52Smaya};
1789f464c52Smaya
1799f464c52Smayastruct stbrp_context
1809f464c52Smaya{
1819f464c52Smaya   int width;
1829f464c52Smaya   int height;
1839f464c52Smaya   int align;
1849f464c52Smaya   int init_mode;
1859f464c52Smaya   int heuristic;
1869f464c52Smaya   int num_nodes;
1879f464c52Smaya   stbrp_node *active_head;
1889f464c52Smaya   stbrp_node *free_head;
1899f464c52Smaya   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
1909f464c52Smaya};
1919f464c52Smaya
1929f464c52Smaya#ifdef __cplusplus
1939f464c52Smaya}
1949f464c52Smaya#endif
1959f464c52Smaya
1969f464c52Smaya#endif
1979f464c52Smaya
1989f464c52Smaya//////////////////////////////////////////////////////////////////////////////
1999f464c52Smaya//
2009f464c52Smaya//     IMPLEMENTATION SECTION
2019f464c52Smaya//
2029f464c52Smaya
2039f464c52Smaya#ifdef STB_RECT_PACK_IMPLEMENTATION
2049f464c52Smaya#ifndef STBRP_SORT
2059f464c52Smaya#include <stdlib.h>
2069f464c52Smaya#define STBRP_SORT qsort
2079f464c52Smaya#endif
2089f464c52Smaya
2099f464c52Smaya#ifndef STBRP_ASSERT
2109f464c52Smaya#include <assert.h>
2119f464c52Smaya#define STBRP_ASSERT assert
2129f464c52Smaya#endif
2139f464c52Smaya
2149f464c52Smaya// [DEAR IMGUI] Added STBRP__CDECL
2159f464c52Smaya#ifdef _MSC_VER
2169f464c52Smaya#define STBRP__NOTUSED(v)  (void)(v)
2179f464c52Smaya#define STBRP__CDECL __cdecl
2189f464c52Smaya#else
2199f464c52Smaya#define STBRP__NOTUSED(v)  (void)sizeof(v)
2209f464c52Smaya#define STBRP__CDECL
2219f464c52Smaya#endif
2229f464c52Smaya
2239f464c52Smayaenum
2249f464c52Smaya{
2259f464c52Smaya   STBRP__INIT_skyline = 1
2269f464c52Smaya};
2279f464c52Smaya
2289f464c52SmayaSTBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
2299f464c52Smaya{
2309f464c52Smaya   switch (context->init_mode) {
2319f464c52Smaya      case STBRP__INIT_skyline:
2329f464c52Smaya         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
2339f464c52Smaya         context->heuristic = heuristic;
2349f464c52Smaya         break;
2359f464c52Smaya      default:
2369f464c52Smaya         STBRP_ASSERT(0);
2379f464c52Smaya   }
2389f464c52Smaya}
2399f464c52Smaya
2409f464c52SmayaSTBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
2419f464c52Smaya{
2429f464c52Smaya   if (allow_out_of_mem)
2439f464c52Smaya      // if it's ok to run out of memory, then don't bother aligning them;
2449f464c52Smaya      // this gives better packing, but may fail due to OOM (even though
2459f464c52Smaya      // the rectangles easily fit). @TODO a smarter approach would be to only
2469f464c52Smaya      // quantize once we've hit OOM, then we could get rid of this parameter.
2479f464c52Smaya      context->align = 1;
2489f464c52Smaya   else {
2499f464c52Smaya      // if it's not ok to run out of memory, then quantize the widths
2509f464c52Smaya      // so that num_nodes is always enough nodes.
2519f464c52Smaya      //
2529f464c52Smaya      // I.e. num_nodes * align >= width
2539f464c52Smaya      //                  align >= width / num_nodes
2549f464c52Smaya      //                  align = ceil(width/num_nodes)
2559f464c52Smaya
2569f464c52Smaya      context->align = (context->width + context->num_nodes-1) / context->num_nodes;
2579f464c52Smaya   }
2589f464c52Smaya}
2599f464c52Smaya
2609f464c52SmayaSTBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
2619f464c52Smaya{
2629f464c52Smaya   int i;
2639f464c52Smaya#ifndef STBRP_LARGE_RECTS
2649f464c52Smaya   STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
2659f464c52Smaya#endif
2669f464c52Smaya
2679f464c52Smaya   for (i=0; i < num_nodes-1; ++i)
2689f464c52Smaya      nodes[i].next = &nodes[i+1];
2699f464c52Smaya   nodes[i].next = NULL;
2709f464c52Smaya   context->init_mode = STBRP__INIT_skyline;
2719f464c52Smaya   context->heuristic = STBRP_HEURISTIC_Skyline_default;
2729f464c52Smaya   context->free_head = &nodes[0];
2739f464c52Smaya   context->active_head = &context->extra[0];
2749f464c52Smaya   context->width = width;
2759f464c52Smaya   context->height = height;
2769f464c52Smaya   context->num_nodes = num_nodes;
2779f464c52Smaya   stbrp_setup_allow_out_of_mem(context, 0);
2789f464c52Smaya
2799f464c52Smaya   // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
2809f464c52Smaya   context->extra[0].x = 0;
2819f464c52Smaya   context->extra[0].y = 0;
2829f464c52Smaya   context->extra[0].next = &context->extra[1];
2839f464c52Smaya   context->extra[1].x = (stbrp_coord) width;
2849f464c52Smaya#ifdef STBRP_LARGE_RECTS
2859f464c52Smaya   context->extra[1].y = (1<<30);
2869f464c52Smaya#else
2879f464c52Smaya   context->extra[1].y = 65535;
2889f464c52Smaya#endif
2899f464c52Smaya   context->extra[1].next = NULL;
2909f464c52Smaya}
2919f464c52Smaya
2929f464c52Smaya// find minimum y position if it starts at x1
2939f464c52Smayastatic int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
2949f464c52Smaya{
2959f464c52Smaya   stbrp_node *node = first;
2969f464c52Smaya   int x1 = x0 + width;
2979f464c52Smaya   int min_y, visited_width, waste_area;
2989f464c52Smaya
2999f464c52Smaya   STBRP__NOTUSED(c);
3009f464c52Smaya
3019f464c52Smaya   STBRP_ASSERT(first->x <= x0);
3029f464c52Smaya
3039f464c52Smaya   #if 0
3049f464c52Smaya   // skip in case we're past the node
3059f464c52Smaya   while (node->next->x <= x0)
3069f464c52Smaya      ++node;
3079f464c52Smaya   #else
3089f464c52Smaya   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
3099f464c52Smaya   #endif
3109f464c52Smaya
3119f464c52Smaya   STBRP_ASSERT(node->x <= x0);
3129f464c52Smaya
3139f464c52Smaya   min_y = 0;
3149f464c52Smaya   waste_area = 0;
3159f464c52Smaya   visited_width = 0;
3169f464c52Smaya   while (node->x < x1) {
3179f464c52Smaya      if (node->y > min_y) {
3189f464c52Smaya         // raise min_y higher.
3199f464c52Smaya         // we've accounted for all waste up to min_y,
3209f464c52Smaya         // but we'll now add more waste for everything we've visted
3219f464c52Smaya         waste_area += visited_width * (node->y - min_y);
3229f464c52Smaya         min_y = node->y;
3239f464c52Smaya         // the first time through, visited_width might be reduced
3249f464c52Smaya         if (node->x < x0)
3259f464c52Smaya            visited_width += node->next->x - x0;
3269f464c52Smaya         else
3279f464c52Smaya            visited_width += node->next->x - node->x;
3289f464c52Smaya      } else {
3299f464c52Smaya         // add waste area
3309f464c52Smaya         int under_width = node->next->x - node->x;
3319f464c52Smaya         if (under_width + visited_width > width)
3329f464c52Smaya            under_width = width - visited_width;
3339f464c52Smaya         waste_area += under_width * (min_y - node->y);
3349f464c52Smaya         visited_width += under_width;
3359f464c52Smaya      }
3369f464c52Smaya      node = node->next;
3379f464c52Smaya   }
3389f464c52Smaya
3399f464c52Smaya   *pwaste = waste_area;
3409f464c52Smaya   return min_y;
3419f464c52Smaya}
3429f464c52Smaya
3439f464c52Smayatypedef struct
3449f464c52Smaya{
3459f464c52Smaya   int x,y;
3469f464c52Smaya   stbrp_node **prev_link;
3479f464c52Smaya} stbrp__findresult;
3489f464c52Smaya
3499f464c52Smayastatic stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
3509f464c52Smaya{
3519f464c52Smaya   int best_waste = (1<<30), best_x, best_y = (1 << 30);
3529f464c52Smaya   stbrp__findresult fr;
3539f464c52Smaya   stbrp_node **prev, *node, *tail, **best = NULL;
3549f464c52Smaya
3559f464c52Smaya   // align to multiple of c->align
3569f464c52Smaya   width = (width + c->align - 1);
3579f464c52Smaya   width -= width % c->align;
3589f464c52Smaya   STBRP_ASSERT(width % c->align == 0);
3599f464c52Smaya
3609f464c52Smaya   node = c->active_head;
3619f464c52Smaya   prev = &c->active_head;
3629f464c52Smaya   while (node->x + width <= c->width) {
3639f464c52Smaya      int y,waste;
3649f464c52Smaya      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
3659f464c52Smaya      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
3669f464c52Smaya         // bottom left
3679f464c52Smaya         if (y < best_y) {
3689f464c52Smaya            best_y = y;
3699f464c52Smaya            best = prev;
3709f464c52Smaya         }
3719f464c52Smaya      } else {
3729f464c52Smaya         // best-fit
3739f464c52Smaya         if (y + height <= c->height) {
3749f464c52Smaya            // can only use it if it first vertically
3759f464c52Smaya            if (y < best_y || (y == best_y && waste < best_waste)) {
3769f464c52Smaya               best_y = y;
3779f464c52Smaya               best_waste = waste;
3789f464c52Smaya               best = prev;
3799f464c52Smaya            }
3809f464c52Smaya         }
3819f464c52Smaya      }
3829f464c52Smaya      prev = &node->next;
3839f464c52Smaya      node = node->next;
3849f464c52Smaya   }
3859f464c52Smaya
3869f464c52Smaya   best_x = (best == NULL) ? 0 : (*best)->x;
3879f464c52Smaya
3889f464c52Smaya   // if doing best-fit (BF), we also have to try aligning right edge to each node position
3899f464c52Smaya   //
3909f464c52Smaya   // e.g, if fitting
3919f464c52Smaya   //
3929f464c52Smaya   //     ____________________
3939f464c52Smaya   //    |____________________|
3949f464c52Smaya   //
3959f464c52Smaya   //            into
3969f464c52Smaya   //
3979f464c52Smaya   //   |                         |
3989f464c52Smaya   //   |             ____________|
3999f464c52Smaya   //   |____________|
4009f464c52Smaya   //
4019f464c52Smaya   // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
4029f464c52Smaya   //
4039f464c52Smaya   // This makes BF take about 2x the time
4049f464c52Smaya
4059f464c52Smaya   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
4069f464c52Smaya      tail = c->active_head;
4079f464c52Smaya      node = c->active_head;
4089f464c52Smaya      prev = &c->active_head;
4099f464c52Smaya      // find first node that's admissible
4109f464c52Smaya      while (tail->x < width)
4119f464c52Smaya         tail = tail->next;
4129f464c52Smaya      while (tail) {
4139f464c52Smaya         int xpos = tail->x - width;
4149f464c52Smaya         int y,waste;
4159f464c52Smaya         STBRP_ASSERT(xpos >= 0);
4169f464c52Smaya         // find the left position that matches this
4179f464c52Smaya         while (node->next->x <= xpos) {
4189f464c52Smaya            prev = &node->next;
4199f464c52Smaya            node = node->next;
4209f464c52Smaya         }
4219f464c52Smaya         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
4229f464c52Smaya         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
4239f464c52Smaya         if (y + height < c->height) {
4249f464c52Smaya            if (y <= best_y) {
4259f464c52Smaya               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
4269f464c52Smaya                  best_x = xpos;
4279f464c52Smaya                  STBRP_ASSERT(y <= best_y);
4289f464c52Smaya                  best_y = y;
4299f464c52Smaya                  best_waste = waste;
4309f464c52Smaya                  best = prev;
4319f464c52Smaya               }
4329f464c52Smaya            }
4339f464c52Smaya         }
4349f464c52Smaya         tail = tail->next;
4359f464c52Smaya      }
4369f464c52Smaya   }
4379f464c52Smaya
4389f464c52Smaya   fr.prev_link = best;
4399f464c52Smaya   fr.x = best_x;
4409f464c52Smaya   fr.y = best_y;
4419f464c52Smaya   return fr;
4429f464c52Smaya}
4439f464c52Smaya
4449f464c52Smayastatic stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
4459f464c52Smaya{
4469f464c52Smaya   // find best position according to heuristic
4479f464c52Smaya   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
4489f464c52Smaya   stbrp_node *node, *cur;
4499f464c52Smaya
4509f464c52Smaya   // bail if:
4519f464c52Smaya   //    1. it failed
4529f464c52Smaya   //    2. the best node doesn't fit (we don't always check this)
4539f464c52Smaya   //    3. we're out of memory
4549f464c52Smaya   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
4559f464c52Smaya      res.prev_link = NULL;
4569f464c52Smaya      return res;
4579f464c52Smaya   }
4589f464c52Smaya
4599f464c52Smaya   // on success, create new node
4609f464c52Smaya   node = context->free_head;
4619f464c52Smaya   node->x = (stbrp_coord) res.x;
4629f464c52Smaya   node->y = (stbrp_coord) (res.y + height);
4639f464c52Smaya
4649f464c52Smaya   context->free_head = node->next;
4659f464c52Smaya
4669f464c52Smaya   // insert the new node into the right starting point, and
4679f464c52Smaya   // let 'cur' point to the remaining nodes needing to be
4689f464c52Smaya   // stiched back in
4699f464c52Smaya
4709f464c52Smaya   cur = *res.prev_link;
4719f464c52Smaya   if (cur->x < res.x) {
4729f464c52Smaya      // preserve the existing one, so start testing with the next one
4739f464c52Smaya      stbrp_node *next = cur->next;
4749f464c52Smaya      cur->next = node;
4759f464c52Smaya      cur = next;
4769f464c52Smaya   } else {
4779f464c52Smaya      *res.prev_link = node;
4789f464c52Smaya   }
4799f464c52Smaya
4809f464c52Smaya   // from here, traverse cur and free the nodes, until we get to one
4819f464c52Smaya   // that shouldn't be freed
4829f464c52Smaya   while (cur->next && cur->next->x <= res.x + width) {
4839f464c52Smaya      stbrp_node *next = cur->next;
4849f464c52Smaya      // move the current node to the free list
4859f464c52Smaya      cur->next = context->free_head;
4869f464c52Smaya      context->free_head = cur;
4879f464c52Smaya      cur = next;
4889f464c52Smaya   }
4899f464c52Smaya
4909f464c52Smaya   // stitch the list back in
4919f464c52Smaya   node->next = cur;
4929f464c52Smaya
4939f464c52Smaya   if (cur->x < res.x + width)
4949f464c52Smaya      cur->x = (stbrp_coord) (res.x + width);
4959f464c52Smaya
4969f464c52Smaya#ifdef _DEBUG
4979f464c52Smaya   cur = context->active_head;
4989f464c52Smaya   while (cur->x < context->width) {
4999f464c52Smaya      STBRP_ASSERT(cur->x < cur->next->x);
5009f464c52Smaya      cur = cur->next;
5019f464c52Smaya   }
5029f464c52Smaya   STBRP_ASSERT(cur->next == NULL);
5039f464c52Smaya
5049f464c52Smaya   {
5059f464c52Smaya      int count=0;
5069f464c52Smaya      cur = context->active_head;
5079f464c52Smaya      while (cur) {
5089f464c52Smaya         cur = cur->next;
5099f464c52Smaya         ++count;
5109f464c52Smaya      }
5119f464c52Smaya      cur = context->free_head;
5129f464c52Smaya      while (cur) {
5139f464c52Smaya         cur = cur->next;
5149f464c52Smaya         ++count;
5159f464c52Smaya      }
5169f464c52Smaya      STBRP_ASSERT(count == context->num_nodes+2);
5179f464c52Smaya   }
5189f464c52Smaya#endif
5199f464c52Smaya
5209f464c52Smaya   return res;
5219f464c52Smaya}
5229f464c52Smaya
5239f464c52Smaya// [DEAR IMGUI] Added STBRP__CDECL
5249f464c52Smayastatic int STBRP__CDECL rect_height_compare(const void *a, const void *b)
5259f464c52Smaya{
5269f464c52Smaya   const stbrp_rect *p = (const stbrp_rect *) a;
5279f464c52Smaya   const stbrp_rect *q = (const stbrp_rect *) b;
5289f464c52Smaya   if (p->h > q->h)
5299f464c52Smaya      return -1;
5309f464c52Smaya   if (p->h < q->h)
5319f464c52Smaya      return  1;
5329f464c52Smaya   return (p->w > q->w) ? -1 : (p->w < q->w);
5339f464c52Smaya}
5349f464c52Smaya
5359f464c52Smaya// [DEAR IMGUI] Added STBRP__CDECL
5369f464c52Smayastatic int STBRP__CDECL rect_original_order(const void *a, const void *b)
5379f464c52Smaya{
5389f464c52Smaya   const stbrp_rect *p = (const stbrp_rect *) a;
5399f464c52Smaya   const stbrp_rect *q = (const stbrp_rect *) b;
5409f464c52Smaya   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
5419f464c52Smaya}
5429f464c52Smaya
5439f464c52Smaya#ifdef STBRP_LARGE_RECTS
5449f464c52Smaya#define STBRP__MAXVAL  0xffffffff
5459f464c52Smaya#else
5469f464c52Smaya#define STBRP__MAXVAL  0xffff
5479f464c52Smaya#endif
5489f464c52Smaya
5499f464c52SmayaSTBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
5509f464c52Smaya{
5519f464c52Smaya   int i, all_rects_packed = 1;
5529f464c52Smaya
5539f464c52Smaya   // we use the 'was_packed' field internally to allow sorting/unsorting
5549f464c52Smaya   for (i=0; i < num_rects; ++i) {
5559f464c52Smaya      rects[i].was_packed = i;
5569f464c52Smaya   }
5579f464c52Smaya
5589f464c52Smaya   // sort according to heuristic
5599f464c52Smaya   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
5609f464c52Smaya
5619f464c52Smaya   for (i=0; i < num_rects; ++i) {
5629f464c52Smaya      if (rects[i].w == 0 || rects[i].h == 0) {
5639f464c52Smaya         rects[i].x = rects[i].y = 0;  // empty rect needs no space
5649f464c52Smaya      } else {
5659f464c52Smaya         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
5669f464c52Smaya         if (fr.prev_link) {
5679f464c52Smaya            rects[i].x = (stbrp_coord) fr.x;
5689f464c52Smaya            rects[i].y = (stbrp_coord) fr.y;
5699f464c52Smaya         } else {
5709f464c52Smaya            rects[i].x = rects[i].y = STBRP__MAXVAL;
5719f464c52Smaya         }
5729f464c52Smaya      }
5739f464c52Smaya   }
5749f464c52Smaya
5759f464c52Smaya   // unsort
5769f464c52Smaya   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
5779f464c52Smaya
5789f464c52Smaya   // set was_packed flags and all_rects_packed status
5799f464c52Smaya   for (i=0; i < num_rects; ++i) {
5809f464c52Smaya      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
5819f464c52Smaya      if (!rects[i].was_packed)
5829f464c52Smaya         all_rects_packed = 0;
5839f464c52Smaya   }
5849f464c52Smaya
5859f464c52Smaya   // return the all_rects_packed status
5869f464c52Smaya   return all_rects_packed;
5879f464c52Smaya}
5889f464c52Smaya#endif
5899f464c52Smaya
5909f464c52Smaya/*
5919f464c52Smaya------------------------------------------------------------------------------
5929f464c52SmayaThis software is available under 2 licenses -- choose whichever you prefer.
5939f464c52Smaya------------------------------------------------------------------------------
5949f464c52SmayaALTERNATIVE A - MIT License
5959f464c52SmayaCopyright (c) 2017 Sean Barrett
5969f464c52SmayaPermission is hereby granted, free of charge, to any person obtaining a copy of
5979f464c52Smayathis software and associated documentation files (the "Software"), to deal in
5989f464c52Smayathe Software without restriction, including without limitation the rights to
5999f464c52Smayause, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
6009f464c52Smayaof the Software, and to permit persons to whom the Software is furnished to do
6019f464c52Smayaso, subject to the following conditions:
6029f464c52SmayaThe above copyright notice and this permission notice shall be included in all
6039f464c52Smayacopies or substantial portions of the Software.
6049f464c52SmayaTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6059f464c52SmayaIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6069f464c52SmayaFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6079f464c52SmayaAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6089f464c52SmayaLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6099f464c52SmayaOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6109f464c52SmayaSOFTWARE.
6119f464c52Smaya------------------------------------------------------------------------------
6129f464c52SmayaALTERNATIVE B - Public Domain (www.unlicense.org)
6139f464c52SmayaThis is free and unencumbered software released into the public domain.
6149f464c52SmayaAnyone is free to copy, modify, publish, use, compile, sell, or distribute this
6159f464c52Smayasoftware, either in source code form or as a compiled binary, for any purpose,
6169f464c52Smayacommercial or non-commercial, and by any means.
6179f464c52SmayaIn jurisdictions that recognize copyright laws, the author or authors of this
6189f464c52Smayasoftware dedicate any and all copyright interest in the software to the public
6199f464c52Smayadomain. We make this dedication for the benefit of the public at large and to
6209f464c52Smayathe detriment of our heirs and successors. We intend this dedication to be an
6219f464c52Smayaovert act of relinquishment in perpetuity of all present and future rights to
6229f464c52Smayathis software under copyright law.
6239f464c52SmayaTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6249f464c52SmayaIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6259f464c52SmayaFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6269f464c52SmayaAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
6279f464c52SmayaACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
6289f464c52SmayaWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6299f464c52Smaya------------------------------------------------------------------------------
6309f464c52Smaya*/
631