Give every exported function a declaration, and check that it stays that way
Closes internal-consistency items 7 through 15. Nineteen non-static functions were in the ABI with no declaration anywhere, so no consumer could call them and any consumer could collide with them. The four gamepad_handle_* functions are the ones that mattered: controller.h declared akgl_controller_handle_button_down and three siblings that did not exist, so anything compiled against the header alone failed to link. The definitions carry the declared names now, which also closes Defects -> Known and still open item 10, and their documentation moved to the header. The rest are either declared under a "part of the internal API" block -- akgl_game_save_actors and akgl_game_load_versioncmp, which tests/game.c had to declare for itself, plus six tilemap loader helpers the untested-loader work wants to reach -- or static, which is what the four save iterators and load_objectnamemap should always have been. akgl_path_relative_from is deleted: declared nowhere, called from nowhere, never wrote its output, and leaked a pooled string on every call, so it closes Known and still open item 4 and item 40 by ceasing to exist. scripts/check_api_surface.sh keeps it closed. It reads the built library's dynamic symbol table and every public header with comments stripped, and fails on an exported akgl_* symbol that is declared nowhere. Stripping comments is the whole point -- four of these were mentioned in controller.h prose, which is how they went unnoticed. The pool-size ceilings are defined once, in heap.h, so the #ifndef override hook fires for the first time; actor.h, sprite.h and character.h were defining the same four unconditionally from headers heap.h includes above its own guard. tests/header_pool_override.c fails the compile if that regresses. Also here: (void) rather than () on the twelve no-argument entry points, AKERR_NOIGNORE only on declarations, static helpers with the akgl_ prefix dropped, and the six parameter-name mismatches. akgl_get_json_with_default had its two contexts swapped rather than merely misspelled -- the incoming one was `err` and its own was `e`, which is the name reserved for an incoming one. 24/24 pass, reindent --check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -206,19 +206,18 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load(char *fname, akgl_Tilemap *
|
||||
*
|
||||
* Drawing goes through the global `akgl_renderer`, not through a backend passed in.
|
||||
*
|
||||
* @param dest The map to draw from. Required. Not an output parameter
|
||||
* despite the name.
|
||||
* @param map The map to draw from. Required.
|
||||
* @param viewport The rectangle of the map, in map pixels, that is on screen.
|
||||
* Required. Usually the global `akgl_camera`.
|
||||
* @param layeridx Which layer to draw, 0 to `numlayers - 1`. **Not**
|
||||
* bounds-checked: an index past the end reads a neighbouring
|
||||
* layer, or past the array.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p dest or @p viewport is `NULL`.
|
||||
* @throws AKERR_NULLPOINTER If @p map or @p viewport is `NULL`.
|
||||
* @throws AKERR_* Whatever the renderer's `draw_texture` raises. The first
|
||||
* failure abandons the rest of the layer.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw(akgl_Tilemap *dest, SDL_FRect *viewport, int layeridx);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw(akgl_Tilemap *map, SDL_FRect *viewport, int layeridx);
|
||||
/**
|
||||
* @brief Draw a whole tileset to the screen, tile by tile, from its offset table.
|
||||
*
|
||||
@@ -227,11 +226,10 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw(akgl_Tilemap *dest, SDL_FRe
|
||||
* matches the source image the offset table is right -- and if tiles are shifted
|
||||
* or duplicated, it is not. The `charviewer` utility uses it.
|
||||
*
|
||||
* @param dest The map holding the tileset. Required. Not an output
|
||||
* parameter despite the name.
|
||||
* @param map The map holding the tileset. Required.
|
||||
* @param tilesetidx Which tileset to draw, 0 to `numtilesets - 1`.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p dest is `NULL`.
|
||||
* @throws AKERR_NULLPOINTER If @p map is `NULL`.
|
||||
* @throws AKERR_OUTOFBOUNDS If @p tilesetidx is at or above `numtilesets`. A
|
||||
* negative index is not rejected.
|
||||
* @throws AKERR_* Whatever the renderer's `draw_texture` raises.
|
||||
@@ -240,7 +238,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw(akgl_Tilemap *dest, SDL_FRe
|
||||
* tileset's, so a tileset whose tiles are a different size from the map's
|
||||
* is reconstructed at the wrong pitch.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw_tileset(akgl_Tilemap *dest, int tilesetidx);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw_tileset(akgl_Tilemap *map, int tilesetidx);
|
||||
|
||||
/*
|
||||
* These functions are part of the internal API and should not be called by the user.
|
||||
@@ -490,4 +488,152 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_release(akgl_Tilemap *dest);
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_scale_actor(akgl_Tilemap *map, akgl_Actor *actor);
|
||||
|
||||
/**
|
||||
* @brief Read a Tiled custom property declared as `number`.
|
||||
*
|
||||
* Tiled writes `float` for a floating-point property, so this matches nothing
|
||||
* Tiled produces today -- akgl_get_json_properties_float is the one the loader
|
||||
* uses. Kept because a hand-written or older map may still say `number`.
|
||||
*
|
||||
* @param obj The Tiled object whose `properties` array to search. Required.
|
||||
* @param key The property name. Required.
|
||||
* @param dest Receives the value as a `float`. Not written on any failure path.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p obj or @p key is `NULL`.
|
||||
* @throws AKERR_KEY If the property is absent, or @p obj has no properties.
|
||||
* @throws AKERR_TYPE If the property is not declared `number`, or its `value` is
|
||||
* not numeric.
|
||||
* @throws AKGL_ERR_HEAP If the string pool is exhausted.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_number(json_t *obj, char *key, float *dest);
|
||||
/**
|
||||
* @brief Read a Tiled custom property declared as `float`.
|
||||
*
|
||||
* The spelling Tiled actually writes for a floating-point property. This is how
|
||||
* the `scale` on a perspective marker is read.
|
||||
*
|
||||
* @param obj The Tiled object whose `properties` array to search. Required.
|
||||
* @param key The property name. Required.
|
||||
* @param dest Receives the value. Not written on any failure path.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p obj or @p key is `NULL`.
|
||||
* @throws AKERR_KEY If the property is absent, or @p obj has no properties.
|
||||
* @throws AKERR_TYPE If the property is not declared `float`, or its `value` is
|
||||
* not numeric.
|
||||
* @throws AKGL_ERR_HEAP If the string pool is exhausted.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_float(json_t *obj, char *key, float *dest);
|
||||
/**
|
||||
* @brief Read a Tiled custom property declared as `float`, at full precision.
|
||||
*
|
||||
* Same declared type as akgl_get_json_properties_float, but writing a `double`.
|
||||
* The map's physics constants are `double`, which is the reason both exist.
|
||||
*
|
||||
* @param obj The Tiled object whose `properties` array to search. Required.
|
||||
* @param key The property name. Required.
|
||||
* @param dest Receives the value. Not written on any failure path.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p obj or @p key is `NULL`.
|
||||
* @throws AKERR_KEY If the property is absent, or @p obj has no properties.
|
||||
* akgl_tilemap_load_physics passes this status to
|
||||
* akgl_get_json_with_default, which turns it into a default of 0.0.
|
||||
* @throws AKERR_TYPE If the property is not declared `float`, or its `value` is
|
||||
* not numeric.
|
||||
* @throws AKGL_ERR_HEAP If the string pool is exhausted.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_double(json_t *obj, char *key, double *dest);
|
||||
/**
|
||||
* @brief Turn one Tiled object into a live actor, creating it if it is not already registered.
|
||||
*
|
||||
* The object's name is the actor's registry key, which is what lets the same
|
||||
* actor be placed by more than one object: the first placement creates it and
|
||||
* binds the character named in the object's `character` property, and every
|
||||
* later one just takes another reference. Either way the object's position,
|
||||
* visibility, and layer are copied onto the actor and the object keeps a
|
||||
* pointer to it.
|
||||
*
|
||||
* Not declared in tilemap.h -- reachable only through
|
||||
* akgl_tilemap_load_layer_objects.
|
||||
*
|
||||
* @param curobj The tilemap object, with its `name`, `x`, `y`, and
|
||||
* `visible` already read from JSON. Required, unchecked,
|
||||
* dereferenced at once.
|
||||
* @param layerdatavalue The object's JSON, for the custom properties --
|
||||
* `character` and `state` -- that are not part of Tiled's
|
||||
* own object fields. Required.
|
||||
* @param layerid The layer this object sits on, copied onto the actor.
|
||||
* @param dirname Directory to resolve paths against. Accepted for
|
||||
* signature consistency; nothing here uses it.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_KEY If the object's name is empty -- an actor has to be
|
||||
* addressable -- if the `character` or `state` property is absent, or if
|
||||
* the named character is not in #AKGL_REGISTRY_CHARACTER.
|
||||
* @throws AKERR_TYPE If `character` is not declared `string` or `state` not
|
||||
* declared `int`.
|
||||
* @throws AKERR_NULLPOINTER If akgl_actor_initialize refuses the name.
|
||||
* @throws AKGL_ERR_HEAP If the actor or string pool is exhausted.
|
||||
*
|
||||
* @note An existing actor's `character` and position are overwritten by each
|
||||
* later placement, so two objects naming one actor leave it wherever the
|
||||
* last one put it rather than producing two.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layer_object_actor(akgl_TilemapObject *curobj, json_t *layerdatavalue, int layerid, akgl_String *dirname);
|
||||
/**
|
||||
* @brief Load one image layer: upload its image as a single texture.
|
||||
*
|
||||
* An image layer is one picture rather than a grid, which is what a parallax
|
||||
* backdrop wants. The layer's `width` and `height` are taken from the loaded
|
||||
* texture rather than from the JSON, so they are always the true pixel size.
|
||||
*
|
||||
* Not declared in tilemap.h -- reachable only through akgl_tilemap_load_layers.
|
||||
*
|
||||
* @param dest The map to load into. Required.
|
||||
* @param root The layer's JSON object. Required.
|
||||
* @param layerid Which layer slot to fill. Not bounds-checked.
|
||||
* @param dirname Directory to resolve the layer's `image` path against.
|
||||
* Required. Joined with a `/` rather than run through
|
||||
* akgl_path_relative, so unlike a tileset image this path is not
|
||||
* canonicalized and an absolute one will not work.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p dest, @p root, or @p dirname is `NULL`.
|
||||
* @throws AKERR_KEY If the layer has no `image`.
|
||||
* @throws AKERR_TYPE If `image` is not a string.
|
||||
* @throws AKGL_ERR_SDL If the image cannot be loaded. The message carries
|
||||
* `SDL_GetError()`.
|
||||
* @throws AKGL_ERR_HEAP If the string pool is exhausted.
|
||||
*
|
||||
* @note The joined path is truncated at
|
||||
* #AKGL_TILEMAP_MAX_TILESET_FILENAME_SIZE without complaint, so an
|
||||
* over-long path fails as a missing file rather than as a length error.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layer_image(akgl_Tilemap *dest, json_t *root, int layerid, akgl_String *dirname);
|
||||
/**
|
||||
* @brief Give the map its own physics backend, if it asked for one.
|
||||
*
|
||||
* A map with a `physics.model` custom property gets its own backend, configured
|
||||
* from `physics.gravity.x`/`.y`/`.z` and `physics.drag.x`/`.y`/`.z`, and
|
||||
* `use_own_physics` is set so a caller knows to simulate through it. Each
|
||||
* constant defaults to 0.0 when absent, so a map can name a model and override
|
||||
* only what it cares about.
|
||||
*
|
||||
* Absence is the normal case at every level: a map with no properties at all, or
|
||||
* with properties but no `physics.model`, uses the game's global backend and
|
||||
* this returns success. That is why the AKERR_KEY handlers here are not error
|
||||
* paths -- they are the "map did not ask" path.
|
||||
*
|
||||
* Not declared in tilemap.h -- reachable only through akgl_tilemap_load.
|
||||
*
|
||||
* @param dest The map to configure. Required in practice; not checked here,
|
||||
* since akgl_tilemap_load has already done so.
|
||||
* @param root The map's root JSON object. Required, likewise.
|
||||
* @return `NULL` on success -- including when the map declared no physics at
|
||||
* all -- otherwise an error context owned by the caller.
|
||||
* @throws AKERR_KEY If `physics.model` names a backend that does not exist.
|
||||
* @throws AKERR_TYPE If `physics.model` is not declared `string`, or one of the
|
||||
* six constants is not declared `float`.
|
||||
* @throws AKERR_NULLPOINTER If akgl_physics_factory refuses its arguments.
|
||||
* @throws AKGL_ERR_HEAP If the string pool is exhausted.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_physics(akgl_Tilemap *dest, json_t *root);
|
||||
|
||||
#endif //_AKGL_TILEMAP_H_
|
||||
|
||||
Reference in New Issue
Block a user