util/rectpack: refactor to use standard mempools
This commit is contained in:
parent
f9c2748fae
commit
a8322f5e1d
4 changed files with 87 additions and 99 deletions
|
@ -122,9 +122,9 @@ static struct {
|
|||
} fb;
|
||||
|
||||
struct {
|
||||
MemArena arena;
|
||||
Allocator alloc;
|
||||
RectPack rectpack;
|
||||
MemArena arena;
|
||||
RectPackSectionPool rpspool;
|
||||
} packer;
|
||||
|
||||
struct {
|
||||
|
@ -257,18 +257,17 @@ void laserdraw_preload(ResourceGroup *rg) {
|
|||
}
|
||||
|
||||
static void laserdraw_init_packer(void) {
|
||||
rectpack_init(&ldraw.packer.rectpack, &ldraw.packer.alloc,
|
||||
PACKING_SPACE_SIZE_W, PACKING_SPACE_SIZE_H);
|
||||
rectpack_init(&ldraw.packer.rectpack, PACKING_SPACE_SIZE_W, PACKING_SPACE_SIZE_H);
|
||||
}
|
||||
|
||||
static void laserdraw_reset_packer(void) {
|
||||
marena_reset(&ldraw.packer.arena);
|
||||
ldraw.packer.rpspool = (RectPackSectionPool) {};
|
||||
laserdraw_init_packer();
|
||||
}
|
||||
|
||||
void laserdraw_init(void) {
|
||||
marena_init(&ldraw.packer.arena, 0);
|
||||
allocator_init_from_arena(&ldraw.packer.alloc, &ldraw.packer.arena);
|
||||
laserdraw_init_packer();
|
||||
dynarray_ensure_capacity(&ldraw.queue, 64);
|
||||
|
||||
|
@ -300,7 +299,6 @@ void laserdraw_init(void) {
|
|||
|
||||
void laserdraw_shutdown(void) {
|
||||
dynarray_free_data(&ldraw.queue);
|
||||
allocator_deinit(&ldraw.packer.alloc);
|
||||
marena_deinit(&ldraw.packer.arena);
|
||||
fbmgr_group_destroy(ldraw.fb.group);
|
||||
r_vertex_array_destroy(ldraw.pass1.va);
|
||||
|
@ -333,7 +331,12 @@ static bool laserdraw_pack_laser(Laser *l, cmplxf *out_ofs, bool *rotated) {
|
|||
FloatExtent bbox_size = { .as_cmplx = laser_packed_dimensions(l) };
|
||||
|
||||
RectPackSection *section = rectpack_add(
|
||||
&ldraw.packer.rectpack, bbox_size.w, bbox_size.h, true);
|
||||
&ldraw.packer.rectpack,
|
||||
(RectPackSectionSource) {
|
||||
.arena = &ldraw.packer.arena,
|
||||
.pool = &ldraw.packer.rpspool,
|
||||
},
|
||||
bbox_size.w, bbox_size.h, true);
|
||||
|
||||
if(!section) {
|
||||
return false;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "config.h"
|
||||
#include "dynarray.h"
|
||||
#include "events.h"
|
||||
#include "memory/arena.h"
|
||||
#include "renderer/api.h"
|
||||
#include "util.h"
|
||||
#include "util/glm.h"
|
||||
|
@ -128,6 +129,8 @@ static struct {
|
|||
Texture *render_tex;
|
||||
Framebuffer *render_buf;
|
||||
SpriteSheetAnchor spritesheets;
|
||||
MemArena arena;
|
||||
RectPackSectionPool rpspool;
|
||||
|
||||
struct {
|
||||
SDL_mutex *new_face;
|
||||
|
@ -191,6 +194,8 @@ static void *ft_realloc(FT_Memory mem, long cur_size, long new_size, void *block
|
|||
static void init_fonts(void) {
|
||||
FT_Error err;
|
||||
|
||||
marena_init(&globals.arena, sizeof(RectPackSection) * 128);
|
||||
|
||||
static typeof(*(FT_Memory)0) ft_mem = {
|
||||
.alloc = ft_alloc,
|
||||
.free = ft_free,
|
||||
|
@ -252,6 +257,7 @@ static void shutdown_fonts(void) {
|
|||
FT_Done_Library(globals.lib);
|
||||
SDL_DestroyMutex(globals.mutex.new_face);
|
||||
SDL_DestroyMutex(globals.mutex.done_face);
|
||||
marena_deinit(&globals.arena);
|
||||
}
|
||||
|
||||
static char *font_path(const char *name) {
|
||||
|
@ -393,6 +399,13 @@ void font_set_kerning_enabled(Font *font, bool newval) {
|
|||
#define SS_TEXTURE_TYPE TEX_TYPE_RGB_8
|
||||
#define SS_TEXTURE_FLAGS 0
|
||||
|
||||
INLINE RectPackSectionSource rps_source(void) {
|
||||
return (RectPackSectionSource) {
|
||||
.arena = &globals.arena,
|
||||
.pool = &globals.rpspool,
|
||||
};
|
||||
}
|
||||
|
||||
static SpriteSheet *add_spritesheet(SpriteSheetAnchor *spritesheets) {
|
||||
auto ss = ALLOC(SpriteSheet, {
|
||||
.tex = r_texture_create(&(TextureParams) {
|
||||
|
@ -409,7 +422,7 @@ static SpriteSheet *add_spritesheet(SpriteSheetAnchor *spritesheets) {
|
|||
})
|
||||
});
|
||||
|
||||
rectpack_init(&ss->rectpack, &default_allocator, SS_WIDTH, SS_HEIGHT);
|
||||
rectpack_init(&ss->rectpack, SS_WIDTH, SS_HEIGHT);
|
||||
|
||||
#ifdef DEBUG
|
||||
char buf[128];
|
||||
|
@ -429,7 +442,7 @@ static bool add_glyph_to_spritesheet(Glyph *glyph, Pixmap *pixmap, SpriteSheet *
|
|||
uint padded_w = pixmap->width + 2 * GLYPH_SPRITE_PADDING;
|
||||
uint padded_h = pixmap->height + 2 * GLYPH_SPRITE_PADDING;
|
||||
|
||||
glyph->spritesheet_section = rectpack_add(&ss->rectpack, padded_w, padded_h);
|
||||
glyph->spritesheet_section = rectpack_add(&ss->rectpack, rps_source(), padded_w, padded_h, false);
|
||||
|
||||
if(glyph->spritesheet_section == NULL) {
|
||||
return false;
|
||||
|
@ -496,7 +509,7 @@ static const char *pixmode_name(FT_Pixel_Mode mode) {
|
|||
|
||||
static void delete_spritesheet(SpriteSheetAnchor *spritesheets, SpriteSheet *ss) {
|
||||
r_texture_destroy(ss->tex);
|
||||
rectpack_deinit(&ss->rectpack);
|
||||
assert(rectpack_is_empty(&ss->rectpack));
|
||||
alist_unlink(spritesheets, ss);
|
||||
mem_free(ss);
|
||||
}
|
||||
|
@ -738,7 +751,7 @@ static void wipe_glyph_cache(Font *font) {
|
|||
RectPackSection *section = g->spritesheet_section;
|
||||
assume(section != NULL);
|
||||
|
||||
rectpack_reclaim(rp, section);
|
||||
rectpack_reclaim(rp, rps_source(), section);
|
||||
|
||||
if(rectpack_is_empty(rp)) {
|
||||
delete_spritesheet(&globals.spritesheets, ss);
|
||||
|
|
|
@ -35,28 +35,20 @@ static inline void section_make_used(RectPack *rp, RectPackSection *s) {
|
|||
s->next = s->prev = s;
|
||||
}
|
||||
|
||||
static RectPackSection *acquire_section(RectPack *rp) {
|
||||
RectPackSection *s = list_pop(&rp->sections_freelist);
|
||||
|
||||
if(!s) {
|
||||
s = ALLOC_VIA(rp->allocator, typeof(*s));
|
||||
}
|
||||
|
||||
*s = (RectPackSection) { };
|
||||
return s;
|
||||
static RectPackSection *acquire_section(RectPackSectionSource secsrc) {
|
||||
return mempool_acquire(secsrc.pool, secsrc.arena);
|
||||
}
|
||||
|
||||
static void release_section(RectPack *rp, RectPackSection *s) {
|
||||
list_push(&rp->sections_freelist, s);
|
||||
static void release_section(RectPackSectionSource secsrc, RectPackSection *s) {
|
||||
mempool_release(secsrc.pool, s);
|
||||
}
|
||||
|
||||
void rectpack_init(RectPack *rp, Allocator *alloc, double width, double height) {
|
||||
void rectpack_init(RectPack *rp, double width, double height) {
|
||||
*rp = (RectPack) {
|
||||
.root.rect = {
|
||||
.top_left = CMPLX(0, 0),
|
||||
.bottom_right = CMPLX(width, height),
|
||||
},
|
||||
.allocator = alloc,
|
||||
};
|
||||
list_push(&rp->unused_sections, &rp->root);
|
||||
assert(rectpack_is_empty(rp));
|
||||
|
@ -71,35 +63,6 @@ bool rectpack_is_empty(RectPack *rp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static void delete_subsections(RectPack *rp, RectPackSection *restrict s) {
|
||||
if(s->children[0] != NULL) {
|
||||
assume(s->children[1] != NULL);
|
||||
assume(s->children[0]->parent == s);
|
||||
assume(s->children[1]->parent == s);
|
||||
|
||||
delete_subsections(rp, s->children[0]);
|
||||
release_section(rp, s->children[0]);
|
||||
s->children[0] = NULL;
|
||||
|
||||
delete_subsections(rp, s->children[1]);
|
||||
release_section(rp, s->children[1]);
|
||||
s->children[1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void rectpack_reset(RectPack *rp) {
|
||||
delete_subsections(rp, &rp->root);
|
||||
}
|
||||
|
||||
void rectpack_deinit(RectPack *rp) {
|
||||
delete_subsections(rp, &rp->root);
|
||||
Allocator *alloc = rp->allocator;
|
||||
|
||||
for(RectPackSection *s; (s = list_pop(&rp->sections_freelist));) {
|
||||
allocator_free(alloc, s);
|
||||
}
|
||||
}
|
||||
|
||||
static double section_fitness(RectPackSection *s, double w, double h) {
|
||||
double sw = rect_width(s->rect);
|
||||
double sh = rect_height(s->rect);
|
||||
|
@ -111,7 +74,7 @@ static double section_fitness(RectPackSection *s, double w, double h) {
|
|||
return sw * sh - w * h; // best area fit
|
||||
}
|
||||
|
||||
void rectpack_reclaim(RectPack *rp, RectPackSection *s) {
|
||||
void rectpack_reclaim(RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s) {
|
||||
assume(s->children[0] == NULL);
|
||||
assume(s->children[1] == NULL);
|
||||
|
||||
|
@ -133,14 +96,14 @@ void rectpack_reclaim(RectPack *rp, RectPackSection *s) {
|
|||
|
||||
// NOTE: the following frees s->sibling and s, in unspecified order
|
||||
|
||||
release_section(rp, parent->children[0]);
|
||||
release_section(secsrc, parent->children[0]);
|
||||
parent->children[0] = NULL;
|
||||
|
||||
release_section(rp, parent->children[1]);
|
||||
release_section(secsrc, parent->children[1]);
|
||||
parent->children[1] = NULL;
|
||||
|
||||
if(parent != NULL) {
|
||||
rectpack_reclaim(rp, parent);
|
||||
rectpack_reclaim(rp, secsrc, parent);
|
||||
}
|
||||
|
||||
RP_DEBUG("done reclaiming parent of %p", (void*)s);
|
||||
|
@ -154,7 +117,7 @@ void rectpack_reclaim(RectPack *rp, RectPackSection *s) {
|
|||
}
|
||||
|
||||
static RectPackSection *select_fittest_section(
|
||||
RectPack *rp, double *width, double *height, bool allow_rotation
|
||||
RectPack *rp, RectPackSectionSource secsrc, double *width, double *height, bool allow_rotation
|
||||
) {
|
||||
RectPackSection *best = NULL;
|
||||
double fitness = DBL_MAX;
|
||||
|
@ -201,10 +164,14 @@ static RectPackSection *select_fittest_section(
|
|||
return best;
|
||||
}
|
||||
|
||||
static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, double width, double height);
|
||||
static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double width, double height);
|
||||
static RectPackSection *split_horizontal(
|
||||
RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height);
|
||||
static RectPackSection *split_vertical(
|
||||
RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height);
|
||||
|
||||
static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, double width, double height) {
|
||||
static RectPackSection *split_horizontal(
|
||||
RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height
|
||||
) {
|
||||
RP_DEBUG("spliting section %p of size %gx%g for rect %gx%g", (void*)s, rect_width(s->rect), rect_height(s->rect), width, height);
|
||||
|
||||
assert(rect_width(s->rect) >= width);
|
||||
|
@ -213,10 +180,10 @@ static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, doubl
|
|||
if(rect_height(s->rect) == height) {
|
||||
assert(rect_width(s->rect) > width);
|
||||
RP_DEBUG("delegated to vertical split");
|
||||
return split_vertical(rp, s, width, height);
|
||||
return split_vertical(rp, secsrc, s, width, height);
|
||||
}
|
||||
|
||||
auto sub = acquire_section(rp);
|
||||
auto sub = acquire_section(secsrc);
|
||||
rect_set_xywh(&sub->rect,
|
||||
rect_x(s->rect),
|
||||
rect_y(s->rect),
|
||||
|
@ -228,7 +195,7 @@ static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, doubl
|
|||
|
||||
sub->parent = s;
|
||||
s->children[0] = sub;
|
||||
s->children[1] = acquire_section(rp);
|
||||
s->children[1] = acquire_section(secsrc);
|
||||
rect_set_xywh(&s->children[1]->rect,
|
||||
rect_x(s->rect),
|
||||
rect_y(s->rect) + height,
|
||||
|
@ -247,13 +214,15 @@ static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, doubl
|
|||
);
|
||||
|
||||
if(rect_width(sub->rect) != width) {
|
||||
sub = split_vertical(rp, sub, width, height);
|
||||
sub = split_vertical(rp, secsrc, sub, width, height);
|
||||
}
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double width, double height) {
|
||||
static RectPackSection *split_vertical(
|
||||
RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height
|
||||
) {
|
||||
assert(rect_width(s->rect) >= width);
|
||||
assert(rect_height(s->rect) >= height);
|
||||
|
||||
|
@ -262,10 +231,10 @@ static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double
|
|||
if(rect_width(s->rect) == width) {
|
||||
assert(rect_height(s->rect) > height);
|
||||
RP_DEBUG("delegated to horizontal split");
|
||||
return split_horizontal(rp, s, width, height);
|
||||
return split_horizontal(rp, secsrc, s, width, height);
|
||||
}
|
||||
|
||||
auto sub = acquire_section(rp);
|
||||
auto sub = acquire_section(secsrc);
|
||||
rect_set_xywh(&sub->rect,
|
||||
rect_x(s->rect),
|
||||
rect_y(s->rect),
|
||||
|
@ -277,7 +246,7 @@ static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double
|
|||
|
||||
sub->parent = s;
|
||||
s->children[0] = sub;
|
||||
s->children[1] = acquire_section(rp);
|
||||
s->children[1] = acquire_section(secsrc);
|
||||
rect_set_xywh(&s->children[1]->rect,
|
||||
rect_x(s->rect) + width,
|
||||
rect_y(s->rect),
|
||||
|
@ -296,26 +265,32 @@ static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double
|
|||
);
|
||||
|
||||
if(rect_height(sub->rect) != height) {
|
||||
sub = split_horizontal(rp, sub, width, height);
|
||||
sub = split_horizontal(rp, secsrc, sub, width, height);
|
||||
}
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
static RectPackSection *split(RectPack *rp, RectPackSection *s, double width, double height) {
|
||||
static RectPackSection *split(
|
||||
RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height
|
||||
) {
|
||||
// short leftover axis split
|
||||
|
||||
if(rect_width(s->rect) - width < rect_height(s->rect) - height) {
|
||||
return split_horizontal(rp, s, width, height);
|
||||
return split_horizontal(rp, secsrc, s, width, height);
|
||||
} else {
|
||||
return split_vertical(rp, s, width, height);
|
||||
return split_vertical(rp, secsrc, s, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
RectPackSection *(rectpack_add)(
|
||||
RectPack *rp, double width, double height, bool allow_rotation
|
||||
RectPackSection *rectpack_add(
|
||||
RectPack *rp,
|
||||
RectPackSectionSource secsrc,
|
||||
double width,
|
||||
double height,
|
||||
bool allow_rotation
|
||||
) {
|
||||
RectPackSection *s = select_fittest_section(rp, &width, &height, allow_rotation);
|
||||
RectPackSection *s = select_fittest_section(rp, secsrc, &width, &height, allow_rotation);
|
||||
|
||||
if(s == NULL) {
|
||||
return NULL;
|
||||
|
@ -327,7 +302,7 @@ RectPackSection *(rectpack_add)(
|
|||
return s;
|
||||
}
|
||||
|
||||
return split(rp, s, width, height);
|
||||
return split(rp, secsrc, s, width, height);
|
||||
}
|
||||
|
||||
Rect rectpack_section_rect(RectPackSection *s) {
|
||||
|
|
|
@ -11,50 +11,47 @@
|
|||
|
||||
#include "geometry.h"
|
||||
#include "list.h"
|
||||
#include "memory/allocator.h"
|
||||
#include "memory/mempool.h"
|
||||
|
||||
typedef struct RectPack RectPack;
|
||||
typedef struct RectPackSection RectPackSection;
|
||||
typedef MEMPOOL(RectPackSection) RectPackSectionPool;
|
||||
typedef struct RectPackSectionSource RectPackSectionSource;
|
||||
|
||||
struct RectPackSection {
|
||||
LIST_INTERFACE(RectPackSection);
|
||||
Rect rect;
|
||||
RectPackSection *parent;
|
||||
RectPackSection *sibling;
|
||||
RectPackSection *children[2];
|
||||
Rect rect;
|
||||
};
|
||||
|
||||
struct RectPack {
|
||||
RectPackSection root;
|
||||
RectPackSection *unused_sections;
|
||||
RectPackSection *sections_freelist;
|
||||
Allocator *allocator;
|
||||
};
|
||||
|
||||
void rectpack_init(RectPack *rp, Allocator *alloc, double width, double height)
|
||||
struct RectPackSectionSource {
|
||||
RectPackSectionPool *pool;
|
||||
MemArena *arena;
|
||||
};
|
||||
|
||||
void rectpack_init(RectPack *rp, double width, double height)
|
||||
attr_nonnull_all;
|
||||
|
||||
void rectpack_reset(RectPack *rp)
|
||||
attr_nonnull(1);
|
||||
|
||||
void rectpack_deinit(RectPack *rp)
|
||||
attr_nonnull(1);
|
||||
|
||||
RectPackSection *rectpack_add(RectPack *rp, double width, double height, bool allow_rotation)
|
||||
attr_nonnull(1);
|
||||
|
||||
#define _rectpack_add_3(rp, width, height) \
|
||||
rectpack_add(rp, width, height, false)
|
||||
#define _rectpack_add_4(rp, width, height, allow_rotation) \
|
||||
rectpack_add(rp, width, height, allow_rotation)
|
||||
#define rectpack_add(...) \
|
||||
MACROHAX_OVERLOAD_NARGS(_rectpack_add_, __VA_ARGS__)(__VA_ARGS__)
|
||||
RectPackSection *rectpack_add(
|
||||
RectPack *rp,
|
||||
RectPackSectionSource secsrc,
|
||||
double width,
|
||||
double height,
|
||||
bool allow_rotation
|
||||
) attr_nonnull(1);
|
||||
|
||||
Rect rectpack_section_rect(RectPackSection *s)
|
||||
attr_nonnull(1);
|
||||
|
||||
void rectpack_reclaim(RectPack *rp, RectPackSection *s)
|
||||
attr_nonnull(1, 2);
|
||||
void rectpack_reclaim(RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s)
|
||||
attr_nonnull(1, 3);
|
||||
|
||||
bool rectpack_is_empty(RectPack *rp)
|
||||
attr_nonnull(1);
|
||||
|
|
Loading…
Reference in a new issue