Fix a clippy warning about superfluous match references
[mandelwow.git] / support / camera.rs
1 use cgmath::{Matrix4, Vector4};
2 use cgmath::conv::array4x4;
3 use glium;
4 use glium::glutin::event::{ ElementState, VirtualKeyCode, WindowEvent };
5 use std::f32;
6 use std::f32::consts::PI;
7 use crate::support::vec3::Vec3;
8 use crate::support::vec3::norm;
9
10 #[derive(Default)]
11 pub struct CameraState {
12     aspect: f32,
13     pos: Vec3,
14     dir: Vec3,
15
16     moving_up: bool,
17     moving_left: bool,
18     moving_down: bool,
19     moving_right: bool,
20     moving_forward: bool,
21     moving_backward: bool,
22     turning_up: bool,
23     turning_left: bool,
24     turning_down: bool,
25     turning_right: bool,
26
27     mouse_x: i32,
28     mouse_y: i32,
29     rel_x: i32,
30     rel_y: i32,
31 }
32
33 impl CameraState {
34     pub fn new() -> CameraState {
35         CameraState {
36             aspect: 1280.0 / 720.0,
37             pos: Vec3(0.0, 0.0, 0.0),
38             dir: Vec3(0.0, 0.0, -1.0),
39             mouse_x: -1,
40             mouse_y: -1,
41             .. Default::default()
42         }
43     }
44
45     pub fn set_pos(&mut self, pos: Vec3) {
46         self.pos = pos;
47     }
48
49     pub fn get_pos(&self) -> Vec3 {
50         self.pos
51     }
52
53     pub fn set_dir(&mut self, dir: Vec3) {
54         self.dir = dir;
55     }
56
57     pub fn get_persp_mat(&self) -> Matrix4<f32> {
58         let fov: f32 = PI / 2.0;
59         let zfar = 1024.0;
60         let znear = 0.1;
61
62         let f = 1.0 / (fov / 2.0).tan();
63
64         // note: remember that this is column-major, so the lines of code are actually columns
65         Matrix4 {
66             x: Vector4{ x: f / self.aspect, y: 0.0, z:  0.0,                           w: 0.0 },
67             y: Vector4{ x: 0.0,             y: f,   z:  0.0,                           w: 0.0 },
68             z: Vector4{ x: 0.0,             y: 0.0, z:  (zfar+znear)/(zfar-znear),     w: 1.0 },
69             w: Vector4{ x: 0.0,             y: 0.0, z: -(2.0*zfar*znear)/(zfar-znear), w: 0.0 },
70         }
71     }
72
73     pub fn get_view_mat(&self) -> Matrix4<f32> {
74         let f = norm(&self.dir);
75
76         let up = Vec3(0.0, 1.0, 0.0);
77
78         let s = Vec3(f.1 * up.2 - f.2 * up.1,
79                      f.2 * up.0 - f.0 * up.2,
80                      f.0 * up.1 - f.1 * up.0);
81         let sn = norm(&s);
82
83         let u = (sn.1 * f.2 - sn.2 * f.1,
84                  sn.2 * f.0 - sn.0 * f.2,
85                  sn.0 * f.1 - sn.1 * f.0);
86
87         let p = (-self.pos.0 * s.0 - self.pos.1 * s.1 - self.pos.2 * s.2,
88                  -self.pos.0 * u.0 - self.pos.1 * u.1 - self.pos.2 * u.2,
89                  -self.pos.0 * f.0 - self.pos.1 * f.1 - self.pos.2 * f.2);
90
91         // note: remember that this is column-major, so the lines of code are actually columns
92         Matrix4{
93             x: Vector4{ x: sn.0, y: u.0, z: f.0, w: 0.0 },
94             y: Vector4{ x: sn.1, y: u.1, z: f.1, w: 0.0 },
95             z: Vector4{ x: sn.2, y: u.2, z: f.2, w: 0.0 },
96             w: Vector4{ x:  p.0, y: p.1, z: p.2, w: 1.0 },
97         }
98     }
99
100     pub fn get_perspview(&self) -> [[f32; 4]; 4] {
101         array4x4(self.get_persp_mat() * self.get_view_mat())
102     }
103
104     pub fn get_perspective(&self) -> [[f32; 4]; 4] {
105         array4x4(self.get_persp_mat())
106     }
107
108     pub fn get_view(&self) -> [[f32; 4]; 4] {
109         array4x4(self.get_view_mat())
110     }
111
112     pub fn update(&mut self) {
113         let f = norm(&self.dir);
114
115         let up = Vec3(0.0, 1.0, 0.0);
116
117         let s = Vec3(f.1 * up.2 - f.2 * up.1,
118                      f.2 * up.0 - f.0 * up.2,
119                      f.0 * up.1 - f.1 * up.0);
120
121         let s = norm(&s);
122
123         let u = Vec3(s.1 * f.2 - s.2 * f.1,
124                      s.2 * f.0 - s.0 * f.2,
125                      s.0 * f.1 - s.1 * f.0);
126
127         let walk_speed = 0.01;
128         let strife_speed = 0.02;
129         let pan_speed = 0.001;
130
131         if self.moving_up {
132             self.pos += u * strife_speed;
133         }
134         if self.moving_down {
135             self.pos -= u * strife_speed;
136         }
137         if self.moving_left {
138             self.pos -= s * strife_speed;
139         }
140         if self.moving_right {
141             self.pos += s * strife_speed;
142         }
143         if self.moving_forward {
144             self.pos += f * walk_speed;
145         }
146         if self.moving_backward {
147             self.pos -= f * walk_speed;
148         }
149
150         if self.turning_left { self.rel_x -= 8; }
151         if self.turning_right { self.rel_x += 8; }
152         if self.turning_up { self.rel_y -= 2; }
153         if self.turning_down { self.rel_y += 2; }
154         let vx = -pan_speed * self.rel_x as f32;
155         let vy = -pan_speed * self.rel_y as f32;
156         self.dir = Vec3(f.0 * vx.cos() + f.2 * vx.sin(),
157                         f.1 * vy.cos() - f.2 * vy.sin(),
158                         f.1 * vy.sin() - f.0 * vx.sin() + f.2 * vx.cos() * vy.cos());
159         self.rel_x = 0;
160         self.rel_y = 0;
161
162         //println!("camera_pos = {:?}", self.pos);
163         //println!("camera_dir = {:?}", self.dir);
164     }
165
166     pub fn process_input(&mut self, event: &WindowEvent) {
167         //println!("camera event={:?}", event);
168         match event {
169             WindowEvent::CursorMoved { position, .. }  => {
170                 let (x, y) = (position.x as i32, position.y as i32);
171                 if self.mouse_x == -1 {
172                     // Set initial absolute position.
173                     self.mouse_x = x;
174                     self.mouse_y = y;
175                 }
176                 self.rel_x += x - self.mouse_x;
177                 self.rel_y += y - self.mouse_y;
178                 self.mouse_x = x;
179                 self.mouse_y = y;
180             }
181             WindowEvent::KeyboardInput { input, .. } => {
182                 let pressed = input.state == ElementState::Pressed;
183                 let key = match input.virtual_keycode {
184                     Some(key) => key,
185                     None => return,
186                 };
187                 match key {
188                     VirtualKeyCode::Left => self.moving_left = pressed,
189                     VirtualKeyCode::Right => self.moving_right = pressed,
190                     VirtualKeyCode::Up => self.moving_up = pressed,
191                     VirtualKeyCode::Down => self.moving_down = pressed,
192                     VirtualKeyCode::W => self.moving_forward = pressed,
193                     VirtualKeyCode::S => self.moving_backward = pressed,
194                     VirtualKeyCode::A => self.turning_left = pressed,
195                     VirtualKeyCode::D => self.turning_right = pressed,
196                     VirtualKeyCode::R => self.turning_up = pressed,
197                     VirtualKeyCode::F => self.turning_down = pressed,
198                     _ => (),
199                 }
200             },
201             _ => (),
202         }
203     }
204 }