use std::time::{Duration, Instant}; use gemini_engine::{ elements::{ containers::CanShade, view::{ScaleFitView, Wrapping}, }, elements3d::{DisplayMode, Mesh3D, Transform3D, Viewport}, gameloop::{sleep_fps, MainLoopRoot}, }; mod debug_manager; pub use debug_manager::DebugManager; #[allow(dead_code)] pub struct Root { canvas: ScaleFitView, viewport: Viewport, models: Vec, display_mode: DisplayMode, shader: Box, // Debug debug_manager: DebugManager, } impl Root { pub fn new( canvas: ScaleFitView, fov: f64, initial_viewport_transform: Transform3D, models: Vec, display_mode: DisplayMode, shader: impl CanShade + 'static, debug_manager: DebugManager, ) -> Self { let viewport_center = canvas.intended_size() / 2; let models = models .into_iter() .map(|m| { let mut m = m; m.transform *= -initial_viewport_transform; m }) .collect(); Self { canvas, viewport: Viewport::new(Transform3D::default(), fov, viewport_center), models, display_mode, shader: Box::new(shader), debug_manager, } } } impl MainLoopRoot for Root { type InputDataType = u8; fn frame(&mut self, _input_data: Option) { for model in &mut self.models { model.transform.rotation.y += 0.05; } } fn render_frame(&mut self) { // Auto-resize self.viewport.origin = self.canvas.intended_size() / 2; self.canvas.update(); let now = Instant::now(); self.canvas.view.blit( &self .viewport .render( self.models.iter().collect(), self.display_mode.clone(), ) .shade_with(&mut self.shader), Wrapping::Ignore, ); self.debug_manager.log_blitting_since(now); let now = Instant::now(); let _ = self.canvas.view.display_render(); self.debug_manager.log_rendering_since(now); self.debug_manager.frame(); } fn sleep_and_get_input_data( &self, fps: f32, elapsed: Duration, ) -> (bool, Option) { // Hijack the sleep function to print elapsed times before falling back to default sleep function self.debug_manager.print_benchmark(fps, elapsed); (sleep_fps(fps, Some(elapsed)), None) } }