Mercurial > molko
diff libmlk-rpg/mlk/rpg/tileset-loader-file.c @ 552:ffd972a3d084
rpg: major rewrite of tilesets
- Now tilesets can be opened using a custom allocator/loader.
- A default mlk_tileset_loader_file implementation is provided.
- Put a simple example-tileset example to demonstrate.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 07 Mar 2023 20:45:00 +0100 |
parents | |
children | f9e85d0aca74 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/tileset-loader-file.c Tue Mar 07 20:45:00 2023 +0100 @@ -0,0 +1,197 @@ +/* + * tileset-file.c -- tileset file loader implementation + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <string.h> + +#include <mlk/core/alloc.h> +#include <mlk/core/animation.h> +#include <mlk/core/image.h> +#include <mlk/core/sprite.h> +#include <mlk/core/texture.h> + +#include "tileset-loader-file.h" +#include "tileset-loader.h" +#include "tileset.h" + +static inline void * +allocate(void ***array, size_t width) +{ + void **ptr, *elem; + + /* Not yet allocated? Allocate a new pointer element. */ + if (!*array) + ptr = mlk_alloc_new0(1, sizeof (void *)); + else + ptr = mlk_alloc_expand(*array, 1); + + if (!ptr) + return NULL; + + /* Now allocate the element itself because. */ + if (!(elem = mlk_alloc_new0(1, width))) + return NULL; + + /* Store it into the array of elements. */ + ptr[mlk_alloc_getn(ptr) - 1] = elem; + *array = ptr; + + return elem; +} + +static void * +expand(void **array, size_t n, size_t w) +{ + void *ptr; + + if (!*array) + ptr = mlk_alloc_new0(n, w); + else + ptr = mlk_alloc_expand(*array, n); + + if (ptr) + *array = ptr; + + return ptr; +} + +static void +finish(void ***ptr, void (*finish)(void *)) +{ + size_t len; + + /* Already cleared. */ + if (!*ptr) + return; + + len = mlk_alloc_getn(*ptr); + + for (size_t i = 0; i < len; ++i) + finish((*ptr)[i]); + + mlk_alloc_free(*ptr); + *ptr = NULL; +} + +static void +finish_texture(void *element) +{ + mlk_texture_finish(element); + mlk_alloc_free(element); +} + +static struct mlk_texture * +init_texture(struct mlk_tileset_loader *self, const char *ident) +{ + struct mlk_tileset_loader_file *file = self->data; + struct mlk_texture *texture; + char path[MLK_PATH_MAX]; + + snprintf(path, sizeof (path), "%s/%s", file->directory, ident); + + /* No need to deallocate, already done in finish anyway. */ + if (!(texture = allocate((void ***)&file->textures, sizeof (struct mlk_texture)))) + return NULL; + if (mlk_image_open(texture, path) < 0) + return NULL; + + return texture; +} + +static struct mlk_sprite * +init_sprite(struct mlk_tileset_loader *self) +{ + struct mlk_tileset_loader_file *file = self->data; + + return allocate((void ***)&file->sprites, sizeof (struct mlk_sprite)); +} + +static struct mlk_animation * +init_animation(struct mlk_tileset_loader *self) +{ + struct mlk_tileset_loader_file *file = self->data; + + return allocate((void ***)&file->animations, sizeof (struct mlk_animation)); +} + +struct mlk_tileset_collision * +expand_collisions(struct mlk_tileset_loader *self, + struct mlk_tileset_collision *array, + size_t arraysz) +{ + (void)array; + + struct mlk_tileset_loader_file *file = self->data; + + return expand((void **)&file->tilecollisions, arraysz, sizeof (struct mlk_tileset_collision)); +} + +struct mlk_tileset_animation * +expand_animations(struct mlk_tileset_loader *self, + struct mlk_tileset_animation *array, + size_t arraysz) +{ + (void)array; + + struct mlk_tileset_loader_file *file = self->data; + + return expand((void **)&file->tileanimations, arraysz, sizeof (struct mlk_tileset_animation)); +} + +void +mlk_tileset_loader_file_init(struct mlk_tileset_loader_file *file, + struct mlk_tileset_loader *loader, + const char *filename) +{ + assert(file); + assert(loader); + assert(filename); + + char filepath[MLK_PATH_MAX]; + + memset(file, 0, sizeof (*file)); + memset(loader, 0, sizeof (*loader)); + + /* Determine base filename base directory. */ + mlk_util_strlcpy(filepath, filename, sizeof (filepath)); + mlk_util_strlcpy(file->directory, mlk_util_dirname(filepath), sizeof (file->directory)); + + loader->data = file; + loader->init_texture = init_texture; + loader->init_sprite = init_sprite; + loader->init_animation = init_animation; + loader->expand_collisions = expand_collisions; + loader->expand_animations = expand_animations; +} + +void +mlk_tileset_loader_file_finish(struct mlk_tileset_loader_file *file) +{ + assert(file); + + /* Finalize individual elements. */ + finish((void ***)&file->textures, finish_texture); + finish((void ***)&file->sprites, mlk_alloc_free); + finish((void ***)&file->animations, mlk_alloc_free); + + /* Clear array of collisions/animations .*/ + mlk_alloc_free(file->tilecollisions); + mlk_alloc_free(file->tileanimations); + + memset(file, 0, sizeof (*file)); +}