Fixed loading of tilesets and images from tilemaps to correctly use relative paths.

This commit is contained in:
2026-05-24 09:51:58 -04:00
parent e3edd5b855
commit 980bbc56fb
8 changed files with 143 additions and 29 deletions

View File

@@ -1,5 +1,6 @@
#include <akerror.h>
#include <akgl/staticstring.h>
#include <errno.h>
akerr_ErrorContext *akgl_string_initialize(akgl_String *obj, char *init)
{
@@ -13,3 +14,17 @@ akerr_ErrorContext *akgl_string_initialize(akgl_String *obj, char *init)
obj->refcount = 1;
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_string_copy(akgl_String *src, akgl_String *dst, int count)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, src, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(e, dst, AKERR_NULLPOINTER, "NULL argument");
if ( count == 0 ) {
count = AKGL_MAX_STRING_LENGTH;
}
if ( (char *)dst->data != strncpy((char *)&src->data, (char *)&dst->data, count) ) {
FAIL_RETURN(e, errno, "strncpy");
}
SUCCEED_RETURN(e);
}

View File

@@ -1,9 +1,13 @@
#include <string.h>
#include <libgen.h>
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <SDL3_mixer/SDL_mixer.h>
#include <string.h>
#include <jansson.h>
#include <akerror.h>
#include <akstdlib.h>
#include <akgl/tilemap.h>
#include <akgl/actor.h>
@@ -13,6 +17,7 @@
#include <akgl/staticstring.h>
#include <akgl/game.h>
akerr_ErrorContext *akgl_get_json_tilemap_property(json_t *obj, char *key, char *type, json_t **dest)
{
PREPARE_ERROR(errctx);
@@ -96,7 +101,7 @@ akerr_ErrorContext *akgl_get_json_properties_number(json_t *obj, char *key, floa
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilemap *dest, int tsidx)
akerr_ErrorContext *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilemap *dest, int tsidx, akgl_String *dirname)
{
PREPARE_ERROR(errctx);
akgl_String *tmpstr = NULL;
@@ -118,13 +123,15 @@ akerr_ErrorContext *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilema
);
CATCH(errctx, akgl_get_json_string_value((json_t *)tileset, "image", &tmpstr));
DISABLE_GCC_WARNING_FORMAT_TRUNCATION
snprintf((char *)&dest->tilesets[tsidx].imagefilename,
AKGL_TILEMAP_MAX_TILESET_FILENAME_SIZE,
"%s%s",
SDL_GetBasePath(),
"%s/%s",
dirname->data,
tmpstr->data
);
RESTORE_GCC_WARNINGS
dest->tilesets[tsidx].texture = IMG_LoadTexture(renderer, (char *)&dest->tilesets[tsidx].imagefilename);
FAIL_ZERO_BREAK(errctx, dest->tilesets[tsidx].texture, AKERR_NULLPOINTER, "Failed loading tileset image : %s", SDL_GetError());
@@ -190,7 +197,7 @@ akerr_ErrorContext *akgl_tilemap_compute_tileset_offsets(akgl_Tilemap *dest, int
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_tilesets(akgl_Tilemap *dest, json_t *root)
akerr_ErrorContext *akgl_tilemap_load_tilesets(akgl_Tilemap *dest, json_t *root, akgl_String *dirname)
{
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "Received NULL tilemap pointer");
@@ -205,7 +212,7 @@ akerr_ErrorContext *akgl_tilemap_load_tilesets(akgl_Tilemap *dest, json_t *root)
CATCH(errctx, akgl_get_json_array_value(root, "tilesets", &tilesets))
for (i = 0; i < json_array_size((json_t *)tilesets); i++) {
CATCH(errctx, akgl_get_json_array_index_object((json_t *)tilesets, i, &jstileset));
CATCH(errctx, akgl_tilemap_load_tilesets_each(jstileset, dest, i));
CATCH(errctx, akgl_tilemap_load_tilesets_each(jstileset, dest, i, dirname));
CATCH(errctx, akgl_tilemap_compute_tileset_offsets(dest, i));
dest->numtilesets += 1;
}
@@ -216,7 +223,7 @@ akerr_ErrorContext *akgl_tilemap_load_tilesets(akgl_Tilemap *dest, json_t *root)
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_layer_object_actor(akgl_TilemapObject *curobj, json_t *layerdatavalue, int layerid)
akerr_ErrorContext *akgl_tilemap_load_layer_object_actor(akgl_TilemapObject *curobj, json_t *layerdatavalue, int layerid, akgl_String *dirname)
{
PREPARE_ERROR(errctx);
akgl_String *tmpstr = NULL;
@@ -260,7 +267,7 @@ akerr_ErrorContext *akgl_tilemap_load_layer_object_actor(akgl_TilemapObject *cur
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_layer_objects(akgl_Tilemap *dest, json_t *root, int layerid)
akerr_ErrorContext *akgl_tilemap_load_layer_objects(akgl_Tilemap *dest, json_t *root, int layerid, akgl_String *dirname)
{
PREPARE_ERROR(errctx);
json_t *layerdata = NULL;
@@ -290,7 +297,7 @@ akerr_ErrorContext *akgl_tilemap_load_layer_objects(akgl_Tilemap *dest, json_t *
CATCH(errctx, akgl_get_json_string_value((json_t *)layerdatavalue, "type", &tmpstr));
if ( strcmp(tmpstr->data, "actor") == 0 ) {
CATCH(errctx, akgl_tilemap_load_layer_object_actor(curobj, layerdatavalue, layerid));
CATCH(errctx, akgl_tilemap_load_layer_object_actor(curobj, layerdatavalue, layerid, dirname));
} else if ( strcmp(tmpstr->data, "perspective") == 0 ) {
curobj->visible = false;
if ( strcmp((char *)curobj->name, "p_foreground") == 0 ) {
@@ -313,7 +320,7 @@ akerr_ErrorContext *akgl_tilemap_load_layer_objects(akgl_Tilemap *dest, json_t *
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_layer_tile(akgl_Tilemap *dest, json_t *root, int layerid)
akerr_ErrorContext *akgl_tilemap_load_layer_tile(akgl_Tilemap *dest, json_t *root, int layerid, akgl_String *dirname)
{
PREPARE_ERROR(errctx);
json_t *layerdata = NULL;
@@ -322,6 +329,7 @@ akerr_ErrorContext *akgl_tilemap_load_layer_tile(akgl_Tilemap *dest, json_t *roo
FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination tilemap reference");
FAIL_ZERO_RETURN(errctx, root, AKERR_NULLPOINTER, "NULL tilemap root reference");
FAIL_ZERO_RETURN(errctx, dirname, AKERR_NULLPOINTER, "dirname");
ATTEMPT {
CATCH(errctx, akgl_get_json_integer_value(root, "height", &dest->layers[layerid].height));
@@ -341,7 +349,7 @@ akerr_ErrorContext *akgl_tilemap_load_layer_tile(akgl_Tilemap *dest, json_t *roo
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_layer_image(akgl_Tilemap *dest, json_t *root, int layerid)
akerr_ErrorContext *akgl_tilemap_load_layer_image(akgl_Tilemap *dest, json_t *root, int layerid, akgl_String *dirname)
{
PREPARE_ERROR(errctx);
akgl_String *tmpstr;
@@ -349,18 +357,21 @@ akerr_ErrorContext *akgl_tilemap_load_layer_image(akgl_Tilemap *dest, json_t *ro
FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination tilemap reference");
FAIL_ZERO_RETURN(errctx, root, AKERR_NULLPOINTER, "NULL tilemap root reference");
FAIL_ZERO_RETURN(errctx, dirname, AKERR_NULLPOINTER, "dirname");
ATTEMPT {
CATCH(errctx, akgl_heap_next_string(&tmpstr));
CATCH(errctx, akgl_heap_next_string(&fpath));
CATCH(errctx, akgl_get_json_string_value(root, "image", &tmpstr));
DISABLE_GCC_WARNING_FORMAT_TRUNCATION
snprintf((char *)&fpath->data,
AKGL_TILEMAP_MAX_TILESET_FILENAME_SIZE,
"%s%s",
SDL_GetBasePath(),
"%s/%s",
dirname->data,
tmpstr->data
);
RESTORE_GCC_WARNINGS
dest->layers[layerid].texture = IMG_LoadTexture(renderer, (char *)fpath->data);
FAIL_ZERO_BREAK(errctx, dest->layers[layerid].texture, AKGL_ERR_SDL, "%s", SDL_GetError());
@@ -375,11 +386,12 @@ akerr_ErrorContext *akgl_tilemap_load_layer_image(akgl_Tilemap *dest, json_t *ro
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_layers(akgl_Tilemap *dest, json_t *root)
akerr_ErrorContext *akgl_tilemap_load_layers(akgl_Tilemap *dest, json_t *root, akgl_String *dirname)
{
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "akgl_tilemap_load_layers received NULL tilemap pointer");
FAIL_ZERO_RETURN(errctx, root, AKERR_NULLPOINTER, "akgl_tilemap_load_layers received NULL json object pointer");
FAIL_ZERO_RETURN(errctx, dirname, AKERR_NULLPOINTER, "dirname");
json_t *layers = NULL;
json_t *layer = NULL;
akgl_String *tmpstr = NULL;
@@ -406,13 +418,13 @@ akerr_ErrorContext *akgl_tilemap_load_layers(akgl_Tilemap *dest, json_t *root)
SDL_Log("Layer %d has type %s", layerid, tmpstr->data);
if ( strncmp((char *)tmpstr->data, "objectgroup", strlen((char *)tmpstr->data)) == 0 ) {
dest->layers[layerid].type = AKGL_TILEMAP_LAYER_TYPE_OBJECTS;
CATCH(errctx, akgl_tilemap_load_layer_objects((akgl_Tilemap *)dest, (json_t *)layer, layerid));
CATCH(errctx, akgl_tilemap_load_layer_objects((akgl_Tilemap *)dest, (json_t *)layer, layerid, dirname));
} else if ( strncmp((char *)tmpstr->data, "tilelayer", strlen((char *)tmpstr->data)) == 0 ) {
dest->layers[layerid].type = AKGL_TILEMAP_LAYER_TYPE_TILES;
CATCH(errctx, akgl_tilemap_load_layer_tile((akgl_Tilemap *)dest, (json_t *)layer, layerid));
CATCH(errctx, akgl_tilemap_load_layer_tile((akgl_Tilemap *)dest, (json_t *)layer, layerid, dirname));
} else if ( strncmp((char *)tmpstr->data, "imagelayer", strlen((char *)tmpstr->data)) == 0 ) {
dest->layers[layerid].type = AKGL_TILEMAP_LAYER_TYPE_IMAGE;
CATCH(errctx, akgl_tilemap_load_layer_image((akgl_Tilemap *)dest, (json_t *)layer, layerid));
CATCH(errctx, akgl_tilemap_load_layer_image((akgl_Tilemap *)dest, (json_t *)layer, layerid, dirname));
}
layer = NULL;
layerid += 1;
@@ -429,6 +441,7 @@ akerr_ErrorContext *akgl_tilemap_load(char *fname, akgl_Tilemap *dest)
json_t *json = NULL;
//akgl_String *tmpstr = NULL;
json_error_t error;
akgl_String *dirnamestr = NULL;
FAIL_ZERO_RETURN(errctx, fname, AKERR_NULLPOINTER, "load_tilemap received null filename");
FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "load_tilemap received null tilemap");
@@ -437,10 +450,13 @@ akerr_ErrorContext *akgl_tilemap_load(char *fname, akgl_Tilemap *dest)
dest->p_foreground_scale = 1.0;
dest->p_vanishing_scale = 1.0;
PASS(errctx, akgl_heap_next_string(&dirnamestr));
ATTEMPT {
//CATCH(errctx, akgl_heap_next_string(&tmpstr));
//CATCH(errctx, akgl_string_initialize(tmpstr, NULL));
//SDL_snprintf(tmpstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), fname);
CATCH(errctx, aksl_realpath(fname, (char *)&dirnamestr->data));
dirname((char *)&dirnamestr->data);
json = json_load_file(fname, 0, &error);
FAIL_ZERO_BREAK(
errctx,
@@ -461,8 +477,8 @@ akerr_ErrorContext *akgl_tilemap_load(char *fname, akgl_Tilemap *dest)
FAIL_RETURN(errctx, AKERR_OUTOFBOUNDS, "Map exceeds the maximum size");
}
CATCH(errctx, akgl_tilemap_load_layers((akgl_Tilemap *)dest, (json_t *)json));
CATCH(errctx, akgl_tilemap_load_tilesets((akgl_Tilemap *)dest, (json_t *)json));
CATCH(errctx, akgl_tilemap_load_layers((akgl_Tilemap *)dest, (json_t *)json, dirnamestr));
CATCH(errctx, akgl_tilemap_load_tilesets((akgl_Tilemap *)dest, (json_t *)json, dirnamestr));
if ( dest->p_foreground_y && dest->p_vanishing_y ) {
// How much bigger is the foreground vs the vanishing point?

View File

@@ -1,5 +1,6 @@
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
@@ -9,6 +10,72 @@
#include <akgl/heap.h>
#include <akgl/registry.h>
#include <akgl/game.h>
#include <akgl/staticstring.h>
#include <akstdlib.h>
akerr_ErrorContext *akgl_path_relative_root(char *root, char *path, akgl_String *dst)
{
PREPARE_ERROR(e);
akgl_String *pathbuf;
akgl_String *strbuf;
char *result;
int rootlen;
int pathlen;
int count;
FAIL_ZERO_RETURN(e, root, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(e, path, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(e, dst, AKERR_NULLPOINTER, "NULL argument");
PASS(e, akgl_heap_next_string(&strbuf));
PASS(e, akgl_heap_next_string(&pathbuf));
ATTEMPT {
// Is it relative to the root?
rootlen = strlen(root);
pathlen = strlen(path);
if ( (rootlen + pathlen) >= AKGL_MAX_STRING_LENGTH ) {
FAIL_RETURN(e, AKERR_OUTOFBOUNDS, "Total path length (%d) is greater than maximum akgl_String length (%d)", (rootlen + pathlen), AKGL_MAX_STRING_LENGTH);
}
CATCH(e, aksl_sprintf(&count, (char *)&pathbuf->data, "%s/%s", root, path));
CATCH(e, aksl_realpath((char *)&pathbuf->data, (char *)&strbuf->data));
CATCH(e, akgl_string_copy(strbuf, dst, 0));
} CLEANUP {
IGNORE(akgl_heap_release_string(strbuf));
IGNORE(akgl_heap_release_string(pathbuf));
} PROCESS(e) {
} FINISH(e, true);
SUCCEED_RETURN(e);
}
akerr_ErrorContext *akgl_path_relative(char *root, char *path, akgl_String *dst)
{
PREPARE_ERROR(e);
akgl_String *strbuf;
char *result;
FAIL_ZERO_RETURN(e, root, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(e, path, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(e, dst, AKERR_NULLPOINTER, "NULL argument");
PASS(e, akgl_heap_next_string(&strbuf));
ATTEMPT {
// Is path relative to our current working directory?
CATCH(e, aksl_realpath(path, (char *)&strbuf->data));
// Yes it is. strbuf->data contains the absolute path.
CATCH(e, akgl_string_copy(strbuf, dst, 0));
} CLEANUP {
IGNORE(akgl_heap_release_string(strbuf));
} PROCESS(e) {
} HANDLE(e, ENOENT) {
// Path is not relative to our current working directory
// Noop - execution proceeds after the break
return akgl_path_relative_root(root, path, dst);
} FINISH(e, true);
SUCCEED_RETURN(e);
}
akerr_ErrorContext *akgl_rectangle_points(RectanglePoints *dest, SDL_FRect *rect)
{