27#define _Class _ImageAtlas
40 for (
size_t i = 0; i < this->images->count; i++) {
47 release(this->images);
53#pragma mark - ImageAtlas
67 $(self->
images, addObject, atlasImage);
102 $(self->names, setObjectForKeyPath, atlasImage,
name);
116 return $(self->names, objectForKeyPath,
name);
124 const SDL_Surface *sa = (*(
const AtlasImage **) a)->image.surface;
125 const SDL_Surface *sb = (*(
const AtlasImage **) b)->image.surface;
127 if (sb->h != sa->h) {
128 return sb->h - sa->h;
131 return sb->w - sa->w;
141 int x = 0, y = 0, row = 0;
143 for (
size_t i = 0; i < count; i++) {
147 if (x + surface->w >
size) {
153 if (y + surface->h >
size) {
157 rects[i] = MakeRect(x, y, surface->w, surface->h);
160 row = max(row, surface->h);
174 const size_t count = self->
images->count;
182 SDL_Rect *rects = calloc(count,
sizeof(SDL_Rect));
188 for (
size_t i = 0; i < count; i++) {
189 images[i] = $(self->
images, objectAtIndex, i);
192 area += (size_t) surface->w * (
size_t) surface->h;
193 size = max(
size, max(surface->w, surface->h));
198 size = max(
size, (
int) ceil(sqrt((
double) area)));
201 while (sheetSize <
size) {
206 while (sheetSize <= self->maxSize) {
207 if (
pack(images, rects, count, sheetSize)) {
216 for (
size_t i = 0; i < count; i++) {
217 images[i]->
rect = rects[i];
220 SDL_Surface *sheet = SDL_CreateSurface(sheetSize, sheetSize, SDL_PIXELFORMAT_RGBA32);
223 SDL_FillSurfaceRect(sheet, NULL, 0);
225 for (
size_t i = 0; i < count; i++) {
229 const size_t pitch = surface->w * SDL_BYTESPERPIXEL(surface->format);
231 for (
int y = 0; y < surface->h; y++) {
232 memcpy((Uint8 *) sheet->pixels + (
image->rect.y + y) * sheet->pitch +
image->rect.x * SDL_BYTESPERPIXEL(sheet->format),
233 (
const Uint8 *) surface->pixels + y * surface->pitch,
238 release(self->
image);
242 SDL_DestroySurface(sheet);
244 self->texture = release(self->texture);
265 self->
images = $$(Array, array);
268 self->names = $$(Dictionary, dictionary);
282 self->texture = release(self->texture);
293 if (self->texture == NULL && self->
image) {
294 self->texture = $(device, createTextureFromSurface, self->
image->
surface, SDL_GPU_TEXTUREUSAGE_SAMPLER,
false);
295 assert(self->texture);
298 return self->texture;
301#pragma mark - Class lifecycle
308 ((ObjectInterface *) clazz->interface)->dealloc =
dealloc;
310 ((ImageAtlasInterface *) clazz->interface)->addImage =
addImage;
311 ((ImageAtlasInterface *) clazz->interface)->addImageWithName =
addImageWithName;
313 ((ImageAtlasInterface *) clazz->interface)->compile =
compile;
314 ((ImageAtlasInterface *) clazz->interface)->imageWithName =
imageWithName;
315 ((ImageAtlasInterface *) clazz->interface)->init =
init;
317 ((ImageAtlasInterface *) clazz->interface)->texture =
texture;
329 clazz = _initialize(&(
const ClassDef) {
330 .name =
"ImageAtlas",
331 .superclass = _Object(),
333 .interfaceSize =
sizeof(ImageAtlasInterface),
static AtlasImage * initWithImage(AtlasImage *self, ImageAtlas *atlas, Image *image)
Class * _AtlasImage(void)
static String * name(const Font *self)
static Image * imageWithSurface(SDL_Surface *surface)
static Image * imageWithResourceName(const char *name, float pixelDensity)
static SDL_Size size(const Image *self)
static AtlasImage * addImageWithName(ImageAtlas *self, const char *name, Image *image)
static AtlasImage * imageWithName(const ImageAtlas *self, const char *name)
static void renderDeviceWillReset(ImageAtlas *self)
static ImageAtlas * init(ImageAtlas *self)
static bool compile(ImageAtlas *self)
static AtlasImage * addImageWithResourceName(ImageAtlas *self, const char *name, float pixelDensity)
Class * _ImageAtlas(void)
static Texture * texture(ImageAtlas *self, RenderDevice *device)
static int compareImages(const void *a, const void *b)
Sorts AtlasImages tallest first, then widest, so that shelf rows waste the least.
static void dealloc(Object *self)
static AtlasImage * addImage(ImageAtlas *self, Image *image)
static void initialize(Class *clazz)
static bool pack(AtlasImage **images, SDL_Rect *rects, size_t count, int size)
Lays out the sorted images in shelves on a square of the given size, writing their rects to rects rat...
Packs many Images into one sheet, backed by one Texture.
#define IMAGE_ATLAS_MAX_SIZE
View logging facilities via SDL_Log.
#define MVC_LogError(fmt,...)
static Image * image(Theme *self, const char *name, float pixelDensity)
An Image packed into an ImageAtlas.
SDL_Rect rect
This AtlasImage's rectangle within the atlas sheet, in texels.
Image image
The superclass.
Packs many Images into one sheet, backed by one Texture.
int maxSize
The largest sheet dimension ImageAtlas::compile will attempt.
void renderDeviceWillReset(ImageAtlas *self)
Releases this atlas' Texture ahead of a RenderDevice reset.
Image * image
The compiled sheet, or NULL until ImageAtlas::compile.
Array * images
The AtlasImages, in the order added.
unsigned generation
Incremented by every ImageAtlas::addImageWithName and ImageAtlas::compile, so that anything derived f...
SDL_Surface * surface
The backing surface.