cen/app/
engine.rs

1use std::ops::{DerefMut};
2use std::sync::{Arc, Mutex};
3use std::time::SystemTime;
4use log::{debug, error, info};
5use winit::event::{StartCause, WindowEvent};
6use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
7use crate::app::app::{AppConfig, UserEvent};
8use crate::app::gui::{GuiComponent, GuiSystem};
9use crate::app::Window;
10use crate::graphics::Renderer;
11use crate::graphics::renderer::{RenderComponent, WindowState};
12
13pub struct Engine {
14    _start_time: SystemTime,
15    window: Box<Window>,
16    component: Arc<Mutex<dyn RenderComponent>>,
17    gui: Option<Arc<Mutex<dyn GuiComponent>>>,
18    gui_system: GuiSystem,
19    renderer: Renderer,
20    frame_count: usize,
21    last_print_time: SystemTime,
22    log_fps: bool,
23}
24
25impl Engine {
26    pub(crate) fn exit(&self) {
27        // Wait for all render operations to finish before exiting
28        // This ensures we can safely start dropping gpu resources
29        self.renderer.device.wait_idle();
30    }
31    
32    pub(crate) fn window_event(&mut self, event_loop: &ActiveEventLoop, event: WindowEvent) {
33        self.window.window_event( event.clone(), event_loop );
34
35        self.gui_system.on_window_event(self.window.winit_window(), &event);
36
37        match event {
38            WindowEvent::RedrawRequested => {
39                self.draw();
40            },
41            WindowEvent::Resized( _ ) => {
42            }
43            _ => (),
44        }
45    }
46
47    pub fn user_event(&mut self, _: &ActiveEventLoop, event: UserEvent) {
48        match event {
49            | UserEvent::GlslUpdate(path) => {
50                debug!("Reloading shader: {:?}", path);
51
52                if let Err(e) = self.renderer.pipeline_store.reload(&path) {
53                    error!("{}", e);
54                }
55            }
56            _ => (),
57        }
58    }
59    
60    pub fn new_events(&mut self, _: &ActiveEventLoop, cause: StartCause) {
61        match cause {
62            | StartCause::Poll => {
63                self.update();
64                self.draw();
65
66                if self.log_fps {
67                    let current_frame_time = SystemTime::now();
68                    let elapsed = current_frame_time.duration_since(self.last_print_time).unwrap();
69                    self.frame_count += 1;
70
71                    if elapsed.as_secs() >= 1 {
72                        info!("fps: {}, frametime: {:.3}ms", self.frame_count, elapsed.as_millis() as f32 / self.frame_count as f32);
73                        self.frame_count = 0;
74                        self.last_print_time = current_frame_time;
75                    }
76                }
77            }
78            _ => {}
79        }
80    }
81    
82    pub fn new(proxy: EventLoopProxy<UserEvent>, event_loop: &ActiveEventLoop, app_config: &AppConfig, user_component: Arc<Mutex<dyn RenderComponent>>, gui_component: Option<Arc<Mutex<dyn GuiComponent>>>) -> Engine {
83        // Create the graphics context
84        let window = Box::new(Window::create(&event_loop, "cen", app_config.width, app_config.height, app_config.fullscreen));
85
86        // Setup renderer
87        let window_state = WindowState {
88            window_handle: window.window_handle(),
89            display_handle: window.display_handle(),
90            extent2d: window.get_extent(),
91        };
92
93        let mut renderer = Renderer::new(&window_state, proxy, app_config.vsync);
94
95        user_component.lock().unwrap().initialize(&mut renderer);
96        
97        // Initialize gui renderer
98        let mut gui_system = GuiSystem::new(window.as_ref());
99        gui_system.initialize(&mut renderer);
100        
101        Engine {
102            _start_time: SystemTime::now(),
103            window,
104            renderer,
105            gui_system,
106            frame_count: 0,
107            last_print_time: SystemTime::now(),
108            component: user_component,
109            log_fps: app_config.log_fps,
110            gui: gui_component,
111        }
112    }
113    
114    pub fn update(&mut self) {
115        if let Some(gui) = &self.gui {
116            self.gui_system.update(
117                self.window.winit_window(),
118                &mut [gui.lock().unwrap().deref_mut()]
119            );
120        }
121    }
122    
123    pub fn draw(&mut self) {
124        self.renderer.update();
125        self.renderer.draw_frame(&mut [
126            self.component.lock().unwrap().deref_mut(),
127            &mut self.gui_system
128        ]);
129    }
130}