Fix the type, macro and state-table defects, and the leftover debris
Closes internal-consistency items 19 through 36, 38 and 41. Item 37, the ~180 redundant casts, is deliberately left open with its reasoning in TODO.md: the benefit only arrives once the build turns on the warnings those casts suppress, and doing it before that is churn across the two files with the most outstanding functional defects. The two that were real bugs are in the actor state table. AKGL_ACTOR_STATE_STRING_NAMES was declared [AKGL_ACTOR_MAX_STATES+1] and defined [32], so a consumer trusting the declared bound read past the object; and indices 11 and 12 were named UNDEFINED_11 and UNDEFINED_12 where actor.h has MOVING_IN and MOVING_OUT, so no character JSON could bind a sprite to either state. tests/registry.c now walks the whole table -- every entry non-NULL, every entry resolving to its own bit, no two entries sharing a name. The bitmask macros are parenthesized and AKGL_BITMASK_CLEAR has lost the semicolon inside its body. Writing tests/bitmasks.c for that turned up something worth knowing: the obvious test does not catch it. For a bit that is set, the misparse `!(mask & bit) == bit` gives the same answer as the correct one. It only diverges for an unset bit whose value is not 1, and that is the shape the suite uses now. akgl_draw_background was the last public function outside the error protocol. It takes a backend like everything else in draw.h, restores the draw colour it found, and is tested -- TODO.md had it filed under "needs the offscreen renderer harness", which was never true; what it needed was to stop reading the global. All eight registry initializers go through one helper, so the seven that leaked an SDL_PropertiesID on every call after the first no longer do. Fixed in the same place because it is the same function: akgl_registry_init never called akgl_registry_init_properties, which made akgl_set_property a silent no-op for anyone not going through akgl_game_init -- Defects, Known and still open item 3. Also: AKGL_COLLIDE_RECTANGLES (three open parens, two closes) and akgl_Frame deleted, float32_t/float64_t used consistently, the developer-specific debug logging removed from the controller inner loop, the abandoned SDL_GetBasePath comments removed, nine unused locals removed, and dst renamed to dest. akgl_game_update's default flags no longer OR the same bit twice. That changes nothing today, and the reason is Performance item 32: the loop never reads either bit, which is why every actor is updated sixteen times a frame. Still open. 25/25 pass, memcheck clean, reindent --check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,49 +37,50 @@
|
||||
#include <akgl/character.h>
|
||||
|
||||
// ---- LOW WORD STATUSES ----
|
||||
//
|
||||
// The trailing column is the bit pattern within its own 16-bit half -- the
|
||||
// low half here, the high half below -- not the full 32-bit value. Read as a
|
||||
// whole word it looks like bit 16 restarts at bit 0, which it does not.
|
||||
|
||||
#define AKGL_ACTOR_STATE_FACE_DOWN 1 << 0 // 1 0000 0000 0000 0001
|
||||
#define AKGL_ACTOR_STATE_FACE_LEFT 1 << 1 // 2 0000 0000 0000 0010
|
||||
#define AKGL_ACTOR_STATE_FACE_RIGHT 1 << 2 // 4 0000 0000 0000 0100
|
||||
#define AKGL_ACTOR_STATE_FACE_UP 1 << 3 // 8 0000 0000 0000 1000
|
||||
#define AKGL_ACTOR_STATE_ALIVE 1 << 4 // 16 0000 0000 0001 0000
|
||||
#define AKGL_ACTOR_STATE_DYING 1 << 5 // 32 0000 0000 0010 0000
|
||||
#define AKGL_ACTOR_STATE_DEAD 1 << 6 // 64 0000 0000 0100 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_LEFT 1 << 7 // 128 0000 0000 1000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_RIGHT 1 << 8 // 256 0000 0001 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_UP 1 << 9 // 512 0000 0010 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_DOWN 1 << 10 // 1024 0000 0100 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_IN 1 << 11 // 2048 0000 1000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_OUT 1 << 12 // 4096 0001 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_13 1 << 13 // 8192 0010 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_14 1 << 14 // 16384 0100 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_15 1 << 15 // 32768 1000 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_FACE_DOWN (1 << 0) // 1 0000 0000 0000 0001
|
||||
#define AKGL_ACTOR_STATE_FACE_LEFT (1 << 1) // 2 0000 0000 0000 0010
|
||||
#define AKGL_ACTOR_STATE_FACE_RIGHT (1 << 2) // 4 0000 0000 0000 0100
|
||||
#define AKGL_ACTOR_STATE_FACE_UP (1 << 3) // 8 0000 0000 0000 1000
|
||||
#define AKGL_ACTOR_STATE_ALIVE (1 << 4) // 16 0000 0000 0001 0000
|
||||
#define AKGL_ACTOR_STATE_DYING (1 << 5) // 32 0000 0000 0010 0000
|
||||
#define AKGL_ACTOR_STATE_DEAD (1 << 6) // 64 0000 0000 0100 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_LEFT (1 << 7) // 128 0000 0000 1000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_RIGHT (1 << 8) // 256 0000 0001 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_UP (1 << 9) // 512 0000 0010 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_DOWN (1 << 10) // 1024 0000 0100 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_IN (1 << 11) // 2048 0000 1000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_MOVING_OUT (1 << 12) // 4096 0001 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_13 (1 << 13) // 8192 0010 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_14 (1 << 14) // 16384 0100 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_15 (1 << 15) // 32768 1000 0000 0000 0000
|
||||
|
||||
// ----- HIGH WORD STATUSES -----
|
||||
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_16 1 << 16 // 65536 0000 0000 0000 0001
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_17 1 << 17 // 131072 0000 0000 0000 0010
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_18 1 << 18 // 262144 0000 0000 0000 0100
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_19 1 << 19 // 524288 0000 0000 0000 1000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_20 1 << 20 // 1048576 0000 0000 0001 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_21 1 << 21 // 2097152 0000 0000 0010 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_22 1 << 22 // 4194304 0000 0000 0100 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_23 1 << 23 // 8388608 0000 0000 1000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_24 1 << 24 // 16777216 0000 0001 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_25 1 << 25 // 33554432 0000 0010 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_26 1 << 26 // 67108864 0000 0100 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_27 1 << 27 // 134217728 0000 1000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_28 1 << 28 // 268435456 0001 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_29 1 << 29 // 536870912 0010 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_30 1 << 30 // 1073741824 0100 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_31 1 << 31 // 2147483648 1000 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_16 (1 << 16) // 65536 0000 0000 0000 0001
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_17 (1 << 17) // 131072 0000 0000 0000 0010
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_18 (1 << 18) // 262144 0000 0000 0000 0100
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_19 (1 << 19) // 524288 0000 0000 0000 1000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_20 (1 << 20) // 1048576 0000 0000 0001 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_21 (1 << 21) // 2097152 0000 0000 0010 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_22 (1 << 22) // 4194304 0000 0000 0100 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_23 (1 << 23) // 8388608 0000 0000 1000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_24 (1 << 24) // 16777216 0000 0001 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_25 (1 << 25) // 33554432 0000 0010 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_26 (1 << 26) // 67108864 0000 0100 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_27 (1 << 27) // 134217728 0000 1000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_28 (1 << 28) // 268435456 0001 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_29 (1 << 29) // 536870912 0010 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_30 (1 << 30) // 1073741824 0100 0000 0000 0000
|
||||
#define AKGL_ACTOR_STATE_UNDEFINED_31 (1 << 31) // 2147483648 1000 0000 0000 0000
|
||||
|
||||
/** @brief Bits in an actor's state word. Fixed by the width of `int32_t state`. */
|
||||
#define AKGL_ACTOR_MAX_STATES 32
|
||||
|
||||
// This is an array of strings equal to actor states from 1-32.
|
||||
// This is built by a utility script and not kept in git, see
|
||||
// the Makefile for lib_src/actor_state_string_names.c
|
||||
/**
|
||||
* @brief Bit position -> state name, as text. Index `i` names the bit `1 << i`.
|
||||
*
|
||||
@@ -87,17 +88,14 @@
|
||||
* #AKGL_REGISTRY_ACTOR_STATE_STRINGS out of this, which is what lets character
|
||||
* JSON write `"AKGL_ACTOR_STATE_FACE_LEFT"` instead of `2`. A bit whose name
|
||||
* here does not match its `#define` above cannot be referred to from JSON at
|
||||
* all.
|
||||
* all -- which was the case for `MOVING_IN` and `MOVING_OUT` until 0.5.0.
|
||||
*
|
||||
* @warning Three known defects, all tracked in TODO.md items 24-26: the
|
||||
* definition in `src/actor_state_string_names.c` is 32 entries while
|
||||
* this declares 33, so reading index 32 reads past the object; bits 11
|
||||
* and 12 are named `UNDEFINED_11`/`UNDEFINED_12` rather than
|
||||
* `MOVING_IN`/`MOVING_OUT`; and the comment above about a generator
|
||||
* script is stale -- there is no such script, and the file is tracked
|
||||
* in git and maintained by hand.
|
||||
* Maintained by hand in `src/actor_state_string_names.c`, and exactly
|
||||
* #AKGL_ACTOR_MAX_STATES entries long: it was declared one longer than it was
|
||||
* defined until 0.5.0, so a consumer trusting the declared bound read past the
|
||||
* object. `tests/registry.c` checks every entry against its bit.
|
||||
*/
|
||||
extern char *AKGL_ACTOR_STATE_STRING_NAMES[AKGL_ACTOR_MAX_STATES+1];
|
||||
extern char *AKGL_ACTOR_STATE_STRING_NAMES[AKGL_ACTOR_MAX_STATES];
|
||||
|
||||
/** @brief Every facing bit. Clear this before setting one, so an actor faces exactly one way. */
|
||||
#define AKGL_ACTOR_STATE_FACE_ALL (AKGL_ACTOR_STATE_FACE_DOWN | AKGL_ACTOR_STATE_FACE_LEFT | AKGL_ACTOR_STATE_FACE_RIGHT | AKGL_ACTOR_STATE_FACE_UP)
|
||||
|
||||
@@ -39,18 +39,27 @@
|
||||
/**
|
||||
* @brief Paint an 8x8 grey checkerboard over a region, the way an image editor shows transparency.
|
||||
*
|
||||
* A diagnostic backdrop, not a general primitive -- `charviewer` uses it so a
|
||||
* sprite's transparent pixels are visible rather than blending into black. It
|
||||
* is the one function in this file that does not follow the file's conventions:
|
||||
* it draws through the *global* `akgl_renderer` rather than a backend the caller
|
||||
* passes in, it leaves the renderer's draw colour changed, and it reports
|
||||
* nothing.
|
||||
* A diagnostic backdrop rather than a general primitive -- `charviewer` uses it
|
||||
* so a sprite's transparent pixels are visible instead of blending into black.
|
||||
*
|
||||
* @param w Width of the region to cover, in pixels, starting at x = 0.
|
||||
* @param h Height of the region, starting at y = 0. Both round up to whole 8px
|
||||
* cells, so a 12-pixel height paints 16.
|
||||
* Until 0.5.0 this was the one function in the library outside the error
|
||||
* protocol: it returned `void`, drew through the *global* `akgl_renderer`
|
||||
* without checking it, and left the renderer's draw colour changed. It now
|
||||
* takes a backend like every other entry point here and restores the colour it
|
||||
* found, which is also what makes it testable without a world.
|
||||
*
|
||||
* @param self The backend to draw through. Required, along with its
|
||||
* `sdl_renderer`.
|
||||
* @param w Width of the region to cover, in pixels, starting at x = 0. Zero
|
||||
* or negative paints nothing and is not reported.
|
||||
* @param h Height of the region, starting at y = 0. Both round up to whole
|
||||
* 8px cells, so a 12-pixel height paints 16.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p self or `self->sdl_renderer` is `NULL`.
|
||||
* @throws AKGL_ERR_SDL If the draw colour cannot be read or set, or a cell
|
||||
* cannot be filled.
|
||||
*/
|
||||
void akgl_draw_background(int w, int h);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_draw_background(akgl_RenderBackend *self, int w, int h);
|
||||
|
||||
/**
|
||||
* @brief Plot a single pixel.
|
||||
|
||||
@@ -74,13 +74,6 @@
|
||||
|
||||
/* ==================== GAME STATE VARIABLES =================== */
|
||||
|
||||
/** @brief Describes a renderable frame. Declared but not used by anything in the library. */
|
||||
typedef struct {
|
||||
float32_t w; /**< Width in pixels. */
|
||||
float32_t h; /**< Height in pixels. */
|
||||
SDL_Texture *texture; /**< The frame's texture. */
|
||||
} akgl_Frame;
|
||||
|
||||
/** @brief Stores application-defined game-state flags. */
|
||||
typedef struct {
|
||||
int32_t flags; /**< Meaning is entirely the application's; the library never reads it. Guard changes with akgl_game_state_lock. */
|
||||
@@ -132,19 +125,29 @@ extern SDL_FRect *akgl_camera;
|
||||
|
||||
/**
|
||||
* @brief True when every bit of `y` is set in `x`. Not "any of them" -- all of them.
|
||||
* @warning Unparenthesized: it expands to `(x & y) == y`, so `!AKGL_BITMASK_HAS(a, b)`
|
||||
* parses as `!(a & b) == b`. Use #AKGL_BITMASK_HASNOT rather than
|
||||
* negating this. TODO.md item 21.
|
||||
*
|
||||
* Fully parenthesized, so it composes: `!AKGL_BITMASK_HAS(a, b)` and
|
||||
* `AKGL_BITMASK_HAS(a, b) && cond` both mean what they read as. Until 0.5.0 it
|
||||
* expanded to a bare `(x & y) == y`, so a negation bound to the `&` and parsed
|
||||
* as `!(a & b) == b`. Nothing in the tree negated it -- #AKGL_BITMASK_HASNOT
|
||||
* exists for that -- which is the only reason it was latent rather than live.
|
||||
*/
|
||||
#define AKGL_BITMASK_HAS(x, y) (x & y) == y
|
||||
/** @brief True when at least one bit of `y` is missing from `x`. Same parenthesization caveat as #AKGL_BITMASK_HAS. */
|
||||
#define AKGL_BITMASK_HASNOT(x, y) (x & y) != y
|
||||
#define AKGL_BITMASK_HAS(x, y) ((((x) & (y)) == (y)))
|
||||
/** @brief True when at least one bit of `y` is missing from `x`. */
|
||||
#define AKGL_BITMASK_HASNOT(x, y) ((((x) & (y)) != (y)))
|
||||
/** @brief Set every bit of `y` in `x`. Modifies `x`. */
|
||||
#define AKGL_BITMASK_ADD(x, y) x |= y
|
||||
#define AKGL_BITMASK_ADD(x, y) ((x) |= (y))
|
||||
/** @brief Clear every bit of `y` in `x`. Modifies `x`. */
|
||||
#define AKGL_BITMASK_DEL(x, y) x &= ~(y)
|
||||
/** @brief Clear every bit of `x`. Carries its own trailing semicolon, so do not add another. */
|
||||
#define AKGL_BITMASK_CLEAR(x) x = 0;
|
||||
#define AKGL_BITMASK_DEL(x, y) ((x) &= ~(y))
|
||||
/**
|
||||
* @brief Clear every bit of `x`. Modifies `x`.
|
||||
*
|
||||
* Carries no trailing semicolon: write `AKGL_BITMASK_CLEAR(flags);` like any
|
||||
* other statement. It used to include one, so every ordinary use produced an
|
||||
* empty statement after it and a use as the whole body of an unbraced `if`
|
||||
* would have taken the following statement with it.
|
||||
*/
|
||||
#define AKGL_BITMASK_CLEAR(x) ((x) = 0)
|
||||
|
||||
/**
|
||||
* @brief Bring the whole library up: error codes, pools, registries, SDL, audio, fonts, gamepads.
|
||||
|
||||
@@ -28,38 +28,38 @@ typedef struct {
|
||||
uint8_t layerid; /**< Layer to restrict the sweep to. Read only when #AKGL_ITERATOR_OP_LAYERMASK is set. */
|
||||
} akgl_Iterator;
|
||||
|
||||
#define AKGL_ITERATOR_OP_UPDATE 1 // 1 Call the actor's updatefunc
|
||||
#define AKGL_ITERATOR_OP_RENDER 1 << 1 // 2 Call the actor's renderfunc
|
||||
#define AKGL_ITERATOR_OP_RELEASE 1 << 2 // 4 Release the object back to its heap layer
|
||||
#define AKGL_ITERATOR_OP_LAYERMASK 1 << 3 // 8 Skip anything whose layer != layerid
|
||||
#define AKGL_ITERATOR_OP_TILEMAPSCALE 1 << 4 // 16 Scale actors to the tilemap; otherwise force scale 1.0
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_5 1 << 5 // 32
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_6 1 << 6 // 64
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_7 1 << 7 // 128
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_8 1 << 8 // 256
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_9 1 << 9 // 512
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_10 1 << 10 // 1024
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_11 1 << 11 // 2048
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_12 1 << 12 // 4096
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_13 1 << 13 // 8192
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_14 1 << 14 // 16384
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_15 1 << 15 // 32768
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_16 1 << 16 // 65536
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_17 1 << 17 // 131072
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_18 1 << 18 // 262144
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_19 1 << 19 // 524288
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_20 1 << 20 // 1048576
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_21 1 << 21 // 2097152
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_22 1 << 22 // 4194304
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_23 1 << 23 // 8388608
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_24 1 << 24 // 16777216
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_25 1 << 25 // 33554432
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_26 1 << 26 // 67108864
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_27 1 << 27 // 134217728
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_28 1 << 28 // 268435456
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_29 1 << 29 // 536870912
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_30 1 << 30 // 1073741824
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_31 1 << 31 // 2147483648
|
||||
#define AKGL_ITERATOR_OP_UPDATE (1 << 0) // 1 Call the actor's updatefunc
|
||||
#define AKGL_ITERATOR_OP_RENDER (1 << 1) // 2 Call the actor's renderfunc
|
||||
#define AKGL_ITERATOR_OP_RELEASE (1 << 2) // 4 Release the object back to its heap layer
|
||||
#define AKGL_ITERATOR_OP_LAYERMASK (1 << 3) // 8 Skip anything whose layer != layerid
|
||||
#define AKGL_ITERATOR_OP_TILEMAPSCALE (1 << 4) // 16 Scale actors to the tilemap; otherwise force scale 1.0
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_5 (1 << 5) // 32
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_6 (1 << 6) // 64
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_7 (1 << 7) // 128
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_8 (1 << 8) // 256
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_9 (1 << 9) // 512
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_10 (1 << 10) // 1024
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_11 (1 << 11) // 2048
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_12 (1 << 12) // 4096
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_13 (1 << 13) // 8192
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_14 (1 << 14) // 16384
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_15 (1 << 15) // 32768
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_16 (1 << 16) // 65536
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_17 (1 << 17) // 131072
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_18 (1 << 18) // 262144
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_19 (1 << 19) // 524288
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_20 (1 << 20) // 1048576
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_21 (1 << 21) // 2097152
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_22 (1 << 22) // 4194304
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_23 (1 << 23) // 8388608
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_24 (1 << 24) // 16777216
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_25 (1 << 25) // 33554432
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_26 (1 << 26) // 67108864
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_27 (1 << 27) // 134217728
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_28 (1 << 28) // 268435456
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_29 (1 << 29) // 536870912
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_30 (1 << 30) // 1073741824
|
||||
#define AKGL_ITERATOR_OP_UNDEFINED_31 (1 << 31) // 2147483648
|
||||
|
||||
|
||||
#endif // _AKGL_ITERATOR_H_
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define _AKGL_JSON_HELPERS_H_
|
||||
|
||||
#include <akerror.h>
|
||||
#include <akgl/types.h>
|
||||
#include <jansson.h>
|
||||
#include <akgl/staticstring.h>
|
||||
|
||||
@@ -85,7 +86,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_integer_value(json_t *obj, char
|
||||
* @throws AKERR_TYPE If @p key is present but is not a number. Integers and
|
||||
* reals are both accepted, so `1` and `1.0` behave alike.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_number_value(json_t *obj, char *key, float *dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_number_value(json_t *obj, char *key, float32_t *dest);
|
||||
/**
|
||||
* @brief Read a number out of a JSON object as a `double`.
|
||||
*
|
||||
@@ -101,7 +102,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_number_value(json_t *obj, char
|
||||
* @throws AKERR_KEY If @p key is absent.
|
||||
* @throws AKERR_TYPE If @p key is present but is not a number.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_double_value(json_t *obj, char *key, double *dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_double_value(json_t *obj, char *key, float64_t *dest);
|
||||
/**
|
||||
* @brief Read a string out of a JSON object into a pooled akgl_String.
|
||||
*
|
||||
|
||||
@@ -41,12 +41,12 @@ typedef struct akgl_PhysicsBackend {
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*collide)(struct akgl_PhysicsBackend *self, akgl_Actor *a1, akgl_Actor *a2); /**< Resolve a collision between two actors. Not called by the simulation loop yet. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*move)(struct akgl_PhysicsBackend *self, akgl_Actor *actor, float32_t dt); /**< Commit one actor's velocity to its position. */
|
||||
|
||||
double drag_x; /**< Fraction of environmental velocity shed per second along x. 0 disables. From `physics.drag.x`. */
|
||||
double drag_y; /**< Drag along y. From `physics.drag.y`. */
|
||||
double drag_z; /**< Drag along z. From `physics.drag.z`. */
|
||||
double gravity_x; /**< Acceleration along x, world units per second squared. Applied toward screen left. From `physics.gravity.x`. */
|
||||
double gravity_y; /**< Acceleration along y. Applied down the screen, since y grows downward. From `physics.gravity.y`. */
|
||||
double gravity_z; /**< Acceleration along z. Applied away from the camera. From `physics.gravity.z`. */
|
||||
float64_t drag_x; /**< Fraction of environmental velocity shed per second along x. 0 disables. From `physics.drag.x`. */
|
||||
float64_t drag_y; /**< Drag along y. From `physics.drag.y`. */
|
||||
float64_t drag_z; /**< Drag along z. From `physics.drag.z`. */
|
||||
float64_t gravity_x; /**< Acceleration along x, world units per second squared. Applied toward screen left. From `physics.gravity.x`. */
|
||||
float64_t gravity_y; /**< Acceleration along y. Applied down the screen, since y grows downward. From `physics.gravity.y`. */
|
||||
float64_t gravity_z; /**< Acceleration along z. Applied away from the camera. From `physics.gravity.z`. */
|
||||
SDL_Time gravity_time; /**< Timestamp of the previous step, in nanoseconds. The simulation's `dt` is measured from this. */
|
||||
SDL_Time timer_gravity; /**< Unused. Nothing in the library reads or writes it. */
|
||||
} akgl_PhysicsBackend;
|
||||
|
||||
@@ -50,10 +50,10 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_string_initialize(akgl_String *obj, char
|
||||
* @brief Copy the contents of one pooled string into another.
|
||||
*
|
||||
* A bounded `strncpy` between two already-claimed pool slots. It copies bytes
|
||||
* only: `refcount` is left alone, so @p dst keeps whatever pool state it had.
|
||||
* only: `refcount` is left alone, so @p dest keeps whatever pool state it had.
|
||||
*
|
||||
* @param src Source string. Required. Read up to @p count bytes.
|
||||
* @param dst Destination string. Required. Overwritten in place; the pool
|
||||
* @param dest Destination string. Required. Overwritten in place; the pool
|
||||
* slot must already have been claimed.
|
||||
* @param count Maximum bytes to copy. 0 selects #AKGL_MAX_STRING_LENGTH, the
|
||||
* whole buffer. A @p count shorter than the source truncates
|
||||
@@ -62,10 +62,10 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_string_initialize(akgl_String *obj, char
|
||||
* #AKGL_MAX_STRING_LENGTH overrun both buffers and are not
|
||||
* rejected.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p src or @p dst is `NULL`.
|
||||
* @throws AKERR_NULLPOINTER If @p src or @p dest is `NULL`.
|
||||
* @throws errno Whatever `errno` holds if `strncpy` returns something other
|
||||
* than @p dst. In practice `strncpy` always returns its destination, so
|
||||
* than @p dest. In practice `strncpy` always returns its destination, so
|
||||
* this path is unreachable rather than merely rare.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_string_copy(akgl_String *src, akgl_String *dst, int count);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_string_copy(akgl_String *src, akgl_String *dest, int count);
|
||||
#endif //_AKGL_STATICSTRING_H_
|
||||
|
||||
@@ -71,8 +71,8 @@
|
||||
|
||||
/** @brief One object placed in a Tiled object layer. */
|
||||
typedef struct {
|
||||
float x; /**< Position in map pixels, from the Tiled object. Copied onto the actor it spawns. */
|
||||
float y; /**< Position in map pixels. */
|
||||
float32_t x; /**< Position in map pixels, from the Tiled object. Copied onto the actor it spawns. */
|
||||
float32_t y; /**< Position in map pixels. */
|
||||
int gid; /**< Global tile id, for a tile object. Not read by the loader. */
|
||||
int id; /**< Tiled's object id. Not read by the loader. */
|
||||
int height; /**< Height in map pixels. Read into the map's perspective bands, not into this field. */
|
||||
@@ -87,7 +87,7 @@ typedef struct {
|
||||
/** @brief One layer of a tilemap: a tile grid, an image, or a group of objects. */
|
||||
typedef struct {
|
||||
short type; /**< Which of the `AKGL_TILEMAP_LAYER_TYPE_*` kinds this is; decides which of the members below mean anything. */
|
||||
float opacity; /**< 0.0 to 1.0, from Tiled. Recorded but not yet applied at draw time. */
|
||||
float32_t opacity; /**< 0.0 to 1.0, from Tiled. Recorded but not yet applied at draw time. */
|
||||
bool visible; /**< From Tiled. Recorded but not yet consulted at draw time. */
|
||||
int height; /**< Tile layer: height in tiles. Image layer: the texture's height in pixels. */
|
||||
int width; /**< Tile layer: width in tiles. Image layer: the texture's width in pixels. */
|
||||
@@ -143,10 +143,10 @@ typedef struct {
|
||||
int p_vanishing_y; /**< Y of the `p_vanishing` marker: the row at which actors are smallest. 0 disables perspective. */
|
||||
int p_foreground_h; /**< Height of the `p_foreground` marker object. Recorded; not used in the current rate calculation. */
|
||||
int p_vanishing_h; /**< Height of the `p_vanishing` marker object. Recorded, likewise. */
|
||||
float p_foreground_scale; /**< Actor scale at `p_foreground_y`. Defaults to 1.0. */
|
||||
float p_vanishing_scale; /**< Actor scale at `p_vanishing_y`. Defaults to 1.0. */
|
||||
float p_scale; /**< Unused. Left from an earlier formulation of the perspective maths. */
|
||||
float p_rate; /**< Scale change per pixel of y between the two markers. Derived at load; what akgl_tilemap_scale_actor interpolates with. */
|
||||
float32_t p_foreground_scale; /**< Actor scale at `p_foreground_y`. Defaults to 1.0. */
|
||||
float32_t p_vanishing_scale; /**< Actor scale at `p_vanishing_y`. Defaults to 1.0. */
|
||||
float32_t p_scale; /**< Unused. Left from an earlier formulation of the perspective maths. */
|
||||
float32_t p_rate; /**< Scale change per pixel of y between the two markers. Derived at load; what akgl_tilemap_scale_actor interpolates with. */
|
||||
akgl_Tileset tilesets[AKGL_TILEMAP_MAX_TILESETS]; /**< The tilesets, in the order Tiled listed them. */
|
||||
akgl_TilemapLayer layers[AKGL_TILEMAP_MAX_LAYERS]; /**< The layers, in draw order: index 0 is furthest back. */
|
||||
|
||||
@@ -505,7 +505,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_scale_actor(akgl_Tilemap *map, a
|
||||
* 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);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_number(json_t *obj, char *key, float32_t *dest);
|
||||
/**
|
||||
* @brief Read a Tiled custom property declared as `float`.
|
||||
*
|
||||
@@ -522,7 +522,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_number(json_t *obj,
|
||||
* 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);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_float(json_t *obj, char *key, float32_t *dest);
|
||||
/**
|
||||
* @brief Read a Tiled custom property declared as `float`, at full precision.
|
||||
*
|
||||
@@ -541,7 +541,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_float(json_t *obj, c
|
||||
* 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);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_double(json_t *obj, char *key, float64_t *dest);
|
||||
/**
|
||||
* @brief Turn one Tiled object into a live actor, creating it if it is not already registered.
|
||||
*
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
/** @brief Single-precision float. Positions, velocities, and scale factors. */
|
||||
typedef float float32_t;
|
||||
/** @brief Double-precision float. Declared for symmetry; unused so far. */
|
||||
/** @brief Double-precision float. The physics backend keeps its drag and gravity constants at this width. */
|
||||
typedef double float64_t;
|
||||
|
||||
#endif // _AKGL_TYPES_H_
|
||||
|
||||
@@ -41,13 +41,6 @@ typedef struct akgl_RectanglePoints {
|
||||
akgl_Point bottomright; /**< (x + w, y + h). */
|
||||
} akgl_RectanglePoints;
|
||||
|
||||
/**
|
||||
* @brief Do not use. Three open parentheses, two closes -- any expansion is a
|
||||
* syntax error. It duplicates akgl_collide_rectangles(), has no callers,
|
||||
* and is slated for deletion. TODO.md item 20.
|
||||
*/
|
||||
#define AKGL_COLLIDE_RECTANGLES(r1x, r1y, r1w, r1h, r2x, r2y, r2w, r2h) ((r1x < (r2x + r2w)) || ((r1x + r1w) > r2x)
|
||||
|
||||
/**
|
||||
* @brief Expand a rectangle into its four corner points.
|
||||
*
|
||||
@@ -116,11 +109,11 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_collide_rectangles(SDL_FRect *r1, SDL_FR
|
||||
* @param root Directory to fall back to, normally `dirname` of the file that
|
||||
* contained @p path. Required, even when unused.
|
||||
* @param path The path to resolve, relative or absolute. Required.
|
||||
* @param dst Receives the resolved absolute path. Required, and must already be
|
||||
* @param dest Receives the resolved absolute path. Required, and must already be
|
||||
* a claimed pool string -- this writes into it, it does not claim
|
||||
* one for you.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p root, @p path, or @p dst is `NULL`.
|
||||
* @throws AKERR_NULLPOINTER If @p root, @p path, or @p dest is `NULL`.
|
||||
* @throws AKERR_OUTOFBOUNDS If `root + "/" + path` would not fit in
|
||||
* #AKGL_MAX_STRING_LENGTH.
|
||||
* @throws ENOENT If neither spelling names an existing file. Any other `errno`
|
||||
@@ -134,7 +127,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_collide_rectangles(SDL_FRect *r1, SDL_FR
|
||||
* error context it was handling. Each such call consumes one slot of
|
||||
* libakerror's fixed 128-entry context array for the life of the process.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_path_relative(char *root, char *path, akgl_String *dst);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_path_relative(char *root, char *path, akgl_String *dest);
|
||||
|
||||
// These are REALLY slow routines that are only useful in testing harnesses
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user