Add a second partitioner, so the vtable is a seam and not a decoration

A binary space partition on libakstdlib's tree links and lists, registered in
the factory as "bsp". It runs the same assertions the grid does, because
tests/partition.c is a table over partitioners and adding a row is all it takes
to be held to the contract.

**Use the grid.** This is here to prove the vtable works and to have something
to measure the grid against, and the file says so at the top. It rebuilds
whenever the proxy set changes, which is the shape PERFORMANCE.md records Phaser
using and capping out around five thousand bodies. It would earn its place in a
world with wildly non-uniform object sizes, or one larger than the grid's fixed
cell array covers.

The difference is visible in the code rather than buried in a benchmark: the
grid's `move` compares four integers and returns when a proxy has not left its
cells, and this one marks the whole partition stale. The incremental-move
assertion in the suite is therefore grid-only, and says why.

aksl_tree_iterate is not used, and the file carries the three reasons so the
next reader does not rediscover them: it is a complete traversal whose only
control signal stops the entire walk, so there is no way to prune a subtree --
which is the only operation a spatial query is made of; it carries no per-node
context, and a pruning descent needs each node's bounds and plane; and its
breadth-first modes allocate, while only the depth-first ones are malloc-free
and those are the ones without pruning. aksl_tree_insert is unusable for a
different reason again: it is a comparator-ordered BST, and a spatial insert has
to compare a leaf against a plane, which aksl_TreeCompareFunc cannot express.

What is used is the link structure and the lists, neither of which allocates,
which is why they fit here at all. The descent is an explicit stack rather than
recursion, so the depth bound is an array bound the compiler can see -- this
library already has one documented way to blow the C stack and does not need a
second.

Split planes are the median of the item centres on the longer axis, not the
spatial midpoint: actors in a tile game cluster on the floor, and a midpoint
split gives one empty child and one full one for several levels running. A split
that separates nothing degrades the node to a leaf rather than recursing forever
on the same set.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-02 07:08:54 -04:00
parent 5e213061af
commit cf930f68bb
7 changed files with 581 additions and 7 deletions

View File

@@ -297,6 +297,7 @@ add_library(akgl SHARED
src/actor.c
src/collision.c
src/collision_arena.c
src/collision_bsp.c
src/collision_grid.c
src/collision_shape.c
src/actor_state_string_names.c