Skip to content

Commit

Permalink
Add atlas packing
Browse files Browse the repository at this point in the history
  • Loading branch information
marekmaskarinec committed Jan 13, 2024
1 parent 6d66dc0 commit 5dd6898
Show file tree
Hide file tree
Showing 12 changed files with 203 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib/sokol
Submodule sokol updated from 896daa to 1e1e7d
2 changes: 1 addition & 1 deletion lib/stb
87 changes: 87 additions & 0 deletions src/atlas.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include "tophat.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>

extern th_global *thg;

Expand All @@ -16,3 +19,87 @@ th_atlas_get_cell(th_atlas *a, th_vf2 cell)
.w = a->cs.x / a->i->dm.x,
.h = a->cs.y / a->i->dm.y};
}

static void
blit(uint32_t *tgt, uint32_t tw, uint32_t th, uint32_t *src, uint32_t x0, uint32_t y0, uint32_t sw,
uint32_t sh)
{
for (uint32_t y = 0; y < sh; y++) {
memcpy(tgt + (y0 + y) * tw + x0, src + y * sw, sw * sizeof(uint32_t));
}
}

void
th_atlas_pack(th_atlas *a, void *arr, th_atlas_pack_strategy strategy)
{
const size_t count = umkaGetDynArrayLen(arr);
th_image **images = ((UmkaDynArray(th_image *) *)arr)->data;

uint32_t w = 0, h = 0;
for (int i = 0; i < count; i++) {
w = MAX(w, images[i]->dm.w);
h = MAX(h, images[i]->dm.h);
}

a->cs = (th_vf2){{w, h}};

uint32_t iw, ih;
uint32_t *data;

switch (strategy) {
case TH_ATLAS_PACK_SQUARE: {
const uint32_t s = ceil(sqrt(count));
a->dm = (th_vf2){{s, s}};
iw = w * s;
ih = h * s;
data = calloc(sizeof(uint32_t), iw * ih);

for (int i = 0; i < count; i++) {
th_image *img = images[i];
const uint32_t x = (i % s) * w + (w - img->dm.w) / 2;
const uint32_t y = (i / s) * h + (h - img->dm.h) / 2;
uint32_t *d = th_image_get_data(img);

blit(data, iw, ih, d, x, y, img->dm.w, img->dm.h);
free(d);
}
break;
}
case TH_ATLAS_PACK_ROW: {
a->dm = (th_vf2){{count, 1}};
iw = w * count;
ih = h;
data = calloc(sizeof(uint32_t), iw * ih);

for (int i = 0; i < count; i++) {
th_image *img = images[i];
uint32_t *d = th_image_get_data(img);
blit(data, iw, ih, d, i * w + (w - img->dm.w) / 2, (h - img->dm.h) / 2,
img->dm.w, img->dm.h);
free(d);
}

break;
}
case TH_ATLAS_PACK_COLUMN: {
a->dm = (th_vf2){{1, count}};
iw = w;
ih = h * count;
data = calloc(sizeof(uint32_t), iw * ih);

for (int i = 0; i < count; i++) {
th_image *img = images[i];
uint32_t *d = th_image_get_data(img);
blit(data, iw, ih, d, (w - img->dm.w) / 2, i * h + (h - img->dm.h) / 2,
img->dm.w, img->dm.h);
free(d);
}

break;
}
default: th_error("Unknown packing strategy %d", strategy); return;
}

a->i = th_image_alloc();
th_image_from_data(a->i, data, (th_vf2){{iw, ih}});
}
13 changes: 13 additions & 0 deletions src/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,16 @@ umth_quad_bounding_box(UmkaStackSlot *p, UmkaStackSlot *r)
*o = th_quad_bounding_box(*q);
}

void
umth_atlas_pack(UmkaStackSlot *p, UmkaStackSlot *r)
{
th_atlas *a = p[2].ptrVal;
UmkaDynArray(th_image *) *images = p[1].ptrVal;
th_atlas_pack_strategy strategy = p[0].intVal;

th_atlas_pack(a, images, strategy);
}

void
_th_umka_bind(void *umka)
{
Expand Down Expand Up @@ -1284,6 +1294,9 @@ _th_umka_bind(void *umka)
umkaAddFunc(umka, "umth_quad_max", &umth_quad_max);
umkaAddFunc(umka, "umth_quad_bounding_box", &umth_quad_bounding_box);

// atlas
umkaAddFunc(umka, "umth_atlas_pack", &umth_atlas_pack);

for (int i = 0; i < th_em_modulenames_count; i++) {
umkaAddModule(umka, th_em_modulenames[i], th_em_modulesrc[i]);
}
Expand Down
1 change: 0 additions & 1 deletion src/collisions.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

#include "tophat.h"

#define MAX(a, b) (a > b ? a : b)
#define MIN(a, b) (a < b ? a : b)

int
Expand Down
14 changes: 14 additions & 0 deletions src/staembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -2764,6 +2764,20 @@ const char *th_em_modulesrc[] = {
"\t\tth.Vf2{(at.x+1) / a.dm.x, (at.y+1) / a.dm.y})\n"
"}\n"
"\n"
"const (\n"
"\tPackSquare* = 0\n"
"\tPackRow*\n"
"\tPackColumn*\n"
")\n"
"\n"
"fn umth_atlas_pack(a: ^Atlas, images: ^[]image.Image, strategy: int)\n"
"\n"
"fn pack*(images: []image.Image, strategy: int): Atlas {\n"
"\tvar a: Atlas\n"
"\tumth_atlas_pack(&a, &images, strategy)\n"
"\treturn a\n"
"}\n"
"\n"
"//~~fn Atlas.draw\n"
"// Draws the tile at `at`\n"
"fn (a: ^Atlas) draw*(at: th.Vf2, t: th.Transform) {\n"
Expand Down
1 change: 1 addition & 0 deletions src/thextdata.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
THEXT(void, th_atlas_pack, th_atlas *, void *, th_atlas_pack_strategy);
THEXT(th_vf2, th_atlas_nth_coords, th_atlas *, uu);
THEXT(th_rect, th_atlas_get_cell, th_atlas *, th_vf2);

Expand Down
10 changes: 10 additions & 0 deletions src/tophat.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef uint32_t uu;
typedef int32_t iu;

#define LEN(a) (sizeof(a) / sizeof((a)[0]))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

typedef union
{
Expand Down Expand Up @@ -159,6 +160,13 @@ typedef struct
th_vf2 dm;
} th_atlas;

typedef enum
{
TH_ATLAS_PACK_SQUARE,
TH_ATLAS_PACK_ROW,
TH_ATLAS_PACK_COLUMN
} th_atlas_pack_strategy;

typedef struct
{
th_atlas a;
Expand Down Expand Up @@ -315,6 +323,8 @@ th_ext_set(void **arr)
#ifndef THEXT

// atlas
void
th_atlas_pack(th_atlas *a, void *arr, th_atlas_pack_strategy strategy);
th_vf2
th_atlas_nth_coords(th_atlas *a, uu n);
th_rect
Expand Down
55 changes: 55 additions & 0 deletions tests/packt.um
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

import (
"th.um"
"canvas.um"
"window.um"
"atlas.um"
"image.um"
)

fn drawAtlas(a: atlas.Atlas, p: th.Vf2): th.Vf2 {
a.i.draw({ p: p, s: { 1, 1 } })
idm := a.i.getDims()

for i:=1; i < a.dm.x; i++ {
canvas.drawLine(th.yellow,
{ p.x + i*a.cs.x, p.y },
{ p.x + i*a.cs.x, p.y + idm.y },
2
)
}

for i:=1; i < a.dm.y; i++ {
canvas.drawLine(th.yellow,
{ p.x, p.y + i*a.cs.y },
{ p.x + idm.x, p.y + i*a.cs.y },
2
)
}

return { p.x, p.y + idm.y + 20 }
}

fn init*() {
window.setup("Pack test", 400, 400)

logos := []image.Image{
image.load("etc/logo/logo-hatonly-white.png"),
image.load("etc/logo/logo-hatonly.png"),
image.load("etc/logo/logo-normal-white.png"),
image.load("etc/logo/logo-normal.png"),
image.load("etc/logo/logo-notext-white.png"),
image.load("etc/logo/logo-notext.png")
}

square := atlas.pack(logos, atlas.PackSquare)
row := atlas.pack(logos, atlas.PackRow)
column := atlas.pack(logos, atlas.PackColumn)

window.onFrame.register(|square, row, column| {
p := th.Vf2{ 1, 1 }
p = drawAtlas(square, p)
p = drawAtlas(row, p)
p = drawAtlas(column, p)
})
}
19 changes: 19 additions & 0 deletions umka/atlas.um
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ fn (a: ^Atlas) cropSource*(at: th.Vf2) {
th.Vf2{(at.x+1) / a.dm.x, (at.y+1) / a.dm.y})
}

//~~enum PackStrategy
const (
PackSquare* = 0
PackRow*
PackColumn*
)
//~~

fn umth_atlas_pack(a: ^Atlas, images: ^[]image.Image, strategy: int)

//~~fn pack
// Packs an array of images into an atlas
fn pack*(images: []image.Image, strategy: int): Atlas {
//~~
var a: Atlas
umth_atlas_pack(&a, &images, strategy)
return a
}

//~~fn Atlas.draw
// Draws the tile at `at`
fn (a: ^Atlas) draw*(at: th.Vf2, t: th.Transform) {
Expand Down

0 comments on commit 5dd6898

Please sign in to comment.