kobalt_runtime/
desktop.rs1use kobalt_core::types::Size;
4use kobalt_render::Renderer;
5use std::sync::Arc;
6use winit::application::ApplicationHandler;
7use winit::event::{Event, WindowEvent};
8use winit::event_loop::{ActiveEventLoop, EventLoop};
9use winit::window::{Window, WindowAttributes, WindowId};
10
11pub struct DesktopWindow {
13 window: Arc<Window>,
14 renderer: Option<Renderer>,
15}
16
17impl DesktopWindow {
18 async fn new(event_loop: &ActiveEventLoop, title: &str, width: u32, height: u32) -> Self {
20 let attributes = WindowAttributes::default()
21 .with_title(title)
22 .with_inner_size(winit::dpi::PhysicalSize::new(width, height));
23
24 let window = Arc::new(event_loop.create_window(attributes).unwrap());
25
26 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
28 backends: wgpu::Backends::all(),
29 ..Default::default()
30 });
31
32 let surface = instance.create_surface(window.clone()).unwrap();
33
34 let size = Size::new(width as f32, height as f32);
35 let renderer = Renderer::new_with_instance(instance, surface, size).await;
36
37 Self {
38 window,
39 renderer: Some(renderer),
40 }
41 }
42
43 pub fn window(&self) -> &Window {
45 &self.window
46 }
47
48 pub fn renderer(&self) -> &Renderer {
50 self.renderer.as_ref().unwrap()
51 }
52
53 pub fn renderer_mut(&mut self) -> &mut Renderer {
55 self.renderer.as_mut().unwrap()
56 }
57
58 pub fn resize(&mut self, width: u32, height: u32) {
60 if let Some(renderer) = &mut self.renderer {
61 renderer.resize(Size::new(width as f32, height as f32));
62 }
63 }
64}
65
66pub struct DesktopApp<F>
68where
69 F: FnMut(&mut DesktopWindow, &Event<()>) + 'static,
70{
71 window: Option<DesktopWindow>,
72 on_event: F,
73 window_config: WindowConfig,
74}
75
76struct WindowConfig {
77 title: String,
78 width: u32,
79 height: u32,
80}
81
82impl<F> DesktopApp<F>
83where
84 F: FnMut(&mut DesktopWindow, &Event<()>) + 'static,
85{
86 pub fn new(title: &str, width: u32, height: u32, on_event: F) -> Self {
88 Self {
89 window: None,
90 on_event,
91 window_config: WindowConfig {
92 title: title.to_string(),
93 width,
94 height,
95 },
96 }
97 }
98
99 pub fn run(mut self) -> Result<(), Box<dyn std::error::Error>> {
101 let event_loop = EventLoop::new()?;
102 event_loop.run_app(&mut self)?;
103 Ok(())
104 }
105}
106
107impl<F> ApplicationHandler for DesktopApp<F>
108where
109 F: FnMut(&mut DesktopWindow, &Event<()>) + 'static,
110{
111 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
112 if self.window.is_none() {
113 let window = pollster::block_on(DesktopWindow::new(
114 event_loop,
115 &self.window_config.title,
116 self.window_config.width,
117 self.window_config.height,
118 ));
119 self.window = Some(window);
120 }
121 }
122
123 fn window_event(
124 &mut self,
125 event_loop: &ActiveEventLoop,
126 window_id: WindowId,
127 event: WindowEvent,
128 ) {
129 if let Some(window) = &mut self.window {
130 if window.window.id() == window_id {
131 match event {
132 WindowEvent::CloseRequested => {
133 event_loop.exit();
134 }
135 WindowEvent::Resized(physical_size) => {
136 window.resize(physical_size.width, physical_size.height);
137 }
138 WindowEvent::RedrawRequested => {
139 (self.on_event)(
141 window,
142 &Event::WindowEvent {
143 window_id,
144 event: WindowEvent::RedrawRequested,
145 },
146 );
147 window.window.request_redraw();
148 }
149 _ => {}
150 }
151 }
152 }
153 }
154
155 fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
156 if let Some(window) = &self.window {
157 window.window.request_redraw();
158 }
159 }
160}