#![deny(clippy::all, clippy::pedantic)] use glfw::{Window, WindowBuilder}; use crate::object::Object; use crate::vector::Vec2; mod opengl; mod renderer; pub mod color; pub mod object; pub mod vector; pub mod vertex; pub use glfw::WindowSize; #[derive(Debug)] pub struct Engine { window: Window, } impl Engine { /// Creates and initializes a new engine. /// /// # Errors /// Will return `Err` if window creation or window configuration fails. pub fn new(window_size: &WindowSize, window_title: &str) -> Result { let window_builder = WindowBuilder::new(); #[cfg(feature = "debug")] let window_builder = window_builder.hint(glfw::window::Hint::OpenGLDebugContext, 1); let window = window_builder .create(window_size, window_title) .map_err(Error::CreateWindowFailed)?; window .make_context_current() .map_err(Error::ConfigureWindowFailed)?; window.set_framebuffer_size_callback(move |new_window_size| { crate::renderer::set_viewport(&Vec2::ZERO, &new_window_size); }); crate::renderer::initialize(&window).map_err(Error::InitializeRendererFailed)?; Ok(Self { window }) } /// Starts the engine. /// /// # Errors /// Will return `Err` if updating the window fails. pub fn start(&self, objects: &[Object], mut func: impl FnMut()) -> Result<(), Error> { while !self.window.should_close() { func(); crate::renderer::render(objects.iter().map(Object::renderable)); self.window .swap_buffers() .map_err(Error::UpdateWindowFailed)?; self.window .poll_events() .map_err(Error::UpdateWindowFailed)?; } Ok(()) } } /// Engine Error #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Failed to create window")] CreateWindowFailed(#[source] glfw::Error), #[error("Failed to configure window")] ConfigureWindowFailed(#[source] glfw::Error), #[error("Failed to initialize renderer")] InitializeRendererFailed(#[source] renderer::Error), #[error("Failed to update window")] UpdateWindowFailed(#[source] glfw::Error), }