geng_core/window/
mod.rs

1use super::*;
2
3mod cursor;
4mod events;
5
6pub use cursor::*;
7pub use events::*;
8
9#[cfg(target_arch = "wasm32")]
10mod js {
11    use super::*;
12
13    #[wasm_bindgen(module = "/src/window/web.js")]
14    extern "C" {
15        pub fn initialize_window(canvas: &web_sys::HtmlCanvasElement);
16        pub fn is_fullscreen() -> bool;
17        pub fn set_fullscreen(canvas: &web_sys::HtmlCanvasElement, fullscreen: bool);
18    }
19}
20
21pub struct Window {
22    #[cfg(target_arch = "wasm32")]
23    canvas: web_sys::HtmlCanvasElement,
24    #[cfg(not(target_arch = "wasm32"))]
25    glutin_window: glutin::WindowedContext<glutin::PossiblyCurrent>,
26    #[cfg(not(target_arch = "wasm32"))]
27    glutin_event_loop: RefCell<glutin::event_loop::EventLoop<()>>,
28    event_handler: Rc<RefCell<Option<Box<dyn FnMut(Event)>>>>,
29    pressed_keys: Rc<RefCell<HashSet<Key>>>,
30    pressed_buttons: Rc<RefCell<HashSet<MouseButton>>>,
31    should_close: Cell<bool>,
32    mouse_pos: Rc<Cell<Vec2<f64>>>,
33    ugli: Rc<Ugli>,
34    #[cfg(not(target_arch = "wasm32"))]
35    is_fullscreen: Cell<bool>,
36}
37
38impl Window {
39    pub fn new(title: &str, vsync: bool) -> Self {
40        #[cfg(target_arch = "wasm32")]
41        let window = {
42            let _ = title;
43            let _ = vsync;
44            let canvas = web_sys::window()
45                .unwrap()
46                .document()
47                .unwrap()
48                .get_element_by_id("geng-canvas")
49                .expect("#geng-canvas not found")
50                .dyn_into::<web_sys::HtmlCanvasElement>()
51                .expect("#geng-canvas is not a canvas");
52            js::initialize_window(&canvas);
53            let ugli = Rc::new(Ugli::create_webgl(&canvas));
54            let window = Self {
55                canvas,
56                event_handler: Rc::new(RefCell::new(None)),
57                ugli,
58                should_close: Cell::new(false),
59                mouse_pos: Rc::new(Cell::new(vec2(0.0, 0.0))),
60                pressed_keys: Rc::new(RefCell::new(HashSet::new())),
61                pressed_buttons: Rc::new(RefCell::new(HashSet::new())),
62            };
63            let event_handler = window.event_handler.clone();
64            let pressed_keys = window.pressed_keys.clone();
65            let pressed_buttons = window.pressed_buttons.clone();
66            let mouse_pos = window.mouse_pos.clone();
67            window.subscribe_events(move |event| {
68                Self::default_handler(&event, &pressed_keys, &pressed_buttons, &mouse_pos);
69                if let Some(ref mut handler) = *event_handler.borrow_mut() {
70                    handler(event);
71                }
72            });
73            window
74        };
75        #[cfg(not(target_arch = "wasm32"))]
76        let window = {
77            let glutin_event_loop = glutin::event_loop::EventLoop::<()>::new();
78            // glutin::ContextBuilder::new(),
79            let glutin_window = glutin::ContextBuilder::new()
80                .with_vsync(vsync)
81                .build_windowed(
82                    glutin::window::WindowBuilder::new().with_title(title), //.with_visibility(false)
83                    &glutin_event_loop,
84                )
85                .unwrap();
86            let glutin_window = unsafe { glutin_window.make_current() }.unwrap();
87            let ugli = Rc::new(Ugli::create_from_glutin(&glutin_window));
88            Self {
89                glutin_window,
90                glutin_event_loop: RefCell::new(glutin_event_loop),
91                event_handler: Rc::new(RefCell::new(None)),
92                ugli,
93                should_close: Cell::new(false),
94                mouse_pos: Rc::new(Cell::new(vec2(0.0, 0.0))),
95                pressed_keys: Rc::new(RefCell::new(HashSet::new())),
96                pressed_buttons: Rc::new(RefCell::new(HashSet::new())),
97                is_fullscreen: Cell::new(false),
98            }
99        };
100        window
101    }
102
103    pub(crate) fn set_event_handler(&self, handler: Box<dyn FnMut(Event)>) {
104        *self.event_handler.borrow_mut() = Some(handler);
105    }
106
107    // #[cfg(not(target_arch = "wasm32"))]
108    // pub fn show(&self) {
109    //     self.glutin_window.window().set_visible(true);
110    // }
111
112    pub fn swap_buffers(&self) {
113        // ugli::sync();
114        #[cfg(not(target_arch = "wasm32"))]
115        {
116            self.glutin_window.swap_buffers().unwrap();
117        }
118        #[cfg(not(target_arch = "wasm32"))]
119        for event in self.internal_get_events() {
120            Self::default_handler(
121                &event,
122                &self.pressed_keys,
123                &self.pressed_buttons,
124                &self.mouse_pos,
125            );
126            if let Some(ref mut handler) = *self.event_handler.borrow_mut() {
127                handler(event);
128            }
129        }
130    }
131
132    fn default_handler(
133        event: &Event,
134        pressed_keys: &RefCell<HashSet<Key>>,
135        pressed_buttons: &RefCell<HashSet<MouseButton>>,
136        mouse_pos: &Cell<Vec2<f64>>,
137    ) {
138        match *event {
139            Event::KeyDown { key } => {
140                pressed_keys.borrow_mut().insert(key);
141            }
142            Event::KeyUp { key } => {
143                pressed_keys.borrow_mut().remove(&key);
144            }
145            Event::MouseMove { position } => {
146                mouse_pos.set(position);
147            }
148            Event::MouseDown { button, .. } => {
149                pressed_buttons.borrow_mut().insert(button);
150            }
151            Event::MouseUp { button, .. } => {
152                pressed_buttons.borrow_mut().remove(&button);
153            }
154            _ => {}
155        }
156    }
157
158    pub fn real_size(&self) -> Vec2<usize> {
159        #[cfg(target_arch = "wasm32")]
160        return {
161            let width = self.canvas.width() as usize;
162            let height = self.canvas.height() as usize;
163            vec2(width, height)
164        };
165        #[cfg(not(target_arch = "wasm32"))]
166        return {
167            let size = self.glutin_window.window().inner_size();
168            let (width, height) = (size.width, size.height);
169            vec2(width as usize, height as usize)
170        };
171    }
172    pub fn size(&self) -> Vec2<usize> {
173        self.real_size().map(|x| x.max(1))
174    }
175
176    pub fn ugli(&self) -> &Rc<Ugli> {
177        self.ugli._set_size(self.size());
178        &self.ugli
179    }
180
181    pub fn should_close(&self) -> bool {
182        self.should_close.get()
183    }
184
185    pub fn is_key_pressed(&self, key: Key) -> bool {
186        self.pressed_keys.borrow().contains(&key)
187    }
188
189    pub fn is_button_pressed(&self, button: MouseButton) -> bool {
190        self.pressed_buttons.borrow().contains(&button)
191    }
192
193    pub fn pressed_keys(&self) -> HashSet<Key> {
194        self.pressed_keys.borrow().clone()
195    }
196
197    pub fn pressed_buttons(&self) -> HashSet<MouseButton> {
198        self.pressed_buttons.borrow().clone()
199    }
200
201    pub fn mouse_pos(&self) -> Vec2<f64> {
202        self.mouse_pos.get()
203    }
204
205    pub fn set_fullscreen(&self, fullscreen: bool) {
206        #[cfg(target_arch = "wasm32")]
207        js::set_fullscreen(&self.canvas, fullscreen);
208        #[cfg(not(target_arch = "wasm32"))]
209        {
210            self.glutin_window.window().set_fullscreen(if fullscreen {
211                Some(glutin::window::Fullscreen::Borderless(
212                    self.glutin_window.window().current_monitor(),
213                ))
214            } else {
215                None
216            });
217            self.is_fullscreen.set(fullscreen);
218        }
219    }
220
221    pub fn is_fullscreen(&self) -> bool {
222        #[cfg(target_arch = "wasm32")]
223        return js::is_fullscreen();
224        #[cfg(not(target_arch = "wasm32"))]
225        self.is_fullscreen.get()
226    }
227
228    pub fn toggle_fullscreen(&self) {
229        self.set_fullscreen(!self.is_fullscreen());
230    }
231}