| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- local m = {}
- m.fov = math.pi / 2
- m.near_plane = 0.01
- m.upvector = Vec3(0, 1, 0)
- m.position = Vec3(0, 3, 4)
- m.center = Vec3(0, 0, 0)
- m.zoom_speed = 1.0
- m.orbit_speed = 1.0
- m.pan_speed = 1.0
- m.azimuth = math.pi / 2
- m.radius = m.position:distance(m.center)
- m.polar = math.acos((m.position.y - m.center.y) / m.radius)
- -- angles are measured from the up vector
- m.polar_upper = 0.1
- m.polar_lower = math.pi - m.polar_upper
- m.radius_lower = 0.1
- -- these are read-only; overwriten in nudge() and resize()
- m.pose = Mat4():target(m.position, m.center, m.upvector)
- m.projection = Mat4():perspective(m.fov, 1, m.near_plane, 0)
- -- should be called on top of lovr.draw()
- function m.setCamera(pass)
- pass:setViewPose(1, m.pose)
- pass:setProjection(1, m.projection)
- end
- -- make relative changes to camera position
- function m.nudge(delta_azimuth, delta_polar, delta_radius)
- delta_azimuth = delta_azimuth or 0
- delta_polar = delta_polar or 0
- delta_radius = delta_radius or 0
- m.azimuth = m.azimuth + delta_azimuth
- m.polar = math.max(m.polar_upper, math.min(m.polar_lower, m.polar + delta_polar))
- m.radius = math.max(m.radius_lower, m.radius + delta_radius)
- m.position.x = m.center.x + m.radius * math.sin(m.polar) * math.cos(m.azimuth)
- m.position.y = m.center.y + m.radius * math.cos(m.polar)
- m.position.z = m.center.z + m.radius * math.sin(m.polar) * math.sin(m.azimuth)
- m.pose:target(m.position, m.center, m.upvector)
- end
- -- should be called from lovr.resize()
- function m.resize(width, height)
- local aspect = width / height
- m.projection = Mat4():perspective(m.fov, aspect, m.near_plane, 0)
- end
- m.resize(lovr.system.getWindowDimensions())
- -- should be called from lovr.mousemoved()
- function m.mousemoved(x, y, dx, dy)
- if lovr.system.isMouseDown(3) then
- if lovr.system.isMouseDown(1) then
- m.center.y = m.center.y + m.pan_speed * 0.01 * dy
- else
- local view = mat4(m.pose):invert()
- local camera_right = vec3(view[1], view[5], view[9])
- local camera_forward = vec3(view[2], 0, view[10]):normalize()
- m.center:add(camera_right * (m.pan_speed * 0.005 * -dx))
- m.center:add(camera_forward * (m.pan_speed * 0.005 * dy))
- end
- m.nudge()
- elseif lovr.system.isMouseDown(1) then
- m.nudge(m.orbit_speed * 0.0025 * dx, m.orbit_speed * 0.0025 * -dy, 0)
- end
- end
- -- should be called from lovr.wheelmoved()
- function m.wheelmoved(dx, dy)
- m.nudge(0, 0, -dy * m.zoom_speed * 0.12)
- end
- -- quick way to start using camera module - just call this function
- function m.integrate()
- local stub_fn = function() end
- local existing_cb = {
- draw = lovr.draw or stub_fn,
- resize = lovr.resize or stub_fn,
- mousemoved = lovr.mousemoved or stub_fn,
- wheelmoved = lovr.wheelmoved or stub_fn,
- }
- local function wrap(callback)
- return function(...)
- m[callback](...)
- existing_cb[callback](...)
- end
- end
- lovr.mousemoved = wrap('mousemoved')
- lovr.wheelmoved = wrap('wheelmoved')
- lovr.resize = wrap('resize')
- lovr.draw = function(pass)
- m.setCamera(pass)
- existing_cb.draw(pass)
- end
- end
- return m
|