# HG changeset patch # User David Demelier # Date 1693128515 -7200 # Node ID bb67f935a93f68df2526ac3282e168d66312dd87 # Parent 8d8fe99b357c6ad50b69fa1165ed239ac5037d77 rpg: rework a little tileset/map loaders diff -r 8d8fe99b357c -r bb67f935a93f examples/example-map/example-map.c --- a/examples/example-map/example-map.c Sun Aug 27 11:04:57 2023 +0200 +++ b/examples/example-map/example-map.c Sun Aug 27 11:28:35 2023 +0200 @@ -59,7 +59,7 @@ static struct mlk_tileset_loader_file tileset_loader; static struct mlk_tileset tileset; -static struct mlk_map_loader map_loader; +static struct mlk_map_loader_file map_loader; static struct mlk_map map; static struct { @@ -165,11 +165,11 @@ * on disk by default which we would like to avoid. We override the * init_tileset function. */ - mlk_map_loader_file_init(&map_loader, ""); - map_loader.new_tileset = map_new_tileset; - map_loader.new_texture = map_new_texture; + mlk_map_loader_file_init(&map_loader, &tileset_loader.iface, ""); + map_loader.iface.new_tileset = map_new_tileset; + map_loader.iface.new_texture = map_new_texture; - if (mlk_map_loader_openmem(&map_loader, &map, assets_maps_world, sizeof (assets_maps_world)) < 0) + if (mlk_map_loader_openmem(&map_loader.iface, &map, assets_maps_world, sizeof (assets_maps_world)) < 0) mlk_panic(); mlk_map_init(&map); @@ -250,8 +250,8 @@ quit(void) { mlk_map_finish(&map); - mlk_map_loader_file_finish(&map_loader); - mlk_tileset_loader_file_finish(&tileset_loader); + mlk_map_loader_finish(&map_loader.iface); + mlk_tileset_loader_finish(&tileset_loader.iface); mlk_example_finish(); } diff -r 8d8fe99b357c -r bb67f935a93f examples/example-tileset/example-tileset.c --- a/examples/example-tileset/example-tileset.c Sun Aug 27 11:04:57 2023 +0200 +++ b/examples/example-tileset/example-tileset.c Sun Aug 27 11:28:35 2023 +0200 @@ -201,7 +201,7 @@ static void quit(void) { - mlk_tileset_loader_file_finish(&loader); + mlk_tileset_loader_finish(&loader.iface); mlk_example_finish(); } diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/loader-file_p.c --- a/libmlk-rpg/mlk/rpg/loader-file_p.c Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/loader-file_p.c Sun Aug 27 11:28:35 2023 +0200 @@ -161,13 +161,19 @@ } void -mlk__loader_file_free(struct mlk__loader_file *loader) +mlk__loader_file_clear(struct mlk__loader_file *loader) { - assert(loader); - free_textures(loader); free_sprites(loader); free_animations(loader); +} +void +mlk__loader_file_free(struct mlk__loader_file *loader) +{ + if (!loader) + return; + + mlk__loader_file_clear(loader); mlk_alloc_free(loader); } diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/loader-file_p.h --- a/libmlk-rpg/mlk/rpg/loader-file_p.h Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/loader-file_p.h Sun Aug 27 11:28:35 2023 +0200 @@ -41,6 +41,9 @@ mlk__loader_file_animation_new(struct mlk__loader_file *loader); void +mlk__loader_file_clear(struct mlk__loader_file *loader); + +void mlk__loader_file_free(struct mlk__loader_file *loader); #endif /* !MLK_RPG_LOADER_FILE_P_H */ diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/map-loader-file.c --- a/libmlk-rpg/mlk/rpg/map-loader-file.c Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/map-loader-file.c Sun Aug 27 11:28:35 2023 +0200 @@ -26,174 +26,152 @@ #include #include #include +#include #include "loader-file_p.h" #include "map-loader-file.h" -#include "map-loader.h" #include "map.h" #include "tileset-loader-file.h" #include "tileset-loader.h" -#include "tileset.h" -struct self { - /* Resources allocator. */ - struct mlk__loader_file *loader; - - /* Own allocated tiles. */ - unsigned int *tiles[MLK_MAP_LAYER_TYPE_LAST]; +#define THIS(loader) \ + MLK_CONTAINER_OF(loader, struct mlk_map_loader_file, iface) - /* - * We use a tileset file loader if new_tileset function isn't present in - * this map loader. - */ - struct mlk_tileset_loader_file tileset_loader; - struct mlk_tileset tileset; - - /* Own allocated blocks. */ - struct mlk_map_block *blocks; -}; +static void +trash(struct mlk_map_loader_file *file) +{ + mlk__loader_file_clear(file->lf); -static struct self * -self_new(const char *path) -{ - struct self *self; - - if (!(self = mlk_alloc_new0(1, sizeof (*self)))) - return NULL; - if (!(self->loader = mlk__loader_file_new(path))) { - mlk_alloc_free(self); - return NULL; + for (int i = 0; i < MLK_MAP_LAYER_TYPE_LAST; ++i) { + mlk_alloc_free(file->tiles[i]); + file->tiles[i] = NULL; } - return self; -} + mlk_alloc_free(file->blocks); -static void -self_free(struct self *self) -{ - mlk__loader_file_free(self->loader); - - for (int i = 0; i < MLK_MAP_LAYER_TYPE_LAST; ++i) - mlk_alloc_free(self->tiles[i]); - - mlk_tileset_loader_file_finish(&self->tileset_loader); - mlk_alloc_free(self->blocks); + file->blocks = NULL; } static struct mlk_texture * -new_texture(struct mlk_map_loader *loader, - struct mlk_map *map, - const char *ident) +new_texture(struct mlk_map_loader *self, struct mlk_map *map, const char *ident) { (void)map; - struct self *self = loader->data; + struct mlk_map_loader_file *file = THIS(self); - return mlk__loader_file_texture_open(self->loader, ident); + return mlk__loader_file_texture_open(file->lf, ident); } static struct mlk_sprite * -new_sprite(struct mlk_map_loader *loader, struct mlk_map *map) +new_sprite(struct mlk_map_loader *self, struct mlk_map *map) { (void)map; - struct self *self = loader->data; + struct mlk_map_loader_file *file = THIS(self); - return mlk__loader_file_sprite_new(self->loader); + return mlk__loader_file_sprite_new(file->lf); } static struct mlk_tileset * -new_tileset(struct mlk_map_loader *loader, - struct mlk_map *map, - const char *ident) +new_tileset(struct mlk_map_loader *self, struct mlk_map *map, const char *ident) { (void)map; - struct self *self = loader->data; - char path[MLK_PATH_MAX]; + struct mlk_map_loader_file *file = THIS(self); + char path[MLK_PATH_MAX] = {}; - snprintf(path, sizeof (path), "%s/%s", mlk__loader_file_directory(self->loader), ident); + snprintf(path, sizeof (path), "%s/%s", mlk__loader_file_directory(file->lf), ident); /* - * Just make sure that we don't leak in case tileset directory is listed - * more than once. + * Cleanup existing resources in case the tileset appears multiple times + * in the map. */ - mlk_tileset_loader_file_finish(&self->tileset_loader); - mlk_tileset_loader_file_init(&self->tileset_loader, path); + mlk_tileset_loader_clear(file->tileset_loader, &file->tileset); - if (mlk_tileset_loader_open(&self->tileset_loader.iface, &self->tileset, path) < 0) + if (mlk_tileset_loader_open(file->tileset_loader, &file->tileset, path) < 0) return NULL; - return &self->tileset; + return &file->tileset; } static unsigned int * -new_tiles(struct mlk_map_loader *loader, +new_tiles(struct mlk_map_loader *self, struct mlk_map *map, enum mlk_map_layer_type type, size_t n) { (void)map; - struct self *self = loader->data; + struct mlk_map_loader_file *file = THIS(self); - return self->tiles[type] = mlk_alloc_new0(n, sizeof (unsigned int)); + return file->tiles[type] = mlk_alloc_new0(n, sizeof (unsigned int)); } static struct mlk_map_block * -expand_blocks(struct mlk_map_loader *loader, +expand_blocks(struct mlk_map_loader *self, struct mlk_map *map, struct mlk_map_block *blocks, size_t blocksz) { (void)map; - struct self *self = loader->data; + struct mlk_map_loader_file *file = THIS(self); struct mlk_map_block *ptr; - if (!self->blocks) + if (!file->blocks) ptr = mlk_alloc_new0(1, sizeof (*ptr)); else - ptr = mlk_alloc_expand(self->blocks, blocksz); + ptr = mlk_alloc_expand(file->blocks, blocksz); if (ptr) - self->blocks = blocks; + file->blocks = blocks; return ptr; } +static void +clear(struct mlk_map_loader *self, struct mlk_map *map) +{ + (void)map; + + struct mlk_map_loader_file *file = THIS(self); + + trash(file); +} + +static void +finish(struct mlk_map_loader *self) +{ + struct mlk_map_loader_file *file = THIS(self); + + trash(file); + mlk__loader_file_free(file->lf); + + file->lf = NULL; +} + int -mlk_map_loader_file_init(struct mlk_map_loader *loader, const char *filename) +mlk_map_loader_file_init(struct mlk_map_loader_file *file, + struct mlk_tileset_loader *tileset_loader, + const char *filename) { - assert(loader); + assert(file); + assert(tileset_loader); assert(filename); - struct self *self; + memset(file, 0, sizeof (*file)); - memset(loader, 0, sizeof (*loader)); - - if (!(self = self_new(filename))) + if (!(file->lf = mlk__loader_file_new(filename))) return -1; - loader->data = self; - loader->new_tileset = new_tileset; - loader->new_texture = new_texture; - loader->new_sprite = new_sprite; - loader->new_tiles = new_tiles; - loader->expand_blocks = expand_blocks; + file->tileset_loader = tileset_loader; + file->iface.new_tileset = new_tileset; + file->iface.new_texture = new_texture; + file->iface.new_sprite = new_sprite; + file->iface.new_tiles = new_tiles; + file->iface.expand_blocks = expand_blocks; + file->iface.clear = clear; + file->iface.finish = finish; return 0; } - -void -mlk_map_loader_file_finish(struct mlk_map_loader *loader) -{ - assert(loader); - - struct self *self = loader->data; - - if (self) - self_free(self); - - memset(loader, 0, sizeof (*loader)); -} diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/map-loader-file.h --- a/libmlk-rpg/mlk/rpg/map-loader-file.h Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/map-loader-file.h Sun Aug 27 11:28:35 2023 +0200 @@ -28,21 +28,20 @@ * on the go depending on the file map content. * * For convenience, this loader will also use ::mlk_tileset_loader for loading - * and associating the tileset. If this behavior is not desired the function - * ::mlk_map_loader::new_tileset can be overriden after calling - * ::mlk_map_loader_file_init. + * and associating the tileset. * * Example of use: * * ```c - * struct mlk_map_loader loader; + * struct mlk_tileset_loader_file tileset_loader; + * struct mlk_map_loader_file map_loader; * struct mlk_map map; * * // The loader needs to know the map location to retrieve relative files. * const char *map_path = "/path/to/world.map"; * * // Initialize the loader, it will be filled with custom internal functions. - * if (mlk_map_loader_file_init(&loader, map_path) < 0) + * if (mlk_map_loader_file_init(&map_loader, &tileset_loader.iface, map_path) < 0) * mlk_panic(); * * // Load the map from the file on disk. @@ -54,11 +53,33 @@ * * // Destroy the resources. * mlk_map_finish(&map); - * mlk_map_loader_file_finish(&loader); + * mlk_map_loader_file_finish(&map_loader); + * mlk_tileset_loader_file_finish(&tileset_loader); * ``` */ -struct mlk_map_loader; +#include "map-loader.h" +#include "map.h" +#include "tileset.h" + +struct mlk_tileset_loader; + +struct mlk_map_loader_file { + /** + * (read-write) + * + * Underlying map loader. + */ + struct mlk_map_loader iface; + + /** \cond MLK_PRIVATE_DECLS */ + unsigned int *tiles[MLK_MAP_LAYER_TYPE_LAST]; + struct mlk_tileset_loader *tileset_loader; + struct mlk_tileset tileset; + struct mlk_map_block *blocks; + struct mlk__loader_file *lf; + /** \endcond MLK_PRIVATE_DECLS */ +}; /** * Initialize the loader with internal functions and internal data to allocate @@ -67,23 +88,19 @@ * After loading the map with this underlying loader, it should be kept until * the map is no longer used. * - * \pre loader != NULL + * The tileset loader is borrowed and not destroyed when this loader is + * destroyed, user must do it manually. + * + * \pre file != NULL * \pre filename != NULL - * \param loader the abstract loader interface + * \param file the file loader + * \param tileset_loader tileset loader interface (borrowed) * \param filename path to the map file * \return 0 on success or -1 on error */ int -mlk_map_loader_file_init(struct mlk_map_loader *loader, const char *filename); - -/** - * Cleanup allocated resources by this file loader. - * - * \pre file != NULL - * \param file the file loader - * \warning the map loaded with this loader must not be used - */ -void -mlk_map_loader_file_finish(struct mlk_map_loader *file); +mlk_map_loader_file_init(struct mlk_map_loader_file *file, + struct mlk_tileset_loader *tileset_loader, + const char *filename); #endif /* !MLK_RPG_MAP_LOADER_FILE_H */ diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/map-loader.c --- a/libmlk-rpg/mlk/rpg/map-loader.c Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/map-loader.c Sun Aug 27 11:28:35 2023 +0200 @@ -327,3 +327,25 @@ return parse(loader, map, fp); } + +void +mlk_map_loader_clear(struct mlk_map_loader *loader, + struct mlk_map *map) +{ + assert(loader); + assert(map); + + if (loader->clear) + loader->clear(loader, map); + + memset(map, 0, sizeof (*map)); +} + +void +mlk_map_loader_finish(struct mlk_map_loader *loader) +{ + assert(loader); + + if (loader->finish) + loader->finish(loader); +} diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/map-loader.h --- a/libmlk-rpg/mlk/rpg/map-loader.h Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/map-loader.h Sun Aug 27 11:28:35 2023 +0200 @@ -140,6 +140,28 @@ struct mlk_map *map, struct mlk_map_block *blocks, size_t blocksz); + + /** + * (read-write, optional) + * + * Cleanup resources allocated for this mao. + * + * This is different than finalizing the loader itself, it should be + * re-usable after calling this function. + * + * \param self this loader + * \param map the underlying map to cleanup + */ + void (*clear)(struct mlk_map_loader *self, struct mlk_map *map); + + /** + * (read-write, optional) + * + * Cleanup the map loader. + * + * \param self this loader + */ + void (*finish)(struct mlk_map_loader *self); }; #if defined(__cplusplus) @@ -179,6 +201,34 @@ const void *data, size_t datasz); +/** + * Cleanup data for this map. + * + * The loader is re-usable after calling this function to load a new map. + * + * Invokes ::mlk_map_loader::clear. + * + * \pre loader != NULL + * \param loader the loader interface + * \param map the map used with this loader + */ +void +mlk_map_loader_clear(struct mlk_map_loader *loader, struct mlk_map *map); + +/** + * Finalize the loader itself. + * + * The underlying interface should also clear map resources by convenience + * if the user forgot to call ::mlk_map_loader_clear. + * + * Invokes ::mlk_map_loader::finish. + * + * \pre loader != NULL + * \param loader the loader to finalize + */ +void +mlk_map_loader_finish(struct mlk_map_loader *loader); + #if defined(__cplusplus) } #endif diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/tileset-loader-file.c --- a/libmlk-rpg/mlk/rpg/tileset-loader-file.c Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/tileset-loader-file.c Sun Aug 27 11:28:35 2023 +0200 @@ -1,5 +1,5 @@ /* - * tileset-file.c -- tileset file loader implementation + * tileset-loader-file.c -- tileset file loader implementation * * Copyright (c) 2020-2023 David Demelier * @@ -34,6 +34,18 @@ #define THIS(loader) \ MLK_CONTAINER_OF(loader, struct mlk_tileset_loader_file, iface) +static void +trash(struct mlk_tileset_loader_file *file) +{ + mlk__loader_file_clear(file->lf); + + mlk_alloc_free(file->tilecollisions); + mlk_alloc_free(file->tileanimations); + + file->tilecollisions = NULL; + file->tileanimations = NULL; +} + static void * expand(void **array, size_t n, size_t w) { @@ -51,37 +63,37 @@ } static struct mlk_texture * -new_texture(struct mlk_tileset_loader *loader, struct mlk_tileset *tileset, const char *ident) +new_texture(struct mlk_tileset_loader *self, struct mlk_tileset *tileset, const char *ident) { (void)tileset; - struct mlk_tileset_loader_file *self = THIS(loader); + struct mlk_tileset_loader_file *file = THIS(self); - return mlk__loader_file_texture_open(self->lf, ident); + return mlk__loader_file_texture_open(file->lf, ident); } static struct mlk_sprite * -new_sprite(struct mlk_tileset_loader *loader, struct mlk_tileset *tileset) +new_sprite(struct mlk_tileset_loader *self, struct mlk_tileset *tileset) { (void)tileset; - struct mlk_tileset_loader_file *self = THIS(loader); + struct mlk_tileset_loader_file *file = THIS(self); - return mlk__loader_file_sprite_new(self->lf); + return mlk__loader_file_sprite_new(file->lf); } static struct mlk_animation * -new_animation(struct mlk_tileset_loader *loader, struct mlk_tileset *tileset) +new_animation(struct mlk_tileset_loader *self, struct mlk_tileset *tileset) { (void)tileset; - struct mlk_tileset_loader_file *self = THIS(loader); + struct mlk_tileset_loader_file *file = THIS(self); - return mlk__loader_file_animation_new(self->lf); + return mlk__loader_file_animation_new(file->lf); } struct mlk_tileset_collision * -expand_collisions(struct mlk_tileset_loader *loader, +expand_collisions(struct mlk_tileset_loader *self, struct mlk_tileset *tileset, struct mlk_tileset_collision *array, size_t arraysz) @@ -89,13 +101,13 @@ (void)tileset; (void)array; - struct mlk_tileset_loader_file *self = THIS(loader); + struct mlk_tileset_loader_file *file = THIS(self); - return expand((void **)&self->tilecollisions, arraysz, sizeof (struct mlk_tileset_collision)); + return expand((void **)&file->tilecollisions, arraysz, sizeof (struct mlk_tileset_collision)); } struct mlk_tileset_animation * -expand_animations(struct mlk_tileset_loader *loader, +expand_animations(struct mlk_tileset_loader *self, struct mlk_tileset *tileset, struct mlk_tileset_animation *array, size_t arraysz) @@ -103,9 +115,30 @@ (void)tileset; (void)array; - struct mlk_tileset_loader_file *self = THIS(loader); + struct mlk_tileset_loader_file *file = THIS(self); + + return expand((void **)&file->tileanimations, arraysz, sizeof (struct mlk_tileset_animation)); +} + +static void +clear(struct mlk_tileset_loader *self, struct mlk_tileset *tileset) +{ + (void)tileset; + + struct mlk_tileset_loader_file *file = THIS(self); - return expand((void **)&self->tileanimations, arraysz, sizeof (struct mlk_tileset_animation)); + trash(file); +} + +static void +finish(struct mlk_tileset_loader *self) +{ + struct mlk_tileset_loader_file *file = THIS(self); + + trash(file); + mlk__loader_file_free(file->lf); + + file->lf = NULL; } int @@ -124,19 +157,8 @@ file->iface.new_animation = new_animation; file->iface.expand_collisions = expand_collisions; file->iface.expand_animations = expand_animations; + file->iface.clear = clear; + file->iface.finish = finish; return 0; } - -void -mlk_tileset_loader_file_finish(struct mlk_tileset_loader_file *file) -{ - assert(file); - - mlk__loader_file_free(file->lf); - - mlk_alloc_free(file->tilecollisions); - mlk_alloc_free(file->tileanimations); - - memset(file, 0, sizeof (*file)); -} diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/tileset-loader-file.h --- a/libmlk-rpg/mlk/rpg/tileset-loader-file.h Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/tileset-loader-file.h Sun Aug 27 11:28:35 2023 +0200 @@ -37,6 +37,10 @@ struct mlk_tileset_animation; struct mlk__loader_file; +/** + * \struct mlk_tileset_loader_file + * \brief Tileset loader from file. + */ struct mlk_tileset_loader_file { /** * (read-write) @@ -57,30 +61,21 @@ #endif /** - * Initialize the loader with internal functions and internal data to allocate - * and find appropriate resources relative to the tileset filename. + * Initialize this file loader and the underlying abstract tileset loader + * interface. * * After loading the tileset with this underlying loader, it should be kept * until the tileset is no longer used. * * \pre file != NULL * \pre filename != NULL - * \param file the abstract loader interface + * \param file the file loader * \param filename path to the tileset file * \return 0 on success or -1 on error */ int mlk_tileset_loader_file_init(struct mlk_tileset_loader_file *file, const char *filename); -/** - * Cleanup allocated resources by this file loader. - * - * \pre file != NULL - * \param file the file loader - */ -void -mlk_tileset_loader_file_finish(struct mlk_tileset_loader_file *file); - #if defined(__cplusplus) } #endif diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/tileset-loader.c --- a/libmlk-rpg/mlk/rpg/tileset-loader.c Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/tileset-loader.c Sun Aug 27 11:28:35 2023 +0200 @@ -316,3 +316,25 @@ return parse(loader, tileset, fp); } + +void +mlk_tileset_loader_clear(struct mlk_tileset_loader *loader, + struct mlk_tileset *tileset) +{ + assert(loader); + assert(tileset); + + if (loader->clear) + loader->clear(loader, tileset); + + memset(tileset, 0, sizeof (*tileset)); +} + +void +mlk_tileset_loader_finish(struct mlk_tileset_loader *loader) +{ + assert(loader); + + if (loader->finish) + loader->finish(loader); +} diff -r 8d8fe99b357c -r bb67f935a93f libmlk-rpg/mlk/rpg/tileset-loader.h --- a/libmlk-rpg/mlk/rpg/tileset-loader.h Sun Aug 27 11:04:57 2023 +0200 +++ b/libmlk-rpg/mlk/rpg/tileset-loader.h Sun Aug 27 11:28:35 2023 +0200 @@ -25,20 +25,17 @@ * * This module provides a generic way to open tilesets. It uses a callback * system whenever an action has to be taken by the user. by itself, this - * module does not alloate nor owns any data. + * module does not allocate nor owns any data. * * It is designed in mind that the loader knows how to decode a tileset data * format file but has no indication on how it should allocate, arrange and * find tileset images and other resources. * - * See tileset-file.h for an implementation of this module using files. + * See tileset-loader-file.h for an implementation of this module using files. */ #include -struct mlk_animation; -struct mlk_sprite; -struct mlk_texture; struct mlk_tileset; struct mlk_tileset_animations; struct mlk_tileset_collision; @@ -126,6 +123,28 @@ struct mlk_tileset_animation *array, size_t arraysz); + /** + * (read-write, optional) + * + * Cleanup resources allocated for this tileset. + * + * This is different than finalizing the loader itself, it should be + * re-usable after calling this function. + * + * \param self this loader + * \param tileset the underlying tileset to cleanup + */ + void (*clear)(struct mlk_tileset_loader *self, struct mlk_tileset *tileset); + + /** + * (read-write, optional) + * + * Cleanup the tileset loader. + * + * \param self this loader + */ + void (*finish)(struct mlk_tileset_loader *self); + /** \cond MLK_PRIVATE_DECLS */ unsigned int tilewidth; unsigned int tileheight; @@ -173,6 +192,35 @@ const void *data, size_t datasz); +/** + * Cleanup data for this tileset. + * + * The loader is re-usable after calling this function to load a new tileset. + * + * Invokes ::mlk_tileset_loader::clear. + * + * \pre loader != NULL + * \param loader the loader interface + * \param tileset the tileset used with this loader + */ +void +mlk_tileset_loader_clear(struct mlk_tileset_loader *loader, + struct mlk_tileset *tileset); + +/** + * Finalize the loader itself. + * + * The underlying interface should also clear tileset resources by convenience + * if the user forgot to call ::mlk_tileset_loader_clear. + * + * Invokes ::mlk_tileset_loader::finish. + * + * \pre loader != NULL + * \param loader the loader to finalize + */ +void +mlk_tileset_loader_finish(struct mlk_tileset_loader *loader); + #if defined(__cplusplus) } #endif diff -r 8d8fe99b357c -r bb67f935a93f tests/test-tileset.c --- a/tests/test-tileset.c Sun Aug 27 11:04:57 2023 +0200 +++ b/tests/test-tileset.c Sun Aug 27 11:28:35 2023 +0200 @@ -46,7 +46,7 @@ static inline void tileset_finish(struct tileset *ts) { - mlk_tileset_loader_file_finish(&ts->loader); + mlk_tileset_loader_finish(&ts->loader.iface); } static void @@ -85,6 +85,27 @@ } static void +test_basics_clear(struct tileset *ts) +{ + DT_EQ_INT(tileset_open(ts, DIRECTORY "/maps/sample-tileset.tileset"), 0); + + /* Do not test everything, already done in basics. */ + DT_EQ_UINT(ts->tileset.sprite->cellw, 64U); + DT_EQ_UINT(ts->tileset.sprite->cellh, 32U); + + /* Make sure we can clear and open again. */ + mlk_tileset_loader_clear(&ts->loader.iface, &ts->tileset); + + /* Check that it was zero'ed. */ + DT_EQ_PTR(ts->tileset.sprite, NULL); + + /* Now it should open our tileset again. */ + DT_EQ_INT(mlk_tileset_loader_open(&ts->loader.iface, &ts->tileset, DIRECTORY "/maps/sample-tileset.tileset"), 0); + DT_EQ_UINT(ts->tileset.sprite->cellw, 64U); + DT_EQ_UINT(ts->tileset.sprite->cellh, 32U); +} + +static void test_error_tilewidth(struct tileset *ts) { DT_EQ_INT(tileset_open(ts, DIRECTORY "/maps/error-tilewidth.tileset"), -1); @@ -126,6 +147,7 @@ return 1; DT_RUN_EX(test_basics_sample, setup, teardown, &ts); + DT_RUN_EX(test_basics_clear, setup, teardown, &ts); DT_RUN_EX(test_error_tilewidth, setup, teardown, &ts); DT_RUN_EX(test_error_tileheight, setup, teardown, &ts); DT_RUN_EX(test_error_image, setup, teardown, &ts);