From 99c5d8712593ec6c2d59749c947ebd060c7d890b Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Mon, 14 Sep 2026 08:34:42 +0700 Subject: [PATCH] Both raylib workarounds, and where the second one went instead --- examples/text-codepoints-loading.flan | 62 ++++++++++++------------ examples/textures-image-processing.flan | 35 +++++++------ test/programs/raylib-codepoints.flan | 25 ++++++---- textures-image-processing | Bin 0 -> 87992 bytes vendor/raylib/generated.flan | 1 + vendor/raylib/raylib.flan | 53 +++++++++++--------- 6 files changed, 97 insertions(+), 79 deletions(-) create mode 100755 textures-image-processing diff --git a/examples/text-codepoints-loading.flan b/examples/text-codepoints-loading.flan index bae3923..e317108 100644 --- a/examples/text-codepoints-loading.flan +++ b/examples/text-codepoints-loading.flan @@ -31,15 +31,16 @@ ;;;; ;;;; **Two things Flan would not do, both written up in docs/PORTING.md.** ;;;; -;;;; 1. `GetCodepointPrevious` cannot be called at all. It reads BACKWARDS -;;;; from the pointer it is handed, and a Flan `string` crosses to C as a -;;;; NUL-terminated *copy* (lib/shim.ml) — so the bytes in front of that -;;;; pointer belong to the allocator and not to the text. It does not -;;;; crash; it reads rubbish and answers 0, which is the worst of the -;;;; available outcomes. `step-back` below is the replacement, and it is -;;;; four lines: a UTF-8 continuation byte is 10xxxxxx, so walking back -;;;; over them lands on the lead byte of the previous codepoint, and -;;;; get-codepoint-next from there says what it is. +;;;; 1. `GetCodepointPrevious` could not be called at all, and now can. +;;;; It reads BACKWARDS from the pointer it is handed, and a Flan +;;;; `string` crosses to C as a NUL-terminated *copy* (lib/shim.ml) — so +;;;; the bytes in front of that pointer belong to the allocator and not +;;;; to the text. It did not crash; it read rubbish and answered 0, which +;;;; is the worst of the available outcomes. The repair is a binding that +;;;; says `(Ptr u8)` and means it, which the header check refused until +;;;; lib/cimport.ml's `agrees` grew the pointer arm its own comment had +;;;; been promising. `rl/get-codepoint-previous` is that binding and +;;;; `step-back` below is now one call to it. ;;;; ;;;; 2. The C's duplicate removal shifts the tail of the array down over ;;;; each duplicate it finds, and its inner loop reads one element past @@ -123,12 +124,6 @@ ;; the cursor is a byte offset into the text, because the pointer it would ;; otherwise be cannot be handed to C: see `step-back`. -;; Is this byte a UTF-8 continuation — 10xxxxxx? Every byte of a multi-byte -;; sequence after the first is, and no lead byte and no ASCII byte is, which -;; is the property that makes the encoding walkable in both directions without -;; a table. -(defn continuation? [b u8] bool (= (bit-and b 0xc0) 0x80)) - ;; The codepoint starting at `off`, and its size in bytes through `size-out`. ;; ;; `(string (slice b off (len b)))` is the whole of what the C's `ptr` is: the @@ -156,21 +151,28 @@ (do (codepoint-at off (addr size)) (if (>= (+ off size) (len b)) off (+ off size)))))) -;; One codepoint back, and the replacement for GetCodepointPrevious. +;; One codepoint back, which is GetCodepointPrevious and no longer a stand-in +;; for it. ;; -;; That function reads backwards from the pointer it is given, and a Flan -;; string reaches C as a copy, so backwards from it is the allocator's -;; business. What it was going to compute is computable here instead and in -;; fewer instructions than the call would have cost: step back one byte, keep -;; stepping while the byte is a continuation, and the codepoint that starts -;; there is the previous one. codepoint-at then says what it is, from the -;; forward direction, where the copy is not a problem. +;; That function reads backwards from the pointer it is given, so a Flan +;; string — which reaches C as a copy — is the one thing it must not be +;; handed. `rl/get-codepoint-previous` takes the bytes and an offset instead +;; and builds the interior pointer itself; see the note beside it in +;; vendor/raylib/raylib.flan. What comes back through `size` is the length of +;; the codepoint *behind* `off`, so the previous offset is the difference. +;; +;; This used to be a hand-written walk over continuation bytes — step back one +;; byte and keep going while the byte is 10xxxxxx — which was correct and was +;; four lines of UTF-8 that the library beside it already knew. The walk is +;; still the right answer for a language with no raylib in it; it is not the +;; right answer for this program. (defn step-back [off i32] i32 (let [b (bytes text) - i (- off 1)] - (while (and (> i 0) (continuation? (at b i))) - (set i (- i 1))) - (if (< i 0) 0 i))) + size 0] + (if (<= off 0) + 0 + (do (rl/get-codepoint-previous b off (addr size)) + (if (< (- off size) 0) 0 (- off size)))))) (defvar font rl/Font) ;; Whether the TTF was there, asked once. A `defvar` and not the call itself @@ -220,10 +222,8 @@ (when (rl/key-pressed? :space) (set show-font-atlas (not show-font-atlas))) ;; The C's "testing code": walk the text and throw the answer away. Kept - ;; because it is what exercises the codepoint walk, and because the two - ;; directions are not symmetric here the way they are in the C — one is a - ;; raylib call and the other is the four lines in step-back that stand in - ;; for the raylib call that cannot be made. + ;; because it is what exercises the codepoint walk, which is now symmetric + ;; here the way it is in the C — a raylib call in each direction. (cond (rl/key-pressed? :right) (set cursor (step-forward cursor)) (rl/key-pressed? :left) (set cursor (step-back cursor))) diff --git a/examples/textures-image-processing.flan b/examples/textures-image-processing.flan index b42af9b..67ee9f5 100644 --- a/examples/textures-image-processing.flan +++ b/examples/textures-image-processing.flan @@ -51,11 +51,14 @@ ;;;; and because the picture is a demonstration of the filter rather than the ;;;; point of the program. ;;;; -;;;; One gap, written up in docs/PORTING.md and worked around in `reload-texture` -;;;; below: LoadImageColors answers a (Ptr Color) and UpdateTexture takes a -;;;; (Ptr u8), because the header spells its parameter `const void *` and Flan -;;;; has no cast between pointer types. The address of the first field of the -;;;; first pixel is the same address, and saying so is what the workaround is. +;;;; One gap, written up in docs/PORTING.md and since closed: LoadImageColors +;;;; answers a (Ptr Color) and UpdateTexture used to take only a (Ptr u8), +;;;; because the header spells its parameter `const void *` and the importer +;;;; had to render that as something. `reload-texture` below spelled the cast +;;;; by hand — the address of the first field of the first pixel, which is the +;;;; same address said at length. It does not any more: the header check +;;;; accepts a pointer to anything where the header says `void *`, so the +;;;; package binds the call twice and the caller names the type it has. (import rl "vendor:raylib") @@ -138,19 +141,23 @@ ;; shortest route: after image-format the working image is already RGBA8, so ;; `(.data im-copy)` is the same bytes and is already a (Ptr u8). It is kept ;; because it is what the C does and because the pair is the only thing in the -;; corpus that exercises it — and because the awkward step in it is a finding -;; rather than an accident. LoadImageColors answers a (Ptr Color); UpdateTexture -;; takes a (Ptr u8), the header having spelled that parameter `const void *`; -;; and there is no cast between pointer types in Flan. What there is, is the -;; address of the red channel of pixel zero, which is the address of the -;; buffer said the long way round. See docs/PORTING.md. +;; corpus that exercises it. +;; +;; The awkward step in it is gone. LoadImageColors answers a (Ptr Color) and +;; UpdateTexture's parameter is `const void *`, which the importer has to +;; render as *something* and renders as (Ptr u8) — so the call used to be +;; written `(addr (.r (at (slice-from-ptr pixels n) 0)))`: the address of the +;; red channel of pixel zero, which is the address of the buffer said the long +;; way round. A `void *` is opaque about what it points at by construction, +;; and the header check now knows that, so the package can offer the same C +;; function under the element type the caller actually has. +;; update-texture-colors is that binding and this is its only caller. (defn reload-texture [] () (rl/unload-image im-copy) (set im-copy (rl/image-copy im-origin)) (apply-process (addr im-copy) current-process) - (let [n (* (.width im-copy) (.height im-copy)) - pixels (rl/load-image-colors im-copy)] - (rl/update-texture texture (addr (.r (at (slice-from-ptr pixels n) 0)))) + (let [pixels (rl/load-image-colors im-copy)] + (rl/update-texture-colors texture pixels) (rl/unload-image-colors pixels))) (defn main [] () diff --git a/test/programs/raylib-codepoints.flan b/test/programs/raylib-codepoints.flan index f9919b9..6211b16 100644 --- a/test/programs/raylib-codepoints.flan +++ b/test/programs/raylib-codepoints.flan @@ -18,12 +18,16 @@ ;;;; ;;;; **2. The walk agrees with itself.** The text is stepped from the first ;;;; codepoint to the last, and then back from the last to the first, and the -;;;; two sequences are compared. That is what pins `step-back` — the four lines -;;;; that replace GetCodepointPrevious, which this language cannot call because -;;;; a Flan string reaches C as a copy and that function reads backwards out of -;;;; the pointer it is handed. If the continuation-byte test were wrong the -;;;; backward walk would land mid-sequence and read a different codepoint, and -;;;; the two sequences would stop being reverses of each other. +;;;; two sequences are compared. That is what pins `step-back`, which is +;;;; GetCodepointPrevious — a function that reads *backwards* out of the +;;;; pointer it is handed, and so the one raylib call a Flan `string` must +;;;; never reach, because a string crosses to C as a NUL-terminated copy and +;;;; the bytes in front of a copy are the allocator's. Handed a copy it +;;;; answers 0 with a size of 0, which is also its answer for malformed UTF-8; +;;;; step-back would then return its argument unchanged, the backward walk +;;;; would never reach offset 0, and the two sequences would stop being +;;;; reverses of each other. That is the shape of the wrong answer this row +;;;; exists to see. ;;;; ;;;; **3. The walk agrees with raylib.** The sequence the walk produces is ;;;; compared against the array LoadCodepoints returned, element for element. @@ -110,10 +114,11 @@ ;; The one call walk-backward never makes: step-back at the very start. ;; It is where the example goes the moment anybody presses LEFT before - ;; pressing RIGHT, and it is the one offset where the continuation-byte - ;; loop is asked to step off the front of the buffer. `and` short-circuits, - ;; so the (> i 0) guard is what keeps (at b -1) from being evaluated at - ;; all — which is a claim about the language and so is worth a row. + ;; pressing RIGHT, and it is the offset at which there is nothing behind + ;; the cursor to read. GetCodepointPrevious reads *backwards* from the + ;; pointer it is handed, so asking it here would read whatever is in front + ;; of the text; the guard in step-back is what means it is not asked, and + ;; a guard nothing exercises is a guard nobody knows about. (show "back at start" (cp/step-back 0)) ;; Item 3: and the forward walk is what raylib said the text contains. diff --git a/textures-image-processing b/textures-image-processing new file mode 100755 index 0000000000000000000000000000000000000000..9a8d5494d36087399c8c684544bdd50cc1d433ee GIT binary patch literal 87992 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 Mpn%WmpX1W_zppzZQ~&?~ literal 0 HcmV?d00001 diff --git a/vendor/raylib/generated.flan b/vendor/raylib/generated.flan index 56ec50e..ed26d08 100644 --- a/vendor/raylib/generated.flan +++ b/vendor/raylib/generated.flan @@ -199,6 +199,7 @@ (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") (declare-c load-texture-cubemap [image Image layout i32] Texture2D "LoadTextureCubemap") +(declare-c update-texture [texture Texture2D pixels (Ptr u8)] "UpdateTexture") (declare-c update-texture-rec [texture Texture2D rec Rectangle pixels (Ptr u8)] "UpdateTextureRec") (declare-c gen-texture-mipmaps [texture (Ptr Texture2D)] "GenTextureMipmaps") (declare-c set-texture-wrap [texture Texture2D wrap i32] "SetTextureWrap") diff --git a/vendor/raylib/raylib.flan b/vendor/raylib/raylib.flan index d121c4d..c4f1189 100644 --- a/vendor/raylib/raylib.flan +++ b/vendor/raylib/raylib.flan @@ -589,36 +589,41 @@ (declare-c unload-texture [texture Texture2D] "UnloadTexture") -;; Refilling a texture's pixels from a CPU-side buffer. +;; Refilling a texture's pixels from a Color buffer. ;; -;; Both of these are hand-written and both call UpdateTexture, which is the -;; whole of what a `void *` parameter is: raylib does not care what the buffer +;; UpdateTexture takes a `const void *` — raylib does not care what the buffer ;; is an array *of*, only that it is the right number of bytes in the format -;; the texture was made with. `cimport.ml` has to render that `void *` as -;; something and renders it `(Ptr u8)`, so the generated line could only ever -;; offer one of the two faces, and the one it picked is the wrong one for the -;; commonest caller: LoadImageColors answers `(Ptr Color)` and handing that -;; straight on is what the C does. +;; the texture was made with. The importer has to render that as *something* +;; and renders it `(Ptr u8)`, which is the generated `update-texture` above. ;; -;; So the package says both, under two names, and the header check now agrees -;; with both — a `void *` is opaque about its element type by construction, so -;; there is no disagreement there for it to report (lib/cimport.ml's -;; [ptr_agrees]). Before that arm existed the call site had to spell the cast -;; by hand as `(addr (.r (at (slice-from-ptr pixels n) 0)))` — the address of -;; the first field of the first element, which is the right address and reads -;; like an apology. +;; That face cannot be the only one, because the commonest source of pixels is +;; LoadImageColors and it answers a `(Ptr Color)`. It also cannot be replaced +;; by a `(Ptr Color)` one: `(.data im-copy)` is already a `(Ptr u8)` over the +;; same bytes and is the shorter route, and `(Ptr u8)` → `(Ptr Color)` is not +;; expressible while `(Ptr Color)` → `(Ptr u8)` is. So the byte face is the +;; declaration and the typed face is this. ;; -;; Neither one checks that the buffer is big enough, because neither can: the +;; A second `declare-c` was the obvious shape and lib/shim.ml refuses it, for a +;; reason that is right: a shim emits one C prototype per declaration, and two +;; prototypes for one symbol that disagree about a parameter type is a C file +;; that does not compile. Its message says what to write instead — "another +;; Flan name for it is a defn" — and this is that defn. docs/PORTING.md §A.2 +;; expected the header check to be the only thing in the way; it was not. +;; +;; `(addr (.r pixels))` is the whole of the conversion. `.` auto-derefs one +;; level and `r` is Color's first field, so this is the address the pointer +;; already held, said in the only way the language has of saying it. It used +;; to be written at the call site as +;; `(addr (.r (at (slice-from-ptr pixels n) 0)))`, which is the same address +;; with a slice built and indexed on the way past. Once, here, with a name on +;; it is better than once per caller. +;; +;; Neither call checks that the buffer is big enough, because neither can: the ;; length raylib wants is width * height * bytes-per-pixel of the *texture*, -;; and a pointer has no length. That is the same deal every raylib pointer +;; and a pointer has no length. That is the deal every raylib pointer ;; parameter offers. -(declare-c update-texture - [texture Texture2D pixels (Ptr u8)] - "UpdateTexture") - -(declare-c update-texture-colors - [texture Texture2D pixels (Ptr Color)] - "UpdateTexture") +(defn update-texture-colors [texture Texture2D pixels (Ptr Color)] () + (update-texture texture (addr (.r pixels)))) ;; How a texture is sampled when it is drawn at anything other than its own ;; size. The header says `int` on SetTextureFilter and means one of these six.