From a3e06ce3d41e92120d9f1d351bfac5a7bde92f0b Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Fri, 11 Sep 2026 20:26:00 +0700 Subject: [PATCH] raylib says what it takes, and shim.c stops existing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All 84 bindings migrated, so the package is raylib.flan and link and no C at all. Two keep a wrapper and both wrappers are Flan, not C: collision-point-poly? takes a slice and collision-lines answers with an Option, and neither is raylib's signature. A slice in a declare-c is refused by name — the length crosses as i64 and the type of the C count parameter beside the pointer is not recoverable from [T] — so that one declares (Ptr Vector2) with an explicit count and the Flan wrapper hands over (addr (at points 0)) and (len points), answering an empty polygon itself rather than reading out of bounds. What this buys and what it costs, stated rather than assumed. Guaranteed: the C typedef and the Flan struct are made from one defstruct, so they cannot disagree — permute the defstruct and both permute. Trusted: that the defstruct is raylib's real struct and that the declare-c is raylib's real signature. No header is read, on purpose, so the build needs libraylib linkable and not raylib-devel, and nothing here can check either half. A _Static_assert on sizeof and offsetof would have both sides coming from the same field list, so it was left out rather than mistaken for evidence. The sharper edge is the prototype: it is generated from the declaration now, so f64 where raylib says float emits double and raylib reads garbage, where before clang narrowed it at the hand-written call site. Every one of the 84 was diffed against the prototypes in the shim.c being deleted, which was the ground truth, and they agree. Strings are sized here and not per call site, because a generator has no call site to look at. 256 bytes on the stack, the heap past that, freed after the call; the only truncation left is on malloc failure. The old wrappers truncated at 256, PATH_MAX and 512 by hand. --- vendor/raylib/raylib.flan | 675 ++++++++++++-------------------------- vendor/raylib/shim.c | 476 --------------------------- 2 files changed, 210 insertions(+), 941 deletions(-) delete mode 100644 vendor/raylib/shim.c diff --git a/vendor/raylib/raylib.flan b/vendor/raylib/raylib.flan index 5b0bb55..a84dc2b 100644 --- a/vendor/raylib/raylib.flan +++ b/vendor/raylib/raylib.flan @@ -1,19 +1,35 @@ ;;;; raylib, declared for Flan. The directory is the package (plan.org, ;;;; Modules), and (import rl "vendor:raylib") qualifies all of it as rl/… ;;;; -;;;; Nothing here names a raylib symbol. Every `declare` names a wrapper in -;;;; shim.c, and that is the whole design decision: raylib passes Color by -;;;; value and returns Vector2 by value, and how a small aggregate is passed -;;;; differs between x86-64, arm64 and wasm32. Written in C, clang classifies -;;;; each one correctly per target for free; written in emit.ml it would be -;;;; three calling conventions to reimplement and then maintain forever. This -;;;; is "one narrow host ABI, implemented twice" (plan.org, Targets), and it -;;;; is why the checker rejects an aggregate in a `declare` signature at all. +;;;; Every binding here is one `declare-c` line naming raylib's own function +;;;; in raylib's own signature — Color by value, Vector2 returned by value — +;;;; and the compiler writes the C that flattens it. There is no shim.c in +;;;; this directory any more, and no hand-written wrapper at all. ;;;; -;;;; So each struct that crosses does it through a pointer, and the `-raw` -;;;; declaration is wrapped by an ordinary Flan function just below it. The -;;;; `-raw` names are visible as rl/…-raw because there is no visibility rule -;;;; yet; they are not meant to be called. +;;;; The shim itself did not go away, only the typing of it. A small +;;;; aggregate's calling convention is a per-target classification rather than +;;;; part of its layout: x86-64 hands Vector2 over as <2 x float> and returns +;;;; Rectangle as {i64,i64}, and arm64 and wasm32 each do something else. +;;;; Written in C, clang classifies every one of them correctly for whichever +;;;; target the build is for; written in emit.ml it would be three calling +;;;; conventions to reimplement and then keep correct forever, and a mistake +;;;; would read as a field full of garbage rather than as a link error. This +;;;; is "one narrow host ABI, implemented twice" (plan.org, Targets). See +;;;; lib/shim.ml. +;;;; +;;;; What that means for reading this file: the `defstruct`s below are the +;;;; only statement anywhere about raylib's layouts, and the generated C +;;;; typedefs are made from them. No raylib header is consulted — a build +;;;; needs libraylib linkable, not raylib-devel — so a wrong field order here +;;;; is wrong everywhere and nothing but a test can catch it. The acceptance +;;;; cases pin the layouts by making raylib *compute* with the fields, and +;;;; they go red when a struct below is permuted. Likewise a scalar's width: +;;;; 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. ;; Layouts are C's — no object headers anywhere — so these are exactly ;; raylib's structs and nothing marshals. @@ -46,31 +62,27 @@ ;; ── Window ────────────────────────────────────────────────────────── -(declare init-window [width i32 height i32 title string] "flan_rl_init_window") -(declare close-window [] "flan_rl_close_window") -(declare window-should-close? [] bool "flan_rl_window_should_close") -(declare set-target-fps [fps i32] "flan_rl_set_target_fps") -(declare set-trace-log-level [level TraceLogLevel] "flan_rl_set_trace_log_level") +(declare-c init-window [width i32 height i32 title string] "InitWindow") +(declare-c close-window [] "CloseWindow") +(declare-c window-should-close? [] bool "WindowShouldClose") +(declare-c set-target-fps [fps i32] "SetTargetFPS") +(declare-c set-trace-log-level [level TraceLogLevel] "SetTraceLogLevel") ;; ── Input ─────────────────────────────────────────────────────────── -(declare key-pressed? [key Key] bool "flan_rl_is_key_pressed") -(declare key-down? [key Key] bool "flan_rl_is_key_down") -(declare key-released? [key Key] bool "flan_rl_is_key_released") +(declare-c key-pressed? [key Key] bool "IsKeyPressed") +(declare-c key-down? [key Key] bool "IsKeyDown") +(declare-c key-released? [key Key] bool "IsKeyReleased") -(declare mouse-button-pressed? [button MouseButton] bool - "flan_rl_is_mouse_button_pressed") -(declare mouse-button-down? [button MouseButton] bool - "flan_rl_is_mouse_button_down") -(declare mouse-button-released? [button MouseButton] bool - "flan_rl_is_mouse_button_released") +(declare-c mouse-button-pressed? + [button MouseButton] bool + "IsMouseButtonPressed") +(declare-c mouse-button-down? [button MouseButton] bool "IsMouseButtonDown") +(declare-c mouse-button-released? + [button MouseButton] bool + "IsMouseButtonReleased") -(declare get-mouse-position-raw [out (Ptr Vector2)] "flan_rl_get_mouse_position") - -(defn get-mouse-position [] Vector2 - (let [v (Vector2 {})] - (get-mouse-position-raw (addr v)) - v)) +(declare-c get-mouse-position [] Vector2 "GetMousePosition") ;; ── Colours ───────────────────────────────────────────────────────── ;; @@ -78,37 +90,22 @@ ;; reading of the packed 0xRRGGBBAA integer — that is why get-color is a real ;; call and not a reinterpretation. -(declare get-color-raw [hex u32 out (Ptr Color)] "flan_rl_get_color") - -(defn get-color [hex u32] Color - (let [c (Color {})] - (get-color-raw hex (addr c)) - c)) +(declare-c get-color [hex u32] Color "GetColor") (defconst black (Color {:r 0 :g 0 :b 0 :a 255})) (defconst white (Color {:r 255 :g 255 :b 255 :a 255})) ;; ── Drawing ───────────────────────────────────────────────────────── -(declare begin-drawing [] "flan_rl_begin_drawing") -(declare end-drawing [] "flan_rl_end_drawing") -(declare draw-fps [x i32 y i32] "flan_rl_draw_fps") +(declare-c begin-drawing [] "BeginDrawing") +(declare-c end-drawing [] "EndDrawing") +(declare-c draw-fps [x i32 y i32] "DrawFPS") -(declare clear-background-raw [color (Ptr Color)] "flan_rl_clear_background") +(declare-c clear-background [color Color] "ClearBackground") -(defn clear-background [color Color] - ;; The copy is not ceremony: a parameter is not an assignable place - ;; (spec-memory.md), so there is no address to take without one. - (let [c color] - (clear-background-raw (addr c)))) - -(declare draw-rectangle-raw - [x i32 y i32 width i32 height i32 color (Ptr Color)] - "flan_rl_draw_rectangle") - -(defn draw-rectangle [x i32 y i32 width i32 height i32 color Color] - (let [c color] - (draw-rectangle-raw x y width height (addr c)))) +(declare-c draw-rectangle + [x i32 y i32 width i32 height i32 color Color] + "DrawRectangle") ;; ── Shapes texture ────────────────────────────────────────────────── ;; @@ -122,29 +119,15 @@ ;; source's width or height is not positive, so a caller — and the test — ;; should keep clear of those values if it wants its own back. -(declare set-shapes-texture-raw - [texture (Ptr Texture2D) source (Ptr Rectangle)] - "flan_rl_set_shapes_texture") +(declare-c set-shapes-texture + [texture Texture2D source Rectangle] + "SetShapesTexture") -(defn set-shapes-texture [texture Texture2D source Rectangle] - (let [t texture - r source] - (set-shapes-texture-raw (addr t) (addr r)))) +(declare-c get-shapes-texture [] Texture2D "GetShapesTexture") -(declare get-shapes-texture-raw [out (Ptr Texture2D)] "flan_rl_get_shapes_texture") - -(defn get-shapes-texture [] Texture2D - (let [t (Texture2D {})] - (get-shapes-texture-raw (addr t)) - t)) - -(declare get-shapes-texture-rectangle-raw - [out (Ptr Rectangle)] "flan_rl_get_shapes_texture_rectangle") - -(defn get-shapes-texture-rectangle [] Rectangle - (let [r (Rectangle {})] - (get-shapes-texture-rectangle-raw (addr r)) - r)) +(declare-c get-shapes-texture-rectangle + [] Rectangle + "GetShapesTextureRectangle") ;; ── Camera2D ──────────────────────────────────────────────────────── ;; @@ -160,13 +143,9 @@ (defstruct Camera2D [offset Vector2 target Vector2 rotation f32 zoom f32]) -(declare begin-mode-2d-raw [camera (Ptr Camera2D)] "flan_rl_begin_mode_2d") +(declare-c begin-mode-2d [camera Camera2D] "BeginMode2D") -(defn begin-mode-2d [camera Camera2D] - (let [c camera] - (begin-mode-2d-raw (addr c)))) - -(declare end-mode-2d [] "flan_rl_end_mode_2d") +(declare-c end-mode-2d [] "EndMode2D") ;; The two conversions are pure arithmetic over every field of the camera, so ;; unlike the rest of the camera they run with no window and no GL context. @@ -174,27 +153,13 @@ ;; a rotated camera, which is the only call here that mixes x into y — it is ;; also the only thing that pins Vector2's two fields against each other. -(declare get-screen-to-world-2d-raw - [position (Ptr Vector2) camera (Ptr Camera2D) out (Ptr Vector2)] - "flan_rl_get_screen_to_world_2d") +(declare-c get-screen-to-world-2d + [position Vector2 camera Camera2D] Vector2 + "GetScreenToWorld2D") -(defn get-screen-to-world-2d [position Vector2 camera Camera2D] Vector2 - (let [p position - c camera - out (Vector2 {})] - (get-screen-to-world-2d-raw (addr p) (addr c) (addr out)) - out)) - -(declare get-world-to-screen-2d-raw - [position (Ptr Vector2) camera (Ptr Camera2D) out (Ptr Vector2)] - "flan_rl_get_world_to_screen_2d") - -(defn get-world-to-screen-2d [position Vector2 camera Camera2D] Vector2 - (let [p position - c camera - out (Vector2 {})] - (get-world-to-screen-2d-raw (addr p) (addr c) (addr out)) - out)) +(declare-c get-world-to-screen-2d + [position Vector2 camera Camera2D] Vector2 + "GetWorldToScreen2D") ;; ── Shapes ────────────────────────────────────────────────────────── ;; @@ -203,16 +168,9 @@ ;; also how the acceptance table pins the layout: a store-and-return check is ;; symmetric and a permuted layout survives it untouched. -(declare get-collision-rec-raw - [a (Ptr Rectangle) b (Ptr Rectangle) out (Ptr Rectangle)] - "flan_rl_get_collision_rec") - -(defn get-collision-rec [a Rectangle b Rectangle] Rectangle - (let [x a - y b - out (Rectangle {})] - (get-collision-rec-raw (addr x) (addr y) (addr out)) - out)) +(declare-c get-collision-rec + [a Rectangle b Rectangle] Rectangle + "GetCollisionRec") ;; ── Collision ─────────────────────────────────────────────────────── ;; @@ -220,103 +178,75 @@ ;; makes them the other half of what the acceptance table can assert, and the ;; only part of the 2D surface that is tested as thoroughly as it is bound. ;; -;; Each takes its aggregates through pointers for the usual reason, and each -;; wrapper copies its parameters into locals first — a parameter is not an -;; assignable place (spec-memory.md), so there is no address to take. +;; Each is declared exactly as raylib declares it. The pointers and the copies +;; the crossing needs — a parameter is not an assignable place +;; (spec-memory.md), so a struct argument has no address to take without one — +;; are in the generated halves and not here. -(declare collision-recs?-raw [a (Ptr Rectangle) b (Ptr Rectangle)] bool - "flan_rl_check_collision_recs") +(declare-c collision-recs? + [a Rectangle b Rectangle] bool + "CheckCollisionRecs") -(defn collision-recs? [a Rectangle b Rectangle] bool - (let [x a y b] - (collision-recs?-raw (addr x) (addr y)))) +(declare-c collision-circles? + [c1 Vector2 r1 f32 c2 Vector2 r2 f32] bool + "CheckCollisionCircles") -(declare collision-circles?-raw - [c1 (Ptr Vector2) r1 f32 c2 (Ptr Vector2) r2 f32] bool - "flan_rl_check_collision_circles") +(declare-c collision-circle-rec? + [center Vector2 radius f32 rec Rectangle] bool + "CheckCollisionCircleRec") -(defn collision-circles? [c1 Vector2 r1 f32 c2 Vector2 r2 f32] bool - (let [a c1 b c2] - (collision-circles?-raw (addr a) r1 (addr b) r2))) +(declare-c collision-circle-line? [center Vector2 radius f32 + p1 Vector2 p2 Vector2] bool "CheckCollisionCircleLine") -(declare collision-circle-rec?-raw - [center (Ptr Vector2) radius f32 rec (Ptr Rectangle)] bool - "flan_rl_check_collision_circle_rec") +(declare-c collision-point-rec? + [point Vector2 rec Rectangle] bool + "CheckCollisionPointRec") -(defn collision-circle-rec? [center Vector2 radius f32 rec Rectangle] bool - (let [c center r rec] - (collision-circle-rec?-raw (addr c) radius (addr r)))) +(declare-c collision-point-circle? + [point Vector2 center Vector2 radius f32] bool + "CheckCollisionPointCircle") -(declare collision-circle-line?-raw - [center (Ptr Vector2) radius f32 p1 (Ptr Vector2) p2 (Ptr Vector2)] bool - "flan_rl_check_collision_circle_line") - -(defn collision-circle-line? [center Vector2 radius f32 - p1 Vector2 p2 Vector2] bool - (let [c center a p1 b p2] - (collision-circle-line?-raw (addr c) radius (addr a) (addr b)))) - -(declare collision-point-rec?-raw [point (Ptr Vector2) rec (Ptr Rectangle)] bool - "flan_rl_check_collision_point_rec") - -(defn collision-point-rec? [point Vector2 rec Rectangle] bool - (let [p point r rec] - (collision-point-rec?-raw (addr p) (addr r)))) - -(declare collision-point-circle?-raw - [point (Ptr Vector2) center (Ptr Vector2) radius f32] bool - "flan_rl_check_collision_point_circle") - -(defn collision-point-circle? [point Vector2 center Vector2 radius f32] bool - (let [p point c center] - (collision-point-circle?-raw (addr p) (addr c) radius))) - -(declare collision-point-triangle?-raw - [point (Ptr Vector2) a (Ptr Vector2) b (Ptr Vector2) c (Ptr Vector2)] bool - "flan_rl_check_collision_point_triangle") - -(defn collision-point-triangle? [point Vector2 a Vector2 b Vector2 - c Vector2] bool - (let [p point x a y b z c] - (collision-point-triangle?-raw (addr p) (addr x) (addr y) (addr z)))) +(declare-c collision-point-triangle? [point Vector2 a Vector2 b Vector2 + c Vector2] bool "CheckCollisionPointTriangle") ;; `threshold` is in pixels, and it is not optional in practice: raylib's test ;; is a distance comparison in floats, so a point exactly on the line fails at ;; a threshold of 0. 1 is the useful smallest value. -(declare collision-point-line?-raw - [point (Ptr Vector2) p1 (Ptr Vector2) p2 (Ptr Vector2) threshold i32] bool - "flan_rl_check_collision_point_line") +(declare-c collision-point-line? [point Vector2 p1 Vector2 p2 Vector2 + threshold i32] bool "CheckCollisionPointLine") -(defn collision-point-line? [point Vector2 p1 Vector2 p2 Vector2 - threshold i32] bool - (let [p point a p1 b p2] - (collision-point-line?-raw (addr p) (addr a) (addr b) threshold))) - -;; A slice crosses as ptr+len, which is exactly what raylib wants here, so -;; this is the one collision call that needs no per-element copying. The -;; polygon is not closed explicitly — raylib joins the last point to the -;; first. -(declare collision-point-poly?-raw [point (Ptr Vector2) points [Vector2]] bool - "flan_rl_check_collision_point_poly") +;; The one binding whose Flan face is not raylib's, and one of only two in +;; this file with a hand-written wrapper on top. A Flan slice crosses as +;; ptr+len with an i64 length; raylib wants a pointer and an `int` count, and +;; the generator refuses to guess what integer type a C count parameter is — +;; so the declaration says (Ptr Vector2) and a count, and the wrapper takes +;; the slice apart. The polygon is not closed explicitly; raylib joins the +;; last point to the first. +;; +;; Empty is answered here rather than passed on: (at points 0) would be an +;; out-of-bounds read, and raylib answers false for a polygon with no points +;; anyway. +(declare-c collision-point-poly?-raw + [point Vector2 points (Ptr Vector2) count i32] bool + "CheckCollisionPointPoly") (defn collision-point-poly? [point Vector2 points [Vector2]] bool - (let [p point] - (collision-point-poly?-raw (addr p) points))) + (if (= (len points) 0) + false + (collision-point-poly?-raw point (addr (at points 0)) (len points)))) ;; The one that answers with more than yes or no: where the two segments meet. ;; None is "they do not", so the point cannot be read when there isn't one — ;; raylib's own signature leaves the out-parameter untouched in that case and ;; a caller that forgets reads whatever was there. -(declare collision-lines-raw - [a1 (Ptr Vector2) a2 (Ptr Vector2) b1 (Ptr Vector2) b2 (Ptr Vector2) - out (Ptr Vector2)] bool - "flan_rl_check_collision_lines") +(declare-c collision-lines-raw + [a1 Vector2 a2 Vector2 b1 Vector2 b2 Vector2 out (Ptr Vector2)] bool + "CheckCollisionLines") (defn collision-lines [a1 Vector2 a2 Vector2 b1 Vector2 b2 Vector2] (Option Vector2) - (let [p a1 q a2 r b1 s b2 - out (Vector2 {})] - (if (collision-lines-raw (addr p) (addr q) (addr r) (addr s) (addr out)) + (let [out (Vector2 {})] + (if (collision-lines-raw a1 a2 b1 b2 (addr out)) (Some out) None))) @@ -328,70 +258,27 @@ ;; only in the log; raylib 5.5 spells it IsTextureValid, and IsTextureReady, ;; which older code calls, does not exist in this version. -(declare load-texture-raw [path string out (Ptr Texture2D)] "flan_rl_load_texture") +(declare-c load-texture [path string] Texture2D "LoadTexture") -(defn load-texture [path string] Texture2D - (let [t (Texture2D {})] - (load-texture-raw path (addr t)) - t)) +(declare-c texture-valid? [texture Texture2D] bool "IsTextureValid") -(declare texture-valid?-raw [texture (Ptr Texture2D)] bool "flan_rl_is_texture_valid") +(declare-c unload-texture [texture Texture2D] "UnloadTexture") -(defn texture-valid? [texture Texture2D] bool - (let [t texture] - (texture-valid?-raw (addr t)))) +(declare-c draw-texture + [texture Texture2D x i32 y i32 tint Color] + "DrawTexture") -(declare unload-texture-raw [texture (Ptr Texture2D)] "flan_rl_unload_texture") +(declare-c draw-texture-v + [texture Texture2D position Vector2 tint Color] + "DrawTextureV") -(defn unload-texture [texture Texture2D] - (let [t texture] - (unload-texture-raw (addr t)))) - -(declare draw-texture-raw - [texture (Ptr Texture2D) x i32 y i32 tint (Ptr Color)] - "flan_rl_draw_texture") - -(defn draw-texture [texture Texture2D x i32 y i32 tint Color] - (let [t texture - c tint] - (draw-texture-raw (addr t) x y (addr c)))) - -(declare draw-texture-v-raw - [texture (Ptr Texture2D) position (Ptr Vector2) tint (Ptr Color)] - "flan_rl_draw_texture_v") - -(defn draw-texture-v [texture Texture2D position Vector2 tint Color] - (let [t texture - p position - c tint] - (draw-texture-v-raw (addr t) (addr p) (addr c)))) - -(declare draw-texture-ex-raw - [texture (Ptr Texture2D) position (Ptr Vector2) rotation f32 scale f32 - tint (Ptr Color)] - "flan_rl_draw_texture_ex") - -(defn draw-texture-ex [texture Texture2D position Vector2 rotation f32 - scale f32 tint Color] - (let [t texture - p position - c tint] - (draw-texture-ex-raw (addr t) (addr p) rotation scale (addr c)))) +(declare-c draw-texture-ex [texture Texture2D position Vector2 rotation f32 + scale f32 tint Color] "DrawTextureEx") ;; A negative source width or height flips the sprite, which is how a sheet is ;; drawn facing the other way without a second image. -(declare draw-texture-rec-raw - [texture (Ptr Texture2D) source (Ptr Rectangle) position (Ptr Vector2) - tint (Ptr Color)] - "flan_rl_draw_texture_rec") - -(defn draw-texture-rec [texture Texture2D source Rectangle position Vector2 - tint Color] - (let [t texture - s source - p position - c tint] - (draw-texture-rec-raw (addr t) (addr s) (addr p) (addr c)))) +(declare-c draw-texture-rec [texture Texture2D source Rectangle position Vector2 + tint Color] "DrawTextureRec") ;; ── Images ────────────────────────────────────────────────────────── ;; @@ -410,101 +297,55 @@ ;; level too, so a caller can see which ones change what they are given. (defstruct Image [data (Ptr u8) width i32 height i32 mipmaps i32 format i32]) -(declare load-image-raw [path string out (Ptr Image)] "flan_rl_load_image") - -(defn load-image [path string] Image - (let [i (Image {})] - (load-image-raw path (addr i)) - i)) +(declare-c load-image [path string] Image "LoadImage") ;; raylib 5.5 spells this IsImageValid. IsImageReady, which older code calls, ;; does not exist here — the same rename that took IsTextureReady. -(declare image-valid?-raw [image (Ptr Image)] bool "flan_rl_is_image_valid") - -(defn image-valid? [image Image] bool - (let [i image] - (image-valid?-raw (addr i)))) +(declare-c image-valid? [image Image] bool "IsImageValid") ;; By value, as raylib has it. The caller's copy is dangling afterwards — ;; `data` pointed at the buffer this just freed — so an Image is used or ;; unloaded, never both. -(declare unload-image-raw [image (Ptr Image)] "flan_rl_unload_image") - -(defn unload-image [image Image] - (let [i image] - (unload-image-raw (addr i)))) +(declare-c unload-image [image Image] "UnloadImage") ;; The format is taken from the path's extension, so ".png" writes a PNG. ;; False means it could not be written. -(declare export-image-raw [image (Ptr Image) path string] bool - "flan_rl_export_image") +(declare-c export-image [image Image path string] bool "ExportImage") -(defn export-image [image Image path string] bool - (let [i image] - (export-image-raw (addr i) path))) - -(declare gen-image-color-raw - [width i32 height i32 color (Ptr Color) out (Ptr Image)] - "flan_rl_gen_image_color") - -(defn gen-image-color [width i32 height i32 color Color] Image - (let [c color - i (Image {})] - (gen-image-color-raw width height (addr c) (addr i)) - i)) +(declare-c gen-image-color + [width i32 height i32 color Color] Image + "GenImageColor") ;; Bicubic, so the pixels that come out are interpolated and only the new ;; width and height are exactly predictable. image-resize-nn is the ;; nearest-neighbour one, and it is the one to reach for when the colours ;; have to survive. -(declare image-resize [image (Ptr Image) width i32 height i32] - "flan_rl_image_resize") -(declare image-resize-nn [image (Ptr Image) width i32 height i32] - "flan_rl_image_resize_nn") +(declare-c image-resize + [image (Ptr Image) width i32 height i32] + "ImageResize") +(declare-c image-resize-nn + [image (Ptr Image) width i32 height i32] + "ImageResizeNN") -(declare image-crop-raw [image (Ptr Image) crop (Ptr Rectangle)] - "flan_rl_image_crop") +(declare-c image-crop [image (Ptr Image) crop Rectangle] "ImageCrop") -(defn image-crop [image (Ptr Image) crop Rectangle] - (let [r crop] - (image-crop-raw image (addr r)))) +(declare-c image-flip-horizontal [image (Ptr Image)] "ImageFlipHorizontal") +(declare-c image-flip-vertical [image (Ptr Image)] "ImageFlipVertical") -(declare image-flip-horizontal [image (Ptr Image)] - "flan_rl_image_flip_horizontal") -(declare image-flip-vertical [image (Ptr Image)] - "flan_rl_image_flip_vertical") - -(declare image-draw-pixel-raw - [image (Ptr Image) x i32 y i32 color (Ptr Color)] - "flan_rl_image_draw_pixel") - -(defn image-draw-pixel [image (Ptr Image) x i32 y i32 color Color] - (let [c color] - (image-draw-pixel-raw image x y (addr c)))) +(declare-c image-draw-pixel + [image (Ptr Image) x i32 y i32 color Color] + "ImageDrawPixel") ;; Out of bounds is not an error: raylib logs a warning and hands back a ;; transparent black, so a caller that is off by one gets zeroes rather than ;; somebody else's memory. -(declare get-image-color-raw - [image (Ptr Image) x i32 y i32 out (Ptr Color)] - "flan_rl_get_image_color") - -(defn get-image-color [image Image x i32 y i32] Color - (let [i image - c (Color {})] - (get-image-color-raw (addr i) x y (addr c)) - c)) +(declare-c get-image-color [image Image x i32 y i32] Color "GetImageColor") ;; The one call in this section that does need a GL context — it uploads. An ;; image loaded and edited on the CPU becomes something draw-texture can use. -(declare load-texture-from-image-raw [image (Ptr Image) out (Ptr Texture2D)] - "flan_rl_load_texture_from_image") - -(defn load-texture-from-image [image Image] Texture2D - (let [i image - t (Texture2D {})] - (load-texture-from-image-raw (addr i) (addr t)) - t)) +(declare-c load-texture-from-image + [image Image] Texture2D + "LoadTextureFromImage") ;; ── Shapes ────────────────────────────────────────────────────────── ;; @@ -522,185 +363,92 @@ ;; and draws nonsense, so this was read off the library with nm rather than ;; remembered. -(declare draw-pixel-raw [x i32 y i32 color (Ptr Color)] "flan_rl_draw_pixel") +(declare-c draw-pixel [x i32 y i32 color Color] "DrawPixel") -(defn draw-pixel [x i32 y i32 color Color] - (let [c color] (draw-pixel-raw x y (addr c)))) +(declare-c draw-pixel-v [position Vector2 color Color] "DrawPixelV") -(declare draw-pixel-v-raw [position (Ptr Vector2) color (Ptr Color)] - "flan_rl_draw_pixel_v") +(declare-c draw-line [x1 i32 y1 i32 x2 i32 y2 i32 color Color] "DrawLine") -(defn draw-pixel-v [position Vector2 color Color] - (let [p position c color] (draw-pixel-v-raw (addr p) (addr c)))) - -(declare draw-line-raw [x1 i32 y1 i32 x2 i32 y2 i32 color (Ptr Color)] - "flan_rl_draw_line") - -(defn draw-line [x1 i32 y1 i32 x2 i32 y2 i32 color Color] - (let [c color] (draw-line-raw x1 y1 x2 y2 (addr c)))) - -(declare draw-line-v-raw - [start (Ptr Vector2) end (Ptr Vector2) color (Ptr Color)] - "flan_rl_draw_line_v") - -(defn draw-line-v [start Vector2 end Vector2 color Color] - (let [a start b end c color] (draw-line-v-raw (addr a) (addr b) (addr c)))) +(declare-c draw-line-v [start Vector2 end Vector2 color Color] "DrawLineV") ;; The thick one is built from triangles rather than GL lines, which is why it ;; is a separate call and not a parameter on the one above. -(declare draw-line-ex-raw - [start (Ptr Vector2) end (Ptr Vector2) thick f32 color (Ptr Color)] - "flan_rl_draw_line_ex") +(declare-c draw-line-ex + [start Vector2 end Vector2 thick f32 color Color] + "DrawLineEx") -(defn draw-line-ex [start Vector2 end Vector2 thick f32 color Color] - (let [a start b end c color] - (draw-line-ex-raw (addr a) (addr b) thick (addr c)))) +(declare-c draw-circle [x i32 y i32 radius f32 color Color] "DrawCircle") -(declare draw-circle-raw [x i32 y i32 radius f32 color (Ptr Color)] - "flan_rl_draw_circle") +(declare-c draw-circle-v + [center Vector2 radius f32 color Color] + "DrawCircleV") -(defn draw-circle [x i32 y i32 radius f32 color Color] - (let [c color] (draw-circle-raw x y radius (addr c)))) +(declare-c draw-circle-lines + [x i32 y i32 radius f32 color Color] + "DrawCircleLines") -(declare draw-circle-v-raw - [center (Ptr Vector2) radius f32 color (Ptr Color)] "flan_rl_draw_circle_v") - -(defn draw-circle-v [center Vector2 radius f32 color Color] - (let [p center c color] (draw-circle-v-raw (addr p) radius (addr c)))) - -(declare draw-circle-lines-raw [x i32 y i32 radius f32 color (Ptr Color)] - "flan_rl_draw_circle_lines") - -(defn draw-circle-lines [x i32 y i32 radius f32 color Color] - (let [c color] (draw-circle-lines-raw x y radius (addr c)))) - -(declare draw-circle-lines-v-raw - [center (Ptr Vector2) radius f32 color (Ptr Color)] - "flan_rl_draw_circle_lines_v") - -(defn draw-circle-lines-v [center Vector2 radius f32 color Color] - (let [p center c color] (draw-circle-lines-v-raw (addr p) radius (addr c)))) +(declare-c draw-circle-lines-v + [center Vector2 radius f32 color Color] + "DrawCircleLinesV") ;; Two radii, horizontal then vertical. Equal radii is a circle, so a wrapper ;; that exchanged them would be invisible unless they differ — which is why ;; sand.flan's ellipse is deliberately wider than it is tall. -(declare draw-ellipse-raw - [x i32 y i32 radius-h f32 radius-v f32 color (Ptr Color)] - "flan_rl_draw_ellipse") +(declare-c draw-ellipse + [x i32 y i32 radius-h f32 radius-v f32 color Color] + "DrawEllipse") -(defn draw-ellipse [x i32 y i32 radius-h f32 radius-v f32 color Color] - (let [c color] (draw-ellipse-raw x y radius-h radius-v (addr c)))) - -(declare draw-ellipse-lines-raw - [x i32 y i32 radius-h f32 radius-v f32 color (Ptr Color)] - "flan_rl_draw_ellipse_lines") - -(defn draw-ellipse-lines [x i32 y i32 radius-h f32 radius-v f32 color Color] - (let [c color] (draw-ellipse-lines-raw x y radius-h radius-v (addr c)))) +(declare-c draw-ellipse-lines + [x i32 y i32 radius-h f32 radius-v f32 color Color] + "DrawEllipseLines") ;; Angles are degrees, clockwise from the +x axis, and `segments` is how many ;; straight pieces the arc is made of — 0 lets raylib pick from the radius. -(declare draw-ring-raw - [center (Ptr Vector2) inner f32 outer f32 start f32 end f32 - segments i32 color (Ptr Color)] - "flan_rl_draw_ring") +(declare-c draw-ring [center Vector2 inner f32 outer f32 start f32 end f32 + segments i32 color Color] "DrawRing") -(defn draw-ring [center Vector2 inner f32 outer f32 start f32 end f32 - segments i32 color Color] - (let [p center c color] - (draw-ring-raw (addr p) inner outer start end segments (addr c)))) - -(declare draw-ring-lines-raw - [center (Ptr Vector2) inner f32 outer f32 start f32 end f32 - segments i32 color (Ptr Color)] - "flan_rl_draw_ring_lines") - -(defn draw-ring-lines [center Vector2 inner f32 outer f32 start f32 end f32 - segments i32 color Color] - (let [p center c color] - (draw-ring-lines-raw (addr p) inner outer start end segments (addr c)))) +(declare-c draw-ring-lines [center Vector2 inner f32 outer f32 start f32 end f32 + segments i32 color Color] "DrawRingLines") ;; Counter-clockwise, and raylib means it: the clockwise winding is culled and ;; draws nothing at all, which looks exactly like a broken binding. -(declare draw-triangle-raw - [v1 (Ptr Vector2) v2 (Ptr Vector2) v3 (Ptr Vector2) color (Ptr Color)] - "flan_rl_draw_triangle") +(declare-c draw-triangle + [v1 Vector2 v2 Vector2 v3 Vector2 color Color] + "DrawTriangle") -(defn draw-triangle [v1 Vector2 v2 Vector2 v3 Vector2 color Color] - (let [a v1 b v2 d v3 c color] - (draw-triangle-raw (addr a) (addr b) (addr d) (addr c)))) +(declare-c draw-triangle-lines + [v1 Vector2 v2 Vector2 v3 Vector2 color Color] + "DrawTriangleLines") -(declare draw-triangle-lines-raw - [v1 (Ptr Vector2) v2 (Ptr Vector2) v3 (Ptr Vector2) color (Ptr Color)] - "flan_rl_draw_triangle_lines") +(declare-c draw-rectangle-v + [position Vector2 size Vector2 color Color] + "DrawRectangleV") -(defn draw-triangle-lines [v1 Vector2 v2 Vector2 v3 Vector2 color Color] - (let [a v1 b v2 d v3 c color] - (draw-triangle-lines-raw (addr a) (addr b) (addr d) (addr c)))) +(declare-c draw-rectangle-rec [rec Rectangle color Color] "DrawRectangleRec") -(declare draw-rectangle-v-raw - [position (Ptr Vector2) size (Ptr Vector2) color (Ptr Color)] - "flan_rl_draw_rectangle_v") - -(defn draw-rectangle-v [position Vector2 size Vector2 color Color] - (let [p position s size c color] - (draw-rectangle-v-raw (addr p) (addr s) (addr c)))) - -(declare draw-rectangle-rec-raw [rec (Ptr Rectangle) color (Ptr Color)] - "flan_rl_draw_rectangle_rec") - -(defn draw-rectangle-rec [rec Rectangle color Color] - (let [r rec c color] (draw-rectangle-rec-raw (addr r) (addr c)))) - -(declare draw-rectangle-lines-raw - [x i32 y i32 width i32 height i32 color (Ptr Color)] - "flan_rl_draw_rectangle_lines") - -(defn draw-rectangle-lines [x i32 y i32 width i32 height i32 color Color] - (let [c color] (draw-rectangle-lines-raw x y width height (addr c)))) +(declare-c draw-rectangle-lines + [x i32 y i32 width i32 height i32 color Color] + "DrawRectangleLines") ;; The one-pixel outline above is drawn with GL lines and sits *on* the ;; rectangle's edge; this one is drawn with quads and sits inside it, so the ;; two do not agree at thickness 1 and that is raylib's doing, not a bug here. -(declare draw-rectangle-lines-ex-raw - [rec (Ptr Rectangle) thick f32 color (Ptr Color)] - "flan_rl_draw_rectangle_lines_ex") - -(defn draw-rectangle-lines-ex [rec Rectangle thick f32 color Color] - (let [r rec c color] (draw-rectangle-lines-ex-raw (addr r) thick (addr c)))) +(declare-c draw-rectangle-lines-ex + [rec Rectangle thick f32 color Color] + "DrawRectangleLinesEx") ;; `roundness` is 0 to 1 as a fraction of the shorter side, so 0 is a plain ;; rectangle and 1 is a stadium. -(declare draw-rectangle-rounded-raw - [rec (Ptr Rectangle) roundness f32 segments i32 color (Ptr Color)] - "flan_rl_draw_rectangle_rounded") - -(defn draw-rectangle-rounded [rec Rectangle roundness f32 segments i32 - color Color] - (let [r rec c color] - (draw-rectangle-rounded-raw (addr r) roundness segments (addr c)))) +(declare-c draw-rectangle-rounded [rec Rectangle roundness f32 segments i32 + color Color] "DrawRectangleRounded") ;; No thickness here — see the section note. The `-ex` form below is the one ;; that takes it. -(declare draw-rectangle-rounded-lines-raw - [rec (Ptr Rectangle) roundness f32 segments i32 color (Ptr Color)] - "flan_rl_draw_rectangle_rounded_lines") +(declare-c draw-rectangle-rounded-lines [rec Rectangle roundness f32 segments i32 + color Color] "DrawRectangleRoundedLines") -(defn draw-rectangle-rounded-lines [rec Rectangle roundness f32 segments i32 - color Color] - (let [r rec c color] - (draw-rectangle-rounded-lines-raw (addr r) roundness segments (addr c)))) - -(declare draw-rectangle-rounded-lines-ex-raw - [rec (Ptr Rectangle) roundness f32 segments i32 thick f32 - color (Ptr Color)] - "flan_rl_draw_rectangle_rounded_lines_ex") - -(defn draw-rectangle-rounded-lines-ex [rec Rectangle roundness f32 - segments i32 thick f32 color Color] - (let [r rec c color] - (draw-rectangle-rounded-lines-ex-raw (addr r) roundness segments thick - (addr c)))) +(declare-c draw-rectangle-rounded-lines-ex [rec Rectangle roundness f32 + segments i32 thick f32 color Color] "DrawRectangleRoundedLinesEx") ;; ── Text ──────────────────────────────────────────────────────────── ;; @@ -718,14 +466,11 @@ ;; load-font, load-font-ex, unload-font, get-font-default, draw-text-ex and ;; measure-text-ex are all absent rather than half-done. -(declare draw-text-raw - [text string x i32 y i32 font-size i32 color (Ptr Color)] - "flan_rl_draw_text") +(declare-c draw-text + [text string x i32 y i32 font-size i32 color Color] + "DrawText") -(defn draw-text [text string x i32 y i32 font-size i32 color Color] - (let [c color] (draw-text-raw text x y font-size (addr c)))) - -(declare measure-text [text string font-size i32] i32 "flan_rl_measure_text") +(declare-c measure-text [text string font-size i32] i32 "MeasureText") ;; ── Timing and window state ───────────────────────────────────────── ;; @@ -734,7 +479,7 @@ ;; delta the last frame took, in seconds, which is what a simulation should ;; scale by instead of assuming the target fps was met. -(declare get-frame-time [] f32 "flan_rl_get_frame_time") -(declare get-time [] f64 "flan_rl_get_time") -(declare get-screen-width [] i32 "flan_rl_get_screen_width") -(declare get-screen-height [] i32 "flan_rl_get_screen_height") +(declare-c get-frame-time [] f32 "GetFrameTime") +(declare-c get-time [] f64 "GetTime") +(declare-c get-screen-width [] i32 "GetScreenWidth") +(declare-c get-screen-height [] i32 "GetScreenHeight") diff --git a/vendor/raylib/shim.c b/vendor/raylib/shim.c deleted file mode 100644 index b9f9e1e..0000000 --- a/vendor/raylib/shim.c +++ /dev/null @@ -1,476 +0,0 @@ -/* The C half of the raylib binding: one wrapper per `declare` in raylib.flan. - * - * The wrappers exist so that no aggregate is ever passed or returned across - * the Flan/C boundary. raylib takes Color by value and returns Vector2 by - * value, and a small aggregate is passed differently on x86-64 (<2 x float>, - * i32), on arm64, and on wasm32. Here, clang classifies each one correctly for - * whichever target the build is for; in the Flan backend it would be three - * conventions to reimplement. Everything below therefore trades in scalars and - * pointers only — see raylib.flan. - * - * raylib's own headers are not needed and not used: these prototypes are the - * declarations, so the build has no dependency on raylib-devel being - * installed, only on the shared library being linkable. - */ - -#include -#include -#include -#include - -typedef struct { float x, y; } Vector2; -typedef struct { unsigned char r, g, b, a; } Color; -typedef struct { unsigned int id; int width, height, mipmaps, format; } Texture2D; -typedef struct { float x, y, width, height; } Rectangle; -typedef struct { Vector2 offset, target; float rotation, zoom; } Camera2D; - -extern void InitWindow(int width, int height, const char *title); -extern void CloseWindow(void); -extern bool WindowShouldClose(void); -extern void SetTargetFPS(int fps); -extern void SetTraceLogLevel(int level); -extern bool IsKeyPressed(int key); -extern bool IsKeyDown(int key); -extern bool IsKeyReleased(int key); -extern bool IsMouseButtonPressed(int button); -extern bool IsMouseButtonDown(int button); -extern bool IsMouseButtonReleased(int button); -extern Vector2 GetMousePosition(void); -extern Color GetColor(unsigned int hex); -extern void BeginDrawing(void); -extern void EndDrawing(void); -extern void DrawFPS(int x, int y); -extern void ClearBackground(Color color); -extern void DrawRectangle(int x, int y, int width, int height, Color color); -extern void SetShapesTexture(Texture2D texture, Rectangle source); -extern Texture2D GetShapesTexture(void); -extern Rectangle GetShapesTextureRectangle(void); -extern Rectangle GetCollisionRec(Rectangle a, Rectangle b); -extern Texture2D LoadTexture(const char *fileName); -extern bool IsTextureValid(Texture2D texture); -extern void UnloadTexture(Texture2D texture); -extern void DrawTexture(Texture2D texture, int posX, int posY, Color tint); -extern void DrawTextureV(Texture2D texture, Vector2 position, Color tint); -extern void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, - float scale, Color tint); -extern void DrawTextureRec(Texture2D texture, Rectangle source, - Vector2 position, Color tint); -extern void BeginMode2D(Camera2D camera); -extern void EndMode2D(void); -extern Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); -extern Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); -extern bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); -extern bool CheckCollisionCircles(Vector2 c1, float r1, Vector2 c2, float r2); -extern bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); -extern bool CheckCollisionCircleLine(Vector2 center, float radius, - Vector2 p1, Vector2 p2); -extern bool CheckCollisionPointRec(Vector2 point, Rectangle rec); -extern bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); -extern bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, - Vector2 p3); -extern bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, - int threshold); -extern bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, - int pointCount); -extern bool CheckCollisionLines(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, - Vector2 *collisionPoint); - -/* A Flan string arrives as ptr+len and is not NUL-terminated, so a C API that - * wants a C string needs a copy. Two callers want one: the window title and a - * texture's file path. Each passes a buffer big enough for what it is — 256 - * for a title, PATH_MAX for a path — and truncating is better than reading - * past the end. A truncated path fails to open and LoadTexture returns an id - * of 0, which is what texture-valid? is for. */ -static const char *cstr(const char *p, long long n, char *buf, size_t cap) { - size_t k = (size_t)n < cap - 1 ? (size_t)n : cap - 1; - memcpy(buf, p, k); - buf[k] = '\0'; - return buf; -} - -void flan_rl_init_window(int width, int height, const char *title, long long n) { - char buf[256]; - InitWindow(width, height, cstr(title, n, buf, sizeof buf)); -} - -void flan_rl_close_window(void) { CloseWindow(); } -bool flan_rl_window_should_close(void) { return WindowShouldClose(); } -void flan_rl_set_target_fps(int fps) { SetTargetFPS(fps); } -void flan_rl_set_trace_log_level(int l) { SetTraceLogLevel(l); } - -bool flan_rl_is_key_pressed(int key) { return IsKeyPressed(key); } -bool flan_rl_is_key_down(int key) { return IsKeyDown(key); } -bool flan_rl_is_key_released(int key) { return IsKeyReleased(key); } - -bool flan_rl_is_mouse_button_pressed(int b) { return IsMouseButtonPressed(b); } -bool flan_rl_is_mouse_button_down(int b) { return IsMouseButtonDown(b); } -bool flan_rl_is_mouse_button_released(int b) { return IsMouseButtonReleased(b); } - -void flan_rl_get_mouse_position(Vector2 *out) { *out = GetMousePosition(); } - -void flan_rl_get_color(unsigned int hex, Color *out) { *out = GetColor(hex); } - -void flan_rl_begin_drawing(void) { BeginDrawing(); } -void flan_rl_end_drawing(void) { EndDrawing(); } -void flan_rl_draw_fps(int x, int y) { DrawFPS(x, y); } - -void flan_rl_clear_background(const Color *color) { ClearBackground(*color); } - -void flan_rl_draw_rectangle(int x, int y, int width, int height, - const Color *color) { - DrawRectangle(x, y, width, height, *color); -} - -void flan_rl_set_shapes_texture(const Texture2D *texture, const Rectangle *source) { - SetShapesTexture(*texture, *source); -} - -void flan_rl_get_shapes_texture(Texture2D *out) { *out = GetShapesTexture(); } - -void flan_rl_get_shapes_texture_rectangle(Rectangle *out) { - *out = GetShapesTextureRectangle(); -} - -void flan_rl_get_collision_rec(const Rectangle *a, const Rectangle *b, - Rectangle *out) { - *out = GetCollisionRec(*a, *b); -} - -void flan_rl_load_texture(const char *path, long long n, Texture2D *out) { - char buf[PATH_MAX]; - *out = LoadTexture(cstr(path, n, buf, sizeof buf)); -} - -bool flan_rl_is_texture_valid(const Texture2D *texture) { - return IsTextureValid(*texture); -} - -void flan_rl_unload_texture(const Texture2D *texture) { UnloadTexture(*texture); } - -void flan_rl_draw_texture(const Texture2D *texture, int x, int y, - const Color *tint) { - DrawTexture(*texture, x, y, *tint); -} - -void flan_rl_draw_texture_v(const Texture2D *texture, const Vector2 *position, - const Color *tint) { - DrawTextureV(*texture, *position, *tint); -} - -void flan_rl_draw_texture_ex(const Texture2D *texture, const Vector2 *position, - float rotation, float scale, const Color *tint) { - DrawTextureEx(*texture, *position, rotation, scale, *tint); -} - -void flan_rl_draw_texture_rec(const Texture2D *texture, const Rectangle *source, - const Vector2 *position, const Color *tint) { - DrawTextureRec(*texture, *source, *position, *tint); -} - -void flan_rl_begin_mode_2d(const Camera2D *camera) { BeginMode2D(*camera); } -void flan_rl_end_mode_2d(void) { EndMode2D(); } - -void flan_rl_get_screen_to_world_2d(const Vector2 *position, - const Camera2D *camera, Vector2 *out) { - *out = GetScreenToWorld2D(*position, *camera); -} - -void flan_rl_get_world_to_screen_2d(const Vector2 *position, - const Camera2D *camera, Vector2 *out) { - *out = GetWorldToScreen2D(*position, *camera); -} - -bool flan_rl_check_collision_recs(const Rectangle *a, const Rectangle *b) { - return CheckCollisionRecs(*a, *b); -} - -bool flan_rl_check_collision_circles(const Vector2 *c1, float r1, - const Vector2 *c2, float r2) { - return CheckCollisionCircles(*c1, r1, *c2, r2); -} - -bool flan_rl_check_collision_circle_rec(const Vector2 *center, float radius, - const Rectangle *rec) { - return CheckCollisionCircleRec(*center, radius, *rec); -} - -bool flan_rl_check_collision_circle_line(const Vector2 *center, float radius, - const Vector2 *p1, const Vector2 *p2) { - return CheckCollisionCircleLine(*center, radius, *p1, *p2); -} - -bool flan_rl_check_collision_point_rec(const Vector2 *point, const Rectangle *rec) { - return CheckCollisionPointRec(*point, *rec); -} - -bool flan_rl_check_collision_point_circle(const Vector2 *point, - const Vector2 *center, float radius) { - return CheckCollisionPointCircle(*point, *center, radius); -} - -bool flan_rl_check_collision_point_triangle(const Vector2 *point, const Vector2 *a, - const Vector2 *b, const Vector2 *c) { - return CheckCollisionPointTriangle(*point, *a, *b, *c); -} - -bool flan_rl_check_collision_point_line(const Vector2 *point, const Vector2 *p1, - const Vector2 *p2, int threshold) { - return CheckCollisionPointLine(*point, *p1, *p2, threshold); -} - -/* A Flan slice arrives as ptr+len, the same shape a string does. raylib wants - * an int count, and a polygon with more than INT_MAX points is not a thing - * that happens; the clamp is there so the conversion is not silent. */ -bool flan_rl_check_collision_point_poly(const Vector2 *point, - const Vector2 *points, long long n) { - if (n > INT_MAX) n = INT_MAX; - return CheckCollisionPointPoly(*point, points, (int)n); -} - -bool flan_rl_check_collision_lines(const Vector2 *a1, const Vector2 *a2, - const Vector2 *b1, const Vector2 *b2, - Vector2 *out) { - return CheckCollisionLines(*a1, *a2, *b1, *b2, out); -} - -/* ── Images ───────────────────────────────────────────────────────── - * - * An Image is pixels in RAM, so all of this runs with no window and no GL - * context — which is why it is the part of the package that a headless test - * can actually assert rather than merely link. `data` is the pixel buffer - * raylib owns; `format` is a PixelFormat enum and GenImageColor makes 7 - * (uncompressed R8G8B8A8). - * - * raylib 5.5 spells the predicate IsImageValid. IsImageReady, which the 5.1 - * header still had, is gone — checked with nm -D, not remembered. - */ -typedef struct { void *data; int width, height, mipmaps, format; } Image; - -extern Image LoadImage(const char *fileName); -extern bool IsImageValid(Image image); -extern void UnloadImage(Image image); -extern bool ExportImage(Image image, const char *fileName); -extern Image GenImageColor(int width, int height, Color color); -extern void ImageResize(Image *image, int newWidth, int newHeight); -extern void ImageResizeNN(Image *image, int newWidth, int newHeight); -extern void ImageCrop(Image *image, Rectangle crop); -extern void ImageFlipHorizontal(Image *image); -extern void ImageFlipVertical(Image *image); -extern void ImageDrawPixel(Image *dst, int posX, int posY, Color color); -extern Color GetImageColor(Image image, int x, int y); -extern Texture2D LoadTextureFromImage(Image image); - -void flan_rl_load_image(const char *path, long long n, Image *out) { - char buf[PATH_MAX]; - *out = LoadImage(cstr(path, n, buf, sizeof buf)); -} - -bool flan_rl_is_image_valid(const Image *image) { return IsImageValid(*image); } -void flan_rl_unload_image(const Image *image) { UnloadImage(*image); } - -bool flan_rl_export_image(const Image *image, const char *path, long long n) { - char buf[PATH_MAX]; - return ExportImage(*image, cstr(path, n, buf, sizeof buf)); -} - -void flan_rl_gen_image_color(int width, int height, const Color *color, - Image *out) { - *out = GenImageColor(width, height, *color); -} - -void flan_rl_image_resize(Image *image, int w, int h) { ImageResize(image, w, h); } -void flan_rl_image_resize_nn(Image *image, int w, int h) { ImageResizeNN(image, w, h); } - -void flan_rl_image_crop(Image *image, const Rectangle *crop) { - ImageCrop(image, *crop); -} - -void flan_rl_image_flip_horizontal(Image *image) { ImageFlipHorizontal(image); } -void flan_rl_image_flip_vertical(Image *image) { ImageFlipVertical(image); } - -void flan_rl_image_draw_pixel(Image *dst, int x, int y, const Color *color) { - ImageDrawPixel(dst, x, y, *color); -} - -void flan_rl_get_image_color(const Image *image, int x, int y, Color *out) { - *out = GetImageColor(*image, x, y); -} - -void flan_rl_load_texture_from_image(const Image *image, Texture2D *out) { - *out = LoadTextureFromImage(*image); -} - -/* ── Shapes, text and timing ───────────────────────────────────────── - * - * All of the drawing below needs a GL context and therefore a window, so none - * of it can be in the acceptance table — it is exercised by running sand.flan - * and looking. The three prototypes most likely to be remembered wrong were - * checked against nm -D on libraylib.so.550 rather than against a header: - * raylib 5.5 moved the line thickness off DrawRectangleRoundedLines onto - * DrawRectangleRoundedLinesEx, so the four-argument form here is the 5.5 one - * and not the 5.1 one. - * - * MeasureText, GetFrameTime, GetTime and GetScreenWidth/Height need no GL - * context but do need InitWindow: the first reads the default font, which - * only InitWindow loads, and the others read window state. Headless they all - * answer 0 — measured, not assumed — so they are no more assertable than the - * drawing is. - */ - -extern void DrawPixel(int posX, int posY, Color color); -extern void DrawPixelV(Vector2 position, Color color); -extern void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, - Color color); -extern void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); -extern void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); -extern void DrawCircle(int centerX, int centerY, float radius, Color color); -extern void DrawCircleV(Vector2 center, float radius, Color color); -extern void DrawCircleLines(int centerX, int centerY, float radius, Color color); -extern void DrawCircleLinesV(Vector2 center, float radius, Color color); -extern void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, - Color color); -extern void DrawEllipseLines(int centerX, int centerY, float radiusH, - float radiusV, Color color); -extern void DrawRing(Vector2 center, float innerRadius, float outerRadius, - float startAngle, float endAngle, int segments, Color color); -extern void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, - float startAngle, float endAngle, int segments, - Color color); -extern void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); -extern void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); -extern void DrawRectangleV(Vector2 position, Vector2 size, Color color); -extern void DrawRectangleRec(Rectangle rec, Color color); -extern void DrawRectangleLines(int posX, int posY, int width, int height, - Color color); -extern void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); -extern void DrawRectangleRounded(Rectangle rec, float roundness, int segments, - Color color); -extern void DrawRectangleRoundedLines(Rectangle rec, float roundness, - int segments, Color color); -extern void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, - int segments, float lineThick, - Color color); -extern void DrawText(const char *text, int posX, int posY, int fontSize, - Color color); -extern int MeasureText(const char *text, int fontSize); -extern float GetFrameTime(void); -extern double GetTime(void); -extern int GetScreenWidth(void); -extern int GetScreenHeight(void); - -void flan_rl_draw_pixel(int x, int y, const Color *c) { DrawPixel(x, y, *c); } - -void flan_rl_draw_pixel_v(const Vector2 *p, const Color *c) { - DrawPixelV(*p, *c); -} - -void flan_rl_draw_line(int x1, int y1, int x2, int y2, const Color *c) { - DrawLine(x1, y1, x2, y2, *c); -} - -void flan_rl_draw_line_v(const Vector2 *a, const Vector2 *b, const Color *c) { - DrawLineV(*a, *b, *c); -} - -void flan_rl_draw_line_ex(const Vector2 *a, const Vector2 *b, float thick, - const Color *c) { - DrawLineEx(*a, *b, thick, *c); -} - -void flan_rl_draw_circle(int x, int y, float radius, const Color *c) { - DrawCircle(x, y, radius, *c); -} - -void flan_rl_draw_circle_v(const Vector2 *center, float radius, const Color *c) { - DrawCircleV(*center, radius, *c); -} - -void flan_rl_draw_circle_lines(int x, int y, float radius, const Color *c) { - DrawCircleLines(x, y, radius, *c); -} - -void flan_rl_draw_circle_lines_v(const Vector2 *center, float radius, - const Color *c) { - DrawCircleLinesV(*center, radius, *c); -} - -void flan_rl_draw_ellipse(int x, int y, float rh, float rv, const Color *c) { - DrawEllipse(x, y, rh, rv, *c); -} - -void flan_rl_draw_ellipse_lines(int x, int y, float rh, float rv, const Color *c) { - DrawEllipseLines(x, y, rh, rv, *c); -} - -void flan_rl_draw_ring(const Vector2 *center, float inner, float outer, - float start, float end, int segments, const Color *c) { - DrawRing(*center, inner, outer, start, end, segments, *c); -} - -void flan_rl_draw_ring_lines(const Vector2 *center, float inner, float outer, - float start, float end, int segments, - const Color *c) { - DrawRingLines(*center, inner, outer, start, end, segments, *c); -} - -void flan_rl_draw_triangle(const Vector2 *a, const Vector2 *b, const Vector2 *d, - const Color *c) { - DrawTriangle(*a, *b, *d, *c); -} - -void flan_rl_draw_triangle_lines(const Vector2 *a, const Vector2 *b, - const Vector2 *d, const Color *c) { - DrawTriangleLines(*a, *b, *d, *c); -} - -void flan_rl_draw_rectangle_v(const Vector2 *position, const Vector2 *size, - const Color *c) { - DrawRectangleV(*position, *size, *c); -} - -void flan_rl_draw_rectangle_rec(const Rectangle *rec, const Color *c) { - DrawRectangleRec(*rec, *c); -} - -void flan_rl_draw_rectangle_lines(int x, int y, int w, int h, const Color *c) { - DrawRectangleLines(x, y, w, h, *c); -} - -void flan_rl_draw_rectangle_lines_ex(const Rectangle *rec, float thick, - const Color *c) { - DrawRectangleLinesEx(*rec, thick, *c); -} - -void flan_rl_draw_rectangle_rounded(const Rectangle *rec, float roundness, - int segments, const Color *c) { - DrawRectangleRounded(*rec, roundness, segments, *c); -} - -/* Four arguments, not five: 5.5's DrawRectangleRoundedLines has no thickness - * and the Ex variant below is where it went. Getting this wrong links fine. */ -void flan_rl_draw_rectangle_rounded_lines(const Rectangle *rec, float roundness, - int segments, const Color *c) { - DrawRectangleRoundedLines(*rec, roundness, segments, *c); -} - -void flan_rl_draw_rectangle_rounded_lines_ex(const Rectangle *rec, - float roundness, int segments, - float thick, const Color *c) { - DrawRectangleRoundedLinesEx(*rec, roundness, segments, thick, *c); -} - -void flan_rl_draw_text(const char *text, long long n, int x, int y, - int font_size, const Color *c) { - char buf[512]; - DrawText(cstr(text, n, buf, sizeof buf), x, y, font_size, *c); -} - -int flan_rl_measure_text(const char *text, long long n, int font_size) { - char buf[512]; - return MeasureText(cstr(text, n, buf, sizeof buf), font_size); -} - -float flan_rl_get_frame_time(void) { return GetFrameTime(); } -double flan_rl_get_time(void) { return GetTime(); } -int flan_rl_get_screen_width(void) { return GetScreenWidth(); } -int flan_rl_get_screen_height(void) { return GetScreenHeight(); }