2019-05-05 15:17:57 +00:00
|
|
|
use client::Client;
|
|
|
|
|
|
|
|
use common::vol::{ReadVol, SampleVol};
|
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
// Standard
|
|
|
|
use std::f32::consts::PI;
|
|
|
|
|
|
|
|
// Library
|
|
|
|
use vek::*;
|
|
|
|
|
|
|
|
const NEAR_PLANE: f32 = 0.1;
|
|
|
|
const FAR_PLANE: f32 = 10000.0;
|
|
|
|
|
2019-05-06 13:22:49 +00:00
|
|
|
const INTERP_TIME: f32 = 0.1;
|
2019-05-05 15:17:57 +00:00
|
|
|
|
2019-01-11 23:18:34 +00:00
|
|
|
pub struct Camera {
|
2019-05-05 15:17:57 +00:00
|
|
|
tgt_focus: Vec3<f32>,
|
2019-01-11 23:18:34 +00:00
|
|
|
focus: Vec3<f32>,
|
|
|
|
ori: Vec3<f32>,
|
2019-05-05 15:17:57 +00:00
|
|
|
tgt_dist: f32,
|
2019-01-11 23:18:34 +00:00
|
|
|
dist: f32,
|
|
|
|
fov: f32,
|
|
|
|
aspect: f32,
|
2019-05-05 15:17:57 +00:00
|
|
|
|
|
|
|
last_time: Option<f64>,
|
2019-01-11 23:18:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Camera {
|
|
|
|
/// Create a new `Camera` with default parameters.
|
2019-04-14 15:05:51 +00:00
|
|
|
pub fn new(aspect: f32) -> Self {
|
2019-01-11 23:18:34 +00:00
|
|
|
Self {
|
2019-05-05 15:17:57 +00:00
|
|
|
tgt_focus: Vec3::unit_z() * 10.0,
|
2019-01-13 20:53:55 +00:00
|
|
|
focus: Vec3::unit_z() * 10.0,
|
2019-01-11 23:18:34 +00:00
|
|
|
ori: Vec3::zero(),
|
2019-05-05 15:17:57 +00:00
|
|
|
tgt_dist: 10.0,
|
2019-04-16 18:01:56 +00:00
|
|
|
dist: 10.0,
|
2019-05-18 19:03:13 +00:00
|
|
|
fov: 1.1,
|
2019-04-14 15:05:51 +00:00
|
|
|
aspect,
|
2019-05-05 15:17:57 +00:00
|
|
|
last_time: None,
|
2019-01-11 23:18:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 15:13:11 +00:00
|
|
|
/// Compute the transformation matrices (view matrix and projection matrix) and position of the
|
|
|
|
/// camera.
|
2019-05-05 15:17:57 +00:00
|
|
|
pub fn compute_dependents(&self, client: &Client) -> (Mat4<f32>, Mat4<f32>, Vec3<f32>) {
|
|
|
|
let dist = {
|
|
|
|
let (start, end) = (
|
|
|
|
self.focus,
|
|
|
|
self.focus
|
|
|
|
+ (Vec3::new(
|
|
|
|
-f32::sin(self.ori.x) * f32::cos(self.ori.y),
|
|
|
|
-f32::cos(self.ori.x) * f32::cos(self.ori.y),
|
|
|
|
f32::sin(self.ori.y),
|
|
|
|
) * self.dist),
|
|
|
|
);
|
|
|
|
|
2019-05-12 05:37:10 +00:00
|
|
|
match client
|
|
|
|
.state()
|
|
|
|
.terrain()
|
|
|
|
.ray(start, end)
|
|
|
|
.ignore_error()
|
|
|
|
.max_iter(500)
|
|
|
|
.cast()
|
|
|
|
{
|
2019-05-05 15:17:57 +00:00
|
|
|
(d, Ok(Some(_))) => f32::min(d - 1.0, self.dist),
|
|
|
|
(_, Ok(None)) => self.dist,
|
|
|
|
(_, Err(_)) => self.dist,
|
2019-05-05 15:54:08 +00:00
|
|
|
}
|
|
|
|
.max(0.0)
|
2019-05-05 15:17:57 +00:00
|
|
|
};
|
|
|
|
|
2019-01-12 01:14:58 +00:00
|
|
|
let view_mat = Mat4::<f32>::identity()
|
2019-05-05 15:17:57 +00:00
|
|
|
* Mat4::translation_3d(-Vec3::unit_z() * dist)
|
2019-01-11 23:18:34 +00:00
|
|
|
* Mat4::rotation_z(self.ori.z)
|
|
|
|
* Mat4::rotation_x(self.ori.y)
|
|
|
|
* Mat4::rotation_y(self.ori.x)
|
|
|
|
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
|
|
|
|
* Mat4::translation_3d(-self.focus);
|
|
|
|
|
2019-04-29 20:37:19 +00:00
|
|
|
let proj_mat = Mat4::perspective_rh_no(self.fov, self.aspect, NEAR_PLANE, FAR_PLANE);
|
2019-01-11 23:18:34 +00:00
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
// TODO: Make this more efficient.
|
2019-01-12 01:14:58 +00:00
|
|
|
let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w());
|
|
|
|
|
|
|
|
(view_mat, proj_mat, cam_pos)
|
2019-01-11 23:18:34 +00:00
|
|
|
}
|
2019-01-12 01:14:58 +00:00
|
|
|
|
2019-01-12 13:56:34 +00:00
|
|
|
/// Rotate the camera about its focus by the given delta, limiting the input accordingly.
|
|
|
|
pub fn rotate_by(&mut self, delta: Vec3<f32>) {
|
2019-03-02 19:43:51 +00:00
|
|
|
// Wrap camera yaw
|
|
|
|
self.ori.x = (self.ori.x + delta.x) % (2.0 * PI);
|
2019-01-12 13:56:34 +00:00
|
|
|
// Clamp camera pitch to the vertical limits
|
2019-04-29 20:37:19 +00:00
|
|
|
self.ori.y = (self.ori.y + delta.y).min(PI / 2.0).max(-PI / 2.0);
|
2019-03-02 19:43:51 +00:00
|
|
|
// Wrap camera roll
|
|
|
|
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
|
2019-01-12 13:56:34 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Set the orientation of the camera about its focus.
|
2019-05-12 13:02:47 +00:00
|
|
|
pub fn set_orientation(&mut self, orientation: Vec3<f32>) {
|
|
|
|
// Wrap camera yaw
|
|
|
|
self.ori.x = orientation.x % (2.0 * PI);
|
|
|
|
// Clamp camera pitch to the vertical limits
|
|
|
|
self.ori.y = orientation.y.min(PI / 2.0).max(-PI / 2.0);
|
|
|
|
// Wrap camera roll
|
|
|
|
self.ori.z = orientation.z % (2.0 * PI);
|
|
|
|
}
|
|
|
|
|
2019-01-30 12:11:34 +00:00
|
|
|
/// Zoom the camera by the given delta, limiting the input accordingly.
|
|
|
|
pub fn zoom_by(&mut self, delta: f32) {
|
|
|
|
// Clamp camera dist to the 0 <= x <= infinity range
|
2019-05-05 15:17:57 +00:00
|
|
|
self.tgt_dist = (self.tgt_dist + delta).max(0.0);
|
|
|
|
}
|
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Set the distance of the camera from the target (i.e., zoom).
|
2019-05-12 13:02:47 +00:00
|
|
|
pub fn set_distance(&mut self, dist: f32) {
|
|
|
|
self.tgt_dist = dist;
|
|
|
|
}
|
|
|
|
|
2019-05-05 15:17:57 +00:00
|
|
|
pub fn update(&mut self, time: f64) {
|
|
|
|
// This is horribly frame time dependent, but so is most of the game
|
|
|
|
let delta = self.last_time.replace(time).map_or(0.0, |t| time - t);
|
|
|
|
if (self.dist - self.tgt_dist).abs() > 0.01 {
|
|
|
|
self.dist = f32::lerp(self.dist, self.tgt_dist, (delta as f32) / INTERP_TIME);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.focus - self.tgt_focus).magnitude() > 0.01 {
|
|
|
|
self.focus = Vec3::lerp(self.focus, self.tgt_focus, (delta as f32) / INTERP_TIME);
|
|
|
|
}
|
2019-01-30 12:11:34 +00:00
|
|
|
}
|
|
|
|
|
2019-01-12 01:14:58 +00:00
|
|
|
/// Get the focus position of the camera.
|
2019-04-29 20:37:19 +00:00
|
|
|
pub fn get_focus_pos(&self) -> Vec3<f32> {
|
2019-05-05 15:17:57 +00:00
|
|
|
self.tgt_focus
|
2019-04-29 20:37:19 +00:00
|
|
|
}
|
2019-01-12 01:14:58 +00:00
|
|
|
/// Set the focus position of the camera.
|
2019-04-29 20:37:19 +00:00
|
|
|
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) {
|
2019-05-05 15:17:57 +00:00
|
|
|
self.tgt_focus = focus;
|
2019-04-29 20:37:19 +00:00
|
|
|
}
|
2019-01-23 22:39:31 +00:00
|
|
|
|
|
|
|
/// Get the aspect ratio of the camera.
|
2019-04-29 20:37:19 +00:00
|
|
|
pub fn get_aspect_ratio(&self) -> f32 {
|
|
|
|
self.aspect
|
|
|
|
}
|
2019-01-23 22:39:31 +00:00
|
|
|
/// Set the aspect ratio of the camera.
|
2019-04-29 20:37:19 +00:00
|
|
|
pub fn set_aspect_ratio(&mut self, aspect: f32) {
|
2019-05-17 05:13:14 +00:00
|
|
|
self.aspect = if aspect.is_normal() { aspect } else { 1.0 };
|
2019-04-29 20:37:19 +00:00
|
|
|
}
|
2019-03-02 03:48:30 +00:00
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
/// Get the orientation of the camera.
|
2019-04-29 20:37:19 +00:00
|
|
|
pub fn get_orientation(&self) -> Vec3<f32> {
|
|
|
|
self.ori
|
|
|
|
}
|
2019-01-11 23:18:34 +00:00
|
|
|
}
|