Files
gaym/src/main.rs
T
2025-04-27 19:22:16 +03:00

180 lines
4.9 KiB
Rust

#![feature(duration_constants)]
#![allow(clippy::new_without_default, clippy::let_unit_value)]
use std::{process::ExitCode, sync::Arc, time::Instant};
use error::Error;
use glam::Vec3;
use render::{
asset::{AssetLoader, TextureLoadStage},
Renderer,
};
use winit::{
application::ApplicationHandler,
dpi::PhysicalSize,
event::{DeviceEvent, DeviceId, StartCause, WindowEvent},
event_loop::{ActiveEventLoop, EventLoop},
window::{Window, WindowId},
};
use world::{Chunk, ChunkGenerator, NoiseChunkGenerator, World};
pub mod error;
pub mod render;
pub mod world;
pub struct Engine {
window: Option<Arc<Window>>,
renderer: Option<Renderer>,
assets: Option<AssetLoader<TextureLoadStage>>,
world: Option<World>,
camera_position: Vec3,
generator: Box<dyn ChunkGenerator>,
start: Instant,
}
impl Engine {
pub fn ensure_renderer(&mut self, event_loop: &ActiveEventLoop) -> Result<(), Error> {
if self.window.is_none() {
let assets = self.assets.take().expect("asset loader");
let window_attributes = Window::default_attributes()
.with_resizable(false)
.with_inner_size(PhysicalSize::new(800, 600));
let window = Arc::new(event_loop.create_window(window_attributes)?);
let render = Renderer::from_window(window.clone(), assets)?;
self.window = Some(window);
self.renderer = Some(render);
}
Ok(())
}
}
impl ApplicationHandler for Engine {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if let Err(error) = self.ensure_renderer(event_loop) {
log::error!("Renderer setup error: {error}");
event_loop.exit();
}
}
fn exiting(&mut self, event_loop: &ActiveEventLoop) {
let _ = event_loop;
log::info!("Exiting");
self.renderer = None;
}
fn suspended(&mut self, event_loop: &ActiveEventLoop) {
let _ = event_loop;
}
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
let _ = event_loop;
let _ = cause;
}
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: ()) {
let _ = event_loop;
let _ = event;
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
window_id: WindowId,
event: WindowEvent,
) {
let _ = window_id;
match event {
WindowEvent::CloseRequested => {
log::info!("Close requested");
event_loop.exit();
}
WindowEvent::Resized(size) => {
log::info!("Window resized: {size:?}");
if let Some(render) = self.renderer.as_mut() {
render.set_swapchain_dirty();
}
}
WindowEvent::RedrawRequested => {
if let (Some(render), Some(world)) = (self.renderer.as_mut(), self.world.as_mut()) {
let delta = self.start.elapsed();
let dt = delta.as_secs_f64();
self.camera_position = Vec3::new(
(dt.cos() * 32.0) as f32 + (Chunk::SIZE / 2) as f32,
48.0,
(dt.sin() * 32.0) as f32 + (Chunk::SIZE / 2) as f32,
);
world.update_with_camera(self.camera_position, &mut *self.generator);
if let Err(error) = render.render(self.camera_position, world) {
log::error!("Render error: {error}");
event_loop.exit();
}
}
}
_ => (),
}
}
fn device_event(
&mut self,
event_loop: &ActiveEventLoop,
device_id: DeviceId,
event: DeviceEvent,
) {
let _ = event_loop;
let _ = device_id;
let _ = event;
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
let _ = event_loop;
if let Some(window) = self.window.as_ref() {
window.request_redraw();
}
}
fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
let _ = event_loop;
}
}
fn run() -> Result<(), Error> {
let loader = AssetLoader::new();
let (loader, block_registry) = loader.load_block_definitions()?;
let world = World::new(block_registry);
let event_loop = EventLoop::new()?;
let mut engine = Engine {
window: None,
renderer: None,
assets: Some(loader),
world: Some(world),
camera_position: Vec3::ZERO,
generator: Box::new(NoiseChunkGenerator::from_seed(1234)),
start: Instant::now(),
};
event_loop.run_app(&mut engine)?;
Ok(())
}
fn main() -> ExitCode {
env_logger::init();
match run() {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
log::error!("Exited with error: {error}");
ExitCode::FAILURE
}
}
}