#include #include #include #include #include #include #include #include #include #include #include akerr_ErrorContext *test_tilemap_akgl_get_json_tilemap_property(void) { PREPARE_ERROR(errctx); json_t *jsondoc = NULL; json_error_t jsonerr; akgl_String *tmpstr = NULL; int propnum; ATTEMPT { CATCH(errctx, akgl_heap_next_string(&tmpstr)); snprintf( (char *)&tmpstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), "assets/snippets/test_tilemap_akgl_get_json_tilemap_property.json" ); jsondoc = json_load_file((char *)&tmpstr->data, 0, (json_error_t *)&jsonerr); FAIL_ZERO_BREAK(errctx, jsondoc, AKERR_NULLPOINTER, "Failure loading json fixture: %s", (char *)jsonerr.text); CATCH( errctx, akgl_get_json_properties_string( jsondoc, "character", &tmpstr ) ); FAIL_NONZERO_BREAK( errctx, strcmp((char *)&tmpstr->data, "testcharacter"), AKERR_VALUE, "Incorrect value loaded from property `character` (`testcharacter` vs `%s`)", (char *)&tmpstr->data ); CATCH( errctx, akgl_get_json_properties_integer( jsondoc, "state", &propnum ) ); FAIL_NONZERO_BREAK( errctx, (propnum != 6), AKERR_VALUE, "Incorrect value loaded from property `state` (6 vs %d)", propnum ); } CLEANUP { if ( tmpstr != NULL ) { IGNORE(akgl_heap_release_string(tmpstr)); } if ( jsondoc != NULL ) { json_decref(jsondoc); } } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_compute_tileset_offsets(void) { int comparison_values[8] = { 0, // Tile 0 X 0, // Tile 0 Y 10, // Tile 1 X 0, // Tile 1 Y 0, // Tile 2 X 10, // Tile 2 Y 10, // Tile 2 X 10 // Tile 2 Y }; int *comparison_ptrs[8] = { &gamemap.tilesets[0].tile_offsets[0][0], // Tile 0 X &gamemap.tilesets[0].tile_offsets[0][1], // Tile 0 Y &gamemap.tilesets[0].tile_offsets[1][0], // Tile 1 X &gamemap.tilesets[0].tile_offsets[1][1], // Tile 0 Y &gamemap.tilesets[0].tile_offsets[2][0], // Tile 2 X &gamemap.tilesets[0].tile_offsets[2][1], // Tile 2 Y &gamemap.tilesets[0].tile_offsets[3][0], // Tile 3 X &gamemap.tilesets[0].tile_offsets[3][0], // Tile 3 Y }; int i = 0; memset((void *)&gamemap, 0x00, sizeof(akgl_Tilemap)); gamemap.tilesets[0].tilecount = 4; gamemap.tilesets[0].columns = 2; gamemap.tilesets[0].firstgid = 1; gamemap.tilesets[0].imageheight = 20; gamemap.tilesets[0].imagewidth = 20; gamemap.tilesets[0].tilecount = 4; gamemap.tilesets[0].tileheight = 10; gamemap.tilesets[0].tilewidth = 10; gamemap.tilesets[0].spacing = 0; gamemap.tilesets[0].margin = 0; PREPARE_ERROR(errctx); ATTEMPT { CATCH(errctx, akgl_tilemap_compute_tileset_offsets(&gamemap, 0)); // Tile 0 X offset for ( i = 0; i < 8; i++ ) { FAIL_NONZERO_BREAK( errctx, (*comparison_ptrs[i] != comparison_values[i]), AKERR_VALUE, "Tile offset incorrectly calculated for index %d (%d vs %d)", i, *comparison_ptrs[i], comparison_values[i] ); } } CLEANUP { } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_load_layer_objects(void) { akgl_String *pathstr; PREPARE_ERROR(errctx); json_t *doc = NULL; json_t *layers = NULL; json_t *objectlayer = NULL; json_error_t errdata; akgl_Actor *testactor; memset((void *)&gamemap, 0x00, sizeof(akgl_Tilemap)); ATTEMPT { CATCH(errctx, akgl_heap_next_string(&pathstr)); snprintf((char *)&pathstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), "assets/testmap.tmj"); doc = json_load_file((char *)&pathstr->data, 0, &errdata); FAIL_ZERO_BREAK(errctx, doc, AKERR_NULLPOINTER, "Failed to load testmap: %s", (char *)&errdata.text); CATCH(errctx, akgl_get_json_array_value(doc, "layers", &layers)); CATCH(errctx, akgl_get_json_array_index_object(layers, 1, &objectlayer)); CATCH(errctx, akgl_tilemap_load_layer_objects(&gamemap, objectlayer, 1)); testactor = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "testactor", NULL); FAIL_ZERO_BREAK( errctx, testactor, AKERR_NULLPOINTER, "Test Actor was not loaded from the test map" ); if ( (testactor->basechar != SDL_GetPointerProperty(AKGL_REGISTRY_CHARACTER, "testcharacter", NULL)) || (testactor->layer != 1) || (testactor->state != 6) || (testactor->visible != true) || (testactor->x != 16) || (testactor->y != 16) ) { FAIL_BREAK(errctx, AKERR_VALUE, "Test actor was loaded with incorrect values (check gdb)"); } } CLEANUP { if ( pathstr != NULL ) { IGNORE(akgl_heap_release_string(pathstr)); } if ( doc != NULL ) { json_decref(doc); } } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_load_layer_tile(void) { akgl_String *pathstr; PREPARE_ERROR(errctx); json_t *doc = NULL; json_t *layers = NULL; json_t *tilelayer = NULL; json_t *tiledata = NULL; json_error_t errdata; memset((void *)&gamemap, 0x00, sizeof(akgl_Tilemap)); ATTEMPT { CATCH(errctx, akgl_heap_next_string(&pathstr)); snprintf((char *)&pathstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), "assets/testmap.tmj"); doc = json_load_file((char *)&pathstr->data, 0, &errdata); FAIL_ZERO_BREAK(errctx, doc, AKERR_NULLPOINTER, "Failed to load testmap: %s", (char *)&errdata.text); CATCH(errctx, akgl_get_json_array_value(doc, "layers", &layers)); CATCH(errctx, akgl_get_json_array_index_object(layers, 0, &tilelayer)); CATCH(errctx, akgl_get_json_array_value(tilelayer, "data", &tiledata)); CATCH(errctx, akgl_tilemap_load_layer_tile(&gamemap, tilelayer, 0)); if ( (gamemap.layers[0].data[0] != 1) || (gamemap.layers[0].data[1] != 2) || (gamemap.layers[0].data[2] != 3) || (gamemap.layers[0].data[3] != 4) ) { FAIL_BREAK(errctx, AKERR_VALUE, "Test tilemap layer 0 tiles loaded with incorrect values (check gdb)"); } } CLEANUP { if ( pathstr != NULL ) { IGNORE(akgl_heap_release_string(pathstr)); } if ( doc != NULL ) { json_decref(doc); } } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_load_layers(void) { akgl_String *pathstr; PREPARE_ERROR(errctx); json_t *doc = NULL; json_error_t errdata; int i = 0; memset((void *)&gamemap, 0x00, sizeof(akgl_Tilemap)); ATTEMPT { CATCH(errctx, akgl_heap_next_string(&pathstr)); snprintf((char *)&pathstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), "assets/testmap.tmj"); doc = json_load_file((char *)&pathstr->data, 0, &errdata); FAIL_ZERO_BREAK(errctx, doc, AKERR_NULLPOINTER, "Failed to load testmap: %s", (char *)&errdata.text); CATCH(errctx, akgl_tilemap_load_layers(&gamemap, doc)); FAIL_NONZERO_BREAK( errctx, (gamemap.numlayers != 3), AKERR_VALUE, "Map layer count incorrect" ); for ( i = 0; i < gamemap.numlayers; i++ ) { if ( (gamemap.layers[i].opacity != 1) || (gamemap.layers[i].visible != true) || (gamemap.layers[i].id != (i + 1)) || (gamemap.layers[i].x != 0) || (gamemap.layers[i].y != 0) ) { FAIL(errctx, AKERR_VALUE, "Map layer data loaded incorrectly (see gdb)"); goto _test_akgl_tilemap_load_layers_cleanup; } } // Layer 2 should have 1 object loaded if ( (gamemap.layers[1].objects[0].actorptr != SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "testactor", NULL)) || (gamemap.layers[1].objects[1].name[0] != '\0' ) || (gamemap.layers[1].objects[1].id != 0) ) { FAIL_BREAK(errctx, AKERR_VALUE, "Map layer 2 should have 1 loaded object (testactor) and nothing else (see gdb)"); } // Layer 1 and 3 should have no objects for ( i = 0; i < AKGL_TILEMAP_MAX_OBJECTS_PER_LAYER ; i++ ) { if ( gamemap.layers[0].objects[i].id != 0 ) { FAIL(errctx, AKERR_VALUE, "Map layers 1 and 3 should have no objects loaded but found objects"); goto _test_akgl_tilemap_load_layers_cleanup; } } for ( i = 0; i < AKGL_TILEMAP_MAX_OBJECTS_PER_LAYER ; i++ ) { if ( gamemap.layers[2].objects[i].id != 0 ) { FAIL(errctx, AKERR_VALUE, "Map layers 1 and 3 should have no objects loaded but found objects"); goto _test_akgl_tilemap_load_layers_cleanup; } } // Layers 1 and 3 should have tile data if ( (gamemap.layers[0].data[0] != 1) || (gamemap.layers[0].data[1] != 2) || (gamemap.layers[0].data[2] != 3) || (gamemap.layers[0].data[3] != 4) || (gamemap.layers[2].data[0] != 0) || (gamemap.layers[2].data[1] != 5) || (gamemap.layers[2].data[2] != 0) || (gamemap.layers[2].data[3] != 6) ) { FAIL_BREAK(errctx, AKERR_VALUE, "Map layers 1 and 3 should have tile data but it is incorrect"); } _test_akgl_tilemap_load_layers_cleanup: } CLEANUP { if ( pathstr != NULL ) { IGNORE(akgl_heap_release_string(pathstr)); } if ( doc != NULL ) { json_decref(doc); } } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_load_tilesets(void) { akgl_String *pathstr = NULL; PREPARE_ERROR(errctx); json_t *doc = NULL; json_error_t errdata; SDL_Texture *image = NULL; memset((void *)&gamemap, 0x00, sizeof(akgl_Tilemap)); ATTEMPT { CATCH(errctx, akgl_heap_next_string(&pathstr)); snprintf((char *)&pathstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), "assets/testmap.tmj"); doc = json_load_file((char *)&pathstr->data, 0, &errdata); FAIL_ZERO_BREAK(errctx, doc, AKERR_NULLPOINTER, "Failed to load testmap: %s", (char *)&errdata.text); CATCH(errctx, akgl_tilemap_load_tilesets(&gamemap, doc)); FAIL_NONZERO_BREAK(errctx, (gamemap.numtilesets != 1), AKERR_VALUE, "Incorrect number of tilesets loaded for map"); if ( (gamemap.tilesets[0].columns != 48 ) || (gamemap.tilesets[0].firstgid != 1) || (gamemap.tilesets[0].imageheight != 576) || (gamemap.tilesets[0].imagewidth != 768) || (gamemap.tilesets[0].margin != 0) || (gamemap.tilesets[0].spacing != 0) || (gamemap.tilesets[0].tilecount != 1728) || (gamemap.tilesets[0].tileheight != 16) || (gamemap.tilesets[0].tilewidth != 16) ) { FAIL_BREAK(errctx, AKERR_VALUE, "Tileset loaded with incorrect values"); } FAIL_NONZERO_BREAK( errctx, strcmp((char *)&gamemap.tilesets[0].name, "World_A1"), AKERR_VALUE, "Tileset loaded with incorrect name"); snprintf((char *)&pathstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), "assets/World_A1.png"); image = IMG_LoadTexture(renderer, (char *)&pathstr->data); FAIL_ZERO_BREAK(errctx, image, AKGL_ERR_SDL, "Failed to load comparison image"); CATCH( errctx, akgl_render_and_compare( gamemap.tilesets[0].texture, image, 0, 0, 768, 576, "test_akgl_tilemap_loaded_tileset.png") ); } CLEANUP { if ( pathstr != NULL ) { IGNORE(akgl_heap_release_string(pathstr)); } if ( doc != NULL ) { json_decref(doc); } } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_load(void) { PREPARE_ERROR(errctx); memset((void *)&gamemap, 0x00, sizeof(akgl_Tilemap)); ATTEMPT { CATCH(errctx, akgl_tilemap_load("assets/testmap.tmj", &gamemap)); } CLEANUP { } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_draw(void) { PREPARE_ERROR(errctx); ATTEMPT { } CLEANUP { } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } akerr_ErrorContext *test_akgl_tilemap_draw_tileset(void) { PREPARE_ERROR(errctx); ATTEMPT { } CLEANUP { } PROCESS(errctx) { } FINISH(errctx, true); SUCCEED_RETURN(errctx); } int main(void) { PREPARE_ERROR(errctx); ATTEMPT { SDL_SetAppMetadata("SDL3-GameTest", "0.1", "net.aklabs.sdl3-gametest"); if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO )) { FAIL_BREAK(errctx, AKGL_ERR_SDL, "Couldn't initialize SDL: %s", SDL_GetError()); } if (!SDL_CreateWindowAndRenderer("net/aklabs/libakgl/test_sprite", 768, 576, 0, &window, &renderer)) { FAIL_BREAK(errctx, AKGL_ERR_SDL, "Couldn't create window/renderer: %s", SDL_GetError()); } CATCH(errctx, akgl_registry_init()); CATCH(errctx, akgl_heap_init()); CATCH(errctx, akgl_sprite_load_json("assets/testsprite.json")); CATCH(errctx, akgl_sprite_load_json("assets/testsprite2.json")); CATCH(errctx, akgl_character_load_json("assets/testcharacter.json")); CATCH(errctx, test_tilemap_akgl_get_json_tilemap_property()); CATCH(errctx, test_akgl_tilemap_compute_tileset_offsets()); CATCH(errctx, test_akgl_tilemap_load_layer_objects()); CATCH(errctx, test_akgl_tilemap_load_layer_tile()); CATCH(errctx, test_akgl_tilemap_load_layers()); CATCH(errctx, test_akgl_tilemap_load_tilesets()); //CATCH(errctx, test_akgl_tilemap_load()); //CATCH(errctx, test_akgl_tilemap_draw_tileset()); //CATCH(errctx, test_akgl_tilemap_draw()); } CLEANUP { } PROCESS(errctx) { } FINISH_NORETURN(errctx); }