core-2d-camera, core-scissor-test, core-window-flags, core-world-screen
and core-window-should-close, ported from raylib 5.5's examples/core.
What each one asked of vendor/raylib:
2d-camera nothing. A whole Camera2D by value, per frame, into the
call that actually draws with it — the layout the
acceptance table pins through arithmetic, now going
through the path it was bound for.
scissor-test begin-scissor-mode / end-scissor-mode, hand-written.
window-flags twelve more ConfigFlags constants; raylib.flan carried
the four sand.flan sets and this reads eleven.
world-screen the 3D surface did not exist: no Vector3, no Camera3D,
and the importer refused every 3D function in raylib.h
by name for want of them. Two defstructs, two defenums,
begin/end-mode-3d, update-camera, get-world-to-screen,
draw-cube, draw-cube-wires, draw-grid — and 24 more 3D
lines the importer can generate now that the types are
described.
window-should-close set-exit-key, and Key/null to pass it.
The hand-written/generated line, written down in vendor/raylib/bindings:
a drawing pair inside a frame is hand-written, and so is anything whose
Flan face is not the C signature — set-exit-key takes a Key, update-camera
takes a (Ptr Camera3D) and a CameraMode. The window-state family and
get-mouse-x/y stay generated: plain scalars in and bool out, with nothing
for a hand-written line to add.
Camera3D's projection field stays i32, because the header says int and the
layout check holds this file to that; rl/camera-projection is the
conversion, and still takes a keyword.
115 lines
5.1 KiB
Plaintext
115 lines
5.1 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 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)
|
|
|
|
(defvar camera rl/Camera3D)
|
|
(defvar cube rl/Vector3)
|
|
|
|
(defn main [] ()
|
|
(rl/init-window screen-width screen-height
|
|
"raylib [core] example - core world screen")
|
|
(defer (rl/close-window))
|
|
|
|
;; `projection` is an i32 and not a CameraProjection, because the header
|
|
;; says the field is `int` and the layout check holds this file to that.
|
|
;; rl/camera-projection is the conversion, and it still takes a keyword, so
|
|
;; a misspelt projection is a compile error rather than a 0.
|
|
(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 (rl/camera-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/begin-drawing)
|
|
(rl/clear-background rl/raywhite)
|
|
|
|
(rl/begin-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)
|
|
(rl/end-mode-3d)
|
|
|
|
;; 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)
|
|
|
|
(rl/end-drawing))))
|