Merge branch 'worktree-agent-ac605f8a376484762' into dev-loop
# Conflicts: # NEXT.md
This commit is contained in:
commit
95697d230f
94
NEXT.md
94
NEXT.md
@ -238,16 +238,54 @@ would cost.
|
||||
|
||||
## ~~To discuss: five gaps the raylib examples hit and could not close~~ — **three closed, two live elsewhere**
|
||||
|
||||
- **Closed:** an enum-typed `defstruct` field is no longer refused by the layout check (an enum *is* an `i32`, and
|
||||
the predicate is symmetric now, so the enum may be on either side); the header check reaches `defconst` and
|
||||
`defenum` through name-mapping directives in `vendor/raylib/bindings`, so a wrong flag bit is no longer silent;
|
||||
and the `Ptr`-indexing gap has its own queue entry at the top of this file, because it now blocks three
|
||||
examples rather than being a note.
|
||||
- **Still open, and both are here rather than in a queue entry because neither has a customer pressing:**
|
||||
**raymath is `static inline`**, so `Clamp`, `Vector2Add` and `Remap` have no symbol to `declare-c` at all — a lane
|
||||
measured the alternative and found writing the arithmetic in Flan cost nothing, which is what makes this a
|
||||
non-problem rather than a gap; and **function-pointer parameters** are refused (`SetTraceLogCallback`, the audio
|
||||
stream processors), which is the callback direction of the FFI and nothing has needed it yet.
|
||||
Found by the lane that ported `core-2d-camera`, `core-scissor-test`, `core-window-flags`,
|
||||
`core-world-screen` and `core-window-should-close`. None blocked those five. All five blocked
|
||||
something else, and each is a language or checker question rather than a missing binding, which is
|
||||
why they are here and not in a binding list.
|
||||
|
||||
1. **A `(Ptr T)` returned from C cannot be indexed.** `indexed` in `lib/check.ml` accepts `Array`
|
||||
and `Slice` only, so a C function answering `int*` is readable at element 0 through `deref` and
|
||||
nowhere else. `LoadRandomSequence` is the case that hit it and `core_random_sequence` is
|
||||
unportable until it moves. The question is what the answer should be: a length has to come from
|
||||
somewhere before a pointer can become a slice, and C does not supply one. Possibly a
|
||||
`(slice-from-ptr p n)` where the caller states the length and owns being right about it.
|
||||
**This has its own queue entry at the top of this file now** — it blocks three more examples than this
|
||||
section knew about, and both candidate shapes are written out there.
|
||||
|
||||
2. ~~**An enum-typed `defstruct` field is refused by the layout check.**~~ **Closed.** The layout
|
||||
check now accepts an enum where the header says `int`, symmetrically, and still refuses
|
||||
anything that is not four bytes. `Camera3D.projection` is a `CameraProjection` again and the
|
||||
`rl/camera-projection` helper is gone; `.projection :perspective` resolves at the construction
|
||||
site, so the keyword half of the problem went away with it. See BUILT.md.
|
||||
|
||||
3. ~~**The header check does not reach `defconst` or `defenum`.**~~ **Closed.** It reaches both.
|
||||
`bindings` gained `enum`, `const` and `constant` lines that say what a Flan constant is called in
|
||||
C; every mapped name is compared by value, and a name the mapping cannot find, a rule that
|
||||
reaches nothing, and a `defenum` with no line at all are each reported rather than skipped. All
|
||||
eight raylib enums and all 16 `ConfigFlags` bits check out against 5.5. See BUILT.md.
|
||||
|
||||
4. ~~**raymath is `static inline`, so there is no symbol to bind.**~~ **Closed for the vector half.**
|
||||
`Clamp`, `Vector2Add`, `Remap` and the rest exist only in the header and `declare-c` has nothing
|
||||
to name, so the arithmetic is written in Flan: `vendor/raylib/vector.flan`, a package file with
|
||||
no `declare-c` in it at all — which is why it is a file of its own rather than more of
|
||||
`raylib.flan`, the file the header check reads hand-written signatures out of. Vector2 and
|
||||
Vector3 add/sub/mul/scale/negate/dot/length/distance/normalize/lerp, `v2-angle`, `v2-rotate`,
|
||||
`v3-cross`, and `remap`, `inverse-lerp`, `wrap-f32` on scalars. raymath's semantics exactly,
|
||||
including the zero-length guard in `normalize`. **`clamp` and `lerp` are deliberately absent**:
|
||||
both are already in the prelude, and a second `lerp` would not even be the same function —
|
||||
the prelude writes `(1-t)a + tb`, raymath writes `a + t*(b - a)`, and shipping both under names
|
||||
one letter apart is a footgun. The C-shim alternative was rejected on the measurement
|
||||
`examples/shapes-following-eyes.flan` already took: it would buy identical arithmetic for a
|
||||
compilation unit in the build and a second place raylib's semantics are written down. rlgl's
|
||||
matrix stack is still unbound for a different reason, so `core_2d_camera_mouse_zoom` is still
|
||||
skipped.
|
||||
|
||||
5. **Four families are still refused by the importer for want of a `defstruct`.** `FilePathList`
|
||||
(a `char**`, blocks `core_drop_files`), `Model`/`Mesh`/`Ray`/`BoundingBox` (the model and
|
||||
3D-collision families), and **function-pointer parameters** (`SetTraceLogCallback`, which blocks
|
||||
`core_custom_logging`, and the audio stream processors). The first three are ordinary widening —
|
||||
write the `defstruct` and they import. The function-pointer one is not, and is the interesting
|
||||
one: it is the callback direction of the FFI, which nothing has needed yet.
|
||||
|
||||
## Queued, 2026-09-13 (second session) — everything four lanes left behind
|
||||
|
||||
@ -382,12 +420,34 @@ Interactively the controls are now `r` and left-mouse only. `test_web.ml`'s asse
|
||||
the wasm module went with the embed: `web-files.flan` is web-built and *run* under node and asserts the embedded
|
||||
bytes print, which is the same property checked harder.
|
||||
|
||||
## Queued: an idiomatic layer over the generated bindings
|
||||
## ~~Queued: an idiomatic layer over the generated bindings~~ — **landed**
|
||||
|
||||
Thin Flan-shaped wrappers **over** the generated bindings, not instead of them. The generated set stays honest to C —
|
||||
that is what makes it checkable against the header — and the layer is where a Flan-shaped API lives. Two of these
|
||||
already exist by hand in `vendor/raylib/raylib.flan` and are the shape to copy: `collision-point-poly?` takes a slice
|
||||
and `collision-lines` answers with an `Option`, each wrapping a `-raw` binding of the same name.
|
||||
Thin Flan-shaped wrappers **over** the generated bindings, not instead of them. Built as three kinds, listed in the
|
||||
header of `vendor/raylib/raylib.flan`:
|
||||
|
||||
- **A slice where C takes a pointer and a count.** The eleven vector-array drawing calls — `draw-line-strip`, the two
|
||||
triangle batches, the five splines, the two `image-draw-triangle-*`, `draw-triangle-strip-3d` — under one section.
|
||||
All eleven and not the three anybody calls: a subset puts the hole where the next caller looks. Each also guards the
|
||||
empty slice, which is the part a hand-written call site gets wrong rather than merely writes out — raylib takes a
|
||||
count of 0 happily, but `(addr (at pts 0))` is out of bounds before raylib is reached.
|
||||
- **An `Option` where C signals with a sentinel.** `get-key-pressed` and `get-char-pressed`, raylib's two input
|
||||
queues, both of which say "empty" with 0. What it buys is in `examples/text-input-box.flan`: the C shape reads the
|
||||
queue in two places, once to prime the loop and once at the bottom of the body, and the Option shape reads it in
|
||||
one.
|
||||
- **An enum where the header says `int`.** `key-up?`, `key-pressed-repeat?`, `mouse-button-up?` — holes in families
|
||||
whose other halves already took a `Key` or a `MouseButton`, so `(rl/key-down? :space)` compiled and
|
||||
`(rl/key-up? :space)` did not. **These are not wrappers.** A C enum parameter has an int's ABI, so the hand-written
|
||||
`declare-c` with the Flan type on it is the whole fix and a `defn` around it would be a rename.
|
||||
|
||||
The mechanism for the first two is the `name` directive in `vendor/raylib/bindings`: the generated declaration keeps
|
||||
the symbol and gives up the name, so nothing about the C signature is hand-written and the generated half keeps its
|
||||
agreement-by-construction with the header. The third is an `exclude` plus a hand-written line, exactly as `SetExitKey`
|
||||
and `SetMouseCursor` already were.
|
||||
|
||||
**Not built: `with-drawing` and `with-mode-2d`.** An unbalanced begin/end is a real bug and a macro removes it, but a
|
||||
macro cannot live in a package — the expander collects `defmacro`s from the prelude and from the file being compiled,
|
||||
and one in an imported package is refused by name. `test/programs/pkg-macro.flan` is that refusal and its whole content
|
||||
is the case. They have to be written in the program that uses them, or wait for macros to be importable.
|
||||
|
||||
## ~~Queued: a restart is not a transaction, and the docs must say so~~ — **landed**
|
||||
|
||||
@ -661,7 +721,9 @@ second.
|
||||
|
||||
One smaller thing found and worth not re-deriving: an enum parameter imports as `i32`, because the header says
|
||||
`KeyboardKey` and nothing tells the importer the package calls that `Key`. The ABI is identical, the face is worse,
|
||||
and it is why `(rl/key-down? :space)` keeps its hand-written line.
|
||||
and it is why `(rl/key-down? :space)` keeps its hand-written line. The idiomatic-layer lane closed the three holes
|
||||
this left — `key-up?`, `key-pressed-repeat?` and `mouse-button-up?` were generated and therefore took an `i32`, so the
|
||||
sibling of a call that worked did not — by excluding them and hand-writing the enum type, which is all it takes.
|
||||
|
||||
### Landed 2026-09-12 — six tracks, one session
|
||||
|
||||
|
||||
@ -54,16 +54,17 @@
|
||||
|
||||
;; The same centre/size to min/max conversion as in
|
||||
;; examples/models-box-collisions.flan. Written out here rather than shared
|
||||
;; because an example is a single file the reader can follow end to end, and
|
||||
;; a two-file port for eight expressions would cost more than it saves.
|
||||
;; because an example is a single file the reader can follow end to end.
|
||||
;;
|
||||
;; It used to be eight expressions of field arithmetic; it is the half-extent
|
||||
;; subtracted and added, which is what the C means, now that the package
|
||||
;; carries vector arithmetic — see vendor/raylib/vector.flan. That file
|
||||
;; exists because raymath is `static inline` and has no symbol to bind, so
|
||||
;; v3-sub and v3-add are Flan and not C.
|
||||
(defn box-around [centre rl/Vector3 size rl/Vector3] rl/BoundingBox
|
||||
(rl/BoundingBox
|
||||
{.min (rl/Vector3 {.x (- (.x centre) (/ (.x size) 2.0))
|
||||
.y (- (.y centre) (/ (.y size) 2.0))
|
||||
.z (- (.z centre) (/ (.z size) 2.0))})
|
||||
.max (rl/Vector3 {.x (+ (.x centre) (/ (.x size) 2.0))
|
||||
.y (+ (.y centre) (/ (.y size) 2.0))
|
||||
.z (+ (.z centre) (/ (.z size) 2.0))})}))
|
||||
(let [half (rl/v3-scale size 0.5)]
|
||||
(rl/BoundingBox {.min (rl/v3-sub centre half)
|
||||
.max (rl/v3-add centre half)})))
|
||||
|
||||
(defn main [] ()
|
||||
(rl/init-window screen-width screen-height
|
||||
|
||||
@ -54,14 +54,15 @@
|
||||
;; min-corner/max-corner, not centre/size, and every collision call in the
|
||||
;; family takes the corner form — so this is the conversion the C writes out
|
||||
;; longhand at each of its two call sites.
|
||||
;;
|
||||
;; It used to be eight expressions of field arithmetic here too; it is the
|
||||
;; half-extent subtracted and added now that the package carries vector
|
||||
;; arithmetic — see vendor/raylib/vector.flan, which is Flan and not C
|
||||
;; because raymath is `static inline` and has no symbol to bind.
|
||||
(defn box-around [centre rl/Vector3 size rl/Vector3] rl/BoundingBox
|
||||
(rl/BoundingBox
|
||||
{.min (rl/Vector3 {.x (- (.x centre) (/ (.x size) 2.0))
|
||||
.y (- (.y centre) (/ (.y size) 2.0))
|
||||
.z (- (.z centre) (/ (.z size) 2.0))})
|
||||
.max (rl/Vector3 {.x (+ (.x centre) (/ (.x size) 2.0))
|
||||
.y (+ (.y centre) (/ (.y size) 2.0))
|
||||
.z (+ (.z centre) (/ (.z size) 2.0))})}))
|
||||
(let [half (rl/v3-scale size 0.5)]
|
||||
(rl/BoundingBox {.min (rl/v3-sub centre half)
|
||||
.max (rl/v3-add centre half)})))
|
||||
|
||||
(defn main [] ()
|
||||
(rl/init-window screen-width screen-height
|
||||
|
||||
@ -17,6 +17,16 @@
|
||||
;;;; has. It reads fine. A Vector2Add would have saved two lines in the whole
|
||||
;;;; file.
|
||||
;;;;
|
||||
;;;; That measurement is what decided the answer, and the answer landed:
|
||||
;;;; vendor/raylib/vector.flan is raymath written in Flan, since a C shim
|
||||
;;;; re-exporting the inlines would have bought identical arithmetic at the
|
||||
;;;; price of a compilation unit and a second place raylib's semantics live.
|
||||
;;;; The measurement is left standing rather than rewritten away — one
|
||||
;;;; subtraction below is `rl/v2-sub` and the rest of the file is unchanged,
|
||||
;;;; including the atan2/cos/sin path, which is deliberate: it needs no guard
|
||||
;;;; for a zero-length vector where a normalise would. One line saved, in a
|
||||
;;;; file that is nothing but vector maths, is the honest size of the gap.
|
||||
;;;;
|
||||
;;;; The raylib call it does exercise is collision-point-circle?, which no
|
||||
;;;; ported example had called, on a frame path, with the point coming
|
||||
;;;; straight out of get-mouse-position — one struct out of raylib and back
|
||||
@ -56,9 +66,8 @@
|
||||
;; because that is what the C does and because it needs no guard for a
|
||||
;; zero-length vector — atan2(0,0) is 0 and the pupil sits at the right
|
||||
;; of the eye, which is unreachable anyway since (0,0) is inside.
|
||||
(let [dx (- (.x mouse) (.x centre))
|
||||
dy (- (.y mouse) (.y centre))
|
||||
angle (atan2-f32 dy dx)]
|
||||
(let [d (rl/v2-sub mouse centre)
|
||||
angle (atan2-f32 (.y d) (.x d))]
|
||||
(rl/Vector2 {.x (+ (.x centre) (* limit (cos-f32 angle)))
|
||||
.y (+ (.y centre) (* limit (sin-f32 angle)))})))))
|
||||
|
||||
|
||||
@ -7,11 +7,19 @@
|
||||
;;;; state — key-down?, key-pressed?, the mouse position — and this is the
|
||||
;;;; only example that drains a *queue*: raylib buffers the characters the
|
||||
;;;; platform produced since the last frame, already through the keyboard
|
||||
;;;; layout and the dead keys, and hands them back one at a time until it
|
||||
;;;; answers 0. The loop that empties it is the point of the example, and a
|
||||
;;;; layout and the dead keys, and hands them back one at a time until it is
|
||||
;;;; empty. The loop that empties it is the point of the example, and a
|
||||
;;;; program that read the queue once per frame instead would silently drop
|
||||
;;;; the second character of a fast pair. It is a plain i32 out of the
|
||||
;;;; generated bindings; nothing needed adding for it.
|
||||
;;;; the second character of a fast pair.
|
||||
;;;;
|
||||
;;;; raylib says "empty" by answering 0, and rl/get-char-pressed is now a
|
||||
;;;; Flan wrapper that says it with None instead — see raylib.flan, "Draining
|
||||
;;;; raylib's two input queues". What that buys is visible below: the C
|
||||
;;;; shape, which this file had, reads the queue in *two* places, once to
|
||||
;;;; prime the loop and once at the bottom of the body, and a `> 0` in
|
||||
;;;; between that a reader has to know raylib's convention to trust. The
|
||||
;;;; Option shape reads it in one place, and the case where there is no
|
||||
;;;; character is a branch the checker knows about rather than a comparison.
|
||||
;;;;
|
||||
;;;; The second is set-mouse-cursor, which needed a new defenum. raylib's
|
||||
;;;; header says `int cursor` and means one of eleven MOUSE_CURSOR_ values, so
|
||||
@ -75,19 +83,22 @@
|
||||
(do
|
||||
(rl/set-mouse-cursor :ibeam)
|
||||
|
||||
;; Drain the character queue. raylib answers 0 when it is empty, and
|
||||
;; more than one character can arrive in a single frame — holding a
|
||||
;; key with the platform's repeat on is the ordinary way that happens.
|
||||
(let [key (rl/get-char-pressed)]
|
||||
(while (> key 0)
|
||||
;; 32..125 is the printable ASCII range the C accepts. Anything
|
||||
;; outside it — an accented letter, a control character — is
|
||||
;; dropped rather than stored, because the buffer is bytes and a
|
||||
;; codepoint above 127 would need more than one of them.
|
||||
(when (and (>= key 32) (<= key 125) (< letter-count max-input-chars))
|
||||
(set (at name letter-count) (u8 key))
|
||||
(set letter-count (+ letter-count 1)))
|
||||
(set key (rl/get-char-pressed))))
|
||||
;; Drain the character queue: more than one character can arrive in
|
||||
;; a single frame — holding a key with the platform's repeat on is
|
||||
;; the ordinary way that happens — and None is the end of it.
|
||||
(let [draining true]
|
||||
(while draining
|
||||
(match (rl/get-char-pressed)
|
||||
None (set draining false)
|
||||
;; 32..125 is the printable ASCII range the C accepts. Anything
|
||||
;; outside it — an accented letter, a control character — is
|
||||
;; dropped rather than stored, because the buffer is bytes and a
|
||||
;; codepoint above 127 would need more than one of them.
|
||||
(Some key)
|
||||
(when (and (>= key 32) (<= key 125)
|
||||
(< letter-count max-input-chars))
|
||||
(set (at name letter-count) (u8 key))
|
||||
(set letter-count (+ letter-count 1))))))
|
||||
|
||||
(when (rl/key-pressed? :backspace)
|
||||
(set letter-count (- letter-count 1))
|
||||
|
||||
50
vendor/raylib/bindings
vendored
50
vendor/raylib/bindings
vendored
@ -57,9 +57,6 @@ name IsWindowFocused window-focused?
|
||||
name IsWindowResized window-resized?
|
||||
name IsWindowState window-state?
|
||||
name IsCursorOnScreen cursor-on-screen?
|
||||
name IsKeyUp key-up?
|
||||
name IsKeyPressedRepeat key-pressed-repeat?
|
||||
name IsMouseButtonUp mouse-button-up?
|
||||
name IsFileDropped file-dropped?
|
||||
name IsFileExtension file-extension?
|
||||
name IsFileNameValid file-name-valid?
|
||||
@ -139,6 +136,53 @@ exclude DrawSphereWires
|
||||
exclude DrawRay
|
||||
exclude GetScreenToWorldRay
|
||||
|
||||
# ── The idiomatic layer, which is what these last two blocks are for ──
|
||||
#
|
||||
# Three kinds of C signature get a Flan face in raylib.flan rather than the
|
||||
# generated one, and each kind is a directive here so that the generated file
|
||||
# does not also define the name. See the "An idiomatic layer" section of
|
||||
# raylib.flan for what each wrapper buys at the call site.
|
||||
#
|
||||
# 1. An `int` parameter the package already has a defenum for. These are
|
||||
# excluded and hand-written with the enum type, exactly as SetExitKey and
|
||||
# SetMouseCursor already are, and for the same reason: a keyword resolves
|
||||
# against the members at compile time and a typo is an error there. What
|
||||
# makes these three different from those is that they are *holes in a
|
||||
# family that already exists* — key-down? takes a Key and key-up? took an
|
||||
# i32, so `(rl/key-up? :space)` did not compile while `(rl/key-down?
|
||||
# :space)` did. A wrapper would be a pure rename; the fix is the
|
||||
# declaration.
|
||||
exclude IsKeyUp
|
||||
exclude IsKeyPressedRepeat
|
||||
exclude IsMouseButtonUp
|
||||
|
||||
# 2. A sentinel return, wrapped by a Flan defn that answers an Option. The
|
||||
# generated declaration is still what calls C and is still checked against
|
||||
# the header — only its *name* moves aside, which is what `name` is for.
|
||||
# Nothing about the signature is wrong, so there is no reason to hand-write
|
||||
# it and lose the generated half's by-construction agreement.
|
||||
name GetCharPressed get-char-pressed-raw
|
||||
name GetKeyPressed get-key-pressed-raw
|
||||
|
||||
# 3. A pointer-and-count pair where Flan has a slice. Same treatment and the
|
||||
# same reason: the C signature is right, the Flan face is a slice, so the
|
||||
# generated line keeps the symbol and the wrapper takes the name. This is
|
||||
# every raylib entry point that takes an array of vectors as pointer plus
|
||||
# count, and it is the whole family on purpose — a subset would put the
|
||||
# hole exactly where the next caller looks, which is the argument
|
||||
# raylib.flan makes about ConfigFlags.
|
||||
name DrawLineStrip draw-line-strip-raw
|
||||
name DrawTriangleFan draw-triangle-fan-raw
|
||||
name DrawTriangleStrip draw-triangle-strip-raw
|
||||
name DrawTriangleStrip3D draw-triangle-strip-3d-raw
|
||||
name DrawSplineLinear draw-spline-linear-raw
|
||||
name DrawSplineBasis draw-spline-basis-raw
|
||||
name DrawSplineCatmullRom draw-spline-catmull-rom-raw
|
||||
name DrawSplineBezierQuadratic draw-spline-bezier-quadratic-raw
|
||||
name DrawSplineBezierCubic draw-spline-bezier-cubic-raw
|
||||
name ImageDrawTriangleFan image-draw-triangle-fan-raw
|
||||
name ImageDrawTriangleStrip image-draw-triangle-strip-raw
|
||||
|
||||
# ── What the package's constants are called in C ────────────────────
|
||||
#
|
||||
# enum <FlanEnum> <C_PREFIX> every member of that defenum
|
||||
|
||||
33
vendor/raylib/generated.flan
vendored
33
vendor/raylib/generated.flan
vendored
@ -1,4 +1,4 @@
|
||||
;;;; Generated from raylib.h by `flan generate-c`. Do not edit this file.
|
||||
;;;; Generated from raylib-5.5.h by `flan generate-c`. Do not edit this file.
|
||||
;;;;
|
||||
;;;; Every line here was read out of the C header named by `headers`, and
|
||||
;;;; the next regeneration overwrites the file — so a correction made here
|
||||
@ -10,7 +10,7 @@
|
||||
;;;;
|
||||
;;;; Regenerating compares the package against the header first and
|
||||
;;;; refuses to write when they disagree, so this file and the
|
||||
;;;; hand-written declarations beside it agreed with raylib.h when it was made.
|
||||
;;;; hand-written declarations beside it agreed with raylib-5.5.h when it was made.
|
||||
|
||||
(declare-c window-fullscreen? [] bool "IsWindowFullscreen")
|
||||
(declare-c window-hidden? [] bool "IsWindowHidden")
|
||||
@ -93,13 +93,10 @@
|
||||
(declare-c set-automation-event-base-frame [frame i32] "SetAutomationEventBaseFrame")
|
||||
(declare-c start-automation-event-recording [] "StartAutomationEventRecording")
|
||||
(declare-c stop-automation-event-recording [] "StopAutomationEventRecording")
|
||||
(declare-c key-pressed-repeat? [key i32] bool "IsKeyPressedRepeat")
|
||||
(declare-c key-up? [key i32] bool "IsKeyUp")
|
||||
(declare-c get-key-pressed [] i32 "GetKeyPressed")
|
||||
(declare-c get-char-pressed [] i32 "GetCharPressed")
|
||||
(declare-c get-key-pressed-raw [] i32 "GetKeyPressed")
|
||||
(declare-c get-char-pressed-raw [] i32 "GetCharPressed")
|
||||
(declare-c set-gamepad-mappings [mappings string] i32 "SetGamepadMappings")
|
||||
(declare-c set-gamepad-vibration [gamepad i32 left-motor f32 right-motor f32 duration f32] "SetGamepadVibration")
|
||||
(declare-c mouse-button-up? [button i32] bool "IsMouseButtonUp")
|
||||
(declare-c get-mouse-x [] i32 "GetMouseX")
|
||||
(declare-c get-mouse-y [] i32 "GetMouseY")
|
||||
(declare-c get-mouse-delta [] Vector2 "GetMouseDelta")
|
||||
@ -108,7 +105,7 @@
|
||||
(declare-c set-mouse-scale [scale-x f32 scale-y f32] "SetMouseScale")
|
||||
(declare-c get-mouse-wheel-move-v [] Vector2 "GetMouseWheelMoveV")
|
||||
(declare-c update-camera-pro [camera (Ptr Camera3D) movement Vector3 rotation Vector3 zoom f32] "UpdateCameraPro")
|
||||
(declare-c draw-line-strip [points (Ptr Vector2) point-count i32 color Color] "DrawLineStrip")
|
||||
(declare-c draw-line-strip-raw [points (Ptr Vector2) point-count i32 color Color] "DrawLineStrip")
|
||||
(declare-c draw-line-bezier [start-pos Vector2 end-pos Vector2 thick f32 color Color] "DrawLineBezier")
|
||||
(declare-c draw-circle-sector [center Vector2 radius f32 start-angle f32 end-angle f32 segments i32 color Color] "DrawCircleSector")
|
||||
(declare-c draw-circle-sector-lines [center Vector2 radius f32 start-angle f32 end-angle f32 segments i32 color Color] "DrawCircleSectorLines")
|
||||
@ -117,16 +114,16 @@
|
||||
(declare-c draw-rectangle-gradient-v [pos-x i32 pos-y i32 width i32 height i32 top Color bottom Color] "DrawRectangleGradientV")
|
||||
(declare-c draw-rectangle-gradient-h [pos-x i32 pos-y i32 width i32 height i32 left Color right Color] "DrawRectangleGradientH")
|
||||
(declare-c draw-rectangle-gradient-ex [rec Rectangle top-left Color bottom-left Color top-right Color bottom-right Color] "DrawRectangleGradientEx")
|
||||
(declare-c draw-triangle-fan [points (Ptr Vector2) point-count i32 color Color] "DrawTriangleFan")
|
||||
(declare-c draw-triangle-strip [points (Ptr Vector2) point-count i32 color Color] "DrawTriangleStrip")
|
||||
(declare-c draw-triangle-fan-raw [points (Ptr Vector2) point-count i32 color Color] "DrawTriangleFan")
|
||||
(declare-c draw-triangle-strip-raw [points (Ptr Vector2) point-count i32 color Color] "DrawTriangleStrip")
|
||||
(declare-c draw-poly [center Vector2 sides i32 radius f32 rotation f32 color Color] "DrawPoly")
|
||||
(declare-c draw-poly-lines [center Vector2 sides i32 radius f32 rotation f32 color Color] "DrawPolyLines")
|
||||
(declare-c draw-poly-lines-ex [center Vector2 sides i32 radius f32 rotation f32 line-thick f32 color Color] "DrawPolyLinesEx")
|
||||
(declare-c draw-spline-linear [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineLinear")
|
||||
(declare-c draw-spline-basis [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBasis")
|
||||
(declare-c draw-spline-catmull-rom [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineCatmullRom")
|
||||
(declare-c draw-spline-bezier-quadratic [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBezierQuadratic")
|
||||
(declare-c draw-spline-bezier-cubic [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBezierCubic")
|
||||
(declare-c draw-spline-linear-raw [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineLinear")
|
||||
(declare-c draw-spline-basis-raw [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBasis")
|
||||
(declare-c draw-spline-catmull-rom-raw [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineCatmullRom")
|
||||
(declare-c draw-spline-bezier-quadratic-raw [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBezierQuadratic")
|
||||
(declare-c draw-spline-bezier-cubic-raw [points (Ptr Vector2) point-count i32 thick f32 color Color] "DrawSplineBezierCubic")
|
||||
(declare-c draw-spline-segment-linear [p-1 Vector2 p-2 Vector2 thick f32 color Color] "DrawSplineSegmentLinear")
|
||||
(declare-c draw-spline-segment-basis [p-1 Vector2 p-2 Vector2 p-3 Vector2 p-4 Vector2 thick f32 color Color] "DrawSplineSegmentBasis")
|
||||
(declare-c draw-spline-segment-catmull-rom [p-1 Vector2 p-2 Vector2 p-3 Vector2 p-4 Vector2 thick f32 color Color] "DrawSplineSegmentCatmullRom")
|
||||
@ -197,8 +194,8 @@
|
||||
(declare-c image-draw-triangle [dst (Ptr Image) v-1 Vector2 v-2 Vector2 v-3 Vector2 color Color] "ImageDrawTriangle")
|
||||
(declare-c image-draw-triangle-ex [dst (Ptr Image) v-1 Vector2 v-2 Vector2 v-3 Vector2 c-1 Color c-2 Color c-3 Color] "ImageDrawTriangleEx")
|
||||
(declare-c image-draw-triangle-lines [dst (Ptr Image) v-1 Vector2 v-2 Vector2 v-3 Vector2 color Color] "ImageDrawTriangleLines")
|
||||
(declare-c image-draw-triangle-fan [dst (Ptr Image) points (Ptr Vector2) point-count i32 color Color] "ImageDrawTriangleFan")
|
||||
(declare-c image-draw-triangle-strip [dst (Ptr Image) points (Ptr Vector2) point-count i32 color Color] "ImageDrawTriangleStrip")
|
||||
(declare-c image-draw-triangle-fan-raw [dst (Ptr Image) points (Ptr Vector2) point-count i32 color Color] "ImageDrawTriangleFan")
|
||||
(declare-c image-draw-triangle-strip-raw [dst (Ptr Image) points (Ptr Vector2) point-count i32 color Color] "ImageDrawTriangleStrip")
|
||||
(declare-c image-draw [dst (Ptr Image) src Image src-rec Rectangle dst-rec Rectangle tint Color] "ImageDraw")
|
||||
(declare-c image-draw-text [dst (Ptr Image) text string pos-x i32 pos-y i32 font-size i32 color Color] "ImageDrawText")
|
||||
(declare-c image-draw-text-ex [dst (Ptr Image) font Font text string position Vector2 font-size f32 spacing f32 tint Color] "ImageDrawTextEx")
|
||||
@ -245,7 +242,7 @@
|
||||
(declare-c draw-point-3d [position Vector3 color Color] "DrawPoint3D")
|
||||
(declare-c draw-circle-3d [center Vector3 radius f32 rotation-axis Vector3 rotation-angle f32 color Color] "DrawCircle3D")
|
||||
(declare-c draw-triangle-3d [v-1 Vector3 v-2 Vector3 v-3 Vector3 color Color] "DrawTriangle3D")
|
||||
(declare-c draw-triangle-strip-3d [points (Ptr Vector3) point-count i32 color Color] "DrawTriangleStrip3D")
|
||||
(declare-c draw-triangle-strip-3d-raw [points (Ptr Vector3) point-count i32 color Color] "DrawTriangleStrip3D")
|
||||
(declare-c draw-cube-wires-v [position Vector3 size Vector3 color Color] "DrawCubeWiresV")
|
||||
(declare-c draw-sphere-ex [center-pos Vector3 radius f32 rings i32 slices i32 color Color] "DrawSphereEx")
|
||||
(declare-c draw-cylinder [position Vector3 radius-top f32 radius-bottom f32 height f32 slices i32 color Color] "DrawCylinder")
|
||||
|
||||
158
vendor/raylib/raylib.flan
vendored
158
vendor/raylib/raylib.flan
vendored
@ -27,9 +27,29 @@
|
||||
;;;; f64 where raylib says float now emits `double` in the generated
|
||||
;;;; prototype, and raylib reads garbage.
|
||||
;;;;
|
||||
;;;; Two bindings keep a hand-written Flan wrapper, both because their Flan
|
||||
;;;; face is deliberately not raylib's: collision-point-poly? takes a slice,
|
||||
;;;; and collision-lines answers with an Option. Both wrappers are Flan.
|
||||
;;;; Some bindings keep a hand-written Flan wrapper, because their Flan face
|
||||
;;;; is deliberately not raylib's. Three shapes of that, and every wrapper in
|
||||
;;;; this file is one of them:
|
||||
;;;;
|
||||
;;;; - a slice where C takes a pointer and a count — collision-point-poly?,
|
||||
;;;; load-image-from-memory, load-font-ex, and the eleven vector-array
|
||||
;;;; drawing calls under "A slice where raylib wants a pointer and a
|
||||
;;;; count";
|
||||
;;;; - an Option where C signals failure by a bool out-parameter or a
|
||||
;;;; sentinel — collision-lines, get-key-pressed, get-char-pressed;
|
||||
;;;; - an enum where the header says `int`. These are NOT wrappers: a C
|
||||
;;;; enum parameter has an int's ABI, so the hand-written declare-c with
|
||||
;;;; the Flan type on it is the whole fix, and set-exit-key,
|
||||
;;;; set-mouse-cursor, key-up? and mouse-button-up? are all that.
|
||||
;;;;
|
||||
;;;; What is NOT here, and was asked for: with-drawing and with-mode-2d over
|
||||
;;;; raylib's begin/end pairs. An unbalanced pair is a real bug and a macro
|
||||
;;;; removes it, but a macro cannot live in a package — the expander collects
|
||||
;;;; defmacros from the prelude and from the file being compiled, and a
|
||||
;;;; defmacro in an imported package is refused by name
|
||||
;;;; (test/programs/pkg-macro.flan, an acceptance case whose whole content is
|
||||
;;;; the refusal). So these have to be written in the program that uses them,
|
||||
;;;; or wait for macros to be importable, and neither is this file's to do.
|
||||
|
||||
;; Layouts are C's — no object headers anywhere — so these are exactly
|
||||
;; raylib's structs and nothing marshals.
|
||||
@ -133,6 +153,18 @@
|
||||
(declare-c key-down? [key Key] bool "IsKeyDown")
|
||||
(declare-c key-released? [key Key] bool "IsKeyReleased")
|
||||
|
||||
;; The other two halves of that family, hand-written for exactly the reason
|
||||
;; above and added late: they were generated, so they took an i32, so
|
||||
;; `(rl/key-up? :space)` did not compile while `(rl/key-down? :space)` did.
|
||||
;; That is a hole in a family rather than a missing convenience — a caller
|
||||
;; who has used key-down? has no reason to expect the sibling to be spelled
|
||||
;; differently, and what they get instead of a keyword is a number nobody
|
||||
;; checks. Nothing wraps these: the ABI of a C enum parameter is the ABI of
|
||||
;; an int, so the declaration IS the fix and a defn around it would only be
|
||||
;; a rename.
|
||||
(declare-c key-up? [key Key] bool "IsKeyUp")
|
||||
(declare-c key-pressed-repeat? [key Key] bool "IsKeyPressedRepeat")
|
||||
|
||||
(declare-c mouse-button-pressed?
|
||||
[button MouseButton] bool
|
||||
"IsMouseButtonPressed")
|
||||
@ -140,6 +172,37 @@
|
||||
(declare-c mouse-button-released?
|
||||
[button MouseButton] bool
|
||||
"IsMouseButtonReleased")
|
||||
(declare-c mouse-button-up? [button MouseButton] bool "IsMouseButtonUp")
|
||||
|
||||
;; ── Draining raylib's two input queues ──────────────────────────────
|
||||
;;
|
||||
;; Both of these answer "nothing left" with 0, and 0 is also a value the
|
||||
;; caller could otherwise have to think about — KEY_NULL for one, the NUL
|
||||
;; byte for the other. An Option says which of the two it is in the type, so
|
||||
;; the loop that drains the queue cannot read the sentinel as a key or as a
|
||||
;; character: `while (> key 0)` is a comparison a reader has to know the
|
||||
;; convention to trust, and `(while-some ...)` — or the `if-let` shape the
|
||||
;; examples use — is one a reader can check.
|
||||
;;
|
||||
;; The generated declarations are still what call C; only their names moved
|
||||
;; aside, to -raw, via the `name` lines in `bindings`. Nothing about the C
|
||||
;; signature was wrong, so hand-writing it would have taken the generated
|
||||
;; half's agreement-by-construction with the header and given nothing back.
|
||||
;;
|
||||
;; get-key-pressed answers an i32 and not a Key. A Key is a *closed* set the
|
||||
;; package names a subset of, and this queue reports every key on the
|
||||
;; keyboard including the ones no member covers, so the enum would be a
|
||||
;; promise the value does not keep. Comparing the answer against `:space`
|
||||
;; would be the reason to want it, and that is what key-pressed? is for.
|
||||
(defn get-key-pressed [] (Option i32)
|
||||
(let [k (get-key-pressed-raw)]
|
||||
(if (= k 0) None (Some k))))
|
||||
|
||||
;; Unicode codepoint, not a byte: raylib decodes the platform's input, so a
|
||||
;; value above 127 is a real codepoint and not the first byte of one.
|
||||
(defn get-char-pressed [] (Option i32)
|
||||
(let [c (get-char-pressed-raw)]
|
||||
(if (= c 0) None (Some c))))
|
||||
|
||||
(declare-c get-mouse-position [] Vector2 "GetMousePosition")
|
||||
|
||||
@ -793,6 +856,95 @@
|
||||
(declare-c draw-rectangle-rounded-lines-ex [rec Rectangle roundness f32
|
||||
segments i32 thick f32 color Color] "DrawRectangleRoundedLinesEx")
|
||||
|
||||
;; ── A slice where raylib wants a pointer and a count ─────────────────
|
||||
;;
|
||||
;; Eleven entry points take an array of vectors as a pointer plus an `int`
|
||||
;; count. A Flan slice already carries both, so every call site that does not
|
||||
;; go through a wrapper has to take the slice apart itself — `(addr (at pts
|
||||
;; 0))` and `(len pts)`, twice, in the right order — and the compiler cannot
|
||||
;; check that the two halves came from the same slice. The wrapper is where
|
||||
;; that idiom lives, which is the rule collision-point-poly? set.
|
||||
;;
|
||||
;; It also guards the empty case, which is the part a hand-written call site
|
||||
;; gets wrong rather than merely writes out. raylib takes a count of 0 and
|
||||
;; draws nothing, but `(at pts 0)` on an empty slice is out of bounds before
|
||||
;; raylib is ever reached: the safe call is "do not call at all", and it is
|
||||
;; written once here instead of at every use.
|
||||
;;
|
||||
;; All eleven and not the three anybody has called. A subset would have its
|
||||
;; hole exactly where the next caller looks, which is the argument this file
|
||||
;; already makes about ConfigFlags, and the eleven are one family — there is
|
||||
;; no line to draw between DrawSplineLinear and DrawSplineBasis that a reader
|
||||
;; would predict.
|
||||
;;
|
||||
;; `bindings` makes the opposite argument a few lines above its own list —
|
||||
;; that hand-writing the variants of a family "would widen the half that has
|
||||
;; to be maintained by hand for nothing the examples ask for" — and it is
|
||||
;; right there and does not reach here. That paragraph is about hand-written
|
||||
;; `declare-c` lines, which are exactly the half a header change can falsify.
|
||||
;; None of these eleven is one: each is a `name` directive, so the generated
|
||||
;; declaration keeps the C symbol and its checked signature and gives up only
|
||||
;; its Flan name. The hand-maintained half does not widen at all — what is
|
||||
;; written below is Flan calling Flan, and it cannot disagree with raylib. They sit together here rather than each in its own section
|
||||
;; for the same reason: the justification above is one argument about a shape
|
||||
;; that cuts across Shapes, Images and 3D, and splitting the family would
|
||||
;; mean writing it three times or leaving two thirds of it unexplained.
|
||||
;;
|
||||
;; Each -raw below is a generated declaration whose name moved aside; see the
|
||||
;; `name` lines at the foot of `bindings`.
|
||||
|
||||
(defn draw-line-strip [points [Vector2] color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-line-strip-raw (addr (at points 0)) (len points) color)))
|
||||
|
||||
(defn draw-triangle-fan [points [Vector2] color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-triangle-fan-raw (addr (at points 0)) (len points) color)))
|
||||
|
||||
(defn draw-triangle-strip [points [Vector2] color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-triangle-strip-raw (addr (at points 0)) (len points) color)))
|
||||
|
||||
(defn draw-triangle-strip-3d [points [Vector3] color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-triangle-strip-3d-raw (addr (at points 0)) (len points) color)))
|
||||
|
||||
;; The five spline drawers. raylib reads the same point array five different
|
||||
;; ways; the only difference between these wrappers is which one it calls.
|
||||
(defn draw-spline-linear [points [Vector2] thick f32 color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-spline-linear-raw (addr (at points 0)) (len points) thick color)))
|
||||
|
||||
(defn draw-spline-basis [points [Vector2] thick f32 color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-spline-basis-raw (addr (at points 0)) (len points) thick color)))
|
||||
|
||||
(defn draw-spline-catmull-rom [points [Vector2] thick f32 color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-spline-catmull-rom-raw (addr (at points 0)) (len points) thick color)))
|
||||
|
||||
(defn draw-spline-bezier-quadratic [points [Vector2] thick f32 color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-spline-bezier-quadratic-raw
|
||||
(addr (at points 0)) (len points) thick color)))
|
||||
|
||||
(defn draw-spline-bezier-cubic [points [Vector2] thick f32 color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(draw-spline-bezier-cubic-raw
|
||||
(addr (at points 0)) (len points) thick color)))
|
||||
|
||||
;; The same two into an Image rather than the frame. `dst` stays a pointer:
|
||||
;; it is the thing being written, not an array, and raylib's convention for
|
||||
;; an in-place Image is the whole Image* family in this file.
|
||||
(defn image-draw-triangle-fan [dst (Ptr Image) points [Vector2] color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(image-draw-triangle-fan-raw dst (addr (at points 0)) (len points) color)))
|
||||
|
||||
(defn image-draw-triangle-strip
|
||||
[dst (Ptr Image) points [Vector2] color Color] ()
|
||||
(when (> (len points) 0)
|
||||
(image-draw-triangle-strip-raw dst (addr (at points 0)) (len points) color)))
|
||||
|
||||
;; ── Text ────────────────────────────────────────────────────────────
|
||||
;;
|
||||
;; Both of these use raylib's built-in font, and both therefore need
|
||||
|
||||
233
vendor/raylib/vector.flan
vendored
Normal file
233
vendor/raylib/vector.flan
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
;;;; Vector arithmetic over raylib's Vector2 and Vector3, in Flan.
|
||||
;;;;
|
||||
;;;; This is raymath, and raymath is the one part of raylib that cannot be
|
||||
;;;; bound at all. raymath.h defines every one of its functions `static
|
||||
;;;; inline` (RMAPI expands to it), so Vector2Add and Clamp and Remap have no
|
||||
;;;; symbol in libraylib for `declare-c` to name — not a signature the
|
||||
;;;; importer gets wrong, not a struct the package has not described, but
|
||||
;;;; nothing to link against. NEXT.md item 4 records it and names the two
|
||||
;;;; ways out: write the arithmetic in Flan, or compile a small C file that
|
||||
;;;; re-exports the inlines as real symbols.
|
||||
;;;;
|
||||
;;;; It is written in Flan, and the measurement that decided it was already
|
||||
;;;; taken: examples/shapes-following-eyes.flan is an example whose every
|
||||
;;;; line is vector maths, ported without a vector library, and its own
|
||||
;;;; header reports that this cost nothing — the C does not use raymath there
|
||||
;;;; either. A C shim would buy identical arithmetic at the price of a
|
||||
;;;; compilation unit in the build, a second place raylib's semantics are
|
||||
;;;; written down, and a third target's worth of it for the web build.
|
||||
;;;;
|
||||
;;;; Every function here is raymath's, semantics included, and the ones where
|
||||
;;;; that is not obvious say so. The one worth knowing without reading: at
|
||||
;;;; zero length, v2-normalize and v3-normalize answer the zero vector rather
|
||||
;;;; than dividing and producing NaNs. raymath makes that choice and a caller
|
||||
;;;; who has raymath in mind would be surprised by the other one.
|
||||
;;;;
|
||||
;;;; ── Why this is a file of its own ───────────────────────────────────
|
||||
;;;;
|
||||
;;;; The split is on `declare-c`, not on "idiomatic". raylib.flan is the
|
||||
;;;; package's statement about C: every line in it is a declaration or a thin
|
||||
;;;; wrapper over one, it is the file the header check reads hand-written
|
||||
;;;; signatures out of, and a wrong line in it stops the build. There is not
|
||||
;;;; one `declare-c` below and there never will be, because there is nothing
|
||||
;;;; to declare — so nothing here can be checked against a header, and
|
||||
;;;; nothing here can be made wrong by raylib changing. A reader who wants to
|
||||
;;;; know what the package claims about C should not have to walk past four
|
||||
;;;; hundred lines of float arithmetic to find out, and 1300 lines of
|
||||
;;;; raylib.flan is already the argument against adding to it.
|
||||
;;;;
|
||||
;;;; A package is a directory, so this is simply another .flan beside the
|
||||
;;;; others and is qualified `rl/` like the rest of it.
|
||||
;;;;
|
||||
;;;; ── Names ───────────────────────────────────────────────────────────
|
||||
;;;;
|
||||
;;;; `v2-` and `v3-`, not `vector2-`. These appear nested inside each other —
|
||||
;;;; `(rl/v2-add p (rl/v2-scale d t))` is the ordinary shape — and the longer
|
||||
;;;; spelling puts more characters between the reader and the arithmetic than
|
||||
;;;; it puts meaning. The prefix still says the type, which is the part a
|
||||
;;;; language without generics needs it to say.
|
||||
;;;;
|
||||
;;;; ── What is NOT here, on purpose ────────────────────────────────────
|
||||
;;;;
|
||||
;;;; `clamp` and `lerp`. Both are already in the prelude — clamp as a macro
|
||||
;;;; (prelude.ml, "clamp is a macro and not a function"), lerp as a function
|
||||
;;;; — and both are unqualified names every program already has;
|
||||
;;;; examples/textures-fog-of-war.flan calls the prelude's clamp today. A
|
||||
;;;; second `rl/lerp` would not even be the same function: the prelude writes
|
||||
;;;; the weighted sum `(1-t)a + tb`, which returns b exactly at t = 1.0,
|
||||
;;;; where raymath writes `a + t*(b - a)`, which does not once rounding is
|
||||
;;;; involved. Shipping both under names one letter apart is a bug waiting
|
||||
;;;; for whoever picks the wrong one. So: use the prelude's, and what is
|
||||
;;;; added below is the neighbours the prelude does not have.
|
||||
|
||||
;; ── f32, the scalars raymath has and the prelude does not ───────────
|
||||
|
||||
;; Where `value` falls between `start` and `end`, as 0.0 at start and 1.0 at
|
||||
;; end. raymath spells this `Normalize`, which collides with the vector
|
||||
;; normalize two sections down and means something unrelated to it; it is the
|
||||
;; inverse of lerp and is named for that. start = end is a division by zero,
|
||||
;; as it is in raymath: an empty range has no answer and inventing one would
|
||||
;; hide the caller's bug.
|
||||
(defn inverse-lerp [value f32 start f32 end f32] f32
|
||||
(/ (- value start) (- end start)))
|
||||
|
||||
;; raymath's Remap, to the character: inverse-lerp on the input range, then
|
||||
;; lerp on the output range, and NOT clamped to either. A value outside the
|
||||
;; input range maps outside the output range, which is what makes it usable
|
||||
;; for extrapolation — a caller who wants it bounded writes the prelude's
|
||||
;; clamp around it and can see that they did.
|
||||
;;
|
||||
;; Written as one expression rather than as (lerp out-start out-end
|
||||
;; (inverse-lerp ...)) because the prelude's lerp is the weighted-sum form
|
||||
;; and raymath's Remap is the a + t*(b - a) form; composing them would be a
|
||||
;; different function in the last bit.
|
||||
(defn remap [value f32 in-start f32 in-end f32
|
||||
out-start f32 out-end f32] f32
|
||||
(+ (* (/ (- value in-start) (- in-end in-start))
|
||||
(- out-end out-start))
|
||||
out-start))
|
||||
|
||||
;; raymath's Wrap. Brings a value into [min, max) by subtracting whole spans
|
||||
;; of it — an angle past 2π, a scrolling offset past the tile width. floor
|
||||
;; and not truncation, so a value below min wraps up instead of sticking.
|
||||
(defn wrap-f32 [value f32 lo f32 hi f32] f32
|
||||
(- value (* (- hi lo) (floor-f32 (/ (- value lo) (- hi lo))))))
|
||||
|
||||
;; ── Vector2 ─────────────────────────────────────────────────────────
|
||||
|
||||
(defn v2-add [a Vector2 b Vector2] Vector2
|
||||
(Vector2 {.x (+ (.x a) (.x b)) .y (+ (.y a) (.y b))}))
|
||||
|
||||
(defn v2-sub [a Vector2 b Vector2] Vector2
|
||||
(Vector2 {.x (- (.x a) (.x b)) .y (- (.y a) (.y b))}))
|
||||
|
||||
;; Componentwise, which is raymath's Vector2Multiply and is not a dot product
|
||||
;; or anything else that deserves the word "multiply" unqualified. It is what
|
||||
;; a non-uniform scale is written as.
|
||||
(defn v2-mul [a Vector2 b Vector2] Vector2
|
||||
(Vector2 {.x (* (.x a) (.x b)) .y (* (.y a) (.y b))}))
|
||||
|
||||
(defn v2-scale [v Vector2 k f32] Vector2
|
||||
(Vector2 {.x (* (.x v) k) .y (* (.y v) k)}))
|
||||
|
||||
(defn v2-negate [v Vector2] Vector2
|
||||
(Vector2 {.x (- 0.0 (.x v)) .y (- 0.0 (.y v))}))
|
||||
|
||||
(defn v2-dot [a Vector2 b Vector2] f32
|
||||
(+ (* (.x a) (.x b)) (* (.y a) (.y b))))
|
||||
|
||||
;; The squared forms are not micro-optimisation dressed up: comparing two
|
||||
;; distances, or a distance against a radius, is the common case and neither
|
||||
;; needs the square root. raymath has both for the same reason.
|
||||
(defn v2-length-sqr [v Vector2] f32
|
||||
(+ (* (.x v) (.x v)) (* (.y v) (.y v))))
|
||||
|
||||
(defn v2-length [v Vector2] f32
|
||||
(sqrt-f32 (+ (* (.x v) (.x v)) (* (.y v) (.y v)))))
|
||||
|
||||
(defn v2-distance-sqr [a Vector2 b Vector2] f32
|
||||
(let [dx (- (.x a) (.x b))
|
||||
dy (- (.y a) (.y b))]
|
||||
(+ (* dx dx) (* dy dy))))
|
||||
|
||||
(defn v2-distance [a Vector2 b Vector2] f32
|
||||
(let [dx (- (.x a) (.x b))
|
||||
dy (- (.y a) (.y b))]
|
||||
(sqrt-f32 (+ (* dx dx) (* dy dy)))))
|
||||
|
||||
;; Zero in, zero out — raymath's Vector2Normalize guards on `length > 0` and
|
||||
;; returns {0, 0}, and this does the same. The alternative is dividing by
|
||||
;; zero and answering a vector of NaNs, which then propagates through every
|
||||
;; subsequent frame's arithmetic and reports itself somewhere else entirely.
|
||||
;; The guard is the whole reason this is a function and not two divisions
|
||||
;; written at the call site.
|
||||
(defn v2-normalize [v Vector2] Vector2
|
||||
(let [length (sqrt-f32 (+ (* (.x v) (.x v)) (* (.y v) (.y v))))]
|
||||
(if (> length 0.0)
|
||||
(let [inv (/ 1.0 length)]
|
||||
(Vector2 {.x (* (.x v) inv) .y (* (.y v) inv)}))
|
||||
(Vector2 {.x 0.0 .y 0.0}))))
|
||||
|
||||
;; The signed angle from a to b, in radians, via atan2 of the 2D cross
|
||||
;; product over the dot. Signed and not absolute, so it says which way to
|
||||
;; turn; raymath's Vector2Angle is this and not the acos form.
|
||||
(defn v2-angle [a Vector2 b Vector2] f32
|
||||
(atan2-f32 (- (* (.x a) (.y b)) (* (.y a) (.x b)))
|
||||
(+ (* (.x a) (.x b)) (* (.y a) (.y b)))))
|
||||
|
||||
;; a + t*(b - a) componentwise, which is raymath's Vector2Lerp exactly. The
|
||||
;; note in the file header applies: the prelude's scalar lerp is the
|
||||
;; weighted-sum form and this is not, so the two do not agree in the last bit
|
||||
;; at t = 1.0. raymath's is kept here because a vector path that disagrees
|
||||
;; with raylib's own would be the surprise.
|
||||
(defn v2-lerp [a Vector2 b Vector2 t f32] Vector2
|
||||
(Vector2 {.x (+ (.x a) (* t (- (.x b) (.x a))))
|
||||
.y (+ (.y a) (* t (- (.y b) (.y a))))}))
|
||||
|
||||
;; Counter-clockwise by `angle` radians in raylib's screen space, which has y
|
||||
;; growing downward — so on screen it turns the other way from the way the
|
||||
;; maths reads. raymath's Vector2Rotate, unchanged.
|
||||
(defn v2-rotate [v Vector2 angle f32] Vector2
|
||||
(let [c (cos-f32 angle)
|
||||
s (sin-f32 angle)]
|
||||
(Vector2 {.x (- (* (.x v) c) (* (.y v) s))
|
||||
.y (+ (* (.x v) s) (* (.y v) c))})))
|
||||
|
||||
;; ── Vector3 ─────────────────────────────────────────────────────────
|
||||
|
||||
(defn v3-add [a Vector3 b Vector3] Vector3
|
||||
(Vector3 {.x (+ (.x a) (.x b)) .y (+ (.y a) (.y b)) .z (+ (.z a) (.z b))}))
|
||||
|
||||
(defn v3-sub [a Vector3 b Vector3] Vector3
|
||||
(Vector3 {.x (- (.x a) (.x b)) .y (- (.y a) (.y b)) .z (- (.z a) (.z b))}))
|
||||
|
||||
(defn v3-mul [a Vector3 b Vector3] Vector3
|
||||
(Vector3 {.x (* (.x a) (.x b)) .y (* (.y a) (.y b)) .z (* (.z a) (.z b))}))
|
||||
|
||||
(defn v3-scale [v Vector3 k f32] Vector3
|
||||
(Vector3 {.x (* (.x v) k) .y (* (.y v) k) .z (* (.z v) k)}))
|
||||
|
||||
(defn v3-negate [v Vector3] Vector3
|
||||
(Vector3 {.x (- 0.0 (.x v)) .y (- 0.0 (.y v)) .z (- 0.0 (.z v))}))
|
||||
|
||||
(defn v3-dot [a Vector3 b Vector3] f32
|
||||
(+ (+ (* (.x a) (.x b)) (* (.y a) (.y b))) (* (.z a) (.z b))))
|
||||
|
||||
;; Right-handed, which is the convention raylib's camera uses: the cross of
|
||||
;; the x axis with the y axis is the z axis.
|
||||
(defn v3-cross [a Vector3 b Vector3] Vector3
|
||||
(Vector3 {.x (- (* (.y a) (.z b)) (* (.z a) (.y b)))
|
||||
.y (- (* (.z a) (.x b)) (* (.x a) (.z b)))
|
||||
.z (- (* (.x a) (.y b)) (* (.y a) (.x b)))}))
|
||||
|
||||
(defn v3-length-sqr [v Vector3] f32
|
||||
(+ (+ (* (.x v) (.x v)) (* (.y v) (.y v))) (* (.z v) (.z v))))
|
||||
|
||||
(defn v3-length [v Vector3] f32
|
||||
(sqrt-f32 (+ (+ (* (.x v) (.x v)) (* (.y v) (.y v))) (* (.z v) (.z v)))))
|
||||
|
||||
(defn v3-distance-sqr [a Vector3 b Vector3] f32
|
||||
(let [dx (- (.x a) (.x b))
|
||||
dy (- (.y a) (.y b))
|
||||
dz (- (.z a) (.z b))]
|
||||
(+ (+ (* dx dx) (* dy dy)) (* dz dz))))
|
||||
|
||||
(defn v3-distance [a Vector3 b Vector3] f32
|
||||
(let [dx (- (.x a) (.x b))
|
||||
dy (- (.y a) (.y b))
|
||||
dz (- (.z a) (.z b))]
|
||||
(sqrt-f32 (+ (+ (* dx dx) (* dy dy)) (* dz dz)))))
|
||||
|
||||
;; Zero in, zero out, exactly as v2-normalize and for the same reason.
|
||||
(defn v3-normalize [v Vector3] Vector3
|
||||
(let [length (sqrt-f32 (+ (+ (* (.x v) (.x v)) (* (.y v) (.y v)))
|
||||
(* (.z v) (.z v))))]
|
||||
(if (> length 0.0)
|
||||
(let [inv (/ 1.0 length)]
|
||||
(Vector3 {.x (* (.x v) inv) .y (* (.y v) inv) .z (* (.z v) inv)}))
|
||||
(Vector3 {.x 0.0 .y 0.0 .z 0.0}))))
|
||||
|
||||
(defn v3-lerp [a Vector3 b Vector3 t f32] Vector3
|
||||
(Vector3 {.x (+ (.x a) (* t (- (.x b) (.x a))))
|
||||
.y (+ (.y a) (* t (- (.y b) (.y a))))
|
||||
.z (+ (.z a) (* t (- (.z b) (.z a))))}))
|
||||
Loading…
x
Reference in New Issue
Block a user