2026-07-30 01:10:31 -04:00
/**
* @ file sprite . h
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Spritesheets ( one texture , many frames ) and the animations cut out of them .
*
* The split is deliberate : an akgl_SpriteSheet owns the ` SDL_Texture ` and the
* frame grid , and any number of akgl_Sprite animations point at the same sheet
* and name the frame indices they use . Loading two sprites from the same image
* loads the image once - - akgl_sprite_load_json looks the sheet up in
* # AKGL_REGISTRY_SPRITESHEET by resolved path before creating one .
*
* Both are pool objects ( akgl_heap_next_sprite , akgl_heap_next_spritesheet ) and
* both publish themselves in a registry under their name , which is how
* akgl_character_sprite_add and the tilemap loader find them . Because loading a
* sheet uploads a texture , the renderer has to exist first - - so
* akgl_render_init2d , or akgl_game_init , before any of this .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
# ifndef _AKGL_SPRITE_H_
# define _AKGL_SPRITE_H_
2025-08-03 10:07:35 -04:00
# include <SDL3/SDL_properties.h>
2026-05-03 23:57:55 -04:00
# include <SDL3/SDL.h>
2026-01-05 08:58:06 -05:00
# include <akerror.h>
2025-08-03 10:07:35 -04:00
2026-05-06 23:18:42 -04:00
# define AKGL_SPRITE_MAX_FRAMES 16
# define AKGL_SPRITE_MAX_NAME_LENGTH 128
# define AKGL_SPRITE_MAX_REGISTRY_SIZE 1024
# define AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH 512
2025-08-03 10:07:35 -04:00
2026-05-06 23:18:42 -04:00
# define AKGL_MAX_HEAP_SPRITE (AKGL_MAX_HEAP_ACTOR * 16)
# define AKGL_MAX_HEAP_SPRITESHEET AKGL_MAX_HEAP_SPRITE
2025-08-03 10:07:35 -04:00
2026-07-30 01:10:31 -04:00
/** @brief Stores a loaded spritesheet texture and frame geometry. */
2025-08-03 10:07:35 -04:00
typedef struct {
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
uint8_t refcount ; /**< Pool bookkeeping; 0 means the slot is free. Destroys the texture when it reaches 0. */
SDL_Texture * texture ; /**< The whole sheet as one GPU texture. Owned by this struct. */
char name [ AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH ] ; /**< Registry key: the resolved path the image was loaded from. */
uint16_t sprite_w ; /**< Frame width. Vestigial: nothing in the library writes or reads it; the grid comes from akgl_Sprite::width. */
uint16_t sprite_h ; /**< Frame height. Vestigial, same as sprite_w. */
2026-05-06 23:18:42 -04:00
} akgl_SpriteSheet ;
2025-08-03 10:07:35 -04:00
2026-07-30 01:10:31 -04:00
/** @brief Describes an animated sprite and its spritesheet reference. */
2025-08-03 10:07:35 -04:00
typedef struct {
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
uint8_t refcount ; /**< Pool bookkeeping; 0 means the slot is free. One reference per character that maps it. */
uint8_t frameids [ AKGL_SPRITE_MAX_FRAMES ] ; /**< Frame numbers on the sheet, in playback order. Counted left to right, then wrapping to the next row. */
uint32_t frames ; /**< How many entries of frameids are in use. */
uint32_t width ; /**< Frame width in pixels; also the horizontal stride used to find a frame on the sheet. */
uint32_t height ; /**< Frame height in pixels; the vertical stride once frames wrap to the next row. */
uint32_t speed ; /**< Nanoseconds one frame is held. Read from JSON in milliseconds and scaled by #AKGL_TIME_ONESEC_MS, which despite its name is nanoseconds-per-millisecond. TODO.md item 6. */
bool loop ; /**< Restart from frame 0 when the last frame is reached, instead of holding it. */
bool loopReverse ; /**< Play back down to frame 0 instead of jumping to it -- a ping-pong loop. */
char name [ AKGL_SPRITE_MAX_NAME_LENGTH ] ; /**< Registry key, from the JSON `name` field. */
akgl_SpriteSheet * sheet ; /**< The sheet these frames are cut from. Borrowed, not owned. */
2026-05-06 23:18:42 -04:00
} akgl_Sprite ;
2025-08-03 10:07:35 -04:00
// initializes a new sprite to use the given sheet and otherwise sets to zero
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Zero a pooled sprite , bind it to a sheet , and publish it in the sprite registry .
*
* Sets the name and the sheet and takes the first reference ; everything else - -
* frame list , geometry , speed , loop flags - - is left at zero for the caller , or
* akgl_sprite_load_json , to fill in . The sheet is borrowed , so this does * not *
* take a reference on it : releasing the sheet out from under a live sprite
* leaves a dangling pointer .
*
* @ param spr Pooled sprite to initialize , normally from akgl_heap_next_sprite .
* Required . Any previous contents are discarded .
* @ param name Registry key , NUL - terminated . Required . Copied at a fixed
* # AKGL_SPRITE_MAX_NAME_LENGTH bytes , so a shorter string reads
* past its end - - pass a name from an akgl_String or another
* buffer of at least that size . An existing entry with the same
* name is silently replaced .
* @ param sheet The spritesheet this sprite ' s frames come from . Required .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p spr , @ p name , or @ p sheet is ` NULL ` .
* @ throws AKERR_KEY If the sprite cannot be written into # AKGL_REGISTRY_SPRITE
* - - in practice , because akgl_registry_init has not run .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
akerr_ErrorContext AKERR_NOIGNORE * akgl_sprite_initialize ( akgl_Sprite * spr , char * name , akgl_SpriteSheet * sheet ) ;
2025-08-03 10:07:35 -04:00
// loads a given image file into a new spritesheet
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Load an image file as a texture and publish it as a spritesheet .
*
* Uploads @ p filename through SDL_image using the global ` renderer ` , so the
* renderer must already be initialized . The sheet is registered in
* # AKGL_REGISTRY_SPRITESHEET under @ p filename , which is the key
* akgl_sprite_load_json looks it up by to avoid loading the same image twice .
*
* @ param sheet Pooled spritesheet to initialize , normally from
* akgl_heap_next_spritesheet . Required . Zeroed first , so a
* texture it already held is leaked rather than destroyed .
* @ param sprite_w Frame width in pixels . Accepted and currently discarded - -
* the frame grid actually used at draw time comes from the
* akgl_Sprite ' s ` width ` / ` height ` , not from here .
* @ param sprite_h Frame height in pixels . Same caveat as @ p sprite_w .
* @ param filename Path to the image , in any format SDL_image can decode .
* Required . Doubles as the registry key , so callers should pass
* an already - resolved path ; two spellings of the same file are
* two sheets . Truncated at
* # AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p sheet or @ p filename is ` NULL ` .
* @ throws AKGL_ERR_SDL If the image cannot be loaded - - missing , unreadable , or
* a format SDL_image was not built with . The message carries
* ` SDL_GetError ( ) ` .
* @ throws AKERR_KEY If the sheet cannot be written into
* # AKGL_REGISTRY_SPRITESHEET .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
akerr_ErrorContext AKERR_NOIGNORE * akgl_spritesheet_initialize ( akgl_SpriteSheet * sheet , int sprite_w , int sprite_h , char * filename ) ;
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Build a sprite - - and , if needed , its spritesheet - - from a JSON definition file .
*
* Reads ` name ` , ` width ` , ` height ` , ` speed ` ( seconds , scaled to milliseconds ) ,
* ` loop ` , ` loopReverse ` , a ` frames ` array of frame indices , and a ` spritesheet `
* object holding ` filename ` , ` frame_width ` , and ` frame_height ` . The sheet ' s
* ` filename ` is resolved * relative to the directory of @ p filename * , so a sprite
* definition can sit next to its image and move with it .
*
* If a spritesheet with that resolved path is already registered it is reused ;
* otherwise one is claimed from the pool and loaded . On failure both the sprite
* and any sheet loaded for it are released again .
*
* @ param filename Path to the JSON document . Required . Must be shorter than
* # AKGL_MAX_STRING_LENGTH - - it is copied into a pooled string
* so ` dirname ` can be taken without modifying the caller ' s
* buffer .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p filename is ` NULL ` , or if the file cannot be
* opened or does not parse . The message carries jansson ' s line number
* and text .
* @ throws AKERR_OUTOFBOUNDS If @ p filename is at least # AKGL_MAX_STRING_LENGTH
* bytes long , or if the ` frames ` array is indexed past its end .
* @ throws AKERR_KEY If a required key is absent , or if the sprite or sheet
* cannot be added to its registry . The message names the key .
* @ throws AKERR_TYPE If a key is present with the wrong JSON type - - ` speed ` as
* a string , ` frames ` as an object .
* @ throws AKGL_ERR_SDL If the spritesheet image fails to load .
* @ throws AKGL_ERR_HEAP If the sprite , spritesheet , or string pool is exhausted .
*
* @ note The ` frames ` array is not bounded against # AKGL_SPRITE_MAX_FRAMES . A
* definition with more than 16 frames writes past ` frameids ` into the
* rest of the struct .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
akerr_ErrorContext AKERR_NOIGNORE * akgl_sprite_load_json ( char * filename ) ;
2025-08-03 10:07:35 -04:00
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Work out where one animation frame sits on its spritesheet .
*
* Frames are numbered in reading order across the sheet : multiply the frame
* number by the sprite width , then wrap whole rows off the right - hand edge of
* the texture and step down by the sprite height for each . Callers use the
* result as the source rectangle for ` SDL_RenderTexture ` .
*
* @ param self The sprite whose sheet and frame geometry to use . Required ,
* along with its ` sheet ` .
* @ param srccoords Receives the frame ' s rectangle on the sheet , in pixels .
* Required - - the return value is the error context .
* @ param frameid Index into the sprite ' s ` frameids ` array , not a frame number
* on the sheet . Not bounds - checked against ` frames ` or
* # AKGL_SPRITE_MAX_FRAMES ; an out - of - range index reads a
* neighbouring struct member and yields a nonsense rectangle
* rather than an error .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p self , @ p srccoords , or ` self - > sheet ` is
* ` NULL ` . Note that ` sheet - > texture ` is dereferenced without a check ,
* so a registered - but - unloaded sheet is a crash rather than an error .
2026-07-30 01:10:31 -04:00
*/
2026-05-12 15:21:36 -04:00
akerr_ErrorContext * akgl_sprite_sheet_coords_for_frame ( akgl_Sprite * self , SDL_FRect * srccoords , uint8_t frameid ) ;
2026-05-06 23:18:42 -04:00
# endif //_AKGL_SPRITE_H_