gust_render/
window.rs

1//!  Window module
2// Alexandre Fourcat 2018
3// window.rs
4// Description:
5//
6
7static DEFAULT_HEIGHT: u32 = 900;
8static DEFAULT_WIDTH: u32 = 1600;
9
10extern crate gl;
11extern crate glfw;
12
13use color::Color;
14use draw;
15use draw::{Drawable, DrawableMut, Drawer};
16use event::{EventReceiver, EventType};
17use glfw::Context;
18use nalgebra;
19use nalgebra::Matrix4;
20use rect::Rect;
21use std::rc::Rc;
22use std::sync::mpsc::Receiver;
23use std::sync::Mutex;
24use view::View;
25use Vector;
26
27static DEFAULT_FPS: u32 = 60;
28
29lazy_static! {
30    static ref DEFAULT_DELTA: f64 = 1.0 / f64::from(DEFAULT_FPS);
31}
32
33/// Window struct
34/// Define a struct by many thing in glfw
35pub struct Window {
36    pub height: u32,
37    pub width: u32,
38    event: Rc<Receiver<(f64, glfw::WindowEvent)>>,
39    pub(super) win: glfw::Window,
40    clear_color: Color,
41    already_init: bool,
42    view: View,
43    fps_limit: u32,
44}
45
46lazy_static! {
47    static ref GLFW_INSTANCE: Mutex<glfw::Glfw> =
48        Mutex::new(glfw::init(glfw::FAIL_ON_ERRORS).unwrap());
49}
50
51/// Window structure implementation
52impl<'a> Window {
53    /// Create a new window by default
54    pub fn new(width: u32, height: u32, name: &str) -> Window {
55        // Init the glfw system
56
57        let mut glfw = GLFW_INSTANCE.lock().unwrap();
58
59        glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
60        glfw.window_hint(glfw::WindowHint::OpenGlProfile(
61            glfw::OpenGlProfileHint::Core,
62        ));
63
64        // Create window from Glfw method create_window
65        // Return the glfw::WindowEvent enum and a window
66        // That we are trying to wrap in this code
67        let (mut win, evt) = glfw
68            .create_window(width, height, name, glfw::WindowMode::Windowed)
69            .unwrap();
70
71        // Load all the gl function from the user configuration
72        gl::load_with(|s| win.get_proc_address(s) as *const _);
73        win.set_cursor_mode(glfw::CursorMode::Normal);
74
75        unsafe {
76            gl::Viewport(0, 0, width as i32, height as i32);
77            gl::Enable(gl::CULL_FACE);
78            gl::Enable(gl::BLEND);
79            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
80        }
81
82        glfw.set_swap_interval(glfw::SwapInterval::Sync(1));
83
84        Window {
85            view: View::from(Rect::new(0.0, 0.0, width as f32, height as f32)),
86            height,
87            width,
88            win,
89            event: Rc::new(evt),
90            clear_color: Color::new(1.0, 1.0, 1.0),
91            already_init: true,
92            fps_limit: self::DEFAULT_FPS,
93        }
94    }
95
96    pub fn set_mouse_pos<T: nalgebra::Scalar + Into<f32>>(&mut self, vec: Vector<T>) {
97        self.win
98            .set_cursor_pos(f64::from(vec.x.into()), f64::from(vec.y.into()))
99    }
100
101    pub fn poll<T: Into<Option<EventType>>>(&mut self, event: T) {
102        Self::match_event_type(self, event.into(), true);
103    }
104
105    pub fn unpoll<T: Into<Option<EventType>>>(&mut self, event: T) {
106        Self::match_event_type(self, event.into(), false);
107    }
108
109    fn match_event_type(window: &mut Window, event: Option<EventType>, active: bool) {
110        if event.is_none() {
111            window.win.set_all_polling(active);
112        } else {
113            match event.unwrap() {
114                EventType::Key => window.win.set_key_polling(active),
115                EventType::Pos => window.win.set_pos_polling(active),
116                EventType::Close => window.win.set_close_polling(active),
117                EventType::Size => window.win.set_size_polling(active),
118                EventType::Refresh => window.win.set_refresh_polling(active),
119                EventType::Focus => window.win.set_focus_polling(active),
120                EventType::Char => window.win.set_char_polling(active),
121                EventType::CharMods => window.win.set_char_mods_polling(active),
122                EventType::MouseButton => window.win.set_mouse_button_polling(active),
123                EventType::CursorPos => window.win.set_cursor_pos_polling(active),
124                EventType::CursorEnter => window.win.set_cursor_enter_polling(active),
125                EventType::Scroll => window.win.set_scroll_polling(active),
126                EventType::FrameBuffer => window.win.set_framebuffer_size_polling(active),
127            }
128        }
129    }
130
131    pub fn mouse_pos(&self) -> Vector<f32> {
132        let pos = self.win.get_cursor_pos();
133        Vector::new(pos.0 as f32, pos.1 as f32)
134    }
135
136    /// Change cursor to hidden mode
137    pub fn hide_cursor(&mut self) {
138        self.win.set_cursor_mode(glfw::CursorMode::Hidden);
139    }
140
141    /// Change cursor to disabled mode
142    pub fn disable_cursor(&mut self) {
143        self.win.set_cursor_mode(glfw::CursorMode::Disabled);
144    }
145
146    /// Change cursor to normal mode
147    pub fn enable_cursor(&mut self) {
148        self.win.set_cursor_mode(glfw::CursorMode::Normal);
149    }
150
151    /// Check if the window is open
152    pub fn is_open(&self) -> bool {
153        !self.win.should_close()
154    }
155
156    /// Poll the event
157    pub fn poll_events(&mut self) {
158        GLFW_INSTANCE.lock().unwrap().poll_events();
159    }
160
161    /// Set clear color
162    pub fn set_clear_color(&mut self, new_color: Color) {
163        self.clear_color = new_color;
164    }
165
166    /// Close window
167    pub fn close(&mut self) {
168        self.win.set_should_close(true);
169    }
170
171    /// Clear screen
172    pub fn clear(&self) {
173        unsafe {
174            gl::ClearColor(
175                self.clear_color.0,
176                self.clear_color.1,
177                self.clear_color.2,
178                self.clear_color.3,
179            );
180            gl::Clear(gl::COLOR_BUFFER_BIT);
181        }
182    }
183
184    /// Activate window on OpenGl context
185    pub fn active(&mut self) -> bool {
186        GLFW_INSTANCE
187            .lock()
188            .unwrap()
189            .make_context_current(Some(&self.win));
190        true
191    }
192
193    pub fn set_view(&mut self, view: View) {
194        self.view = view;
195    }
196
197    /// Display the screen
198    pub fn display(&mut self) {
199        self.win.swap_buffers();
200    }
201
202    /// Init basic gl modules
203    fn init_gl() {
204        unimplemented!();
205    }
206
207    /// Should not be used (low level glfw function)
208    fn set_input_mode(&self, im: &InputMode) {
209        let (mode, value) = im.to_i32();
210        unsafe {
211            glfw::ffi::glfwSetInputMode(self.win.window_ptr(), mode, value);
212        }
213    }
214
215    /// Should not be used (low level glfw function)
216    fn input_mode(&self, im: &InputMode) -> InputMode {
217        unsafe {
218            InputMode::from(glfw::ffi::glfwGetInputMode(
219                self.win.window_ptr(),
220                im.to_i32().0,
221            ))
222        }
223    }
224
225    pub fn view(&self) -> &View {
226        &self.view
227    }
228
229    pub fn view_mut(&mut self) -> &mut View {
230        &mut self.view
231    }
232
233    pub fn set_fps_limit(&mut self, limit: u32) -> u32 {
234        let old = self.fps_limit;
235        self.fps_limit = limit;
236        old
237    }
238
239    pub fn fps_limit(&self) -> u32 {
240        self.fps_limit
241    }
242
243    pub fn event(&self) -> &EventReceiver {
244        &self.event
245    }
246
247    pub fn event_mut(&mut self) -> &mut EventReceiver {
248        &mut self.event
249    }
250}
251
252impl Drawer for Window {
253    fn draw<T: Drawable>(&mut self, drawable: &T) {
254        self.active();
255        drawable.draw(self);
256    }
257
258    #[inline]
259    fn draw_mut<T: DrawableMut>(&mut self, drawable: &mut T) {
260        self.active();
261        drawable.draw_mut(self);
262    }
263
264    #[inline]
265    fn draw_with_context<T: Drawable>(&mut self, drawable: &mut T, context: &mut draw::Context) {
266        self.active();
267        drawable.draw_with_context(context);
268    }
269
270    #[inline]
271    fn draw_with_context_mut<T: DrawableMut>(
272        &mut self,
273        drawable: &mut T,
274        context: &mut draw::Context,
275    ) {
276        self.active();
277        drawable.draw_with_context(context);
278    }
279
280    #[inline]
281    fn get_sizes(&self) -> Vector<f32> {
282        Vector::new(self.width as f32, self.height as f32)
283    }
284
285    #[inline]
286    fn get_center(&self) -> Vector<f32> {
287        let view_pos = self.view().postition();
288        let view_zoom = self.view().get_zoom();
289
290        println!("View pos: {:?}", view_pos);
291        Vector::new(
292            (self.width as f32 / (2.0 * (1.0 / view_zoom))) + view_pos.x,
293            (self.height as f32 / (2.0 * (1.0 / view_zoom))) + view_pos.y,
294        )
295    }
296
297    fn projection(&self) -> &Matrix4<f32> {
298        self.view.projection()
299    }
300}
301
302/// Default trait implementation for window
303impl Default for Window {
304    fn default() -> Window {
305        let (mut win, evt) = GLFW_INSTANCE
306            .lock()
307            .unwrap()
308            .create_window(
309                DEFAULT_HEIGHT as u32,
310                DEFAULT_WIDTH as u32,
311                "Gust",
312                glfw::WindowMode::Windowed,
313            )
314            .unwrap();
315
316        gl::load_with(|s| win.get_proc_address(s) as *const _);
317
318        Window {
319            view: View::from(Rect::new(
320                0.0,
321                0.0,
322                DEFAULT_WIDTH as f32,
323                DEFAULT_HEIGHT as f32,
324            )),
325            height: DEFAULT_HEIGHT,
326            width: DEFAULT_WIDTH,
327            win,
328            event: Rc::new(evt),
329            clear_color: Color::new(1.0, 1.0, 1.0),
330            already_init: true,
331            fps_limit: self::DEFAULT_FPS,
332        }
333    }
334}
335
336pub enum InputMode {
337    CursorMode(InputState),
338    StickMouseButtons,
339    StickKeys,
340    NotDefined,
341}
342
343impl InputMode {
344    fn to_i32(&self) -> (i32, i32) {
345        match self {
346            InputMode::CursorMode(a) => (0x0003_3001, a as *const _ as i32),
347            InputMode::StickKeys => (0x0003_3002, 1),
348            InputMode::StickMouseButtons => (0x0003_3003, 1),
349            InputMode::NotDefined => (-1, -1),
350        }
351    }
352}
353
354impl From<i32> for InputMode {
355    fn from(value: i32) -> InputMode {
356        match value {
357            0x0003_3001 => InputMode::CursorMode(InputState::Normal),
358            0x0003_3002 => InputMode::StickKeys,
359            0x0003_3003 => InputMode::StickMouseButtons,
360            _ => InputMode::NotDefined,
361        }
362    }
363}
364
365pub enum InputState {
366    Normal = 0x0003_4001,
367    Hidden = 0x0003_4002,
368    Disable = 0x0003_4003,
369}