From 8d3ef72e3ce083ae7471e29115af9d41852f77c8 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 24 Nov 2014 18:12:46 -0800 Subject: [PATCH] fixed bugs related to the best-fit heuristic --- stb_rect_pack.h | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/stb_rect_pack.h b/stb_rect_pack.h index 6f1065c..47a074d 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -1,17 +1,24 @@ // stb_rect_pack.h - v0.01 - public domain - rectangle packing +// Sean Barrett 2014 // // Useful for e.g. packing rectangular textures into an atlas. +// Does not do rotation. // -// By Sean Barrett and Ryan Gordon +// Not necessarily the awesomest packing method, but better than +// the totally naive one in stb_truetype (which is primarily what +// this is meant to replace). +// +// Has only had a few tests run, may have issues. +// +// More docs to come. +// +// No memory allocations; uses qsort() and assert() from stblib. // // This library currently uses the Skyline Bottom-Left algorithm. // // Please note: better rectangle packers are welcome! Please // implement them to the same API, but with a different init -// function. Contact me for details of how to set up the -// heuristic enums and suchlike (as the code currently isn't -// designed to do that correctly internally). -// +// function. #ifndef STB_INCLUDE_STB_RECT_PACK_H #define STB_INCLUDE_STB_RECT_PACK_H @@ -37,7 +44,7 @@ typedef unsigned short stbrp_coord; #endif STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); -// Assign packing locations to rectangles. The rectangles are of type +// Assign packed locations to rectangles. The rectangles are of type // 'stbrp_rect' defined below, stored in the array 'rects', and there // are 'num_rects' many of them. // @@ -139,6 +146,7 @@ STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) switch (context->init_mode) { case STBRP__INIT_skyline: assert(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); + context->heuristic = heuristic; break; default: assert(0); @@ -218,21 +226,26 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0 min_y = 0; waste_area = 0; visited_width = 0; - while (node->x <= x1) { + while (node->x < x1) { if (node->y > min_y) { // raise min_y higher. // we've accounted for all waste up to min_y, // but we'll now add more waste for everything we've visted waste_area += visited_width * (node->y - min_y); min_y = node->y; + // the first time through, visited_width might be reduced + if (node->x < x0) + visited_width += node->next->x - x0; + else + visited_width += node->next->x - node->x; } else { // add waste area int under_width = node->next->x - node->x; if (under_width + visited_width > width) under_width = width - visited_width; waste_area += under_width * (min_y - node->y); + visited_width += under_width; } - visited_width += node->next->x - node->x; // adds too much the last time, but that's never used node = node->next; } @@ -259,7 +272,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt node = c->active_head; prev = &c->active_head; - while (node->x + width < c->width) { + while (node->x + width <= c->width) { int y,waste; y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL @@ -309,13 +322,13 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt // find first node that's admissible while (tail->x < width) tail = tail->next; - while (tail->x <= c->width) { + while (tail) { int xpos = tail->x - width; int y,waste; assert(xpos >= 0); // find the left position that matches this while (node->next->x <= xpos) { - prev = &node; + prev = &node->next; node = node->next; } assert(node->next->x > xpos && node->x <= xpos); @@ -376,7 +389,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i // from here, traverse cur and free the nodes, until we get to one // that shouldn't be freed - while (cur->next->x <= res.x + width) { + while (cur->next && cur->next->x <= res.x + width) { stbrp_node *next = cur->next; // move the current node to the free list cur->next = context->free_head;