Mercurial > molko
changeset 295:aec448037320
rpg: add support for compressed tilesets/maps
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 10 Mar 2021 16:40:02 +0100 |
parents | 1606b061e4ce |
children | 032aeb430424 |
files | CMakeLists.txt cmake/FindZSTD.cmake libmlk-adventure/adventure/molko.c libmlk-core/CMakeLists.txt libmlk-core/core/zfile.c libmlk-core/core/zfile.h libmlk-rpg/CMakeLists.txt libmlk-rpg/rpg/map-file.c libmlk-rpg/rpg/tileset-file.c |
diffstat | 9 files changed, 253 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Wed Mar 10 13:45:12 2021 +0100 +++ b/CMakeLists.txt Wed Mar 10 16:40:02 2021 +0100 @@ -40,6 +40,7 @@ include(cmake/MolkoDefineTest.cmake) find_package(Jansson REQUIRED) +find_package(ZSTD REQUIRED) find_package(SDL2 REQUIRED COMPONENTS image mixer ttf) find_package(Intl)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/FindZSTD.cmake Wed Mar 10 16:40:02 2021 +0100 @@ -0,0 +1,56 @@ +# +# FindZSTD.cmake -- find ZSTD C library +# +# Copyright (c) 2020 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. +# +# Find ZSTD library, this modules defines: +# +# ZSTD_INCLUDE_DIRS, where to find zstd.h +# ZSTD_LIBRARIES, where to find library +# ZSTD_FOUND, if it is found +# +# The following imported targets will be available: +# +# ZSTD::ZSTD, if found. +# + +find_path(ZSTD_INCLUDE_DIR NAMES zstd.h) +find_library(ZSTD_LIBRARY NAMES libzstd zstd) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + ZSTD + FOUND_VAR ZSTD_FOUND + REQUIRED_VARS ZSTD_LIBRARY ZSTD_INCLUDE_DIR +) + +if (ZSTD_FOUND) + set(ZSTD_LIBRARIES ${ZSTD_LIBRARY}) + set(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR}) + + if (NOT TARGET ZSTD::ZSTD) + add_library(ZSTD::ZSTD UNKNOWN IMPORTED) + set_target_properties( + ZSTD::ZSTD + PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${ZSTD_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${ZSTD_INCLUDE_DIRS}" + ) + endif () +endif () + +mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
--- a/libmlk-adventure/adventure/molko.c Wed Mar 10 13:45:12 2021 +0100 +++ b/libmlk-adventure/adventure/molko.c Wed Mar 10 16:40:02 2021 +0100 @@ -99,7 +99,7 @@ molko.team.members[0] = &character_neth; molko.team.members[1] = &character_neth; inventory_add(&molko.inventory, &item_potion, 100); - molko_teleport("maps/map-world.map", -1, -1); + molko_teleport("maps/map-world.map.zst", -1, -1); #endif }
--- a/libmlk-core/CMakeLists.txt Wed Mar 10 13:45:12 2021 +0100 +++ b/libmlk-core/CMakeLists.txt Wed Mar 10 16:40:02 2021 +0100 @@ -84,6 +84,8 @@ ${libmlk-core_SOURCE_DIR}/core/window.c ${libmlk-core_SOURCE_DIR}/core/window.h ${libmlk-core_SOURCE_DIR}/core/window_p.h + ${libmlk-core_SOURCE_DIR}/core/zfile.c + ${libmlk-core_SOURCE_DIR}/core/zfile.h ) configure_file(
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-core/core/zfile.c Wed Mar 10 16:40:02 2021 +0100 @@ -0,0 +1,126 @@ +/* + * zfile.c -- load potentially ZSTD compressed file + * + * Copyright (c) 2020 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 <sys/stat.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <zstd.h> + +#include "zfile.h" + +static int +is_zstd(int fd) +{ + uint32_t magic = 0; + + read(fd, &magic, sizeof (magic)); + lseek(fd, 0, SEEK_SET); + +#if SDL_BYTEORDER != SDL_LIL_ENDIAN + magic = SDL_Swap32(magic); +#endif + + return magic == ZSTD_MAGICNUMBER; +} + +static int +decompress(int fd, struct zfile *zf) +{ + char *in = NULL; + unsigned long long datasz; + struct stat st; + + /* Load uncompressed data. */ + if (fstat(fd, &st) < 0) + goto fail; + if (!(in = calloc(1, st.st_size)) || read(fd, in, st.st_size) != st.st_size) + goto fail; + + switch ((datasz = ZSTD_getFrameContentSize(in, st.st_size))) { + case ZSTD_CONTENTSIZE_ERROR: + errno = EINVAL; + goto fail; + case ZSTD_CONTENTSIZE_UNKNOWN: + errno = ENOTSUP; + goto fail; + default: + break; + } + + /* Finally decompress. */ + if (!(zf->data = calloc(1, datasz + 1))) + goto fail; + if (ZSTD_isError(ZSTD_decompress(zf->data, datasz, in, st.st_size))) { + errno = EINVAL; + goto fail; + } + if (!(zf->fp = fmemopen(zf->data, datasz, "r"))) + goto fail; + + close(fd); + free(in); + + return 0; + +fail: + close(fd); + free(zf->data); + free(in); + + return -1; +} + +static int +reopen(int fd, struct zfile *zf) +{ + if (!(zf->fp = fdopen(fd, "r"))) + return close(fd), -1; + + return 0; +} + +int +zfile_open(struct zfile *zf, const char *path) +{ + assert(zf); + assert(path); + + int fd, status; + + memset(zf, 0, sizeof (*zf)); + + if ((fd = open(path, O_RDONLY)) < 0) + return -1; + + return is_zstd(fd) ? decompress(fd, zf) : reopen(fd, zf); +} + +void +zfile_close(struct zfile *zf) +{ + assert(zf); + + free(zf->data); + fclose(zf->fp); + memset(zf, 0, sizeof (*zf)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-core/core/zfile.h Wed Mar 10 16:40:02 2021 +0100 @@ -0,0 +1,41 @@ +/* + * zfile.h -- load potentially ZSTD compressed file + * + * Copyright (c) 2020 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. + */ + +#ifndef MOLKO_CORE_ZFILE_H +#define MOLKO_CORE_ZFILE_H + +#include <stdio.h> + +#include "core.h" + +struct zfile { + FILE *fp; + char *data; +}; + +CORE_BEGIN_DECLS + +int +zfile_open(struct zfile *, const char *); + +void +zfile_close(struct zfile *); + +CORE_END_DECLS + +#endif /* !MOLKO_CORE_ZFILE_H */
--- a/libmlk-rpg/CMakeLists.txt Wed Mar 10 13:45:12 2021 +0100 +++ b/libmlk-rpg/CMakeLists.txt Wed Mar 10 16:40:02 2021 +0100 @@ -105,6 +105,7 @@ SOURCES ${SOURCES} ${PO} ${ASSETS} LIBRARIES PUBLIC + ZSTD::ZSTD libmlk-core libmlk-ui INCLUDES
--- a/libmlk-rpg/rpg/map-file.c Wed Mar 10 13:45:12 2021 +0100 +++ b/libmlk-rpg/rpg/map-file.c Wed Mar 10 16:40:02 2021 +0100 @@ -29,6 +29,7 @@ #include <core/error.h> #include <core/image.h> #include <core/trace.h> +#include <core/zfile.h> #include "map-file.h" #include "rpg_p.h" @@ -271,24 +272,31 @@ .mf = file, .map = map, }; + struct zfile zf; bool ret = true; memset(map, 0, sizeof (*map)); if (!alloc_pool_init(&file->blocks, sizeof (*map->blocks), NULL)) - return false; + goto fail; + if (zfile_open(&zf, path) < 0) + goto fail; - if (!(ctx.fp = fopen(path, "r"))) - return errorf("%s: %s", path, strerror(errno)); + ctx.fp = zf.fp; + + if (!(ret = parse(&ctx, path)) || !(ret = check(map))) + goto fail; - if (!(ret = parse(&ctx, path)) || !(ret = check(map))) { - map_finish(map); - map_file_finish(file); - } + zfile_close(&zf); + + return true; - fclose(ctx.fp); +fail: + map_finish(map); + map_file_finish(file); + zfile_close(&zf); - return ret; + return false; } void
--- a/libmlk-rpg/rpg/tileset-file.c Wed Mar 10 13:45:12 2021 +0100 +++ b/libmlk-rpg/rpg/tileset-file.c Wed Mar 10 16:40:02 2021 +0100 @@ -30,6 +30,7 @@ #include <core/error.h> #include <core/image.h> #include <core/util.h> +#include <core/zfile.h> #include "rpg_p.h" #include "tileset-file.h" @@ -310,15 +311,21 @@ .tf = tf, .tileset = tileset }; + struct zfile zf; bool ret = true; memset(tileset, 0, sizeof (*tileset)); - if (!(ctx.fp = fopen(path, "r"))) + if (zfile_open(&zf, path) < 0) return errorf("%s: %s", path, strerror(errno)); + + ctx.fp = zf.fp; + if (!(ret = parse(&ctx, path)) || !(ret = check(tileset))) tileset_file_finish(tf); + zfile_close(&zf); + return ret; }