1use std;
4use std::convert::TryFrom;
5use std::time;
6use log;
7
8use nsys::{self, gl, math::Vector2};
9use nsys::gl::glium::{self, glutin};
10use nsys::gl::winit;
11
12use crate::prelude::*;
13use super::{Graphics, Presentation};
14
15pub mod remote;
16pub mod render;
17
18pub use self::remote::Remote;
19
20pub const RESOURCE_TEXTURES_16X16 : u16 = 0;
21pub const RESOURCE_TEXTURES_64X64 : u16 = 1;
22pub const RESOURCE_TEXTURES_ANYSIZE : u16 = 2;
23
24pub const POINTER_TEXTURE_INDEX : u16 = 0;
25
26pub struct Opengl {
28 pub draw_crosshair : bool,
29 pub inner : (winit::event_loop::EventLoop <()>, gl::Render),
30 input_state : InputState,
31 tileset_id : Option <gl::render::resource::DefaultTilesetId>,
32 glium_frame : Option <glium::Frame>,
33 frame : u64,
34 screen_tiles : Option <NodeId>
35}
36
37pub (crate) struct InputState {
38 pub dimensions : view::dimensions::Pixel,
39 pub modifiers : winit::keyboard::ModifiersState,
42 pub pointer_hv : (f32, f32),
46 pub pointer_sensitivity : f32
47}
48
49pub (crate) struct InputHandler <'a> {
50 pub input_buffer : &'a mut Vec <view::Input>,
51 pub input_state : &'a mut InputState,
52}
53
54pub fn log_glium_info (
56 glium_display : &glium::Display <glutin::surface::WindowSurface>
57) {
58 let glium_info = gl::info::Glium::new (glium_display);
59 log::info!("{:#?}", glium_info);
60}
61
62impl Opengl {
63 #[inline]
64 pub fn inner (&self) -> &(winit::event_loop::EventLoop <()>, gl::Render) {
65 &self.inner
66 }
67 #[inline]
68 pub fn inner_mut (&mut self)
69 -> &mut (winit::event_loop::EventLoop <()>, gl::Render)
70 {
71 &mut self.inner
72 }
73 #[inline]
74 pub fn frame (&self) -> u64 {
75 self.frame
76 }
77 #[inline]
78 pub fn screen_tiles_id (&self) -> &NodeId {
79 self.screen_tiles.as_ref().unwrap()
80 }
81 #[inline]
82 pub fn dimensions (&self) -> view::dimensions::Pixel {
83 let inner_size : (u32, u32) =
84 self.inner.1.window.inner_size().into();
85 Vector2::from (inner_size).into()
86 }
87 pub fn pointer_sentivity (&self) -> f32 {
88 self.input_state.pointer_sensitivity
89 }
90 pub fn set_pointer_sensitivity (&mut self, pointer_sensitivity : f32) {
91 self.input_state.pointer_sensitivity = pointer_sensitivity
92 }
93 pub fn load_pointer (&mut self,
94 key : gl::render::resource::PointerTextureIndexRepr,
95 bytes : &[u8],
96 offset : Vector2 <i16>
97 ) {
98 let render = &mut self.inner_mut().1;
99 render::load_pointer (render, key, bytes, offset);
100 }
101 pub fn load_textures (&mut self,
102 textures_16x16 : &[&'static str],
103 textures_64x64 : &[&'static str],
104 textures_anysize : &[&'static str]
105 ) {
106 render::load_textures (
107 &mut self.inner.1, textures_16x16, textures_64x64, textures_anysize)
108 }
109}
110
111impl std::fmt::Debug for Opengl {
112 fn fmt (&self, f : &mut std::fmt::Formatter) -> Result <(), std::fmt::Error> {
113 write!(f, "Opengl {{ inner: ({:?}, Render), frame: {} }}",
114 self.inner.0, self.frame)
115 }
116}
117
118impl Default for Opengl {
119 fn default() -> Self {
120 let tileset_id =
122 Some (gl::render::resource::DefaultTilesetId::EasciiAcorn128);
123 let input_state = InputState::new();
124 let inner = {
125 let (event_loop, window, _config, display) =
126 gl::init::glium_init_gl33core ("Gooey Opengl Window");
127 window.set_cursor_visible (false);
129 window.set_cursor_grab (winit::window::CursorGrabMode::Confined).unwrap();
130 let render =
131 gl::Render::<gl::render::resource::Default>::new (display, window);
132 let [tile_width, tile_height] =
134 render.resource.tile_dimensions (tileset_id.unwrap_or_default());
135 unsafe {
136 std::env::set_var ("GOOEY_TILE_WIDTH", tile_width.to_string());
137 std::env::set_var ("GOOEY_TILE_HEIGHT", tile_height.to_string());
138 }
139 (event_loop, render)
140 };
141 Opengl {
142 inner, input_state, tileset_id,
143 glium_frame: None,
144 frame: 0,
145 screen_tiles: None,
146 draw_crosshair: false
147 }
148 }
149}
150
151impl Graphics for Opengl { }
152impl Presentation for Opengl {
153 fn with_root (root : View, _id : NodeId) -> Self {
155 use gl::render::resource::{draw2d, MAIN_VIEWPORT};
156 let mut opengl = Self::default();
157 {
158 let draw_crosshair = opengl.draw_crosshair;
159 let render = &mut opengl.inner_mut().1;
160 render::set_screen_view (render, &root);
161 let resources = draw2d::ViewportResources {
162 draw_crosshair, .. Default::default()
163 };
164 render.resource.draw2d.viewport_resources_set (MAIN_VIEWPORT, resources);
165 }
166 log::debug!("opengl with root: {:?}", opengl);
167 opengl
168 }
169
170 fn make_interface <A : Application> () -> Interface <A, Self> {
173 let screen = {
174 let mut screen = frame::screen::PixelBuilder::<A>::new()
177 .anchor (Alignment::pixel())
178 .build_element();
179 let canvas = Canvas::try_ref_mut (&mut screen.view.component).unwrap();
181 canvas.coordinates.modify_dimensions_horizontal (1);
182 canvas.coordinates.modify_dimensions_vertical (1);
183 screen
184 };
185 let mut interface = Interface::<A, Opengl>::with_root (screen);
187 let screen_id = interface.root_id().clone();
189 let screen_tiles = frame::free::Builder::<A>::new (
190 interface.elements(), &screen_id
191 ) .layout (layout::Free {
192 size: Size::fill(), .. layout::Free::default_tile()
193 }.into())
194 .clear_color (canvas::ClearColor::Fixed (None))
195 .coord_kind_override (coordinates::Kind::Tile)
196 .build_element();
197 let tiles_id =
198 match interface.action (&screen_id,
199 Action::create_singleton (screen_tiles, CreateOrder::Append)
200 ).next().unwrap() {
201 (_, Event::Create (_, id, _)) => id,
202 _ => unreachable!()
203 };
204 interface.presentation.screen_tiles = Some (tiles_id);
205 interface
206 }
207
208 fn get_input (&mut self, input_buffer : &mut Vec <view::Input>) {
209 use winit::platform::pump_events::EventLoopExtPumpEvents;
210 log::trace!("get input...");
211 self.inner.0.pump_app_events (
214 Some (time::Duration::ZERO),
215 &mut InputHandler { input_buffer, input_state: &mut self.input_state });
216 log::trace!("...get input");
217 }
218
219 fn display_view <V : AsRef <View>> (&mut self,
220 view_tree : &Tree <V>,
221 _display_values : std::vec::Drain <(NodeId, view::Display)>
222 ) {
223 let tileset_id = self.tileset_id;
225 let draw_crosshair = self.draw_crosshair;
226 render::update (&mut self.inner_mut().1, tileset_id, view_tree,
227 draw_crosshair);
228 self.inner.1.do_frame (self.glium_frame.as_mut());
230 self.frame += 1;
231 log::trace!("...display view");
232 }
233}
234
235impl <'a> InputHandler <'a> {
236 fn handle_event (&mut self, event : winit::event::Event <()>) {
237 match self.input_state.try_convert_winit_event (event) {
238 Ok (input) => {
239 log::debug!("input: {:?}", input);
240 self.input_buffer.extend (input)
241 }
242 Err (event) => log::trace!("ignored winit event: {:?}", event)
243 }
244 }
245}
246
247impl InputState {
248 fn new() -> Self {
249 InputState {
250 dimensions: Default::default(),
251 modifiers: Default::default(),
252 pointer_hv: (-1.0, -1.0),
255 pointer_sensitivity: 1.0
256 }
257 }
258 fn try_convert_winit_event <T> (&mut self, event : winit::event::Event <T>)
262 -> Result <Vec <view::Input>, winit::event::Event <T>>
263 where T : std::fmt::Debug
264 {
265 use winit::event::{self, Event};
266 use view::input;
267 log::trace!("winit event: {:?}", event);
268 let winit_event = event; let input = match &winit_event {
270 Event::NewEvents (_) => return Err (winit_event),
271 Event::WindowEvent { event, .. } => match event {
272 event::WindowEvent::ModifiersChanged (modifiers) => {
273 self.modifiers = modifiers.state();
274 return Err (winit_event)
275 }
276 event::WindowEvent::AxisMotion {..} => return Err (winit_event),
277 event::WindowEvent::CloseRequested => input::System::Close.into(),
278 event::WindowEvent::CursorEntered {..} => input::System::CursorEntered
279 .into(),
280 event::WindowEvent::CursorLeft {..} => input::System::CursorLeft
281 .into(),
282 event::WindowEvent::CursorMoved {..} => return Err (winit_event),
287 event::WindowEvent::RedrawRequested => input::System::Redraw.into(),
288 event::WindowEvent::Destroyed => input::System::Destroyed.into(),
289 event::WindowEvent::Focused (focused) =>
290 input::System::Focused (*focused).into(),
291 event::WindowEvent::KeyboardInput { event, is_synthetic: false, .. } => {
292 let input = (event, self.modifiers).into();
293 if event.state == event::ElementState::Pressed {
294 if let Some (mut text) = event.text.clone()
295 .map (|text| text.to_string())
296 {
297 let text_input = if text.len() > 1 {
298 input::Text::String (text)
299 } else {
300 debug_assert_eq!(text.len(), 1);
301 input::Text::Char (text.pop().unwrap())
302 }.into();
303 return Ok (vec![input, text_input])
304 }
305 }
306 input
307 }
308 event::WindowEvent::KeyboardInput { is_synthetic: true, .. } =>
309 return Err (winit_event),
310 #[allow(deprecated)]
313 event::WindowEvent::MouseInput { button, state, .. } =>
314 mouse_button (*button, self.modifiers, *state),
315 #[allow(deprecated)]
318 event::WindowEvent::MouseWheel { delta, .. } =>
319 mouse_wheel (*delta, self.modifiers),
320 event::WindowEvent::Resized (logical_size) => {
321 let (width, height) = (*logical_size).into();
323 let mut out = vec![input::System::Resized { width, height }.into()];
324 self.dimensions =
325 view::coordinates::dimensions::Pixel::new_wh (width, height);
326 if self.pointer_hv == (-1.0, -1.0) {
327 self.pointer_hv.0 = width as f32 / 2.0;
328 self.pointer_hv.1 = height as f32 / 2.0;
329 out.push (self.pointer().into());
330 } else {
331 self.clip_pointer().map (|pointer| out.push (pointer.into()));
332 }
333 return Ok (out)
334 }
335 event::WindowEvent::Ime (_) =>
337 input::System::InputMethod ().into(),
338 event::WindowEvent::Occluded (occluded) =>
339 input::System::Occluded (*occluded).into(),
340 event::WindowEvent::Moved (_) => return Err (winit_event),
341 _ => {
342 log::error!("TODO: unhandled glutin window event: {:?}", event);
343 unimplemented!("TODO: unhandled glutin window event: {:?}", event)
344 }
345 }
346 Event::DeviceEvent { event, .. } => match event {
347 event::DeviceEvent::Button {..} => return Err (winit_event),
349 event::DeviceEvent::Key (_) => return Err (winit_event),
350 event::DeviceEvent::Motion { axis, value } =>
352 input::Axis { axis: *axis, value: value.round() as i32 }.into(),
353 event::DeviceEvent::MouseMotion { delta: (x, y) } => {
355 let motion = input::Motion (x.round() as i32, y.round() as i32).into();
356 let pointer = {
357 self.pointer_hv.0 += (x.abs().powf (self.pointer_sensitivity as f64)
358 * x.signum()) as f32;
359 self.pointer_hv.1 -= (y.abs().powf (self.pointer_sensitivity as f64)
360 * y.signum()) as f32;
361 self.clip_pointer().unwrap_or_else (|| self.pointer()).into()
362 };
363 return Ok (vec![motion, pointer])
364 }
365 event::DeviceEvent::MouseWheel {..} => return Err (winit_event),
366 event::DeviceEvent::Added {..} => return Err (winit_event),
367 _ => {
368 log::error!("TODO: unhandled glutin device event: {:?}", event);
369 unimplemented!("TODO: unhandled glutin device event: {:?}", event)
370 }
371 }
372 Event::Resumed => return Err (winit_event),
374 Event::AboutToWait => return Err (winit_event),
375 _ => {
376 log::error!("TODO: unhandled winit event: {:?}", winit_event);
377 unimplemented!("TODO: unhandld winit event: {:?}", winit_event)
378 }
379 };
380 Ok (vec![input])
381 }
382
383 fn pointer (&self) -> view::input::Pointer {
384 view::input::Pointer {
385 position_horizontal: self.pointer_hv.0,
386 position_vertical: self.pointer_hv.1,
387 modifiers: self.modifiers.into()
388 }
389 }
390
391 fn clip_pointer (&mut self) -> Option <view::input::Pointer> {
393 let hv_before = self.pointer_hv;
394 self.pointer_hv.0 = f32::min (self.pointer_hv.0, self.dimensions.width()
395 as f32);
396 self.pointer_hv.0 = f32::max (self.pointer_hv.0, 0.0);
397 self.pointer_hv.1 = f32::min (self.pointer_hv.1, self.dimensions.height()
398 as f32);
399 self.pointer_hv.1 = f32::max (self.pointer_hv.1, 0.0);
400 if hv_before != self.pointer_hv {
401 Some (self.pointer())
402 } else {
403 None
404 }
405 }
406}
407
408impl <'a> winit::application::ApplicationHandler for InputHandler <'a> {
409 fn resumed (&mut self, _event_loop : &winit::event_loop::ActiveEventLoop) {
411 self.handle_event (winit::event::Event::Resumed)
412 }
413 fn window_event (&mut self,
414 _event_loop : &winit::event_loop::ActiveEventLoop,
415 window_id : winit::window::WindowId,
416 event : winit::event::WindowEvent
417 ) {
418 self.handle_event (winit::event::Event::WindowEvent { window_id, event })
419 }
420 fn new_events (&mut self,
422 _event_loop : &winit::event_loop::ActiveEventLoop,
423 cause : winit::event::StartCause
424 ) {
425 self.handle_event (winit::event::Event::NewEvents (cause))
426 }
427 fn user_event (&mut self,
428 _event_loop : &winit::event_loop::ActiveEventLoop,
429 event : ()
430 ) {
431 self.handle_event (winit::event::Event::UserEvent (event))
432 }
433 fn device_event (&mut self,
434 _event_loop : &winit::event_loop::ActiveEventLoop,
435 device_id : winit::event::DeviceId,
436 event : winit::event::DeviceEvent
437 ) {
438 self.handle_event (winit::event::Event::DeviceEvent { device_id, event })
439 }
440 fn about_to_wait (&mut self,
441 _event_loop : &winit::event_loop::ActiveEventLoop
442 ) {
443 self.handle_event (winit::event::Event::AboutToWait)
444 }
445 fn suspended (&mut self,
446 _event_loop : &winit::event_loop::ActiveEventLoop
447 ) {
448 self.handle_event (winit::event::Event::Suspended)
449 }
450 fn exiting (&mut self, _event_loop : &winit::event_loop::ActiveEventLoop) {
451 self.handle_event (winit::event::Event::LoopExiting)
452 }
453 fn memory_warning (&mut self,
454 _event_loop : &winit::event_loop::ActiveEventLoop
455 ) {
456 self.handle_event (winit::event::Event::MemoryWarning)
457 }
458}
459
460impl From <winit::event::MouseButton> for view::input::button::Mouse {
461 fn from (button : winit::event::MouseButton) -> view::input::button::Mouse {
462 use winit::event::MouseButton;
463 use view::input::button::Mouse;
464 match button {
465 MouseButton::Left => Mouse::Mouse1,
466 MouseButton::Right => Mouse::Mouse2,
467 MouseButton::Middle => Mouse::Mouse3,
468 MouseButton::Other (4) => Mouse::Mouse4,
469 MouseButton::Other (5) => Mouse::Mouse5,
470 button => {
471 log::error!("unhandled glutin mouse button: {:?}", button);
472 unimplemented!()
473 }
474 }
475 }
476}
477
478impl From <(&winit::event::KeyEvent, winit::keyboard::ModifiersState)>
479 for view::Input
480{
481 fn from (
482 (input, modifiers) :
483 (&winit::event::KeyEvent, winit::keyboard::ModifiersState)
484 ) -> view::Input {
485 use std::str::FromStr;
486 use view::{input, Input};
487 use winit::keyboard;
488 let state = input.state.into();
489 let button = {
490 let variant = match &input.logical_key {
491 keyboard::Key::Named (named_key) =>
492 input::button::Keycode::from ((*named_key, input.location)),
493 keyboard::Key::Character (ch) => input::button::Keycode::try_from (
494 char::from_str (ch.as_str()).unwrap()
495 ).unwrap(),
496 keyboard::Key::Unidentified (k) =>
498 unimplemented!("TODO: unidentified key: {:?}", k),
499 keyboard::Key::Dead (k) =>
500 unimplemented!("TODO: dead key: {:?}", k)
501 }.into();
502 input::Button { variant, modifiers: modifiers.into() }
503 };
504 Input::Button (button, state)
505 }
506}
507
508impl From <winit::event::ElementState> for view::input::button::State {
509 fn from (state : winit::event::ElementState) -> Self {
510 use winit::event::ElementState;
511 use view::input::button::State;
512 match state {
513 ElementState::Pressed => State::Pressed,
514 ElementState::Released => State::Released
515 }
516 }
517}
518
519impl From <winit::keyboard::ModifiersState> for view::input::Modifiers {
520 fn from (modifiers : winit::keyboard::ModifiersState) -> Self {
521 use view::input::Modifiers;
522 let mut out = Modifiers::empty();
523 out.set (Modifiers::SHIFT, modifiers.shift_key());
524 out.set (Modifiers::CTRL, modifiers.control_key());
525 out.set (Modifiers::ALT, modifiers.alt_key());
526 out.set (Modifiers::SUPER, modifiers.super_key());
527 out
528 }
529}
530
531fn mouse_button (
534 button : winit::event::MouseButton,
535 modifiers : winit::keyboard::ModifiersState,
536 state : winit::event::ElementState
537) -> view::Input {
538 let state = state.into();
539 let button = {
540 let variant = view::input::button::Mouse::from (button).into();
541 let modifiers = modifiers.into();
542 view::input::Button { variant, modifiers }
543 };
544 view::Input::Button (button, state)
545}
546
547fn mouse_wheel (
550 delta : winit::event::MouseScrollDelta,
551 modifiers : winit::keyboard::ModifiersState
552) -> view::Input {
553 let delta = match delta {
554 winit::event::MouseScrollDelta::LineDelta (x, y)
555 => (x.round() as i32, y.round() as i32),
556 winit::event::MouseScrollDelta::PixelDelta (
557 winit::dpi::PhysicalPosition { x, y }
558 ) => (x.round() as i32, y.round() as i32)
559 };
560 let modifiers = modifiers.into();
561 view::input::Wheel { delta, modifiers }.into()
562}