(local keybindings {:left [:left :a] :right [:right :d] :down [:down :s] :up [:up :w]})
(fn check-keybinding [direction]
(if (love.keyboard.isDown (unpack (. keybindings direction))) 1 0))
(fn init [opts keybindings?]
(local cam {:x 0 :y 0 :scale 3 :speed 7
:v {:cx 0 :cy 0 :sx 0 :sy 0 :active false}})
(each [key value (ipairs opts)] (tset cam key value))
(when keybindings?
(each [key value (ipairs keybindings?)] (tset keybindings key value)))
cam)
(fn transform [cam]
(love.graphics.scale cam.scale)
(love.graphics.translate cam.x cam.y))
(fn transform-without-scale [cam]
(love.graphics.translate (* cam.scale cam.x) (* cam.scale cam.y)))
(fn to-camera-space [cam x y]
(values (- (/ x cam.scale) cam.x)
(- (/ y cam.scale) cam.y)))
(fn to-global-space [cam x y]
(values (* (+ x cam.x) cam.scale)
(* (+ y cam.y) cam.scale)))
(local editor
{
:update
(fn [cam dt]
(let [l (check-keybinding :left)
r (check-keybinding :right)
u (check-keybinding :up)
d (check-keybinding :down)
lr (- l r)
ud (- u d)
mag (if (and (= 0 lr) (= 0 ud)) 1 (math.sqrt (+ (^ lr 2) (^ ud 2))))
lrn (/ lr mag)
udn (/ ud mag)]
(set cam.x (+ cam.x (-> lrn (* cam.speed) (/ cam.scale))))
(set cam.y (+ cam.y (-> udn (* cam.speed) (/ cam.scale))))))
:mousepressed
(fn [cam x y button]
(when (= button 3)
(set cam.v.sx x)
(set cam.v.sy y)
(set cam.v.cx cam.x)
(set cam.v.cy cam.y)
(set cam.v.active true)))
:mousemoved
(fn [cam x y]
(when cam.v.active
(set cam.x (- cam.v.cx (-> (- cam.v.sx x) (/ cam.scale))))
(set cam.y (- cam.v.cy (-> (- cam.v.sy y) (/ cam.scale))))))
:mousereleased
(fn [cam x y button] (set cam.v.active false))
:wheelmoved
(fn [cam x y]
(when (not cam.v.active)
(let [p cam.scale
n (-> cam.scale (* (+ 1 (* 0.1 y))) (math.max 1) (math.min 8))
(mx my) (love.mouse.getPosition)
ox (* mx (/ (- n p) (* p n)))
oy (* my (/ (- n p) (* p n)))]
(set cam.scale n)
(set cam.x (- cam.x ox))
(set cam.y (- cam.y oy)))))
})
{: editor : init : transform : transform-without-scale : to-camera-space : to-global-space}