From cf9ebb206f661bc5d3bf8fcf77b648644517a52c Mon Sep 17 00:00:00 2001 From: Andrew Kesterson Date: Wed, 29 Jul 2026 18:01:05 -0400 Subject: [PATCH] Repair embedded dependency build and test setup Isolate vendored test registration, namespace project error codes, and update dependency revisions. Fix mutable sprite path handling, out-of-tree fixtures, and charviewer initialization while documenting the outstanding character-to-sprite refcount bug. Co-authored-by: Codex (GPT-5) --- .gitmodules | 4 +-- AGENTS.md | 44 ++++++++++++++++++++++++++++++ CMakeLists.txt | 37 +++++++++++++++++++++++++- TODO.md | 15 +++++++++++ deps/libakerror | 2 +- deps/libakstdlib | 2 +- include/akgl/error.h | 7 +++-- src/actor.c | 30 +++++++++++++++++++++ src/controller.c | 2 +- src/heap.c | 14 ++++++---- src/sprite.c | 15 ++++++++--- tests/actor.c | 11 ++++---- tests/assets/testcharacter.json | 7 ++--- tests/assets/testsprite.json | 2 +- tests/assets/testsprite2.json | 2 +- tests/character.c | 6 +++-- tests/charviewer.c | 2 +- tests/registry.c | 2 +- tests/staticstring.c | 3 ++- tests/tilemap.c | 2 +- tests/util.c | 47 +++++++++++++++++---------------- util/charviewer.c | 17 ++++++------ 22 files changed, 209 insertions(+), 64 deletions(-) create mode 100644 AGENTS.md create mode 100644 TODO.md diff --git a/.gitmodules b/.gitmodules index 3085247..854bbba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,10 +15,10 @@ url = git@github.com:libsdl-org/SDL_ttf.git [submodule "deps/libsdlerror"] path = deps/libakerror - url = https://source.home.aklabs.net/andrew/libsdlerror.git + url = https://source.starfort.tech/andrew/libakerror.git [submodule "deps/libakstdlib"] path = deps/libakstdlib - url = https://source.home.aklabs.net/andrew/libakstdlib.git + url = https://source.starfort.tech/andrew/libakstdlib.git [submodule "deps/jansson"] path = deps/jansson url = git@github.com:akheron/jansson.git diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0454fa9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,44 @@ +# Repository Guidelines + +## Project Structure & Module Organization + +This is a C library intended to support the development of video games. Public C headers live in `include/akgl/`; keep declarations there aligned with their implementations in `src/`. Tests are standalone C programs under `tests/`, with JSON, image, and map fixtures in `tests/assets/`. The `util/` directory contains the `charviewer` utility and its sample assets. Third-party and companion libraries are vendored in `deps/`. Treat `build/`, generated `akgl.pc` files, and `include/akgl/SDL_GameControllerDB.h` as build outputs rather than hand-maintained source. + +## Build, Test, and Development Commands + +Configure an out-of-tree development build: + +```sh +cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo +``` + +Build all library, utility, and test targets: + +```sh +cmake --build build --parallel +``` + +Run the complete test suite with failure details: + +```sh +ctest --test-dir build --output-on-failure +``` + +Run one test while iterating, for example `ctest --test-dir build -R sprite --output-on-failure`. The `rebuild.sh` script also installs into a developer-specific `/home/andrew/local` prefix and removes existing outputs; prefer the portable commands above unless that exact workflow is intended. + +## Coding Style & Naming Conventions + +Follow the surrounding C style: braces on the next line for function bodies, spaces inside control-flow parentheses, and short, focused functions. Preserve the indentation of the file being edited; older files contain both spaces and tabs. Public symbols use the `akgl_` prefix, public types use `akgl_TypeName`, and constants/macros use `AKGL_UPPER_SNAKE_CASE`. Name matching header/source pairs by feature, such as `include/akgl/sprite.h` and `src/sprite.c`. No repository-wide formatter or linter is configured, so avoid unrelated formatting churn. + +## Rules + +- Add yourself (agent program name, model name and version) as a co-author on every commit message +- Avoid dynamic memory allocation. Use the `akgl_heap_*` methods to retrieve necessary objects at runtime, and to release them when done. If the akgl heap facilities don't provide the kind of object needed, create a new heap layer to support that type of object. + +## Testing Guidelines + +Tests use simple executable return codes and are registered through CTest in `CMakeLists.txt`; there is no declared coverage threshold. Add focused tests as `tests/.c`, create a matching `test_` target, and register it with `add_test`. Put reusable fixtures in `tests/assets/` and keep paths compatible with tests launched from the build tree. + +## Commit & Pull Request Guidelines + +Recent commits use concise, imperative summaries such as `Fix a scale bug...` and often explain related changes in one sentence. Keep each commit scoped and describe user-visible behavior. Pull requests should summarize the change, identify affected modules, list the CMake/CTest commands run, and link relevant issues. Include screenshots only for rendering, map, or `charviewer` changes. diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ca7763..1de6d1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,25 @@ project(akgl LANGUAGES C) include(CTest) if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - + +# Vendored projects own their test suites. Suppress their CTest registration +# while embedded so the top-level suite contains only targets built here. +set(AKGL_SUPPRESS_DEPENDENCY_TESTS TRUE) +function(add_test) + if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS) + _add_test(${ARGV}) + endif() +endfunction() +function(set_tests_properties) + if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS) + _set_tests_properties(${ARGV}) + endif() +endfunction() + +set(JANSSON_WITHOUT_TESTS ON CACHE BOOL "Do not build vendored Jansson tests" FORCE) +set(JANSSON_EXAMPLES OFF CACHE BOOL "Do not build vendored Jansson examples" FORCE) +set(JANSSON_BUILD_DOCS OFF CACHE BOOL "Do not build vendored Jansson docs" FORCE) + add_subdirectory(deps/jansson EXCLUDE_FROM_ALL) add_subdirectory(deps/libakerror EXCLUDE_FROM_ALL) add_subdirectory(deps/libakstdlib EXCLUDE_FROM_ALL) @@ -13,6 +31,13 @@ add_subdirectory(deps/SDL_image EXCLUDE_FROM_ALL) add_subdirectory(deps/SDL_mixer EXCLUDE_FROM_ALL) add_subdirectory(deps/SDL_ttf EXCLUDE_FROM_ALL) +# Reserve error-name table entries for libakgl-specific status codes. +target_compile_definitions(akerror PUBLIC + AKERR_MAX_ERR_VALUE=256 +) + +set(AKGL_SUPPRESS_DEPENDENCY_TESTS FALSE) + else() find_package(PkgConfig REQUIRED) @@ -48,6 +73,11 @@ set(libdir "\${exec_prefix}/lib") set(includedir "\${prefix}/include") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/akgl.pc.in ${CMAKE_CURRENT_BINARY_DIR}/akgl.pc @ONLY) +# Tests use both relative paths and SDL_GetBasePath(), so stage fixtures beside +# test executables in every out-of-tree build. +file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests/assets" + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + add_custom_command( OUTPUT ${GAMECONTROLLERDB_H} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/mkcontrollermappings.sh ${CMAKE_CURRENT_SOURCE_DIR} @@ -100,6 +130,11 @@ add_test(NAME tilemap COMMAND test_tilemap) add_test(NAME util COMMAND test_util) add_test(NAME semver_unit COMMAND test_semver_unit) +set_tests_properties( + actor bitmasks character registry sprite staticstring tilemap util semver_unit + PROPERTIES WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" +) + # Specify include directories for the library's headers (if applicable) target_include_directories(akgl PUBLIC include/ diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..55d8866 --- /dev/null +++ b/TODO.md @@ -0,0 +1,15 @@ +# TODO + +1. **Make character-to-sprite state bindings release their references symmetrically.** + `akgl_character_sprite_add()` increments the sprite refcount for every state-map + binding, but no corresponding removal API exists. Replacing a state binding + also leaves the previous sprite's refcount incremented. When + `akgl_heap_release_character()` drops the character refcount to zero, it clears + the character registry entry and zeroes the structure without enumerating + `state_sprites`, decrementing the bound sprites, or destroying the SDL property + map. Implement binding removal/replacement so each removed binding releases + exactly one sprite reference. On final character release, enumerate every + remaining binding (the existing `akgl_character_state_sprites_iterate()` release + path may be reusable), release each reference, destroy `state_sprites`, and then + clear the character. Add tests for removal, replacement, duplicate sprite + bindings across multiple states, and final character release. diff --git a/deps/libakerror b/deps/libakerror index 4a09ca8..0c0d812 160000 --- a/deps/libakerror +++ b/deps/libakerror @@ -1 +1 @@ -Subproject commit 4a09ca87fd675eb9c4cf9fe86d86a2762cd195e1 +Subproject commit 0c0d81249fc6dcb35c6126dfb8265beeea697d69 diff --git a/deps/libakstdlib b/deps/libakstdlib index b9d703f..a87cbfb 160000 --- a/deps/libakstdlib +++ b/deps/libakstdlib @@ -1 +1 @@ -Subproject commit b9d703f48aeed5a60bd74d0cc3ecf542eecc99fb +Subproject commit a87cbfb26dce716e263c918908b2039741ff1aff diff --git a/include/akgl/error.h b/include/akgl/error.h index a76608b..e9782a3 100644 --- a/include/akgl/error.h +++ b/include/akgl/error.h @@ -12,7 +12,10 @@ #define RESTORE_GCC_WARNINGS \ _Pragma("GCC diagnostic pop") -#define AKGL_ERR_SDL AKERR_LAST_ERRNO_VALUE + 1 -#define AKGL_ERR_LOGICINTERRUPT AKERR_LAST_ERRNO_VALUE + 2 +#define AKGL_ERR_SDL (AKERR_LAST_ERRNO_VALUE + 18) +#define AKGL_ERR_REGISTRY (AKERR_LAST_ERRNO_VALUE + 19) +#define AKGL_ERR_HEAP (AKERR_LAST_ERRNO_VALUE + 20) +#define AKGL_ERR_BEHAVIOR (AKERR_LAST_ERRNO_VALUE + 21) +#define AKGL_ERR_LOGICINTERRUPT (AKERR_LAST_ERRNO_VALUE + 22) #endif // _ERROR_H_ diff --git a/src/actor.c b/src/actor.c index 10e26aa..81d43d4 100644 --- a/src/actor.c +++ b/src/actor.c @@ -274,6 +274,36 @@ akerr_ErrorContext *akgl_actor_add_child(akgl_Actor *obj, akgl_Actor *child) FAIL_RETURN(errctx, AKERR_OUTOFBOUNDS, "Parent object has no remaining child slots left"); } +void akgl_registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name) +{ + PREPARE_ERROR(errctx); + akgl_Iterator *opflags = (akgl_Iterator *)userdata; + akgl_Actor *obj = NULL; + + ATTEMPT { + FAIL_ZERO_BREAK(errctx, name, AKERR_NULLPOINTER, "registry_iterate_actor received NULL property name"); + FAIL_ZERO_BREAK(errctx, opflags, AKERR_NULLPOINTER, "received NULL iterator flags"); + obj = SDL_GetPointerProperty(registry, name, NULL); + FAIL_ZERO_BREAK(errctx, obj, AKERR_KEY, "registry_iterate_actor received property name that was not in the registry"); + if (AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_LAYERMASK) && obj->layer != opflags->layerid) { + break; + } + if (AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_UPDATE)) { + CATCH(errctx, obj->updatefunc(obj)); + } + if (AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_TILEMAPSCALE)) { + CATCH(errctx, akgl_tilemap_scale_actor(gamemap, obj)); + } else { + obj->scale = 1.0; + } + if (AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_RENDER)) { + CATCH(errctx, obj->renderfunc(obj)); + } + } CLEANUP { + } PROCESS(errctx) { + } FINISH_NORETURN(errctx); +} + akerr_ErrorContext AKERR_NOIGNORE *akgl_Actor_cmhf_left_on(akgl_Actor *obj, SDL_Event *event) { PREPARE_ERROR(errctx); diff --git a/src/controller.c b/src/controller.c index dbd1ef3..2170dfd 100644 --- a/src/controller.c +++ b/src/controller.c @@ -277,7 +277,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_default(int controlmapid, cha controlmap->jsid = jsid; controlmap->target = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, actorname, NULL); - FAIL_ZERO_BREAK(errctx, controlmap->target, AKERR_REGISTRY, "Actor %s not found in registry", actorname); + FAIL_ZERO_BREAK(errctx, controlmap->target, AKGL_ERR_REGISTRY, "Actor %s not found in registry", actorname); // ---- KEYBOARD CONTROLS ---- diff --git a/src/heap.c b/src/heap.c index e172fa9..68904e0 100644 --- a/src/heap.c +++ b/src/heap.c @@ -20,6 +20,10 @@ akerr_ErrorContext *akgl_heap_init() PREPARE_ERROR(errctx); int i = 0; akerr_name_for_status(AKGL_ERR_SDL, "SDL Error"); + akerr_name_for_status(AKGL_ERR_REGISTRY, "Registry Error"); + akerr_name_for_status(AKGL_ERR_HEAP, "Heap Error"); + akerr_name_for_status(AKGL_ERR_BEHAVIOR, "Behavior Error"); + akerr_name_for_status(AKGL_ERR_LOGICINTERRUPT, "Logic Interrupt"); PASS(errctx, akgl_heap_init_actor()); for ( i = 0; i < AKGL_MAX_HEAP_SPRITE; i++) { memset(&HEAP_SPRITE[i], 0x00, sizeof(akgl_Sprite)); @@ -55,7 +59,7 @@ akerr_ErrorContext *akgl_heap_next_actor(akgl_Actor **dest) *dest = &HEAP_ACTOR[i]; SUCCEED_RETURN(errctx); } - FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused actor on the heap"); + FAIL_RETURN(errctx, AKGL_ERR_HEAP, "Unable to find unused actor on the heap"); } akerr_ErrorContext *akgl_heap_next_sprite(akgl_Sprite **dest) @@ -68,7 +72,7 @@ akerr_ErrorContext *akgl_heap_next_sprite(akgl_Sprite **dest) *dest = &HEAP_SPRITE[i]; SUCCEED_RETURN(errctx); } - FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused sprite on the heap"); + FAIL_RETURN(errctx, AKGL_ERR_HEAP, "Unable to find unused sprite on the heap"); } akerr_ErrorContext *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest) @@ -81,7 +85,7 @@ akerr_ErrorContext *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest) *dest = &HEAP_SPRITESHEET[i]; SUCCEED_RETURN(errctx); } - FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused spritesheet on the heap"); + FAIL_RETURN(errctx, AKGL_ERR_HEAP, "Unable to find unused spritesheet on the heap"); } akerr_ErrorContext *akgl_heap_next_character(akgl_Character **dest) @@ -94,7 +98,7 @@ akerr_ErrorContext *akgl_heap_next_character(akgl_Character **dest) *dest = &HEAP_CHARACTER[i]; SUCCEED_RETURN(errctx); } - FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused character on the heap"); + FAIL_RETURN(errctx, AKGL_ERR_HEAP, "Unable to find unused character on the heap"); } akerr_ErrorContext *akgl_heap_next_string(akgl_String **dest) @@ -108,7 +112,7 @@ akerr_ErrorContext *akgl_heap_next_string(akgl_String **dest) HEAP_STRING[i].refcount += 1; SUCCEED_RETURN(errctx); } - FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused string on the heap"); + FAIL_RETURN(errctx, AKGL_ERR_HEAP, "Unable to find unused string on the heap"); } akerr_ErrorContext *akgl_heap_release_actor(akgl_Actor *ptr) diff --git a/src/sprite.c b/src/sprite.c index e1c0880..13cc821 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -58,7 +58,7 @@ static akerr_ErrorContext *akgl_sprite_load_json_spritesheet(json_t *json, akgl_ if ( *sheet == NULL ) { CATCH(errctx, akgl_heap_next_spritesheet(sheet)); CATCH(errctx, akgl_get_json_integer_value((json_t *)spritesheet_json, "frame_width", &ss_frame_width)); - CATCH(errctx, akgl_get_json_integer_value((json_t *)spritesheet_json, "frame_height", &ss_frame_width)); + CATCH(errctx, akgl_get_json_integer_value((json_t *)spritesheet_json, "frame_height", &ss_frame_height)); CATCH(errctx, akgl_spritesheet_initialize( (akgl_SpriteSheet *)*sheet, @@ -85,12 +85,20 @@ akerr_ErrorContext *akgl_sprite_load_json(char *filename) akgl_Sprite *obj = NULL; akgl_SpriteSheet *sheet = NULL; akgl_String *spritename = NULL; - //string *tmpstr = NULL; + akgl_String *filename_copy = NULL; int i = 0; FAIL_ZERO_RETURN(errctx, filename, AKERR_NULLPOINTER, "Received null filename"); ATTEMPT { CATCH(errctx, akgl_heap_next_sprite(&obj)); + CATCH(errctx, akgl_heap_next_string(&filename_copy)); + FAIL_NONZERO_BREAK( + errctx, + strlen(filename) >= AKGL_MAX_STRING_LENGTH, + AKERR_OUTOFBOUNDS, + "Sprite filename exceeds temporary string capacity" + ); + SDL_strlcpy(filename_copy->data, filename, AKGL_MAX_STRING_LENGTH); //CATCH(errctx, akgl_heap_next_string(&tmpstr)); //CATCH(errctx, akgl_string_initialize(tmpstr, NULL)); CATCH(errctx, akgl_heap_next_string(&spritename)); @@ -105,7 +113,7 @@ akerr_ErrorContext *akgl_sprite_load_json(char *filename) "Error while loading sprite from %s on line %d: %s", filename, error.line, error.text ); - CATCH(errctx, akgl_sprite_load_json_spritesheet((json_t *)json, &sheet, dirname(filename))); + CATCH(errctx, akgl_sprite_load_json_spritesheet((json_t *)json, &sheet, dirname(filename_copy->data))); CATCH(errctx, akgl_get_json_string_value((json_t *)json, "name", &spritename)); CATCH(errctx, akgl_sprite_initialize( @@ -132,6 +140,7 @@ akerr_ErrorContext *akgl_sprite_load_json(char *filename) IGNORE(akgl_heap_release_spritesheet(sheet)); } IGNORE(akgl_heap_release_string(spritename)); + IGNORE(akgl_heap_release_string(filename_copy)); //IGNORE(akgl_heap_release_string(tmpstr)); } PROCESS(errctx) { } FINISH(errctx, true); diff --git a/tests/actor.c b/tests/actor.c index 46307e3..03d793b 100644 --- a/tests/actor.c +++ b/tests/actor.c @@ -2,6 +2,7 @@ handle_unhandled_error(errctx); #include +#include #define UNHANDLED_ERROR_EXIT 0 #define UNHANDLED_ERROR_SET 1 @@ -42,7 +43,7 @@ akerr_ErrorContext *akgl_actor_update_noop(akgl_Actor *obj) // Currently the renderer assumes there is a global variable named `renderer` int akgl_actor_rendered; -akerr_ErrorContext *akgl_actor_render_noop(akgl_Actor *obj, SDL_Renderer *r) +akerr_ErrorContext *akgl_actor_render_noop(akgl_Actor *obj) { PREPARE_ERROR(errctx); akgl_actor_rendered = 1; @@ -129,13 +130,13 @@ akerr_ErrorContext *test_registry_actor_iterator_updaterender(void) FAIL_ZERO_BREAK( unhandled_error_context, akgl_actor_updated, - AKERR_BEHAVIOR, + AKGL_ERR_BEHAVIOR, "actor->updatefunc not called by the iterator" ); FAIL_ZERO_BREAK( unhandled_error_context, akgl_actor_rendered, - AKERR_BEHAVIOR, + AKGL_ERR_BEHAVIOR, "actor->renderfunc not called by the iterator" ); } CLEANUP { @@ -235,7 +236,7 @@ akerr_ErrorContext *test_actor_manage_children(void) CATCH(errctx, parent->addchild(parent, child)); } CLEANUP { if ( errctx == NULL ) { - FAIL(errctx, AKERR_BEHAVIOR, "addchild does not throw AKERR_RELATIONSHIP when child already has a parent"); + FAIL(errctx, AKGL_ERR_BEHAVIOR, "addchild does not throw AKERR_RELATIONSHIP when child already has a parent"); } } PROCESS(errctx) { } HANDLE(errctx, AKERR_RELATIONSHIP) { @@ -248,7 +249,7 @@ akerr_ErrorContext *test_actor_manage_children(void) CATCH(errctx, parent->addchild(parent, child)); } CLEANUP { if ( errctx == NULL ) { - FAIL(errctx, AKERR_BEHAVIOR, "addchild does not throw AKERR_OUTOFBOUNDS when all children already set"); + FAIL(errctx, AKGL_ERR_BEHAVIOR, "addchild does not throw AKERR_OUTOFBOUNDS when all children already set"); } } PROCESS(errctx) { } HANDLE(errctx, AKERR_OUTOFBOUNDS) { diff --git a/tests/assets/testcharacter.json b/tests/assets/testcharacter.json index 975d3d6..a716ebf 100644 --- a/tests/assets/testcharacter.json +++ b/tests/assets/testcharacter.json @@ -1,7 +1,8 @@ { "name": "testcharacter", - "velocity_x": 0.20, - "velocity_y": 0.20, + "movementspeed": 1, + "acceleration_x": 0.20, + "acceleration_y": 0.20, "sprite_mappings": [ { "state": [ @@ -12,7 +13,7 @@ }, { "state": [ - "ACTOR_STATE_DEAD" + "AKGL_ACTOR_STATE_DEAD" ], "sprite": "testsprite2" } diff --git a/tests/assets/testsprite.json b/tests/assets/testsprite.json index bbf40e2..4da8229 100644 --- a/tests/assets/testsprite.json +++ b/tests/assets/testsprite.json @@ -1,6 +1,6 @@ { "spritesheet": { - "filename": "assets/spritesheet.png", + "filename": "spritesheet.png", "frame_width": 48, "frame_height": 48 }, diff --git a/tests/assets/testsprite2.json b/tests/assets/testsprite2.json index bfabdc3..8b64a08 100644 --- a/tests/assets/testsprite2.json +++ b/tests/assets/testsprite2.json @@ -1,6 +1,6 @@ { "spritesheet": { - "filename": "assets/spritesheet.png", + "filename": "spritesheet.png", "frame_width": 48, "frame_height": 48 }, diff --git a/tests/character.c b/tests/character.c index 97312f8..955bc98 100644 --- a/tests/character.c +++ b/tests/character.c @@ -50,6 +50,7 @@ akerr_ErrorContext *test_character_sprite_mgmt() PREPARE_ERROR(errctx); ATTEMPT { CATCH(errctx, akgl_heap_next_character(&testchar)); + CATCH(errctx, akgl_character_initialize(testchar, "testchar")); CATCH(errctx, akgl_sprite_load_json("assets/testsprite.json")); testsprite = SDL_GetPointerProperty(AKGL_REGISTRY_SPRITE, "testsprite", NULL); FAIL_ZERO_BREAK( @@ -89,6 +90,7 @@ akerr_ErrorContext *test_character_iterate_state_sprites() PREPARE_ERROR(errctx); ATTEMPT { CATCH(errctx, akgl_heap_next_character(&testchar)); + CATCH(errctx, akgl_character_initialize(testchar, "testchar")); CATCH(errctx, akgl_sprite_load_json("assets/testsprite.json")); testsprite = SDL_GetPointerProperty(AKGL_REGISTRY_SPRITE, "testsprite", NULL); FAIL_ZERO_BREAK( @@ -169,8 +171,8 @@ akerr_ErrorContext *test_akgl_character_load_json() CATCH(errctx, testcharacter->sprite_get(testcharacter, AKGL_ACTOR_STATE_DEAD, &comparesprite)); FAIL_ZERO_BREAK(errctx, (comparesprite == testsprite2), AKERR_VALUE, "Wrong sprite for state AKGL_ACTOR_STATE_DEAD"); - FAIL_ZERO_BREAK(errctx, (testcharacter->vx != 0.200000003), AKERR_VALUE, "Wrong X velocity for test character"); - FAIL_ZERO_BREAK(errctx, (testcharacter->vy != 0.200000003), AKERR_VALUE, "Wrong Y velocity for test character"); + FAIL_ZERO_BREAK(errctx, (testcharacter->ax != 0.200000003), AKERR_VALUE, "Wrong X acceleration for test character"); + FAIL_ZERO_BREAK(errctx, (testcharacter->ay != 0.200000003), AKERR_VALUE, "Wrong Y acceleration for test character"); // Release our handles on the sprites so the character's heap_release can reduce them to 0 CATCH(errctx, akgl_heap_release_sprite(testsprite)); diff --git a/tests/charviewer.c b/tests/charviewer.c index 02504a8..a688668 100644 --- a/tests/charviewer.c +++ b/tests/charviewer.c @@ -68,7 +68,7 @@ int main(void) AKGL_REGISTRY_CHARACTER, "little guy", NULL); - FAIL_ZERO_BREAK(errctx, actorptr->basechar, AKERR_REGISTRY, "Can't load character 'little guy' from the registry"); + FAIL_ZERO_BREAK(errctx, actorptr->basechar, AKGL_ERR_REGISTRY, "Can't load character 'little guy' from the registry"); actorptr->movement_controls_face = false; actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_LEFT); actorptr->x = 320; diff --git a/tests/registry.c b/tests/registry.c index 9b0d8bf..345fb0f 100644 --- a/tests/registry.c +++ b/tests/registry.c @@ -43,7 +43,7 @@ akerr_ErrorContext *test_akgl_registry_init(RegistryFuncPtr funcptr) } PROCESS(errctx) { } FINISH(errctx, true); - FAIL_RETURN(errctx, AKERR_BEHAVIOR, "SDL memory allocator fails but registry reports successful property creation"); + FAIL_RETURN(errctx, AKGL_ERR_BEHAVIOR, "SDL memory allocator fails but registry reports successful property creation"); } akerr_ErrorContext *test_akgl_registry_init_creation_failures(void) diff --git a/tests/staticstring.c b/tests/staticstring.c index 0d1d43a..6eab9d2 100644 --- a/tests/staticstring.c +++ b/tests/staticstring.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -111,7 +112,7 @@ akerr_ErrorContext *test_akgl_string_initialize(void) FAIL_NONZERO_BREAK(errctx, strcmp((char *)&ptr->data, "Test value"), AKERR_VALUE, "Expected 'Test value', got %s", (char *)&ptr->data); CATCH(errctx, akgl_heap_release_string(NULL)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Failure to properly handle NULL pointer"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Failure to properly handle NULL pointer"); } CLEANUP { } PROCESS(errctx) { } FINISH(errctx, true); diff --git a/tests/tilemap.c b/tests/tilemap.c index 696df1a..606480f 100644 --- a/tests/tilemap.c +++ b/tests/tilemap.c @@ -26,7 +26,7 @@ akerr_ErrorContext *test_tilemap_akgl_get_json_tilemap_property(void) AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), - "assets/snippets/test_tilemap_akgl_get_json_tilemap_property.json" + "assets/snippets/test_tilemap_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); diff --git a/tests/util.c b/tests/util.c index 175930e..d8a4645 100644 --- a/tests/util.c +++ b/tests/util.c @@ -1,5 +1,6 @@ #include #include +#include #include akerr_ErrorContext *test_akgl_rectangle_points_nullpointers(void) @@ -10,7 +11,7 @@ akerr_ErrorContext *test_akgl_rectangle_points_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_rectangle_points(NULL, NULL)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_rectangle_points fails to FAIL with all NULL pointers"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_rectangle_points fails to FAIL with all NULL pointers"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -19,7 +20,7 @@ akerr_ErrorContext *test_akgl_rectangle_points_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_rectangle_points(NULL, &testrect)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_rectangle_points fails to FAIL with NULL SDL_FRect pointer"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_rectangle_points fails to FAIL with NULL SDL_FRect pointer"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -28,7 +29,7 @@ akerr_ErrorContext *test_akgl_rectangle_points_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_rectangle_points(&points, NULL)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_rectangle_points fails to FAIL with NULL RectanglePoints pointer"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_rectangle_points fails to FAIL with NULL RectanglePoints pointer"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -63,7 +64,7 @@ akerr_ErrorContext *test_akgl_rectangle_points_math(void) points.bottomright.y != 32 ) { FAIL_BREAK( errctx, - AKERR_BEHAVIOR, + AKGL_ERR_BEHAVIOR, "akgl_rectangle_points incorrectly calculated points for {x=0, y=0, w=32, h=32} to {topleft={%d, %d}, topright={%d, %d}, bottomleft={%d, %d}, bottomright={%d, %d}}", points.topleft.x, points.topleft.y, points.topright.x, points.topright.y, @@ -87,7 +88,7 @@ akerr_ErrorContext *test_akgl_collide_point_rectangle_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_point_rectangle(&testpoint, &testrectpoints, NULL)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_point_rectangle(*, *, NULL) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_point_rectangle(*, *, NULL) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -96,7 +97,7 @@ akerr_ErrorContext *test_akgl_collide_point_rectangle_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_point_rectangle(&testpoint, NULL, &testcollide)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_point_rectangle(*, NULL, *) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_point_rectangle(*, NULL, *) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -105,7 +106,7 @@ akerr_ErrorContext *test_akgl_collide_point_rectangle_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_point_rectangle(NULL, &testrectpoints, &testcollide)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_point_rectangle(NULL, *, *) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_point_rectangle(NULL, *, *) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -114,7 +115,7 @@ akerr_ErrorContext *test_akgl_collide_point_rectangle_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_point_rectangle(NULL, NULL, NULL)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_point_rectangle(NULL, NULL, NULL) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_point_rectangle(NULL, NULL, NULL) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -142,14 +143,14 @@ akerr_ErrorContext *test_akgl_collide_point_rectangle_logic(void) CATCH(errctx, akgl_rectangle_points(&testrectpoints, &testrect)); CATCH(errctx, akgl_collide_point_rectangle(&testpoint, &testrectpoints, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } testpoint.x = 48; testpoint.y = 48; CATCH(errctx, akgl_collide_point_rectangle(&testpoint, &testrectpoints, &testcollide)); if ( testcollide == true ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Invalid collision reported"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Invalid collision reported"); } } CLEANUP { } PROCESS(errctx) { @@ -167,7 +168,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, NULL)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_rectangles(*, *, NULL) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_rectangles(*, *, NULL) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -176,7 +177,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_rectangles(&testrect1, NULL, &testcollide)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_rectangles(*, NULL, *) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_rectangles(*, NULL, *) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -185,7 +186,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_rectangles(NULL, &testrect2, &testcollide)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_rectangles(NULL, *, *) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_rectangles(NULL, *, *) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -194,7 +195,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_nullpointers(void) ATTEMPT { CATCH(errctx, akgl_collide_rectangles(NULL, NULL, NULL)); - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "akgl_collide_rectangles(NULL, NULL, NULL) failed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_rectangles(NULL, NULL, NULL) failed"); } CLEANUP { } PROCESS(errctx) { } HANDLE(errctx, AKERR_NULLPOINTER) { @@ -222,14 +223,14 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) // Collision overlapping on the top left CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Collision overlapping on the top right testrect1.x = 64; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Collision overlapping on the bottom left @@ -237,7 +238,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) testrect1.y = 32; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Collision overlapping on the bottom right @@ -245,7 +246,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) testrect1.y = 32; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Collision overlapping the top edge @@ -255,7 +256,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) testrect1.h = 32; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Collision overlapping the left edge @@ -265,7 +266,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) testrect1.h = 80; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Collision overlapping the right edge @@ -275,7 +276,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) testrect1.h = 80; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Collision overlapping the bottom edge @@ -285,7 +286,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) testrect1.h = 32; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == false ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Valid collision missed"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Valid collision missed"); } // Not colliding @@ -295,7 +296,7 @@ akerr_ErrorContext *test_akgl_collide_rectangles_logic(void) testrect1.h = 16; CATCH(errctx, akgl_collide_rectangles(&testrect1, &testrect2, &testcollide)); if ( testcollide == true ) { - FAIL_BREAK(errctx, AKERR_BEHAVIOR, "Invalid collision reported"); + FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "Invalid collision reported"); } } CLEANUP { diff --git a/util/charviewer.c b/util/charviewer.c index 6f37814..4e80699 100644 --- a/util/charviewer.c +++ b/util/charviewer.c @@ -48,12 +48,11 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) strcpy((char *)&game.name, "charviewer"); strcpy((char *)&game.version, "0.0.1"); strcpy((char *)&game.uri, "net.aklabs.libakgl.charviewer"); - game.screenwidth = 640; - game.screenheight = 480; - CATCH(errctx, akgl_game_init()); - CATCH(errctx, akgl_heap_init()); - CATCH(errctx, akgl_registry_init()); + CATCH(errctx, akgl_set_property("game.screenwidth", "640")); + CATCH(errctx, akgl_set_property("game.screenheight", "480")); + CATCH(errctx, akgl_render_init2d(renderer)); + CATCH(errctx, akgl_physics_init_null(physics)); } CLEANUP { } PROCESS(errctx) { @@ -94,7 +93,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) AKGL_REGISTRY_CHARACTER, "little guy", NULL); - FAIL_ZERO_BREAK(errctx, actorptr->basechar, AKERR_REGISTRY, "Can't load character 'little guy' from the registry"); + FAIL_ZERO_BREAK(errctx, actorptr->basechar, AKGL_ERR_REGISTRY, "Can't load character 'little guy' from the registry"); actorptr->movement_controls_face = false; actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_DOWN); actorptr->x = 320; @@ -145,9 +144,9 @@ SDL_AppResult SDL_AppIterate(void *appstate) AKGL_BITMASK_CLEAR(opflags.flags); AKGL_BITMASK_ADD(opflags.flags, AKGL_ITERATOR_OP_UPDATE); AKGL_BITMASK_ADD(opflags.flags, AKGL_ITERATOR_OP_RENDER); - akgl_draw_background(game.screenwidth, game.screenheight); + akgl_draw_background((int)camera->w, (int)camera->h); ATTEMPT { - CATCH(errctx, akgl_tilemap_draw(renderer, (akgl_Tilemap *)&gamemap, &camera, i)); + CATCH(errctx, akgl_tilemap_draw(gamemap, camera, i)); SDL_EnumerateProperties(AKGL_REGISTRY_ACTOR, &akgl_registry_iterate_actor, (void *)&opflags); } CLEANUP { } PROCESS(errctx) { @@ -155,7 +154,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) LOG_ERROR(errctx); return SDL_APP_FAILURE; } FINISH_NORETURN(errctx); - SDL_RenderPresent(renderer); + SDL_RenderPresent(renderer->sdl_renderer); return SDL_APP_CONTINUE; }