aboutsummaryrefslogtreecommitdiff
path: root/src/camera.rs
blob: 768255315733142de37258ee2df8c0fb6e945760 (plain)
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
use cgmath::prelude::*;
use cgmath::{Matrix3, Vector3};

use crate::screen::ScreenIterator;
type Vector = Vector3<f32>;

// The physical screen that camera projects onto
#[derive(Debug, Copy, Clone)]
pub struct Screen {
    pub width: f32,
    pub height: f32,
}

#[derive(Debug, Copy, Clone)]
pub struct Camera {
    pub position: Vector,
    pub direction: Vector,
    pub up: Vector,
    pub distance: f32,
    pub speed: f32,
    pub turn_rate: f32,
    pub screen: Screen,
}

const ASPECT_RATIO: f32 = 2.0 / 3.0;

impl Camera {
    pub fn new(position: Vector, look_at: Vector, angle: f32, distance: f32) -> Self {
        let width = distance * 2.0 * (angle / 2.0).tan();
        let height = width * ASPECT_RATIO;

        Self {
            position,
            direction: (look_at - position).normalize(),
            up: Vector::unit_z(),
            distance,
            screen: Screen { width, height },
            speed: 0.5,
            turn_rate: 60.0,
        }
    }
    pub fn get_screen_iterator(self) -> ScreenIterator {
        // Linear transormation operator for calculating screen position
        // Assumes "initial" screen is perpendicular to OX
        // and it's bottom edge is parallel to OY
        let operator = Matrix3::from_cols(
            self.direction * self.distance,
            self.direction.cross(self.up) * self.screen.width,
            -self.up * self.screen.height,
        );

        ScreenIterator::from_screen_position(
            operator * Vector::new(1.0, -0.5, -0.5),
            operator * Vector::unit_z(),
            operator * Vector::unit_y(),
        )
    }
}