;;;; 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.fln's draw-int, which space the glyphs raylib's default way. import rl "vendor:raylib" import rlgl "vendor:rlgl" import d "digits.fln" const screen-width = 800 const screen-height = 450 ;; 0 zooms with the mouse wheel, 1 with a right-button drag. once zoom-mode: i32 once 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. fn anchor-at-mouse() -> () let mouse-world = rl/get-screen-to-world-2d(rl/get-mouse-position(), camera) camera.offset = rl/get-mouse-position() camera.target = 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. fn zoom-by(amount: f32, rate: f32) -> () let factor = 1.0 + rate * abs-f32(amount) let factor = if amount < 0.0 then 1.0 / factor else factor camera.zoom = clamp(camera.zoom * factor, 0.125, 64.0) fn 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. camera = rl/Camera2D{.zoom 1.0} zoom-mode = 0 rl/set-target-fps(60) until rl/window-should-close() ;; Update if rl/is-key-pressed(:key-one) zoom-mode = 0 elif rl/is-key-pressed(:key-two) zoom-mode = 1 ;; Drag to move: the mouse's screen delta, scaled back into world units. if rl/is-mouse-button-down(:mouse-left) let delta = rl/v2-scale(rl/get-mouse-delta(), -1.0 / camera.zoom) camera.target = rl/v2-add(camera.target, delta) if zoom-mode == 0 let wheel = rl/get-mouse-wheel-move() if wheel != 0.0 anchor-at-mouse() zoom-by(wheel, 0.25) else if rl/is-mouse-button-pressed(:mouse-right) anchor-at-mouse() if rl/is-mouse-button-down(:mouse-right) zoom-by(rl/get-mouse-delta().x, 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(mouse.x) - 44 y = i32(mouse.y) - 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) let 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) let 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) else rl/draw-text("Mouse left button drag to move, mouse press and move to zoom", 20, 50, 20, rl/darkgray)