1 use std::time::Duration; |
1 use std::time::Duration; |
2 |
2 |
3 use futures::executor::block_on; |
3 use futures::executor::block_on; |
|
4 use glutin::event_loop::ControlFlow; |
4 use glutin::{ |
5 use glutin::{ |
5 dpi, ContextTrait, DeviceEvent, ElementState, Event, EventsLoop, GlProfile, GlRequest, |
6 dpi, |
6 MouseButton, MouseScrollDelta, Window, WindowBuilder, WindowEvent, WindowedContext, |
7 event::{DeviceEvent, ElementState, Event, MouseButton, MouseScrollDelta, WindowEvent}, |
|
8 event_loop::EventLoop, |
|
9 window::{Window, WindowBuilder}, |
|
10 ContextWrapper, GlProfile, GlRequest, NotCurrent, PossiblyCurrent, WindowedContext, |
7 }; |
11 }; |
8 use hedgewars_engine::instance::EngineInstance; |
12 use hedgewars_engine::instance::EngineInstance; |
9 use integral_geometry::Point; |
13 use integral_geometry::Point; |
10 use std::error::Error; |
14 use std::error::Error; |
11 use wgpu::{ |
15 use wgpu::{ |
13 LoadOp, Operations, PowerPreference, PresentMode, Queue, RenderPassColorAttachmentDescriptor, |
17 LoadOp, Operations, PowerPreference, PresentMode, Queue, RenderPassColorAttachmentDescriptor, |
14 RenderPassDescriptor, RequestAdapterOptions, Surface, SwapChain, SwapChainDescriptor, |
18 RenderPassDescriptor, RequestAdapterOptions, Surface, SwapChain, SwapChainDescriptor, |
15 TextureFormat, TextureUsage, |
19 TextureFormat, TextureUsage, |
16 }; |
20 }; |
17 |
21 |
18 type HwGlRendererContext = WindowedContext; |
22 type HwGlRendererContext = ContextWrapper<PossiblyCurrent, Window>; |
19 |
23 |
20 struct HwWgpuRenderingContext { |
24 struct HwWgpuRenderingContext { |
21 window: Window, |
25 window: Window, |
22 surface: Surface, |
26 surface: Surface, |
23 adapter: Adapter, |
27 adapter: Adapter, |
39 } |
43 } |
40 } |
44 } |
41 |
45 |
42 impl HwRendererContext { |
46 impl HwRendererContext { |
43 fn get_framebuffer_size(window: &Window) -> (u32, u32) { |
47 fn get_framebuffer_size(window: &Window) -> (u32, u32) { |
44 let size = window.get_inner_size().unwrap(); |
48 window.inner_size().into() |
45 (size.to_physical(window.get_hidpi_factor())).into() |
|
46 } |
49 } |
47 |
50 |
48 fn create_wpgu_swap_chain(window: &Window, surface: &Surface, device: &Device) -> SwapChain { |
51 fn create_wpgu_swap_chain(window: &Window, surface: &Surface, device: &Device) -> SwapChain { |
49 let (width, height) = Self::get_framebuffer_size(window); |
52 let (width, height) = Self::get_framebuffer_size(window); |
50 device.create_swap_chain( |
53 device.create_swap_chain( |
57 present_mode: PresentMode::Fifo, |
60 present_mode: PresentMode::Fifo, |
58 }, |
61 }, |
59 ) |
62 ) |
60 } |
63 } |
61 |
64 |
62 fn init_wgpu(event_loop: &EventsLoop, size: dpi::LogicalSize) -> HwWgpuRenderingContext { |
65 fn init_wgpu( |
|
66 event_loop: &EventLoop<()>, |
|
67 size: dpi::LogicalSize<f64>, |
|
68 ) -> HwWgpuRenderingContext { |
63 let builder = WindowBuilder::new() |
69 let builder = WindowBuilder::new() |
64 .with_title("hwengine") |
70 .with_title("hwengine") |
65 .with_dimensions(size); |
71 .with_inner_size(size); |
66 let window = builder.build(event_loop).unwrap(); |
72 let window = builder.build(event_loop).unwrap(); |
67 |
73 |
68 let instance = wgpu::Instance::new(BackendBit::VULKAN); |
74 let instance = wgpu::Instance::new(BackendBit::PRIMARY); |
69 |
75 |
70 let surface = unsafe { instance.create_surface(&window) }; |
76 let surface = unsafe { instance.create_surface(&window) }; |
71 |
77 |
72 let adapter = block_on(instance.request_adapter(&RequestAdapterOptions { |
78 let adapter = block_on(instance.request_adapter(&RequestAdapterOptions { |
73 power_preference: PowerPreference::HighPerformance, |
79 power_preference: PowerPreference::HighPerformance, |
87 queue, |
93 queue, |
88 swap_chain, |
94 swap_chain, |
89 } |
95 } |
90 } |
96 } |
91 |
97 |
92 fn init_gl(event_loop: &EventsLoop, size: dpi::LogicalSize) -> HwGlRendererContext { |
98 fn init_gl(event_loop: &EventLoop<()>, size: dpi::LogicalSize<f64>) -> HwGlRendererContext { |
93 use glutin::ContextBuilder; |
99 use glutin::ContextBuilder; |
94 |
100 |
95 let builder = WindowBuilder::new() |
101 let builder = WindowBuilder::new() |
96 .with_title("hwengine") |
102 .with_title("hwengine") |
97 .with_dimensions(size); |
103 .with_inner_size(size); |
98 |
104 |
99 let context = ContextBuilder::new() |
105 let context = ContextBuilder::new() |
100 .with_gl(GlRequest::Latest) |
106 .with_gl(GlRequest::Latest) |
101 .with_gl_profile(GlProfile::Core) |
107 .with_gl_profile(GlProfile::Core) |
102 .build_windowed(builder, &event_loop) |
108 .build_windowed(builder, &event_loop) |
103 .ok() |
109 .ok() |
104 .unwrap(); |
110 .unwrap(); |
105 |
111 |
106 unsafe { |
112 unsafe { |
107 context.make_current().unwrap(); |
113 let wrapper = context.make_current().unwrap(); |
108 gl::load_with(|ptr| context.get_proc_address(ptr) as *const _); |
114 gl::load_with(|ptr| wrapper.get_proc_address(ptr) as *const _); |
109 |
115 |
110 if let Some(sz) = context.get_inner_size() { |
116 let (width, height) = Self::get_framebuffer_size(wrapper.window()); |
111 let (width, height) = Self::get_framebuffer_size(context.window()); |
117 gl::Viewport(0, 0, width as i32, height as i32); |
112 gl::Viewport(0, 0, width as i32, height as i32); |
118 wrapper |
113 } |
119 } |
114 } |
120 } |
115 |
121 |
116 context |
122 fn new(event_loop: &EventLoop<()>, size: dpi::LogicalSize<f64>, use_wgpu: bool) -> Self { |
117 } |
|
118 |
|
119 fn new(event_loop: &EventsLoop, size: dpi::LogicalSize, use_wgpu: bool) -> Self { |
|
120 if use_wgpu { |
123 if use_wgpu { |
121 Self::Wgpu(Self::init_wgpu(event_loop, size)) |
124 Self::Wgpu(Self::init_wgpu(event_loop, size)) |
122 } else { |
125 } else { |
123 Self::Gl(Self::init_gl(event_loop, size)) |
126 Self::Gl(Self::init_gl(event_loop, size)) |
124 } |
127 } |
182 Ok(()) |
185 Ok(()) |
183 } |
186 } |
184 } |
187 } |
185 |
188 |
186 fn main() { |
189 fn main() { |
187 let use_wgpu = true; |
190 let use_wgpu = false; |
188 let mut event_loop = EventsLoop::new(); |
191 let mut event_loop = EventLoop::<()>::new(); |
189 let (w, h) = (1024.0, 768.0); |
192 let (w, h) = (1024.0, 768.0); |
190 |
193 |
191 let mut context = HwRendererContext::new(&event_loop, dpi::LogicalSize::new(w, h), use_wgpu); |
194 let mut context = HwRendererContext::new(&event_loop, dpi::LogicalSize::new(w, h), use_wgpu); |
192 |
195 |
193 let mut engine = EngineInstance::new(); |
196 let mut engine = EngineInstance::new(); |
201 |
204 |
202 let mut now = Instant::now(); |
205 let mut now = Instant::now(); |
203 let mut update_time = Instant::now(); |
206 let mut update_time = Instant::now(); |
204 let mut render_time = Instant::now(); |
207 let mut render_time = Instant::now(); |
205 |
208 |
206 let mut is_running = true; |
209 let current_time = Instant::now(); |
207 |
210 let delta = current_time - now; |
208 while is_running { |
211 now = current_time; |
209 let current_time = Instant::now(); |
212 let ms = delta.as_secs() as f64 * 1000.0 + delta.subsec_millis() as f64; |
210 let delta = current_time - now; |
213 context.window().set_title(&format!("hwengine {:.3}ms", ms)); |
211 now = current_time; |
214 |
212 let ms = delta.as_secs() as f64 * 1000.0 + delta.subsec_millis() as f64; |
215 event_loop.run(move |event, _, control_flow| { |
213 context.window().set_title(&format!("hwengine {:.3}ms", ms)); |
216 *control_flow = ControlFlow::Poll; |
214 |
217 match event { |
215 if update_time.elapsed() > Duration::from_millis(10) { |
|
216 update_time = current_time; |
|
217 engine.world.step() |
|
218 } |
|
219 |
|
220 event_loop.poll_events(|event| match event { |
|
221 Event::WindowEvent { event, .. } => match event { |
218 Event::WindowEvent { event, .. } => match event { |
222 WindowEvent::CloseRequested => { |
219 WindowEvent::CloseRequested => { |
223 is_running = false; |
220 *control_flow = ControlFlow::Exit; |
224 } |
221 } |
225 WindowEvent::Resized(_) | WindowEvent::HiDpiFactorChanged(_) => context.update(), |
222 WindowEvent::Resized(_) | WindowEvent::ScaleFactorChanged { .. } => { |
|
223 context.update() |
|
224 } |
226 |
225 |
227 WindowEvent::MouseInput { button, state, .. } => { |
226 WindowEvent::MouseInput { button, state, .. } => { |
228 if let MouseButton::Right = button { |
227 if let MouseButton::Right = button { |
229 dragging = state == ElementState::Pressed; |
228 dragging = state == ElementState::Pressed; |
230 } |
229 } |
231 } |
230 } |
232 |
231 |
233 WindowEvent::MouseWheel { delta, .. } => { |
232 WindowEvent::MouseWheel { delta, .. } => { |
234 let zoom_change = match delta { |
233 let zoom_change = match delta { |
235 MouseScrollDelta::LineDelta(x, y) => y as f32 * 0.1f32, |
234 MouseScrollDelta::LineDelta(x, y) => y as f32 * 0.1f32, |
236 MouseScrollDelta::PixelDelta(delta) => { |
235 MouseScrollDelta::PixelDelta(delta) => delta.y as f32 * 0.1f32, |
237 let physical = delta.to_physical(context.window().get_hidpi_factor()); |
|
238 physical.y as f32 * 0.1f32 |
|
239 } |
|
240 }; |
236 }; |
241 engine.world.move_camera(Point::ZERO, zoom_change); |
237 engine.world.move_camera(Point::ZERO, zoom_change); |
242 } |
238 } |
243 _ => (), |
239 _ => (), |
244 }, |
240 }, |
250 .move_camera(Point::new(delta.0 as i32, delta.1 as i32), 0.0) |
246 .move_camera(Point::new(delta.0 as i32, delta.1 as i32), 0.0) |
251 } |
247 } |
252 } |
248 } |
253 _ => {} |
249 _ => {} |
254 }, |
250 }, |
|
251 |
255 _ => (), |
252 _ => (), |
256 }); |
253 } |
|
254 |
|
255 let current_time = Instant::now(); |
|
256 |
|
257 if update_time.elapsed() > Duration::from_millis(10) { |
|
258 update_time = current_time; |
|
259 engine.world.step() |
|
260 } |
257 |
261 |
258 if render_time.elapsed() > Duration::from_millis(16) { |
262 if render_time.elapsed() > Duration::from_millis(16) { |
259 render_time = current_time; |
263 render_time = current_time; |
260 if !use_wgpu { |
264 if !use_wgpu { |
261 engine.render(); |
265 engine.render(); |
262 } |
266 } |
263 context.present().ok().unwrap(); |
267 context.present().ok().unwrap(); |
264 } |
268 } |
265 } |
269 }); |
266 } |
270 } |