diff --git a/sand.flan b/sand.flan index 1a14d49..dd3c080 100644 --- a/sand.flan +++ b/sand.flan @@ -35,6 +35,13 @@ (defvar brush rl/Texture2D) (defvar brush-ok bool) +;; The same sheet a second time, mirrored on the CPU before the GPU ever sees +;; it. That is what the Image family is for, and this is its only call site: +;; nothing headless can make a texture, so load-texture-from-image would +;; otherwise be bound and never called, which is the same as not bound. +(defvar brush-mirrored rl/Texture2D) +(defvar brush-mirrored-ok bool) + ;; A missing file is not a crash and not silence: LoadTexture hands back a ;; texture with an id of 0, every draw with it is a no-op, and the program ;; looks like it has a drawing bug. So it is asked and said once, here. @@ -42,7 +49,16 @@ (set brush (rl/load-texture "brush.png")) (set brush-ok (rl/texture-valid? brush)) (unless brush-ok - (print-line "sand: cannot load brush.png — drawing the cursor is off"))) + (print-line "sand: cannot load brush.png — drawing the cursor is off")) + ;; The other route to a texture: the file into RAM, changed there, and only + ;; then uploaded. An Image that failed to load has a null buffer and + ;; unloading it is still safe, so there is one unload and not two. + (let [sheet (rl/load-image "brush.png")] + (when (rl/image-valid? sheet) + (rl/image-flip-horizontal (addr sheet)) + (set brush-mirrored (rl/load-texture-from-image sheet))) + (rl/unload-image sheet)) + (set brush-mirrored-ok (rl/texture-valid? brush-mirrored))) ;; Four draws, one per shape the call comes in, because none of them can be in ;; the acceptance table. The cursor picks one frame out of the sheet and so @@ -60,7 +76,13 @@ (rl/draw-texture brush 20 50 rl/white) (rl/draw-texture-v brush (rl/Vector2 {:x 44.0 :y 50.0}) (rl/get-color (nth sim/colors sim/current-color))) - (rl/draw-texture-ex brush (rl/Vector2 {:x 72.0 :y 46.0}) 0.0 2.0 rl/white)))) + (rl/draw-texture-ex brush (rl/Vector2 {:x 72.0 :y 46.0}) 0.0 2.0 rl/white))) + ;; The mirrored one beside them, scaled up so the flip is visible rather + ;; than eight pixels wide. If the two badges look the same, either the flip + ;; did nothing or the upload took the unedited buffer. + (when brush-mirrored-ok + (rl/draw-texture-ex brush-mirrored (rl/Vector2 {:x 110.0 :y 46.0}) + 0.0 2.0 rl/white))) ;; ── The view ──────────────────────────────────────────────────────── ;; @@ -169,7 +191,10 @@ (rl/Vector2 {:x x :y (+ y r)}) tint) (rl/draw-line-ex (rl/Vector2 {:x (- x (f32 4.0)) :y y}) (rl/Vector2 {:x (+ x (f32 4.0)) :y y}) (f32 3.0) rl/white) - ;; The exact world point, one pixel of it. + ;; The exact world point: a filled dot, and one pixel of white on top of + ;; it. Both are the Vector2 forms, so they land where the ring's centre + ;; is and not somewhere an integer cast put them. + (rl/draw-circle-v p (f32 5.0) tint) (rl/draw-pixel-v p rl/white) ;; A pointer above the cursor. Counter-clockwise, because raylib culls the ;; other winding and draws nothing — which looks exactly like a broken @@ -281,6 +306,7 @@ ;; is no GPU to upload to until InitWindow has made a context. (load-brush) (defer (rl/unload-texture brush)) + (defer (rl/unload-texture brush-mirrored)) ;; The dev agent listens on a socket for redefinitions and hands them over; ;; (agent/poll) below is where they are installed. Building without --dev is ;; fine — nothing has cells to install into, so a module is refused on the