oxygengine_backend_desktop/
app.rs1use crate::resource::DesktopAppEvents;
2use core::app::{App, AppLifeCycle, AppParams, BackendAppRunner};
3use glutin::{
4 dpi::LogicalSize,
5 event::{Event, WindowEvent},
6 event_loop::{ControlFlow, EventLoop},
7 platform::run_return::EventLoopExtRunReturn,
8 window::{Fullscreen, Window, WindowBuilder},
9 ContextBuilder, ContextWrapper, PossiblyCurrent,
10};
11use std::{
12 cell::RefCell,
13 collections::HashMap,
14 env::{current_exe, set_current_dir, var},
15 rc::Rc,
16 sync::Arc,
17};
18
19pub type DesktopContextWrapper = ContextWrapper<PossiblyCurrent, Window>;
20
21pub fn desktop_app_params() -> AppParams {
22 let mut result = HashMap::default();
23 let mut key = None;
24 for arg in std::env::args() {
25 if let Some(value) = arg.strip_prefix("--") {
26 key = Some(value.to_owned());
27 result.insert(value.to_owned(), Default::default());
28 } else if let Some(value) = arg.strip_prefix('-') {
29 key = Some(value.to_owned());
30 result.insert(value.to_owned(), Default::default());
31 } else if let Some(value) = arg.strip_prefix('/') {
32 key = Some(value.to_owned());
33 result.insert(value.to_owned(), Default::default());
34 } else if let Some(key) = key.take() {
35 result.insert(key, arg.to_owned());
36 }
37 }
38 AppParams::new(result)
39}
40
41pub struct DesktopAppConfig {
42 pub title: String,
43 pub width: u32,
44 pub height: u32,
45 pub fullscreen: bool,
46 pub vsync: bool,
47 pub depth: bool,
48 pub stencil: bool,
49}
50
51impl Default for DesktopAppConfig {
52 fn default() -> Self {
53 Self {
54 title: "Oxygengine Game".to_owned(),
55 width: 1024,
56 height: 576,
57 fullscreen: false,
58 vsync: false,
59 depth: false,
60 stencil: false,
61 }
62 }
63}
64
65pub struct DesktopAppRunner {
66 event_loop: EventLoop<()>,
67 context_wrapper: Arc<DesktopContextWrapper>,
68}
69
70impl DesktopAppRunner {
71 pub fn new(config: DesktopAppConfig) -> Self {
72 if let Ok(path) = var("OXY_ROOT_PATH") {
73 let _ = set_current_dir(path);
74 } else if let Ok(mut dir) = current_exe() {
75 dir.pop();
76 let _ = set_current_dir(dir);
77 }
78 let DesktopAppConfig {
79 title,
80 width,
81 height,
82 fullscreen,
83 vsync,
84 depth,
85 stencil,
86 } = config;
87 let fullscreen = if fullscreen {
88 Some(Fullscreen::Borderless(None))
89 } else {
90 None
91 };
92 let event_loop = EventLoop::new();
93 let window_builder = WindowBuilder::new()
94 .with_title(title.as_str())
95 .with_inner_size(LogicalSize::new(width, height))
96 .with_fullscreen(fullscreen);
97 let context_wrapper = Arc::new(unsafe {
98 let mut builder = ContextBuilder::new()
99 .with_vsync(vsync)
100 .with_double_buffer(Some(true))
101 .with_hardware_acceleration(Some(true));
102 if depth {
103 builder = builder.with_depth_buffer(24);
104 }
105 if stencil {
106 builder = builder.with_stencil_buffer(8);
107 }
108 builder
109 .build_windowed(window_builder, &event_loop)
110 .expect("Could not build windowed context wrapper!")
111 .make_current()
112 .expect("Could not make windowed context wrapper a current one!")
113 });
114 Self {
115 event_loop,
116 context_wrapper,
117 }
118 }
119
120 pub fn context_wrapper(&self) -> Arc<DesktopContextWrapper> {
121 self.context_wrapper.clone()
122 }
123}
124
125impl BackendAppRunner<()> for DesktopAppRunner {
126 fn run(&mut self, app: Rc<RefCell<App>>) -> Result<(), ()> {
127 let mut running = true;
128 while running {
129 self.event_loop.run_return(|event, _, control_flow| {
130 *control_flow = ControlFlow::Poll;
131 match event {
132 Event::MainEventsCleared => {
133 let mut app = app.borrow_mut();
134 app.process();
135 app.multiverse
136 .default_universe_mut()
137 .unwrap()
138 .expect_resource_mut::<DesktopAppEvents>()
139 .clear();
140 let _ = self.context_wrapper.swap_buffers();
141 if !app.multiverse.is_running() {
142 running = false;
143 }
144 *control_flow = ControlFlow::Exit;
145 }
146 Event::WindowEvent { event, .. } => match event {
147 WindowEvent::Resized(physical_size) => {
148 self.context_wrapper.resize(physical_size);
149 app.borrow_mut()
150 .multiverse
151 .default_universe_mut()
152 .unwrap()
153 .expect_resource_mut::<DesktopAppEvents>()
154 .push(event.to_static().unwrap());
155 }
156 WindowEvent::CloseRequested => {
157 for universe in app.borrow_mut().multiverse.universes_mut() {
158 universe.expect_resource_mut::<AppLifeCycle>().running = false;
159 }
160 }
161 event => {
162 if let Some(event) = event.to_static() {
163 app.borrow_mut()
164 .multiverse
165 .default_universe_mut()
166 .unwrap()
167 .expect_resource_mut::<DesktopAppEvents>()
168 .push(event);
169 }
170 }
171 },
172 _ => {}
173 }
174 });
175 }
176 Ok(())
177 }
178}