Files
gaym/src/main.rs
T
2025-04-28 09:21:27 +03:00

226 lines
6.6 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 input::InputState;
use render::{
asset::{AssetLoader, TextureLoadStage},
Renderer,
};
use winit::{
application::ApplicationHandler,
dpi::PhysicalSize,
event::{DeviceEvent, DeviceId, StartCause, WindowEvent},
event_loop::{ActiveEventLoop, EventLoop},
window::{CursorGrabMode, Window, WindowId},
};
use world::{camera::Camera, ChunkGenerator, NoiseChunkGenerator, World};
pub mod error;
pub mod input;
pub mod render;
pub mod world;
pub struct Engine {
window: Option<Arc<Window>>,
renderer: Option<Renderer>,
assets: Option<AssetLoader<TextureLoadStage>>,
world: Option<World>,
input: InputState,
camera: Camera,
generator: Box<dyn ChunkGenerator>,
last_frame: 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)?);
window.set_cursor_grab(CursorGrabMode::Locked).ok();
window.set_cursor_visible(false);
let render = Renderer::from_window(window.clone(), assets)?;
self.window = Some(window);
self.renderer = Some(render);
}
Ok(())
}
pub fn update_camera(&mut self, dt: f64) {
const SENSITIVITY: f64 = 0.15;
const HORIZONTAL_SPEED: f32 = 17.5;
const VERTICAL_SPEED: f32 = 15.0;
let (mouse_dx, mouse_dy) = self.input.mouse_delta();
let mouse_dx = mouse_dx * dt * SENSITIVITY;
let mouse_dy = mouse_dy * dt * SENSITIVITY;
self.camera.turn(mouse_dy as f32, mouse_dx as f32);
let want_dz = self.input.forward as i32 - self.input.backwards as i32;
let want_dx = self.input.right as i32 - self.input.left as i32;
let want_dy = self.input.up as i32 - self.input.down as i32;
if want_dx == 0 && want_dy == 0 && want_dz == 0 {
return;
}
let want_horizontal_vector = if want_dx != 0 || want_dz != 0 {
let look_vector = self.camera.horizontal_look_vector();
let right_vector = look_vector.cross(Vec3::Y);
((want_dx as f32) * right_vector + (want_dz as f32) * look_vector).normalize()
} else {
Vec3::ZERO
};
let want_vertical_vector = (want_dy as f32) * Vec3::Y;
let horizontal_vector = want_horizontal_vector * dt as f32 * HORIZONTAL_SPEED;
let vertical_vector = want_vertical_vector * dt as f32 * VERTICAL_SPEED;
self.camera
.move_towards(horizontal_vector + vertical_vector);
}
}
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 => {
let frame_delta = self.last_frame.elapsed();
self.last_frame = Instant::now();
let frame_dt = frame_delta.as_secs_f64();
self.update_camera(frame_dt);
if let (Some(render), Some(world)) = (self.renderer.as_mut(), self.world.as_mut()) {
let camera_position = self.camera.position();
world.update_with_camera(camera_position, &mut *self.generator);
if let Err(error) = render.render(&mut self.camera, world) {
log::error!("Render error: {error}");
event_loop.exit();
}
}
}
WindowEvent::KeyboardInput { event, .. } => self.input.key_event(event),
_ => (),
}
}
fn device_event(
&mut self,
event_loop: &ActiveEventLoop,
device_id: DeviceId,
event: DeviceEvent,
) {
let _ = event_loop;
let _ = device_id;
if let DeviceEvent::MouseMotion { delta } = event {
self.input.add_mouse_motion(delta.0, delta.1);
}
}
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: Camera::new(),
input: InputState::new(),
generator: Box::new(NoiseChunkGenerator::from_seed(1234)),
last_frame: 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
}
}
}