fps_camera/
first_person.rs

1// Original PistonDevelopers/camera_controllers license:
2//
3// The MIT License (MIT)
4//
5// Copyright (c) 2015 PistonDevelopers
6//
7// Permission is hereby granted, free of charge, to any person obtaining a copy
8// of this software and associated documentation files (the "Software"), to deal
9// in the Software without restriction, including without limitation the rights
10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11// copies of the Software, and to permit persons to whom the Software is
12// furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in all
15// copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23// SOFTWARE.
24
25//! A 3D first-person camera type.
26//!
27//! Adapted from PistonDevelopers/camera_controllers under the MIT license
28//! https://github.com/PistonDevelopers/camera_controllers/blob/8edf8a464b57107683c2585bbdc55d9e46994783/src/first_person.rs
29
30use vecmath::traits::{ Float, Radians };
31
32use Camera;
33
34bitflags!(pub struct Actions: u8 {
35    const MOVE_FORWARD  = 0b00000001;
36    const MOVE_BACKWARD = 0b00000010;
37    const STRAFE_LEFT   = 0b00000100;
38    const STRAFE_RIGHT  = 0b00001000;
39    const FLY_UP        = 0b00010000;
40    const FLY_DOWN      = 0b00100000;
41    const MOVE_FASTER   = 0b01000000;
42});
43
44/// First person camera settings.
45pub struct FirstPersonSettings<T=f32> {
46    /// The horizontal movement speed.
47    ///
48    /// This is measured in units per second.
49    pub speed_horizontal: T,
50    /// The vertical movement speed.
51    ///
52    /// This is measured in units per second.
53    pub speed_vertical: T,
54    /// The horizontal mouse sensitivity.
55    ///
56    /// This is a multiplier applied to horizontal mouse movements.
57    pub mouse_sensitivity_horizontal: T,
58    /// The vertical mouse sensitivity.
59    ///
60    /// This is a multiplier applied to vertical mouse movements.
61    pub mouse_sensitivity_vertical: T,
62}
63
64impl<T> Default for FirstPersonSettings<T>
65    where T: Float
66{
67    /// Creates new first person camera settings with wasd defaults.
68    fn default() -> FirstPersonSettings<T> {
69        FirstPersonSettings {
70            speed_horizontal: T::one(),
71            speed_vertical: T::one(),
72            mouse_sensitivity_horizontal: T::one(),
73            mouse_sensitivity_vertical: T::one(),
74        }
75    }
76}
77
78/// Models a flying first person camera.
79pub struct FirstPerson<T=f32> {
80    /// The first person camera settings.
81    pub settings: FirstPersonSettings<T>,
82    /// The yaw angle (in radians).
83    pub yaw: T,
84    /// The pitch angle (in radians).
85    pub pitch: T,
86    /// The position of the camera.
87    pub position: [T; 3],
88    /// The velocity we are moving.
89    pub velocity: T,
90    /// The active actions.
91    pub actions: Actions,
92}
93
94impl<T> FirstPerson<T>
95    where T: Float
96{
97    /// Creates a new first person camera.
98    pub fn new(
99        position: [T; 3],
100        settings: FirstPersonSettings<T>
101    ) -> FirstPerson<T> {
102        let _0: T = T::zero();
103        FirstPerson {
104            settings: settings,
105            yaw: _0,
106            pitch: _0,
107            position: position,
108            velocity: T::one(),
109            actions: Actions::empty(),
110        }
111    }
112
113    /// Computes camera.
114    pub fn camera(&self, dt: T) -> Camera<T> {
115        let dh = dt * self.velocity * self.settings.speed_horizontal;
116        let (dx, dy, dz) = self.movement_direction();
117        let (s, c) = (self.yaw.sin(), self.yaw.cos());
118        let mut camera = Camera::new([
119            self.position[0] + (s * dx - c * dz) * dh,
120            self.position[1] + dy * dt * self.settings.speed_vertical,
121            self.position[2] + (s * dz + c * dx) * dh
122        ]);
123        camera.set_yaw_pitch(self.yaw, self.pitch);
124        camera
125    }
126
127    /// Updates the camera for an elapsed number of seconds.
128    pub fn update(&mut self, dt: T) {
129        let cam = self.camera(dt);
130        self.position = cam.position;
131    }
132
133    /// Updates the camera for a mouse movement.
134    pub fn update_mouse(&mut self, relative_dx: T, relative_dy: T) {
135        let FirstPerson {
136            ref mut yaw, ref mut pitch, ref settings, ..
137        } = *self;
138
139        let dx = relative_dx * settings.mouse_sensitivity_horizontal;
140        let dy = relative_dy * settings.mouse_sensitivity_vertical;
141
142        let pi: T = Radians::_180();
143        let _0 = T::zero();
144        let _1 = T::one();
145        let _2 = _1 + _1;
146        let _3 = _2 + _1;
147        let _4 = _3 + _1;
148        let _360 = T::from_isize(360);
149
150        *yaw = (*yaw - dx / _360 * pi / _4) % (_2 * pi);
151        *pitch = *pitch + dy / _360 * pi / _4;
152        *pitch = (*pitch).min(pi / _2).max(-pi / _2);
153    }
154
155    /// Gets the direction of movement.
156    pub fn movement_direction(&self) -> (T, T, T) {
157        let (mut dx, mut dy, mut dz) = (T::zero(), T::zero(), T::zero());
158
159        let set_axis = |axis: &mut T, positive, negative| {
160            if self.actions.contains(positive) &&
161                self.actions.contains(negative) {
162                *axis = T::zero();
163            } else if self.actions.contains(positive) {
164                *axis = T::one();
165            } else if self.actions.contains(negative) {
166                *axis = -T::one();
167            }
168        };
169
170        set_axis(&mut dx, Actions::MOVE_BACKWARD, Actions::MOVE_FORWARD);
171        set_axis(&mut dz, Actions::STRAFE_LEFT, Actions::STRAFE_RIGHT);
172        set_axis(&mut dy, Actions::FLY_UP, Actions::FLY_DOWN);
173
174        (dx,dy,dz)
175    }
176
177    pub fn enable_actions(&mut self, actions: Actions) {
178        self.actions |= actions;
179    }
180
181    pub fn disable_action(&mut self, action: Actions) {
182        self.actions &= !action;
183    }
184}