Add the models namespace, port basic-voxel (209 → 233 bindings) - #8
Merged
Conversation
Phase 3's biggest item: 3D model loading, generation and drawing. 24 new bindings taking the project from 209 to 233, plus the five structs they need. THE PART THAT MATTERS. The Model struct CHANGED between raylib 5.5 and 6.0 - 5.5 ended with boneCount/bones*/bindPose*, while 6.0 replaces those with a nested ModelSkeleton, a currentPose pointer and a boneMatrices pointer. Model is passed BY VALUE to every draw call, so a wrong layout does not error, it reads garbage. Binding this before the 6.0 upgrade would have produced code that silently broke on it. Layouts verified two ways. By size against hand-computed offsets: mesh 120, material 40, material-map 28, model-skeleton 24, model 136. Then against real raylib data, which is the check that actually proves the offsets: a generated 2x2x2 cube reports 24 vertices and 12 triangles with a nonzero VAO, the model it loads into reports meshCount 1 and materialCount 1 and validates, its bounding box is exactly -1..+1, and its transform reads as an exact identity matrix. That last one is the strongest evidence available - 16 floats can only all land correctly if every preceding offset is right. Pointer fields are real ::mem/pointers with explicit padding rather than the split lo/hi ints used for Shader. coffi does not insert alignment padding itself and fails loudly at alias definition if a pointer is misaligned, so every :_pad is load-bearing. set-model-material-color! walks into memory the model owns, because raylib exposes no function for it and its own examples reach into model.materials[i].maps[j].color directly. Worth knowing it MULTIPLIES with the tint passed to draw-model! rather than replacing it. Two structs move to raylib.structs so models does not have to depend on core.collision and core.camera3d for types it needs by value: bounding-box and camera-3d. camera3d keeps a local alias so existing ::camera3d references still resolve, and all nine existing models examples were re-run to confirm no regression.
An 8x8x8 block of cubes walked in first person, with left-click removing the one under the crosshair. First example on raylib.models, and the end-to-end proof of it: Model is passed by value to 512 draw calls a frame. pick-voxel takes its ray/box test as an argument rather than calling raylib directly, so the nearest-hit rule is checkable without a window. Verified: the nearest of four candidates wins, no hits gives nil rather than removing something arbitrary, an empty world gives nil rather than erroring, and a tie returns a member of the set. The material colour is set as well as the tint, both BEIGE, because raylib multiplies them - setting only the tint renders the cubes noticeably lighter than the C does.
Regenerated against main after PR #7 landed, rather than merged hunk by hunk. Both branches were cut from the same commit and both bumped example counts in the same thirteen files, so git had "106 -> 107" against "106 -> 109" with no way to pick. Counts are re-derived from the registry and bb check either way, so regenerating is both simpler and less error-prone than resolving. 110 examples (22 models now), 140 namespaces, 99 of 110 starting an embedded nREPL. Adds raylib.models to the module layout in the architecture guide. Validated after the rebase: catalog rows, gallery entries, GIFs and registry all agree at 110, every registry alias is in the catalog, no broken preview links or anchors, and each section header matches its own row count. The four examples that collided across the two branches were re-run together. The demo leans on mouse LOOK rather than clicks: pointer moves land reliably where button presses do not, so first-person motion carries the preview and the single click is opportunistic. 30 frames.
burinc
force-pushed
the
arc/models-namespace
branch
from
August 23, 2026 07:38
42fc8c1 to
5d0997f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 3's biggest item. Adds
raylib.models— 24 new bindings (209 → 233)plus the five structs they need — and ports
basic-voxelas the end-to-endproof. 106 → 107.
This is the largest single addition to the binding surface so far, and it
opens the models examples, which are the biggest unported group (21 of them).
The part that matters
The
Modelstruct changed between raylib 5.5 and 6.0. 5.5 ended withboneCount/bones*/bindPose*; 6.0 replaces those with a nestedModelSkeleton, acurrentPosepointer and aboneMatricespointer.Modelis passed by value to every draw call, so a wrong layout doesn'terror — it reads garbage. Binding this before the 6.0 upgrade would have
produced code that silently broke on it. Worth noting the 6.0 upgrade turned
out to be a prerequisite for this work rather than a parallel nicety.
Layouts verified two ways. By size against hand-computed offsets (mesh
120, material 40, material-map 28, model-skeleton 24, model 136), then against
real raylib data — which is the check that actually proves the offsets:
land correctly if every preceding offset is right
Pointer fields are real
::mem/pointers with explicit padding rather than thesplit lo/hi ints used for
Shader. coffi doesn't insert alignment padding andfails loudly at alias definition if a pointer is misaligned, so every
:_padis load-bearing.
set-model-material-color!raylib has no function for this — its own examples reach into
model.materials[i].maps[j].colordirectly, so this walks the same pointers.It multiplies with the tint passed to
draw-model!rather than replacingit, which is why
basic-voxelsets both to BEIGE: setting only the tintrenders the cubes noticeably lighter than the C does.
Struct moves
Matrixis new inraylib.structs.BoundingBoxandCamera3Dmove therefrom
core/collisionandcore/camera3d, soraylib.modelsdoesn't dependon those namespaces for types it needs by value.
core/camera3dkeeps a localalias so existing
::camera3dreferences still resolve, and all nineexisting models examples were re-run to confirm no regression.
basic-voxelpick-voxeltakes its ray/box test as an argument rather than calling raylib,so the nearest-hit rule is checkable without a window: nearest of four wins,
no hits gives
nilrather than removing something arbitrary, an empty worldgives
nilrather than erroring, a tie returns a set member.Gate: 137 namespaces, 0 lint errors, 69 warnings.
What this unlocks next
Three examples are now fully clear, and several need only a small tier more:
LoadModelAnimations/UpdateModelAnimation/UnloadModelAnimationsLoadImage/LoadTextureFromImage/UnloadImage+GenMeshCubicmap/GenMeshHeightmapGetRayCollisionMeshmesh_pickingOne decision for you.
billboard_renderingis fully unblocked and itsasset (
billboard.png) is CC0.directional_billboardis also unblocked butneeds
skillbot.png, which — likepatterns.png— has no licence entryupstream. I've held both rather than add a second unattributed asset while
the first is still an open question.