flan/examples/core-2d-camera-mouse-zoom.flan

109 lines
4.2 KiB
Plaintext

;;;; raylib [core] example - 2d camera mouse zoom
;;;;
;;;; examples/core/core_2d_camera_mouse_zoom.c at the raylib 5.5 tag. It
;;;; needed rlgl's matrix stack: the grid is a 3D grid on the XZ plane, and the
;;;; C stands it up in the XY plane by pushing a matrix, translating, rotating
;;;; ninety degrees about X and drawing. vendor/rlgl binds that stack.
;;;;
;;;; One difference from the C. The mouse read-out is `TextFormat("[%i, %i]",
;;;; ...)` through DrawTextEx with a spacing of 2. TextFormat is variadic and
;;;; unbound, so the read-out is drawn in pieces with draw-text and
;;;; digits.flan's draw-int, which space the glyphs raylib's default way.
(import rl "vendor:raylib")
(import rlgl "vendor:rlgl")
(import d "digits.flan")
(defconst screen-width 800)
(defconst screen-height 450)
;; 0 zooms with the mouse wheel, 1 with a right-button drag.
(defonce zoom-mode i32)
(defonce camera rl/Camera2D)
;; Put the world point under the mouse at the camera's origin, and the origin
;; under the mouse, so a zoom that follows keeps that point still.
(defn anchor-at-mouse [] ()
(let [mouse-world (rl/get-screen-to-world-2d (rl/get-mouse-position) camera)]
(set (.offset camera) (rl/get-mouse-position))
(set (.target camera) mouse-world)))
;; One zoom step: `amount` is how far the input moved, and the direction is its
;; sign. The zoom stays between 1/8 and 64.
(defn zoom-by [amount f32 rate f32] ()
(let [factor (+ 1.0 (* rate (abs-f32 amount)))
factor (if (< amount 0.0) (/ 1.0 factor) factor)]
(set (.zoom camera) (clamp (* (.zoom camera) factor) 0.125 64.0))))
(defn main [] ()
(rl/init-window screen-width screen-height
"raylib [core] example - 2d camera mouse zoom")
(defer (rl/close-window))
;; A zero zoom makes the camera's transform singular.
(set camera (rl/Camera2D {.zoom 1.0}))
(set zoom-mode 0)
(rl/set-target-fps 60)
(until (rl/window-should-close?)
;; Update
(cond
(rl/key-pressed? :key-one) (set zoom-mode 0)
(rl/key-pressed? :key-two) (set zoom-mode 1))
;; Drag to move: the mouse's screen delta, scaled back into world units.
(when (rl/mouse-button-down? :mouse-left)
(let [delta (rl/v2-scale (rl/get-mouse-delta) (/ -1.0 (.zoom camera)))]
(set (.target camera) (rl/v2-add (.target camera) delta))))
(if (= zoom-mode 0)
(let [wheel (rl/get-mouse-wheel-move)]
(when (!= wheel 0.0)
(anchor-at-mouse)
(zoom-by wheel 0.25)))
(do
(when (rl/mouse-button-pressed? :mouse-right)
(anchor-at-mouse))
(when (rl/mouse-button-down? :mouse-right)
(zoom-by (.x (rl/get-mouse-delta)) 0.01))))
;; Draw
(rl/with-drawing
(rl/clear-background rl/raywhite)
(rl/begin-mode-2d camera)
;; The 3D grid, rotated ninety degrees and centred on the origin, so it
;; lies in the XY plane the 2D camera looks at.
(rlgl/push-matrix)
(rlgl/translate 0.0 (* 25.0 50.0) 0.0)
(rlgl/rotate 90.0 1.0 0.0 0.0)
(rl/draw-grid 100 50.0)
(rlgl/pop-matrix)
;; A reference circle.
(rl/draw-circle (/ (rl/get-screen-width) 2) (/ (rl/get-screen-height) 2)
50.0 rl/maroon)
(rl/end-mode-2d)
;; The mouse, and where it is in screen pixels.
(let [mouse (rl/get-mouse-position)
x (- (i32 (.x mouse)) 44)
y (- (i32 (.y mouse)) 24)]
(rl/draw-circle-v mouse 4.0 rl/darkgray)
(rl/draw-text "[" x y 20 rl/black)
(let [x (+ x (rl/measure-text "[" 20))
x (+ x (d/draw-int (rl/get-mouse-x) x y 20 rl/black))]
(rl/draw-text ", " x y 20 rl/black)
(let [x (+ x (rl/measure-text ", " 20))
x (+ x (d/draw-int (rl/get-mouse-y) x y 20 rl/black))]
(rl/draw-text "]" x y 20 rl/black))))
(rl/draw-text "[1][2] Select mouse zoom mode (Wheel or Move)"
20 20 20 rl/darkgray)
(if (= zoom-mode 0)
(rl/draw-text "Mouse left button drag to move, mouse wheel to zoom"
20 50 20 rl/darkgray)
(rl/draw-text "Mouse left button drag to move, mouse press and move to zoom"
20 50 20 rl/darkgray)))))