Remove the corner helpers akgl_collide_rectangles no longer uses
Some checks failed
libakgl CI Build / cmake_build (push) Failing after 21s
libakgl CI Build / performance (push) Failing after 21s
libakgl CI Build / memory_check (push) Failing after 17s
libakgl CI Build / mutation_test (push) Failing after 19s

akgl_rectangle_points, akgl_collide_point_rectangle, akgl_Point and
akgl_RectanglePoints go. They were the intermediate form of an implementation
that changed: akgl_collide_rectangles was eight corner-containment tests built on
them, and it has been four span comparisons since the cross-case fix. Nothing
outside tests/ called either function, and a point-in-rectangle test is four
comparisons a caller can write without a struct conversion in front of them.

akgl_collide_rectangles stays. It has two correct callers in the sidescroller
asking a game-level overlap question -- a coin, a hazard, from an updatefunc --
where a bool is the whole answer and a proxy plus a narrowphase call would be
computing a normal nothing reads. TODO.md records the split rather than leaving
it to be rediscovered.

Public API removal, so 194 exported akgl_ symbols against 196, and the manual's
counts move with them. The perf suite loses its rectangle_points row; the
all-pairs sweep stays as the control it is now labelled, and PERFORMANCE.md says
what 0.8.0 measured against it -- 188.5 us for 32,640 pairs at 256 actors, where
a whole step with collision attached is 54.1 us doing strictly more.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
This commit is contained in:
2026-08-02 08:09:42 -04:00
parent 3a6569e384
commit 4e32328681
11 changed files with 134 additions and 395 deletions

View File

@@ -1,15 +1,16 @@
/**
* @file util.h
* @brief Axis-aligned collision tests, path resolution, and two test-only image helpers.
* @brief A rectangle overlap test, path resolution, and two test-only image helpers.
*
* The grab bag. Three unrelated groups live here: rectangle/point overlap for
* the physics backend, path resolution for the asset loaders, and a pair of
* pixel-comparison routines that exist only so tests can assert on what was
* actually drawn.
* The grab bag. Three unrelated groups live here: one rectangle overlap test,
* path resolution for the asset loaders, and a pair of pixel-comparison routines
* that exist only so tests can assert on what was actually drawn.
*
* All the geometry here is axis-aligned and treats edges as touching: a point
* exactly on a boundary is inside. There is no rotation support and no
* separating-axis test.
* akgl_collide_rectangles is axis-aligned and treats edges as touching: two
* rectangles sharing an edge and nothing more overlap. It answers a *game's*
* question -- a pickup, a minimap marker, a UI hit test -- and is deliberately
* not what the physics step uses. Anything that should push or be pushed wants a
* collision shape and akgl_collision_test; see `akgl/collision.h`.
*/
#ifndef _AKGL_UTIL_H_
@@ -20,71 +21,12 @@
#include <stdbool.h>
#include <akgl/staticstring.h>
/** @brief An integer point. Carries a `z` the collision routines do not use. */
typedef struct akgl_Point {
int x; /**< Horizontal position, in whatever space the caller is working in. */
int y; /**< Vertical position. */
int z; /**< Depth. Never written by akgl_rectangle_points and never read by the collision tests. */
} akgl_Point;
/**
* @brief The four corners of an axis-aligned rectangle, precomputed.
*
* The form akgl_collide_point_rectangle wants. akgl_rectangle_points derives one
* of these from an `SDL_FRect`.
*
* @note akgl_collide_rectangles used to be built on this, corner by corner, and
* missed the cross case that way -- two rectangles overlapping in a plus
* sign have no corner of either inside the other. It compares edge spans
* in `float32_t` since 0.8.0 and does not go through here at all.
*/
typedef struct akgl_RectanglePoints {
akgl_Point topleft; /**< (x, y). */
akgl_Point topright; /**< (x + w, y). */
akgl_Point bottomleft; /**< (x, y + h). */
akgl_Point bottomright; /**< (x + w, y + h). */
} akgl_RectanglePoints;
/**
* @brief Expand a rectangle into its four corner points.
*
* Coordinates are truncated from `float` to `int` on the way in, so a rectangle
* at x = 10.9 has its corners at 10. That is deliberate for tile-grid work and
* wrong for sub-pixel work; callers needing the latter should not round-trip
* through this.
*
* @param dest Receives the corners. Required.
* @param rect The rectangle, in any coordinate space. Required. `w` and `h` are
* taken as extents from `x`/`y`, so a negative one produces a
* rectangle whose "bottom right" is above and left of its "top
* left" -- which every test here then reports as empty.
* @return `NULL` on success, otherwise an error context owned by the caller.
* @throws AKERR_NULLPOINTER If @p dest or @p rect is `NULL`.
*/
akerr_ErrorContext AKERR_NOIGNORE *akgl_rectangle_points(akgl_RectanglePoints *dest, SDL_FRect *rect);
/**
* @brief Test whether a point falls inside a rectangle, edges included.
*
* Compares against `topleft` and `bottomright` only, so it assumes @p r is
* well-formed -- the two corners actually being the minimum and maximum. `z` is
* ignored on both sides: this is a 2D test.
*
* @param p The point to test. Required.
* @param r The rectangle, as corners from akgl_rectangle_points. Required.
* @param collide Receives `true` when the point is inside or exactly on an edge,
* `false` otherwise. Required -- the return value is the error
* context. Not written on any failure path.
* @return `NULL` on success, otherwise an error context owned by the caller.
* @throws AKERR_NULLPOINTER If @p p, @p r, or @p collide is `NULL`.
*/
akerr_ErrorContext AKERR_NOIGNORE *akgl_collide_point_rectangle(akgl_Point *p, akgl_RectanglePoints *r, bool *collide);
/**
* @brief Test whether two rectangles overlap, edges included.
*
* Tests all eight corners -- each rectangle's four against the other -- and
* stops at the first hit. Checking both directions is what catches the case
* where one rectangle is entirely inside the other and so has no corner within
* its neighbour.
* Compares the two rectangles' spans on both axes: they overlap when neither is
* wholly to one side of the other. Four comparisons, in `float32_t`, with no
* intermediate form.
*
* @param r1 First rectangle. Required.
* @param r2 Second rectangle. Required. Order does not matter.
@@ -99,8 +41,15 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_collide_point_rectangle(akgl_Point *p, a
* the other, and every corner test said no. It is a span comparison on
* both axes now. Two consequences for a caller upgrading: that
* arrangement starts reporting `true`, and the comparison is in `float`
* rather than through akgl_Point's `int` members, so an overlap smaller
* than one pixel is no longer truncated away.
* rather than through the removed akgl_Point's `int` members, so an
* overlap smaller than one pixel is no longer truncated away.
*
* @note akgl_rectangle_points, akgl_collide_point_rectangle, akgl_Point and
* akgl_RectanglePoints were removed in 0.8.0. They existed to feed the
* corner form this no longer uses, and nothing outside `tests/` called
* either function. A point-in-rectangle test is four comparisons a caller
* can write; the intermediate struct was the only thing this header was
* adding.
*/
akerr_ErrorContext AKERR_NOIGNORE *akgl_collide_rectangles(SDL_FRect *r1, SDL_FRect *r2, bool *collide);