1#![deny(unused_imports)]
2
3use std::{fmt::Debug, marker::PhantomData};
4
5use instant::Instant;
6use maplibre::{
7 environment::{Environment, OffscreenKernelEnvironment},
8 event_loop::{EventLoop, EventLoopProxy, SendEventError},
9 io::{apc::AsyncProcedureCall, scheduler::Scheduler, source_client::HttpClient},
10 map::Map,
11 window::{HeadedMapWindow, MapWindowConfig},
12};
13use winit::{
14 event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
15 event_loop::ControlFlow,
16};
17
18use crate::input::{InputController, UpdateState};
19
20pub mod input;
21
22pub type RawWinitWindow = winit::window::Window;
23pub type RawWinitEventLoop<ET> = winit::event_loop::EventLoop<ET>;
24pub type RawEventLoopProxy<ET> = winit::event_loop::EventLoopProxy<ET>;
25
26#[cfg(target_arch = "wasm32")]
27mod web;
28
29#[cfg(not(target_arch = "wasm32"))]
30mod noweb;
31
32#[cfg(not(target_arch = "wasm32"))]
33pub use noweb::*;
34#[cfg(target_arch = "wasm32")]
35pub use web::*;
36
37pub struct WinitMapWindow<ET: 'static> {
38 window: RawWinitWindow,
39 event_loop: Option<WinitEventLoop<ET>>,
40}
41
42impl<ET> WinitMapWindow<ET> {
43 pub fn take_event_loop(&mut self) -> Option<WinitEventLoop<ET>> {
44 self.event_loop.take()
45 }
46}
47
48impl<ET> HeadedMapWindow for WinitMapWindow<ET> {
49 type RawWindow = RawWinitWindow;
50
51 fn raw(&self) -> &Self::RawWindow {
52 &self.window
53 }
54
55 fn request_redraw(&self) {
56 self.window.request_redraw()
57 }
58
59 fn id(&self) -> u64 {
60 self.window.id().into()
61 }
62}
63
64pub struct WinitEventLoop<ET: 'static> {
65 event_loop: RawWinitEventLoop<ET>,
66}
67
68impl<ET: 'static + PartialEq + Debug> EventLoop<ET> for WinitEventLoop<ET> {
69 type EventLoopProxy = WinitEventLoopProxy<ET>;
70
71 fn run<E>(self, mut map: Map<E>, max_frames: Option<u64>)
72 where
73 E: Environment,
74 <E::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow,
75 {
76 let mut last_render_time = Instant::now();
77 let mut current_frame: u64 = 0;
78
79 let mut input_controller = InputController::new(0.2, 100.0, 0.1);
80
81 self.event_loop
82 .run(move |event, _window_target, control_flow| {
83 #[cfg(target_os = "android")]
84 if !map.has_renderer() && event == Event::Resumed {
85 use tokio::{runtime::Handle, task};
86
87 task::block_in_place(|| {
88 Handle::current().block_on(async {
89 map.initialize_renderer().await.unwrap();
90 })
91 });
92 return;
93 }
94
95 match event {
96 Event::DeviceEvent {
97 ref event,
98 .. } => {
100 input_controller.device_input(event);
101 }
102
103 Event::WindowEvent {
104 ref event,
105 window_id,
106 } if window_id == map.window().id().into() => {
107 if !input_controller.window_input(event) {
108 match event {
109 WindowEvent::CloseRequested
110 | WindowEvent::KeyboardInput {
111 input:
112 KeyboardInput {
113 state: ElementState::Pressed,
114 virtual_keycode: Some(VirtualKeyCode::Escape),
115 ..
116 },
117 ..
118 } => *control_flow = ControlFlow::Exit,
119 WindowEvent::Resized(physical_size) => {
120 if let Ok(map_context) = map.context_mut() {
121 map_context.resize(physical_size.width, physical_size.height);
122 }
123 }
124 WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
125 if let Ok(map_context) = map.context_mut() {
126 map_context.resize(new_inner_size.width, new_inner_size.height);
127 }
128 }
129 _ => {}
130 }
131 }
132 }
133 Event::RedrawRequested(_) => {
134 let now = Instant::now();
135 let dt = now - last_render_time;
136 last_render_time = now;
137
138 if let Ok(map_context) = map.context_mut() {
139 input_controller.update_state(map_context, dt);
140 }
141
142 map.run_schedule().expect("Failed to run schedule!");
144
145 if let Some(max_frames) = max_frames {
146 if current_frame >= max_frames {
147 log::info!("Exiting because maximum frames reached.");
148 *control_flow = ControlFlow::Exit;
149 }
150
151 current_frame += 1;
152 }
153 }
154 Event::Suspended => {
155 }
157 Event::Resumed => {
158 }
160 Event::MainEventsCleared => {
161 map.window().request_redraw();
164 }
165 _ => {}
166 }
167 });
168 }
169
170 fn create_proxy(&self) -> Self::EventLoopProxy {
171 WinitEventLoopProxy {
172 proxy: self.event_loop.create_proxy(),
173 }
174 }
175}
176pub struct WinitEventLoopProxy<ET: 'static> {
177 proxy: RawEventLoopProxy<ET>,
178}
179
180impl<ET: 'static> EventLoopProxy<ET> for WinitEventLoopProxy<ET> {
181 fn send_event(&self, event: ET) -> Result<(), SendEventError> {
182 self.proxy
183 .send_event(event)
184 .map_err(|_e| SendEventError::Closed)
185 }
186}
187
188pub struct WinitEnvironment<
189 S: Scheduler,
190 HC: HttpClient,
191 K: OffscreenKernelEnvironment,
192 APC: AsyncProcedureCall<K>,
193 ET,
194> {
195 phantom_s: PhantomData<S>,
196 phantom_hc: PhantomData<HC>,
197 phantom_k: PhantomData<K>,
198 phantom_apc: PhantomData<APC>,
199 phantom_et: PhantomData<ET>,
200}
201
202impl<
203 S: Scheduler,
204 HC: HttpClient,
205 K: OffscreenKernelEnvironment,
206 APC: AsyncProcedureCall<K>,
207 ET: 'static,
208 > Environment for WinitEnvironment<S, HC, K, APC, ET>
209{
210 type MapWindowConfig = WinitMapWindowConfig<ET>;
211 type AsyncProcedureCall = APC;
212 type Scheduler = S;
213 type HttpClient = HC;
214 type OffscreenKernelEnvironment = K;
215}