1313 *
1414 * More docs to come.
1515 *
16- * No memory allocations; uses qsort() and assert() from stdlib.
17- * Can override those by defining STBRP_SORT and STBRP_ASSERT.
16+ * No memory allocations; uses qsort() from stdlib.
1817 *
1918 * This library currently uses the Skyline Bottom-Left algorithm.
2019 *
3029 * Martins Mozeiko
3130 * Bugfixes / warning fixes
3231 * [your name could be here]
33- *
34- * Version history:
35- *
36- * 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
37- * 0.05: added STBRP_ASSERT to allow replacing assert
38- * 0.04: fixed minor bug in STBRP_LARGE_RECTS support
39- * 0.01: initial release
4032*/
4133
4234#ifndef STB_INCLUDE_STB_RECT_PACK_H
@@ -58,12 +50,6 @@ typedef struct stbrp_context stbrp_context;
5850typedef struct stbrp_node stbrp_node ;
5951typedef struct stbrp_rect stbrp_rect ;
6052
61- #ifdef STBRP_LARGE_RECTS
62- typedef int stbrp_coord ;
63- #else
64- typedef unsigned short stbrp_coord ;
65- #endif
66-
6753STBRP_DEF void stbrp_pack_rects (stbrp_context * context ,
6854 stbrp_rect * rects , int num_rects );
6955
@@ -92,8 +78,8 @@ STBRP_DEF void stbrp_pack_rects (stbrp_context *context,
9278struct stbrp_rect
9379{
9480 int id ; /* reserved for your use: */
95- stbrp_coord w , h ; /* input: */
96- stbrp_coord x , y ; /* output: */
81+ uint16_t w , h ; /* input: */
82+ uint16_t x , y ; /* output: */
9783 int was_packed ; /* non-zero if valid packing */
9884}; /* 16 bytes, nominally */
9985
@@ -122,21 +108,6 @@ STBRP_DEF void stbrp_init_target (stbrp_context *context,
122108 * may run out of temporary storage and be unable to pack some rectangles.
123109 */
124110
125- STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context * context , int allow_out_of_mem );
126-
127- /* Optionally call this function after init but before doing any packing to
128- * change the handling of the out-of-temp-memory scenario, described above.
129- * If you call init again, this will be reset to the default (false).
130- */
131-
132-
133- STBRP_DEF void stbrp_setup_heuristic (stbrp_context * context , int heuristic );
134-
135- /* Optionally select which packing heuristic the library should use. Different
136- * heuristics will produce better/worse results for different data sets.
137- * If you call init again, this will be reset to the default.
138- */
139-
140111enum
141112{
142113 STBRP_HEURISTIC_Skyline_default = 0 ,
150121
151122struct stbrp_node
152123{
153- stbrp_coord x ,y ;
124+ uint16_t x ,y ;
154125 stbrp_node * next ;
155126};
156127
@@ -176,63 +147,16 @@ struct stbrp_context
176147/* IMPLEMENTATION SECTION */
177148
178149#ifdef STB_RECT_PACK_IMPLEMENTATION
179- #ifndef STBRP_SORT
180150#include <stdlib.h>
181- #define STBRP_SORT qsort
182- #endif
183-
184- #ifndef STBRP_ASSERT
185- #include <assert.h>
186- #define STBRP_ASSERT assert
187- #endif
188151
189152enum
190153{
191154 STBRP__INIT_skyline = 1
192155};
193156
194- STBRP_DEF void stbrp_setup_heuristic (stbrp_context * context , int heuristic )
195- {
196- switch (context -> init_mode )
197- {
198- case STBRP__INIT_skyline :
199- STBRP_ASSERT (heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight );
200- context -> heuristic = heuristic ;
201- break ;
202- default :
203- STBRP_ASSERT (0 );
204- }
205- }
206-
207- STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context * context , int allow_out_of_mem )
208- {
209- /* if it's ok to run out of memory, then don't bother aligning them;
210- * this gives better packing, but may fail due to OOM (even though
211- * the rectangles easily fit). @TODO a smarter approach would be to only
212- * quantize once we've hit OOM, then we could get rid of this parameter.
213- */
214- if (allow_out_of_mem )
215- context -> align = 1 ;
216- else
217- {
218- /* if it's not ok to run out of memory, then quantize the widths
219- * so that num_nodes is always enough nodes.
220- *
221- * I.e. num_nodes * align >= width
222- * align >= width / num_nodes
223- * align = ceil(width/num_nodes)
224- */
225- context -> align = (context -> width + context -> num_nodes - 1 ) / context -> num_nodes ;
226- }
227- }
228-
229157STBRP_DEF void stbrp_init_target (stbrp_context * context , int width , int height , stbrp_node * nodes , int num_nodes )
230158{
231159 int i ;
232- #ifndef STBRP_LARGE_RECTS
233- STBRP_ASSERT (width <= 0xffff && height <= 0xffff );
234- #endif
235-
236160 for (i = 0 ; i < num_nodes - 1 ; ++ i )
237161 nodes [i ].next = & nodes [i + 1 ];
238162 nodes [i ].next = NULL ;
@@ -243,19 +167,15 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height,
243167 context -> width = width ;
244168 context -> height = height ;
245169 context -> num_nodes = num_nodes ;
246- stbrp_setup_allow_out_of_mem (context , 0 ) ;
170+ context -> align = (context -> width + context -> num_nodes - 1 ) / context -> num_nodes ;
247171
248172 /* node 0 is the full width,
249173 * node 1 is the sentinel (lets us not store width explicitly) */
250174 context -> extra [0 ].x = 0 ;
251175 context -> extra [0 ].y = 0 ;
252176 context -> extra [0 ].next = & context -> extra [1 ];
253- context -> extra [1 ].x = (stbrp_coord ) width ;
254- #ifdef STBRP_LARGE_RECTS
255- context -> extra [1 ].y = (1 <<30 );
256- #else
177+ context -> extra [1 ].x = (uint16_t ) width ;
257178 context -> extra [1 ].y = 65535 ;
258- #endif
259179 context -> extra [1 ].next = NULL ;
260180}
261181
@@ -266,11 +186,6 @@ static int stbrp__skyline_find_min_y(stbrp_context *c,
266186 int min_y , visited_width , waste_area ;
267187 stbrp_node * node = first ;
268188 int x1 = x0 + width ;
269-
270- STBRP_ASSERT (first -> x <= x0 );
271- STBRP_ASSERT (node -> next -> x > x0 );
272- STBRP_ASSERT (node -> x <= x0 );
273-
274189 min_y = 0 ;
275190 waste_area = 0 ;
276191 visited_width = 0 ;
@@ -322,7 +237,6 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
322237 /* align to multiple of c->align */
323238 width = (width + c -> align - 1 );
324239 width -= width % c -> align ;
325- STBRP_ASSERT (width % c -> align == 0 );
326240
327241 node = c -> active_head ;
328242 prev = & c -> active_head ;
@@ -390,7 +304,6 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
390304 {
391305 int xpos = tail -> x - width ;
392306 int y ,waste ;
393- STBRP_ASSERT (xpos >= 0 );
394307
395308 /* find the left position that matches this */
396309 while (node -> next -> x <= xpos )
@@ -399,7 +312,6 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
399312 node = node -> next ;
400313 }
401314
402- STBRP_ASSERT (node -> next -> x > xpos && node -> x <= xpos );
403315 y = stbrp__skyline_find_min_y (c , node , xpos , width , & waste );
404316
405317 if (y + height < c -> height )
@@ -409,7 +321,6 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
409321 if (y < best_y || waste < best_waste || (waste == best_waste && xpos < best_x ))
410322 {
411323 best_x = xpos ;
412- STBRP_ASSERT (y <= best_y );
413324 best_y = y ;
414325 best_waste = waste ;
415326 best = prev ;
@@ -429,7 +340,6 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
429340static stbrp__findresult stbrp__skyline_pack_rectangle (stbrp_context * context , int width , int height )
430341{
431342 /* find best position according to heuristic */
432- stbrp_node * node , * cur ;
433343 stbrp__findresult res = stbrp__skyline_find_best_pos (context , width , height );
434344
435345 /* bail if:
@@ -438,52 +348,51 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
438348 * 3. we're out of memory
439349 */
440350 if (res .prev_link == NULL || res .y + height > context -> height || context -> free_head == NULL )
441- {
442351 res .prev_link = NULL ;
443- return res ;
444- }
445-
446- /* on success, create new node */
447- node = context -> free_head ;
448- node -> x = (stbrp_coord ) res .x ;
449- node -> y = (stbrp_coord ) (res .y + height );
450-
451- context -> free_head = node -> next ;
352+ else
353+ {
354+ stbrp_node * cur ;
355+ /* on success, create new node */
356+ stbrp_node * node = context -> free_head ;
357+ node -> x = (uint16_t ) res .x ;
358+ node -> y = (uint16_t ) (res .y + height );
452359
453- /* insert the new node into the right starting point, and
454- * let 'cur' point to the remaining nodes needing to be
455- * stiched back in
456- */
360+ context -> free_head = node -> next ;
457361
458- cur = * res .prev_link ;
459- if (cur -> x < res .x )
460- {
461- /* preserve the existing one, so start testing with the next one */
462- stbrp_node * next = cur -> next ;
463- cur -> next = node ;
464- cur = next ;
465- }
466- else
467- * res .prev_link = node ;
362+ /* insert the new node into the right starting point, and
363+ * let 'cur' point to the remaining nodes needing to be
364+ * stiched back in
365+ */
468366
469- /* from here, traverse cur and free the nodes, until we get to one
470- * that shouldn't be freed */
471- while (cur -> next && cur -> next -> x <= res .x + width )
472- {
473- stbrp_node * next = cur -> next ;
367+ cur = * res .prev_link ;
368+ if (cur -> x < res .x )
369+ {
370+ /* preserve the existing one, so start testing with the next one */
371+ stbrp_node * next = cur -> next ;
372+ cur -> next = node ;
373+ cur = next ;
374+ }
375+ else
376+ * res .prev_link = node ;
474377
475- /* move the current node to the free list */
476- cur -> next = context -> free_head ;
477- context -> free_head = cur ;
478- cur = next ;
479- }
378+ /* from here, traverse cur and free the nodes, until we get to one
379+ * that shouldn't be freed */
380+ while ( cur -> next && cur -> next -> x <= res . x + width )
381+ {
382+ stbrp_node * next = cur -> next ;
480383
481- /* stitch the list back in */
482- node -> next = cur ;
384+ /* move the current node to the free list */
385+ cur -> next = context -> free_head ;
386+ context -> free_head = cur ;
387+ cur = next ;
388+ }
483389
484- if ( cur -> x < res . x + width )
485- cur -> x = ( stbrp_coord ) ( res . x + width ) ;
390+ /* stitch the list back in */
391+ node -> next = cur ;
486392
393+ if (cur -> x < res .x + width )
394+ cur -> x = (uint16_t ) (res .x + width );
395+ }
487396 return res ;
488397}
489398
@@ -498,29 +407,14 @@ static int rect_height_compare(const void *a, const void *b)
498407 return (p -> w > q -> w ) ? -1 : (p -> w < q -> w );
499408}
500409
501- STBRP_DEF int rect_width_compare (const void * a , const void * b )
502- {
503- stbrp_rect * p = (stbrp_rect * ) a ;
504- stbrp_rect * q = (stbrp_rect * ) b ;
505- if (p -> w > q -> w )
506- return -1 ;
507- if (p -> w < q -> w )
508- return 1 ;
509- return (p -> h > q -> h ) ? -1 : (p -> h < q -> h );
510- }
511-
512410static int rect_original_order (const void * a , const void * b )
513411{
514412 stbrp_rect * p = (stbrp_rect * ) a ;
515413 stbrp_rect * q = (stbrp_rect * ) b ;
516414 return (p -> was_packed < q -> was_packed ) ? -1 : (p -> was_packed > q -> was_packed );
517415}
518416
519- #ifdef STBRP_LARGE_RECTS
520- #define STBRP__MAXVAL 0xffffffff
521- #else
522417#define STBRP__MAXVAL 0xffff
523- #endif
524418
525419STBRP_DEF void stbrp_pack_rects (stbrp_context * context , stbrp_rect * rects , int num_rects )
526420{
@@ -531,22 +425,22 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n
531425 rects [i ].was_packed = i ;
532426
533427 /* sort according to heuristic */
534- STBRP_SORT (rects , num_rects , sizeof (rects [0 ]), rect_height_compare );
428+ qsort (rects , num_rects , sizeof (rects [0 ]), rect_height_compare );
535429
536430 for (i = 0 ; i < num_rects ; ++ i )
537431 {
538432 stbrp__findresult fr = stbrp__skyline_pack_rectangle (context , rects [i ].w , rects [i ].h );
539433 if (fr .prev_link )
540434 {
541- rects [i ].x = (stbrp_coord ) fr .x ;
542- rects [i ].y = (stbrp_coord ) fr .y ;
543- } else {
544- rects [i ].x = rects [i ].y = STBRP__MAXVAL ;
435+ rects [i ].x = (uint16_t ) fr .x ;
436+ rects [i ].y = (uint16_t ) fr .y ;
545437 }
438+ else
439+ rects [i ].x = rects [i ].y = STBRP__MAXVAL ;
546440 }
547441
548442 /* unsort */
549- STBRP_SORT (rects , num_rects , sizeof (rects [0 ]), rect_original_order );
443+ qsort (rects , num_rects , sizeof (rects [0 ]), rect_original_order );
550444
551445 /* set was_packed flags */
552446 for (i = 0 ; i < num_rects ; ++ i )
0 commit comments