15776
|
1 |
use std::time::Duration;
|
|
2 |
|
|
3 |
use futures::executor::block_on;
|
15798
|
4 |
use glutin::event_loop::ControlFlow;
|
14187
|
5 |
use glutin::{
|
15798
|
6 |
dpi,
|
|
7 |
event::{DeviceEvent, ElementState, Event, MouseButton, MouseScrollDelta, WindowEvent},
|
|
8 |
event_loop::EventLoop,
|
|
9 |
window::{Window, WindowBuilder},
|
|
10 |
ContextWrapper, GlProfile, GlRequest, NotCurrent, PossiblyCurrent, WindowedContext,
|
15776
|
11 |
};
|
|
12 |
use hedgewars_engine::instance::EngineInstance;
|
|
13 |
use integral_geometry::Point;
|
15892
|
14 |
use std::{
|
|
15 |
error::Error,
|
|
16 |
path::Path,
|
|
17 |
};
|
15776
|
18 |
use wgpu::{
|
|
19 |
Adapter, BackendBit, Color, CommandEncoderDescriptor, Device, DeviceDescriptor, Features,
|
|
20 |
LoadOp, Operations, PowerPreference, PresentMode, Queue, RenderPassColorAttachmentDescriptor,
|
|
21 |
RenderPassDescriptor, RequestAdapterOptions, Surface, SwapChain, SwapChainDescriptor,
|
|
22 |
TextureFormat, TextureUsage,
|
14187
|
23 |
};
|
|
24 |
|
15798
|
25 |
type HwGlRendererContext = ContextWrapper<PossiblyCurrent, Window>;
|
15776
|
26 |
|
|
27 |
struct HwWgpuRenderingContext {
|
|
28 |
window: Window,
|
|
29 |
surface: Surface,
|
|
30 |
adapter: Adapter,
|
|
31 |
device: Device,
|
|
32 |
queue: Queue,
|
|
33 |
swap_chain: SwapChain,
|
|
34 |
}
|
|
35 |
|
|
36 |
enum HwRendererContext {
|
|
37 |
Gl(HwGlRendererContext),
|
|
38 |
Wgpu(HwWgpuRenderingContext),
|
|
39 |
}
|
|
40 |
|
|
41 |
struct ErrorStub;
|
|
42 |
|
|
43 |
impl<T: Error> From<T> for ErrorStub {
|
|
44 |
fn from(_: T) -> Self {
|
|
45 |
ErrorStub
|
|
46 |
}
|
|
47 |
}
|
14704
|
48 |
|
15776
|
49 |
impl HwRendererContext {
|
15777
|
50 |
fn get_framebuffer_size(window: &Window) -> (u32, u32) {
|
15798
|
51 |
window.inner_size().into()
|
15777
|
52 |
}
|
|
53 |
|
|
54 |
fn create_wpgu_swap_chain(window: &Window, surface: &Surface, device: &Device) -> SwapChain {
|
|
55 |
let (width, height) = Self::get_framebuffer_size(window);
|
|
56 |
device.create_swap_chain(
|
|
57 |
&surface,
|
|
58 |
&SwapChainDescriptor {
|
|
59 |
usage: TextureUsage::OUTPUT_ATTACHMENT,
|
|
60 |
format: TextureFormat::Bgra8Unorm,
|
|
61 |
width,
|
|
62 |
height,
|
|
63 |
present_mode: PresentMode::Fifo,
|
|
64 |
},
|
|
65 |
)
|
|
66 |
}
|
|
67 |
|
15798
|
68 |
fn init_wgpu(
|
|
69 |
event_loop: &EventLoop<()>,
|
|
70 |
size: dpi::LogicalSize<f64>,
|
|
71 |
) -> HwWgpuRenderingContext {
|
15777
|
72 |
let builder = WindowBuilder::new()
|
|
73 |
.with_title("hwengine")
|
15798
|
74 |
.with_inner_size(size);
|
15777
|
75 |
let window = builder.build(event_loop).unwrap();
|
|
76 |
|
15798
|
77 |
let instance = wgpu::Instance::new(BackendBit::PRIMARY);
|
15777
|
78 |
|
|
79 |
let surface = unsafe { instance.create_surface(&window) };
|
|
80 |
|
|
81 |
let adapter = block_on(instance.request_adapter(&RequestAdapterOptions {
|
|
82 |
power_preference: PowerPreference::HighPerformance,
|
|
83 |
compatible_surface: Some(&surface),
|
|
84 |
}))
|
|
85 |
.unwrap();
|
|
86 |
|
|
87 |
let (device, queue) = block_on(adapter.request_device(&Default::default(), None)).unwrap();
|
|
88 |
|
|
89 |
let swap_chain = Self::create_wpgu_swap_chain(&window, &surface, &device);
|
|
90 |
|
|
91 |
HwWgpuRenderingContext {
|
|
92 |
window,
|
|
93 |
surface,
|
|
94 |
adapter,
|
|
95 |
device,
|
|
96 |
queue,
|
|
97 |
swap_chain,
|
|
98 |
}
|
|
99 |
}
|
|
100 |
|
15798
|
101 |
fn init_gl(event_loop: &EventLoop<()>, size: dpi::LogicalSize<f64>) -> HwGlRendererContext {
|
15777
|
102 |
use glutin::ContextBuilder;
|
|
103 |
|
|
104 |
let builder = WindowBuilder::new()
|
|
105 |
.with_title("hwengine")
|
15798
|
106 |
.with_inner_size(size);
|
15777
|
107 |
|
|
108 |
let context = ContextBuilder::new()
|
|
109 |
.with_gl(GlRequest::Latest)
|
|
110 |
.with_gl_profile(GlProfile::Core)
|
|
111 |
.build_windowed(builder, &event_loop)
|
|
112 |
.ok()
|
|
113 |
.unwrap();
|
|
114 |
|
|
115 |
unsafe {
|
15798
|
116 |
let wrapper = context.make_current().unwrap();
|
|
117 |
gl::load_with(|ptr| wrapper.get_proc_address(ptr) as *const _);
|
15777
|
118 |
|
15798
|
119 |
let (width, height) = Self::get_framebuffer_size(wrapper.window());
|
|
120 |
gl::Viewport(0, 0, width as i32, height as i32);
|
|
121 |
wrapper
|
15777
|
122 |
}
|
|
123 |
}
|
|
124 |
|
15798
|
125 |
fn new(event_loop: &EventLoop<()>, size: dpi::LogicalSize<f64>, use_wgpu: bool) -> Self {
|
15777
|
126 |
if use_wgpu {
|
|
127 |
Self::Wgpu(Self::init_wgpu(event_loop, size))
|
|
128 |
} else {
|
|
129 |
Self::Gl(Self::init_gl(event_loop, size))
|
|
130 |
}
|
|
131 |
}
|
|
132 |
|
15776
|
133 |
pub fn window(&self) -> &Window {
|
|
134 |
match self {
|
|
135 |
HwRendererContext::Gl(gl) => &gl.window(),
|
|
136 |
HwRendererContext::Wgpu(wgpu) => &wgpu.window,
|
|
137 |
}
|
|
138 |
}
|
|
139 |
|
15777
|
140 |
pub fn update(&mut self) {
|
15776
|
141 |
match self {
|
|
142 |
HwRendererContext::Gl(context) => unsafe {
|
15777
|
143 |
let (width, height) = Self::get_framebuffer_size(&context.window());
|
|
144 |
gl::Viewport(0, 0, width as i32, height as i32);
|
15776
|
145 |
},
|
|
146 |
HwRendererContext::Wgpu(context) => {
|
15777
|
147 |
context.swap_chain = Self::create_wpgu_swap_chain(
|
|
148 |
&context.window,
|
15776
|
149 |
&context.surface,
|
15777
|
150 |
&context.device,
|
15776
|
151 |
);
|
|
152 |
}
|
|
153 |
}
|
|
154 |
}
|
|
155 |
|
|
156 |
pub fn present(&mut self) -> Result<(), ErrorStub> {
|
|
157 |
match self {
|
|
158 |
HwRendererContext::Gl(context) => context.swap_buffers()?,
|
|
159 |
HwRendererContext::Wgpu(context) => {
|
|
160 |
let frame_view = &context.swap_chain.get_current_frame()?.output.view;
|
14188
|
161 |
|
15776
|
162 |
let mut encoder =
|
|
163 |
context
|
|
164 |
.device
|
|
165 |
.create_command_encoder(&CommandEncoderDescriptor {
|
|
166 |
label: Some("Main encoder"),
|
|
167 |
});
|
|
168 |
encoder.begin_render_pass(&RenderPassDescriptor {
|
|
169 |
color_attachments: &[RenderPassColorAttachmentDescriptor {
|
|
170 |
attachment: &frame_view,
|
|
171 |
resolve_target: None,
|
|
172 |
ops: Operations {
|
15777
|
173 |
load: LoadOp::Clear(Color {
|
|
174 |
r: 0.7,
|
|
175 |
g: 0.4,
|
|
176 |
b: 0.2,
|
|
177 |
a: 1.0,
|
|
178 |
}),
|
15776
|
179 |
store: false,
|
|
180 |
},
|
|
181 |
}],
|
|
182 |
depth_stencil_attachment: None,
|
|
183 |
});
|
|
184 |
let buffer = encoder.finish();
|
|
185 |
context.queue.submit(std::iter::once(buffer));
|
|
186 |
}
|
|
187 |
}
|
|
188 |
Ok(())
|
|
189 |
}
|
|
190 |
}
|
|
191 |
|
14187
|
192 |
fn main() {
|
15798
|
193 |
let use_wgpu = false;
|
|
194 |
let mut event_loop = EventLoop::<()>::new();
|
14702
|
195 |
let (w, h) = (1024.0, 768.0);
|
15776
|
196 |
|
15777
|
197 |
let mut context = HwRendererContext::new(&event_loop, dpi::LogicalSize::new(w, h), use_wgpu);
|
14187
|
198 |
|
15892
|
199 |
let mut engine = EngineInstance::new(Path::new("../../share/hedgewars/Data"));
|
15776
|
200 |
if !use_wgpu {
|
|
201 |
engine.world.create_renderer(w as u16, h as u16);
|
|
202 |
}
|
14188
|
203 |
|
14702
|
204 |
let mut dragging = false;
|
14188
|
205 |
|
14702
|
206 |
use std::time::Instant;
|
14188
|
207 |
|
14702
|
208 |
let mut now = Instant::now();
|
15776
|
209 |
let mut update_time = Instant::now();
|
|
210 |
let mut render_time = Instant::now();
|
14705
|
211 |
|
15798
|
212 |
let current_time = Instant::now();
|
|
213 |
let delta = current_time - now;
|
|
214 |
now = current_time;
|
|
215 |
let ms = delta.as_secs() as f64 * 1000.0 + delta.subsec_millis() as f64;
|
|
216 |
context.window().set_title(&format!("hwengine {:.3}ms", ms));
|
15766
|
217 |
|
15798
|
218 |
event_loop.run(move |event, _, control_flow| {
|
|
219 |
*control_flow = ControlFlow::Poll;
|
|
220 |
match event {
|
14705
|
221 |
Event::WindowEvent { event, .. } => match event {
|
|
222 |
WindowEvent::CloseRequested => {
|
15798
|
223 |
*control_flow = ControlFlow::Exit;
|
14705
|
224 |
}
|
15798
|
225 |
WindowEvent::Resized(_) | WindowEvent::ScaleFactorChanged { .. } => {
|
|
226 |
context.update()
|
|
227 |
}
|
15776
|
228 |
|
14705
|
229 |
WindowEvent::MouseInput { button, state, .. } => {
|
|
230 |
if let MouseButton::Right = button {
|
14709
|
231 |
dragging = state == ElementState::Pressed;
|
14702
|
232 |
}
|
14705
|
233 |
}
|
14709
|
234 |
|
14705
|
235 |
WindowEvent::MouseWheel { delta, .. } => {
|
|
236 |
let zoom_change = match delta {
|
|
237 |
MouseScrollDelta::LineDelta(x, y) => y as f32 * 0.1f32,
|
15798
|
238 |
MouseScrollDelta::PixelDelta(delta) => delta.y as f32 * 0.1f32,
|
14705
|
239 |
};
|
|
240 |
engine.world.move_camera(Point::ZERO, zoom_change);
|
|
241 |
}
|
|
242 |
_ => (),
|
|
243 |
},
|
|
244 |
Event::DeviceEvent { event, .. } => match event {
|
|
245 |
DeviceEvent::MouseMotion { delta } => {
|
|
246 |
if dragging {
|
|
247 |
engine
|
|
248 |
.world
|
|
249 |
.move_camera(Point::new(delta.0 as i32, delta.1 as i32), 0.0)
|
14702
|
250 |
}
|
|
251 |
}
|
14705
|
252 |
_ => {}
|
|
253 |
},
|
15798
|
254 |
|
14705
|
255 |
_ => (),
|
15798
|
256 |
}
|
|
257 |
|
|
258 |
let current_time = Instant::now();
|
|
259 |
|
|
260 |
if update_time.elapsed() > Duration::from_millis(10) {
|
|
261 |
update_time = current_time;
|
|
262 |
engine.world.step()
|
|
263 |
}
|
14188
|
264 |
|
15776
|
265 |
if render_time.elapsed() > Duration::from_millis(16) {
|
|
266 |
render_time = current_time;
|
|
267 |
if !use_wgpu {
|
|
268 |
engine.render();
|
|
269 |
}
|
15777
|
270 |
context.present().ok().unwrap();
|
15766
|
271 |
}
|
15798
|
272 |
});
|
14187
|
273 |
}
|