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>
This commit is contained in:
@@ -1,6 +1,19 @@
|
||||
/**
|
||||
* @file renderer.h
|
||||
* @brief Declares the public renderer API.
|
||||
* @brief The pluggable rendering backend: a record of function pointers plus an initializer.
|
||||
*
|
||||
* There is one backend shipped, the 2D SDL one, and `akgl_render_init2d` is its
|
||||
* initializer -- it creates the window and the `SDL_Renderer` and then fills in
|
||||
* the six `akgl_render_2d_*` entry points. A different renderer is a different
|
||||
* initializer populating the same struct, not a branch inside these functions.
|
||||
*
|
||||
* Callers do not normally name the `akgl_render_2d_*` functions directly; they
|
||||
* go through the pointers on the backend (`renderer->frame_start(renderer)`),
|
||||
* which is what makes the swap possible. The global `renderer` in game.h is the
|
||||
* instance the rest of the library draws through.
|
||||
*
|
||||
* A frame is `frame_start` (clear), any number of `draw_*` calls, then
|
||||
* `frame_end` (present).
|
||||
*/
|
||||
|
||||
#ifndef _RENDERER_H_
|
||||
@@ -14,71 +27,146 @@
|
||||
|
||||
/** @brief Defines a pluggable renderer backend and drawing callbacks. */
|
||||
typedef struct akgl_RenderBackend {
|
||||
SDL_Renderer *sdl_renderer;
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*shutdown)(struct akgl_RenderBackend *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*frame_start)(struct akgl_RenderBackend *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*frame_end)(struct akgl_RenderBackend *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*draw_texture)(struct akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*draw_mesh)(struct akgl_RenderBackend *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*draw_world)(struct akgl_RenderBackend *self, akgl_Iterator *opflags);
|
||||
SDL_Renderer *sdl_renderer; /**< The SDL renderer, created by the initializer. Owned by SDL, not freed here. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*shutdown)(struct akgl_RenderBackend *self); /**< Tear the backend down. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*frame_start)(struct akgl_RenderBackend *self); /**< Begin a frame: clear the target. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*frame_end)(struct akgl_RenderBackend *self); /**< End a frame: present it. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*draw_texture)(struct akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip); /**< Blit one texture. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*draw_mesh)(struct akgl_RenderBackend *self); /**< Reserved for a 3D backend; the 2D one refuses. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*draw_world)(struct akgl_RenderBackend *self, akgl_Iterator *opflags); /**< Draw the whole scene, layer by layer. */
|
||||
} akgl_RenderBackend;
|
||||
|
||||
/**
|
||||
* @brief Render 2d shutdown.
|
||||
* @param self Backend or object instance to operate on.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_* Propagates an error reported by a delegated operation.
|
||||
* @brief Tear the 2D backend down.
|
||||
*
|
||||
* A no-op placeholder that always succeeds. The window and `SDL_Renderer` this
|
||||
* backend created are still owned by SDL and are reclaimed by `SDL_Quit`, so
|
||||
* there is nothing here to release yet; the hook exists so a backend that *does*
|
||||
* own resources has somewhere to free them.
|
||||
*
|
||||
* @param self The backend to shut down. Ignored -- not even dereferenced, so
|
||||
* `NULL` is currently harmless.
|
||||
* @return `NULL` always. It has no failure path today; check it anyway, because
|
||||
* a backend that acquires anything will grow one.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_shutdown(akgl_RenderBackend *self);
|
||||
/**
|
||||
* @brief Render 2d frame start.
|
||||
* @param self Backend or object instance to operate on.
|
||||
* @brief Begin a frame: clear the render target to opaque black.
|
||||
* @param self The backend to draw through. Required, and dereferenced *before*
|
||||
* it is checked -- a `NULL` @p self is a crash, not an error.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER When the corresponding validation or operation fails.
|
||||
* @throws AKERR_NULLPOINTER If `self->sdl_renderer` is `NULL`, which means the
|
||||
* backend was never run through akgl_render_init2d.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_start(akgl_RenderBackend *self);
|
||||
/**
|
||||
* @brief Render 2d frame end.
|
||||
* @param self Backend or object instance to operate on.
|
||||
* @brief End a frame: present everything drawn since akgl_render_2d_frame_start.
|
||||
* @param self The backend to draw through. Required, and dereferenced *before*
|
||||
* it is checked -- a `NULL` @p self is a crash, not an error.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER When the corresponding validation or operation fails.
|
||||
* @throws AKERR_NULLPOINTER If `self->sdl_renderer` is `NULL`, which means the
|
||||
* backend was never run through akgl_render_init2d.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_end(akgl_RenderBackend *self);
|
||||
/**
|
||||
* @brief Render 2d draw texture.
|
||||
* @param self Backend or object instance to operate on.
|
||||
* @param texture SDL texture to draw.
|
||||
* @param src Source value to copy or inspect.
|
||||
* @param dest Output destination populated by the function.
|
||||
* @param angle Clockwise rotation angle in degrees.
|
||||
* @param center Optional rotation center.
|
||||
* @param flip SDL texture flip mode.
|
||||
* @brief Blit a texture, rotating it only when asked to.
|
||||
*
|
||||
* A rotation of exactly 0 takes the plain `SDL_RenderTexture` path, which is why
|
||||
* @p center and @p flip are only consulted when @p angle is non-zero.
|
||||
*
|
||||
* @param self The backend to draw through. Required.
|
||||
* @param texture The texture to blit. Required.
|
||||
* @param src The rectangle of @p texture to take, in pixels. Optional --
|
||||
* `NULL` means the whole texture.
|
||||
* @param dest Where to put it on the render target, in pixels. Optional --
|
||||
* `NULL` means stretch to fill the whole target. Not an output
|
||||
* parameter despite the name.
|
||||
* @param angle Clockwise rotation in degrees. Exactly 0 skips rotation
|
||||
* entirely, along with @p center and @p flip.
|
||||
* @param center Pivot for the rotation, relative to @p dest. Required *when*
|
||||
* @p angle is non-zero, ignored otherwise. SDL's own "NULL means
|
||||
* the centre of dest" convention is not available here.
|
||||
* @param flip Horizontal/vertical mirroring. Applied only on the rotated
|
||||
* path; ignored when @p angle is 0.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER When the corresponding validation or operation fails.
|
||||
* @throws AKERR_NULLPOINTER If @p self or @p texture is `NULL`; if @p angle is
|
||||
* non-zero and @p center is `NULL`; or if the SDL draw call itself
|
||||
* fails, in which case the message carries `SDL_GetError()`. That last
|
||||
* case is a reused status rather than a pointer problem.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_texture(akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip);
|
||||
/**
|
||||
* @brief Render 2d draw mesh.
|
||||
* @param self Backend or object instance to operate on.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_API When the corresponding validation or operation fails.
|
||||
* @brief Draw geometry. Not implemented by the 2D backend.
|
||||
*
|
||||
* The hook exists so a 3D backend has a slot to fill; this one refuses every
|
||||
* call. It is not a stub that quietly does nothing -- it fails loudly, so a
|
||||
* caller that reaches it finds out at once.
|
||||
*
|
||||
* @param self The backend. Ignored.
|
||||
* @return Never `NULL`.
|
||||
* @throws AKERR_API Always, with the message "Not implemented".
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_mesh(akgl_RenderBackend *self);
|
||||
/**
|
||||
* @brief Render 2d draw world.
|
||||
* @param self Backend or object instance to operate on.
|
||||
* @param opflags Optional iterator operation flags; `NULL` selects defaults.
|
||||
* @brief Draw the whole scene: every tilemap layer, and the actors standing on it.
|
||||
*
|
||||
* Walks layers from 0 to #AKGL_TILEMAP_MAX_LAYERS. For each, it draws that layer
|
||||
* of the global `gamemap` through `camera` (if the map has that many layers),
|
||||
* then sweeps the actor pool and calls `renderfunc` on every live actor whose
|
||||
* `layer` matches. Sweeping in layer order is what puts actors in front of the
|
||||
* scenery they stand on and behind the scenery they walk under.
|
||||
*
|
||||
* It reads the globals `gamemap`, `camera`, and `HEAP_ACTOR` directly rather
|
||||
* than taking them as arguments, so there is exactly one world to draw.
|
||||
*
|
||||
* @param self The backend to draw through. Required.
|
||||
* @param opflags Iterator flags. Optional -- `NULL` substitutes a zeroed set.
|
||||
* Currently ignored either way: this function sweeps the actor
|
||||
* pool itself instead of going through
|
||||
* akgl_registry_iterate_actor, so no `AKGL_ITERATOR_OP_*` bit
|
||||
* reaches anything. The parameter is here for the backend
|
||||
* signature and for the layer-mask support that has yet to be
|
||||
* wired up.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER When the corresponding validation or operation fails.
|
||||
* @throws AKERR_NULLPOINTER If @p self is `NULL`.
|
||||
* @throws AKERR_* Whatever akgl_tilemap_draw or an actor's own `renderfunc`
|
||||
* raises; the first failure aborts the frame and propagates unchanged.
|
||||
*
|
||||
* @warning Neither the global `gamemap` nor a live actor's `renderfunc` is
|
||||
* checked before use, so drawing before akgl_tilemap_load, or with a
|
||||
* hand-built actor that was never run through akgl_actor_initialize,
|
||||
* is a crash rather than an error context.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_world(akgl_RenderBackend *self, akgl_Iterator *opflags);
|
||||
|
||||
/**
|
||||
* @brief Render init2d.
|
||||
* @param self Backend or object instance to operate on.
|
||||
* @brief Create the window and SDL renderer, and bind the 2D backend's methods.
|
||||
*
|
||||
* Reads `game.screenwidth` and `game.screenheight` from the property registry
|
||||
* (both defaulting to the string "0", which asks SDL for a zero-sized window),
|
||||
* creates the window and renderer with `game.uri` as the title, points `camera`
|
||||
* at the full screen rectangle, and installs the six `akgl_render_2d_*` function
|
||||
* pointers on @p self.
|
||||
*
|
||||
* Because the dimensions come from the registry, akgl_registry_init_properties
|
||||
* and the property writes have to happen first -- see the note on
|
||||
* akgl_registry_init about the properties registry not being initialized for
|
||||
* callers that skip akgl_game_init.
|
||||
*
|
||||
* @param self The backend to initialize. Required. Its `sdl_renderer` and method
|
||||
* pointers are overwritten; anything it held before is not released.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER When the corresponding validation or operation fails.
|
||||
* @throws AKGL_ERR_SDL When the corresponding validation or operation fails.
|
||||
* @throws AKERR_NULLPOINTER If @p self is `NULL`.
|
||||
* @throws AKERR_VALUE If `game.screenwidth` or `game.screenheight` is set to
|
||||
* something that is not a base-10 integer.
|
||||
* @throws ERANGE If either dimension does not fit in an `int`.
|
||||
* @throws AKGL_ERR_SDL If the window and renderer cannot be created. The message
|
||||
* carries `SDL_GetError()`.
|
||||
* @throws AKGL_ERR_HEAP If the string pool is exhausted while reading the two
|
||||
* properties.
|
||||
*
|
||||
* @note The two pooled strings holding the dimensions are only released on the
|
||||
* success path, so each failed initialization leaks two string slots.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_init2d(akgl_RenderBackend *self);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user