use crate::ecs::World;
use crate::graphics::Renderer;
use crate::input::InputState;
use crate::time::Time;
use std::sync::Arc;
use winit::{
event::*,
event_loop::EventLoop,
window::{Window, WindowBuilder},
};
pub struct Engine {
event_loop: Option<EventLoop<()>>,
window: Arc<Window>,
renderer: Renderer,
world: World,
input: InputState,
time: Time,
}
pub struct EngineBuilder {
title: String,
width: u32,
height: u32,
}
impl EngineBuilder {
pub fn new() -> Self {
Self {
title: "Shadow Engine 2D".to_string(),
width: 1280,
height: 720,
}
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = title.into();
self
}
pub fn size(mut self, width: u32, height: u32) -> Self {
self.width = width;
self.height = height;
self
}
pub fn build(self) -> Engine {
let event_loop = EventLoop::new().unwrap();
let window = Arc::new(WindowBuilder::new()
.with_title(self.title)
.with_inner_size(winit::dpi::PhysicalSize::new(self.width, self.height))
.build(&event_loop)
.unwrap());
let renderer = pollster::block_on(Renderer::new(window.clone()));
let world = World::new();
let input = InputState::new();
let time = Time::new();
Engine {
event_loop: Some(event_loop),
window,
renderer,
world,
input,
time,
}
}
}
impl Default for EngineBuilder {
fn default() -> Self {
Self::new()
}
}
impl Engine {
pub fn builder() -> EngineBuilder {
EngineBuilder::new()
}
pub fn world(&self) -> &World {
&self.world
}
pub fn world_mut(&mut self) -> &mut World {
&mut self.world
}
pub fn run<F>(mut self, mut update_fn: F)
where
F: FnMut(&mut World, &InputState, &Time) + 'static,
{
let event_loop = self.event_loop.take().unwrap();
event_loop
.run(move |event, control_flow| {
match event {
Event::WindowEvent {
ref event,
window_id,
} if window_id == self.window.id() => {
self.input.process_event(event);
match event {
WindowEvent::CloseRequested => control_flow.exit(),
WindowEvent::Resized(physical_size) => {
self.renderer.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
self.time.update();
update_fn(&mut self.world, &self.input, &self.time);
match self.renderer.render(&self.world) {
Ok(_) => {}
Err(wgpu::SurfaceError::Lost) => {
self.renderer.resize(self.renderer.size())
}
Err(wgpu::SurfaceError::OutOfMemory) => control_flow.exit(),
Err(e) => eprintln!("Render error: {:?}", e),
}
self.input.end_frame();
}
_ => {}
}
}
Event::AboutToWait => {
self.window.request_redraw();
}
_ => {}
}
})
.unwrap();
}
}