Skip to main content

gust_render/
view.rs

1//
2//  Rust file | 2018
3//  Author: Alexandre Fourcat
4//  view.rs
5//  module:
6//! View system.
7//! A view is a point of view on a 2D scene. It's like a camera filming paper.
8//! A view should be defined by sizes and left and down.
9//! ```no_run
10//! use gust::view::View;
11//! use gust::window::Window;
12//! use gust::rect::Rect;
13//!
14//! let window = Window::new(1920, 1080, "View mod");
15//! let view = View::from(Rect::new(500.0, 500.0, 10.0, 10.0));
16//! let view2 = View::from(Rect::new(0.0, 0.0, 500.0, 500.0))
17//! ```
18
19use nalgebra;
20use nalgebra::Matrix4;
21use rect::Rect;
22use {Point, Vector};
23
24/// A View is a 2D camera.
25/// It's the screen viewport.
26/// You can make multiple views and use them as Minimap, 2nd player screen etc...
27/// The view is attached to a gust::Window.
28#[derive(Debug, Clone, PartialEq)]
29pub struct View {
30    projection: Matrix4<f32>,
31    sizes: Vector<f32>,
32    pos: Vector<f32>,
33    screen: Rect<f32>,
34    angle: f32,
35    zoom: f32,
36    need_update: bool,
37}
38
39impl View {
40    /// Create a new View from a pos point and a Rect
41    pub fn new(pos: Point<f32>, rect: Rect<f32>) -> View {
42        View {
43            projection: Matrix4::new_ortho(
44                rect.left as f32,
45                rect.width as f32,
46                rect.top as f32,
47                rect.height as f32,
48                -1.0,
49                1.0,
50            ),
51            zoom: 1.0,
52            angle: 0.0,
53            sizes: Vector::new(rect.width, rect.height),
54            pos,
55            screen: Rect::new(1.0, 1.0, 1.0, 1.0),
56            need_update: false,
57        }
58    }
59
60    /// Reset the rect if you don't want to you can use (set_sizes)[]
61    pub fn reset(&mut self, rect: Rect<f32>) {
62        self.projection = Matrix4::new_orthographic(
63            rect.left as f32,
64            rect.width as f32,
65            rect.top as f32,
66            rect.height as f32,
67            -1.0,
68            1.0,
69        );
70        self.sizes = Vector::new(rect.width, rect.height);
71        self.need_update = true;
72    }
73
74    /// Set pos of the view (usefull for game like 2D Zelda-Like)
75    pub fn set_center(&mut self, pos: Point<f32>) {
76        self.pos.x = pos.x - self.sizes.x / 2.0;
77        self.pos.y = pos.y - self.sizes.y / 2.0;
78        self.need_update = true;
79    }
80
81    /// Set the viewport of the view (the viewport is given as a float factor 0.5 / 1.0 / 0.2 etc)
82    /// That way people can simply handle screen part.
83    pub fn set_viewport(&mut self, viewport: Rect<f32>) {
84        self.screen = viewport;
85    }
86
87    /// Set the size of the rect
88    pub fn set_sizes(&mut self, sizes: Vector<f32>) {
89        self.sizes.x = sizes.x;
90        self.sizes.y = sizes.y;
91    }
92
93    /// Move the view from actual position with the offset `offset`.
94    pub fn translate<T: nalgebra::Scalar + Into<f32>>(&mut self, offset: Vector<T>) {
95        self.pos.x += offset.x.into();
96        self.pos.y += offset.y.into();
97        self.need_update = true;
98    }
99
100    /// Update the view: Apply all transformations.
101    pub fn update(&mut self) {
102        if self.need_update {
103            let width = self.sizes.x * self.zoom;
104            let height = self.sizes.y * self.zoom;
105
106            self.projection = Matrix4::new_ortho(
107                self.pos.x,
108                width + self.pos.x,
109                height + self.pos.y,
110                self.pos.y,
111                -1.0,
112                1.0,
113            );
114            self.need_update = false;
115        }
116    }
117
118    /// Set the view zoom.
119    pub fn set_zoom(&mut self, zoom: f32) {
120        self.zoom = zoom;
121        self.need_update = true;
122    }
123
124    /// Multiply the current zoom by this one.
125    pub fn zoom(&mut self, zoom: f32) {
126        self.zoom *= 1.0 / zoom;
127        self.need_update = true;
128    }
129
130    /// Return zoom.
131    pub fn get_zoom(&self) -> f32 {
132        self.zoom
133    }
134
135    /// Return projection Matrix4.
136    pub fn projection(&self) -> &Matrix4<f32> {
137        &self.projection
138    }
139
140    /// Return sizes in a Vector<f32>.
141    pub fn sizes(&self) -> Vector<f32> {
142        self.sizes
143    }
144
145    /// Return position of the view in a Vector<f32>.
146    pub fn postition(&self) -> Vector<f32> {
147        self.pos
148    }
149}
150
151impl From<Rect<f32>> for View {
152    fn from(rect: Rect<f32>) -> View {
153        let proj = Matrix4::new_ortho(
154            rect.left,
155            rect.width + rect.left,
156            rect.height + rect.top,
157            rect.top,
158            -1.0,
159            1.0,
160        );
161        View {
162            pos: Vector::new(rect.left, rect.top),
163            projection: proj,
164            sizes: Vector::new(rect.width, rect.height),
165            need_update: false,
166            zoom: 1.0,
167            angle: 0.0,
168            screen: Rect::new(0.0, 0.0, 1.0, 1.0),
169        }
170    }
171}
172
173/// TEST implementation on crate type.
174impl Ortho for Matrix4<f32> {}
175
176/// Trait that implement fonction new_ortho for Matrix4.
177trait Ortho {
178    fn new_ortho(
179        left: f32,
180        right: f32,
181        bottom: f32,
182        top: f32,
183        near: f32,
184        far: f32,
185    ) -> Matrix4<f32> {
186        let width = right - left;
187        let height = top - bottom;
188        let a = 2.0 / width;
189        let b = 2.0 / height;
190        let c = -2.0 / (far - near);
191        let tx = -(right + left) / width;
192        let ty = -(top + bottom) / height;
193        let tz = -(far + near) / far - near;
194
195        Matrix4::new(
196            a, 0.0, 0.0, tx, 0.0, b, 0.0, ty, 0.0, 0.0, c, tz, 0.0, 0.0, 0.0, 1.0,
197        )
198    }
199}