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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use reverie_util::math::{
    self,
    nalgebra::{Matrix4, Point3, Vector3},
    Deg, Rad,
};

use crate::{
    gl::Gl,
    shader::Program,
    texture::ImageLoadInfo,
    vao::{Phong3DRenderer, Phong3DRenderingInfo, PhongRenderingInfo, Renderer, Vao},
};

#[derive(Debug)]
pub struct Camera {
    pos: Point3<f32>,
    yaw: Rad<f32>,
    pitch: Rad<f32>,
    fov: Deg<f32>,
    gl: Gl,
    renderer: Phong3DRenderer,
}

impl Camera {
    pub fn new(gl: Gl, pos: Point3<f32>, yaw: Rad<f32>, pitch: Rad<f32>, fov: Deg<f32>) -> Self {
        let shader = Program::default_uv(gl.clone()).unwrap();
        let renderer = Phong3DRenderer::new(shader);
        Self {
            pos,
            yaw,
            pitch,
            fov,
            gl,
            renderer,
        }
    }

    pub fn render(
        &self,
        vao: &Vao,
        model_matrix: &Matrix4<f32>,
        width: u32,
        height: u32,
        phong_info: &PhongRenderingInfo,
        block_atlas_texture: &ImageLoadInfo,
    ) {
        let view_matrix = self.view_matrix();
        let projection_matrix = self.projection_matrix(width, height);

        let info = &Phong3DRenderingInfo {
            phong: phong_info,
            model_matrix,
            view_matrix: &view_matrix,
            projection_matrix: &projection_matrix,
            camera_pos: &self.pos,
            texture: block_atlas_texture,
        };
        self.renderer.render(self.gl.clone(), vao, info);
    }

    pub fn view_matrix(&self) -> Matrix4<f32> {
        let (front, _right, up) = math::calc_front_right_up(self.yaw, self.pitch);
        Matrix4::<f32>::look_at_rh(&self.pos, &(self.pos + front), &up)
    }

    pub fn projection_matrix(&self, width: u32, height: u32) -> Matrix4<f32> {
        Matrix4::new_perspective(width as f32 / height as f32, self.fov.to_rad().into(), 0.1, 100.0)
    }

    pub fn set_pos(&mut self, pos: Point3<f32>) {
        self.pos = pos;
    }

    pub fn move_pos(&mut self, d: Vector3<f32>) {
        self.pos += d;
    }

    pub fn set_yaw(&mut self, yaw: Rad<f32>) {
        self.yaw = yaw;
    }

    pub fn add_yaw(&mut self, yaw_d: Rad<f32>) {
        self.yaw += yaw_d;
    }

    pub fn set_pitch(&mut self, pitch: Rad<f32>) {
        self.pitch = pitch;
    }

    pub fn add_pitch(&mut self, pitch_d: Rad<f32>) {
        self.pitch += pitch_d;
    }

    pub fn set_fov(&mut self, fov: Deg<f32>) {
        self.fov = fov;
    }

    pub fn pos(&self) -> Point3<f32> {
        self.pos
    }

    pub fn yaw(&self) -> Rad<f32> {
        self.yaw
    }

    pub fn pitch(&self) -> Rad<f32> {
        self.pitch
    }

    pub fn fov(&self) -> Deg<f32> {
        self.fov
    }
}