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

103 lines
4.0 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.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)