An idiomatic layer over the raylib bindings, and raymath in Flan
Three kinds of Flan face over the generated set, which stays honest to C because that is what makes it checkable against the header. A slice where C takes a pointer and a count: the eleven vector-array drawing calls, all eleven rather than the three anybody calls, since a subset has its hole where the next caller looks. Each 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 taking the address of element 0 of an empty slice 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 that buys is in text-input-box.flan, which read the queue in two places -- once to prime the loop, once at the bottom of the body -- and now reads it in one. Both of those use the `name` directive in bindings, so the generated declaration keeps the symbol and gives up the name: nothing about the C signature is hand-written and the generated half keeps its agreement-by-construction with the header. An enum where the header says int: key-up?, key-pressed-repeat?, mouse-button-up?. These are NOT wrappers -- a C enum parameter has an int's ABI, so the hand-written declare-c with the Flan type is the whole fix. They were holes in families whose other halves already took a Key, so (rl/key-down? :space) compiled and (rl/key-up? :space) did not. Not built: with-drawing and with-mode-2d. A macro cannot live in a package -- the expander collects defmacros 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 vendor/raylib/vector.flan, which is raymath written in Flan because raymath is static inline and has no symbol to bind. A file of its own, split on declare-c and not on "idiomatic": there is not one declaration in it, so it is not part of the surface the header check reads, and raylib.flan is 1300 lines already. clamp and lerp are deliberately absent -- the prelude has both, and a second lerp would not even be the same function, since the prelude writes (1-t)a + tb where raymath writes a + t*(b - a). Examples: the identical eight-expression box-around helper in core-3d-picking and models-box-collisions is a half-extent subtracted and added. shapes-following-eyes keeps its measurement and gives up one line to v2-sub, which is the honest size of the gap in a file that is nothing but vector maths.
This commit is contained in:
parent
8472c50d57
commit
5a1c2745b0
57
NEXT.md
57
NEXT.md
@ -286,12 +286,21 @@ why they are here and not in a binding list.
|
||||
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.** `Clamp`, `Vector2Add`, `Remap` and
|
||||
the rest exist only in the header. `declare-c` has nothing to name. rlgl's matrix stack is
|
||||
unbound for a different reason. Together they make `core_2d_camera_mouse_zoom` unfaithful rather
|
||||
than merely awkward, so it was skipped. The options are writing the arithmetic in Flan, which is
|
||||
what the prelude would do anyway, or compiling a small C file that re-exports them as real
|
||||
symbols.
|
||||
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
|
||||
@ -433,12 +442,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**
|
||||
|
||||
@ -712,7 +743,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")
|
||||
|
||||
148
vendor/raylib/raylib.flan
vendored
148
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,85 @@
|
||||
(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. 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