Draw actors at their sprite's height, and update each one once a frame
Closes Defects item 26 and Performance item 32. akgl_actor_render set dest.h from curSprite->width, so every actor was drawn square and a non-square sprite was stretched or squashed. Invisible in the fixtures because they are all square, so tests/actor.c gets a 48x24 sprite and a render backend whose draw_texture records the rectangle it is handed instead of drawing it. That recording backend is the first coverage akgl_actor_render has had at all -- every other test in the file stubs renderfunc out. akgl_game_update looped over AKGL_TILEMAP_MAX_LAYERS with the actor sweep nested inside it and never compared an actor's layer to the layer it was on, so every live actor's updatefunc ran sixteen times a frame. The sweep is hoisted out: updating an actor is not a per-layer operation, and akgl_render_2d_draw_world already walks the layers for the half that is. AKGL_ITERATOR_OP_LAYERMASK is honoured rather than ignored now, so a caller who wants one layer can still ask, and gets each of those actors once. Counting is the assertion, deliberately. The defect was invisible in the frame total because the tilemap blits are three orders of magnitude larger, so a timing test would have measured the rasterizer. tests/game.c counts calls into a stub updatefunc and reports 16 against the old code. PERFORMANCE.md records the timing side as what it honestly is: the gap between the akgl_game_update and draw_world rows of the same run, 92 us before and noise in both directions after. The absolute table is not re-taken -- a later run on this machine read every row about 15% high, including rows nothing has touched. 25/25 pass, reindent --check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -282,17 +282,24 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_state_unlock(void);
|
||||
/**
|
||||
* @brief One frame: update every actor layer by layer, step the physics, draw the world.
|
||||
*
|
||||
* Takes the state lock, counts the frame, then walks layers 0 through
|
||||
* #AKGL_TILEMAP_MAX_LAYERS calling each live actor's `updatefunc`, optionally
|
||||
* rescaling it to the tilemap first. Then it steps `akgl_physics` and draws through
|
||||
* `akgl_renderer`, and releases the lock.
|
||||
* Takes the state lock, counts the frame, then calls each live actor's
|
||||
* `updatefunc` **exactly once**, optionally rescaling it to the tilemap first.
|
||||
* Then it steps `akgl_physics` and draws through `akgl_renderer`, and releases
|
||||
* the lock.
|
||||
*
|
||||
* @param opflags Iterator flags. Optional -- `NULL` selects a default set that
|
||||
* sweeps one layer at a time, in which case `layerid` is advanced
|
||||
* by the loop. Only #AKGL_ITERATOR_OP_TILEMAPSCALE is read here;
|
||||
* with it clear every actor's `scale` is forced to 1.0. Note that
|
||||
* the flags are *not* forwarded to the physics or render calls,
|
||||
* both of which are passed `NULL`.
|
||||
* Until 0.5.0 the sweep sat inside a walk over #AKGL_TILEMAP_MAX_LAYERS that
|
||||
* never compared an actor's `layer` to the layer it was on, so every actor
|
||||
* updated sixteen times a frame. Updating an actor is not a per-layer
|
||||
* operation; drawing is, and akgl_render_2d_draw_world walks the layers itself.
|
||||
*
|
||||
* @param opflags Iterator flags. Optional -- `NULL` selects
|
||||
* #AKGL_ITERATOR_OP_UPDATE alone, which is every live actor
|
||||
* once. Two bits are read here:
|
||||
* #AKGL_ITERATOR_OP_TILEMAPSCALE, without which every actor's
|
||||
* `scale` is forced to 1.0; and #AKGL_ITERATOR_OP_LAYERMASK,
|
||||
* which restricts the sweep to the actors whose `layer` matches
|
||||
* `layerid`. Note that the flags are *not* forwarded to the
|
||||
* physics or render calls, both of which are passed `NULL`.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKGL_ERR_SDL If the state lock cannot be taken.
|
||||
* @throws AKERR_* Whatever an actor's `updatefunc`, akgl_tilemap_scale_actor,
|
||||
|
||||
Reference in New Issue
Block a user