The trio the author decided on 2026-09-20 is now all built: def is CL's defparameter — its initialiser runs on every daemon re-run, unguarded, so an edited initialiser repaints the same storage on C-c C-c plus re-run — defonce (Clojure's name for CL's defvar, per the author) initialises once behind the .init~once. flag, and defconst stays the image. One parse arm reads both forms; the difference is Ast.reinit, carried to Tast.global's grerun. Emit.startup_plan gives a def no guard flag, and Check.check_global lifts every def initialiser — zero and literal included — into global/<n>, so the host's startup reaches it through the function cell and a re-evaluated def swaps it (Session's def_inits; Emit.redefinition declares the cell for a non-sibling target). The old defvar spelling is refused with the rename and both compiling spellings, and every program, test, doc and editor list is swept — except sand.flan, the author's live WIP, whose seven defvar lines are flagged in FIX.org and keep its three dependent tests red on this branch.
112 lines
5.0 KiB
Plaintext
112 lines
5.0 KiB
Plaintext
;;;; raylib [core] example - world to screen
|
|
;;;;
|
|
;;;; examples/core/core_world_screen.c, and the first thing in this directory
|
|
;;;; to draw in 3D at all. That is why it is here: before it, vendor/raylib
|
|
;;;; described no Vector3, no Camera3D and not one call that takes either, so
|
|
;;;; the importer refused every 3D function in raylib.h by name — "Vector3 is
|
|
;;;; a struct the package does not describe". Two defstructs later it refuses
|
|
;;;; none of them, and the generated half grew the cubes, spheres, cylinders
|
|
;;;; and billboards along with the eight lines this example needs.
|
|
;;;;
|
|
;;;; Hand-written in raylib.flan rather than generated, and why each:
|
|
;;;;
|
|
;;;; begin-mode-3d / end-mode-3d a begin/end pair inside a frame, the
|
|
;;;; class docs/PORTING.md §1 names, and taken
|
|
;;;; together the way begin-mode-2d is
|
|
;;;; draw-cube / draw-cube-wires / draw-grid drawn every frame
|
|
;;;; update-camera the Flan face differs: (Ptr Camera3D),
|
|
;;;; because it mutates, and a CameraMode
|
|
;;;; rather than the header's int
|
|
;;;; get-world-to-screen it reads the same camera as the mode
|
|
;;;;
|
|
;;;; What is NOT pinned by anything, and cannot be: Camera3D's first three
|
|
;;;; fields are all Vector3, so every permutation of position, target and up
|
|
;;;; has the identical layout and no computed test can tell them apart. A
|
|
;;;; camera looking from the wrong place is a picture, not a number. The same
|
|
;;;; is true of Vector3's own x, y and z. Only the screen catches those.
|
|
;;;;
|
|
;;;; update-camera in :third-person mode also takes the mouse, which is why
|
|
;;;; the C calls DisableCursor: the cursor is locked to the window and its
|
|
;;;; movement becomes camera rotation rather than a pointer. disable-cursor
|
|
;;;; comes from the generated half — it is called once, before the loop.
|
|
;;;;
|
|
;;;; The C's two TextFormats go through examples/digits.flan, as in the other
|
|
;;;; ports, because Flan has no TextFormat and i64->bytes has no field width.
|
|
|
|
(import rl "vendor:raylib")
|
|
(import d "digits.flan")
|
|
|
|
(defconst screen-width 800)
|
|
(defconst screen-height 450)
|
|
|
|
(defonce camera rl/Camera3D)
|
|
(defonce cube rl/Vector3)
|
|
|
|
(defn main [] ()
|
|
(rl/init-window screen-width screen-height
|
|
"raylib [core] example - core world screen")
|
|
(defer (rl/close-window))
|
|
|
|
;; `projection` is a CameraProjection, so the keyword resolves against the
|
|
;; enum's members right here and a misspelt projection is a compile error
|
|
;; rather than a 0. raylib's field is `int` and the layout is unchanged —
|
|
;; an enum is four bytes either way.
|
|
(set camera
|
|
(rl/Camera3D {.position (rl/Vector3 {.x 10.0 .y 10.0 .z 10.0})
|
|
.target (rl/Vector3 {.x 0.0 .y 0.0 .z 0.0})
|
|
.up (rl/Vector3 {.x 0.0 .y 1.0 .z 0.0})
|
|
.fovy 45.0
|
|
.projection :perspective}))
|
|
|
|
(set cube (rl/Vector3 {.x 0.0 .y 0.0 .z 0.0}))
|
|
|
|
;; The mouse becomes the camera's, not a pointer's.
|
|
(rl/disable-cursor)
|
|
|
|
(rl/set-target-fps 60)
|
|
|
|
(until (rl/window-should-close?)
|
|
;; Update. The camera is passed by address because update-camera writes
|
|
;; to it — a global is an assignable place, so it has an address to take.
|
|
(rl/update-camera (addr camera) :third-person)
|
|
|
|
;; Where the point 2.5 units above the cube lands on the screen. This is
|
|
;; the whole example: the same transform raylib is about to draw with,
|
|
;; asked in advance, so a label can be put on a thing in the world.
|
|
(let [label-pos (rl/get-world-to-screen
|
|
(rl/Vector3 {.x (.x cube)
|
|
.y (+ (.y cube) 2.5)
|
|
.z (.z cube)})
|
|
camera)]
|
|
|
|
;; Draw
|
|
(rl/with-drawing
|
|
(rl/clear-background rl/raywhite)
|
|
|
|
(rl/with-mode-3d camera
|
|
(rl/draw-cube cube 2.0 2.0 2.0 rl/red)
|
|
(rl/draw-cube-wires cube 2.0 2.0 2.0 rl/maroon)
|
|
(rl/draw-grid 10 1.0))
|
|
|
|
;; And the 2D half, drawn after end-mode-3d and therefore on top of the
|
|
;; cube whatever the depth buffer says — which is the second half of
|
|
;; what the example demonstrates.
|
|
(rl/draw-text "Enemy: 100 / 100"
|
|
(- (i32 (.x label-pos))
|
|
(/ (rl/measure-text "Enemy: 100/100" 20) 2))
|
|
(i32 (.y label-pos)) 20 rl/black)
|
|
|
|
(let [x 10]
|
|
(rl/draw-text "Cube position in screen space coordinates: [" x 10 20
|
|
rl/lime)
|
|
(set x (+ x (rl/measure-text
|
|
"Cube position in screen space coordinates: [" 20)))
|
|
(set x (+ x (d/draw-int (i32 (.x label-pos)) x 10 20 rl/lime)))
|
|
(rl/draw-text ", " x 10 20 rl/lime)
|
|
(set x (+ x (rl/measure-text ", " 20)))
|
|
(set x (+ x (d/draw-int (i32 (.y label-pos)) x 10 20 rl/lime)))
|
|
(rl/draw-text "]" x 10 20 rl/lime))
|
|
|
|
(rl/draw-text "Text 2d should be always on top of the cube" 10 40 20
|
|
rl/gray)))))
|