1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// This file is part of Carambolage.

// Carambolage is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Carambolage is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Carambolage.  If not, see <http://www.gnu.org/licenses/>.
use log::info;
use nalgebra::{clamp, Matrix4, Point3, Vector3};
use serde_derive::{Deserialize, Serialize};
use util::Lerp;

/// Camera to calculate the view matrix and follow ingame objects.
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct Camera {
    // Parameter to create view matrix.
    position: Vector3<f32>,
    focus: Vector3<f32>,
    up: Vector3<f32>,

    // Internal parameter.
    height: f32,
    height_min: f32,
    height_max: f32,
    speed: f32,

    // Parameter for camera movement.
    focus_goal: Vector3<f32>,
    height_goal: f32,
}

impl Camera {
    /// Create a new `Camera` with fixed values.
    pub fn new() -> Camera {
        info!("Camera::new()");
        let height = 50.;
        Camera {
            position: Vector3::new(0., 0., height),
            focus: Vector3::new(0., 0., 0.),
            up: Vector3::new(0., 1., 0.),
            height,
            height_min: 30.,
            height_max: 140.,
            speed: 1.8,

            focus_goal: Vector3::new(0., 0., 0.),
            height_goal: height,
        }
    }

    /// Update the cameras position relative to the delta time `dt`.
    pub fn update(&mut self, dt: f32) {
        self.focus = Vector3::lerp(&self.focus, &self.focus_goal, self.speed * dt);
        self.height = f32::lerp(&self.height, &self.height_goal, self.speed * dt);
        self.position = self.focus + Vector3::new(0., 0., self.height);
    }

    /// Smooth transition to the focus goal postion.
    pub fn move_to_focus(&mut self, position: Vector3<f32>) {
        self.focus_goal = position;
    }

    /// Set the focus goal and the camera instantaneously.
    pub fn _set_focus(&mut self, position: Vector3<f32>) {
        self.focus_goal = position;
        self.focus = position;
        self.position = position + Vector3::new(0., 0., self.height);
    }

    /// Smooth transition to the camera height goal.
    pub fn move_to_height(&mut self, distance: f32) {
        self.height_goal = clamp(distance, self.height_min, self.height_max);
    }

    /// Set the camera height instantaneously.
    pub fn _set_height(&mut self, distance: f32) {
        self.height_goal = clamp(distance, self.height_min, self.height_max);
        self.height = self.height_goal;
    }

    /// Get the view matrix, calculated from camera values.
    pub fn get_viewmatrix(&self) -> Matrix4<f32> {
        Matrix4::look_at_rh(
            &Point3::from_coordinates(self.position + Vector3::new(0., -5., 0.)),
            &Point3::from_coordinates(self.focus_goal),
            &self.up,
        )
    }
}