Three shapes, two text, three textures, one models and one core, picked for
binding surface rather than for how they look.
shapes-basic-shapes brings in six draw families nothing had called — the
circle and rectangle gradients, the triangles, all three poly draws — and is
the first call in the corpus to pass two Colors or three Vector2s at once.
shapes-collision-area is get-collision-rec, the only binding that takes two
Rectangles and answers a third, on a frame path. shapes-following-eyes is the
raymath gap measured rather than worked around: every line of it is vector
arithmetic written without a vector library, the way the C writes it.
text-input-box drains get-char-pressed's queue, which no example had read,
and needed a MouseCursor defenum for set-mouse-cursor. text-writing-anim
replaces TextSubtext — unbindable, it answers a pointer into a rotating
static buffer — with (string (slice b 0 n)), which is the same operation
without the shared state.
textures-image-generation runs nine Gen* calls and the
gen/upload/unload-image path, all procedural, no file on disk.
textures-fog-of-war needed a TextureFilter defenum: the smooth fog edge is
entirely :bilinear on a 25x15 render texture, and it is also the first
draw-texture-pro with a negative source height. textures-mouse-painting is
the same render texture used as a document rather than as scratch, plus the
round trip back off the GPU — load-image-from-texture, image-flip-vertical,
export-image — which nothing had run.
models-box-collisions is the counterexample to "a models example is a binding
exercise": nothing in it is a Model, and one BoundingBox defstruct un-refuses
four functions. core-3d-picking is the only caller anywhere for Ray and
RayCollision, and picking is the inverse of the get-world-to-screen the
corpus already had.
Added to vendor/raylib: defstructs BoundingBox, Ray and RayCollision;
defenums MouseCursor and TextureFilter with their mapping lines in bindings;
hand-written declare-c for SetMouseCursor, SetTextureFilter, DrawCubeV,
DrawSphere, DrawSphereWires, DrawRay and GetScreenToWorldRay, each excluded
from the generated half on the rule bindings already states. generated.flan
regenerated against raylib 5.5: 272 declarations, 117 refused, every
defstruct, hand-written declare-c and mapped constant agreeing with the
header.
Two gaps the raylib examples hit.
The layout check compared a Flan enum against the header's `int` and
called it a disagreement. It is not one: Shim.cty lowers a defenum to
int32_t in a struct field exactly as it does in a parameter, which is
what the signature check already knew and the layout check did not. One
predicate now serves both, symmetric, and tolerant of a 32-bit integer
and nothing else -- f64 against the library's float still fails, in the
very struct whose other field is an enum. Camera3D.projection is a
CameraProjection again and rl/camera-projection is gone with it, so
`.projection :perspective` resolves at the construction site.
And generate-c's claim said nothing about a defconst or a defenum
member, so a wrong flag bit was completely silent. `bindings` gained
`enum`, `const` and `constant` lines saying what a Flan constant is
called in C -- the prefix is nowhere in the Flan name, so it is declared
rather than guessed. Nothing goes quiet in either direction: a name the
rule builds and the header lacks is reported, a rule that reaches
nothing is reported, and a defenum with no line is itself a finding,
because otherwise the silence just moves up one level.
clang's dump gives anonymous EnumDecls for every raylib enum and no
value at all for an enumerator written without `= n`, so the constants
are one flat table and the values are counted the way C counts them.
cache_format bumped with the dump type.
core-2d-camera, core-scissor-test, core-window-flags, core-world-screen
and core-window-should-close, ported from raylib 5.5's examples/core.
What each one asked of vendor/raylib:
2d-camera nothing. A whole Camera2D by value, per frame, into the
call that actually draws with it — the layout the
acceptance table pins through arithmetic, now going
through the path it was bound for.
scissor-test begin-scissor-mode / end-scissor-mode, hand-written.
window-flags twelve more ConfigFlags constants; raylib.flan carried
the four sand.flan sets and this reads eleven.
world-screen the 3D surface did not exist: no Vector3, no Camera3D,
and the importer refused every 3D function in raylib.h
by name for want of them. Two defstructs, two defenums,
begin/end-mode-3d, update-camera, get-world-to-screen,
draw-cube, draw-cube-wires, draw-grid — and 24 more 3D
lines the importer can generate now that the types are
described.
window-should-close set-exit-key, and Key/null to pass it.
The hand-written/generated line, written down in vendor/raylib/bindings:
a drawing pair inside a frame is hand-written, and so is anything whose
Flan face is not the C signature — set-exit-key takes a Key, update-camera
takes a (Ptr Camera3D) and a CameraMode. The window-state family and
get-mouse-x/y stay generated: plain scalars in and bool out, with nothing
for a hand-written line to add.
Camera3D's projection field stays i32, because the header says int and the
layout check holds this file to that; rl/camera-projection is the
conversion, and still takes a keyword.
generated.flan carries the 253 declarations the importer reads out of raylib's
header, so a build needs libraylib linkable and no header at all. The opt-in
no longer decides how many bindings a package has — every build now gets all
425, they are greppable, and they diff when raylib moves.
What that gives up is the build-time check, so `flan generate-c` is the only
thing that writes the file and it compares first: every defstruct against the
header's record, every hand-written declare-c against the header's signature,
and it writes nothing when they disagree. Against the 5.1-dev header on this
machine that is ten real differences and no write.
The 172 hand-written lines stay, and not out of caution. Everything the
generator emits agrees with the header by construction, so diffing generated
output against its own source is a tautology; the hand-written lines were
transcribed by a person, so they are the only thing here a header can
contradict. All ten of those differences came from them.
`bindings` beside `headers` is what survives regeneration, because a hand-edit
to a committed generated file does not. Two directives: `exclude` drops
raylib's three allocator entry points, and `name` gives the 19 generated
predicates the `?` spelling the hand-written ones already use.