;;;; 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)))))