gooey/presentation/opengl/
remote.rs1use std::{env, thread, time, vec};
11use std::sync::{self, atomic};
12use lazy_static::lazy_static;
13use nsys::{self, gl, math};
14use nsys::gl::glium::{self, glutin};
15use nsys::gl::winit;
16use key_vec::KeyVec;
17use unbounded_spsc;
18
19use crate::prelude::*;
20use super::{render, Graphics, InputHandler, InputState, Presentation};
21
22lazy_static!{
23 static ref GLUTIN_WINDOW
25 : sync::Mutex <Option <(winit::window::Window, glutin::config::Config)>>
26 = sync::Mutex::new (None);
27 static ref DISPLAY_RECEIVER
29 : sync::Mutex <Option <
30 unbounded_spsc::Receiver <Vec <(NodeId, view::Display)>>>>
31 = sync::Mutex::new (None);
32 static ref FRAME : sync::Arc <atomic::AtomicU64> =
34 sync::Arc::new (atomic::AtomicU64::new (0));
35}
36
37pub struct Remote {
39 pub event_loop : winit::event_loop::EventLoop <()>,
40 display : unbounded_spsc::Sender <Vec <(NodeId, view::Display)>>,
41 input_state : InputState,
42 screen_tiles : Option <NodeId>
43}
44
45pub struct Opengl {
47 pub draw_crosshair : bool,
48 pub inner : gl::Render,
49 tileset_id : Option <gl::render::resource::DefaultTilesetId>,
50 updates : unbounded_spsc::Receiver <Vec <(NodeId, view::Display)>>,
51 id_map : KeyVec <NodeId, NodeId>,
52 view : Tree <interface::View>,
53 glium_frame : Option <glium::Frame>,
54 display_counter : u64
56}
57
58pub fn create_screen_tiles <A, P> (interface : &mut Interface <A, P>) where
62 A : Application,
63 P : Presentation + presentation::HasGraphics <Remote>
64{
65 let screen_id = interface.root_id().clone();
66 let screen_tiles = frame::free::Builder::<A>::new (
67 interface.elements(), &screen_id
68 ) .layout (layout::Free {
69 size: Size::fill(), .. layout::Free::default_tile()
70 }.into())
71 .clear_color (canvas::ClearColor::Fixed (None))
72 .coord_kind_override (coordinates::Kind::Tile)
73 .build_element();
74 let tiles_id =
75 match interface.action (&screen_id,
76 Action::create_singleton (screen_tiles, CreateOrder::Append)
77 ).next().unwrap() {
78 (_, Event::Create (_, id, _)) => id,
79 _ => unreachable!()
80 };
81 interface.presentation.graphics().screen_tiles = Some (tiles_id);
82}
83
84impl Default for Remote {
85 fn default() -> Self {
86 let event_loop = {
87 let (event_loop, window, gl_config) =
88 gl::init::glutin_window ("Gooey Opengl Remote Window");
89 {
90 let mut glutin_window_lock = GLUTIN_WINDOW.lock().unwrap();
91 debug_assert!(glutin_window_lock.is_none());
92 window.set_cursor_visible (false);
97 *glutin_window_lock = Some ((window, gl_config));
102 }
103 event_loop
104 };
105 let display = {
106 let (sender, receiver) =
107 unbounded_spsc::channel::<Vec <(NodeId, view::Display)>>();
108 {
109 let mut display_receiver_lock = DISPLAY_RECEIVER.lock().unwrap();
110 debug_assert!(display_receiver_lock.is_none());
111 *display_receiver_lock = Some (receiver);
112 }
113 sender
114 };
115 Remote {
116 event_loop,
117 display,
118 input_state: InputState::new(),
119 screen_tiles: None
120 }
121 }
122}
123
124pub fn frame() -> u64 {
126 FRAME.load (atomic::Ordering::SeqCst)
127}
128
129impl Remote {
130 #[inline]
131 pub fn screen_tiles_id (&self) -> &NodeId {
132 self.screen_tiles.as_ref().unwrap()
133 }
134 #[inline]
135 pub fn dimensions (&self) -> dimensions::Pixel {
136 self.input_state.dimensions.clone()
137 }
138 pub fn pointer_sensitivity (&self) -> f32 {
139 self.input_state.pointer_sensitivity
140 }
141 pub fn set_pointer_sensitivity (&mut self, pointer_sensitivity : f32) {
142 self.input_state.pointer_sensitivity = pointer_sensitivity
143 }
144}
145
146impl Graphics for Remote { }
147impl Presentation for Remote {
148 fn with_root (root : View, id : NodeId) -> Self {
152 let remote = Self::default();
153 log::debug!("opengl remote with root: {:?}", root);
154 remote.display.send (vec![
155 (id.clone(), Display::Create (root, id, CreateOrder::Append))
156 ]).unwrap();
157 loop {
160 if (*DISPLAY_RECEIVER).lock().unwrap().is_none() {
161 break
162 }
163 thread::sleep (time::Duration::from_millis (100));
164 }
165 remote
166 }
167
168 fn make_interface <A : Application> () -> Interface <A, Self> {
172 let screen = {
173 let mut screen = frame::screen::PixelBuilder::<A>::new()
176 .anchor (Alignment::pixel())
177 .build_element();
178 let canvas = Canvas::try_ref_mut (&mut screen.view.component).unwrap();
180 canvas.coordinates.modify_dimensions_horizontal (1);
181 canvas.coordinates.modify_dimensions_vertical (1);
182 screen
183 };
184 Interface::<A, Remote>::with_root (screen)
185 }
186
187 fn get_input (&mut self, input_buffer : &mut Vec <view::Input>) {
188 use winit::platform::pump_events::EventLoopExtPumpEvents;
189 log::trace!("get input...");
190 self.event_loop.pump_app_events (
193 Some (time::Duration::ZERO),
194 &mut InputHandler { input_buffer, input_state: &mut self.input_state });
195 log::trace!("...get input");
196 }
197
198 fn display_view <V : AsRef <View>> (&mut self,
199 _view_tree : &Tree <V>,
200 display_values : vec::Drain <(NodeId, view::Display)>
201 ) {
202 self.display.send (display_values.collect()).unwrap();
203 }
204}
205
206impl Opengl {
207 pub fn init (tileset_id : Option <gl::render::resource::DefaultTilesetId>)
211 -> Self
212 {
213 let inner = {
214 use gl::render::resource::MAIN_VIEWPORT;
215 let (window, gl_config) = loop {
217 if let Some (glutin_window) = (*GLUTIN_WINDOW).lock().unwrap().take() {
218 break glutin_window
219 }
220 thread::sleep (time::Duration::from_millis (100));
221 };
222 let display = gl::init::glium_display_gl33core (&window, &gl_config);
228 let mut render =
229 gl::Render::<gl::render::resource::Default>::new (display, window);
230 let [tile_width, tile_height] =
232 render.resource.tile_dimensions (tileset_id.unwrap_or_default());
233 unsafe {
234 env::set_var ("GOOEY_TILE_WIDTH", tile_width.to_string());
235 env::set_var ("GOOEY_TILE_HEIGHT", tile_height.to_string());
236 }
237 render.resource.draw2d
239 .viewport_resources_set (MAIN_VIEWPORT, Default::default());
240 render
241 };
242 let updates = loop {
243 if let Some (receiver) = (*DISPLAY_RECEIVER).lock().unwrap().take() {
244 break receiver
245 }
246 thread::sleep (time::Duration::from_millis (100));
247 };
248 Opengl {
249 inner,
250 tileset_id,
251 updates,
252 id_map: KeyVec::new(),
253 view: Tree::new(),
254 glium_frame: None,
255 display_counter: 0,
256 draw_crosshair: false
257 }
258 }
259
260 #[inline]
261 pub fn inner (&self) -> &gl::Render {
262 &self.inner
263 }
264 #[inline]
265 pub fn inner_mut (&mut self) -> &mut gl::Render {
266 &mut self.inner
267 }
268 #[inline]
269 #[deprecated = "use remote::frame() function instead"]
270 pub fn frame (&self) -> u64 {
271 frame()
272 }
273 #[inline]
274 pub fn display_counter (&self) -> u64 {
275 self.display_counter
276 }
277 #[inline]
278 pub fn reset_display_counter (&mut self) {
279 self.display_counter = 0;
280 }
281 pub fn load_pointer (&mut self,
282 key : gl::render::resource::PointerTextureIndexRepr,
283 bytes : &[u8],
284 offset : math::Vector2 <i16>
285 ) {
286 let render = &mut self.inner;
287 render::load_pointer (render, key, bytes, offset);
288 }
289 pub fn load_textures (&mut self,
290 textures_16x16 : &[&'static str],
291 textures_64x64 : &[&'static str],
292 textures_anysize : &[&'static str]
293 ) {
294 render::load_textures (
295 &mut self.inner, textures_16x16, textures_64x64, textures_anysize)
296 }
297 pub fn process_display_events (&mut self) {
298 while let Ok (updates) = self.updates.try_recv() {
299 for (node_id, display) in updates {
300 match display {
301 view::Display::Create (view, child_id, order) => {
302 let new_id = if self.id_map.is_empty() {
303 self.view.insert (tree::Node::new (view),
305 tree::InsertBehavior::AsRoot).unwrap()
306 } else {
307 let parent_id = self.id_map.get (&node_id).unwrap();
308 let new_id = self.view.insert (tree::Node::new (view),
309 tree::InsertBehavior::UnderNode (&parent_id)).unwrap();
310 match order {
311 interface::CreateOrder::Prepend => {
312 let _ = self.view.make_first_sibling (&new_id).unwrap();
313 }
314 interface::CreateOrder::NthSibling (n) => {
315 let _ = self.view.make_nth_sibling (&new_id, n as usize)
316 .unwrap();
317 }
318 interface::CreateOrder::Append => {}
319 }
320 new_id
321 };
322 assert!(self.id_map.insert (child_id, new_id).is_none());
323 }
324 view::Display::Update (update) => {
325 let id = self.id_map.get (&node_id).unwrap();
326 match update {
327 view::Update::View (view) =>
328 *self.view.get_mut (id).unwrap().data_mut() = view,
329 view::Update::FocusTop => {
330 self.view.make_last_sibling (&id).unwrap();
331 }
332 }
333 }
334 view::Display::Destroy => {
335 let id = self.id_map.remove (&node_id).unwrap();
336 let _ = self.view
337 .remove_node (id, tree::RemoveBehavior::DropChildren).unwrap();
338 }
339 }
340 }
341 self.display_counter += 1;
342 }
343 }
344 pub fn update_and_do_frame (&mut self) {
345 render::update (
347 &mut self.inner, self.tileset_id, &self.view, self.draw_crosshair);
348 self.inner.do_frame (self.glium_frame.as_mut());
350 FRAME.fetch_add (1, atomic::Ordering::SeqCst);
351 }
352 pub fn display (&mut self) {
354 self.process_display_events();
355 self.update_and_do_frame();
356 }
357}
358
359impl AsRef <View> for View {
362 fn as_ref (&self) -> &View {
363 self
364 }
365}