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