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