From 097bd50e4b6f8637f6ee8c50ff321da379a96beb Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 19 Jan 2023 15:41:45 +0100 Subject: [PATCH 01/81] start rewrite --- .gitignore | 3 + Cargo.toml | 2 +- src/game.rs | 162 --------------------- src/game/assets.rs | 15 -- src/game/assets/textures.rs | 103 -------------- src/game/blocks.rs | 141 ------------------- src/game/camera.rs | 157 --------------------- src/game/controller.rs | 116 ---------------- src/game/display.rs | 16 --- src/game/items.rs | 9 -- src/game/options.rs | 13 -- src/game/physics.rs | 46 ------ src/game/player.rs | 7 - src/game/shaders.rs | 17 --- src/game/shaders/chunk.rs | 34 ----- src/game/shaders/colored2d.rs | 10 -- src/game/shaders/glsl/chunk.frag | 15 -- src/game/shaders/glsl/chunk.vert | 19 --- src/game/shaders/glsl/colored2d.frag | 8 -- src/game/shaders/glsl/colored2d.vert | 7 - src/game/world.rs | 201 --------------------------- src/game/world/chunk.rs | 45 ------ src/game/world/thread.rs | 97 ------------- src/game/world/thread/mesh_gen.rs | 139 ------------------ src/game/world/thread/world_gen.rs | 58 -------- src/logging.rs | 45 ------ src/main.rs | 6 +- 27 files changed, 5 insertions(+), 1486 deletions(-) delete mode 100644 src/game.rs delete mode 100644 src/game/assets.rs delete mode 100644 src/game/assets/textures.rs delete mode 100644 src/game/blocks.rs delete mode 100644 src/game/camera.rs delete mode 100644 src/game/controller.rs delete mode 100644 src/game/display.rs delete mode 100644 src/game/items.rs delete mode 100644 src/game/options.rs delete mode 100644 src/game/physics.rs delete mode 100644 src/game/player.rs delete mode 100644 src/game/shaders.rs delete mode 100644 src/game/shaders/chunk.rs delete mode 100644 src/game/shaders/colored2d.rs delete mode 100644 src/game/shaders/glsl/chunk.frag delete mode 100644 src/game/shaders/glsl/chunk.vert delete mode 100644 src/game/shaders/glsl/colored2d.frag delete mode 100644 src/game/shaders/glsl/colored2d.vert delete mode 100644 src/game/world.rs delete mode 100644 src/game/world/chunk.rs delete mode 100644 src/game/world/thread.rs delete mode 100644 src/game/world/thread/mesh_gen.rs delete mode 100644 src/game/world/thread/world_gen.rs delete mode 100644 src/logging.rs diff --git a/.gitignore b/.gitignore index 6985cf1..07db1ba 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ Cargo.lock # MSVC Windows builds of rustc generate these, which store debugging information *.pdb + +#old source +_src diff --git a/Cargo.toml b/Cargo.toml index 20a81de..0905424 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ glam = { version = "0.22", features = ["debug-glam-assert", "mint", "fast-math"] hashbrown = "0.13" noise = "0.8" rayon = "1.6" -#ordered-float = "3.4" +specs = { version = "0.18", features = ["specs-derive"] } [features] default = [] diff --git a/src/game.rs b/src/game.rs deleted file mode 100644 index 3c9d308..0000000 --- a/src/game.rs +++ /dev/null @@ -1,162 +0,0 @@ -use glam::Vec2; -use glium::Surface; -use glium::glutin::{ - event::{Event, WindowEvent, DeviceEvent}, - event_loop::{EventLoop, ControlFlow}, -}; -use std::time::Instant; - -mod assets; -mod display; -mod shaders; -mod camera; -mod controller; -mod world; -mod blocks; -mod items; -mod options; -mod physics; -mod player; - -use assets::Assets; -use display::init_display; -use shaders::Programs; -use camera::Camera; -use controller::Controls; -use world::World; -use options::GameOptions; - -struct State { - pub camera: Camera, - pub first_draw: bool, - pub controls: Controls, - pub world: World -} -impl State { - pub fn init() -> Self { - Self { - first_draw: true, - camera: Camera::default(), - controls: Controls::default(), - world: World::new(), - } - } -} - -pub fn run() { - log::info!("starting up"); - let event_loop = EventLoop::new(); - log::info!("initializing display"); - let display = init_display(&event_loop); - log::info!("compiling shaders"); - let programs = Programs::compile_all(&display); - log::info!("loading assets"); - let assets = Assets::load_all_sync(&display); - log::info!("init game options"); - let options = GameOptions::default(); - log::info!("init game state"); - let mut state = State::init(); - state.camera.position = [0., 260., -1.]; - log::info!("game loaded"); - - //======================= - // let vertex1 = ChunkVertex { position: [-0.5, -0.5, 0.], uv: [0., 0.], normal: [0., 1., 0.] }; - // let vertex2 = ChunkVertex { position: [ 0.0, 0.5, 0.], uv: [0., 1.], normal: [0., 1., 0.] }; - // let vertex3 = ChunkVertex { position: [ 0.5, -0.5, 0.], uv: [1., 1.], normal: [0., 1., 0.] }; - // let shape = vec![vertex1, vertex2, vertex3]; - // let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap(); - //======================= - - let mut last_render = Instant::now(); - - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; - match event { - // Mouse motion - Event::DeviceEvent { - event: DeviceEvent::MouseMotion{ delta, }, .. - } => { - state.controls.process_mouse_input(delta.0, delta.1); - return - } - // Keyboard input - Event::DeviceEvent { event: DeviceEvent::Key(input), .. } => { - if let Some(key) = input.virtual_keycode { - state.controls.process_keyboard_input(key, input.state); - } - return - } - // Window events - Event::WindowEvent { event, .. } => { - match event { - WindowEvent::CloseRequested => { - log::info!("exit requested"); - *control_flow = ControlFlow::Exit; - return - }, - WindowEvent::Resized(size) => { - state.camera.update_perspective_matrix((size.width, size.height)); - }, - _ => return - } - }, - Event::MainEventsCleared => (), - _ => return - } - - //Calculate delta time - let now = Instant::now(); - let dt = (now - last_render).as_secs_f32(); - last_render = now; - - //Update controls - state.controls.calculate(dt).apply_to_camera(&mut state.camera); - - //Load new chunks - - state.world.update_loaded_chunks( - Vec2::new(state.camera.position[0], state.camera.position[2]), - &options, - &display - ); - - //Start drawing - let mut target = display.draw(); - target.clear_color_and_depth((0.5, 0.5, 1., 1.), 1.); - - //Compute camera - if state.first_draw { - let target_dimensions = target.get_dimensions(); - state.camera.update_perspective_matrix(target_dimensions); - } - let perspective = state.camera.perspective_matrix; - let view = state.camera.view_matrix(); - - //Draw chunks - state.world.render(&mut target, &programs, &assets, perspective, view, &options); - - //Draw example triangle - // target.draw( - // &vertex_buffer, - // glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList), - // &programs.chunk, - // &uniform! { - // model: [ - // [1., 0., 0., 0.], - // [0., 1., 0., 0.], - // [0., 0., 1., 0.], - // [0., 0., 0., 1.0_f32] - // ], - // view: view, - // perspective: perspective, - // tex: Sampler(&assets.textures.block_atlas, sampler_nearest) - // }, - // &Default::default() - // ).unwrap(); - - //Finish drawing - target.finish().unwrap(); - - state.first_draw = false; - }); -} diff --git a/src/game/assets.rs b/src/game/assets.rs deleted file mode 100644 index 27687a9..0000000 --- a/src/game/assets.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub mod textures; - -use textures::Textures; - -pub struct Assets { - pub textures: Textures -} -impl Assets { - /// Load all assets synchronously - pub fn load_all_sync(display: &glium::Display) -> Self { - Self { - textures: Textures::load_sync(display) - } - } -} diff --git a/src/game/assets/textures.rs b/src/game/assets/textures.rs deleted file mode 100644 index c7cf857..0000000 --- a/src/game/assets/textures.rs +++ /dev/null @@ -1,103 +0,0 @@ -use std::{fs, io, path::PathBuf, sync::atomic::AtomicU16}; -use rayon::prelude::*; -use glium::texture::{RawImage2d, SrgbTexture2d, SrgbTexture2dArray}; - -//This code is terrible and has a alot of duplication - -fn load_png(file_path: &str, display: &glium::Display) -> SrgbTexture2d { - log::info!("loading texture {}", file_path); - - //Load file - let data = fs::read(file_path) - .unwrap_or_else(|_| panic!("Failed to load texture: {}", file_path)); - - //decode image data - let image_data = image::load( - io::Cursor::new(&data), - image::ImageFormat::Png - ).unwrap().to_rgba8(); - - //Create raw glium image - let image_dimensions = image_data.dimensions(); - let raw_image = RawImage2d::from_raw_rgba_reversed( - &image_data.into_raw(), - image_dimensions - ); - - //Create texture - SrgbTexture2d::new(display, raw_image).unwrap() -} - -fn load_png_array(file_paths: &[PathBuf], display: &glium::Display) -> SrgbTexture2dArray { - let counter = AtomicU16::new(0); - let raw_images: Vec> = file_paths.par_iter().enumerate().map(|(_, file_path)| { - - let fname: &str = file_path.file_name().unwrap_or_default().to_str().unwrap(); - - //Load file - let data = fs::read(file_path).expect(&format!("Failed to load texture {}", fname)); - - //decode image data - let image_data = image::load( - io::Cursor::new(&data), - image::ImageFormat::Png - ).unwrap().to_rgba8(); - - //Create raw glium image - let image_dimensions = image_data.dimensions(); - let raw_image = RawImage2d::from_raw_rgba_reversed( - &image_data.into_raw(), - image_dimensions - ); - - let counter = counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1; - log::info!("loaded texture {}/{}: {}", counter, file_paths.len(), fname); - - raw_image - }).collect(); - SrgbTexture2dArray::new(display, raw_images).unwrap() -} - -pub struct Textures { - pub blocks: SrgbTexture2dArray -} -impl Textures { - /// Load textures synchronously, one by one and upload them to the GPU - pub fn load_sync(display: &glium::Display) -> Self { - Self { - blocks: load_png_array(&[ - "./assets/blocks/stone.png".into(), - "./assets/blocks/dirt.png".into(), - "./assets/blocks/grass_top.png".into(), - "./assets/blocks/grass_side.png".into(), - "./assets/blocks/sand.png".into(), - "./assets/blocks/bedrock.png".into(), - "./assets/blocks/wood.png".into(), - "./assets/blocks/wood_top.png".into(), - "./assets/blocks/leaf.png".into(), - "./assets/blocks/torch.png".into(), - "./assets/blocks/tall_grass.png".into(), - "./assets/blocks/snow.png".into(), - "./assets/blocks/grass_side_snow.png".into(), - ], display) - } - } -} - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -pub enum BlockTexture { - Stone = 0, - Dirt = 1, - GrassTop = 2, - GrassSide = 3, - Sand = 4, - Bedrock = 5, - Wood = 6, - WoodTop = 7, - Leaf = 8, - Torch = 9, - TallGrass = 10, - Snow = 11, - GrassSideSnow = 12, -} diff --git a/src/game/blocks.rs b/src/game/blocks.rs deleted file mode 100644 index 9db47b6..0000000 --- a/src/game/blocks.rs +++ /dev/null @@ -1,141 +0,0 @@ -use strum::{EnumIter, IntoEnumIterator}; -use crate::game::{ - items::Item, - assets::textures::BlockTexture, -}; - - -#[derive(Clone, Copy, Debug)] -pub enum CollisionType { - Solid, - Liquid, - Ladder, -} - -#[derive(Clone, Copy, Debug)] -pub enum RenderType { - OpaqueBlock, - TranslucentBlock, - TranslucentLiquid, - CrossShape -} - -#[derive(Clone, Copy, Debug)] -pub struct BlockTextures { - pub top: BlockTexture, - pub bottom: BlockTexture, - pub left: BlockTexture, - pub right: BlockTexture, - pub back: BlockTexture, - pub front: BlockTexture, -} -impl BlockTextures { - pub const fn all(tex: BlockTexture) -> Self { - Self { - top: tex, - bottom: tex, - left: tex, - right: tex, - back: tex, - front: tex, - } - } - pub const fn top_sides_bottom(top: BlockTexture, sides: BlockTexture, bottom: BlockTexture) -> Self { - Self { - top, - bottom, - left: sides, - right: sides, - back: sides, - front: sides, - } - } -} - -#[derive(Clone, Copy, Debug)] -pub struct BlockDescriptor { - pub name: &'static str, - pub id: &'static str, - pub collision: Option, - pub raycast_collision: bool, - pub render: Option<(RenderType, BlockTextures)>, - pub item: Option, -} -impl BlockDescriptor { - //Not using the Default trait because this function has to be const! - pub const fn default() -> Self { - Self { - name: "default", - id: "default", - collision: Some(CollisionType::Solid), - raycast_collision: true, - render: Some((RenderType::OpaqueBlock, BlockTextures::all(BlockTexture::Stone))), - item: None - } - } -} - -#[derive(Clone, Copy, Debug, EnumIter)] -pub enum Block { - Air, - Stone, - Dirt, - Grass, - Sand, -} -impl Block { - //TODO make this O(1) with compile-time computed maps - pub fn get_by_id(id: &str) -> Option { - for block in Self::iter() { - if block.descriptor().id == id { - return Some(block) - } - } - None - } - - pub const fn descriptor(self) -> BlockDescriptor { - match self { - Self::Air => BlockDescriptor { - name: "Air", - id: "air", - collision: None, - raycast_collision: false, - render: None, - item: None, - }, - Self::Stone => BlockDescriptor { - name: "Stone", - id: "stone", - collision: Some(CollisionType::Solid), - raycast_collision: true, - render: Some((RenderType::OpaqueBlock, BlockTextures::all(BlockTexture::Stone))), - item: Some(Item::StoneBlock) - }, - Self::Dirt => BlockDescriptor { - name: "Dirt", - id: "dirt", - collision: Some(CollisionType::Solid), - raycast_collision: true, - render: Some((RenderType::OpaqueBlock, BlockTextures::all(BlockTexture::Dirt))), - item: Some(Item::DirtBlock) - }, - Self::Grass => BlockDescriptor { - name: "Grass", - id: "grass", - collision: Some(CollisionType::Solid), - raycast_collision: true, - render: Some((RenderType::OpaqueBlock, BlockTextures::top_sides_bottom(BlockTexture::GrassTop, BlockTexture::GrassSide, BlockTexture::Dirt))), - item: Some(Item::DirtBlock) - }, - Self::Sand => BlockDescriptor { - name: "Sand", - id: "sand", - collision: Some(CollisionType::Solid), - raycast_collision: true, - render: Some((RenderType::OpaqueBlock, BlockTextures::all(BlockTexture::Sand))), //this is not a sand tex - item: Some(Item::StoneBlock) - } - } - } -} diff --git a/src/game/camera.rs b/src/game/camera.rs deleted file mode 100644 index 5dc2ce6..0000000 --- a/src/game/camera.rs +++ /dev/null @@ -1,157 +0,0 @@ -// Perspective/View matrix code from: -// https://glium.github.io/glium/book/tuto-10-perspective.html -// https://glium.github.io/glium/book/tuto-12-camera.html -// I don't understand anything but it works - -use std::f32::consts::PI; - -pub fn calculate_forward_direction(yaw: f32, pitch: f32) -> [f32; 3] { - [ - yaw.cos() * pitch.cos(), - pitch.sin(), - yaw.sin() * pitch.cos(), - ] -} - -fn normalize_plane(mut plane: [f32; 4]) -> [f32; 4] { - let mag = (plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]).sqrt(); - plane[0] = plane[0] / mag; - plane[1] = plane[1] / mag; - plane[2] = plane[2] / mag; - plane[3] = plane[3] / mag; - plane -} - -pub struct Camera { - pub yaw: f32, - pub pitch: f32, - pub position: [f32; 3], - pub direction: [f32; 3], - pub up: [f32; 3], - pub fov: f32, - pub znear: f32, - pub zfar: f32, - pub perspective_matrix: [[f32; 4]; 4], -} -impl Camera { - /// Update camera direction based on yaw/pitch - pub fn update_direction(&mut self) { - self.direction = calculate_forward_direction(self.yaw, self.pitch); - } - pub fn forward(&mut self, amount: f32) { - self.position[0] += self.direction[0] * amount; - self.position[1] += self.direction[1] * amount; - self.position[2] += self.direction[2] * amount; - } - - pub fn view_matrix(&self) -> [[f32; 4]; 4] { - let position = self.position; - let direction = self.direction; - let up = self.up; - - let f = { - let f = direction; - let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2]; - let len = len.sqrt(); - [f[0] / len, f[1] / len, f[2] / len] - }; - let s = [up[1] * f[2] - up[2] * f[1], - up[2] * f[0] - up[0] * f[2], - up[0] * f[1] - up[1] * f[0]]; - let s_norm = { - let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2]; - let len = len.sqrt(); - [s[0] / len, s[1] / len, s[2] / len] - }; - let u = [f[1] * s_norm[2] - f[2] * s_norm[1], - f[2] * s_norm[0] - f[0] * s_norm[2], - f[0] * s_norm[1] - f[1] * s_norm[0]]; - let p = [-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2], - -position[0] * u[0] - position[1] * u[1] - position[2] * u[2], - -position[0] * f[0] - position[1] * f[1] - position[2] * f[2]]; - [ - [s_norm[0], u[0], f[0], 0.0], - [s_norm[1], u[1], f[1], 0.0], - [s_norm[2], u[2], f[2], 0.0], - [p[0], p[1], p[2], 1.0], - ] - } - - pub fn update_perspective_matrix(&mut self, target_dimensions: (u32, u32)) { - let znear = self.znear; - let zfar = self.zfar; - let fov = self.fov; - let (width, height) = target_dimensions; - let aspect_ratio = height as f32 / width as f32; - let f = 1.0 / (fov / 2.0).tan(); - self.perspective_matrix = [ - [f*aspect_ratio, 0.0, 0.0, 0.0], - [0.0, f, 0.0, 0.0], - [0.0, 0.0, (zfar+znear)/(zfar-znear), 1.0], - [0.0, 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0], - ]; - } - - // https://www.flipcode.com/archives/Frustum_Culling.shtml - // https://web.archive.org/web/20070226173353/https://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf - pub fn frustum_planes(&self, normalized: bool) -> [[f32; 4]; 6] { - let mut p_planes = [[0.0_f32; 4]; 6]; - let matrix = self.perspective_matrix; - - // Left clipping plane - p_planes[0][0] = matrix[3][0] + matrix[0][0]; - p_planes[0][1] = matrix[3][1] + matrix[0][1]; - p_planes[0][2] = matrix[3][2] + matrix[0][2]; - p_planes[0][3] = matrix[3][3] + matrix[0][3]; - // Right clipping plane - p_planes[1][0] = matrix[3][0] - matrix[0][0]; - p_planes[1][1] = matrix[3][1] - matrix[0][1]; - p_planes[1][2] = matrix[3][2] - matrix[0][2]; - p_planes[1][3] = matrix[3][3] - matrix[0][3]; - // Top clipping plane - p_planes[2][0] = matrix[3][0] - matrix[1][0]; - p_planes[2][1] = matrix[3][1] - matrix[1][1]; - p_planes[2][2] = matrix[3][2] - matrix[1][2]; - p_planes[2][3] = matrix[3][3] - matrix[1][3]; - // Bottom clipping plane - p_planes[3][0] = matrix[3][0] + matrix[1][0]; - p_planes[3][1] = matrix[3][1] + matrix[1][1]; - p_planes[3][2] = matrix[3][2] + matrix[1][2]; - p_planes[3][3] = matrix[3][3] + matrix[1][3]; - // Near clipping plane - p_planes[4][0] = matrix[3][0] + matrix[3][0]; - p_planes[4][1] = matrix[3][1] + matrix[3][1]; - p_planes[4][2] = matrix[3][2] + matrix[3][2]; - p_planes[4][3] = matrix[3][3] + matrix[3][3]; - // Far clipping plane - p_planes[5][0] = matrix[3][0] - matrix[3][0]; - p_planes[5][1] = matrix[3][1] - matrix[3][1]; - p_planes[5][2] = matrix[3][2] - matrix[3][2]; - p_planes[5][3] = matrix[3][3] - matrix[3][3]; - - //Normalize planes - if normalized { - for plane in &mut p_planes { - *plane = normalize_plane(*plane); - } - } - - p_planes - } - -} -impl Default for Camera { - fn default() -> Self { - Self { - position: [0., 0., 0.], - direction: [0., 0., 0.], - up: [0., 1., 0.], - fov: PI / 3., - zfar: 1024., - znear: 0.1, - yaw: 0., - pitch: 0., - perspective_matrix: [[0.; 4]; 4] - } - } -} diff --git a/src/game/controller.rs b/src/game/controller.rs deleted file mode 100644 index 58b5b29..0000000 --- a/src/game/controller.rs +++ /dev/null @@ -1,116 +0,0 @@ -use glium::glutin::event::{VirtualKeyCode, ElementState}; -use std::f32::consts::PI; -use crate::game::camera::Camera; - -#[derive(Default, Clone, Copy)] -pub struct InputAmounts { - move_x: (f32, f32), - move_y: (f32, f32), - move_z: (f32, f32), - look_h: f32, - look_v: f32, -} - -pub struct Actions { - pub movement: [f32; 3], - pub rotation: [f32; 2], -} -impl Actions { - pub fn apply_to_camera(&self, camera: &mut Camera) { - //Apply rotation - camera.yaw -= self.rotation[0]; - camera.pitch -= self.rotation[1]; - camera.pitch = camera.pitch.clamp(-PI/2. + f32::EPSILON, PI/2. - f32::EPSILON); - camera.update_direction(); - //Apply movement - let (yaw_sin, yaw_cos) = camera.yaw.sin_cos(); - //forward movement - camera.position[0] += yaw_cos * self.movement[2]; - camera.position[2] += yaw_sin * self.movement[2]; - //sideways movement - camera.position[0] -= -yaw_sin * self.movement[0]; - camera.position[2] -= yaw_cos * self.movement[0]; - //up/down movement - camera.position[1] += self.movement[1]; - } -} - -pub struct Controls { - inputs: InputAmounts, - pub speed: f32, - pub sensitivity: f32, -} -impl Controls { - //TODO locking controls - pub fn lock(&mut self) { - todo!() - } - pub fn unlock(&mut self) { - todo!() - } - pub fn process_mouse_input(&mut self, dx: f64, dy: f64) { - self.inputs.look_h += dx as f32; - self.inputs.look_v += dy as f32; - } - pub fn process_keyboard_input(&mut self, key: VirtualKeyCode, state: ElementState) { - let value = match state { - ElementState::Pressed => 1., - ElementState::Released => 0., - }; - match key { - VirtualKeyCode::W | VirtualKeyCode::Up => { - self.inputs.move_z.0 = value; - } - VirtualKeyCode::S | VirtualKeyCode::Down => { - self.inputs.move_z.1 = -value; - } - VirtualKeyCode::A | VirtualKeyCode::Left => { - self.inputs.move_x.0 = -value; - } - VirtualKeyCode::D | VirtualKeyCode::Right => { - self.inputs.move_x.1 = value; - } - VirtualKeyCode::Space => { - self.inputs.move_y.0 = value; - } - VirtualKeyCode::LShift => { - self.inputs.move_y.1 = -value; - } - _ => () - } - } - pub fn calculate(&mut self, dt: f32) -> Actions { - let movement = { - let move_x = self.inputs.move_x.0 + self.inputs.move_x.1; - let move_y = self.inputs.move_y.0 + self.inputs.move_y.1; - let move_z = self.inputs.move_z.0 + self.inputs.move_z.1; - let magnitude = (move_x.powi(2) + move_y.powi(2) + move_z.powi(2)).sqrt(); - if magnitude == 0. { - [0., 0., 0.] - } else { - [ - dt * self.speed * (move_x / magnitude), - dt * self.speed * (move_y / magnitude), - dt * self.speed * (move_z / magnitude) - ] - } - }; - let rotation = [ //Do mouse inputs need to be multiplied by dt? - self.inputs.look_h * self.sensitivity * 0.01, //* dt - self.inputs.look_v * self.sensitivity * 0.01 //* dt - ]; - //Only mouse related actions need to be reset - self.inputs.look_h = 0.; - self.inputs.look_v = 0.; - Actions { movement, rotation } - } -} -impl Default for Controls { - fn default() -> Self { - Self { - inputs: Default::default(), - speed: 40., - sensitivity: 1.24, - } - } -} diff --git a/src/game/display.rs b/src/game/display.rs deleted file mode 100644 index 97d7e02..0000000 --- a/src/game/display.rs +++ /dev/null @@ -1,16 +0,0 @@ -use glium::Display; -use glium::glutin::{ - ContextBuilder, - GlProfile, - window::WindowBuilder, - event_loop::EventLoop -}; - -pub fn init_display(event_loop: &EventLoop<()>) -> Display { - let wb = WindowBuilder::new() - .with_maximized(true); - let cb = ContextBuilder::new() - .with_depth_buffer(24) - .with_gl_profile(GlProfile::Core); - Display::new(wb, cb, event_loop).unwrap() -} diff --git a/src/game/items.rs b/src/game/items.rs deleted file mode 100644 index 0028d1c..0000000 --- a/src/game/items.rs +++ /dev/null @@ -1,9 +0,0 @@ -//TODO items - -#[derive(Clone, Copy, Debug)] -pub enum Item { - StoneBlock, - DirtBlock, - GrassBlock, - SandBlock, -} diff --git a/src/game/options.rs b/src/game/options.rs deleted file mode 100644 index 7a19998..0000000 --- a/src/game/options.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[derive(Clone, Debug)] -pub struct GameOptions { - pub render_distance: u8, - pub debug_wireframe_mode: bool, -} -impl Default for GameOptions { - fn default() -> Self { - Self { - render_distance: if cfg!(debug_assertions) { 8 } else { 16 }, - debug_wireframe_mode: false, - } - } -} diff --git a/src/game/physics.rs b/src/game/physics.rs deleted file mode 100644 index a0e0d2c..0000000 --- a/src/game/physics.rs +++ /dev/null @@ -1,46 +0,0 @@ -use glam::{Vec3A, vec3a}; -use crate::game::World; - -const GRAVITY: Vec3A = vec3a(0., -1., 0.); - -pub struct BasicPhysicsActor { - pub height: f32, - pub gravity: Vec3A, - pub position: Vec3A, - pub velocity: Vec3A, -} -impl BasicPhysicsActor { - pub fn new(height: f32) -> Self { - Self { - height, - gravity: GRAVITY, - position: vec3a(0., 0., 0.), - velocity: vec3a(0., 0., 0.), - } - } - pub fn update(&mut self, world: &World, dt: f32) { - self.velocity += GRAVITY; - self.position += self.velocity; - loop { - let block_pos = self.position.floor().as_ivec3(); - let block_pos_f = block_pos.as_vec3a(); - if let Some(block) = world.try_get(block_pos) { - match block.descriptor().collision { - Some(super::blocks::CollisionType::Solid) => { - let position_delta = self.position - block_pos_f; - let distance_to_zero = position_delta.abs(); - let distance_to_one = (vec3a(1., 1., 1.) - position_delta).abs(); - - // let mut max_distance = 0; - // let mut max_distance_normal = 0; - // distance_to_one.x - //todo compute restitution here - } - _ => break - } - } else { - break - } - } - } -} diff --git a/src/game/player.rs b/src/game/player.rs deleted file mode 100644 index 8fde307..0000000 --- a/src/game/player.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::game::camera::Camera; -use crate::game::physics::BasicPhysicsActor; - -pub struct MainPlayer { - pub camera: Camera, - pub actor: BasicPhysicsActor, -} diff --git a/src/game/shaders.rs b/src/game/shaders.rs deleted file mode 100644 index d949234..0000000 --- a/src/game/shaders.rs +++ /dev/null @@ -1,17 +0,0 @@ -use glium::{Display, Program}; - -pub mod chunk; -pub mod colored2d; - -pub struct Programs { - pub colored_2d: Program, - pub chunk: Program, -} -impl Programs { - pub fn compile_all(display: &Display) -> Self { - Self { - colored_2d: Program::from_source(display, colored2d::VERTEX_SHADER, colored2d::FRAGMENT_SHADER, None).unwrap(), - chunk: Program::from_source(display, chunk::VERTEX_SHADER, chunk::FRAGMENT_SHADER, None).unwrap(), - } - } -} diff --git a/src/game/shaders/chunk.rs b/src/game/shaders/chunk.rs deleted file mode 100644 index 03c47e6..0000000 --- a/src/game/shaders/chunk.rs +++ /dev/null @@ -1,34 +0,0 @@ -use glium::implement_vertex; - -#[derive(Clone, Copy)] -pub struct Vertex { - pub position: [f32; 3], - pub normal: [f32; 3], - pub uv: [f32; 2], - pub tex_index: u8, -} -implement_vertex!(Vertex, position, normal, uv, tex_index); - -pub const VERTEX_SHADER: &str = include_str!("./glsl/chunk.vert"); -pub const FRAGMENT_SHADER: &str = include_str!("./glsl/chunk.frag"); - -// pub const VERTEX_SHADER: &str = r#" -// #version 150 core - -// in vec3 position; -// in vec3 normal; -// in vec2 uv; -// out vec3 v_normal; -// out vec2 v_uv; -// uniform mat4 perspective; -// uniform mat4 view; -// uniform mat4 model; - -// void main() { -// mat4 modelview = view * model; -// //v_normal = transpose(inverse(mat3(modelview))) * normal; -// v_normal = normal; -// v_uv = uv; -// gl_Position = perspective * modelview * vec4(position, 1.0); -// } -// "#; diff --git a/src/game/shaders/colored2d.rs b/src/game/shaders/colored2d.rs deleted file mode 100644 index 336dab8..0000000 --- a/src/game/shaders/colored2d.rs +++ /dev/null @@ -1,10 +0,0 @@ -use glium::implement_vertex; - -#[derive(Clone, Copy)] -pub struct Vertex { - pub position: [f32; 2] -} -implement_vertex!(Vertex, position); - -pub const VERTEX_SHADER: &str = include_str!("./glsl/colored2d.vert"); -pub const FRAGMENT_SHADER: &str = include_str!("./glsl/colored2d.frag"); diff --git a/src/game/shaders/glsl/chunk.frag b/src/game/shaders/glsl/chunk.frag deleted file mode 100644 index e07b5e1..0000000 --- a/src/game/shaders/glsl/chunk.frag +++ /dev/null @@ -1,15 +0,0 @@ -#version 150 core - -in vec3 v_normal; -in vec2 v_uv; -flat in uint v_tex_index; -out vec4 color; -uniform sampler2DArray tex; - -void main() { - // base color from texture - color = texture(tex, vec3(v_uv, v_tex_index)); - //basic "lighting" - float light = abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z); - color *= vec4(vec3(light), 1.); -} diff --git a/src/game/shaders/glsl/chunk.vert b/src/game/shaders/glsl/chunk.vert deleted file mode 100644 index 91e2b39..0000000 --- a/src/game/shaders/glsl/chunk.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 150 core - -in vec3 position; -in vec3 normal; -in vec2 uv; -in uint tex_index; -out vec2 v_uv; -out vec3 v_normal; -flat out uint v_tex_index; -uniform vec2 position_offset; -uniform mat4 perspective; -uniform mat4 view; - -void main() { - v_normal = normal; - v_tex_index = tex_index; - v_uv = uv; - gl_Position = perspective * view * (vec4(position, 1.0) + vec4(position_offset.x, 0., position_offset.y, 0.)); -} diff --git a/src/game/shaders/glsl/colored2d.frag b/src/game/shaders/glsl/colored2d.frag deleted file mode 100644 index 9b2ac94..0000000 --- a/src/game/shaders/glsl/colored2d.frag +++ /dev/null @@ -1,8 +0,0 @@ -#version 150 core - -out vec4 color; -uniform vec4 u_color; - -void main() { - color = u_color; -} diff --git a/src/game/shaders/glsl/colored2d.vert b/src/game/shaders/glsl/colored2d.vert deleted file mode 100644 index af1807e..0000000 --- a/src/game/shaders/glsl/colored2d.vert +++ /dev/null @@ -1,7 +0,0 @@ -#version 150 core - -in vec2 position; - -void main() { - gl_Position = vec4(position, 0., 1.); -} diff --git a/src/game/world.rs b/src/game/world.rs deleted file mode 100644 index de8ff50..0000000 --- a/src/game/world.rs +++ /dev/null @@ -1,201 +0,0 @@ -use glam::{Vec2, IVec2, IVec3, Vec3Swizzles}; -use glium::{ - Display, Frame, Surface, - DrawParameters, Depth, - DepthTest, PolygonMode, - uniform, - uniforms::{ - Sampler, SamplerBehavior, - MinifySamplerFilter, MagnifySamplerFilter, - } -}; -use hashbrown::HashMap; -use crate::game::{ - options::GameOptions, - shaders::Programs, - assets::Assets, - blocks::Block, -}; - -mod chunk; -mod thread; - -use chunk::{Chunk, ChunkState, CHUNK_SIZE}; -use thread::WorldThreading; - -const POSITIVE_X_NEIGHBOR: usize = 0; -const NEGATIVE_X_NEIGHBOR: usize = 1; -const POSITIVE_Z_NEIGHBOR: usize = 2; -const NEGATIVE_Z_NEIGHBOR: usize = 3; - -const MAX_TASKS: usize = 6; - -pub struct World { - pub chunks: HashMap, - pub thread: WorldThreading, -} -impl World { - pub fn chunk_neighbors(&self, position: IVec2) -> [Option<&Chunk>; 4] { - [ - self.chunks.get(&(position + IVec2::new(1, 0))), - self.chunks.get(&(position - IVec2::new(1, 0))), - self.chunks.get(&(position + IVec2::new(0, 1))), - self.chunks.get(&(position - IVec2::new(0, 1))), - ] - } - - pub fn try_get(&self, position: IVec3) -> Option { - let chunk_coord = IVec2::new(position.x, position.z) / CHUNK_SIZE as i32; - let chunk = self.chunks.get(&chunk_coord)?; - let block_data = chunk.block_data.as_ref()?; - let block_position = position - (chunk_coord * CHUNK_SIZE as i32).extend(0).xzy(); - Some( - *block_data - .get(block_position.x as usize)? - .get(block_position.y as usize)? - .get(block_position.z as usize)? - ) - } - - pub fn new() -> Self { - Self { - chunks: HashMap::new(), - thread: WorldThreading::new(), - } - } - - pub fn render( - &self, - target: &mut Frame, - programs: &Programs, - assets: &Assets, - perspective: [[f32; 4]; 4], - view: [[f32; 4]; 4], - options: &GameOptions - ) { - let sampler = SamplerBehavior { - minify_filter: MinifySamplerFilter::Linear, - magnify_filter: MagnifySamplerFilter::Nearest, - max_anisotropy: 8, - ..Default::default() - }; - let draw_parameters = DrawParameters { - depth: Depth { - test: DepthTest::IfLess, - write: true, - ..Default::default() - }, - polygon_mode: if options.debug_wireframe_mode { - PolygonMode::Line - } else { - PolygonMode::Fill - }, - backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockwise, - ..Default::default() - }; - for (&position, chunk) in &self.chunks { - if let Some(mesh) = &chunk.mesh { - target.draw( - &mesh.vertex_buffer, - &mesh.index_buffer, - &programs.chunk, - &uniform! { - position_offset: (position.as_vec2() * CHUNK_SIZE as f32).to_array(), - view: view, - perspective: perspective, - tex: Sampler(&assets.textures.blocks, sampler) - }, - &draw_parameters - ).unwrap(); - } - } - } - - pub fn update_loaded_chunks(&mut self, around_position: Vec2, options: &GameOptions, display: &Display) { - let render_dist = options.render_distance as i32 + 1; - let inside_chunk = (around_position / CHUNK_SIZE as f32).as_ivec2(); - - //Mark all chunks for unload - for (_, chunk) in &mut self.chunks { - chunk.desired = ChunkState::Unload; - } - - //Load new/update chunks in range - for x in -render_dist..=render_dist { - for z in -render_dist..=render_dist { - let offset = IVec2::new(x, z); - let position = inside_chunk + offset; - if !self.chunks.contains_key(&position) { - self.chunks.insert(position, Chunk::new(position)); - } - { - //we only need mutable reference here: - let chunk = self.chunks.get_mut(&position).unwrap(); - if x == -render_dist || z == -render_dist || x == render_dist || z == render_dist { - chunk.desired = ChunkState::Loaded; - } else { - chunk.desired = ChunkState::Rendered; - } - } - let chunk = self.chunks.get(&position).unwrap(); - if self.thread.task_amount() < MAX_TASKS { - if matches!(chunk.state, ChunkState::Nothing) && matches!(chunk.desired, ChunkState::Loaded | ChunkState::Rendered) { - self.thread.queue_load(position); - self.chunks.get_mut(&position).unwrap().state = ChunkState::Loading; - } else if matches!(chunk.state, ChunkState::Loaded) && matches!(chunk.desired, ChunkState::Rendered) { - let mut state_changed = false; - fn all_some<'a>(x: [Option<&'a Chunk>; 4]) -> Option<[&'a Chunk; 4]> { - Some([x[0]?, x[1]?, x[2]?, x[3]?]) - } - if let Some(neighbors) = all_some(self.chunk_neighbors(chunk.position)) { - if { - neighbors[0].block_data.is_some() && - neighbors[1].block_data.is_some() && - neighbors[2].block_data.is_some() && - neighbors[3].block_data.is_some() - } { - self.thread.queue_mesh( - position, - chunk.block_data.clone().unwrap(), - [ - neighbors[0].block_data.clone().unwrap(), - neighbors[1].block_data.clone().unwrap(), - neighbors[2].block_data.clone().unwrap(), - neighbors[3].block_data.clone().unwrap(), - ] - ); - state_changed = true; - } - } - if state_changed { - self.chunks.get_mut(&position).unwrap().state = ChunkState::Rendering; - } - } - } - } - } - //Unloads and state downgrades - self.chunks.retain(|_, chunk| { - match chunk.desired { - // Chunk unload - ChunkState::Unload => false, - // Any => Nothing downgrade - ChunkState::Nothing => { - chunk.block_data = None; - chunk.mesh = None; - chunk.state = ChunkState::Nothing; - true - }, - //Render => Loaded downgrade - ChunkState::Loaded if matches!(chunk.state, ChunkState::Rendering | ChunkState::Rendered) => { - chunk.mesh = None; - chunk.state = ChunkState::Loaded; - true - }, - _ => true - } - }); - //Apply changes from threads - self.thread.apply_tasks(&mut self.chunks, display); - } -} diff --git a/src/game/world/chunk.rs b/src/game/world/chunk.rs deleted file mode 100644 index 481b04b..0000000 --- a/src/game/world/chunk.rs +++ /dev/null @@ -1,45 +0,0 @@ -use glam::IVec2; -use glium::{VertexBuffer, IndexBuffer}; -use crate::game::{ - blocks::Block, - shaders::chunk::Vertex as ChunkVertex -}; - -pub const CHUNK_SIZE: usize = 32; -pub const CHUNK_HEIGHT: usize = 255; - -pub enum ChunkState { - Unload, - Nothing, - Loading, - Loaded, - Rendering, - Rendered, -} - -pub type ChunkData = Box<[[[Block; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE]>; - -pub struct ChunkMesh { - pub is_dirty: bool, - pub vertex_buffer: VertexBuffer, - pub index_buffer: IndexBuffer, -} - -pub struct Chunk { - pub position: IVec2, - pub block_data: Option, - pub mesh: Option, - pub state: ChunkState, - pub desired: ChunkState, -} -impl Chunk { - pub fn new(position: IVec2) -> Self { - Self { - position, - block_data: None, - mesh: None, - state: ChunkState::Nothing, - desired: ChunkState::Nothing, - } - } -} diff --git a/src/game/world/thread.rs b/src/game/world/thread.rs deleted file mode 100644 index b051112..0000000 --- a/src/game/world/thread.rs +++ /dev/null @@ -1,97 +0,0 @@ -use glam::IVec2; -use glium::{Display, VertexBuffer, IndexBuffer, index::PrimitiveType}; -use std::{mem, thread::{self, JoinHandle}}; -use hashbrown::HashMap; -use super::chunk::{Chunk, ChunkData, ChunkState}; -use crate::game::{shaders::chunk::Vertex as ChunkVertex, world::chunk::ChunkMesh}; - -mod world_gen; -mod mesh_gen; - -#[derive(Default)] -pub struct WorldThreading { - //drain_filter is not stable yet so - //Options are needed here to take ownership, - //None values should never appear here! - pub load_tasks: HashMap>>, - pub mesh_tasks: HashMap, Vec)>>>, -} -impl WorldThreading { - pub fn new() -> Self { - Self::default() - } - pub fn is_done(&self) -> bool { - self.load_tasks.is_empty() && - self.mesh_tasks.is_empty() - } - pub fn task_amount(&self) -> usize { - self.load_tasks.len() + self.mesh_tasks.len() - } - pub fn queue_load(&mut self, position: IVec2) { - let handle = thread::spawn(move || { - world_gen::generate_chunk(position, 0xdead_cafe) - }); - if self.load_tasks.insert(position, Some(handle)).is_some() { - log::warn!("load: discarded {}, reason: new task started", position); - } - } - pub fn queue_mesh(&mut self, position: IVec2, chunk: ChunkData, neighbor_data: [ChunkData; 4]) { - let handle = thread::spawn(move || { - mesh_gen::generate_mesh(position, chunk, neighbor_data) - }); - if self.mesh_tasks.insert(position, Some(handle)).is_some() { - log::warn!("mesh: discarded {}, reason: new task started", position); - } - } - pub fn apply_tasks(&mut self, chunks: &mut HashMap, display: &Display) { - //LOAD TASKS - self.load_tasks.retain(|position, handle| { - if !chunks.contains_key(position) { - log::warn!("load: discarded {}, reason: chunk no longer exists", position); - return false - } - if !matches!(chunks.get(position).unwrap().desired, ChunkState::Loaded | ChunkState::Rendered) { - log::warn!("load: discarded {}, reason: state undesired", position); - return false - } - if !handle.as_ref().expect("Something went terribly wrong").is_finished() { - //task not finished yet, keep it and wait - return true - } - log::info!("load: done {}", position); - let handle = mem::take(handle).unwrap(); - let data = handle.join().unwrap(); - let chunk = chunks.get_mut(position).unwrap(); - chunk.block_data = Some(data); - chunk.state = ChunkState::Loaded; - false - }); - //MESH TASKS - self.mesh_tasks.retain(|position, handle| { - if !chunks.contains_key(position) { - log::warn!("mesh: discarded {}, reason: chunk no longer exists", position); - return false - } - if !matches!(chunks.get(position).unwrap().desired, ChunkState::Rendered) { - log::warn!("mesh: discarded {}, reason: state undesired", position); - return false - } - if !handle.as_ref().expect("Something went terribly wrong").is_finished() { - //task not finished yet, keep it and wait - return true - } - log::info!("mesh: done {}", position); - let handle = mem::take(handle).unwrap(); - let (shape, index) = handle.join().unwrap(); - let chunk = chunks.get_mut(position).unwrap(); - chunk.mesh = Some(ChunkMesh { - is_dirty: false, - vertex_buffer: VertexBuffer::new(display, &shape).expect("Failed to build VertexBuffer"), - index_buffer: IndexBuffer::new(display, PrimitiveType::TrianglesList, &index).expect("Failed to build IndexBuffer") - }); - chunk.state = ChunkState::Rendered; - false - }); - - } -} diff --git a/src/game/world/thread/mesh_gen.rs b/src/game/world/thread/mesh_gen.rs deleted file mode 100644 index ad32b11..0000000 --- a/src/game/world/thread/mesh_gen.rs +++ /dev/null @@ -1,139 +0,0 @@ -use glam::{IVec2, IVec3, Vec2, Vec3A, vec3a, vec2, ivec3}; -use strum::{EnumIter, IntoEnumIterator}; -use crate::game::{ - world::{ - POSITIVE_X_NEIGHBOR, - NEGATIVE_X_NEIGHBOR, - POSITIVE_Z_NEIGHBOR, - NEGATIVE_Z_NEIGHBOR, - chunk::{ChunkData, CHUNK_SIZE, CHUNK_HEIGHT} - }, - shaders::chunk::Vertex, - blocks::Block -}; - -#[repr(usize)] -#[derive(Clone, Copy, Debug, EnumIter)] -pub enum CubeFace { - Top = 0, - Front = 1, - Left = 2, - Right = 3, - Back = 4, - Bottom = 5, -} -const CUBE_FACE_VERTICES: [[Vec3A; 4]; 6] = [ - [vec3a(0., 1., 0.), vec3a(0., 1., 1.), vec3a(1., 1., 0.), vec3a(1., 1., 1.)], - [vec3a(0., 0., 0.), vec3a(0., 1., 0.), vec3a(1., 0., 0.), vec3a(1., 1., 0.)], - [vec3a(0., 0., 1.), vec3a(0., 1., 1.), vec3a(0., 0., 0.), vec3a(0., 1., 0.)], - [vec3a(1., 0., 0.), vec3a(1., 1., 0.), vec3a(1., 0., 1.), vec3a(1., 1., 1.)], - [vec3a(1., 0., 1.), vec3a(1., 1., 1.), vec3a(0., 0., 1.), vec3a(0., 1., 1.)], - [vec3a(0., 0., 1.), vec3a(0., 0., 0.), vec3a(1., 0., 1.), vec3a(1., 0., 0.)], -]; -const CUBE_FACE_NORMALS: [[f32; 3]; 6] = [ - [0., 1., 0.], - [0., 0., -1.], - [-1., 0., 0.], - [1., 0., 0.], - [0., 0., 1.], - [0., -1., 0.] -]; -const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; -const UV_COORDS: [[f32; 2]; 4] = [ - [0., 0.], - [0., 1.], - [1., 0.], - [1., 1.], -]; - - -#[derive(Default)] -struct MeshBuilder { - vertex_buffer: Vec, - index_buffer: Vec, - idx_counter: u32, -} -impl MeshBuilder { - pub fn new() -> Self { - Self::default() - } - - pub fn add_face(&mut self, face: CubeFace, coord: IVec3, texture: u8) { - let coord = coord.as_vec3a(); - let face_index = face as usize; - - //Push vertexes - let norm = CUBE_FACE_NORMALS[face_index]; - let vert = CUBE_FACE_VERTICES[face_index]; - self.vertex_buffer.reserve(4); - for i in 0..4 { - self.vertex_buffer.push(Vertex { - position: (coord + vert[i]).to_array(), - normal: norm, - uv: UV_COORDS[i], - tex_index: texture - }); - } - - //Push indices - self.index_buffer.extend_from_slice(&CUBE_FACE_INDICES.map(|x| x + self.idx_counter)); - self.idx_counter += 4; - } - - pub fn finish(self) -> (Vec, Vec) { - (self.vertex_buffer, self.index_buffer) - } -} - -pub fn generate_mesh(position: IVec2, chunk_data: ChunkData, neighbors: [ChunkData; 4]) -> (Vec, Vec) { - let get_block = |pos: IVec3| -> Block { - if pos.x < 0 { - neighbors[NEGATIVE_X_NEIGHBOR][(CHUNK_SIZE as i32 + pos.x) as usize][pos.y as usize][pos.z as usize] - } else if pos.x >= CHUNK_SIZE as i32 { - neighbors[POSITIVE_X_NEIGHBOR][pos.x as usize - CHUNK_SIZE as usize][pos.y as usize][pos.z as usize] - } else if pos.z < 0 { - neighbors[NEGATIVE_Z_NEIGHBOR][pos.x as usize][pos.y as usize][(CHUNK_SIZE as i32 + pos.z) as usize] - } else if pos.z >= CHUNK_SIZE as i32 { - neighbors[POSITIVE_Z_NEIGHBOR][pos.x as usize][pos.y as usize][pos.z as usize - CHUNK_SIZE as usize] - } else { - chunk_data[pos.x as usize][pos.y as usize][pos.z as usize] - } - }; - - let mut builer = MeshBuilder::new(); - - for x in 0..CHUNK_SIZE { - for y in 0..CHUNK_HEIGHT { - for z in 0..CHUNK_SIZE { - let coord = ivec3(x as i32, y as i32, z as i32); - let descriptor = get_block(coord).descriptor(); - if descriptor.render.is_none() { - continue - } - for face in CubeFace::iter() { - let facing = Vec3A::from_array(CUBE_FACE_NORMALS[face as usize]).as_ivec3(); - let facing_coord = coord + facing; - let show = { - (facing_coord.y < 0) || - (facing_coord.y >= CHUNK_HEIGHT as i32) || - get_block(facing_coord).descriptor().render.is_none() - }; - if show { - let texures = descriptor.render.unwrap().1; - let block_texture = match face { - CubeFace::Top => texures.top, - CubeFace::Front => texures.front, - CubeFace::Left => texures.left, - CubeFace::Right => texures.right, - CubeFace::Back => texures.back, - CubeFace::Bottom => texures.bottom, - }; - builer.add_face(face, coord, block_texture as u8); - } - } - } - } - } - - builer.finish() -} diff --git a/src/game/world/thread/world_gen.rs b/src/game/world/thread/world_gen.rs deleted file mode 100644 index 34b979b..0000000 --- a/src/game/world/thread/world_gen.rs +++ /dev/null @@ -1,58 +0,0 @@ -use glam::{Vec2, DVec2, IVec2}; -use noise::{NoiseFn, Perlin, Simplex, Fbm, Seedable}; -use crate::game::{ - world::chunk::{ChunkData, CHUNK_SIZE, CHUNK_HEIGHT}, - blocks::Block -}; - -const HEIGHTMAP_SCALE: f64 = 0.004; -const MOUNTAINESS_SCALE: f64 = 0.0001; -const MNT_RAMP_1: f64 = 0.5; -const MNT_RAMP_2: f64 = 0.6; -const MTN_VAL_SCALE: f64 = 1.233; -const TERRAIN_HEIGHT_MIN: f64 = 60.; -const TERRAIN_HEIGHT_MAX: f64 = 80.; - -pub fn generate_chunk(position: IVec2, seed: u32) -> ChunkData { - let world_xz = position.as_vec2() * CHUNK_SIZE as f32; - let mut chunk = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE]); - - //generate noises - let mut terrain_base_fbm: Fbm = Fbm::new(seed); - terrain_base_fbm.octaves = 6; - - let mut mountainess_base_fbm: Fbm = Fbm::new(seed); - mountainess_base_fbm.octaves = 4; - - //put everything together - for x in 0..CHUNK_SIZE { - for z in 0..CHUNK_SIZE { - let point = world_xz.as_dvec2() + DVec2::from_array([x as f64, z as f64]); - - let heightmap = (terrain_base_fbm.get((point * HEIGHTMAP_SCALE).to_array()) + 1.) / 2.; - let mountainess = MTN_VAL_SCALE * ((mountainess_base_fbm.get((point * MOUNTAINESS_SCALE).to_array()) + 1.) / 2.); - - //generate basic terrain - let terain_height = - ( - TERRAIN_HEIGHT_MIN + - (heightmap * TERRAIN_HEIGHT_MAX * (0.1 + 1.5 * if mountainess < MNT_RAMP_1 { - 0. - } else { - if mountainess > MNT_RAMP_2 { - 1. - } else { - (mountainess - MNT_RAMP_1) / (MNT_RAMP_2 - MNT_RAMP_1) * 1. - } - })) - ).floor() as usize; - for y in 0..terain_height { - chunk[x][y][z] = Block::Dirt; - } - chunk[x][terain_height][z] = Block::Grass; - } - } - - //return generated world - chunk -} diff --git a/src/logging.rs b/src/logging.rs deleted file mode 100644 index 013b4e9..0000000 --- a/src/logging.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Custom env_logger options and styling - -use env_logger::{fmt::Color, Builder, Env}; -use log::Level; -use std::io::Write; - -pub fn init() { - let mut env = Env::default(); - if cfg!(debug_assertions) { - env = env.filter_or("RUST_LOG", "trace"); - } - Builder::from_env(env) - .format(|buf, record| { - let mut level_style = buf.style(); - level_style.set_color(match record.level() { - Level::Error => Color::Red, - Level::Warn => Color::Yellow, - _ => Color::Blue - }).set_bold(true); - - let mut location_style = buf.style(); - location_style.set_bold(true); - location_style.set_dimmed(true); - - let mut location_line_style = buf.style(); - location_line_style.set_dimmed(true); - - writeln!( - buf, - "{} {:<50}\t{}{}{}", - level_style.value(match record.level() { - Level::Error => "[e]", - Level::Warn => "[w]", - Level::Info => "[i]", - Level::Debug => "[d]", - Level::Trace => "[t]", - }), - format!("{}", record.args()), - location_style.value(record.target()), - location_line_style.value(" :"), - location_line_style.value(record.line().unwrap_or(0)) - ) - }) - .init(); -} diff --git a/src/main.rs b/src/main.rs index 08de79c..58dfaaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,3 @@ -mod game; -mod logging; - fn main() { - logging::init(); - game::run(); + } From 470d1a7567f240e93fb94a82eec362ea663ab623 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 19 Jan 2023 21:27:34 +0100 Subject: [PATCH 02/81] switch to `shipyard` --- Cargo.toml | 5 +---- src/main.rs | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0905424..13d6df1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,4 @@ glam = { version = "0.22", features = ["debug-glam-assert", "mint", "fast-math"] hashbrown = "0.13" noise = "0.8" rayon = "1.6" -specs = { version = "0.18", features = ["specs-derive"] } - -[features] -default = [] +shipyard = { version = "0.6", features = ["thread_local"] } diff --git a/src/main.rs b/src/main.rs index 58dfaaa..d58a2bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use shipyard::World; + fn main() { - + let world = World::new(); } From b1b78cc4dd637950fa41152f1dfc67e438f01475 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 19 Jan 2023 21:58:49 +0100 Subject: [PATCH 03/81] x --- src/main.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main.rs b/src/main.rs index d58a2bd..65ac1ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,16 @@ +use glium::glutin::event_loop::EventLoop; use shipyard::World; +mod logging; + fn main() { + logging::init(); + let world = World::new(); + world.add_unique(component) + + let event_loop = EventLoop::new(); + event_loop.run(move |event, _, control_flow| { + + }); } From fcb123b02ff1e8460f5165e5531377a8c0bf3d3f Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 19 Jan 2023 21:58:59 +0100 Subject: [PATCH 04/81] x --- src/logging.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/rendering.rs | 3 +++ 2 files changed, 48 insertions(+) create mode 100644 src/logging.rs create mode 100644 src/rendering.rs diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..013b4e9 --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,45 @@ +//! Custom env_logger options and styling + +use env_logger::{fmt::Color, Builder, Env}; +use log::Level; +use std::io::Write; + +pub fn init() { + let mut env = Env::default(); + if cfg!(debug_assertions) { + env = env.filter_or("RUST_LOG", "trace"); + } + Builder::from_env(env) + .format(|buf, record| { + let mut level_style = buf.style(); + level_style.set_color(match record.level() { + Level::Error => Color::Red, + Level::Warn => Color::Yellow, + _ => Color::Blue + }).set_bold(true); + + let mut location_style = buf.style(); + location_style.set_bold(true); + location_style.set_dimmed(true); + + let mut location_line_style = buf.style(); + location_line_style.set_dimmed(true); + + writeln!( + buf, + "{} {:<50}\t{}{}{}", + level_style.value(match record.level() { + Level::Error => "[e]", + Level::Warn => "[w]", + Level::Info => "[i]", + Level::Debug => "[d]", + Level::Trace => "[t]", + }), + format!("{}", record.args()), + location_style.value(record.target()), + location_line_style.value(" :"), + location_line_style.value(record.line().unwrap_or(0)) + ) + }) + .init(); +} diff --git a/src/rendering.rs b/src/rendering.rs new file mode 100644 index 0000000..db2ad61 --- /dev/null +++ b/src/rendering.rs @@ -0,0 +1,3 @@ +fn init_display() { + +} From d77779d7204fbdeb90a0871c83ed3798cfc9f42f Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 19 Jan 2023 23:28:07 +0100 Subject: [PATCH 05/81] got a window --- src/main.rs | 59 +++++++++++++++++++++++++++++++++++++++++++----- src/rendering.rs | 32 ++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 65ac1ef..76e1fcd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,63 @@ -use glium::glutin::event_loop::EventLoop; -use shipyard::World; +use shipyard::{World, Workload, IntoWorkload, View, UniqueView, NonSendSync}; +use glium::{ + Surface, + glutin::{ + event_loop::{EventLoop, ControlFlow}, + event::{Event, WindowEvent} + } +}; mod logging; +mod rendering; + +use rendering::{Rederer, RenderTarget}; + +fn render() -> Workload { + (||()).into_workload() +} +fn update() -> Workload { + (||()).into_workload() +} fn main() { logging::init(); - - let world = World::new(); - world.add_unique(component) + //Create event loop let event_loop = EventLoop::new(); + + //Create a shipyard world + let world = World::new(); + + //Add systems and uniques + world.add_unique_non_send_sync( + Rederer::init(&event_loop) + ); + world.add_workload(update); + world.add_workload(render); + + //Run the event loop event_loop.run(move |event, _, control_flow| { - + *control_flow = ControlFlow::Poll; + match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => { + *control_flow = ControlFlow::Exit; + }, + _ => (), + }, + Event::MainEventsCleared => { + world.run_workload(update).unwrap(); + let mut target = { + let renderer = world.borrow::>>().unwrap(); + renderer.display.draw() + }; + target.clear_color_and_depth((0., 0., 0., 1.), 1.); + world.add_unique_non_send_sync(RenderTarget(target)); + world.run_workload(render).unwrap(); + let target = world.remove_unique::().unwrap(); + target.0.finish().unwrap(); + }, + _ => (), + }; }); } diff --git a/src/rendering.rs b/src/rendering.rs index db2ad61..8182c93 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -1,3 +1,31 @@ -fn init_display() { - +use shipyard::Unique; +use glium::{ + glutin::{ + event_loop::EventLoop, + window::WindowBuilder, + ContextBuilder, GlProfile + }, + Display, +}; + +#[derive(Unique)] +pub struct RenderTarget(pub glium::Frame); + +#[derive(Unique)] +pub struct Rederer { + pub display: Display +} +impl Rederer { + pub fn init(event_loop: &EventLoop<()>) -> Self { + log::info!("initializing display"); + let wb = WindowBuilder::new() + .with_title("uwu") + .with_maximized(true); + let cb = ContextBuilder::new() + .with_depth_buffer(24) + .with_gl_profile(GlProfile::Core); + let display = Display::new(wb, cb, event_loop) + .expect("Failed to create a glium Display"); + Self { display } + } } From e89dd07e66ce58b1e3910899b13ad2b976a1ea24 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 00:45:46 +0100 Subject: [PATCH 06/81] some progress --- src/camera.rs | 0 src/main.rs | 41 +++++++++++++++++++++++++++++++++++++---- src/player.rs | 1 + src/prefabs.rs | 0 src/rendering.rs | 12 ++++++++++-- src/world.rs | 2 ++ src/world/block.rs | 11 +++++++++++ src/world/chunk.rs | 0 8 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/camera.rs create mode 100644 src/player.rs create mode 100644 src/prefabs.rs create mode 100644 src/world.rs create mode 100644 src/world/block.rs create mode 100644 src/world/chunk.rs diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index 76e1fcd..f85003a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,8 @@ -use shipyard::{World, Workload, IntoWorkload, View, UniqueView, NonSendSync}; +use shipyard::{ + World, Workload, IntoWorkload, + UniqueView, UniqueViewMut, + NonSendSync, Unique +}; use glium::{ Surface, glutin::{ @@ -6,14 +10,24 @@ use glium::{ event::{Event, WindowEvent} } }; +use glam::vec3; +use std::time::{Instant, Duration}; mod logging; -mod rendering; +pub(crate) mod rendering; +pub(crate) mod player; +pub(crate) mod world; -use rendering::{Rederer, RenderTarget}; +use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; + +#[derive(Unique)] +pub(crate) struct DeltaTime(Duration); fn render() -> Workload { - (||()).into_workload() + ( + clear_background, + + ).into_workload() } fn update() -> Workload { (||()).into_workload() @@ -29,6 +43,8 @@ fn main() { let world = World::new(); //Add systems and uniques + world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); + world.add_unique(DeltaTime(Duration::default())); world.add_unique_non_send_sync( Rederer::init(&event_loop) ); @@ -36,24 +52,41 @@ fn main() { world.add_workload(render); //Run the event loop + let mut last_update = Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => { + log::info!("exit requested"); *control_flow = ControlFlow::Exit; }, _ => (), }, Event::MainEventsCleared => { + //Update delta time (maybe move this into a system?) + { + let mut dt_view = world.borrow::>().unwrap(); + let now = Instant::now(); + dt_view.0 = now - last_update; + last_update = now; + } + + //Run update workflow world.run_workload(update).unwrap(); + + //Start rendering let mut target = { let renderer = world.borrow::>>().unwrap(); renderer.display.draw() }; target.clear_color_and_depth((0., 0., 0., 1.), 1.); world.add_unique_non_send_sync(RenderTarget(target)); + + //Run render workflow world.run_workload(render).unwrap(); + + //Finish rendering let target = world.remove_unique::().unwrap(); target.0.finish().unwrap(); }, diff --git a/src/player.rs b/src/player.rs new file mode 100644 index 0000000..a8bdf86 --- /dev/null +++ b/src/player.rs @@ -0,0 +1 @@ +pub struct Player; diff --git a/src/prefabs.rs b/src/prefabs.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/rendering.rs b/src/rendering.rs index 8182c93..c00f500 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -1,16 +1,20 @@ -use shipyard::Unique; +use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut}; use glium::{ glutin::{ event_loop::EventLoop, window::WindowBuilder, ContextBuilder, GlProfile }, - Display, + Display, Surface, }; +use glam::Vec3; #[derive(Unique)] pub struct RenderTarget(pub glium::Frame); +#[derive(Unique)] +pub struct BackgroundColor(pub Vec3); + #[derive(Unique)] pub struct Rederer { pub display: Display @@ -29,3 +33,7 @@ impl Rederer { Self { display } } } + +pub fn clear_background(mut target: NonSendSync>, color: UniqueView) { + target.0.clear_color_srgb_and_depth((color.0.x, color.0.y, color.0.z, 1.), 1.); +} diff --git a/src/world.rs b/src/world.rs new file mode 100644 index 0000000..750315d --- /dev/null +++ b/src/world.rs @@ -0,0 +1,2 @@ +pub mod chunk; +pub mod block; diff --git a/src/world/block.rs b/src/world/block.rs new file mode 100644 index 0000000..3ac2026 --- /dev/null +++ b/src/world/block.rs @@ -0,0 +1,11 @@ +use strum::EnumIter; + +#[derive(Clone, Copy, Debug, EnumIter)] +#[repr(u8)] +pub enum Block { + Air, + Stone, + Dirt, + Grass, + Sand, +} diff --git a/src/world/chunk.rs b/src/world/chunk.rs new file mode 100644 index 0000000..e69de29 From 000e1c341af7ac8e3603d41c2452f7e39625bf30 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 02:54:41 +0100 Subject: [PATCH 07/81] prefab loader --- src/main.rs | 11 +++++-- src/prefabs.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index f85003a..1acab60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,8 +17,10 @@ mod logging; pub(crate) mod rendering; pub(crate) mod player; pub(crate) mod world; +pub(crate) mod prefabs; use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; +use prefabs::load_prefabs; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); @@ -42,12 +44,15 @@ fn main() { //Create a shipyard world let world = World::new(); - //Add systems and uniques - world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); - world.add_unique(DeltaTime(Duration::default())); + //Init and load things world.add_unique_non_send_sync( Rederer::init(&event_loop) ); + load_prefabs(&world); + + //Add systems and uniques + world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); + world.add_unique(DeltaTime(Duration::default())); world.add_workload(update); world.add_workload(render); diff --git a/src/prefabs.rs b/src/prefabs.rs index e69de29..66fe6be 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -0,0 +1,88 @@ +use shipyard::{World, NonSendSync, UniqueView, Unique}; +use strum::{EnumIter, IntoEnumIterator}; +use rayon::prelude::*; +use glium::{texture::{SrgbTexture2dArray, RawImage2d}, backend::Facade}; +use std::{fs::File, path::PathBuf, io::BufReader}; +use crate::rendering::Rederer; + +trait AssetPaths { + fn file_name(self) -> &'static str; +} + +#[derive(Clone, Copy, Debug, EnumIter)] +#[repr(u8)] +pub enum BlockTextures { + Stone = 0, + Dirt = 1, + GrassTop = 2, + GrassSide = 3, + Sand = 4, + Bedrock = 5, + Wood = 6, + WoodTop = 7, + Leaf = 8, + Torch = 9, + TallGrass = 10, + Snow = 11, + GrassSideSnow = 12, +} +impl AssetPaths for BlockTextures { + fn file_name(self) -> &'static str { + match self { + Self::Stone => "stone.png", + Self::Dirt => "dirt.png", + Self::GrassTop => "grass_top.png", + Self::GrassSide => "grass_side.png", + Self::Sand => "sand.png", + Self::Bedrock => "bedrock.png", + Self::Wood => "wood.png", + Self::WoodTop => "wood_top.png", + Self::Leaf => "leaf.png", + Self::Torch => "torch.png", + Self::TallGrass => "tall_grass.png", + Self::Snow => "snow.png", + Self::GrassSideSnow => "grass_side_snow.png", + } + } +} + +fn load_texture2darray_prefab(directory: PathBuf, facade: &E) -> SrgbTexture2dArray { + //Load raw images + let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect(); + let raw_images: Vec> = tex_files.par_iter().map(|&file_name| { + log::info!("loading texture {}", file_name); + //Get path to the image and open the file + let reader = { + let path = directory.join(file_name); + BufReader::new(File::open(path).expect("Failed to open texture file")) + }; + //Parse image data + let (image_data, dimensions) = { + let image =image::load( + reader, + image::ImageFormat::Png + ).unwrap().to_rgba8(); + let dimensions = image.dimensions(); + (image.into_raw(), dimensions) + }; + //Create a glium RawImage + RawImage2d::from_raw_rgba_reversed( + &image_data, + dimensions + ) + }).collect(); + log::info!("done loading texture files, uploading to the gpu"); + //Upload images to the GPU + SrgbTexture2dArray::new(facade, raw_images) + .expect("Failed to upload texture array to GPU") +} + +#[derive(Unique)] +pub struct BlockTexturesPrefab(SrgbTexture2dArray); + +pub fn load_prefabs(world: &World) { + let renderer = world.borrow::>>().unwrap(); + world.add_unique_non_send_sync(BlockTexturesPrefab( + load_texture2darray_prefab::("./assets/blocks/".into(), &renderer.display) + )); +} From d96e99fd0e20a57de3538102802428153b811dea Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 03:08:09 +0100 Subject: [PATCH 08/81] world structure --- src/main.rs | 2 +- src/world.rs | 9 +++++++++ src/world/chunk.rs | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 1acab60..1f10005 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,7 +80,7 @@ fn main() { //Run update workflow world.run_workload(update).unwrap(); - //Start rendering + //Start rendering (maybe use custom views for this?) let mut target = { let renderer = world.borrow::>>().unwrap(); renderer.display.draw() diff --git a/src/world.rs b/src/world.rs index 750315d..a21d2bf 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,2 +1,11 @@ +use glam::IVec2; +use hashbrown::HashMap; + pub mod chunk; pub mod block; + +use chunk::Chunk; + +pub struct World { + pub chunks: HashMap +} diff --git a/src/world/chunk.rs b/src/world/chunk.rs index e69de29..abfa45e 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -0,0 +1 @@ +pub struct Chunk; From 706f482f1870eefead5f7970dafc43421feee5d6 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 03:28:08 +0100 Subject: [PATCH 09/81] Add readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..3431e0e --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +

Kubi

+work in progress +
~ uwu
From 2c01480a93cac31d42e3e97bb29e115eae61f127 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 03:41:04 +0100 Subject: [PATCH 10/81] chunk structure --- src/world/chunk.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/world/chunk.rs b/src/world/chunk.rs index abfa45e..d47b680 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -1 +1,41 @@ -pub struct Chunk; +use glam::IVec3; +use glium::{VertexBuffer, IndexBuffer}; +use super::block::Block; + +pub const CHUNK_SIZE: usize = 32; + +type ChunkBlockData = Box<[[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]>; + +pub struct ChunkData { + pub blocks: ChunkBlockData, + pub has_renderable_blocks: bool, +} +impl ChunkData { + pub fn update_metadata(&mut self) { + todo!() + } +} + +pub struct ChunkMesh { + pub is_dirty: bool, + pub vertex_buffer: VertexBuffer, + pub index_buffer: IndexBuffer, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ChunkState { + ToUnload, //desired only + Nothing, + Loading, //current only + Loaded, + Meshing, //current only + Rendered +} + +pub struct Chunk { + pub position: IVec3, + pub block_data: Option, + pub mesh: Option, + pub current_state: ChunkState, + pub desired_state: ChunkState, +} From a39ad3b2dd8eff3f47190547a6bed9db32d4d4d6 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 16:28:34 +0100 Subject: [PATCH 11/81] loader --- crabs.txt | 1 + shaders/world.frag | 15 +++++++++++ shaders/world.vert | 25 ++++++++++++++++++ src/main.rs | 3 +++ src/prefabs.rs | 58 +++++++++++++++++------------------------- src/prefabs/shaders.rs | 29 +++++++++++++++++++++ src/prefabs/texture.rs | 40 +++++++++++++++++++++++++++++ src/world.rs | 1 + src/world/chunk.rs | 6 ++--- src/world/render.rs | 10 ++++++++ 10 files changed, 150 insertions(+), 38 deletions(-) create mode 100644 crabs.txt create mode 100644 shaders/world.frag create mode 100644 shaders/world.vert create mode 100644 src/prefabs/shaders.rs create mode 100644 src/prefabs/texture.rs create mode 100644 src/world/render.rs diff --git a/crabs.txt b/crabs.txt new file mode 100644 index 0000000..aecc062 --- /dev/null +++ b/crabs.txt @@ -0,0 +1 @@ +sorry no crabs here diff --git a/shaders/world.frag b/shaders/world.frag new file mode 100644 index 0000000..e07b5e1 --- /dev/null +++ b/shaders/world.frag @@ -0,0 +1,15 @@ +#version 150 core + +in vec3 v_normal; +in vec2 v_uv; +flat in uint v_tex_index; +out vec4 color; +uniform sampler2DArray tex; + +void main() { + // base color from texture + color = texture(tex, vec3(v_uv, v_tex_index)); + //basic "lighting" + float light = abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z); + color *= vec4(vec3(light), 1.); +} diff --git a/shaders/world.vert b/shaders/world.vert new file mode 100644 index 0000000..955ca12 --- /dev/null +++ b/shaders/world.vert @@ -0,0 +1,25 @@ +#version 150 core + +//TODO pack this data: +// uint position_normal_uv +// XXYYZZNU +// wehere Normal and Uv are enums +// maybe somehow pack in tex index too + +in vec3 position; +in vec3 normal; +in vec2 uv; +in uint tex_index; +out vec2 v_uv; +out vec3 v_normal; +flat out uint v_tex_index; +uniform vec2 position_offset; +uniform mat4 perspective; +uniform mat4 view; + +void main() { + v_normal = normal; + v_tex_index = tex_index; + v_uv = uv; + gl_Position = perspective * view * (vec4(position, 1.0) + vec4(position_offset.x, 0., position_offset.y, 0.)); +} diff --git a/src/main.rs b/src/main.rs index 1f10005..c683f6b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,6 +62,9 @@ fn main() { *control_flow = ControlFlow::Poll; match event { Event::WindowEvent { event, .. } => match event { + WindowEvent::Resized(size) => { + // todo ... + } WindowEvent::CloseRequested => { log::info!("exit requested"); *control_flow = ControlFlow::Exit; diff --git a/src/prefabs.rs b/src/prefabs.rs index 66fe6be..8b33afe 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -1,11 +1,15 @@ use shipyard::{World, NonSendSync, UniqueView, Unique}; use strum::{EnumIter, IntoEnumIterator}; -use rayon::prelude::*; -use glium::{texture::{SrgbTexture2dArray, RawImage2d}, backend::Facade}; -use std::{fs::File, path::PathBuf, io::BufReader}; +use glium::{texture::{SrgbTexture2dArray, RawImage2d}, backend::Facade, Program}; use crate::rendering::Rederer; -trait AssetPaths { +mod texture; +mod shaders; + +use texture::load_texture2darray_prefab; +use shaders::include_shader_prefab; + +pub trait AssetPaths { fn file_name(self) -> &'static str; } @@ -46,43 +50,27 @@ impl AssetPaths for BlockTextures { } } -fn load_texture2darray_prefab(directory: PathBuf, facade: &E) -> SrgbTexture2dArray { - //Load raw images - let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect(); - let raw_images: Vec> = tex_files.par_iter().map(|&file_name| { - log::info!("loading texture {}", file_name); - //Get path to the image and open the file - let reader = { - let path = directory.join(file_name); - BufReader::new(File::open(path).expect("Failed to open texture file")) - }; - //Parse image data - let (image_data, dimensions) = { - let image =image::load( - reader, - image::ImageFormat::Png - ).unwrap().to_rgba8(); - let dimensions = image.dimensions(); - (image.into_raw(), dimensions) - }; - //Create a glium RawImage - RawImage2d::from_raw_rgba_reversed( - &image_data, - dimensions - ) - }).collect(); - log::info!("done loading texture files, uploading to the gpu"); - //Upload images to the GPU - SrgbTexture2dArray::new(facade, raw_images) - .expect("Failed to upload texture array to GPU") -} + #[derive(Unique)] pub struct BlockTexturesPrefab(SrgbTexture2dArray); +#[derive(Unique)] +pub struct ChunkShaderPrefab(Program); + pub fn load_prefabs(world: &World) { let renderer = world.borrow::>>().unwrap(); world.add_unique_non_send_sync(BlockTexturesPrefab( - load_texture2darray_prefab::("./assets/blocks/".into(), &renderer.display) + load_texture2darray_prefab::( + "./assets/blocks/".into(), + &renderer.display + ) + )); + world.add_unique_non_send_sync(ChunkShaderPrefab( + include_shader_prefab!( + "../shaders/world.vert", + "../shaders/world.frag", + &renderer.display + ) )); } diff --git a/src/prefabs/shaders.rs b/src/prefabs/shaders.rs new file mode 100644 index 0000000..5f7ed07 --- /dev/null +++ b/src/prefabs/shaders.rs @@ -0,0 +1,29 @@ +use glium::{Program, backend::Facade}; + +macro_rules! include_shader_prefab { + ($vert: literal, $frag: literal, $geom: literal, $facade: expr) => { + { + log::info!("↓↓↓ compiling shader prefab ↓↓↓"); + log::info!("{} {} {}", $vert, $frag, $geom); + Program::from_source( + &*$facade, + include_str!($vert), + include_str!($frag), + Some(include_str!($geom)), + ).expect("Failed to compile gpu program") + } + }; + ($vert: literal, $frag: literal, $facade: expr) => { + { + log::info!("↓↓↓ compiling shader prefab ↓↓↓"); + log::info!("{} {}", $vert, $frag); + Program::from_source( + &*$facade, + include_str!($vert), + include_str!($frag), + None, + ).expect("Failed to compile gpu program") + } + }; +} +pub(crate) use include_shader_prefab; diff --git a/src/prefabs/texture.rs b/src/prefabs/texture.rs new file mode 100644 index 0000000..7bfda57 --- /dev/null +++ b/src/prefabs/texture.rs @@ -0,0 +1,40 @@ +use strum::IntoEnumIterator; +use rayon::prelude::*; +use std::{fs::File, path::PathBuf, io::BufReader}; +use glium::{texture::{SrgbTexture2dArray, RawImage2d}, backend::Facade}; +use super::AssetPaths; + +pub fn load_texture2darray_prefab( + directory: PathBuf, + facade: &E +) -> SrgbTexture2dArray { + log::info!("↓↓↓ loading textures {} ↓↓↓", directory.as_os_str().to_str().unwrap()); + //Load raw images + let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect(); + let raw_images: Vec> = tex_files.par_iter().map(|&file_name| { + log::info!("loading texture {}", file_name); + //Get path to the image and open the file + let reader = { + let path = directory.join(file_name); + BufReader::new(File::open(path).expect("Failed to open texture file")) + }; + //Parse image data + let (image_data, dimensions) = { + let image =image::load( + reader, + image::ImageFormat::Png + ).unwrap().to_rgba8(); + let dimensions = image.dimensions(); + (image.into_raw(), dimensions) + }; + //Create a glium RawImage + RawImage2d::from_raw_rgba_reversed( + &image_data, + dimensions + ) + }).collect(); + log::info!("done loading texture files, uploading to the gpu"); + //Upload images to the GPU + SrgbTexture2dArray::new(facade, raw_images) + .expect("Failed to upload texture array to GPU") +} diff --git a/src/world.rs b/src/world.rs index a21d2bf..c780f13 100644 --- a/src/world.rs +++ b/src/world.rs @@ -3,6 +3,7 @@ use hashbrown::HashMap; pub mod chunk; pub mod block; +pub mod render; use chunk::Chunk; diff --git a/src/world/chunk.rs b/src/world/chunk.rs index d47b680..d4af7d1 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -1,6 +1,6 @@ use glam::IVec3; use glium::{VertexBuffer, IndexBuffer}; -use super::block::Block; +use super::{block::Block, render::ChunkVertex}; pub const CHUNK_SIZE: usize = 32; @@ -26,9 +26,9 @@ pub struct ChunkMesh { pub enum ChunkState { ToUnload, //desired only Nothing, - Loading, //current only + Loading, //current only Loaded, - Meshing, //current only + Meshing, //current only Rendered } diff --git a/src/world/render.rs b/src/world/render.rs new file mode 100644 index 0000000..9ae11b1 --- /dev/null +++ b/src/world/render.rs @@ -0,0 +1,10 @@ +use glium::implement_vertex; + +#[derive(Clone, Copy)] +pub struct ChunkVertex { + pub position: [f32; 3], + pub normal: [f32; 3], + pub uv: [f32; 2], + pub tex_index: u8, +} +implement_vertex!(ChunkVertex, position, normal, uv, tex_index); From cc08456b392f695227aa3dc202a54692d743020b Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 17:42:04 +0100 Subject: [PATCH 12/81] meow --- src/main.rs | 8 ++-- src/prefabs.rs | 6 +-- src/prefabs/shaders.rs | 4 +- src/prefabs/texture.rs | 5 ++- src/world.rs | 99 ++++++++++++++++++++++++++++++++++++++++-- src/world/mesh.rs | 0 6 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 src/world/mesh.rs diff --git a/src/main.rs b/src/main.rs index c683f6b..14bb48c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ pub(crate) mod world; pub(crate) mod prefabs; use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; +use world::GameWorld; use prefabs::load_prefabs; #[derive(Unique)] @@ -44,13 +45,14 @@ fn main() { //Create a shipyard world let world = World::new(); - //Init and load things + //Add systems and uniques, Init and load things world.add_unique_non_send_sync( Rederer::init(&event_loop) ); load_prefabs(&world); - - //Add systems and uniques + world.add_unique_non_send_sync( + GameWorld::new() + ); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); world.add_workload(update); diff --git a/src/prefabs.rs b/src/prefabs.rs index 8b33afe..f4c0532 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -1,6 +1,6 @@ use shipyard::{World, NonSendSync, UniqueView, Unique}; -use strum::{EnumIter, IntoEnumIterator}; -use glium::{texture::{SrgbTexture2dArray, RawImage2d}, backend::Facade, Program}; +use glium::{texture::SrgbTexture2dArray, Program}; +use strum::EnumIter; use crate::rendering::Rederer; mod texture; @@ -50,8 +50,6 @@ impl AssetPaths for BlockTextures { } } - - #[derive(Unique)] pub struct BlockTexturesPrefab(SrgbTexture2dArray); diff --git a/src/prefabs/shaders.rs b/src/prefabs/shaders.rs index 5f7ed07..97bffa6 100644 --- a/src/prefabs/shaders.rs +++ b/src/prefabs/shaders.rs @@ -1,8 +1,9 @@ -use glium::{Program, backend::Facade}; + macro_rules! include_shader_prefab { ($vert: literal, $frag: literal, $geom: literal, $facade: expr) => { { + use ::glium::Program; log::info!("↓↓↓ compiling shader prefab ↓↓↓"); log::info!("{} {} {}", $vert, $frag, $geom); Program::from_source( @@ -15,6 +16,7 @@ macro_rules! include_shader_prefab { }; ($vert: literal, $frag: literal, $facade: expr) => { { + use ::glium::Program; log::info!("↓↓↓ compiling shader prefab ↓↓↓"); log::info!("{} {}", $vert, $frag); Program::from_source( diff --git a/src/prefabs/texture.rs b/src/prefabs/texture.rs index 7bfda57..bb1415d 100644 --- a/src/prefabs/texture.rs +++ b/src/prefabs/texture.rs @@ -4,7 +4,10 @@ use std::{fs::File, path::PathBuf, io::BufReader}; use glium::{texture::{SrgbTexture2dArray, RawImage2d}, backend::Facade}; use super::AssetPaths; -pub fn load_texture2darray_prefab( +pub fn load_texture2darray_prefab< + T: AssetPaths + IntoEnumIterator, + E: Facade +>( directory: PathBuf, facade: &E ) -> SrgbTexture2dArray { diff --git a/src/world.rs b/src/world.rs index c780f13..c53434b 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,4 +1,5 @@ -use glam::IVec2; +use shipyard::Unique; +use glam::{IVec3, ivec3}; use hashbrown::HashMap; pub mod chunk; @@ -7,6 +8,98 @@ pub mod render; use chunk::Chunk; -pub struct World { - pub chunks: HashMap + +//TODO separate world struct for render data +// because this is not send-sync + + +pub struct AllChunksNeighbors<'a> { + pub center: &'a Chunk, + pub top: &'a Chunk, + pub bottom: &'a Chunk, + pub left: &'a Chunk, + pub right: &'a Chunk, + pub front: &'a Chunk, + pub back: &'a Chunk, +} +pub struct AllChunksNeighborsMut<'a> { + pub center: &'a mut Chunk, + pub top: &'a mut Chunk, + pub bottom: &'a mut Chunk, + pub left: &'a mut Chunk, + pub right: &'a mut Chunk, + pub front: &'a mut Chunk, + pub back: &'a mut Chunk, +} +pub struct ChunksNeighbors<'a> { + pub center: Option<&'a Chunk>, + pub top: Option<&'a Chunk>, + pub bottom: Option<&'a Chunk>, + pub left: Option<&'a Chunk>, + pub right: Option<&'a Chunk>, + pub front: Option<&'a Chunk>, + pub back: Option<&'a Chunk>, +} +impl<'a> ChunksNeighbors<'a> { + pub fn all(&self) -> Option> { + Some(AllChunksNeighbors { + center: self.center?, + top: self.top?, + bottom: self.bottom?, + left: self.left?, + right: self.right?, + front: self.front?, + back: self.back?, + }) + } +} + +#[derive(Default, Unique)] +pub struct GameWorld { + pub chunks: HashMap +} +impl GameWorld { + pub fn new() -> Self { + Self::default() + } + pub fn neighbors(&self, coords: IVec3) -> ChunksNeighbors { + ChunksNeighbors { + center: self.chunks.get(&coords), + top: self.chunks.get(&(coords - ivec3(0, 1, 0))), + bottom: self.chunks.get(&(coords + ivec3(0, 1, 0))), + left: self.chunks.get(&(coords - ivec3(1, 0, 0))), + right: self.chunks.get(&(coords + ivec3(1, 0, 0))), + front: self.chunks.get(&(coords - ivec3(0, 0, 1))), + back: self.chunks.get(&(coords + ivec3(0, 0, 1))), + } + } + pub fn neighbors_all(&self, coords: IVec3) -> Option { + self.neighbors(coords).all() + } + pub fn neighbors_all_mut(&mut self, coords: IVec3) -> Option { + let mut refs = self.chunks.get_many_mut([ + &coords, + &(coords - ivec3(0, 1, 0)), + &(coords + ivec3(0, 1, 0)), + &(coords - ivec3(1, 0, 0)), + &(coords + ivec3(1, 0, 0)), + &(coords - ivec3(0, 0, 1)), + &(coords + ivec3(0, 0, 1)), + ])?.map(Some); + Some(AllChunksNeighborsMut { + center: std::mem::take(&mut refs[0]).unwrap(), + top: std::mem::take(&mut refs[1]).unwrap(), + bottom: std::mem::take(&mut refs[2]).unwrap(), + left: std::mem::take(&mut refs[3]).unwrap(), + right: std::mem::take(&mut refs[4]).unwrap(), + front: std::mem::take(&mut refs[5]).unwrap(), + back: std::mem::take(&mut refs[6]).unwrap(), + }) + } +} + +fn update_world( + +) { + } diff --git a/src/world/mesh.rs b/src/world/mesh.rs new file mode 100644 index 0000000..e69de29 From 10faee215fb87773ca3410ad4698ba34edbacd4a Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 20:40:08 +0100 Subject: [PATCH 13/81] owo --- src/main.rs | 1 + src/transform.rs | 3 +++ src/world.rs | 2 +- src/world/chunk.rs | 1 - src/world/tasks.rs | 0 5 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 src/transform.rs create mode 100644 src/world/tasks.rs diff --git a/src/main.rs b/src/main.rs index 14bb48c..03346ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ pub(crate) mod rendering; pub(crate) mod player; pub(crate) mod world; pub(crate) mod prefabs; +pub(crate) mod transform; use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; use world::GameWorld; diff --git a/src/transform.rs b/src/transform.rs new file mode 100644 index 0000000..9176edd --- /dev/null +++ b/src/transform.rs @@ -0,0 +1,3 @@ +use glam::Mat4; + +pub struct Transform(Mat4); diff --git a/src/world.rs b/src/world.rs index c53434b..93d7f72 100644 --- a/src/world.rs +++ b/src/world.rs @@ -5,10 +5,10 @@ use hashbrown::HashMap; pub mod chunk; pub mod block; pub mod render; +pub mod tasks; use chunk::Chunk; - //TODO separate world struct for render data // because this is not send-sync diff --git a/src/world/chunk.rs b/src/world/chunk.rs index d4af7d1..3cb1978 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -5,7 +5,6 @@ use super::{block::Block, render::ChunkVertex}; pub const CHUNK_SIZE: usize = 32; type ChunkBlockData = Box<[[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]>; - pub struct ChunkData { pub blocks: ChunkBlockData, pub has_renderable_blocks: bool, diff --git a/src/world/tasks.rs b/src/world/tasks.rs new file mode 100644 index 0000000..e69de29 From 3d7083dc42f660ea2014eb0f28b5cf9362a23b15 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 20 Jan 2023 21:55:02 +0100 Subject: [PATCH 14/81] some things --- src/main.rs | 23 ++++++++++++++++++----- src/player.rs | 24 ++++++++++++++++++++++++ src/transform.rs | 5 ++++- src/world.rs | 8 +------- src/world/loading.rs | 13 +++++++++++++ 5 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 src/world/loading.rs diff --git a/src/main.rs b/src/main.rs index 03346ad..1b4fb3f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,20 +21,27 @@ pub(crate) mod prefabs; pub(crate) mod transform; use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; -use world::GameWorld; +use player::spawn_player; +use world::{GameWorld, loading::load_world_around_player}; use prefabs::load_prefabs; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); -fn render() -> Workload { +fn startup() -> Workload { ( - clear_background, - + spawn_player, ).into_workload() } fn update() -> Workload { - (||()).into_workload() + ( + load_world_around_player + ).into_workload() +} +fn render() -> Workload { + ( + clear_background, + ).into_workload() } fn main() { @@ -56,9 +63,15 @@ fn main() { ); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); + + //Register workloads + world.add_workload(startup); world.add_workload(update); world.add_workload(render); + //Run startup systems + world.run_workload(startup).unwrap(); + //Run the event loop let mut last_update = Instant::now(); event_loop.run(move |event, _, control_flow| { diff --git a/src/player.rs b/src/player.rs index a8bdf86..5052205 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1 +1,25 @@ +use glam::Mat4; +use shipyard::{Component, EntitiesViewMut, ViewMut}; + +use crate::transform::Transform; + +#[derive(Component)] pub struct Player; + +pub fn spawn_player ( + mut entities: EntitiesViewMut, + mut vm_player: ViewMut, + mut vm_transform: ViewMut +) { + log::info!("spawning player"); + entities.add_entity( + ( + &mut vm_player, + &mut vm_transform + ), + ( + Player, + Transform(Mat4::default()) + ) + ); +} diff --git a/src/transform.rs b/src/transform.rs index 9176edd..5087b6c 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,3 +1,6 @@ +use shipyard::Component; use glam::Mat4; -pub struct Transform(Mat4); +#[derive(Component, Clone, Copy, Debug, Default)] +#[track(All)] +pub struct Transform(pub Mat4); diff --git a/src/world.rs b/src/world.rs index 93d7f72..b2608c7 100644 --- a/src/world.rs +++ b/src/world.rs @@ -6,13 +6,13 @@ pub mod chunk; pub mod block; pub mod render; pub mod tasks; +pub mod loading; use chunk::Chunk; //TODO separate world struct for render data // because this is not send-sync - pub struct AllChunksNeighbors<'a> { pub center: &'a Chunk, pub top: &'a Chunk, @@ -97,9 +97,3 @@ impl GameWorld { }) } } - -fn update_world( - -) { - -} diff --git a/src/world/loading.rs b/src/world/loading.rs new file mode 100644 index 0000000..551cfd1 --- /dev/null +++ b/src/world/loading.rs @@ -0,0 +1,13 @@ +use shipyard::{View, UniqueViewMut, NonSendSync, IntoIter}; +use crate::{player::Player, transform::Transform}; +use super::GameWorld; + +pub fn load_world_around_player( + v_player: View, + v_transform: View, + vm_world: NonSendSync>, +) { + for (player, transform) in (&v_player, v_transform.inserted_or_modified()).iter() { + + } +} From e3ef07df674c996a5e66b9fb4733ee23f7508545 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 21 Jan 2023 02:39:55 +0100 Subject: [PATCH 15/81] sync --- src/main.rs | 1 + src/settings.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/settings.rs diff --git a/src/main.rs b/src/main.rs index 1b4fb3f..235edde 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ pub(crate) mod player; pub(crate) mod world; pub(crate) mod prefabs; pub(crate) mod transform; +pub(crate) mod settings; use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; use player::spawn_player; diff --git a/src/settings.rs b/src/settings.rs new file mode 100644 index 0000000..9b52fd2 --- /dev/null +++ b/src/settings.rs @@ -0,0 +1,14 @@ +use shipyard::Unique; + +#[derive(Unique)] +pub struct GameSettings { + //there's a 1 chunk border of loaded but invisible around this + pub render_distance: usize, +} +impl Default for GameSettings { + fn default() -> Self { + Self { + render_distance: 5 + } + } +} From 5b0817b3187d14c8c7931823d848a0ede4f3b040 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 21 Jan 2023 03:40:23 +0100 Subject: [PATCH 16/81] WIP Chunk loading --- src/main.rs | 2 ++ src/player.rs | 6 +++++ src/settings.rs | 2 +- src/world/loading.rs | 61 ++++++++++++++++++++++++++++++++++++-------- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 235edde..b27a5c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; use player::spawn_player; use world::{GameWorld, loading::load_world_around_player}; use prefabs::load_prefabs; +use settings::GameSettings; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); @@ -64,6 +65,7 @@ fn main() { ); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); + world.add_unique(GameSettings::default()); //Register workloads world.add_workload(startup); diff --git a/src/player.rs b/src/player.rs index 5052205..9990f65 100644 --- a/src/player.rs +++ b/src/player.rs @@ -3,22 +3,28 @@ use shipyard::{Component, EntitiesViewMut, ViewMut}; use crate::transform::Transform; +#[derive(Component)] +pub struct LocalPlayer; + #[derive(Component)] pub struct Player; pub fn spawn_player ( mut entities: EntitiesViewMut, mut vm_player: ViewMut, + mut vm_local_player: ViewMut, mut vm_transform: ViewMut ) { log::info!("spawning player"); entities.add_entity( ( &mut vm_player, + &mut vm_local_player, &mut vm_transform ), ( Player, + LocalPlayer, Transform(Mat4::default()) ) ); diff --git a/src/settings.rs b/src/settings.rs index 9b52fd2..df9cd49 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -3,7 +3,7 @@ use shipyard::Unique; #[derive(Unique)] pub struct GameSettings { //there's a 1 chunk border of loaded but invisible around this - pub render_distance: usize, + pub render_distance: u8, } impl Default for GameSettings { fn default() -> Self { diff --git a/src/world/loading.rs b/src/world/loading.rs index 551cfd1..bb42a57 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -1,13 +1,52 @@ -use shipyard::{View, UniqueViewMut, NonSendSync, IntoIter}; -use crate::{player::Player, transform::Transform}; -use super::GameWorld; +use glam::ivec3; +use shipyard::{View, UniqueView, UniqueViewMut, NonSendSync, IntoIter, Workload, IntoWorkload}; +use crate::{player::LocalPlayer, transform::Transform, settings::GameSettings}; +use super::{GameWorld, chunk::{ChunkState, CHUNK_SIZE}}; -pub fn load_world_around_player( - v_player: View, - v_transform: View, - vm_world: NonSendSync>, -) { - for (player, transform) in (&v_player, v_transform.inserted_or_modified()).iter() { - - } +pub fn load_world_around_player() -> Workload { + ( + mark_chunks, + ).into_workload() +} + +pub fn mark_chunks( + v_settings: UniqueView, + v_local_player: View, + v_transform: View, + mut vm_world: NonSendSync>, +) { + //Read game settings + let load_distance = (v_settings.render_distance + 1) as i32; + + //Check if a player moved + let Some((_, transform)) = (&v_local_player, v_transform.inserted_or_modified()).iter().next() else { + return + }; + + //If it did, get it's position and current chunk + let position = transform.0.to_scale_rotation_translation().2; + let at_chunk = position.as_ivec3() / CHUNK_SIZE as i32; + + //Then, mark *ALL* chunks with ToUnload + for (_, chunk) in &mut vm_world.chunks { + chunk.desired_state = ChunkState::ToUnload; + } + + //Then mark chunks that are near to the player + for x in -load_distance..=load_distance { + for y in -load_distance..=load_distance { + for z in -load_distance..=load_distance { + let chunk_pos_offset = ivec3(x, y, z); + let is_border = chunk_pos_offset.to_array() + .iter().any(|x| x.abs() == load_distance); + let desired = match is_border { + true => ChunkState::Loaded, + false => ChunkState::Rendered, + }; + } + } + } + + //TODO + todo!() } From dc0c314bf5ff3470f9b0d19574d5110341283e1d Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 21 Jan 2023 23:56:07 +0100 Subject: [PATCH 17/81] =?UTF-8?q?=D1=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 ++ src/main.rs | 6 ++---- src/world.rs | 36 +++++++++++++++++++++++++++++++++--- src/world/chunk.rs | 5 +++-- src/world/loading.rs | 6 +++--- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 13d6df1..a3273a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,5 @@ hashbrown = "0.13" noise = "0.8" rayon = "1.6" shipyard = { version = "0.6", features = ["thread_local"] } +nohash-hasher = "0.2.0" +anyhow = "1.0" diff --git a/src/main.rs b/src/main.rs index b27a5c0..b538ec9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ pub(crate) mod settings; use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; use player::spawn_player; -use world::{GameWorld, loading::load_world_around_player}; +use world::{ChunkStorage, loading::load_world_around_player}; use prefabs::load_prefabs; use settings::GameSettings; @@ -60,9 +60,7 @@ fn main() { Rederer::init(&event_loop) ); load_prefabs(&world); - world.add_unique_non_send_sync( - GameWorld::new() - ); + world.add_unique(ChunkStorage::new()); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); world.add_unique(GameSettings::default()); diff --git a/src/world.rs b/src/world.rs index b2608c7..e22fafa 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,14 +1,17 @@ +use nohash_hasher::BuildNoHashHasher; use shipyard::Unique; use glam::{IVec3, ivec3}; use hashbrown::HashMap; +use anyhow::{Result, Context}; pub mod chunk; pub mod block; pub mod render; pub mod tasks; pub mod loading; +pub mod mesh; -use chunk::Chunk; +use chunk::{Chunk, ChunkMesh}; //TODO separate world struct for render data // because this is not send-sync @@ -55,10 +58,10 @@ impl<'a> ChunksNeighbors<'a> { } #[derive(Default, Unique)] -pub struct GameWorld { +pub struct ChunkStorage { pub chunks: HashMap } -impl GameWorld { +impl ChunkStorage { pub fn new() -> Self { Self::default() } @@ -97,3 +100,30 @@ impl GameWorld { }) } } + +pub struct ChunkMeshStorage { + meshes: HashMap>, + index: u64, +} +impl ChunkMeshStorage { + pub fn new() -> Self { + Self { + meshes: HashMap::with_capacity_and_hasher(250, BuildNoHashHasher::default()), + index: 0, + } + } + pub fn insert(&mut self, mesh: ChunkMesh) -> u64 { + let index = self.index; + self.meshes.insert_unique_unchecked(index, mesh); + self.index += 1; + index + } + pub fn update(&mut self, key: u64, mesh: ChunkMesh) -> Result<()> { + *self.meshes.get_mut(&key).context("Chunk doesn't exist")? = mesh; + Ok(()) + } + pub fn remove(&mut self, key: u64) -> Result<()> { + self.meshes.remove(&key).context("Chunk doesn't exist")?; + Ok(()) + } +} diff --git a/src/world/chunk.rs b/src/world/chunk.rs index 3cb1978..c08bd9d 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -28,13 +28,14 @@ pub enum ChunkState { Loading, //current only Loaded, Meshing, //current only - Rendered + Rendered, + RecalculatingMesh //current only } pub struct Chunk { pub position: IVec3, pub block_data: Option, - pub mesh: Option, + pub mesh_index: Option, pub current_state: ChunkState, pub desired_state: ChunkState, } diff --git a/src/world/loading.rs b/src/world/loading.rs index bb42a57..57c0cde 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -1,7 +1,7 @@ use glam::ivec3; -use shipyard::{View, UniqueView, UniqueViewMut, NonSendSync, IntoIter, Workload, IntoWorkload}; +use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload}; use crate::{player::LocalPlayer, transform::Transform, settings::GameSettings}; -use super::{GameWorld, chunk::{ChunkState, CHUNK_SIZE}}; +use super::{ChunkStorage, chunk::{ChunkState, CHUNK_SIZE}}; pub fn load_world_around_player() -> Workload { ( @@ -13,7 +13,7 @@ pub fn mark_chunks( v_settings: UniqueView, v_local_player: View, v_transform: View, - mut vm_world: NonSendSync>, + mut vm_world: UniqueViewMut, ) { //Read game settings let load_distance = (v_settings.render_distance + 1) as i32; From 0a528d8ccf03efc0194eb97758a074146bb32a21 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sun, 22 Jan 2023 00:00:22 +0100 Subject: [PATCH 18/81] "unroll" loop --- src/world/loading.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/world/loading.rs b/src/world/loading.rs index 57c0cde..46942ee 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -37,8 +37,11 @@ pub fn mark_chunks( for y in -load_distance..=load_distance { for z in -load_distance..=load_distance { let chunk_pos_offset = ivec3(x, y, z); - let is_border = chunk_pos_offset.to_array() - .iter().any(|x| x.abs() == load_distance); + let is_border = { + chunk_pos_offset.x.abs() == load_distance || + chunk_pos_offset.y.abs() == load_distance || + chunk_pos_offset.z.abs() == load_distance + }; let desired = match is_border { true => ChunkState::Loaded, false => ChunkState::Rendered, From c761688f81d6e70e0cda576d94c1987c3bd020c6 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sun, 22 Jan 2023 01:51:23 +0100 Subject: [PATCH 19/81] chunk marking/loading!! --- src/main.rs | 13 +++++------ src/prefabs.rs | 4 ++-- src/rendering.rs | 4 ++-- src/world.rs | 13 +++++++---- src/world/chunk.rs | 14 +++++++++++- src/world/loading.rs | 54 +++++++++++++++++++++++++++++++++----------- 6 files changed, 72 insertions(+), 30 deletions(-) diff --git a/src/main.rs b/src/main.rs index b538ec9..daf797d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,9 +21,9 @@ pub(crate) mod prefabs; pub(crate) mod transform; pub(crate) mod settings; -use rendering::{Rederer, RenderTarget, BackgroundColor, clear_background}; +use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; use player::spawn_player; -use world::{ChunkStorage, loading::load_world_around_player}; +use world::{ChunkStorage, ChunkMeshStorage, loading::load_world_around_player}; use prefabs::load_prefabs; use settings::GameSettings; @@ -56,14 +56,13 @@ fn main() { let world = World::new(); //Add systems and uniques, Init and load things - world.add_unique_non_send_sync( - Rederer::init(&event_loop) - ); - load_prefabs(&world); + world.add_unique_non_send_sync(Renderer::init(&event_loop)); world.add_unique(ChunkStorage::new()); + world.add_unique_non_send_sync(ChunkMeshStorage::new()); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); world.add_unique(GameSettings::default()); + load_prefabs(&world); //Register workloads world.add_workload(startup); @@ -102,7 +101,7 @@ fn main() { //Start rendering (maybe use custom views for this?) let mut target = { - let renderer = world.borrow::>>().unwrap(); + let renderer = world.borrow::>>().unwrap(); renderer.display.draw() }; target.clear_color_and_depth((0., 0., 0., 1.), 1.); diff --git a/src/prefabs.rs b/src/prefabs.rs index f4c0532..b77108e 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -1,7 +1,7 @@ use shipyard::{World, NonSendSync, UniqueView, Unique}; use glium::{texture::SrgbTexture2dArray, Program}; use strum::EnumIter; -use crate::rendering::Rederer; +use crate::rendering::Renderer; mod texture; mod shaders; @@ -57,7 +57,7 @@ pub struct BlockTexturesPrefab(SrgbTexture2dArray); pub struct ChunkShaderPrefab(Program); pub fn load_prefabs(world: &World) { - let renderer = world.borrow::>>().unwrap(); + let renderer = world.borrow::>>().unwrap(); world.add_unique_non_send_sync(BlockTexturesPrefab( load_texture2darray_prefab::( "./assets/blocks/".into(), diff --git a/src/rendering.rs b/src/rendering.rs index c00f500..ae07223 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -16,10 +16,10 @@ pub struct RenderTarget(pub glium::Frame); pub struct BackgroundColor(pub Vec3); #[derive(Unique)] -pub struct Rederer { +pub struct Renderer { pub display: Display } -impl Rederer { +impl Renderer { pub fn init(event_loop: &EventLoop<()>) -> Self { log::info!("initializing display"); let wb = WindowBuilder::new() diff --git a/src/world.rs b/src/world.rs index e22fafa..72d19e0 100644 --- a/src/world.rs +++ b/src/world.rs @@ -58,6 +58,7 @@ impl<'a> ChunksNeighbors<'a> { } #[derive(Default, Unique)] +#[track(Modification)] pub struct ChunkStorage { pub chunks: HashMap } @@ -101,9 +102,11 @@ impl ChunkStorage { } } + +#[derive(Default, Unique)] pub struct ChunkMeshStorage { - meshes: HashMap>, - index: u64, + meshes: HashMap>, + index: usize, } impl ChunkMeshStorage { pub fn new() -> Self { @@ -112,17 +115,17 @@ impl ChunkMeshStorage { index: 0, } } - pub fn insert(&mut self, mesh: ChunkMesh) -> u64 { + pub fn insert(&mut self, mesh: ChunkMesh) -> usize { let index = self.index; self.meshes.insert_unique_unchecked(index, mesh); self.index += 1; index } - pub fn update(&mut self, key: u64, mesh: ChunkMesh) -> Result<()> { + pub fn update(&mut self, key: usize, mesh: ChunkMesh) -> Result<()> { *self.meshes.get_mut(&key).context("Chunk doesn't exist")? = mesh; Ok(()) } - pub fn remove(&mut self, key: u64) -> Result<()> { + pub fn remove(&mut self, key: usize) -> Result<()> { self.meshes.remove(&key).context("Chunk doesn't exist")?; Ok(()) } diff --git a/src/world/chunk.rs b/src/world/chunk.rs index c08bd9d..f99989c 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -21,9 +21,10 @@ pub struct ChunkMesh { pub index_buffer: IndexBuffer, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub enum ChunkState { ToUnload, //desired only + #[default] Nothing, Loading, //current only Loaded, @@ -39,3 +40,14 @@ pub struct Chunk { pub current_state: ChunkState, pub desired_state: ChunkState, } +impl Chunk { + pub fn new(position: IVec3) -> Self { + Self { + position, + block_data: None, + mesh_index: None, + current_state: Default::default(), + desired_state: Default::default(), + } + } +} diff --git a/src/world/loading.rs b/src/world/loading.rs index 46942ee..27c20cd 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -1,31 +1,32 @@ use glam::ivec3; -use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload}; +use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync}; use crate::{player::LocalPlayer, transform::Transform, settings::GameSettings}; -use super::{ChunkStorage, chunk::{ChunkState, CHUNK_SIZE}}; +use super::{ChunkStorage, chunk::{Chunk, ChunkState, CHUNK_SIZE}, ChunkMeshStorage}; pub fn load_world_around_player() -> Workload { ( - mark_chunks, + update_chunks_if_player_moved, + unload_marked_chunks ).into_workload() } -pub fn mark_chunks( +pub fn update_chunks_if_player_moved( v_settings: UniqueView, v_local_player: View, v_transform: View, mut vm_world: UniqueViewMut, ) { - //Read game settings - let load_distance = (v_settings.render_distance + 1) as i32; - - //Check if a player moved + //Check if the player actually moved let Some((_, transform)) = (&v_local_player, v_transform.inserted_or_modified()).iter().next() else { return }; + //Read game settings + let load_distance = (v_settings.render_distance + 1) as i32; + //If it did, get it's position and current chunk - let position = transform.0.to_scale_rotation_translation().2; - let at_chunk = position.as_ivec3() / CHUNK_SIZE as i32; + let player_position = transform.0.to_scale_rotation_translation().2; + let player_at_chunk = player_position.as_ivec3() / CHUNK_SIZE as i32; //Then, mark *ALL* chunks with ToUnload for (_, chunk) in &mut vm_world.chunks { @@ -37,19 +38,46 @@ pub fn mark_chunks( for y in -load_distance..=load_distance { for z in -load_distance..=load_distance { let chunk_pos_offset = ivec3(x, y, z); + let chunk_pos = player_at_chunk + chunk_pos_offset; let is_border = { chunk_pos_offset.x.abs() == load_distance || chunk_pos_offset.y.abs() == load_distance || chunk_pos_offset.z.abs() == load_distance }; + //If chunk doesn't exist create it + let chunk = match vm_world.chunks.get_mut(&chunk_pos) { + Some(chunk) => chunk, + None => { + let chunk = Chunk::new(chunk_pos); + vm_world.chunks.insert_unique_unchecked(chunk_pos, chunk); + vm_world.chunks.get_mut(&chunk_pos).unwrap() + } + }; let desired = match is_border { true => ChunkState::Loaded, false => ChunkState::Rendered, }; + chunk.desired_state = desired; } } } - - //TODO - todo!() +} + +fn unload_marked_chunks( + mut vm_world: UniqueViewMut, + mut vm_meshes: NonSendSync> +) { + if !vm_world.is_modified() { + return + } + vm_world.chunks.retain(|_, chunk| { + if chunk.desired_state == ChunkState::ToUnload { + if let Some(mesh_index) = chunk.mesh_index { + vm_meshes.remove(mesh_index).unwrap(); + } + false + } else { + true + } + }) } From 26b43ed2ca10485b1b1a1dcc92296896295db611 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sun, 22 Jan 2023 03:24:28 +0100 Subject: [PATCH 20/81] wip camera --- src/camera.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 14 ++++++++----- src/state.rs | 6 ++++++ src/world/loading.rs | 11 +++++++++-- 4 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 src/state.rs diff --git a/src/camera.rs b/src/camera.rs index e69de29..3efa0f6 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -0,0 +1,47 @@ +use glam::{Mat4, Vec3, Vec3A}; +use shipyard::{Component, ViewMut, View, IntoIter, Workload, IntoWorkload}; +use crate::transform::Transform; + +#[derive(Component)] +pub struct Camera { + pub view_matrix: Mat4, + pub perspective_matrix: Mat4, + pub up: Vec3, + pub fov: f32, + pub z_near: f32, + pub z_far: f32, +} + +pub fn compute_cameras() -> Workload { + ( + update_perspective_matrix, + update_view_matrix, + ).into_workload() +} + +fn update_view_matrix( + mut vm_camera: ViewMut, + v_transform: View +) { + for (camera, transform) in (&mut vm_camera, v_transform.inserted_or_modified()).iter() { + let (_, rotation, translation) = transform.0.to_scale_rotation_translation(); + let dir = rotation * Vec3::Z; //this may be incorrect! + camera.view_matrix = Mat4::look_to_rh(translation, dir, camera.up); + } +} + +fn update_perspective_matrix( + mut vm_camera: ViewMut, + v_transform: View +) { + //todo compute this on win resize! + const ASPECT_RATIO: f32 = 9. / 16.; + for (camera, transform) in (&mut vm_camera, &v_transform).iter() { + camera.perspective_matrix = Mat4::perspective_rh_gl( + camera.fov, + ASPECT_RATIO, + camera.z_near, + camera.z_far, + ) + } +} diff --git a/src/main.rs b/src/main.rs index daf797d..97232f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,17 +15,20 @@ use std::time::{Instant, Duration}; mod logging; pub(crate) mod rendering; -pub(crate) mod player; pub(crate) mod world; +pub(crate) mod player; pub(crate) mod prefabs; pub(crate) mod transform; pub(crate) mod settings; +pub(crate) mod state; +pub(crate) mod camera; use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; +use world::{ChunkStorage, ChunkMeshStorage, loading::update_loaded_world_around_player}; use player::spawn_player; -use world::{ChunkStorage, ChunkMeshStorage, loading::load_world_around_player}; use prefabs::load_prefabs; use settings::GameSettings; +use camera::compute_cameras; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); @@ -37,13 +40,14 @@ fn startup() -> Workload { } fn update() -> Workload { ( - load_world_around_player + update_loaded_world_around_player, + compute_cameras, ).into_workload() } fn render() -> Workload { ( clear_background, - ).into_workload() + ).into_sequential_workload() } fn main() { @@ -57,8 +61,8 @@ fn main() { //Add systems and uniques, Init and load things world.add_unique_non_send_sync(Renderer::init(&event_loop)); - world.add_unique(ChunkStorage::new()); world.add_unique_non_send_sync(ChunkMeshStorage::new()); + world.add_unique(ChunkStorage::new()); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); world.add_unique(GameSettings::default()); diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..6e1f9a7 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,6 @@ +pub enum GameState { + MainMenu, + Connecting, + LoadingWorld, + InGame +} diff --git a/src/world/loading.rs b/src/world/loading.rs index 27c20cd..dab53df 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -3,7 +3,7 @@ use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload use crate::{player::LocalPlayer, transform::Transform, settings::GameSettings}; use super::{ChunkStorage, chunk::{Chunk, ChunkState, CHUNK_SIZE}, ChunkMeshStorage}; -pub fn load_world_around_player() -> Workload { +pub fn update_loaded_world_around_player() -> Workload { ( update_chunks_if_player_moved, unload_marked_chunks @@ -16,7 +16,8 @@ pub fn update_chunks_if_player_moved( v_transform: View, mut vm_world: UniqueViewMut, ) { - //Check if the player actually moved + //Check if the player actually moved + //TODO fix this also triggers on rotation, only activate when the player crosses the chnk border let Some((_, transform)) = (&v_local_player, v_transform.inserted_or_modified()).iter().next() else { return }; @@ -81,3 +82,9 @@ fn unload_marked_chunks( } }) } + +fn process_tasks( + +) { + +} From 7b5120b1d43b9f6a4f91cbf129d20729e87c539c Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sun, 22 Jan 2023 17:01:54 +0100 Subject: [PATCH 21/81] chunk rendering --- src/camera.rs | 22 ++++++++++--- src/main.rs | 3 +- src/player.rs | 15 ++++++--- src/prefabs.rs | 4 +-- src/rendering.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++--- src/world.rs | 3 ++ 6 files changed, 113 insertions(+), 16 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 3efa0f6..501f720 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,5 +1,6 @@ -use glam::{Mat4, Vec3, Vec3A}; +use glam::{Mat4, Vec3}; use shipyard::{Component, ViewMut, View, IntoIter, Workload, IntoWorkload}; +use std::f32::consts::PI; use crate::transform::Transform; #[derive(Component)] @@ -11,6 +12,20 @@ pub struct Camera { pub z_near: f32, pub z_far: f32, } +impl Camera { + pub fn new(fov: f32, z_near: f32, z_far: f32, up: Vec3) -> Self { + Self { + fov, z_near, z_far, up, + perspective_matrix: Mat4::default(), + view_matrix: Mat4::default(), + } + } +} +impl Default for Camera { + fn default() -> Self { + Self::new(PI / 3., 0.1, 1024., Vec3::Y) + } +} pub fn compute_cameras() -> Workload { ( @@ -31,12 +46,11 @@ fn update_view_matrix( } fn update_perspective_matrix( - mut vm_camera: ViewMut, - v_transform: View + mut vm_camera: ViewMut ) { //todo compute this on win resize! const ASPECT_RATIO: f32 = 9. / 16.; - for (camera, transform) in (&mut vm_camera, &v_transform).iter() { + for camera in (&mut vm_camera).iter() { camera.perspective_matrix = Mat4::perspective_rh_gl( camera.fov, ASPECT_RATIO, diff --git a/src/main.rs b/src/main.rs index 97232f8..64230cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ pub(crate) mod settings; pub(crate) mod state; pub(crate) mod camera; -use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; +use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background, draw_world}; use world::{ChunkStorage, ChunkMeshStorage, loading::update_loaded_world_around_player}; use player::spawn_player; use prefabs::load_prefabs; @@ -47,6 +47,7 @@ fn update() -> Workload { fn render() -> Workload { ( clear_background, + draw_world, ).into_sequential_workload() } diff --git a/src/player.rs b/src/player.rs index 9990f65..822a1df 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,7 +1,9 @@ use glam::Mat4; use shipyard::{Component, EntitiesViewMut, ViewMut}; - -use crate::transform::Transform; +use crate::{ + transform::Transform, + camera::Camera, +}; #[derive(Component)] pub struct LocalPlayer; @@ -13,19 +15,22 @@ pub fn spawn_player ( mut entities: EntitiesViewMut, mut vm_player: ViewMut, mut vm_local_player: ViewMut, - mut vm_transform: ViewMut + mut vm_transform: ViewMut, + mut vm_camera: ViewMut, ) { log::info!("spawning player"); entities.add_entity( ( &mut vm_player, &mut vm_local_player, - &mut vm_transform + &mut vm_transform, + &mut vm_camera, ), ( Player, LocalPlayer, - Transform(Mat4::default()) + Transform(Mat4::default()), + Camera::default() ) ); } diff --git a/src/prefabs.rs b/src/prefabs.rs index b77108e..9d2f3ba 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -51,10 +51,10 @@ impl AssetPaths for BlockTextures { } #[derive(Unique)] -pub struct BlockTexturesPrefab(SrgbTexture2dArray); +pub struct BlockTexturesPrefab(pub SrgbTexture2dArray); #[derive(Unique)] -pub struct ChunkShaderPrefab(Program); +pub struct ChunkShaderPrefab(pub Program); pub fn load_prefabs(world: &World) { let renderer = world.borrow::>>().unwrap(); diff --git a/src/rendering.rs b/src/rendering.rs index ae07223..30480c9 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -1,13 +1,38 @@ -use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut}; +use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut, View, IntoIter}; use glium::{ + Display, Surface, uniform, + DrawParameters, + uniforms::{ + Sampler, + SamplerBehavior, + MinifySamplerFilter, + MagnifySamplerFilter + }, + draw_parameters::{ + Depth, + DepthTest, + PolygonMode, + BackfaceCullingMode, + }, glutin::{ event_loop::EventLoop, window::WindowBuilder, ContextBuilder, GlProfile - }, - Display, Surface, + }, }; use glam::Vec3; +use crate::{ + camera::Camera, + prefabs::{ + ChunkShaderPrefab, + BlockTexturesPrefab, + }, + world::{ + ChunkStorage, + ChunkMeshStorage, + chunk::CHUNK_SIZE, + }, +}; #[derive(Unique)] pub struct RenderTarget(pub glium::Frame); @@ -34,6 +59,55 @@ impl Renderer { } } -pub fn clear_background(mut target: NonSendSync>, color: UniqueView) { +pub fn clear_background( + mut target: NonSendSync>, + color: UniqueView, +) { target.0.clear_color_srgb_and_depth((color.0.x, color.0.y, color.0.z, 1.), 1.); } + +pub fn draw_world( + mut target: NonSendSync>, + chunks: UniqueView, + meshes: NonSendSync>, + program: NonSendSync>, + texture: NonSendSync>, + camera: View, +) { + let camera = camera.iter().next().expect("No cameras in the scene"); + let draw_parameters = DrawParameters { + depth: Depth { + test: DepthTest::IfLess, + write: true, + ..Default::default() + }, + ..Default::default() + }; + let texture_sampler = Sampler(&texture.0, SamplerBehavior { + minify_filter: MinifySamplerFilter::Linear, + magnify_filter: MagnifySamplerFilter::Nearest, + max_anisotropy: 8, + ..Default::default() + }); + let view = camera.view_matrix.to_cols_array_2d(); + let perspective = camera.perspective_matrix.to_cols_array_2d(); + + for (&position, chunk) in &chunks.chunks { + if let Some(key) = chunk.mesh_index { + let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); + let world_position = (position.as_vec3() * CHUNK_SIZE as f32).to_array(); + target.0.draw( + &mesh.vertex_buffer, + &mesh.index_buffer, + &program.0, + &uniform! { + position_offset: world_position, + view: view, + perspective: perspective, + tex: texture_sampler + }, + &draw_parameters + ).unwrap(); + } + } +} diff --git a/src/world.rs b/src/world.rs index 72d19e0..a3d0f5c 100644 --- a/src/world.rs +++ b/src/world.rs @@ -129,4 +129,7 @@ impl ChunkMeshStorage { self.meshes.remove(&key).context("Chunk doesn't exist")?; Ok(()) } + pub fn get(&self, key: usize) -> Option<&ChunkMesh> { + self.meshes.get(&key) + } } From f9a7953dd82d5bb55143c4d2f9b77fb9857902b2 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sun, 22 Jan 2023 21:24:35 +0100 Subject: [PATCH 22/81] Separate chunk neighbor code, WIP tasks --- Cargo.toml | 4 +- src/rendering.rs | 2 + src/world.rs | 76 +------------------------ src/world/chunk.rs | 5 +- src/world/neighbors.rs | 122 +++++++++++++++++++++++++++++++++++++++++ src/world/tasks.rs | 42 ++++++++++++++ 6 files changed, 172 insertions(+), 79 deletions(-) create mode 100644 src/world/neighbors.rs diff --git a/Cargo.toml b/Cargo.toml index a3273a9..833d37b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,6 @@ name = "kubi" version = "0.1.0" edition = "2021" -[profile.dev.package.noise] -opt-level = 3 - [dependencies] glium = "0.32" image = { version = "0.24", default_features = false, features = ["png"] } @@ -19,3 +16,4 @@ rayon = "1.6" shipyard = { version = "0.6", features = ["thread_local"] } nohash-hasher = "0.2.0" anyhow = "1.0" +flume = "0.10" diff --git a/src/rendering.rs b/src/rendering.rs index 30480c9..334a33e 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -81,6 +81,8 @@ pub fn draw_world( write: true, ..Default::default() }, + polygon_mode: PolygonMode::Fill, //Change to Line for wireframe + backface_culling: BackfaceCullingMode::CullCounterClockwise, ..Default::default() }; let texture_sampler = Sampler(&texture.0, SamplerBehavior { diff --git a/src/world.rs b/src/world.rs index a3d0f5c..f194a3c 100644 --- a/src/world.rs +++ b/src/world.rs @@ -10,52 +10,14 @@ pub mod render; pub mod tasks; pub mod loading; pub mod mesh; +pub mod neighbors; use chunk::{Chunk, ChunkMesh}; //TODO separate world struct for render data // because this is not send-sync -pub struct AllChunksNeighbors<'a> { - pub center: &'a Chunk, - pub top: &'a Chunk, - pub bottom: &'a Chunk, - pub left: &'a Chunk, - pub right: &'a Chunk, - pub front: &'a Chunk, - pub back: &'a Chunk, -} -pub struct AllChunksNeighborsMut<'a> { - pub center: &'a mut Chunk, - pub top: &'a mut Chunk, - pub bottom: &'a mut Chunk, - pub left: &'a mut Chunk, - pub right: &'a mut Chunk, - pub front: &'a mut Chunk, - pub back: &'a mut Chunk, -} -pub struct ChunksNeighbors<'a> { - pub center: Option<&'a Chunk>, - pub top: Option<&'a Chunk>, - pub bottom: Option<&'a Chunk>, - pub left: Option<&'a Chunk>, - pub right: Option<&'a Chunk>, - pub front: Option<&'a Chunk>, - pub back: Option<&'a Chunk>, -} -impl<'a> ChunksNeighbors<'a> { - pub fn all(&self) -> Option> { - Some(AllChunksNeighbors { - center: self.center?, - top: self.top?, - bottom: self.bottom?, - left: self.left?, - right: self.right?, - front: self.front?, - back: self.back?, - }) - } -} + #[derive(Default, Unique)] #[track(Modification)] @@ -66,40 +28,6 @@ impl ChunkStorage { pub fn new() -> Self { Self::default() } - pub fn neighbors(&self, coords: IVec3) -> ChunksNeighbors { - ChunksNeighbors { - center: self.chunks.get(&coords), - top: self.chunks.get(&(coords - ivec3(0, 1, 0))), - bottom: self.chunks.get(&(coords + ivec3(0, 1, 0))), - left: self.chunks.get(&(coords - ivec3(1, 0, 0))), - right: self.chunks.get(&(coords + ivec3(1, 0, 0))), - front: self.chunks.get(&(coords - ivec3(0, 0, 1))), - back: self.chunks.get(&(coords + ivec3(0, 0, 1))), - } - } - pub fn neighbors_all(&self, coords: IVec3) -> Option { - self.neighbors(coords).all() - } - pub fn neighbors_all_mut(&mut self, coords: IVec3) -> Option { - let mut refs = self.chunks.get_many_mut([ - &coords, - &(coords - ivec3(0, 1, 0)), - &(coords + ivec3(0, 1, 0)), - &(coords - ivec3(1, 0, 0)), - &(coords + ivec3(1, 0, 0)), - &(coords - ivec3(0, 0, 1)), - &(coords + ivec3(0, 0, 1)), - ])?.map(Some); - Some(AllChunksNeighborsMut { - center: std::mem::take(&mut refs[0]).unwrap(), - top: std::mem::take(&mut refs[1]).unwrap(), - bottom: std::mem::take(&mut refs[2]).unwrap(), - left: std::mem::take(&mut refs[3]).unwrap(), - right: std::mem::take(&mut refs[4]).unwrap(), - front: std::mem::take(&mut refs[5]).unwrap(), - back: std::mem::take(&mut refs[6]).unwrap(), - }) - } } diff --git a/src/world/chunk.rs b/src/world/chunk.rs index f99989c..cb4a134 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -4,9 +4,10 @@ use super::{block::Block, render::ChunkVertex}; pub const CHUNK_SIZE: usize = 32; -type ChunkBlockData = Box<[[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]>; +pub type BlockData = Box<[[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]>; + pub struct ChunkData { - pub blocks: ChunkBlockData, + pub blocks: BlockData, pub has_renderable_blocks: bool, } impl ChunkData { diff --git a/src/world/neighbors.rs b/src/world/neighbors.rs new file mode 100644 index 0000000..3943e14 --- /dev/null +++ b/src/world/neighbors.rs @@ -0,0 +1,122 @@ +use glam::{IVec3, ivec3}; +use super::chunk::Chunk; + +#[derive(Clone, Copy)] +pub struct ChunkNeighbors<'a> { + pub center: Option<&'a Chunk>, + pub top: Option<&'a Chunk>, + pub bottom: Option<&'a Chunk>, + pub left: Option<&'a Chunk>, + pub right: Option<&'a Chunk>, + pub front: Option<&'a Chunk>, + pub back: Option<&'a Chunk>, +} +#[derive(Clone, Copy)] +pub struct AllChunkNeighbors<'a> { + pub center: &'a Chunk, + pub top: &'a Chunk, + pub bottom: &'a Chunk, + pub left: &'a Chunk, + pub right: &'a Chunk, + pub front: &'a Chunk, + pub back: &'a Chunk, +} +pub struct AllChunkNeighborsMut<'a> { + pub center: &'a mut Chunk, + pub top: &'a mut Chunk, + pub bottom: &'a mut Chunk, + pub left: &'a mut Chunk, + pub right: &'a mut Chunk, + pub front: &'a mut Chunk, + pub back: &'a mut Chunk, +} + +impl<'a> ChunkNeighbors<'a> { + pub fn all(&self) -> Option> { + Some(AllChunkNeighbors { + center: self.center?, + top: self.top?, + bottom: self.bottom?, + left: self.left?, + right: self.right?, + front: self.front?, + back: self.back?, + }) + } +} +impl<'a> From> for AllChunkNeighbors<'a> { + fn from(neighbors: AllChunkNeighborsMut<'a>) -> Self { + AllChunkNeighbors { + center: neighbors.center, + top: neighbors.top, + bottom: neighbors.bottom, + left: neighbors.left, + right: neighbors.right, + front: neighbors.front, + back: neighbors.back, + } + } +} +impl<'a> From> for ChunkNeighbors<'a> { + fn from(neighbors: AllChunkNeighbors<'a>) -> Self { + ChunkNeighbors { + center: Some(neighbors.center), + top: Some(neighbors.top), + bottom: Some(neighbors.bottom), + left: Some(neighbors.left), + right: Some(neighbors.right), + front: Some(neighbors.front), + back: Some(neighbors.back), + } + } +} +impl<'a> From> for ChunkNeighbors<'a> { + fn from(neighbors: AllChunkNeighborsMut<'a>) -> Self { + ChunkNeighbors { + center: Some(neighbors.center), + top: Some(neighbors.top), + bottom: Some(neighbors.bottom), + left: Some(neighbors.left), + right: Some(neighbors.right), + front: Some(neighbors.front), + back: Some(neighbors.back), + } + } +} + +impl super::ChunkStorage { + pub fn neighbors(&self, coords: IVec3) -> ChunkNeighbors { + ChunkNeighbors { + center: self.chunks.get(&coords), + top: self.chunks.get(&(coords - ivec3(0, 1, 0))), + bottom: self.chunks.get(&(coords + ivec3(0, 1, 0))), + left: self.chunks.get(&(coords - ivec3(1, 0, 0))), + right: self.chunks.get(&(coords + ivec3(1, 0, 0))), + front: self.chunks.get(&(coords - ivec3(0, 0, 1))), + back: self.chunks.get(&(coords + ivec3(0, 0, 1))), + } + } + pub fn neighbors_all(&self, coords: IVec3) -> Option { + self.neighbors(coords).all() + } + pub fn neighbors_all_mut(&mut self, coords: IVec3) -> Option { + let mut refs = self.chunks.get_many_mut([ + &coords, + &(coords - ivec3(0, 1, 0)), + &(coords + ivec3(0, 1, 0)), + &(coords - ivec3(1, 0, 0)), + &(coords + ivec3(1, 0, 0)), + &(coords - ivec3(0, 0, 1)), + &(coords + ivec3(0, 0, 1)), + ])?.map(Some); + Some(AllChunkNeighborsMut { + center: std::mem::take(&mut refs[0]).unwrap(), + top: std::mem::take(&mut refs[1]).unwrap(), + bottom: std::mem::take(&mut refs[2]).unwrap(), + left: std::mem::take(&mut refs[3]).unwrap(), + right: std::mem::take(&mut refs[4]).unwrap(), + front: std::mem::take(&mut refs[5]).unwrap(), + back: std::mem::take(&mut refs[6]).unwrap(), + }) + } +} diff --git a/src/world/tasks.rs b/src/world/tasks.rs index e69de29..828847b 100644 --- a/src/world/tasks.rs +++ b/src/world/tasks.rs @@ -0,0 +1,42 @@ +use flume::{Sender, Receiver}; +use glam::IVec3; +use super::{ + chunk::BlockData, + render::ChunkVertex +}; + +pub enum ChunkTask { + LoadChunk { + position: IVec3 + }, + GenerateMesh { + position: IVec3, + + } +} + +pub enum ChunkTaskResponse { + LoadedChunk { + position: IVec3, + chunk_data: BlockData, + }, + GeneratedMesh { + position: IVec3, + vertices: Vec, + indexes: Vec + }, +} + +pub struct ChunkTaskManager { + channel: (Sender, Receiver), +} +impl ChunkTaskManager { + pub fn new() -> Self { + Self { + channel: flume::bounded::(0), + } + } + pub fn spawn_task() { + + } +} From 5f06c8527908100330666c025ef5806ee0f51cae Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sun, 22 Jan 2023 22:09:37 +0100 Subject: [PATCH 23/81] change neighbors to a right handed system --- src/world/neighbors.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/world/neighbors.rs b/src/world/neighbors.rs index 3943e14..5151bce 100644 --- a/src/world/neighbors.rs +++ b/src/world/neighbors.rs @@ -92,31 +92,31 @@ impl super::ChunkStorage { bottom: self.chunks.get(&(coords + ivec3(0, 1, 0))), left: self.chunks.get(&(coords - ivec3(1, 0, 0))), right: self.chunks.get(&(coords + ivec3(1, 0, 0))), - front: self.chunks.get(&(coords - ivec3(0, 0, 1))), - back: self.chunks.get(&(coords + ivec3(0, 0, 1))), + front: self.chunks.get(&(coords + ivec3(0, 0, 1))), + back: self.chunks.get(&(coords - ivec3(0, 0, 1))), } } pub fn neighbors_all(&self, coords: IVec3) -> Option { self.neighbors(coords).all() } pub fn neighbors_all_mut(&mut self, coords: IVec3) -> Option { - let mut refs = self.chunks.get_many_mut([ + let [ + center, + top, + bottom, + left, + right, + front, + back + ] = self.chunks.get_many_mut([ &coords, &(coords - ivec3(0, 1, 0)), &(coords + ivec3(0, 1, 0)), &(coords - ivec3(1, 0, 0)), &(coords + ivec3(1, 0, 0)), - &(coords - ivec3(0, 0, 1)), &(coords + ivec3(0, 0, 1)), - ])?.map(Some); - Some(AllChunkNeighborsMut { - center: std::mem::take(&mut refs[0]).unwrap(), - top: std::mem::take(&mut refs[1]).unwrap(), - bottom: std::mem::take(&mut refs[2]).unwrap(), - left: std::mem::take(&mut refs[3]).unwrap(), - right: std::mem::take(&mut refs[4]).unwrap(), - front: std::mem::take(&mut refs[5]).unwrap(), - back: std::mem::take(&mut refs[6]).unwrap(), - }) + &(coords - ivec3(0, 0, 1)), + ])?; + Some(AllChunkNeighborsMut { center, top, bottom, left, right, front, back }) } } From 8f1821a8f5bc857a957b28a8028a6950ef37516a Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sun, 22 Jan 2023 22:31:16 +0100 Subject: [PATCH 24/81] add mipmaps and spcify wrap function on sampler --- src/prefabs.rs | 5 +++-- src/prefabs/texture.rs | 7 ++++--- src/rendering.rs | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/prefabs.rs b/src/prefabs.rs index 9d2f3ba..f215f50 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -1,5 +1,5 @@ use shipyard::{World, NonSendSync, UniqueView, Unique}; -use glium::{texture::SrgbTexture2dArray, Program}; +use glium::{texture::{SrgbTexture2dArray, MipmapsOption}, Program}; use strum::EnumIter; use crate::rendering::Renderer; @@ -61,7 +61,8 @@ pub fn load_prefabs(world: &World) { world.add_unique_non_send_sync(BlockTexturesPrefab( load_texture2darray_prefab::( "./assets/blocks/".into(), - &renderer.display + &renderer.display, + MipmapsOption::AutoGeneratedMipmaps ) )); world.add_unique_non_send_sync(ChunkShaderPrefab( diff --git a/src/prefabs/texture.rs b/src/prefabs/texture.rs index bb1415d..cf2ae4c 100644 --- a/src/prefabs/texture.rs +++ b/src/prefabs/texture.rs @@ -1,7 +1,7 @@ use strum::IntoEnumIterator; use rayon::prelude::*; use std::{fs::File, path::PathBuf, io::BufReader}; -use glium::{texture::{SrgbTexture2dArray, RawImage2d}, backend::Facade}; +use glium::{texture::{SrgbTexture2dArray, RawImage2d, MipmapsOption}, backend::Facade}; use super::AssetPaths; pub fn load_texture2darray_prefab< @@ -9,7 +9,8 @@ pub fn load_texture2darray_prefab< E: Facade >( directory: PathBuf, - facade: &E + facade: &E, + mipmaps: MipmapsOption, ) -> SrgbTexture2dArray { log::info!("↓↓↓ loading textures {} ↓↓↓", directory.as_os_str().to_str().unwrap()); //Load raw images @@ -38,6 +39,6 @@ pub fn load_texture2darray_prefab< }).collect(); log::info!("done loading texture files, uploading to the gpu"); //Upload images to the GPU - SrgbTexture2dArray::new(facade, raw_images) + SrgbTexture2dArray::with_mipmaps(facade, raw_images, mipmaps) .expect("Failed to upload texture array to GPU") } diff --git a/src/rendering.rs b/src/rendering.rs index 334a33e..d20bde5 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -6,7 +6,8 @@ use glium::{ Sampler, SamplerBehavior, MinifySamplerFilter, - MagnifySamplerFilter + MagnifySamplerFilter, + SamplerWrapFunction }, draw_parameters::{ Depth, @@ -89,6 +90,7 @@ pub fn draw_world( minify_filter: MinifySamplerFilter::Linear, magnify_filter: MagnifySamplerFilter::Nearest, max_anisotropy: 8, + wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp), ..Default::default() }); let view = camera.view_matrix.to_cols_array_2d(); From ee55ef2d2a409390fe9167b5fd4c5cea90b07e95 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 00:16:58 +0100 Subject: [PATCH 25/81] some refactoring, worldgen tasks and more (i forgor :skull:) --- src/main.rs | 4 +-- src/rendering.rs | 79 ++-------------------------------------- src/world.rs | 7 ++-- src/world/mesh.rs | 2 ++ src/world/mesh/data.rs | 34 ++++++++++++++++++ src/world/render.rs | 82 +++++++++++++++++++++++++++++++++++++++++- src/world/tasks.rs | 23 +++++++++--- src/world/worldgen.rs | 12 +++++++ 8 files changed, 156 insertions(+), 87 deletions(-) create mode 100644 src/world/mesh/data.rs create mode 100644 src/world/worldgen.rs diff --git a/src/main.rs b/src/main.rs index 64230cb..e474530 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,8 +23,8 @@ pub(crate) mod settings; pub(crate) mod state; pub(crate) mod camera; -use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background, draw_world}; -use world::{ChunkStorage, ChunkMeshStorage, loading::update_loaded_world_around_player}; +use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; +use world::{ChunkStorage, ChunkMeshStorage, loading::update_loaded_world_around_player, render::draw_world}; use player::spawn_player; use prefabs::load_prefabs; use settings::GameSettings; diff --git a/src/rendering.rs b/src/rendering.rs index d20bde5..2bf0517 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -1,20 +1,6 @@ -use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut, View, IntoIter}; +use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut}; use glium::{ - Display, Surface, uniform, - DrawParameters, - uniforms::{ - Sampler, - SamplerBehavior, - MinifySamplerFilter, - MagnifySamplerFilter, - SamplerWrapFunction - }, - draw_parameters::{ - Depth, - DepthTest, - PolygonMode, - BackfaceCullingMode, - }, + Display, Surface, glutin::{ event_loop::EventLoop, window::WindowBuilder, @@ -22,18 +8,6 @@ use glium::{ }, }; use glam::Vec3; -use crate::{ - camera::Camera, - prefabs::{ - ChunkShaderPrefab, - BlockTexturesPrefab, - }, - world::{ - ChunkStorage, - ChunkMeshStorage, - chunk::CHUNK_SIZE, - }, -}; #[derive(Unique)] pub struct RenderTarget(pub glium::Frame); @@ -66,52 +40,3 @@ pub fn clear_background( ) { target.0.clear_color_srgb_and_depth((color.0.x, color.0.y, color.0.z, 1.), 1.); } - -pub fn draw_world( - mut target: NonSendSync>, - chunks: UniqueView, - meshes: NonSendSync>, - program: NonSendSync>, - texture: NonSendSync>, - camera: View, -) { - let camera = camera.iter().next().expect("No cameras in the scene"); - let draw_parameters = DrawParameters { - depth: Depth { - test: DepthTest::IfLess, - write: true, - ..Default::default() - }, - polygon_mode: PolygonMode::Fill, //Change to Line for wireframe - backface_culling: BackfaceCullingMode::CullCounterClockwise, - ..Default::default() - }; - let texture_sampler = Sampler(&texture.0, SamplerBehavior { - minify_filter: MinifySamplerFilter::Linear, - magnify_filter: MagnifySamplerFilter::Nearest, - max_anisotropy: 8, - wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp), - ..Default::default() - }); - let view = camera.view_matrix.to_cols_array_2d(); - let perspective = camera.perspective_matrix.to_cols_array_2d(); - - for (&position, chunk) in &chunks.chunks { - if let Some(key) = chunk.mesh_index { - let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); - let world_position = (position.as_vec3() * CHUNK_SIZE as f32).to_array(); - target.0.draw( - &mesh.vertex_buffer, - &mesh.index_buffer, - &program.0, - &uniform! { - position_offset: world_position, - view: view, - perspective: perspective, - tex: texture_sampler - }, - &draw_parameters - ).unwrap(); - } - } -} diff --git a/src/world.rs b/src/world.rs index f194a3c..349dc79 100644 --- a/src/world.rs +++ b/src/world.rs @@ -11,14 +11,13 @@ pub mod tasks; pub mod loading; pub mod mesh; pub mod neighbors; +pub mod worldgen; use chunk::{Chunk, ChunkMesh}; //TODO separate world struct for render data // because this is not send-sync - - #[derive(Default, Unique)] #[track(Modification)] pub struct ChunkStorage { @@ -30,6 +29,10 @@ impl ChunkStorage { } } +#[derive(Unique)] +pub struct WorldInfo { + pub seed: u32, +} #[derive(Default, Unique)] pub struct ChunkMeshStorage { diff --git a/src/world/mesh.rs b/src/world/mesh.rs index e69de29..ae5a6cd 100644 --- a/src/world/mesh.rs +++ b/src/world/mesh.rs @@ -0,0 +1,2 @@ +pub mod data; +use data::MeshGenData; diff --git a/src/world/mesh/data.rs b/src/world/mesh/data.rs new file mode 100644 index 0000000..403d1d4 --- /dev/null +++ b/src/world/mesh/data.rs @@ -0,0 +1,34 @@ +use crate::world::{ + neighbors::AllChunkNeighbors, + chunk::BlockData +}; + +pub struct MeshGenData { + pub block_data: BlockData, + pub block_data_pos_z: BlockData, + pub block_data_neg_z: BlockData, + pub block_data_pos_y: BlockData, + pub block_data_neg_y: BlockData, + pub block_data_pos_x: BlockData, + pub block_data_neg_x: BlockData, +} +impl<'a> AllChunkNeighbors<'a> { + pub fn mesh_data(&self) -> Option { + let center_block_data = self.center.block_data.as_ref()?; + let front_block_data = self.front.block_data.as_ref()?; + let back_block_data = self.back.block_data.as_ref()?; + let top_block_data = self.top.block_data.as_ref()?; + let bottom_block_data = self.bottom.block_data.as_ref()?; + let right_block_data = self.right.block_data.as_ref()?; + let left_block_data = self.left.block_data.as_ref()?; + Some(MeshGenData { + block_data: center_block_data.blocks.clone(), + block_data_pos_z: front_block_data.blocks.clone(), + block_data_neg_z: back_block_data.blocks.clone(), + block_data_pos_y: top_block_data.blocks.clone(), + block_data_neg_y: bottom_block_data.blocks.clone(), + block_data_pos_x: right_block_data.blocks.clone(), + block_data_neg_x: left_block_data.blocks.clone(), + }) + } +} diff --git a/src/world/render.rs b/src/world/render.rs index 9ae11b1..23fbbda 100644 --- a/src/world/render.rs +++ b/src/world/render.rs @@ -1,4 +1,34 @@ -use glium::implement_vertex; +use shipyard::{NonSendSync, UniqueView, UniqueViewMut, View, IntoIter}; +use glium::{ + implement_vertex, uniform, + Surface, DrawParameters, + uniforms::{ + Sampler, + SamplerBehavior, + MinifySamplerFilter, + MagnifySamplerFilter, + SamplerWrapFunction + }, + draw_parameters::{ + Depth, + DepthTest, + PolygonMode, + BackfaceCullingMode, + } +}; +use crate::{ + camera::Camera, + rendering::RenderTarget, + prefabs::{ + ChunkShaderPrefab, + BlockTexturesPrefab, + }, + world::{ + ChunkStorage, + ChunkMeshStorage, + chunk::CHUNK_SIZE, + }, +}; #[derive(Clone, Copy)] pub struct ChunkVertex { @@ -8,3 +38,53 @@ pub struct ChunkVertex { pub tex_index: u8, } implement_vertex!(ChunkVertex, position, normal, uv, tex_index); + + +pub fn draw_world( + mut target: NonSendSync>, + chunks: UniqueView, + meshes: NonSendSync>, + program: NonSendSync>, + texture: NonSendSync>, + camera: View, +) { + let camera = camera.iter().next().expect("No cameras in the scene"); + let draw_parameters = DrawParameters { + depth: Depth { + test: DepthTest::IfLess, + write: true, + ..Default::default() + }, + polygon_mode: PolygonMode::Fill, //Change to Line for wireframe + backface_culling: BackfaceCullingMode::CullCounterClockwise, + ..Default::default() + }; + let texture_sampler = Sampler(&texture.0, SamplerBehavior { + minify_filter: MinifySamplerFilter::Linear, + magnify_filter: MagnifySamplerFilter::Nearest, + max_anisotropy: 8, + wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp), + ..Default::default() + }); + let view = camera.view_matrix.to_cols_array_2d(); + let perspective = camera.perspective_matrix.to_cols_array_2d(); + + for (&position, chunk) in &chunks.chunks { + if let Some(key) = chunk.mesh_index { + let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); + let world_position = (position.as_vec3() * CHUNK_SIZE as f32).to_array(); + target.0.draw( + &mesh.vertex_buffer, + &mesh.index_buffer, + &program.0, + &uniform! { + position_offset: world_position, + view: view, + perspective: perspective, + tex: texture_sampler + }, + &draw_parameters + ).unwrap(); + } + } +} diff --git a/src/world/tasks.rs b/src/world/tasks.rs index 828847b..e2f1263 100644 --- a/src/world/tasks.rs +++ b/src/world/tasks.rs @@ -2,19 +2,21 @@ use flume::{Sender, Receiver}; use glam::IVec3; use super::{ chunk::BlockData, - render::ChunkVertex + render::ChunkVertex, + mesh::data::MeshGenData, + worldgen::generate_world, }; pub enum ChunkTask { LoadChunk { + seed: u32, position: IVec3 }, GenerateMesh { position: IVec3, - + data: MeshGenData } } - pub enum ChunkTaskResponse { LoadedChunk { position: IVec3, @@ -36,7 +38,18 @@ impl ChunkTaskManager { channel: flume::bounded::(0), } } - pub fn spawn_task() { - + pub fn spawn_task(&self, task: ChunkTask) { + let sender = self.channel.0.clone(); + rayon::spawn(move || { + sender.send(match task { + ChunkTask::GenerateMesh { position, data } => { + todo!() + }, + ChunkTask::LoadChunk { position, seed } => { + let chunk_data = generate_world(position, seed); + ChunkTaskResponse::LoadedChunk { position, chunk_data } + } + }); + }); } } diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs new file mode 100644 index 0000000..3a58dc7 --- /dev/null +++ b/src/world/worldgen.rs @@ -0,0 +1,12 @@ +use glam::IVec3; +use super::{ + chunk::{BlockData, CHUNK_SIZE}, + block::Block +}; + +pub fn generate_world(position: IVec3, seed: u32) -> BlockData { + let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); + blocks[0][0][0] = Block::Stone; + //TODO actual world generation + blocks +} From 38c0bfa9d1111d600b656d42090b35d55307b309 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 02:34:25 +0100 Subject: [PATCH 26/81] hacky shit but it works --- src/main.rs | 6 +- src/state.rs | 6 -- src/world.rs | 11 +++- src/world/chunk.rs | 33 +++++++---- src/world/loading.rs | 127 +++++++++++++++++++++++++++++++++++++++---- src/world/mesh.rs | 41 ++++++++++++++ src/world/tasks.rs | 9 ++- 7 files changed, 195 insertions(+), 38 deletions(-) delete mode 100644 src/state.rs diff --git a/src/main.rs b/src/main.rs index e474530..d272559 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,11 +20,10 @@ pub(crate) mod player; pub(crate) mod prefabs; pub(crate) mod transform; pub(crate) mod settings; -pub(crate) mod state; pub(crate) mod camera; use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; -use world::{ChunkStorage, ChunkMeshStorage, loading::update_loaded_world_around_player, render::draw_world}; +use world::{loading::update_loaded_world_around_player, render::draw_world, init_world}; use player::spawn_player; use prefabs::load_prefabs; use settings::GameSettings; @@ -62,12 +61,11 @@ fn main() { //Add systems and uniques, Init and load things world.add_unique_non_send_sync(Renderer::init(&event_loop)); - world.add_unique_non_send_sync(ChunkMeshStorage::new()); - world.add_unique(ChunkStorage::new()); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); world.add_unique(GameSettings::default()); load_prefabs(&world); + init_world(&world); //Register workloads world.add_workload(startup); diff --git a/src/state.rs b/src/state.rs deleted file mode 100644 index 6e1f9a7..0000000 --- a/src/state.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub enum GameState { - MainMenu, - Connecting, - LoadingWorld, - InGame -} diff --git a/src/world.rs b/src/world.rs index 349dc79..a4281e3 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,6 +1,6 @@ use nohash_hasher::BuildNoHashHasher; -use shipyard::Unique; -use glam::{IVec3, ivec3}; +use shipyard::{Unique, World}; +use glam::IVec3; use hashbrown::HashMap; use anyhow::{Result, Context}; @@ -14,6 +14,7 @@ pub mod neighbors; pub mod worldgen; use chunk::{Chunk, ChunkMesh}; +use tasks::ChunkTaskManager; //TODO separate world struct for render data // because this is not send-sync @@ -64,3 +65,9 @@ impl ChunkMeshStorage { self.meshes.get(&key) } } + +pub fn init_world(world: &World) { + world.add_unique_non_send_sync(ChunkMeshStorage::new()); + world.add_unique(ChunkStorage::new()); + world.add_unique(ChunkTaskManager::new()); +} diff --git a/src/world/chunk.rs b/src/world/chunk.rs index cb4a134..20e91e5 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -8,12 +8,12 @@ pub type BlockData = Box<[[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]>; pub struct ChunkData { pub blocks: BlockData, - pub has_renderable_blocks: bool, + //pub has_renderable_blocks: bool, } impl ChunkData { - pub fn update_metadata(&mut self) { - todo!() - } + // pub fn update_metadata(&mut self) { + // todo!() + // } } pub struct ChunkMesh { @@ -22,24 +22,33 @@ pub struct ChunkMesh { pub index_buffer: IndexBuffer, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] -pub enum ChunkState { - ToUnload, //desired only +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub enum CurrentChunkState { #[default] Nothing, - Loading, //current only + Loading, Loaded, - Meshing, //current only + CalculatingMesh, Rendered, - RecalculatingMesh //current only + RecalculatingMesh, + Unloading, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub enum DesiredChunkState { + #[default] + Nothing, + Loaded, + Rendered, + ToUnload, } pub struct Chunk { pub position: IVec3, pub block_data: Option, pub mesh_index: Option, - pub current_state: ChunkState, - pub desired_state: ChunkState, + pub current_state: CurrentChunkState, + pub desired_state: DesiredChunkState, } impl Chunk { pub fn new(position: IVec3) -> Self { diff --git a/src/world/loading.rs b/src/world/loading.rs index dab53df..c2302e3 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -1,12 +1,24 @@ -use glam::ivec3; -use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync}; -use crate::{player::LocalPlayer, transform::Transform, settings::GameSettings}; -use super::{ChunkStorage, chunk::{Chunk, ChunkState, CHUNK_SIZE}, ChunkMeshStorage}; +use glam::{IVec3, ivec3}; +use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType}; +use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync, Nothing}; +use crate::{ + player::LocalPlayer, + transform::Transform, + settings::GameSettings, + rendering::Renderer +}; +use super::{ + ChunkStorage, ChunkMeshStorage, + chunk::{Chunk, DesiredChunkState, CHUNK_SIZE, ChunkMesh, CurrentChunkState, ChunkData}, + tasks::{ChunkTaskManager, ChunkTaskResponse, ChunkTask}, +}; pub fn update_loaded_world_around_player() -> Workload { ( update_chunks_if_player_moved, - unload_marked_chunks + unload_marked_chunks, + start_required_tasks, + process_completed_tasks, ).into_workload() } @@ -31,7 +43,7 @@ pub fn update_chunks_if_player_moved( //Then, mark *ALL* chunks with ToUnload for (_, chunk) in &mut vm_world.chunks { - chunk.desired_state = ChunkState::ToUnload; + chunk.desired_state = DesiredChunkState::ToUnload; } //Then mark chunks that are near to the player @@ -55,8 +67,8 @@ pub fn update_chunks_if_player_moved( } }; let desired = match is_border { - true => ChunkState::Loaded, - false => ChunkState::Rendered, + true => DesiredChunkState::Loaded, + false => DesiredChunkState::Rendered, }; chunk.desired_state = desired; } @@ -72,7 +84,7 @@ fn unload_marked_chunks( return } vm_world.chunks.retain(|_, chunk| { - if chunk.desired_state == ChunkState::ToUnload { + if chunk.desired_state == DesiredChunkState::ToUnload { if let Some(mesh_index) = chunk.mesh_index { vm_meshes.remove(mesh_index).unwrap(); } @@ -83,8 +95,99 @@ fn unload_marked_chunks( }) } -fn process_tasks( - +fn start_required_tasks( + task_manager: UniqueView, + mut world: UniqueViewMut, ) { - + //HACK: cant iterate over chunks.keys() or chunk directly! + let hashmap_keys: Vec = world.chunks.keys().copied().collect(); + for position in hashmap_keys { + let chunk = world.chunks.get(&position).unwrap(); + match chunk.desired_state { + DesiredChunkState::Loaded | DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Nothing => { + //start load task + task_manager.spawn_task(ChunkTask::LoadChunk { + seed: 0xdead_cafe, + position + }); + //Update chunk state + let chunk = world.chunks.get_mut(&position).unwrap(); + chunk.current_state = CurrentChunkState::Loading; + }, + DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Loaded => { + //get needed data + let Some(neighbors) = world.neighbors_all(position) else { + continue + }; + let Some(data) = neighbors.mesh_data() else { + continue + }; + //spawn task + task_manager.spawn_task(ChunkTask::GenerateMesh { data, position }); + //Update chunk state + let chunk = world.chunks.get_mut(&position).unwrap(); + chunk.current_state = CurrentChunkState::CalculatingMesh; + } + _ => () + } + } +} + +fn process_completed_tasks( + task_manager: UniqueView, + mut world: UniqueViewMut, + mut meshes: NonSendSync>, + renderer: NonSendSync> +) { + while let Some(res) = task_manager.receive() { + match res { + ChunkTaskResponse::LoadedChunk { position, chunk_data } => { + //check if chunk exists + let Some(chunk) = world.chunks.get_mut(&position) else { + log::warn!("blocks data discarded: chunk doesn't exist"); + return + }; + + //check if chunk still wants it + if matches!(chunk.desired_state, DesiredChunkState::Loaded | DesiredChunkState::Rendered) { + log::warn!("block data discarded: state undesirable"); + return + } + + //set the block data + chunk.block_data = Some(ChunkData { + blocks: chunk_data + }); + + //update chunk state + chunk.current_state = CurrentChunkState::Loaded; + }, + ChunkTaskResponse::GeneratedMesh { position, vertices, indexes } => { + //check if chunk exists + let Some(chunk) = world.chunks.get_mut(&position) else { + log::warn!("mesh discarded: chunk doesn't exist"); + return + }; + + //check if chunk still wants it + if chunk.desired_state != DesiredChunkState::Rendered { + log::warn!("mesh discarded: state undesirable"); + return + } + + //apply the mesh + let vertex_buffer = VertexBuffer::new(&renderer.display, &vertices).unwrap(); + let index_buffer = IndexBuffer::new(&renderer.display, PrimitiveType::TrianglesList, &indexes).unwrap(); + let mesh_index = meshes.insert(ChunkMesh { + is_dirty: false, + vertex_buffer, + index_buffer, + }); + chunk.mesh_index = Some(mesh_index); + + //update chunk state + chunk.current_state = CurrentChunkState::Rendered; + } + } + } } diff --git a/src/world/mesh.rs b/src/world/mesh.rs index ae5a6cd..6fdcecd 100644 --- a/src/world/mesh.rs +++ b/src/world/mesh.rs @@ -1,2 +1,43 @@ +use strum::{EnumIter, IntoEnumIterator}; +use glam::{Vec3A, vec3a}; + pub mod data; use data::MeshGenData; + +#[repr(usize)] +#[derive(Clone, Copy, Debug, EnumIter)] +pub enum CubeFace { + Top = 0, + Front = 1, + Left = 2, + Right = 3, + Back = 4, + Bottom = 5, +} +const CUBE_FACE_VERTICES: [[Vec3A; 4]; 6] = [ + [vec3a(0., 1., 0.), vec3a(0., 1., 1.), vec3a(1., 1., 0.), vec3a(1., 1., 1.)], + [vec3a(0., 0., 0.), vec3a(0., 1., 0.), vec3a(1., 0., 0.), vec3a(1., 1., 0.)], + [vec3a(0., 0., 1.), vec3a(0., 1., 1.), vec3a(0., 0., 0.), vec3a(0., 1., 0.)], + [vec3a(1., 0., 0.), vec3a(1., 1., 0.), vec3a(1., 0., 1.), vec3a(1., 1., 1.)], + [vec3a(1., 0., 1.), vec3a(1., 1., 1.), vec3a(0., 0., 1.), vec3a(0., 1., 1.)], + [vec3a(0., 0., 1.), vec3a(0., 0., 0.), vec3a(1., 0., 1.), vec3a(1., 0., 0.)], +]; +const CUBE_FACE_NORMALS: [Vec3A; 6] = [ //this is likely incorrect for a right handed system + vec3a(0., 1., 0.), + vec3a(0., 0., 1.), + vec3a(-1.,0., 0.), + vec3a(1., 0., 0.), + vec3a(0., 0., -1.), + vec3a(0., -1.,0.) +]; +const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; +const UV_COORDS: [[f32; 2]; 4] = [ + [0., 0.], + [0., 1.], + [1., 0.], + [1., 1.], +]; + +pub fn generate_mesh(data: MeshGenData) { + +} diff --git a/src/world/tasks.rs b/src/world/tasks.rs index e2f1263..2047d80 100644 --- a/src/world/tasks.rs +++ b/src/world/tasks.rs @@ -1,5 +1,6 @@ use flume::{Sender, Receiver}; use glam::IVec3; +use shipyard::Unique; use super::{ chunk::BlockData, render::ChunkVertex, @@ -29,19 +30,20 @@ pub enum ChunkTaskResponse { }, } +#[derive(Unique)] pub struct ChunkTaskManager { channel: (Sender, Receiver), } impl ChunkTaskManager { pub fn new() -> Self { Self { - channel: flume::bounded::(0), + channel: flume::unbounded::(), //maybe put a bound or even bound(0)? } } pub fn spawn_task(&self, task: ChunkTask) { let sender = self.channel.0.clone(); rayon::spawn(move || { - sender.send(match task { + let _ = sender.send(match task { ChunkTask::GenerateMesh { position, data } => { todo!() }, @@ -52,4 +54,7 @@ impl ChunkTaskManager { }); }); } + pub fn receive(&self) -> Option { + self.channel.1.try_recv().ok() + } } From d290dd8ab82d3cf8b29c79a9d12d6025048774e8 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 02:36:27 +0100 Subject: [PATCH 27/81] add logging --- src/world/loading.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/world/loading.rs b/src/world/loading.rs index c2302e3..6a8b9e5 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -113,6 +113,8 @@ fn start_required_tasks( //Update chunk state let chunk = world.chunks.get_mut(&position).unwrap(); chunk.current_state = CurrentChunkState::Loading; + // =========== + log::info!("Started loading chunk {position}"); }, DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Loaded => { //get needed data @@ -127,6 +129,8 @@ fn start_required_tasks( //Update chunk state let chunk = world.chunks.get_mut(&position).unwrap(); chunk.current_state = CurrentChunkState::CalculatingMesh; + // =========== + log::info!("Started generating mesh for chunk {position}"); } _ => () } From 6f866d2305d77fd9bf9059cd44bb304b4de197eb Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 03:11:48 +0100 Subject: [PATCH 28/81] got something to render... --- shaders/world.vert | 4 +- src/camera.rs | 2 +- src/settings.rs | 2 +- src/world/block.rs | 2 +- src/world/loading.rs | 6 +-- src/world/mesh.rs | 96 ++++++++++++++++++++++++++++++++++++++++++-- src/world/tasks.rs | 5 ++- 7 files changed, 104 insertions(+), 13 deletions(-) diff --git a/shaders/world.vert b/shaders/world.vert index 955ca12..de3d2e7 100644 --- a/shaders/world.vert +++ b/shaders/world.vert @@ -13,7 +13,7 @@ in uint tex_index; out vec2 v_uv; out vec3 v_normal; flat out uint v_tex_index; -uniform vec2 position_offset; +uniform vec3 position_offset; uniform mat4 perspective; uniform mat4 view; @@ -21,5 +21,5 @@ void main() { v_normal = normal; v_tex_index = tex_index; v_uv = uv; - gl_Position = perspective * view * (vec4(position, 1.0) + vec4(position_offset.x, 0., position_offset.y, 0.)); + gl_Position = perspective * view * vec4(position + position_offset, 1.); } diff --git a/src/camera.rs b/src/camera.rs index 501f720..97efee5 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -49,7 +49,7 @@ fn update_perspective_matrix( mut vm_camera: ViewMut ) { //todo compute this on win resize! - const ASPECT_RATIO: f32 = 9. / 16.; + const ASPECT_RATIO: f32 = 16. / 9.; for camera in (&mut vm_camera).iter() { camera.perspective_matrix = Mat4::perspective_rh_gl( camera.fov, diff --git a/src/settings.rs b/src/settings.rs index df9cd49..2ad524c 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -8,7 +8,7 @@ pub struct GameSettings { impl Default for GameSettings { fn default() -> Self { Self { - render_distance: 5 + render_distance: 2 } } } diff --git a/src/world/block.rs b/src/world/block.rs index 3ac2026..ced61a8 100644 --- a/src/world/block.rs +++ b/src/world/block.rs @@ -1,6 +1,6 @@ use strum::EnumIter; -#[derive(Clone, Copy, Debug, EnumIter)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)] #[repr(u8)] pub enum Block { Air, diff --git a/src/world/loading.rs b/src/world/loading.rs index 6a8b9e5..571c3bb 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -153,8 +153,8 @@ fn process_completed_tasks( }; //check if chunk still wants it - if matches!(chunk.desired_state, DesiredChunkState::Loaded | DesiredChunkState::Rendered) { - log::warn!("block data discarded: state undesirable"); + if !matches!(chunk.desired_state, DesiredChunkState::Loaded | DesiredChunkState::Rendered) { + log::warn!("block data discarded: state undesirable: {:?}", chunk.desired_state); return } @@ -175,7 +175,7 @@ fn process_completed_tasks( //check if chunk still wants it if chunk.desired_state != DesiredChunkState::Rendered { - log::warn!("mesh discarded: state undesirable"); + log::warn!("mesh discarded: state undesirable: {:?}", chunk.desired_state); return } diff --git a/src/world/mesh.rs b/src/world/mesh.rs index 6fdcecd..fb5686f 100644 --- a/src/world/mesh.rs +++ b/src/world/mesh.rs @@ -1,5 +1,6 @@ use strum::{EnumIter, IntoEnumIterator}; -use glam::{Vec3A, vec3a}; +use glam::{Vec3A, vec3a, IVec3, ivec3}; +use super::{render::ChunkVertex, chunk::CHUNK_SIZE, block::Block}; pub mod data; use data::MeshGenData; @@ -38,6 +39,95 @@ const UV_COORDS: [[f32; 2]; 4] = [ [1., 1.], ]; -pub fn generate_mesh(data: MeshGenData) { - +#[derive(Default)] +struct MeshBuilder { + vertex_buffer: Vec, + index_buffer: Vec, + idx_counter: u32, +} +impl MeshBuilder { + pub fn new() -> Self { + Self::default() + } + + pub fn add_face(&mut self, face: CubeFace, coord: IVec3, texture: u8) { + let coord = coord.as_vec3a(); + let face_index = face as usize; + + //Push vertexes + let norm = CUBE_FACE_NORMALS[face_index]; + let vert = CUBE_FACE_VERTICES[face_index]; + self.vertex_buffer.reserve(4); + for i in 0..4 { + self.vertex_buffer.push(ChunkVertex { + position: (coord + vert[i]).to_array(), + normal: norm.to_array(), + uv: UV_COORDS[i], + tex_index: texture + }); + } + + //Push indices + self.index_buffer.extend_from_slice(&CUBE_FACE_INDICES.map(|x| x + self.idx_counter)); + self.idx_counter += 4; + } + + pub fn finish(self) -> (Vec, Vec) { + (self.vertex_buffer, self.index_buffer) + } +} + +pub fn generate_mesh(data: MeshGenData) -> (Vec, Vec) { + let get_block = |pos: IVec3| -> Block { + if pos.x < 0 { + data.block_data_neg_x[(CHUNK_SIZE as i32 + pos.x) as usize][pos.y as usize][pos.z as usize] + } else if pos.x >= CHUNK_SIZE as i32 { + data.block_data_pos_x[pos.x as usize - CHUNK_SIZE][pos.y as usize][pos.z as usize] + } else if pos.y < 0 { + data.block_data_neg_y[pos.x as usize][(CHUNK_SIZE as i32 + pos.y) as usize][pos.z as usize] + } else if pos.y >= CHUNK_SIZE as i32 { + data.block_data_pos_y[pos.x as usize][pos.y as usize - CHUNK_SIZE][pos.z as usize] + } else if pos.z < 0 { + data.block_data_neg_z[pos.x as usize][pos.y as usize][(CHUNK_SIZE as i32 + pos.z) as usize] + } else if pos.z >= CHUNK_SIZE as i32 { + data.block_data_pos_z[pos.x as usize][pos.y as usize][pos.z as usize - CHUNK_SIZE] + } else { + data.block_data[pos.x as usize][pos.y as usize][pos.z as usize] + } + }; + + let mut builder = MeshBuilder::new(); + + for x in 0..CHUNK_SIZE { + for y in 0..CHUNK_SIZE { + for z in 0..CHUNK_SIZE { + let coord = ivec3(x as i32, y as i32, z as i32); + let block = get_block(coord); + if block == Block::Air { + continue + } + for face in CubeFace::iter() { + let facing = CUBE_FACE_NORMALS[face as usize].as_ivec3(); + let facing_coord = coord + facing; + let show = { + get_block(facing_coord) == Block::Air + }; + if show { + // let texures = descriptor.render.unwrap().1; + // let block_texture = match face { + // CubeFace::Top => texures.top, + // CubeFace::Front => texures.front, + // CubeFace::Left => texures.left, + // CubeFace::Right => texures.right, + // CubeFace::Back => texures.back, + // CubeFace::Bottom => texures.bottom, + // }; + builder.add_face(face, coord, 0); + } + } + } + } + } + + builder.finish() } diff --git a/src/world/tasks.rs b/src/world/tasks.rs index 2047d80..9b921bc 100644 --- a/src/world/tasks.rs +++ b/src/world/tasks.rs @@ -4,7 +4,7 @@ use shipyard::Unique; use super::{ chunk::BlockData, render::ChunkVertex, - mesh::data::MeshGenData, + mesh::{generate_mesh, data::MeshGenData}, worldgen::generate_world, }; @@ -45,7 +45,8 @@ impl ChunkTaskManager { rayon::spawn(move || { let _ = sender.send(match task { ChunkTask::GenerateMesh { position, data } => { - todo!() + let (vertices, indexes) = generate_mesh(data); + ChunkTaskResponse::GeneratedMesh { position, vertices, indexes } }, ChunkTask::LoadChunk { position, seed } => { let chunk_data = generate_world(position, seed); From 59cdd84fc5e0c1eff43622d15254c8e22bddf4ee Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 03:12:23 +0100 Subject: [PATCH 29/81] Use correct culling? --- src/world/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/render.rs b/src/world/render.rs index 23fbbda..56499db 100644 --- a/src/world/render.rs +++ b/src/world/render.rs @@ -56,7 +56,7 @@ pub fn draw_world( ..Default::default() }, polygon_mode: PolygonMode::Fill, //Change to Line for wireframe - backface_culling: BackfaceCullingMode::CullCounterClockwise, + backface_culling: BackfaceCullingMode::CullClockwise, ..Default::default() }; let texture_sampler = Sampler(&texture.0, SamplerBehavior { From cb428f4c711a0b87ff0ef8bddf37f8f82aca61a9 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 03:13:37 +0100 Subject: [PATCH 30/81] Ooops cleared the frame twice --- src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index d272559..0ac56ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -107,7 +107,6 @@ fn main() { let renderer = world.borrow::>>().unwrap(); renderer.display.draw() }; - target.clear_color_and_depth((0., 0., 0., 1.), 1.); world.add_unique_non_send_sync(RenderTarget(target)); //Run render workflow From ff38faa891375ed3ae15112a59dfe8ce374284f8 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 03:19:26 +0100 Subject: [PATCH 31/81] Remove useless `mut` --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 0ac56ad..aed3a39 100644 --- a/src/main.rs +++ b/src/main.rs @@ -103,7 +103,7 @@ fn main() { world.run_workload(update).unwrap(); //Start rendering (maybe use custom views for this?) - let mut target = { + let target = { let renderer = world.borrow::>>().unwrap(); renderer.display.draw() }; From ecedfc929dbfb129cdbed2e150fe10884035d994 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 03:24:43 +0100 Subject: [PATCH 32/81] spawn L shapes --- src/world/worldgen.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index 3a58dc7..0b100b0 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -7,6 +7,9 @@ use super::{ pub fn generate_world(position: IVec3, seed: u32) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); blocks[0][0][0] = Block::Stone; + blocks[1][0][0] = Block::Stone; + blocks[0][1][0] = Block::Stone; + blocks[0][0][1] = Block::Stone; //TODO actual world generation blocks } From 710bedeaecda91343d0a05c4e2e67ca4e28ac20d Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 03:27:08 +0100 Subject: [PATCH 33/81] swap face normals --- src/world/mesh.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/world/mesh.rs b/src/world/mesh.rs index fb5686f..4074cb8 100644 --- a/src/world/mesh.rs +++ b/src/world/mesh.rs @@ -23,12 +23,12 @@ const CUBE_FACE_VERTICES: [[Vec3A; 4]; 6] = [ [vec3a(1., 0., 1.), vec3a(1., 1., 1.), vec3a(0., 0., 1.), vec3a(0., 1., 1.)], [vec3a(0., 0., 1.), vec3a(0., 0., 0.), vec3a(1., 0., 1.), vec3a(1., 0., 0.)], ]; -const CUBE_FACE_NORMALS: [Vec3A; 6] = [ //this is likely incorrect for a right handed system +const CUBE_FACE_NORMALS: [Vec3A; 6] = [ vec3a(0., 1., 0.), - vec3a(0., 0., 1.), + vec3a(0., 0., -1.), vec3a(-1.,0., 0.), vec3a(1., 0., 0.), - vec3a(0., 0., -1.), + vec3a(0., 0., 1.), vec3a(0., -1.,0.) ]; const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; From 92b0d8972a43708746c99d341a7404b7fa76e311 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 03:41:04 +0100 Subject: [PATCH 34/81] fix warnings --- src/main.rs | 3 +-- src/world/loading.rs | 2 +- src/world/worldgen.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index aed3a39..0ae9e00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use shipyard::{ NonSendSync, Unique }; use glium::{ - Surface, glutin::{ event_loop::{EventLoop, ControlFlow}, event::{Event, WindowEvent} @@ -81,7 +80,7 @@ fn main() { *control_flow = ControlFlow::Poll; match event { Event::WindowEvent { event, .. } => match event { - WindowEvent::Resized(size) => { + WindowEvent::Resized(_size) => { // todo ... } WindowEvent::CloseRequested => { diff --git a/src/world/loading.rs b/src/world/loading.rs index 571c3bb..0e5cbdf 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -1,6 +1,6 @@ use glam::{IVec3, ivec3}; use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType}; -use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync, Nothing}; +use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync}; use crate::{ player::LocalPlayer, transform::Transform, diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index 0b100b0..a3b17c5 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -4,7 +4,7 @@ use super::{ block::Block }; -pub fn generate_world(position: IVec3, seed: u32) -> BlockData { +pub fn generate_world(_position: IVec3, _seed: u32) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); blocks[0][0][0] = Block::Stone; blocks[1][0][0] = Block::Stone; From 68fcb7135d107eb9642b20be807bcf5736dfbc4e Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Mon, 23 Jan 2023 18:46:30 +0100 Subject: [PATCH 35/81] create files --- src/fly_controller.rs | 0 src/input.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/fly_controller.rs create mode 100644 src/input.rs diff --git a/src/fly_controller.rs b/src/fly_controller.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..e69de29 From 567e6d8d8541a89b3b13d5beafc3f510f9221e86 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Tue, 24 Jan 2023 18:58:56 +0100 Subject: [PATCH 36/81] wip input system --- src/input.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 2 ++ 2 files changed, 50 insertions(+) diff --git a/src/input.rs b/src/input.rs index e69de29..a363882 100644 --- a/src/input.rs +++ b/src/input.rs @@ -0,0 +1,48 @@ +use glium::glutin::event::VirtualKeyCode; +use shipyard::{AllStoragesView, Unique}; +use hashbrown::HashMap; +use nohash_hasher::BuildNoHashHasher; + +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +pub enum Action { + Move(f32, f32), + Look(f32, f32), +} + +#[derive(Unique)] +pub struct InputSystem { + pub keyboard_keymap: HashMap>, + mouse_map: Option A>, + keyboard_state: HashMap>, + mouse_delta: (f32, f32), + mouse_position: (f32, f32), +} +impl InputSystem { + pub fn new() -> Self { + Self { + keyboard_keymap: HashMap::with_hasher(BuildNoHashHasher::default()), + mouse_map: None, + keyboard_state: HashMap::with_hasher(BuildNoHashHasher::default()), + mouse_delta: (0., 0.), + mouse_position: (0., 0.), + } + } + pub fn map_to_mouse(&mut self, function: fn(f32, f32) -> A) { + self.mouse_map = Some(function); + } +} + +pub fn setup_input_system( + storages: AllStoragesView +) { + let mut input = InputSystem::new(); + input.keyboard_keymap.extend([ + (VirtualKeyCode::W, Action::Move(0., 1.)), + (VirtualKeyCode::A, Action::Move(-1., 0.)), + (VirtualKeyCode::S, Action::Move(0., -1.)), + (VirtualKeyCode::D, Action::Move(1., 0.)) + ]); + input.map_to_mouse(Action::Look); + storages.add_unique(input); +} diff --git a/src/main.rs b/src/main.rs index 0ae9e00..cf209f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,8 @@ pub(crate) mod prefabs; pub(crate) mod transform; pub(crate) mod settings; pub(crate) mod camera; +pub(crate) mod input; +pub(crate) mod fly_controller; use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; use world::{loading::update_loaded_world_around_player, render::draw_world, init_world}; From 9c802a6e70a3d3bf66acc4007513ae300f1226b6 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Tue, 24 Jan 2023 19:09:41 +0100 Subject: [PATCH 37/81] input system updates --- src/input.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/input.rs b/src/input.rs index a363882..6455f6c 100644 --- a/src/input.rs +++ b/src/input.rs @@ -3,17 +3,20 @@ use shipyard::{AllStoragesView, Unique}; use hashbrown::HashMap; use nohash_hasher::BuildNoHashHasher; -#[repr(u8)] #[derive(Clone, Copy, Debug)] +#[repr(u8)] pub enum Action { Move(f32, f32), Look(f32, f32), } +pub type MouseCallback = fn(x: f32, y: f32) -> A; + #[derive(Unique)] pub struct InputSystem { pub keyboard_keymap: HashMap>, - mouse_map: Option A>, + mouse_map: Option>, + pub mouse_sensitivity: f32, keyboard_state: HashMap>, mouse_delta: (f32, f32), mouse_position: (f32, f32), @@ -23,12 +26,13 @@ impl InputSystem { Self { keyboard_keymap: HashMap::with_hasher(BuildNoHashHasher::default()), mouse_map: None, + mouse_sensitivity: 1., keyboard_state: HashMap::with_hasher(BuildNoHashHasher::default()), mouse_delta: (0., 0.), mouse_position: (0., 0.), } } - pub fn map_to_mouse(&mut self, function: fn(f32, f32) -> A) { + pub fn map_to_mouse(&mut self, function: MouseCallback) { self.mouse_map = Some(function); } } From 8615853debbb10db282a497493fb528a8c01db14 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Tue, 24 Jan 2023 21:10:24 +0100 Subject: [PATCH 38/81] undo input code --- src/input.rs | 48 +----------------------------------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/src/input.rs b/src/input.rs index 6455f6c..1d0736b 100644 --- a/src/input.rs +++ b/src/input.rs @@ -3,50 +3,4 @@ use shipyard::{AllStoragesView, Unique}; use hashbrown::HashMap; use nohash_hasher::BuildNoHashHasher; -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -pub enum Action { - Move(f32, f32), - Look(f32, f32), -} - -pub type MouseCallback = fn(x: f32, y: f32) -> A; - -#[derive(Unique)] -pub struct InputSystem { - pub keyboard_keymap: HashMap>, - mouse_map: Option>, - pub mouse_sensitivity: f32, - keyboard_state: HashMap>, - mouse_delta: (f32, f32), - mouse_position: (f32, f32), -} -impl InputSystem { - pub fn new() -> Self { - Self { - keyboard_keymap: HashMap::with_hasher(BuildNoHashHasher::default()), - mouse_map: None, - mouse_sensitivity: 1., - keyboard_state: HashMap::with_hasher(BuildNoHashHasher::default()), - mouse_delta: (0., 0.), - mouse_position: (0., 0.), - } - } - pub fn map_to_mouse(&mut self, function: MouseCallback) { - self.mouse_map = Some(function); - } -} - -pub fn setup_input_system( - storages: AllStoragesView -) { - let mut input = InputSystem::new(); - input.keyboard_keymap.extend([ - (VirtualKeyCode::W, Action::Move(0., 1.)), - (VirtualKeyCode::A, Action::Move(-1., 0.)), - (VirtualKeyCode::S, Action::Move(0., -1.)), - (VirtualKeyCode::D, Action::Move(1., 0.)) - ]); - input.map_to_mouse(Action::Look); - storages.add_unique(input); -} +//todo From 83f06950e2444da572dd567a664fcbefac03e92a Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Wed, 25 Jan 2023 03:01:44 +0100 Subject: [PATCH 39/81] events and input --- src/events.rs | 55 ++++++++++++++++++++++++++++++++++++ src/input.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 15 +++++++--- src/prefabs.rs | 12 ++++---- src/world.rs | 12 ++++---- 5 files changed, 151 insertions(+), 18 deletions(-) create mode 100644 src/events.rs diff --git a/src/events.rs b/src/events.rs new file mode 100644 index 0000000..bab5db7 --- /dev/null +++ b/src/events.rs @@ -0,0 +1,55 @@ +use glam::UVec2; +use shipyard::{World, Component, AllStoragesViewMut, SparseSet}; +use glium::glutin::event::{Event, DeviceEvent, DeviceId, WindowEvent}; + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct EventComponent; + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct OnBeforeExitEvent; + +#[derive(Component, Clone, Debug)] +pub struct InputDeviceEvent{ + pub device_id: DeviceId, + pub event: DeviceEvent +} + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct WindowResizedEvent(UVec2); + +pub fn process_glutin_events(world: &mut World, event: &Event<'_, ()>) { + #[allow(clippy::collapsible_match, clippy::single_match)] + match event { + Event::WindowEvent { window_id: _, event } => match event { + WindowEvent::Resized(size) => { + world.add_entity(( + EventComponent, + WindowResizedEvent(UVec2::new(size.width as _, size.height as _)) + )); + }, + _ => () + }, + Event::DeviceEvent { device_id, event } => { + world.add_entity(( + EventComponent, + InputDeviceEvent { + device_id: *device_id, + event: event.clone() + } + )); + }, + Event::LoopDestroyed => { + world.add_entity(( + EventComponent, + OnBeforeExitEvent + )); + }, + _ => (), + } +} + +pub fn clear_events( + mut all_storages: AllStoragesViewMut, +) { + all_storages.delete_any::>(); +} diff --git a/src/input.rs b/src/input.rs index 1d0736b..eb5031e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,6 +1,73 @@ -use glium::glutin::event::VirtualKeyCode; -use shipyard::{AllStoragesView, Unique}; -use hashbrown::HashMap; +use glam::{Vec2, DVec2}; +use glium::glutin::event::{DeviceEvent, VirtualKeyCode, ElementState}; +use hashbrown::HashSet; use nohash_hasher::BuildNoHashHasher; +use shipyard::{AllStoragesView, Unique, View, IntoIter, UniqueViewMut, Workload, IntoWorkload, UniqueView}; +use crate::events::InputDeviceEvent; -//todo +#[derive(Unique, Clone, Copy, Default, Debug)] +pub struct Inputs { + pub movement: Vec2, + pub look: Vec2, + pub action_a: bool, + pub action_b: bool, +} + +#[derive(Unique, Clone, Default, Debug)] +pub struct RawInputState { + pub keyboard_state: HashSet>, + pub mouse_delta: DVec2 +} + +pub fn process_events( + device_events: View, + mut input_state: UniqueViewMut, +) { + input_state.mouse_delta = DVec2::ZERO; + for event in device_events.iter() { + match event.event { + DeviceEvent::MouseMotion { delta } => { + input_state.mouse_delta = DVec2::from(delta); + }, + DeviceEvent::Key(input) => { + if let Some(keycode) = input.virtual_keycode { + match input.state { + ElementState::Pressed => input_state.keyboard_state.insert(keycode), + ElementState::Released => input_state.keyboard_state.remove(&keycode), + }; + } + }, + DeviceEvent::Button { button, state } => { + println!("Button {button} {state:?}"); + }, + _ => () + } + } +} + +pub fn update_input_states ( + raw_inputs: UniqueView, + mut inputs: UniqueViewMut, +) { + inputs.movement = Vec2::new( + raw_inputs.keyboard_state.contains(&VirtualKeyCode::D) as u32 as f32 - + raw_inputs.keyboard_state.contains(&VirtualKeyCode::A) as u32 as f32, + raw_inputs.keyboard_state.contains(&VirtualKeyCode::W) as u32 as f32 - + raw_inputs.keyboard_state.contains(&VirtualKeyCode::S) as u32 as f32 + ).normalize_or_zero(); + inputs.look = raw_inputs.mouse_delta.as_vec2(); +} + +pub fn init_input ( + storages: AllStoragesView +) { + storages.add_unique(Inputs::default()); + storages.add_unique(RawInputState::default()); +} + +pub fn process_inputs() -> Workload { + ( + process_events, + update_input_states + ).into_workload() +} diff --git a/src/main.rs b/src/main.rs index cf209f1..d9f3243 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,28 +20,36 @@ pub(crate) mod prefabs; pub(crate) mod transform; pub(crate) mod settings; pub(crate) mod camera; +pub(crate) mod events; pub(crate) mod input; pub(crate) mod fly_controller; use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; -use world::{loading::update_loaded_world_around_player, render::draw_world, init_world}; +use world::{loading::update_loaded_world_around_player, render::draw_world, init_game_world}; use player::spawn_player; use prefabs::load_prefabs; use settings::GameSettings; use camera::compute_cameras; +use events::{clear_events, process_glutin_events}; +use input::{init_input, process_inputs}; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); fn startup() -> Workload { ( + load_prefabs, + init_input, + init_game_world, spawn_player, ).into_workload() } fn update() -> Workload { ( + process_inputs, update_loaded_world_around_player, compute_cameras, + clear_events ).into_workload() } fn render() -> Workload { @@ -58,15 +66,13 @@ fn main() { let event_loop = EventLoop::new(); //Create a shipyard world - let world = World::new(); + let mut world = World::new(); //Add systems and uniques, Init and load things world.add_unique_non_send_sync(Renderer::init(&event_loop)); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); world.add_unique(DeltaTime(Duration::default())); world.add_unique(GameSettings::default()); - load_prefabs(&world); - init_world(&world); //Register workloads world.add_workload(startup); @@ -80,6 +86,7 @@ fn main() { let mut last_update = Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; + process_glutin_events(&mut world, &event); match event { Event::WindowEvent { event, .. } => match event { WindowEvent::Resized(_size) => { diff --git a/src/prefabs.rs b/src/prefabs.rs index f215f50..6043bcf 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -1,4 +1,4 @@ -use shipyard::{World, NonSendSync, UniqueView, Unique}; +use shipyard::{NonSendSync, UniqueView, Unique, AllStoragesView}; use glium::{texture::{SrgbTexture2dArray, MipmapsOption}, Program}; use strum::EnumIter; use crate::rendering::Renderer; @@ -56,16 +56,18 @@ pub struct BlockTexturesPrefab(pub SrgbTexture2dArray); #[derive(Unique)] pub struct ChunkShaderPrefab(pub Program); -pub fn load_prefabs(world: &World) { - let renderer = world.borrow::>>().unwrap(); - world.add_unique_non_send_sync(BlockTexturesPrefab( +pub fn load_prefabs( + storages: AllStoragesView, + renderer: NonSendSync> +) { + storages.add_unique_non_send_sync(BlockTexturesPrefab( load_texture2darray_prefab::( "./assets/blocks/".into(), &renderer.display, MipmapsOption::AutoGeneratedMipmaps ) )); - world.add_unique_non_send_sync(ChunkShaderPrefab( + storages.add_unique_non_send_sync(ChunkShaderPrefab( include_shader_prefab!( "../shaders/world.vert", "../shaders/world.frag", diff --git a/src/world.rs b/src/world.rs index a4281e3..2f3ace1 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,5 +1,5 @@ use nohash_hasher::BuildNoHashHasher; -use shipyard::{Unique, World}; +use shipyard::{Unique, AllStoragesView}; use glam::IVec3; use hashbrown::HashMap; use anyhow::{Result, Context}; @@ -66,8 +66,10 @@ impl ChunkMeshStorage { } } -pub fn init_world(world: &World) { - world.add_unique_non_send_sync(ChunkMeshStorage::new()); - world.add_unique(ChunkStorage::new()); - world.add_unique(ChunkTaskManager::new()); +pub fn init_game_world( + storages: AllStoragesView, +) { + storages.add_unique_non_send_sync(ChunkMeshStorage::new()); + storages.add_unique(ChunkStorage::new()); + storages.add_unique(ChunkTaskManager::new()); } From e68e0b39e3ae7c670ed65420bbf8e3855944825e Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Wed, 25 Jan 2023 03:36:24 +0100 Subject: [PATCH 40/81] testing --- src/fly_controller.rs | 18 ++++++++++++++++++ src/main.rs | 14 ++++++++++++-- src/player.rs | 14 ++++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/fly_controller.rs b/src/fly_controller.rs index e69de29..09921a7 100644 --- a/src/fly_controller.rs +++ b/src/fly_controller.rs @@ -0,0 +1,18 @@ +use glam::{Mat4, EulerRot, Quat}; +use shipyard::{Component, View, ViewMut, IntoIter, UniqueView}; +use crate::{transform::Transform, input::Inputs}; + +#[derive(Component)] +pub struct FlyController; + +pub fn update_controllers( + controllers: View, + mut transforms: ViewMut, + inputs: UniqueView +) { + for (_, mut transform) in (&controllers, &mut transforms).iter() { + let (scale, mut rotation, translation) = transform.0.to_scale_rotation_translation(); + rotation *= Quat::from_euler(EulerRot::XYZ, 0., 0.001, 0.); + transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); + } +} diff --git a/src/main.rs b/src/main.rs index d9f3243..e4cec44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ use settings::GameSettings; use camera::compute_cameras; use events::{clear_events, process_glutin_events}; use input::{init_input, process_inputs}; +use fly_controller::update_controllers; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); @@ -47,9 +48,9 @@ fn startup() -> Workload { fn update() -> Workload { ( process_inputs, + update_controllers, update_loaded_world_around_player, - compute_cameras, - clear_events + compute_cameras ).into_workload() } fn render() -> Workload { @@ -58,6 +59,11 @@ fn render() -> Workload { draw_world, ).into_sequential_workload() } +fn after_frame_end() -> Workload { + ( + clear_events, + ).into_workload() +} fn main() { logging::init(); @@ -78,6 +84,7 @@ fn main() { world.add_workload(startup); world.add_workload(update); world.add_workload(render); + world.add_workload(after_frame_end); //Run startup systems world.run_workload(startup).unwrap(); @@ -123,6 +130,9 @@ fn main() { //Finish rendering let target = world.remove_unique::().unwrap(); target.0.finish().unwrap(); + + //FrameEnd + world.run_workload(after_frame_end).unwrap(); }, _ => (), }; diff --git a/src/player.rs b/src/player.rs index 822a1df..88ce652 100644 --- a/src/player.rs +++ b/src/player.rs @@ -2,7 +2,8 @@ use glam::Mat4; use shipyard::{Component, EntitiesViewMut, ViewMut}; use crate::{ transform::Transform, - camera::Camera, + camera::Camera, + fly_controller::FlyController, }; #[derive(Component)] @@ -11,26 +12,35 @@ pub struct LocalPlayer; #[derive(Component)] pub struct Player; +#[derive(Component)] +pub struct MainPlayer; + pub fn spawn_player ( mut entities: EntitiesViewMut, mut vm_player: ViewMut, + mut vm_main_player: ViewMut, mut vm_local_player: ViewMut, mut vm_transform: ViewMut, mut vm_camera: ViewMut, + mut vm_controls: ViewMut, ) { log::info!("spawning player"); entities.add_entity( ( &mut vm_player, + &mut vm_main_player, &mut vm_local_player, &mut vm_transform, &mut vm_camera, + &mut vm_controls ), ( Player, + MainPlayer, LocalPlayer, Transform(Mat4::default()), - Camera::default() + Camera::default(), + FlyController ) ); } From 3d6988f459fe7c05fb7e55fa580f9a01adec3d3a Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Wed, 25 Jan 2023 03:52:54 +0100 Subject: [PATCH 41/81] wip camera --- src/fly_controller.rs | 10 ++++++---- src/input.rs | 2 +- src/settings.rs | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/fly_controller.rs b/src/fly_controller.rs index 09921a7..51f4285 100644 --- a/src/fly_controller.rs +++ b/src/fly_controller.rs @@ -1,6 +1,6 @@ -use glam::{Mat4, EulerRot, Quat}; +use glam::{Vec3, Mat4, EulerRot, Quat}; use shipyard::{Component, View, ViewMut, IntoIter, UniqueView}; -use crate::{transform::Transform, input::Inputs}; +use crate::{transform::Transform, input::Inputs, settings::GameSettings}; #[derive(Component)] pub struct FlyController; @@ -8,11 +8,13 @@ pub struct FlyController; pub fn update_controllers( controllers: View, mut transforms: ViewMut, - inputs: UniqueView + inputs: UniqueView, + settings: UniqueView, ) { for (_, mut transform) in (&controllers, &mut transforms).iter() { let (scale, mut rotation, translation) = transform.0.to_scale_rotation_translation(); - rotation *= Quat::from_euler(EulerRot::XYZ, 0., 0.001, 0.); + let look = inputs.look * settings.mouse_sensitivity * -1.; + rotation *= Quat::from_euler(EulerRot::YXZ, look.x, look.y, 0.); transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); } } diff --git a/src/input.rs b/src/input.rs index eb5031e..498a0b8 100644 --- a/src/input.rs +++ b/src/input.rs @@ -38,7 +38,7 @@ pub fn process_events( } }, DeviceEvent::Button { button, state } => { - println!("Button {button} {state:?}"); + //log::debug!("Button {button} {state:?}"); }, _ => () } diff --git a/src/settings.rs b/src/settings.rs index 2ad524c..e62bf97 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -4,11 +4,13 @@ use shipyard::Unique; pub struct GameSettings { //there's a 1 chunk border of loaded but invisible around this pub render_distance: u8, + pub mouse_sensitivity: f32, } impl Default for GameSettings { fn default() -> Self { Self { - render_distance: 2 + render_distance: 2, + mouse_sensitivity: 0.01, } } } From 29166c3b95cb353e13346f07c01c525c71ce964f Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Wed, 25 Jan 2023 04:11:55 +0100 Subject: [PATCH 42/81] upd camera --- src/camera.rs | 13 ++++++++----- src/events.rs | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 97efee5..f05935b 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,7 +1,7 @@ use glam::{Mat4, Vec3}; use shipyard::{Component, ViewMut, View, IntoIter, Workload, IntoWorkload}; use std::f32::consts::PI; -use crate::transform::Transform; +use crate::{transform::Transform, events::WindowResizedEvent}; #[derive(Component)] pub struct Camera { @@ -46,14 +46,17 @@ fn update_view_matrix( } fn update_perspective_matrix( - mut vm_camera: ViewMut + mut vm_camera: ViewMut, + resize: View, ) { - //todo compute this on win resize! - const ASPECT_RATIO: f32 = 16. / 9.; + //TODO update on launch + let Some(&size) = resize.iter().next() else { + return + }; for camera in (&mut vm_camera).iter() { camera.perspective_matrix = Mat4::perspective_rh_gl( camera.fov, - ASPECT_RATIO, + size.0.x as f32 / size.0.y as f32, camera.z_near, camera.z_far, ) diff --git a/src/events.rs b/src/events.rs index bab5db7..3a37298 100644 --- a/src/events.rs +++ b/src/events.rs @@ -15,7 +15,7 @@ pub struct InputDeviceEvent{ } #[derive(Component, Clone, Copy, Debug, Default)] -pub struct WindowResizedEvent(UVec2); +pub struct WindowResizedEvent(pub UVec2); pub fn process_glutin_events(world: &mut World, event: &Event<'_, ()>) { #[allow(clippy::collapsible_match, clippy::single_match)] From 56c2f0de888e7f8b1aebda2423c41a93d2004f6e Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 03:05:29 +0100 Subject: [PATCH 43/81] fuck --- src/camera.rs | 12 +++++-- src/fly_controller.rs | 23 +++++++++++--- src/prefabs.rs | 6 ++-- src/world/block.rs | 73 +++++++++++++++++++++++++++++++++++++++++++ src/world/worldgen.rs | 1 + 5 files changed, 105 insertions(+), 10 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index f05935b..6405e04 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,4 +1,4 @@ -use glam::{Mat4, Vec3}; +use glam::{Mat4, Vec3, EulerRot}; use shipyard::{Component, ViewMut, View, IntoIter, Workload, IntoWorkload}; use std::f32::consts::PI; use crate::{transform::Transform, events::WindowResizedEvent}; @@ -40,8 +40,14 @@ fn update_view_matrix( ) { for (camera, transform) in (&mut vm_camera, v_transform.inserted_or_modified()).iter() { let (_, rotation, translation) = transform.0.to_scale_rotation_translation(); - let dir = rotation * Vec3::Z; //this may be incorrect! - camera.view_matrix = Mat4::look_to_rh(translation, dir, camera.up); + //let direction = rotation * Vec3::Z; //this may be incorrect! + let (yaw, pitch, _) = rotation.to_euler(EulerRot::YXZ); + let direction= Vec3::new( + yaw.cos() * pitch.cos(), + pitch.sin(), + yaw.sin() * pitch.cos() + ); + camera.view_matrix = Mat4::look_to_rh(translation, direction, camera.up); } } diff --git a/src/fly_controller.rs b/src/fly_controller.rs index 51f4285..b6f35f4 100644 --- a/src/fly_controller.rs +++ b/src/fly_controller.rs @@ -1,4 +1,4 @@ -use glam::{Vec3, Mat4, EulerRot, Quat}; +use glam::{Vec3, Mat4, Quat, EulerRot}; use shipyard::{Component, View, ViewMut, IntoIter, UniqueView}; use crate::{transform::Transform, input::Inputs, settings::GameSettings}; @@ -12,9 +12,24 @@ pub fn update_controllers( settings: UniqueView, ) { for (_, mut transform) in (&controllers, &mut transforms).iter() { - let (scale, mut rotation, translation) = transform.0.to_scale_rotation_translation(); - let look = inputs.look * settings.mouse_sensitivity * -1.; - rotation *= Quat::from_euler(EulerRot::YXZ, look.x, look.y, 0.); + let (scale, mut rotation, mut translation) = transform.0.to_scale_rotation_translation(); + let look = inputs.look * settings.mouse_sensitivity; + + //rotation *= Quat::from_axis_angle(Vec3::Y, look.x); + + //old way + // rotation = rotation.normalize(); + // rotation *= Quat::from_euler(EulerRot::ZYX, 0., look.x, look.y).normalize(); + // rotation = rotation.normalize(); + + // let direction = (rotation * Vec3::Z).normalize(); + // let camera_right = Vec3::Y.cross(direction).normalize(); + // let camera_up = direction.cross(camera_right); + // rotation *= Quat::from_axis_angle(Vec3::Y, look.x); + // rotation *= Quat::from_axis_angle(camera_right, look.y); + + //translation += (rotation * Vec3::X) / 4.; + transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); } } diff --git a/src/prefabs.rs b/src/prefabs.rs index 6043bcf..fc1e075 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -15,7 +15,7 @@ pub trait AssetPaths { #[derive(Clone, Copy, Debug, EnumIter)] #[repr(u8)] -pub enum BlockTextures { +pub enum BlockTexture { Stone = 0, Dirt = 1, GrassTop = 2, @@ -30,7 +30,7 @@ pub enum BlockTextures { Snow = 11, GrassSideSnow = 12, } -impl AssetPaths for BlockTextures { +impl AssetPaths for BlockTexture { fn file_name(self) -> &'static str { match self { Self::Stone => "stone.png", @@ -61,7 +61,7 @@ pub fn load_prefabs( renderer: NonSendSync> ) { storages.add_unique_non_send_sync(BlockTexturesPrefab( - load_texture2darray_prefab::( + load_texture2darray_prefab::( "./assets/blocks/".into(), &renderer.display, MipmapsOption::AutoGeneratedMipmaps diff --git a/src/world/block.rs b/src/world/block.rs index ced61a8..dc3de5d 100644 --- a/src/world/block.rs +++ b/src/world/block.rs @@ -1,4 +1,5 @@ use strum::EnumIter; +use crate::prefabs::BlockTexture; #[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)] #[repr(u8)] @@ -9,3 +10,75 @@ pub enum Block { Grass, Sand, } +impl Block { + pub const fn descriptor(self) -> BlockDescriptor { + match self { + Self::Air => BlockDescriptor { + name: "air", + render: RenderType::None, + collision: CollisionType::None, + raycast_collision: false, + }, + Self::Stone => BlockDescriptor { + name: "stone", + render: RenderType::SolidBlock(CubeTexture::all(BlockTexture::Stone)), + collision: CollisionType::Solid, + raycast_collision: true, + }, + _ => todo!() + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct BlockDescriptor { + pub name: &'static str, + pub render: RenderType, + pub collision: CollisionType, + pub raycast_collision: bool, +} +impl BlockDescriptor { + pub fn of(block: Block) -> Self { + block.descriptor() + } +} + +#[derive(Clone, Copy, Debug)] +pub struct CubeTexture { + pub top: BlockTexture, + pub bottom: BlockTexture, + pub left: BlockTexture, + pub right: BlockTexture, + pub front: BlockTexture, + pub back: BlockTexture, +} +impl CubeTexture { + pub const fn top_sides_bottom(top: BlockTexture, sides: BlockTexture, bottom: BlockTexture) -> Self { + Self { + top, + bottom, + left: sides, + right: sides, + front: sides, + back: sides, + } + } + pub const fn horizontal_vertical(horizontal: BlockTexture, vertical: BlockTexture) -> Self { + Self::top_sides_bottom(vertical, horizontal, vertical) + } + pub const fn all(texture: BlockTexture) -> Self { + Self::horizontal_vertical(texture, texture) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CollisionType { + None, + Solid, +} + +#[derive(Clone, Copy, Debug)] +pub enum RenderType { + None, + SolidBlock(CubeTexture) +} diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index a3b17c5..ba6c4e0 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -9,6 +9,7 @@ pub fn generate_world(_position: IVec3, _seed: u32) -> BlockData { blocks[0][0][0] = Block::Stone; blocks[1][0][0] = Block::Stone; blocks[0][1][0] = Block::Stone; + blocks[0][2][0] = Block::Stone; blocks[0][0][1] = Block::Stone; //TODO actual world generation blocks From f3f0227511fd3bd8da6cab8397180a53688ca93c Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 03:28:05 +0100 Subject: [PATCH 44/81] yay it works! --- src/camera.rs | 8 +----- src/fly_controller.rs | 58 +++++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 6405e04..61899e9 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -40,13 +40,7 @@ fn update_view_matrix( ) { for (camera, transform) in (&mut vm_camera, v_transform.inserted_or_modified()).iter() { let (_, rotation, translation) = transform.0.to_scale_rotation_translation(); - //let direction = rotation * Vec3::Z; //this may be incorrect! - let (yaw, pitch, _) = rotation.to_euler(EulerRot::YXZ); - let direction= Vec3::new( - yaw.cos() * pitch.cos(), - pitch.sin(), - yaw.sin() * pitch.cos() - ); + let direction = rotation * Vec3::NEG_Z; camera.view_matrix = Mat4::look_to_rh(translation, direction, camera.up); } } diff --git a/src/fly_controller.rs b/src/fly_controller.rs index b6f35f4..85f3821 100644 --- a/src/fly_controller.rs +++ b/src/fly_controller.rs @@ -1,35 +1,51 @@ -use glam::{Vec3, Mat4, Quat, EulerRot}; -use shipyard::{Component, View, ViewMut, IntoIter, UniqueView}; +use glam::{Vec3, Mat4, Quat, EulerRot, Vec2}; +use shipyard::{Component, View, ViewMut, IntoIter, UniqueView, Workload, IntoWorkload}; +use std::f32::consts::PI; use crate::{transform::Transform, input::Inputs, settings::GameSettings}; #[derive(Component)] pub struct FlyController; -pub fn update_controllers( +pub fn update_controllers() -> Workload { + ( + update_look, + update_movement + ).into_workload() +} + +const MAX_PITCH: f32 = PI/2. - 0.001; + +fn update_look( controllers: View, mut transforms: ViewMut, inputs: UniqueView, settings: UniqueView, ) { + let look = inputs.look * settings.mouse_sensitivity; + if look == Vec2::ZERO { return } for (_, mut transform) in (&controllers, &mut transforms).iter() { - let (scale, mut rotation, mut translation) = transform.0.to_scale_rotation_translation(); - let look = inputs.look * settings.mouse_sensitivity; - - //rotation *= Quat::from_axis_angle(Vec3::Y, look.x); - - //old way - // rotation = rotation.normalize(); - // rotation *= Quat::from_euler(EulerRot::ZYX, 0., look.x, look.y).normalize(); - // rotation = rotation.normalize(); - - // let direction = (rotation * Vec3::Z).normalize(); - // let camera_right = Vec3::Y.cross(direction).normalize(); - // let camera_up = direction.cross(camera_right); - // rotation *= Quat::from_axis_angle(Vec3::Y, look.x); - // rotation *= Quat::from_axis_angle(camera_right, look.y); - - //translation += (rotation * Vec3::X) / 4.; - + let (scale, mut rotation, translation) = transform.0.to_scale_rotation_translation(); + let (mut yaw, mut pitch, _roll) = rotation.to_euler(EulerRot::YXZ); + yaw -= look.x; + pitch -= look.y; + pitch = pitch.clamp(-MAX_PITCH, MAX_PITCH); + rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, 0.); + transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); + } +} + +fn update_movement( + controllers: View, + mut transforms: ViewMut, + inputs: UniqueView, + settings: UniqueView, +) { + let movement = inputs.movement; + if movement == Vec2::ZERO { return } + for (_, mut transform) in (&controllers, &mut transforms).iter() { + let (scale, rotation, mut translation) = transform.0.to_scale_rotation_translation(); + translation += (rotation * Vec3::NEG_Z) * movement.y; + translation += (rotation * Vec3::X) * movement.x; transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); } } From fc6da8856de67946314bc007e801976dffc98c69 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 03:28:17 +0100 Subject: [PATCH 45/81] remove useless argument --- src/fly_controller.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fly_controller.rs b/src/fly_controller.rs index 85f3821..1d11b80 100644 --- a/src/fly_controller.rs +++ b/src/fly_controller.rs @@ -37,8 +37,7 @@ fn update_look( fn update_movement( controllers: View, mut transforms: ViewMut, - inputs: UniqueView, - settings: UniqueView, + inputs: UniqueView ) { let movement = inputs.movement; if movement == Vec2::ZERO { return } From dfdcc3e4b7bb0eda9d263b1df2688ebc08bd744d Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 03:39:39 +0100 Subject: [PATCH 46/81] change world generations, enable mi[mapping in sampler, unlink movement speed from fps --- src/fly_controller.rs | 11 ++++++----- src/settings.rs | 2 +- src/world/render.rs | 2 +- src/world/worldgen.rs | 9 ++++++++- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/fly_controller.rs b/src/fly_controller.rs index 1d11b80..4da9593 100644 --- a/src/fly_controller.rs +++ b/src/fly_controller.rs @@ -1,7 +1,7 @@ use glam::{Vec3, Mat4, Quat, EulerRot, Vec2}; use shipyard::{Component, View, ViewMut, IntoIter, UniqueView, Workload, IntoWorkload}; use std::f32::consts::PI; -use crate::{transform::Transform, input::Inputs, settings::GameSettings}; +use crate::{transform::Transform, input::Inputs, settings::GameSettings, DeltaTime}; #[derive(Component)] pub struct FlyController; @@ -19,7 +19,7 @@ fn update_look( controllers: View, mut transforms: ViewMut, inputs: UniqueView, - settings: UniqueView, + settings: UniqueView ) { let look = inputs.look * settings.mouse_sensitivity; if look == Vec2::ZERO { return } @@ -29,7 +29,7 @@ fn update_look( yaw -= look.x; pitch -= look.y; pitch = pitch.clamp(-MAX_PITCH, MAX_PITCH); - rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, 0.); + rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, 0.).normalize(); transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); } } @@ -37,9 +37,10 @@ fn update_look( fn update_movement( controllers: View, mut transforms: ViewMut, - inputs: UniqueView + inputs: UniqueView, + dt: UniqueView, ) { - let movement = inputs.movement; + let movement = inputs.movement * 30. * dt.0.as_secs_f32(); if movement == Vec2::ZERO { return } for (_, mut transform) in (&controllers, &mut transforms).iter() { let (scale, rotation, mut translation) = transform.0.to_scale_rotation_translation(); diff --git a/src/settings.rs b/src/settings.rs index e62bf97..0588cf8 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -9,7 +9,7 @@ pub struct GameSettings { impl Default for GameSettings { fn default() -> Self { Self { - render_distance: 2, + render_distance: 5, mouse_sensitivity: 0.01, } } diff --git a/src/world/render.rs b/src/world/render.rs index 56499db..70e6132 100644 --- a/src/world/render.rs +++ b/src/world/render.rs @@ -60,7 +60,7 @@ pub fn draw_world( ..Default::default() }; let texture_sampler = Sampler(&texture.0, SamplerBehavior { - minify_filter: MinifySamplerFilter::Linear, + minify_filter: MinifySamplerFilter::LinearMipmapLinear, magnify_filter: MagnifySamplerFilter::Nearest, max_anisotropy: 8, wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp), diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index ba6c4e0..8c49489 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -4,13 +4,20 @@ use super::{ block::Block }; -pub fn generate_world(_position: IVec3, _seed: u32) -> BlockData { +pub fn generate_world(position: IVec3, _seed: u32) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); blocks[0][0][0] = Block::Stone; blocks[1][0][0] = Block::Stone; blocks[0][1][0] = Block::Stone; blocks[0][2][0] = Block::Stone; blocks[0][0][1] = Block::Stone; + if position.y == 0 { + for x in 0..CHUNK_SIZE { + for z in 0..CHUNK_SIZE { + blocks[x][0][z] = Block::Stone; + } + } + } //TODO actual world generation blocks } From 941f5630599a020aad463f45d73234660b1ffc16 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 03:50:38 +0100 Subject: [PATCH 47/81] block textures --- src/world/block.rs | 22 ++++++++++++++++++++++ src/world/mesh.rs | 33 ++++++++++++++++++--------------- src/world/worldgen.rs | 15 ++++++++------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/world/block.rs b/src/world/block.rs index dc3de5d..e16641c 100644 --- a/src/world/block.rs +++ b/src/world/block.rs @@ -25,6 +25,28 @@ impl Block { collision: CollisionType::Solid, raycast_collision: true, }, + Self::Dirt => BlockDescriptor { + name: "dirt", + render: RenderType::SolidBlock(CubeTexture::all(BlockTexture::Dirt)), + collision: CollisionType::Solid, + raycast_collision: true, + }, + Self::Grass => BlockDescriptor { + name: "grass", + render: RenderType::SolidBlock(CubeTexture::top_sides_bottom( + BlockTexture::GrassTop, + BlockTexture::GrassSide, + BlockTexture::Dirt + )), + collision: CollisionType::Solid, + raycast_collision: true, + }, + Self::Sand => BlockDescriptor { + name: "sand", + render: RenderType::SolidBlock(CubeTexture::all(BlockTexture::Sand)), + collision: CollisionType::Solid, + raycast_collision: true, + }, _ => todo!() } } diff --git a/src/world/mesh.rs b/src/world/mesh.rs index 4074cb8..6d6b6f2 100644 --- a/src/world/mesh.rs +++ b/src/world/mesh.rs @@ -1,6 +1,6 @@ use strum::{EnumIter, IntoEnumIterator}; use glam::{Vec3A, vec3a, IVec3, ivec3}; -use super::{render::ChunkVertex, chunk::CHUNK_SIZE, block::Block}; +use super::{render::ChunkVertex, chunk::CHUNK_SIZE, block::{Block, RenderType}}; pub mod data; use data::MeshGenData; @@ -103,26 +103,29 @@ pub fn generate_mesh(data: MeshGenData) -> (Vec, Vec) { for z in 0..CHUNK_SIZE { let coord = ivec3(x as i32, y as i32, z as i32); let block = get_block(coord); - if block == Block::Air { + let descriptor = block.descriptor(); + if matches!(descriptor.render, RenderType::None) { continue } for face in CubeFace::iter() { let facing = CUBE_FACE_NORMALS[face as usize].as_ivec3(); let facing_coord = coord + facing; - let show = { - get_block(facing_coord) == Block::Air - }; + let show = matches!(get_block(facing_coord).descriptor().render, RenderType::None); if show { - // let texures = descriptor.render.unwrap().1; - // let block_texture = match face { - // CubeFace::Top => texures.top, - // CubeFace::Front => texures.front, - // CubeFace::Left => texures.left, - // CubeFace::Right => texures.right, - // CubeFace::Back => texures.back, - // CubeFace::Bottom => texures.bottom, - // }; - builder.add_face(face, coord, 0); + match descriptor.render { + RenderType::SolidBlock(textures) => { + let face_texture = match face { + CubeFace::Top => textures.top, + CubeFace::Front => textures.front, + CubeFace::Left => textures.left, + CubeFace::Right => textures.right, + CubeFace::Back => textures.back, + CubeFace::Bottom => textures.bottom, + }; + builder.add_face(face, coord, face_texture as u8); + }, + _ => unimplemented!() + } } } } diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index 8c49489..fa72ca6 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -6,17 +6,18 @@ use super::{ pub fn generate_world(position: IVec3, _seed: u32) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); - blocks[0][0][0] = Block::Stone; - blocks[1][0][0] = Block::Stone; - blocks[0][1][0] = Block::Stone; - blocks[0][2][0] = Block::Stone; - blocks[0][0][1] = Block::Stone; - if position.y == 0 { + if position.y == -1 { for x in 0..CHUNK_SIZE { for z in 0..CHUNK_SIZE { - blocks[x][0][z] = Block::Stone; + blocks[x][0][z] = Block::Grass; } } + } else { + blocks[0][0][0] = Block::Stone; + blocks[1][0][0] = Block::Stone; + blocks[0][1][0] = Block::Stone; + blocks[0][2][0] = Block::Stone; + blocks[0][0][1] = Block::Stone; } //TODO actual world generation blocks From 9ed19bfc0e6384184d5bd009f2f71db70f280b47 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 03:54:41 +0100 Subject: [PATCH 48/81] skip drawing empty chunks --- src/world/render.rs | 26 ++++++++++++++------------ src/world/worldgen.rs | 8 +------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/world/render.rs b/src/world/render.rs index 70e6132..ce5c115 100644 --- a/src/world/render.rs +++ b/src/world/render.rs @@ -73,18 +73,20 @@ pub fn draw_world( if let Some(key) = chunk.mesh_index { let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); let world_position = (position.as_vec3() * CHUNK_SIZE as f32).to_array(); - target.0.draw( - &mesh.vertex_buffer, - &mesh.index_buffer, - &program.0, - &uniform! { - position_offset: world_position, - view: view, - perspective: perspective, - tex: texture_sampler - }, - &draw_parameters - ).unwrap(); + if mesh.index_buffer.len() > 0 { //maybe this is a bit hacky? + target.0.draw( + &mesh.vertex_buffer, + &mesh.index_buffer, + &program.0, + &uniform! { + position_offset: world_position, + view: view, + perspective: perspective, + tex: texture_sampler + }, + &draw_parameters + ).unwrap(); + } } } } diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index fa72ca6..1079975 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -6,19 +6,13 @@ use super::{ pub fn generate_world(position: IVec3, _seed: u32) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); + //TODO actual world generation if position.y == -1 { for x in 0..CHUNK_SIZE { for z in 0..CHUNK_SIZE { blocks[x][0][z] = Block::Grass; } } - } else { - blocks[0][0][0] = Block::Stone; - blocks[1][0][0] = Block::Stone; - blocks[0][1][0] = Block::Stone; - blocks[0][2][0] = Block::Stone; - blocks[0][0][1] = Block::Stone; } - //TODO actual world generation blocks } From 5c3ee1c4b6f79505fe7712fe16d172c97518a144 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 03:58:05 +0100 Subject: [PATCH 49/81] testing --- src/world/worldgen.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index 1079975..a518bcd 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -13,6 +13,14 @@ pub fn generate_world(position: IVec3, _seed: u32) -> BlockData { blocks[x][0][z] = Block::Grass; } } + } else if position.y < -1 { + for x in 0..CHUNK_SIZE { + for y in 0..CHUNK_SIZE { + for z in 0..CHUNK_SIZE { + blocks[x][y][z] = Block::Dirt; + } + } + } } blocks } From a512fffcc4be75e149e9ec2d5730fd5e6067c881 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 04:12:29 +0100 Subject: [PATCH 50/81] Chunk state downgrades --- src/camera.rs | 2 +- src/input.rs | 2 +- src/world/loading.rs | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 61899e9..7551dea 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,4 +1,4 @@ -use glam::{Mat4, Vec3, EulerRot}; +use glam::{Mat4, Vec3}; use shipyard::{Component, ViewMut, View, IntoIter, Workload, IntoWorkload}; use std::f32::consts::PI; use crate::{transform::Transform, events::WindowResizedEvent}; diff --git a/src/input.rs b/src/input.rs index 498a0b8..cff8084 100644 --- a/src/input.rs +++ b/src/input.rs @@ -37,7 +37,7 @@ pub fn process_events( }; } }, - DeviceEvent::Button { button, state } => { + DeviceEvent::Button { button: _, state: _ } => { //log::debug!("Button {button} {state:?}"); }, _ => () diff --git a/src/world/loading.rs b/src/world/loading.rs index 0e5cbdf..61ef605 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -16,7 +16,7 @@ use super::{ pub fn update_loaded_world_around_player() -> Workload { ( update_chunks_if_player_moved, - unload_marked_chunks, + unload_downgrade_chunks, start_required_tasks, process_completed_tasks, ).into_workload() @@ -76,13 +76,14 @@ pub fn update_chunks_if_player_moved( } } -fn unload_marked_chunks( +fn unload_downgrade_chunks( mut vm_world: UniqueViewMut, mut vm_meshes: NonSendSync> ) { if !vm_world.is_modified() { return } + //TODO refactor this vm_world.chunks.retain(|_, chunk| { if chunk.desired_state == DesiredChunkState::ToUnload { if let Some(mesh_index) = chunk.mesh_index { @@ -90,6 +91,16 @@ fn unload_marked_chunks( } false } else { + match chunk.desired_state { + DesiredChunkState::Loaded if matches!(chunk.current_state, CurrentChunkState::Rendered | CurrentChunkState::CalculatingMesh) => { + if let Some(mesh_index) = chunk.mesh_index { + vm_meshes.remove(mesh_index).unwrap(); + } + chunk.mesh_index = None; + chunk.current_state = CurrentChunkState::Loaded; + }, + _ => (), + } true } }) @@ -99,6 +110,9 @@ fn start_required_tasks( task_manager: UniqueView, mut world: UniqueViewMut, ) { + if !world.is_modified() { + return + } //HACK: cant iterate over chunks.keys() or chunk directly! let hashmap_keys: Vec = world.chunks.keys().copied().collect(); for position in hashmap_keys { From 294648b1b2f1c02025329ab21e0196ca3f240c10 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Thu, 26 Jan 2023 14:44:11 +0100 Subject: [PATCH 51/81] u --- src/world/loading.rs | 99 +++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/src/world/loading.rs b/src/world/loading.rs index 61ef605..8c85d93 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -13,6 +13,9 @@ use super::{ tasks::{ChunkTaskManager, ChunkTaskResponse, ChunkTask}, }; +//todo limit task starts insted +const MAX_CHUNK_RECV: usize = 8; + pub fn update_loaded_world_around_player() -> Workload { ( update_chunks_if_player_moved, @@ -121,7 +124,7 @@ fn start_required_tasks( DesiredChunkState::Loaded | DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Nothing => { //start load task task_manager.spawn_task(ChunkTask::LoadChunk { - seed: 0xdead_cafe, + seed: 0xbeef_face_dead_cafe, position }); //Update chunk state @@ -157,54 +160,56 @@ fn process_completed_tasks( mut meshes: NonSendSync>, renderer: NonSendSync> ) { - while let Some(res) = task_manager.receive() { - match res { - ChunkTaskResponse::LoadedChunk { position, chunk_data } => { - //check if chunk exists - let Some(chunk) = world.chunks.get_mut(&position) else { - log::warn!("blocks data discarded: chunk doesn't exist"); - return - }; + for _ in 0..MAX_CHUNK_OPS { + if let Some(res) = task_manager.receive() { + match res { + ChunkTaskResponse::LoadedChunk { position, chunk_data } => { + //check if chunk exists + let Some(chunk) = world.chunks.get_mut(&position) else { + log::warn!("blocks data discarded: chunk doesn't exist"); + return + }; - //check if chunk still wants it - if !matches!(chunk.desired_state, DesiredChunkState::Loaded | DesiredChunkState::Rendered) { - log::warn!("block data discarded: state undesirable: {:?}", chunk.desired_state); - return + //check if chunk still wants it + if !matches!(chunk.desired_state, DesiredChunkState::Loaded | DesiredChunkState::Rendered) { + log::warn!("block data discarded: state undesirable: {:?}", chunk.desired_state); + return + } + + //set the block data + chunk.block_data = Some(ChunkData { + blocks: chunk_data + }); + + //update chunk state + chunk.current_state = CurrentChunkState::Loaded; + }, + ChunkTaskResponse::GeneratedMesh { position, vertices, indexes } => { + //check if chunk exists + let Some(chunk) = world.chunks.get_mut(&position) else { + log::warn!("mesh discarded: chunk doesn't exist"); + return + }; + + //check if chunk still wants it + if chunk.desired_state != DesiredChunkState::Rendered { + log::warn!("mesh discarded: state undesirable: {:?}", chunk.desired_state); + return + } + + //apply the mesh + let vertex_buffer = VertexBuffer::new(&renderer.display, &vertices).unwrap(); + let index_buffer = IndexBuffer::new(&renderer.display, PrimitiveType::TrianglesList, &indexes).unwrap(); + let mesh_index = meshes.insert(ChunkMesh { + is_dirty: false, + vertex_buffer, + index_buffer, + }); + chunk.mesh_index = Some(mesh_index); + + //update chunk state + chunk.current_state = CurrentChunkState::Rendered; } - - //set the block data - chunk.block_data = Some(ChunkData { - blocks: chunk_data - }); - - //update chunk state - chunk.current_state = CurrentChunkState::Loaded; - }, - ChunkTaskResponse::GeneratedMesh { position, vertices, indexes } => { - //check if chunk exists - let Some(chunk) = world.chunks.get_mut(&position) else { - log::warn!("mesh discarded: chunk doesn't exist"); - return - }; - - //check if chunk still wants it - if chunk.desired_state != DesiredChunkState::Rendered { - log::warn!("mesh discarded: state undesirable: {:?}", chunk.desired_state); - return - } - - //apply the mesh - let vertex_buffer = VertexBuffer::new(&renderer.display, &vertices).unwrap(); - let index_buffer = IndexBuffer::new(&renderer.display, PrimitiveType::TrianglesList, &indexes).unwrap(); - let mesh_index = meshes.insert(ChunkMesh { - is_dirty: false, - vertex_buffer, - index_buffer, - }); - chunk.mesh_index = Some(mesh_index); - - //update chunk state - chunk.current_state = CurrentChunkState::Rendered; } } } From a7a1b44548fac834ac9dd63559cca4d7e9c6de65 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 01:04:01 +0100 Subject: [PATCH 52/81] testing noise --- Cargo.toml | 3 ++- src/world/tasks.rs | 2 +- src/world/worldgen.rs | 29 ++++++++++++++++------------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 833d37b..769fdad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,10 @@ env_logger = "0.10" strum = { version = "0.24", features = ["derive"] } glam = { version = "0.22", features = ["debug-glam-assert", "mint", "fast-math"] } hashbrown = "0.13" -noise = "0.8" rayon = "1.6" shipyard = { version = "0.6", features = ["thread_local"] } nohash-hasher = "0.2.0" anyhow = "1.0" flume = "0.10" +#once_cell = "1.17" +bracket-noise = "0.8" diff --git a/src/world/tasks.rs b/src/world/tasks.rs index 9b921bc..6570829 100644 --- a/src/world/tasks.rs +++ b/src/world/tasks.rs @@ -10,7 +10,7 @@ use super::{ pub enum ChunkTask { LoadChunk { - seed: u32, + seed: u64, position: IVec3 }, GenerateMesh { diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index a518bcd..c40716e 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -1,26 +1,29 @@ -use glam::IVec3; +use glam::{IVec3, ivec3}; +use bracket_noise::prelude::*; use super::{ chunk::{BlockData, CHUNK_SIZE}, block::Block }; -pub fn generate_world(position: IVec3, _seed: u32) -> BlockData { +pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData { + let offset = chunk_position * CHUNK_SIZE as i32; + let mut noise = FastNoise::seeded(seed); + noise.set_fractal_type(FractalType::FBM); + noise.set_frequency(0.1); + let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); - //TODO actual world generation - if position.y == -1 { - for x in 0..CHUNK_SIZE { + + for x in 0..CHUNK_SIZE { + for y in 0..CHUNK_SIZE { for z in 0..CHUNK_SIZE { - blocks[x][0][z] = Block::Grass; - } - } - } else if position.y < -1 { - for x in 0..CHUNK_SIZE { - for y in 0..CHUNK_SIZE { - for z in 0..CHUNK_SIZE { - blocks[x][y][z] = Block::Dirt; + let position = ivec3(x as i32, y as i32, z as i32) + offset; + let noise = noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32); + if noise > 0.8 { + blocks[x][y][z] = Block::Stone; } } } } + blocks } From 90c5b2a1e2d2c254659c8791d46cb1bfbc311976 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 01:04:56 +0100 Subject: [PATCH 53/81] fix --- src/world/loading.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/loading.rs b/src/world/loading.rs index 8c85d93..f7418a2 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -14,7 +14,7 @@ use super::{ }; //todo limit task starts insted -const MAX_CHUNK_RECV: usize = 8; +const MAX_CHUNK_OPS: usize = 8; pub fn update_loaded_world_around_player() -> Workload { ( From 6b8deab09456966391b66171978ebe7faceed6f5 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 02:14:10 +0100 Subject: [PATCH 54/81] control --- src/world/tasks.rs | 5 ++++- src/world/worldgen.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/world/tasks.rs b/src/world/tasks.rs index 6570829..61a1c8d 100644 --- a/src/world/tasks.rs +++ b/src/world/tasks.rs @@ -1,6 +1,7 @@ use flume::{Sender, Receiver}; use glam::IVec3; use shipyard::Unique; +use rayon::{ThreadPool, ThreadPoolBuilder}; use super::{ chunk::BlockData, render::ChunkVertex, @@ -33,16 +34,18 @@ pub enum ChunkTaskResponse { #[derive(Unique)] pub struct ChunkTaskManager { channel: (Sender, Receiver), + pool: ThreadPool, } impl ChunkTaskManager { pub fn new() -> Self { Self { channel: flume::unbounded::(), //maybe put a bound or even bound(0)? + pool: ThreadPoolBuilder::new().num_threads(4).build().unwrap() } } pub fn spawn_task(&self, task: ChunkTask) { let sender = self.channel.0.clone(); - rayon::spawn(move || { + self.pool.spawn(move || { let _ = sender.send(match task { ChunkTask::GenerateMesh { position, data } => { let (vertices, indexes) = generate_mesh(data); diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index c40716e..deac50a 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -18,7 +18,7 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData { for z in 0..CHUNK_SIZE { let position = ivec3(x as i32, y as i32, z as i32) + offset; let noise = noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32); - if noise > 0.8 { + if (0.7..0.8).contains(&noise) { blocks[x][y][z] = Block::Stone; } } From 783b6a1f84633d2b28ae1a54be5b6afea081ac77 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 03:24:21 +0100 Subject: [PATCH 55/81] wip --- src/world/loading.rs | 4 ++-- src/world/render.rs | 39 +++++++++++++++++++++++++-------------- src/world/worldgen.rs | 31 ++++++++++++++++++++----------- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/world/loading.rs b/src/world/loading.rs index f7418a2..226b6e3 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -131,7 +131,7 @@ fn start_required_tasks( let chunk = world.chunks.get_mut(&position).unwrap(); chunk.current_state = CurrentChunkState::Loading; // =========== - log::info!("Started loading chunk {position}"); + //log::trace!("Started loading chunk {position}"); }, DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Loaded => { //get needed data @@ -147,7 +147,7 @@ fn start_required_tasks( let chunk = world.chunks.get_mut(&position).unwrap(); chunk.current_state = CurrentChunkState::CalculatingMesh; // =========== - log::info!("Started generating mesh for chunk {position}"); + //log::trace!("Started generating mesh for chunk {position}"); } _ => () } diff --git a/src/world/render.rs b/src/world/render.rs index ce5c115..ec1460b 100644 --- a/src/world/render.rs +++ b/src/world/render.rs @@ -1,3 +1,4 @@ +use glam::{vec3a, Vec3A, Vec4Swizzles, Vec3}; use shipyard::{NonSendSync, UniqueView, UniqueViewMut, View, IntoIter}; use glium::{ implement_vertex, uniform, @@ -68,25 +69,35 @@ pub fn draw_world( }); let view = camera.view_matrix.to_cols_array_2d(); let perspective = camera.perspective_matrix.to_cols_array_2d(); + let camera_mat = camera.perspective_matrix * camera.view_matrix; for (&position, chunk) in &chunks.chunks { if let Some(key) = chunk.mesh_index { let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); - let world_position = (position.as_vec3() * CHUNK_SIZE as f32).to_array(); - if mesh.index_buffer.len() > 0 { //maybe this is a bit hacky? - target.0.draw( - &mesh.vertex_buffer, - &mesh.index_buffer, - &program.0, - &uniform! { - position_offset: world_position, - view: view, - perspective: perspective, - tex: texture_sampler - }, - &draw_parameters - ).unwrap(); + let world_position = position.as_vec3a() * CHUNK_SIZE as f32; + if mesh.index_buffer.len() == 0 { + continue } + + //basic culling + // let chunk_center = world_position + Vec3A::splat(CHUNK_SIZE as f32) * 0.5; + // let cull_point = camera_mat * chunk_center.extend(1.); + // if (cull_point.xyz() / cull_point.w).abs().cmpgt(Vec3::splat(1.)).any() { + // continue + // } + + target.0.draw( + &mesh.vertex_buffer, + &mesh.index_buffer, + &program.0, + &uniform! { + position_offset: world_position.to_array(), + view: view, + perspective: perspective, + tex: texture_sampler + }, + &draw_parameters + ).unwrap(); } } } diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index deac50a..3718009 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -13,17 +13,26 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); - for x in 0..CHUNK_SIZE { - for y in 0..CHUNK_SIZE { - for z in 0..CHUNK_SIZE { - let position = ivec3(x as i32, y as i32, z as i32) + offset; - let noise = noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32); - if (0.7..0.8).contains(&noise) { - blocks[x][y][z] = Block::Stone; - } - } - } - } + blocks[0][0][0] = Block::Stone; + blocks[0][CHUNK_SIZE - 1][0] = Block::Stone; + blocks[CHUNK_SIZE - 1][0][0] = Block::Stone; + blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][0] = Block::Stone; + blocks[0][0][CHUNK_SIZE - 1] = Block::Stone; + blocks[0][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; + blocks[CHUNK_SIZE - 1][0][CHUNK_SIZE - 1] = Block::Stone; + blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; + + // for x in 0..CHUNK_SIZE { + // for y in 0..CHUNK_SIZE { + // for z in 0..CHUNK_SIZE { + // let position = ivec3(x as i32, y as i32, z as i32) + offset; + // let noise = noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32); + // if (0.7..0.8).contains(&noise) { + // blocks[x][y][z] = Block::Stone; + // } + // } + // } + // } blocks } From 19fa7e67bc7e3557899bcab47b64045ba49ca4a7 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 04:02:27 +0100 Subject: [PATCH 56/81] Wip frustum code port --- src/camera.rs | 40 +++++-------------------- src/camera/frustum.rs | 66 ++++++++++++++++++++++++++++++++++++++++++ src/camera/matrices.rs | 42 +++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 33 deletions(-) create mode 100644 src/camera/frustum.rs create mode 100644 src/camera/matrices.rs diff --git a/src/camera.rs b/src/camera.rs index 7551dea..7f6c83b 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,7 +1,11 @@ use glam::{Mat4, Vec3}; -use shipyard::{Component, ViewMut, View, IntoIter, Workload, IntoWorkload}; +use shipyard::{Component, Workload, IntoWorkload}; use std::f32::consts::PI; -use crate::{transform::Transform, events::WindowResizedEvent}; + +mod matrices; +mod frustum; + +use matrices::update_matrices; #[derive(Component)] pub struct Camera { @@ -29,36 +33,6 @@ impl Default for Camera { pub fn compute_cameras() -> Workload { ( - update_perspective_matrix, - update_view_matrix, + update_matrices, ).into_workload() } - -fn update_view_matrix( - mut vm_camera: ViewMut, - v_transform: View -) { - for (camera, transform) in (&mut vm_camera, v_transform.inserted_or_modified()).iter() { - let (_, rotation, translation) = transform.0.to_scale_rotation_translation(); - let direction = rotation * Vec3::NEG_Z; - camera.view_matrix = Mat4::look_to_rh(translation, direction, camera.up); - } -} - -fn update_perspective_matrix( - mut vm_camera: ViewMut, - resize: View, -) { - //TODO update on launch - let Some(&size) = resize.iter().next() else { - return - }; - for camera in (&mut vm_camera).iter() { - camera.perspective_matrix = Mat4::perspective_rh_gl( - camera.fov, - size.0.x as f32 / size.0.y as f32, - camera.z_near, - camera.z_far, - ) - } -} diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs new file mode 100644 index 0000000..fff9511 --- /dev/null +++ b/src/camera/frustum.rs @@ -0,0 +1,66 @@ +// basically ported from c++ +// - used as a reference: +// [ https://github.com/Beastwick18/gltest/blob/main/src/renderer/Frustum.cpp ] +// - original code: +// [ https://gist.github.com/podgorskiy/e698d18879588ada9014768e3e82a644 ] +// - which uses cube vs frustum intersection code from: +// [ http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm ] +// three layers of stolen code, yay! + +use glam::{Vec3, Vec4, Vec4Swizzles}; + +use super::Camera; + + +#[repr(usize)] +enum FrustumPlane { + Left, + Right, + Bottom, + Top, + Near, + Far, +} +const PLANE_COUNT: usize = 6; +const PLANE_COMBINATIONS: usize = PLANE_COUNT * (PLANE_COUNT - 1) / 2; + +struct Frustum { + planes: [Vec4; PLANE_COUNT], + crosses: [Vec3; PLANE_COMBINATIONS], +} +impl Frustum { + pub fn compute(camera: &Camera) -> Self { + //compute transposed view-projection matrix + let mat = (camera.perspective_matrix * camera.view_matrix).transpose(); + + // compute planes + let mut planes = [Vec4::default(); PLANE_COUNT]; + planes[FrustumPlane::Left as usize] = mat.w_axis + mat.x_axis; + planes[FrustumPlane::Right as usize] = mat.w_axis - mat.x_axis; + planes[FrustumPlane::Bottom as usize] = mat.w_axis + mat.y_axis; + planes[FrustumPlane::Top as usize] = mat.w_axis - mat.y_axis; + planes[FrustumPlane::Near as usize] = mat.w_axis + mat.z_axis; + planes[FrustumPlane::Far as usize] = mat.w_axis - mat.z_axis; + + //compute crosses + let crosses = [ + planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Right as usize].xyz()), + planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Bottom as usize].xyz()), + planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()), + planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), + planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), + planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Bottom as usize].xyz()), + planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()), + planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), + planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), + planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()), + planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), + planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), + planes[FrustumPlane::Top as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), + planes[FrustumPlane::Top as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), + planes[FrustumPlane::Near as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), + ]; + + Self { planes, crosses } + } +} diff --git a/src/camera/matrices.rs b/src/camera/matrices.rs new file mode 100644 index 0000000..b2086f6 --- /dev/null +++ b/src/camera/matrices.rs @@ -0,0 +1,42 @@ +use glam::{Vec3, Mat4}; +use shipyard::{ViewMut, View, IntoIter, Workload, IntoWorkload}; +use crate::{transform::Transform, events::WindowResizedEvent}; +use super::Camera; + +//maybe parallelize these two? + +fn update_view_matrix( + mut vm_camera: ViewMut, + v_transform: View +) { + for (camera, transform) in (&mut vm_camera, v_transform.inserted_or_modified()).iter() { + let (_, rotation, translation) = transform.0.to_scale_rotation_translation(); + let direction = rotation * Vec3::NEG_Z; + camera.view_matrix = Mat4::look_to_rh(translation, direction, camera.up); + } +} + +fn update_perspective_matrix( + mut vm_camera: ViewMut, + resize: View, +) { + //TODO update on launch + let Some(&size) = resize.iter().next() else { + return + }; + for camera in (&mut vm_camera).iter() { + camera.perspective_matrix = Mat4::perspective_rh_gl( + camera.fov, + size.0.x as f32 / size.0.y as f32, + camera.z_near, + camera.z_far, + ) + } +} + +pub fn update_matrices() -> Workload { + ( + update_view_matrix, + update_perspective_matrix, + ).into_workload() +} From a29f6c65fdd1bf5246f614bee6caf669885a041e Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 21:15:23 +0100 Subject: [PATCH 57/81] frustum --- src/camera/frustum.rs | 66 ++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs index fff9511..22708fa 100644 --- a/src/camera/frustum.rs +++ b/src/camera/frustum.rs @@ -7,7 +7,7 @@ // [ http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm ] // three layers of stolen code, yay! -use glam::{Vec3, Vec4, Vec4Swizzles}; +use glam::{Vec3A, Vec4, Mat3A, vec3a}; use super::Camera; @@ -21,12 +21,14 @@ enum FrustumPlane { Near, Far, } + const PLANE_COUNT: usize = 6; const PLANE_COMBINATIONS: usize = PLANE_COUNT * (PLANE_COUNT - 1) / 2; +const POINT_COUNT: usize = 8; struct Frustum { planes: [Vec4; PLANE_COUNT], - crosses: [Vec3; PLANE_COMBINATIONS], + points: [Vec3A; POINT_COUNT] } impl Frustum { pub fn compute(camera: &Camera) -> Self { @@ -44,23 +46,49 @@ impl Frustum { //compute crosses let crosses = [ - planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Right as usize].xyz()), - planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Bottom as usize].xyz()), - planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()), - planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), - planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), - planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Bottom as usize].xyz()), - planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()), - planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), - planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), - planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()), - planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), - planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), - planes[FrustumPlane::Top as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()), - planes[FrustumPlane::Top as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), - planes[FrustumPlane::Near as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()), + Vec3A::from(planes[FrustumPlane::Left as usize]).cross(planes[FrustumPlane::Right as usize].into()), + Vec3A::from(planes[FrustumPlane::Left as usize]).cross(planes[FrustumPlane::Bottom as usize].into()), + Vec3A::from(planes[FrustumPlane::Left as usize]).cross(planes[FrustumPlane::Top as usize].into()), + Vec3A::from(planes[FrustumPlane::Left as usize]).cross(planes[FrustumPlane::Near as usize].into()), + Vec3A::from(planes[FrustumPlane::Left as usize]).cross(planes[FrustumPlane::Far as usize].into()), + Vec3A::from(planes[FrustumPlane::Right as usize]).cross(planes[FrustumPlane::Bottom as usize].into()), + Vec3A::from(planes[FrustumPlane::Right as usize]).cross(planes[FrustumPlane::Top as usize].into()), + Vec3A::from(planes[FrustumPlane::Right as usize]).cross(planes[FrustumPlane::Near as usize].into()), + Vec3A::from(planes[FrustumPlane::Right as usize]).cross(planes[FrustumPlane::Far as usize].into()), + Vec3A::from(planes[FrustumPlane::Bottom as usize]).cross(planes[FrustumPlane::Top as usize].into()), + Vec3A::from(planes[FrustumPlane::Bottom as usize]).cross(planes[FrustumPlane::Near as usize].into()), + Vec3A::from(planes[FrustumPlane::Bottom as usize]).cross(planes[FrustumPlane::Far as usize].into()), + Vec3A::from(planes[FrustumPlane::Top as usize]).cross(planes[FrustumPlane::Near as usize].into()), + Vec3A::from(planes[FrustumPlane::Top as usize]).cross(planes[FrustumPlane::Far as usize].into()), + Vec3A::from(planes[FrustumPlane::Near as usize]).cross(planes[FrustumPlane::Far as usize].into()), ]; - - Self { planes, crosses } + + //compute points + let points = [ + intersection::<{FrustumPlane::Left as usize}, {FrustumPlane::Bottom as usize}, {FrustumPlane::Near as usize}>(&planes, &crosses), + intersection::<{FrustumPlane::Left as usize}, {FrustumPlane::Top as usize}, {FrustumPlane::Near as usize}>(&planes, &crosses), + intersection::<{FrustumPlane::Right as usize}, {FrustumPlane::Bottom as usize}, {FrustumPlane::Near as usize}>(&planes, &crosses), + intersection::<{FrustumPlane::Right as usize}, {FrustumPlane::Top as usize}, {FrustumPlane::Near as usize}>(&planes, &crosses), + intersection::<{FrustumPlane::Left as usize}, {FrustumPlane::Bottom as usize}, {FrustumPlane::Far as usize}>(&planes, &crosses), + intersection::<{FrustumPlane::Left as usize}, {FrustumPlane::Top as usize}, {FrustumPlane::Far as usize}>(&planes, &crosses), + intersection::<{FrustumPlane::Right as usize}, {FrustumPlane::Bottom as usize}, {FrustumPlane::Far as usize}>(&planes, &crosses), + intersection::<{FrustumPlane::Right as usize}, {FrustumPlane::Top as usize}, {FrustumPlane::Far as usize}>(&planes, &crosses), + ]; + + Self { planes, points } } } + + +const fn ij2k() -> usize { + I * (9 - I) / 2 + J - 1 +} +fn intersection(planes: &[Vec4; PLANE_COUNT], crosses: &[Vec3A; PLANE_COMBINATIONS]) -> Vec3A { + let d = Vec3A::from(planes[A]).dot(crosses[ij2k::()]); + let res = Mat3A::from_cols( + crosses[ij2k::()], + crosses[ij2k::()], + crosses[ij2k::()], + ) * vec3a(planes[A].w, planes[B].w, planes[C].w); + res * (-1. / d) +} From 1f1b3379880a4cb3000eb6906cd69818907f2c0b Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 21:50:33 +0100 Subject: [PATCH 58/81] frustum culling impl --- src/camera.rs | 5 ++++ src/camera/frustum.rs | 69 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 7f6c83b..3da67c3 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -6,11 +6,13 @@ mod matrices; mod frustum; use matrices::update_matrices; +use frustum::{Frustum, update_frustum}; #[derive(Component)] pub struct Camera { pub view_matrix: Mat4, pub perspective_matrix: Mat4, + pub frustum: Frustum, pub up: Vec3, pub fov: f32, pub z_near: f32, @@ -20,8 +22,10 @@ impl Camera { pub fn new(fov: f32, z_near: f32, z_far: f32, up: Vec3) -> Self { Self { fov, z_near, z_far, up, + //TODO maybe separate this? perspective_matrix: Mat4::default(), view_matrix: Mat4::default(), + frustum: Frustum::default(), } } } @@ -34,5 +38,6 @@ impl Default for Camera { pub fn compute_cameras() -> Workload { ( update_matrices, + update_frustum, ).into_workload() } diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs index 22708fa..259b211 100644 --- a/src/camera/frustum.rs +++ b/src/camera/frustum.rs @@ -7,11 +7,10 @@ // [ http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm ] // three layers of stolen code, yay! -use glam::{Vec3A, Vec4, Mat3A, vec3a}; - +use glam::{Vec3A, Vec4, Mat3A, vec3a, Vec3, vec4}; +use shipyard::{ViewMut, IntoIter}; use super::Camera; - #[repr(usize)] enum FrustumPlane { Left, @@ -26,7 +25,8 @@ const PLANE_COUNT: usize = 6; const PLANE_COMBINATIONS: usize = PLANE_COUNT * (PLANE_COUNT - 1) / 2; const POINT_COUNT: usize = 8; -struct Frustum { +#[derive(Default)] +pub struct Frustum { planes: [Vec4; PLANE_COUNT], points: [Vec3A; POINT_COUNT] } @@ -77,8 +77,59 @@ impl Frustum { Self { planes, points } } -} + //this may be broken + pub fn intersect_box(&self, minp: Vec3, maxp: Vec3) -> bool { + // check box outside/inside of frustum + for i in 0..PLANE_COUNT { + if self.planes[i].dot(vec4(minp.x, minp.y, minp.z, 1.)) < 0. && + self.planes[i].dot(vec4(maxp.x, minp.y, minp.z, 1.)) < 0. && + self.planes[i].dot(vec4(minp.x, maxp.y, minp.z, 1.)) < 0. && + self.planes[i].dot(vec4(maxp.x, maxp.y, minp.z, 1.)) < 0. && + self.planes[i].dot(vec4(minp.x, minp.y, maxp.z, 1.)) < 0. && + self.planes[i].dot(vec4(maxp.x, minp.y, maxp.z, 1.)) < 0. && + self.planes[i].dot(vec4(minp.x, maxp.y, maxp.z, 1.)) < 0. && + self.planes[i].dot(vec4(maxp.x, maxp.y, maxp.z, 1.)) < 0. + { + return false + } + } + + // check frustum outside/inside box + let mut out: u8 = 0; + for i in 0..POINT_COUNT { + out += (self.points[i].x > maxp.x) as u8; + if out == 8 { return false } + } + let mut out: u8 = 0; + for i in 0..POINT_COUNT { + out += (self.points[i].x < minp.x) as u8; + if out == 8 { return false } + } + let mut out: u8 = 0; + for i in 0..POINT_COUNT { + out += (self.points[i].y > maxp.y) as u8; + if out == 8 { return false } + } + let mut out: u8 = 0; + for i in 0..POINT_COUNT { + out += (self.points[i].y < minp.y) as u8; + if out == 8 { return false } + } + let mut out: u8 = 0; + for i in 0..POINT_COUNT { + out += (self.points[i].z > maxp.z) as u8; + if out == 8 { return false } + } + let mut out: u8 = 0; + for i in 0..POINT_COUNT { + out += (self.points[i].z < minp.z) as u8; + if out == 8 { return false } + } + + true + } +} const fn ij2k() -> usize { I * (9 - I) / 2 + J - 1 @@ -92,3 +143,11 @@ fn intersection(planes: &[Vec4; ) * vec3a(planes[A].w, planes[B].w, planes[C].w); res * (-1. / d) } + +pub fn update_frustum( + mut cameras: ViewMut, +) { + for camera in (&mut cameras).iter() { + camera.frustum = Frustum::compute(camera); + } +} From 5b4f54a19ed72c0e5a734ff81b9dc8a4835b7a6b Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 22:01:51 +0100 Subject: [PATCH 59/81] wip culling --- shaders/world.frag | 5 +++++ src/camera/frustum.rs | 2 +- src/world/render.rs | 14 ++++---------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/shaders/world.frag b/shaders/world.frag index e07b5e1..017c5e1 100644 --- a/shaders/world.frag +++ b/shaders/world.frag @@ -5,6 +5,7 @@ in vec2 v_uv; flat in uint v_tex_index; out vec4 color; uniform sampler2DArray tex; +uniform bool debug; void main() { // base color from texture @@ -12,4 +13,8 @@ void main() { //basic "lighting" float light = abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z); color *= vec4(vec3(light), 1.); + //highlight + if (debug) { + color *= vec4(1., 0., 0., 1.); + } } diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs index 259b211..78f97c6 100644 --- a/src/camera/frustum.rs +++ b/src/camera/frustum.rs @@ -79,7 +79,7 @@ impl Frustum { } //this may be broken - pub fn intersect_box(&self, minp: Vec3, maxp: Vec3) -> bool { + pub fn is_box_visible(&self, minp: Vec3, maxp: Vec3) -> bool { // check box outside/inside of frustum for i in 0..PLANE_COUNT { if self.planes[i].dot(vec4(minp.x, minp.y, minp.z, 1.)) < 0. && diff --git a/src/world/render.rs b/src/world/render.rs index ec1460b..99ad9ad 100644 --- a/src/world/render.rs +++ b/src/world/render.rs @@ -69,22 +69,15 @@ pub fn draw_world( }); let view = camera.view_matrix.to_cols_array_2d(); let perspective = camera.perspective_matrix.to_cols_array_2d(); - let camera_mat = camera.perspective_matrix * camera.view_matrix; for (&position, chunk) in &chunks.chunks { if let Some(key) = chunk.mesh_index { let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); - let world_position = position.as_vec3a() * CHUNK_SIZE as f32; + let world_position = position.as_vec3() * CHUNK_SIZE as f32; if mesh.index_buffer.len() == 0 { continue } - - //basic culling - // let chunk_center = world_position + Vec3A::splat(CHUNK_SIZE as f32) * 0.5; - // let cull_point = camera_mat * chunk_center.extend(1.); - // if (cull_point.xyz() / cull_point.w).abs().cmpgt(Vec3::splat(1.)).any() { - // continue - // } + let debug = !camera.frustum.is_box_visible(world_position, world_position + Vec3::splat(CHUNK_SIZE as f32)); target.0.draw( &mesh.vertex_buffer, @@ -94,7 +87,8 @@ pub fn draw_world( position_offset: world_position.to_array(), view: view, perspective: perspective, - tex: texture_sampler + tex: texture_sampler, + debug: debug }, &draw_parameters ).unwrap(); From fe5bafdd35101a9dba92c4a532cf1b33c17fc1ac Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 22:17:30 +0100 Subject: [PATCH 60/81] fix --- src/camera/frustum.rs | 62 +++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs index 78f97c6..9a91c5e 100644 --- a/src/camera/frustum.rs +++ b/src/camera/frustum.rs @@ -78,18 +78,17 @@ impl Frustum { Self { planes, points } } - //this may be broken pub fn is_box_visible(&self, minp: Vec3, maxp: Vec3) -> bool { // check box outside/inside of frustum - for i in 0..PLANE_COUNT { - if self.planes[i].dot(vec4(minp.x, minp.y, minp.z, 1.)) < 0. && - self.planes[i].dot(vec4(maxp.x, minp.y, minp.z, 1.)) < 0. && - self.planes[i].dot(vec4(minp.x, maxp.y, minp.z, 1.)) < 0. && - self.planes[i].dot(vec4(maxp.x, maxp.y, minp.z, 1.)) < 0. && - self.planes[i].dot(vec4(minp.x, minp.y, maxp.z, 1.)) < 0. && - self.planes[i].dot(vec4(maxp.x, minp.y, maxp.z, 1.)) < 0. && - self.planes[i].dot(vec4(minp.x, maxp.y, maxp.z, 1.)) < 0. && - self.planes[i].dot(vec4(maxp.x, maxp.y, maxp.z, 1.)) < 0. + for plane in self.planes { + if (plane.dot(vec4(minp.x, minp.y, minp.z, 1.)) < 0.) && + (plane.dot(vec4(maxp.x, minp.y, minp.z, 1.)) < 0.) && + (plane.dot(vec4(minp.x, maxp.y, minp.z, 1.)) < 0.) && + (plane.dot(vec4(maxp.x, maxp.y, minp.z, 1.)) < 0.) && + (plane.dot(vec4(minp.x, minp.y, maxp.z, 1.)) < 0.) && + (plane.dot(vec4(maxp.x, minp.y, maxp.z, 1.)) < 0.) && + (plane.dot(vec4(minp.x, maxp.y, maxp.z, 1.)) < 0.) && + (plane.dot(vec4(maxp.x, maxp.y, maxp.z, 1.)) < 0.) { return false } @@ -97,35 +96,40 @@ impl Frustum { // check frustum outside/inside box let mut out: u8 = 0; - for i in 0..POINT_COUNT { - out += (self.points[i].x > maxp.x) as u8; - if out == 8 { return false } + for point in self.points { + out += (point.x > maxp.x) as u8; } + if out == 8 { return false } + let mut out: u8 = 0; - for i in 0..POINT_COUNT { - out += (self.points[i].x < minp.x) as u8; - if out == 8 { return false } + for point in self.points { + out += (point.x < minp.x) as u8; } + if out == 8 { return false } + let mut out: u8 = 0; - for i in 0..POINT_COUNT { - out += (self.points[i].y > maxp.y) as u8; - if out == 8 { return false } + for point in self.points { + out += (point.y > maxp.y) as u8; } + if out == 8 { return false } + let mut out: u8 = 0; - for i in 0..POINT_COUNT { - out += (self.points[i].y < minp.y) as u8; - if out == 8 { return false } + for point in self.points { + out += (point.y < minp.y) as u8; } + if out == 8 { return false } + let mut out: u8 = 0; - for i in 0..POINT_COUNT { - out += (self.points[i].z > maxp.z) as u8; - if out == 8 { return false } + for point in self.points { + out += (point.z > maxp.z) as u8; } + if out == 8 { return false } + let mut out: u8 = 0; - for i in 0..POINT_COUNT { - out += (self.points[i].z < minp.z) as u8; - if out == 8 { return false } + for point in self.points { + out += (point.z < minp.z) as u8; } + if out == 8 { return false } true } @@ -138,7 +142,7 @@ fn intersection(planes: &[Vec4; let d = Vec3A::from(planes[A]).dot(crosses[ij2k::()]); let res = Mat3A::from_cols( crosses[ij2k::()], - crosses[ij2k::()], + -crosses[ij2k::()], crosses[ij2k::()], ) * vec3a(planes[A].w, planes[B].w, planes[C].w); res * (-1. / d) From 4c2a29e0a314eeca7b1487f5bb173387969fae73 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 22:22:49 +0100 Subject: [PATCH 61/81] enable frustum culling! --- shaders/world.frag | 5 ----- src/world/render.rs | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/shaders/world.frag b/shaders/world.frag index 017c5e1..e07b5e1 100644 --- a/shaders/world.frag +++ b/shaders/world.frag @@ -5,7 +5,6 @@ in vec2 v_uv; flat in uint v_tex_index; out vec4 color; uniform sampler2DArray tex; -uniform bool debug; void main() { // base color from texture @@ -13,8 +12,4 @@ void main() { //basic "lighting" float light = abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z); color *= vec4(vec3(light), 1.); - //highlight - if (debug) { - color *= vec4(1., 0., 0., 1.); - } } diff --git a/src/world/render.rs b/src/world/render.rs index 99ad9ad..3cda8fc 100644 --- a/src/world/render.rs +++ b/src/world/render.rs @@ -74,11 +74,22 @@ pub fn draw_world( if let Some(key) = chunk.mesh_index { let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); let world_position = position.as_vec3() * CHUNK_SIZE as f32; + + //Skip mesh if its empty if mesh.index_buffer.len() == 0 { continue } - let debug = !camera.frustum.is_box_visible(world_position, world_position + Vec3::splat(CHUNK_SIZE as f32)); + //Frustum culling + { + let minp = world_position; + let maxp = world_position + Vec3::splat(CHUNK_SIZE as f32); + if !camera.frustum.is_box_visible(minp, maxp) { + continue + } + } + + //Draw chunk mesh target.0.draw( &mesh.vertex_buffer, &mesh.index_buffer, @@ -88,7 +99,6 @@ pub fn draw_world( view: view, perspective: perspective, tex: texture_sampler, - debug: debug }, &draw_parameters ).unwrap(); From d9ab57ba12031264693f79db3bf6978172459197 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 22:27:48 +0100 Subject: [PATCH 62/81] Mouse sensitivity is now affected by delta time --- src/fly_controller.rs | 5 +++-- src/settings.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fly_controller.rs b/src/fly_controller.rs index 4da9593..a8972ea 100644 --- a/src/fly_controller.rs +++ b/src/fly_controller.rs @@ -19,9 +19,10 @@ fn update_look( controllers: View, mut transforms: ViewMut, inputs: UniqueView, - settings: UniqueView + settings: UniqueView, + dt: UniqueView, ) { - let look = inputs.look * settings.mouse_sensitivity; + let look = inputs.look * settings.mouse_sensitivity * dt.0.as_secs_f32(); if look == Vec2::ZERO { return } for (_, mut transform) in (&controllers, &mut transforms).iter() { let (scale, mut rotation, translation) = transform.0.to_scale_rotation_translation(); diff --git a/src/settings.rs b/src/settings.rs index 0588cf8..5e80b67 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -10,7 +10,7 @@ impl Default for GameSettings { fn default() -> Self { Self { render_distance: 5, - mouse_sensitivity: 0.01, + mouse_sensitivity: 1., } } } From 16bc214628360413d2f790125410684736dbb3ee Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 22:32:23 +0100 Subject: [PATCH 63/81] reenable worldgen --- src/world/worldgen.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index 3718009..7101ceb 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -13,26 +13,26 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); - blocks[0][0][0] = Block::Stone; - blocks[0][CHUNK_SIZE - 1][0] = Block::Stone; - blocks[CHUNK_SIZE - 1][0][0] = Block::Stone; - blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][0] = Block::Stone; - blocks[0][0][CHUNK_SIZE - 1] = Block::Stone; - blocks[0][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; - blocks[CHUNK_SIZE - 1][0][CHUNK_SIZE - 1] = Block::Stone; - blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; + // blocks[0][0][0] = Block::Stone; + // blocks[0][CHUNK_SIZE - 1][0] = Block::Stone; + // blocks[CHUNK_SIZE - 1][0][0] = Block::Stone; + // blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][0] = Block::Stone; + // blocks[0][0][CHUNK_SIZE - 1] = Block::Stone; + // blocks[0][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; + // blocks[CHUNK_SIZE - 1][0][CHUNK_SIZE - 1] = Block::Stone; + // blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; - // for x in 0..CHUNK_SIZE { - // for y in 0..CHUNK_SIZE { - // for z in 0..CHUNK_SIZE { - // let position = ivec3(x as i32, y as i32, z as i32) + offset; - // let noise = noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32); - // if (0.7..0.8).contains(&noise) { - // blocks[x][y][z] = Block::Stone; - // } - // } - // } - // } + for x in 0..CHUNK_SIZE { + for y in 0..CHUNK_SIZE { + for z in 0..CHUNK_SIZE { + let position = ivec3(x as i32, y as i32, z as i32) + offset; + let noise = noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32); + if (0.7..0.8).contains(&noise) { + blocks[x][y][z] = Block::Stone; + } + } + } + } blocks } From 158639d3b7f5be38073eeb0ef1fd5ade0fb9f72e Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 22:34:57 +0100 Subject: [PATCH 64/81] update frustum only if the camera moves --- src/camera/frustum.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs index 9a91c5e..af0d483 100644 --- a/src/camera/frustum.rs +++ b/src/camera/frustum.rs @@ -8,7 +8,8 @@ // three layers of stolen code, yay! use glam::{Vec3A, Vec4, Mat3A, vec3a, Vec3, vec4}; -use shipyard::{ViewMut, IntoIter}; +use shipyard::{ViewMut, IntoIter, View}; +use crate::transform::Transform; use super::Camera; #[repr(usize)] @@ -150,8 +151,9 @@ fn intersection(planes: &[Vec4; pub fn update_frustum( mut cameras: ViewMut, + transforms: View ) { - for camera in (&mut cameras).iter() { + for (camera, _) in (&mut cameras, transforms.inserted_or_modified()).iter() { camera.frustum = Frustum::compute(camera); } } From a9666062eca5ff79cec5da0f530b2e0e4ce7c231 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 27 Jan 2023 22:41:33 +0100 Subject: [PATCH 65/81] refactor part of the cube frustum culling code --- src/camera/frustum.rs | 43 +++++++------------------------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs index af0d483..8143215 100644 --- a/src/camera/frustum.rs +++ b/src/camera/frustum.rs @@ -96,42 +96,13 @@ impl Frustum { } // check frustum outside/inside box - let mut out: u8 = 0; - for point in self.points { - out += (point.x > maxp.x) as u8; - } - if out == 8 { return false } - - let mut out: u8 = 0; - for point in self.points { - out += (point.x < minp.x) as u8; - } - if out == 8 { return false } - - let mut out: u8 = 0; - for point in self.points { - out += (point.y > maxp.y) as u8; - } - if out == 8 { return false } - - let mut out: u8 = 0; - for point in self.points { - out += (point.y < minp.y) as u8; - } - if out == 8 { return false } - - let mut out: u8 = 0; - for point in self.points { - out += (point.z > maxp.z) as u8; - } - if out == 8 { return false } - - let mut out: u8 = 0; - for point in self.points { - out += (point.z < minp.z) as u8; - } - if out == 8 { return false } - + if self.points.iter().all(|point| point.x > maxp.x) { return false } + if self.points.iter().all(|point| point.x < minp.x) { return false } + if self.points.iter().all(|point| point.y > maxp.y) { return false } + if self.points.iter().all(|point| point.y < minp.y) { return false } + if self.points.iter().all(|point| point.z > maxp.z) { return false } + if self.points.iter().all(|point| point.z < minp.z) { return false } + true } } From 3b36990d32d9870ef3e2621c97858006ddf501d5 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 04:20:51 +0100 Subject: [PATCH 66/81] raycasts, refactor --- src/input.rs | 9 +++- src/main.rs | 19 ++++++- src/player.rs | 42 +++++----------- src/rendering.rs | 3 ++ src/rendering/selection_box.rs | 18 +++++++ src/{world/render.rs => rendering/world.rs} | 2 +- src/world.rs | 28 ++++++++++- src/world/chunk.rs | 3 +- src/world/loading.rs | 4 +- src/world/mesh.rs | 3 +- src/world/raycast.rs | 55 +++++++++++++++++++++ src/world/tasks.rs | 2 +- 12 files changed, 147 insertions(+), 41 deletions(-) create mode 100644 src/rendering/selection_box.rs rename src/{world/render.rs => rendering/world.rs} (99%) create mode 100644 src/world/raycast.rs diff --git a/src/input.rs b/src/input.rs index cff8084..522b569 100644 --- a/src/input.rs +++ b/src/input.rs @@ -16,6 +16,7 @@ pub struct Inputs { #[derive(Unique, Clone, Default, Debug)] pub struct RawInputState { pub keyboard_state: HashSet>, + pub button_state: [bool; 32], pub mouse_delta: DVec2 } @@ -37,8 +38,10 @@ pub fn process_events( }; } }, - DeviceEvent::Button { button: _, state: _ } => { - //log::debug!("Button {button} {state:?}"); + DeviceEvent::Button { button, state } => { + if button < 32 { + input_state.button_state[button as usize] = matches!(state, ElementState::Pressed); + } }, _ => () } @@ -56,6 +59,8 @@ pub fn update_input_states ( raw_inputs.keyboard_state.contains(&VirtualKeyCode::S) as u32 as f32 ).normalize_or_zero(); inputs.look = raw_inputs.mouse_delta.as_vec2(); + inputs.action_a = raw_inputs.button_state[1]; + inputs.action_b = raw_inputs.button_state[3]; } pub fn init_input ( diff --git a/src/main.rs b/src/main.rs index e4cec44..aa72591 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use glam::vec3; use std::time::{Instant, Duration}; mod logging; + pub(crate) mod rendering; pub(crate) mod world; pub(crate) mod player; @@ -24,8 +25,17 @@ pub(crate) mod events; pub(crate) mod input; pub(crate) mod fly_controller; -use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background}; -use world::{loading::update_loaded_world_around_player, render::draw_world, init_game_world}; +use rendering::{ + Renderer, + RenderTarget, + BackgroundColor, + clear_background +}; +use world::{ + init_game_world, + loading::update_loaded_world_around_player, + raycast::update_player_raycast +}; use player::spawn_player; use prefabs::load_prefabs; use settings::GameSettings; @@ -33,6 +43,10 @@ use camera::compute_cameras; use events::{clear_events, process_glutin_events}; use input::{init_input, process_inputs}; use fly_controller::update_controllers; +use rendering::{ + selection_box::render_selection_box, + world::draw_world, +}; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); @@ -50,6 +64,7 @@ fn update() -> Workload { process_inputs, update_controllers, update_loaded_world_around_player, + update_player_raycast, compute_cameras ).into_workload() } diff --git a/src/player.rs b/src/player.rs index 88ce652..4a2fbc1 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,14 +1,12 @@ use glam::Mat4; -use shipyard::{Component, EntitiesViewMut, ViewMut}; +use shipyard::{Component, AllStoragesViewMut}; use crate::{ transform::Transform, camera::Camera, - fly_controller::FlyController, + fly_controller::FlyController, + world::raycast::LookingAtBlock, }; -#[derive(Component)] -pub struct LocalPlayer; - #[derive(Component)] pub struct Player; @@ -16,31 +14,15 @@ pub struct Player; pub struct MainPlayer; pub fn spawn_player ( - mut entities: EntitiesViewMut, - mut vm_player: ViewMut, - mut vm_main_player: ViewMut, - mut vm_local_player: ViewMut, - mut vm_transform: ViewMut, - mut vm_camera: ViewMut, - mut vm_controls: ViewMut, + mut storages: AllStoragesViewMut ) { log::info!("spawning player"); - entities.add_entity( - ( - &mut vm_player, - &mut vm_main_player, - &mut vm_local_player, - &mut vm_transform, - &mut vm_camera, - &mut vm_controls - ), - ( - Player, - MainPlayer, - LocalPlayer, - Transform(Mat4::default()), - Camera::default(), - FlyController - ) - ); + storages.add_entity(( + Player, + MainPlayer, + Transform::default(), + Camera::default(), + FlyController, + LookingAtBlock::default(), + )); } diff --git a/src/rendering.rs b/src/rendering.rs index 2bf0517..7a42932 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -9,6 +9,9 @@ use glium::{ }; use glam::Vec3; +pub mod world; +pub mod selection_box; + #[derive(Unique)] pub struct RenderTarget(pub glium::Frame); diff --git a/src/rendering/selection_box.rs b/src/rendering/selection_box.rs new file mode 100644 index 0000000..4871bf2 --- /dev/null +++ b/src/rendering/selection_box.rs @@ -0,0 +1,18 @@ +use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut}; +use crate::{ + player::MainPlayer, + world::raycast::LookingAtBlock, + camera::Camera +}; +use super::RenderTarget; + +//wip +pub fn render_selection_box( + lookat: View, + camera: View, + mut target: NonSendSync>, +) { + for lookat in lookat.iter() { + + } +} diff --git a/src/world/render.rs b/src/rendering/world.rs similarity index 99% rename from src/world/render.rs rename to src/rendering/world.rs index 3cda8fc..26f8822 100644 --- a/src/world/render.rs +++ b/src/rendering/world.rs @@ -19,7 +19,6 @@ use glium::{ }; use crate::{ camera::Camera, - rendering::RenderTarget, prefabs::{ ChunkShaderPrefab, BlockTexturesPrefab, @@ -30,6 +29,7 @@ use crate::{ chunk::CHUNK_SIZE, }, }; +use super::RenderTarget; #[derive(Clone, Copy)] pub struct ChunkVertex { diff --git a/src/world.rs b/src/world.rs index 2f3ace1..a52c55a 100644 --- a/src/world.rs +++ b/src/world.rs @@ -6,16 +6,18 @@ use anyhow::{Result, Context}; pub mod chunk; pub mod block; -pub mod render; pub mod tasks; pub mod loading; pub mod mesh; pub mod neighbors; pub mod worldgen; +pub mod raycast; use chunk::{Chunk, ChunkMesh}; use tasks::ChunkTaskManager; +use self::{chunk::CHUNK_SIZE, block::Block}; + //TODO separate world struct for render data // because this is not send-sync @@ -25,6 +27,30 @@ pub struct ChunkStorage { pub chunks: HashMap } impl ChunkStorage { + pub const fn to_chunk_coords(position: IVec3) -> (IVec3, IVec3) { + ( + IVec3::new( + position.x.div_euclid(CHUNK_SIZE as i32), + position.y.div_euclid(CHUNK_SIZE as i32), + position.z.div_euclid(CHUNK_SIZE as i32), + ), + IVec3::new( + position.x.rem_euclid(CHUNK_SIZE as i32), + position.y.rem_euclid(CHUNK_SIZE as i32), + position.z.rem_euclid(CHUNK_SIZE as i32), + ) + ) + } + pub fn get_block(&self, position: IVec3) -> Option { + let (chunk, block) = Self::to_chunk_coords(position); + let block = self.chunks + .get(&chunk)? + .block_data.as_ref()? + .blocks.get(block.x as usize)? + .get(block.y as usize)? + .get(block.z as usize)?; + Some(*block) + } pub fn new() -> Self { Self::default() } diff --git a/src/world/chunk.rs b/src/world/chunk.rs index 20e91e5..ba46819 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -1,6 +1,7 @@ use glam::IVec3; use glium::{VertexBuffer, IndexBuffer}; -use super::{block::Block, render::ChunkVertex}; +use super::block::Block; +use crate::rendering::world::ChunkVertex; pub const CHUNK_SIZE: usize = 32; diff --git a/src/world/loading.rs b/src/world/loading.rs index 226b6e3..498c3af 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -2,7 +2,7 @@ use glam::{IVec3, ivec3}; use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType}; use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync}; use crate::{ - player::LocalPlayer, + player::MainPlayer, transform::Transform, settings::GameSettings, rendering::Renderer @@ -27,7 +27,7 @@ pub fn update_loaded_world_around_player() -> Workload { pub fn update_chunks_if_player_moved( v_settings: UniqueView, - v_local_player: View, + v_local_player: View, v_transform: View, mut vm_world: UniqueViewMut, ) { diff --git a/src/world/mesh.rs b/src/world/mesh.rs index 6d6b6f2..69018dc 100644 --- a/src/world/mesh.rs +++ b/src/world/mesh.rs @@ -1,6 +1,7 @@ use strum::{EnumIter, IntoEnumIterator}; use glam::{Vec3A, vec3a, IVec3, ivec3}; -use super::{render::ChunkVertex, chunk::CHUNK_SIZE, block::{Block, RenderType}}; +use super::{chunk::CHUNK_SIZE, block::{Block, RenderType}}; +use crate::rendering::world::ChunkVertex; pub mod data; use data::MeshGenData; diff --git a/src/world/raycast.rs b/src/world/raycast.rs new file mode 100644 index 0000000..303df3e --- /dev/null +++ b/src/world/raycast.rs @@ -0,0 +1,55 @@ +use glam::{Vec3, IVec3}; +use shipyard::{View, Component, ViewMut, IntoIter, UniqueView}; +use crate::{player::MainPlayer, transform::Transform}; + +use super::{ChunkStorage, block::Block}; + +const RAYCAST_STEP: f32 = 0.25; + +#[derive(Clone, Copy, Debug)] +pub struct RaycastReport { + pub length: f32, + pub position: Vec3, + pub block_position: IVec3, + pub block: Block, +} + +impl ChunkStorage { + //this is probably pretty slow... + pub fn raycast(&self, origin: Vec3, direction: Vec3, limit: Option) -> Option { + debug_assert!(direction.is_normalized(), "Ray direction not normalized"); + let mut position = origin; + let mut length = 0.; + loop { + let block_position = position.floor().as_ivec3(); + if let Some(block) = self.get_block(block_position) { + if block.descriptor().raycast_collision { + return Some(RaycastReport { length, position, block_position, block }); + } + } + length += RAYCAST_STEP; + position += direction * RAYCAST_STEP; + if let Some(limit) = limit { + if length > limit { + return None; + } + } + } + } +} + +#[derive(Component, Clone, Copy, Debug, Default)] +pub struct LookingAtBlock(pub Option); + +pub fn update_player_raycast( + main_player: View, + transform: View, + mut raycast: ViewMut, + world: UniqueView, +) { + for (_, transform, report) in (&main_player, transform.inserted_or_modified(), &mut raycast).iter() { + let (_, rotation, position) = transform.0.to_scale_rotation_translation(); + let direction = rotation * Vec3::NEG_Z; + *report = LookingAtBlock(world.raycast(position, direction, Some(10.))); + } +} diff --git a/src/world/tasks.rs b/src/world/tasks.rs index 61a1c8d..2c73c16 100644 --- a/src/world/tasks.rs +++ b/src/world/tasks.rs @@ -4,10 +4,10 @@ use shipyard::Unique; use rayon::{ThreadPool, ThreadPoolBuilder}; use super::{ chunk::BlockData, - render::ChunkVertex, mesh::{generate_mesh, data::MeshGenData}, worldgen::generate_world, }; +use crate::rendering::world::ChunkVertex; pub enum ChunkTask { LoadChunk { From b4462a0176c678770891bf468716933d623fc30a Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 04:26:47 +0100 Subject: [PATCH 67/81] wip --- src/rendering/selection_box.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/rendering/selection_box.rs b/src/rendering/selection_box.rs index 4871bf2..7d757f8 100644 --- a/src/rendering/selection_box.rs +++ b/src/rendering/selection_box.rs @@ -1,11 +1,13 @@ use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut}; +use glium::Surface; use crate::{ - player::MainPlayer, world::raycast::LookingAtBlock, camera::Camera }; use super::RenderTarget; +const CUBE_VERTICES: &[f32] = &[0.0]; + //wip pub fn render_selection_box( lookat: View, @@ -13,6 +15,17 @@ pub fn render_selection_box( mut target: NonSendSync>, ) { for lookat in lookat.iter() { - + // target.0.draw( + // &mesh.vertex_buffer, + // &mesh.index_buffer, + // &program.0, + // &uniform! { + // position_offset: world_position.to_array(), + // view: view, + // perspective: perspective, + // tex: texture_sampler, + // }, + // &draw_parameters + // ).unwrap(); } } From 2bb22ddaec02af1dcc026dcf37b0cd8a160703bf Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 04:35:55 +0100 Subject: [PATCH 68/81] wip selection box --- shaders/selection_box.frag | 8 ++++++++ shaders/selection_box.vert | 10 ++++++++++ src/prefabs.rs | 10 ++++++++++ src/rendering.rs | 1 + src/rendering/primitives.rs | 32 ++++++++++++++++++++++++++++++++ src/rendering/selection_box.rs | 8 ++++++-- 6 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 shaders/selection_box.frag create mode 100644 shaders/selection_box.vert create mode 100644 src/rendering/primitives.rs diff --git a/shaders/selection_box.frag b/shaders/selection_box.frag new file mode 100644 index 0000000..9b2ac94 --- /dev/null +++ b/shaders/selection_box.frag @@ -0,0 +1,8 @@ +#version 150 core + +out vec4 color; +uniform vec4 u_color; + +void main() { + color = u_color; +} diff --git a/shaders/selection_box.vert b/shaders/selection_box.vert new file mode 100644 index 0000000..7243a1f --- /dev/null +++ b/shaders/selection_box.vert @@ -0,0 +1,10 @@ +#version 150 core + +in vec3 position; +uniform vec3 u_position; +uniform mat4 perspective; +uniform mat4 view; + +void main() { + gl_Position = perspective * view * vec4(position + u_position, 1.); +} diff --git a/src/prefabs.rs b/src/prefabs.rs index fc1e075..793966e 100644 --- a/src/prefabs.rs +++ b/src/prefabs.rs @@ -56,6 +56,9 @@ pub struct BlockTexturesPrefab(pub SrgbTexture2dArray); #[derive(Unique)] pub struct ChunkShaderPrefab(pub Program); +#[derive(Unique)] +pub struct SelBoxShaderPrefab(pub Program); + pub fn load_prefabs( storages: AllStoragesView, renderer: NonSendSync> @@ -74,4 +77,11 @@ pub fn load_prefabs( &renderer.display ) )); + storages.add_unique_non_send_sync(SelBoxShaderPrefab( + include_shader_prefab!( + "../shaders/selection_box.vert", + "../shaders/selection_box.frag", + &renderer.display + ) + )); } diff --git a/src/rendering.rs b/src/rendering.rs index 7a42932..9389e76 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -9,6 +9,7 @@ use glium::{ }; use glam::Vec3; +pub mod primitives; pub mod world; pub mod selection_box; diff --git a/src/rendering/primitives.rs b/src/rendering/primitives.rs new file mode 100644 index 0000000..998ad16 --- /dev/null +++ b/src/rendering/primitives.rs @@ -0,0 +1,32 @@ +const CUBE_VERTICES: &[f32] = &[ + // front + -1.0, -1.0, 1.0, + 1.0, -1.0, 1.0, + 1.0, 1.0, 1.0, + -1.0, 1.0, 1.0, + // back + -1.0, -1.0, -1.0, + 1.0, -1.0, -1.0, + 1.0, 1.0, -1.0, + -1.0, 1.0, -1.0 +]; +const CUBE_INDICES: &[u16] = &[ + // front + 0, 1, 2, + 2, 3, 0, + // right + 1, 5, 6, + 6, 2, 1, + // back + 7, 6, 5, + 5, 4, 7, + // left + 4, 0, 3, + 3, 7, 4, + // bottom + 4, 5, 1, + 1, 0, 4, + // top + 3, 2, 6, + 6, 7, 3 +]; diff --git a/src/rendering/selection_box.rs b/src/rendering/selection_box.rs index 7d757f8..6301a0d 100644 --- a/src/rendering/selection_box.rs +++ b/src/rendering/selection_box.rs @@ -1,12 +1,16 @@ use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut}; -use glium::Surface; +use glium::{Surface, implement_vertex}; use crate::{ world::raycast::LookingAtBlock, camera::Camera }; use super::RenderTarget; -const CUBE_VERTICES: &[f32] = &[0.0]; +#[derive(Clone, Copy)] +pub struct SelBoxVertex { + pub position: [f32; 3], +} +implement_vertex!(SelBoxVertex, position); //wip pub fn render_selection_box( From a4f4a765ae84ef06803b5c9bb4c7f68343fbe91e Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 20:56:17 +0100 Subject: [PATCH 69/81] having issues with blending... --- src/main.rs | 1 + src/player.rs | 1 - src/rendering/primitives.rs | 20 ++++----- src/rendering/selection_box.rs | 79 ++++++++++++++++++++++++++-------- 4 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/main.rs b/src/main.rs index aa72591..7bfbd13 100644 --- a/src/main.rs +++ b/src/main.rs @@ -72,6 +72,7 @@ fn render() -> Workload { ( clear_background, draw_world, + render_selection_box, ).into_sequential_workload() } fn after_frame_end() -> Workload { diff --git a/src/player.rs b/src/player.rs index 4a2fbc1..a6afaed 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,4 +1,3 @@ -use glam::Mat4; use shipyard::{Component, AllStoragesViewMut}; use crate::{ transform::Transform, diff --git a/src/rendering/primitives.rs b/src/rendering/primitives.rs index 998ad16..7efa2e5 100644 --- a/src/rendering/primitives.rs +++ b/src/rendering/primitives.rs @@ -1,16 +1,16 @@ -const CUBE_VERTICES: &[f32] = &[ +pub const CUBE_VERTICES: &[f32] = &[ // front - -1.0, -1.0, 1.0, - 1.0, -1.0, 1.0, - 1.0, 1.0, 1.0, - -1.0, 1.0, 1.0, + 0.0, 0.0, 1.0, + 1.0, 0.0, 1.0, + 1.0, 1.0, 1.0, + 0.0, 1.0, 1.0, // back - -1.0, -1.0, -1.0, - 1.0, -1.0, -1.0, - 1.0, 1.0, -1.0, - -1.0, 1.0, -1.0 + 0.0, 0.0, 0.0, + 1.0, 0.0, 0.0, + 1.0, 1.0, 0.0, + 0.0, 1.0, 0.0 ]; -const CUBE_INDICES: &[u16] = &[ +pub const CUBE_INDICES: &[u16] = &[ // front 0, 1, 2, 2, 3, 0, diff --git a/src/rendering/selection_box.rs b/src/rendering/selection_box.rs index 6301a0d..a359163 100644 --- a/src/rendering/selection_box.rs +++ b/src/rendering/selection_box.rs @@ -1,35 +1,76 @@ -use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut}; -use glium::{Surface, implement_vertex}; +use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut, UniqueView}; +use glium::{Surface, implement_vertex, IndexBuffer, index::PrimitiveType, VertexBuffer, uniform, DrawParameters, Blend, BackfaceCullingMode}; use crate::{ world::raycast::LookingAtBlock, - camera::Camera + camera::Camera, prefabs::SelBoxShaderPrefab +}; +use super::{ + RenderTarget, + primitives::{CUBE_INDICES, CUBE_VERTICES}, Renderer }; -use super::RenderTarget; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct SelBoxVertex { pub position: [f32; 3], } implement_vertex!(SelBoxVertex, position); +const fn box_vertices() -> [SelBoxVertex; CUBE_VERTICES.len() / 3] { + let mut arr = [SelBoxVertex { position: [0., 0., 0.] }; CUBE_VERTICES.len() / 3]; + let mut ptr = 0; + loop { + arr[ptr] = SelBoxVertex { + position: [ + CUBE_VERTICES[ptr * 3], + CUBE_VERTICES[(ptr * 3) + 1], + CUBE_VERTICES[(ptr * 3) + 2] + ] + }; + ptr += 1; + if ptr >= CUBE_VERTICES.len() / 3 { + return arr + } + } +} +const BOX_VERTICES: &[SelBoxVertex] = &box_vertices(); + //wip pub fn render_selection_box( lookat: View, camera: View, mut target: NonSendSync>, + display: NonSendSync>, + program: NonSendSync>, ) { - for lookat in lookat.iter() { - // target.0.draw( - // &mesh.vertex_buffer, - // &mesh.index_buffer, - // &program.0, - // &uniform! { - // position_offset: world_position.to_array(), - // view: view, - // perspective: perspective, - // tex: texture_sampler, - // }, - // &draw_parameters - // ).unwrap(); - } + let camera = camera.iter().next().unwrap(); + let Some(lookat) = lookat.iter().next() else { return }; + let Some(lookat) = lookat.0 else { return }; + + //this may be slow but the amount of vertices is very low + let vert = VertexBuffer::new( + &display.display, + BOX_VERTICES + ).unwrap(); + let index = IndexBuffer::new( + &display.display, + PrimitiveType::TrianglesList, + CUBE_INDICES + ).unwrap(); + + target.0.draw( + &vert, + &index, + &program.0, + &uniform! { + color: [0., 0., 0., 0.5_f32], + u_position: lookat.block_position.as_vec3().to_array(), + perspective: camera.perspective_matrix.to_cols_array_2d(), + view: camera.view_matrix.to_cols_array_2d(), + }, + &DrawParameters { + blend: Blend::alpha_blending(), + backface_culling: BackfaceCullingMode::CullClockwise, + ..Default::default() + } + ).unwrap(); } From 0c25bfa5ae6ca541162f50b0a9250944e8213b35 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 21:28:25 +0100 Subject: [PATCH 70/81] selection kinda works --- src/rendering/selection_box.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/rendering/selection_box.rs b/src/rendering/selection_box.rs index a359163..88ac6c5 100644 --- a/src/rendering/selection_box.rs +++ b/src/rendering/selection_box.rs @@ -1,5 +1,14 @@ use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut, UniqueView}; -use glium::{Surface, implement_vertex, IndexBuffer, index::PrimitiveType, VertexBuffer, uniform, DrawParameters, Blend, BackfaceCullingMode}; +use glium::{ + Surface, + implement_vertex, + IndexBuffer, + index::PrimitiveType, + VertexBuffer, uniform, + DrawParameters, + BackfaceCullingMode, + PolygonMode, Blend, BlendingFunction, LinearBlendingFactor, Depth, DepthTest +}; use crate::{ world::raycast::LookingAtBlock, camera::Camera, prefabs::SelBoxShaderPrefab @@ -62,14 +71,29 @@ pub fn render_selection_box( &index, &program.0, &uniform! { - color: [0., 0., 0., 0.5_f32], + color: [0., 0., 0., 1.], u_position: lookat.block_position.as_vec3().to_array(), perspective: camera.perspective_matrix.to_cols_array_2d(), view: camera.view_matrix.to_cols_array_2d(), }, &DrawParameters { - blend: Blend::alpha_blending(), backface_culling: BackfaceCullingMode::CullClockwise, + blend: Blend { + //for some reason only constant alpha works??? + color: BlendingFunction::Addition { + source: LinearBlendingFactor::ConstantAlpha, + destination: LinearBlendingFactor::OneMinusConstantAlpha, + }, + alpha: BlendingFunction::Addition { + source: LinearBlendingFactor::ConstantAlpha, + destination: LinearBlendingFactor::OneMinusConstantAlpha + }, + constant_value: (0.0, 0.0, 0.0, 0.5) + }, + depth: Depth { + test: DepthTest::IfLessOrEqual, //this may be unreliable! + ..Default::default() + }, ..Default::default() } ).unwrap(); From 407f87aaaba285fb54e712b6052df89d4562dc85 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 21:30:51 +0100 Subject: [PATCH 71/81] increase player range --- src/world/raycast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/raycast.rs b/src/world/raycast.rs index 303df3e..c55e087 100644 --- a/src/world/raycast.rs +++ b/src/world/raycast.rs @@ -50,6 +50,6 @@ pub fn update_player_raycast( for (_, transform, report) in (&main_player, transform.inserted_or_modified(), &mut raycast).iter() { let (_, rotation, position) = transform.0.to_scale_rotation_translation(); let direction = rotation * Vec3::NEG_Z; - *report = LookingAtBlock(world.raycast(position, direction, Some(10.))); + *report = LookingAtBlock(world.raycast(position, direction, Some(30.))); } } From b8bbda4be81fd9cdf50b2c584b92a27781d9558c Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 21:34:11 +0100 Subject: [PATCH 72/81] better check --- src/world/mesh.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/world/mesh.rs b/src/world/mesh.rs index 69018dc..f991594 100644 --- a/src/world/mesh.rs +++ b/src/world/mesh.rs @@ -1,5 +1,6 @@ use strum::{EnumIter, IntoEnumIterator}; use glam::{Vec3A, vec3a, IVec3, ivec3}; +use std::mem::discriminant; use super::{chunk::CHUNK_SIZE, block::{Block, RenderType}}; use crate::rendering::world::ChunkVertex; @@ -111,7 +112,7 @@ pub fn generate_mesh(data: MeshGenData) -> (Vec, Vec) { for face in CubeFace::iter() { let facing = CUBE_FACE_NORMALS[face as usize].as_ivec3(); let facing_coord = coord + facing; - let show = matches!(get_block(facing_coord).descriptor().render, RenderType::None); + let show = discriminant(&get_block(facing_coord).descriptor().render) != discriminant(&descriptor.render); if show { match descriptor.render { RenderType::SolidBlock(textures) => { From f3e84599684e782ce636931f2c3271e6e5a786f1 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 21:37:00 +0100 Subject: [PATCH 73/81] generalize lookingat --- src/main.rs | 4 ++-- src/world/raycast.rs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7bfbd13..8d0edd9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,7 @@ use rendering::{ use world::{ init_game_world, loading::update_loaded_world_around_player, - raycast::update_player_raycast + raycast::update_raycasts }; use player::spawn_player; use prefabs::load_prefabs; @@ -64,7 +64,7 @@ fn update() -> Workload { process_inputs, update_controllers, update_loaded_world_around_player, - update_player_raycast, + update_raycasts, compute_cameras ).into_workload() } diff --git a/src/world/raycast.rs b/src/world/raycast.rs index c55e087..fb705ef 100644 --- a/src/world/raycast.rs +++ b/src/world/raycast.rs @@ -41,13 +41,12 @@ impl ChunkStorage { #[derive(Component, Clone, Copy, Debug, Default)] pub struct LookingAtBlock(pub Option); -pub fn update_player_raycast( - main_player: View, +pub fn update_raycasts( transform: View, mut raycast: ViewMut, world: UniqueView, ) { - for (_, transform, report) in (&main_player, transform.inserted_or_modified(), &mut raycast).iter() { + for (transform, report) in (transform.inserted_or_modified(), &mut raycast).iter() { let (_, rotation, position) = transform.0.to_scale_rotation_translation(); let direction = rotation * Vec3::NEG_Z; *report = LookingAtBlock(world.raycast(position, direction, Some(30.))); From c1cd48101bff06d300e1b1f41d7f610d433aea84 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 22:06:08 +0100 Subject: [PATCH 74/81] block breaking! --- src/camera/frustum.rs | 4 ++-- src/main.rs | 3 ++- src/rendering/selection_box.rs | 4 +++- src/rendering/world.rs | 2 +- src/world.rs | 10 ++++++++++ src/world/chunk.rs | 3 ++- src/world/loading.rs | 12 ++++++++---- src/world/raycast.rs | 28 +++++++++++++++++++++++++--- 8 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/camera/frustum.rs b/src/camera/frustum.rs index 8143215..9042dd4 100644 --- a/src/camera/frustum.rs +++ b/src/camera/frustum.rs @@ -111,8 +111,8 @@ const fn ij2k() -> usize { I * (9 - I) / 2 + J - 1 } fn intersection(planes: &[Vec4; PLANE_COUNT], crosses: &[Vec3A; PLANE_COMBINATIONS]) -> Vec3A { - let d = Vec3A::from(planes[A]).dot(crosses[ij2k::()]); - let res = Mat3A::from_cols( + let d = Vec3A::from(planes[A]).dot(crosses[ij2k::()]); + let res = Mat3A::from_cols( crosses[ij2k::()], -crosses[ij2k::()], crosses[ij2k::()], diff --git a/src/main.rs b/src/main.rs index 8d0edd9..2027324 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,7 @@ use rendering::{ use world::{ init_game_world, loading::update_loaded_world_around_player, - raycast::update_raycasts + raycast::{update_raycasts, break_block_test_only} }; use player::spawn_player; use prefabs::load_prefabs; @@ -65,6 +65,7 @@ fn update() -> Workload { update_controllers, update_loaded_world_around_player, update_raycasts, + break_block_test_only, compute_cameras ).into_workload() } diff --git a/src/rendering/selection_box.rs b/src/rendering/selection_box.rs index 88ac6c5..4a23eed 100644 --- a/src/rendering/selection_box.rs +++ b/src/rendering/selection_box.rs @@ -7,7 +7,9 @@ use glium::{ VertexBuffer, uniform, DrawParameters, BackfaceCullingMode, - PolygonMode, Blend, BlendingFunction, LinearBlendingFactor, Depth, DepthTest + Blend, BlendingFunction, + LinearBlendingFactor, + Depth, DepthTest, }; use crate::{ world::raycast::LookingAtBlock, diff --git a/src/rendering/world.rs b/src/rendering/world.rs index 26f8822..2cd543c 100644 --- a/src/rendering/world.rs +++ b/src/rendering/world.rs @@ -1,4 +1,4 @@ -use glam::{vec3a, Vec3A, Vec4Swizzles, Vec3}; +use glam::Vec3; use shipyard::{NonSendSync, UniqueView, UniqueViewMut, View, IntoIter}; use glium::{ implement_vertex, uniform, diff --git a/src/world.rs b/src/world.rs index a52c55a..ff75456 100644 --- a/src/world.rs +++ b/src/world.rs @@ -51,6 +51,16 @@ impl ChunkStorage { .get(block.z as usize)?; Some(*block) } + pub fn get_block_mut(&mut self, position: IVec3) -> Option<&mut Block> { + let (chunk, block) = Self::to_chunk_coords(position); + let block = self.chunks + .get_mut(&chunk)? + .block_data.as_mut()? + .blocks.get_mut(block.x as usize)? + .get_mut(block.y as usize)? + .get_mut(block.z as usize)?; + Some(block) + } pub fn new() -> Self { Self::default() } diff --git a/src/world/chunk.rs b/src/world/chunk.rs index ba46819..672d767 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -18,7 +18,6 @@ impl ChunkData { } pub struct ChunkMesh { - pub is_dirty: bool, pub vertex_buffer: VertexBuffer, pub index_buffer: IndexBuffer, } @@ -50,6 +49,7 @@ pub struct Chunk { pub mesh_index: Option, pub current_state: CurrentChunkState, pub desired_state: DesiredChunkState, + pub dirty: bool, } impl Chunk { pub fn new(position: IVec3) -> Self { @@ -59,6 +59,7 @@ impl Chunk { mesh_index: None, current_state: Default::default(), desired_state: Default::default(), + dirty: false, } } } diff --git a/src/world/loading.rs b/src/world/loading.rs index 498c3af..1a0af1c 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -95,7 +95,7 @@ fn unload_downgrade_chunks( false } else { match chunk.desired_state { - DesiredChunkState::Loaded if matches!(chunk.current_state, CurrentChunkState::Rendered | CurrentChunkState::CalculatingMesh) => { + DesiredChunkState::Loaded if matches!(chunk.current_state, CurrentChunkState::Rendered | CurrentChunkState::CalculatingMesh | CurrentChunkState::RecalculatingMesh) => { if let Some(mesh_index) = chunk.mesh_index { vm_meshes.remove(mesh_index).unwrap(); } @@ -133,7 +133,7 @@ fn start_required_tasks( // =========== //log::trace!("Started loading chunk {position}"); }, - DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Loaded => { + DesiredChunkState::Rendered if (chunk.current_state == CurrentChunkState::Loaded || chunk.dirty) => { //get needed data let Some(neighbors) = world.neighbors_all(position) else { continue @@ -145,7 +145,12 @@ fn start_required_tasks( task_manager.spawn_task(ChunkTask::GenerateMesh { data, position }); //Update chunk state let chunk = world.chunks.get_mut(&position).unwrap(); - chunk.current_state = CurrentChunkState::CalculatingMesh; + if chunk.dirty { + chunk.current_state = CurrentChunkState::RecalculatingMesh; + chunk.dirty = false; + } else { + chunk.current_state = CurrentChunkState::CalculatingMesh; + } // =========== //log::trace!("Started generating mesh for chunk {position}"); } @@ -201,7 +206,6 @@ fn process_completed_tasks( let vertex_buffer = VertexBuffer::new(&renderer.display, &vertices).unwrap(); let index_buffer = IndexBuffer::new(&renderer.display, PrimitiveType::TrianglesList, &indexes).unwrap(); let mesh_index = meshes.insert(ChunkMesh { - is_dirty: false, vertex_buffer, index_buffer, }); diff --git a/src/world/raycast.rs b/src/world/raycast.rs index fb705ef..8da93d6 100644 --- a/src/world/raycast.rs +++ b/src/world/raycast.rs @@ -1,6 +1,6 @@ use glam::{Vec3, IVec3}; -use shipyard::{View, Component, ViewMut, IntoIter, UniqueView}; -use crate::{player::MainPlayer, transform::Transform}; +use shipyard::{View, Component, ViewMut, IntoIter, UniqueView, UniqueViewMut}; +use crate::{player::MainPlayer, transform::Transform, input::Inputs}; use super::{ChunkStorage, block::Block}; @@ -46,9 +46,31 @@ pub fn update_raycasts( mut raycast: ViewMut, world: UniqueView, ) { - for (transform, report) in (transform.inserted_or_modified(), &mut raycast).iter() { + //idk if this check is even needed + if !(world.is_inserted_or_modified() || (transform.inserted_or_modified(), &raycast).iter().next().is_some()) { + return + } + for (transform, report) in (&transform, &mut raycast).iter() { let (_, rotation, position) = transform.0.to_scale_rotation_translation(); let direction = rotation * Vec3::NEG_Z; *report = LookingAtBlock(world.raycast(position, direction, Some(30.))); } } + +pub fn break_block_test_only( + raycast: View, + input: UniqueView, + mut world: UniqueViewMut +) { + if input.action_a { + //get raycast info + let Some(ray) = raycast.iter().next().unwrap().0 else { return }; + //update block + let Some(block) = world.get_block_mut(ray.block_position) else { return }; + *block = Block::Air; + //mark chunk as dirty + let (chunk_pos, _) = ChunkStorage::to_chunk_coords(ray.block_position); + let chunk = world.chunks.get_mut(&chunk_pos).unwrap(); + chunk.dirty = true; + } +} From 5f9f0ad72f471f20fdf4bef24fdd665023cc414f Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 22:27:40 +0100 Subject: [PATCH 75/81] update --- src/block_placement.rs | 36 ++++++++++++++++++++++++++++++++++++ src/main.rs | 6 ++++-- src/world/block.rs | 11 +++++------ src/world/loading.rs | 7 ++++++- src/world/raycast.rs | 31 ++++++++++--------------------- 5 files changed, 61 insertions(+), 30 deletions(-) create mode 100644 src/block_placement.rs diff --git a/src/block_placement.rs b/src/block_placement.rs new file mode 100644 index 0000000..725472f --- /dev/null +++ b/src/block_placement.rs @@ -0,0 +1,36 @@ +use glam::Vec3; +use shipyard::{UniqueViewMut, UniqueView, View, IntoIter}; +use crate::{ + player::MainPlayer, + world::{raycast::LookingAtBlock, ChunkStorage, block::Block}, + input::Inputs +}; + +pub fn block_placement_system( + main_player: View, + raycast: View, + input: UniqueView, + mut world: UniqueViewMut +) { + //this cant process both place and break btw + if input.action_a || input.action_b { + //get raycast info + let Some(ray) = (&main_player, &raycast).iter().next().unwrap().1/**/.0 else { return }; + //update block + let is_place = input.action_b; + let place_position = if is_place { + let position = (ray.position - ray.direction * 0.5).floor().as_ivec3(); + let Some(block) = world.get_block_mut(position) else { return }; + *block = Block::Dirt; + position + } else { + let Some(block) = world.get_block_mut(ray.block_position) else { return }; + *block = Block::Air; + ray.block_position + }; + //mark chunk as dirty + let (chunk_pos, _) = ChunkStorage::to_chunk_coords(place_position); + let chunk = world.chunks.get_mut(&chunk_pos).unwrap(); + chunk.dirty = true; + } +} diff --git a/src/main.rs b/src/main.rs index 2027324..2cda345 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ pub(crate) mod camera; pub(crate) mod events; pub(crate) mod input; pub(crate) mod fly_controller; +pub(crate) mod block_placement; use rendering::{ Renderer, @@ -34,7 +35,7 @@ use rendering::{ use world::{ init_game_world, loading::update_loaded_world_around_player, - raycast::{update_raycasts, break_block_test_only} + raycast::update_raycasts }; use player::spawn_player; use prefabs::load_prefabs; @@ -47,6 +48,7 @@ use rendering::{ selection_box::render_selection_box, world::draw_world, }; +use block_placement::block_placement_system; #[derive(Unique)] pub(crate) struct DeltaTime(Duration); @@ -65,7 +67,7 @@ fn update() -> Workload { update_controllers, update_loaded_world_around_player, update_raycasts, - break_block_test_only, + block_placement_system, compute_cameras ).into_workload() } diff --git a/src/world/block.rs b/src/world/block.rs index e16641c..92fba77 100644 --- a/src/world/block.rs +++ b/src/world/block.rs @@ -47,7 +47,6 @@ impl Block { collision: CollisionType::Solid, raycast_collision: true, }, - _ => todo!() } } } @@ -59,11 +58,11 @@ pub struct BlockDescriptor { pub collision: CollisionType, pub raycast_collision: bool, } -impl BlockDescriptor { - pub fn of(block: Block) -> Self { - block.descriptor() - } -} +// impl BlockDescriptor { +// pub fn of(block: Block) -> Self { +// block.descriptor() +// } +// } #[derive(Clone, Copy, Debug)] pub struct CubeTexture { diff --git a/src/world/loading.rs b/src/world/loading.rs index 1a0af1c..a686316 100644 --- a/src/world/loading.rs +++ b/src/world/loading.rs @@ -42,7 +42,12 @@ pub fn update_chunks_if_player_moved( //If it did, get it's position and current chunk let player_position = transform.0.to_scale_rotation_translation().2; - let player_at_chunk = player_position.as_ivec3() / CHUNK_SIZE as i32; + let player_position_ivec3 = player_position.as_ivec3(); + let player_at_chunk = ivec3( + player_position_ivec3.x.div_euclid(CHUNK_SIZE as i32), + player_position_ivec3.y.div_euclid(CHUNK_SIZE as i32), + player_position_ivec3.z.div_euclid(CHUNK_SIZE as i32), + ); //Then, mark *ALL* chunks with ToUnload for (_, chunk) in &mut vm_world.chunks { diff --git a/src/world/raycast.rs b/src/world/raycast.rs index 8da93d6..3f2f407 100644 --- a/src/world/raycast.rs +++ b/src/world/raycast.rs @@ -1,6 +1,6 @@ use glam::{Vec3, IVec3}; -use shipyard::{View, Component, ViewMut, IntoIter, UniqueView, UniqueViewMut}; -use crate::{player::MainPlayer, transform::Transform, input::Inputs}; +use shipyard::{View, Component, ViewMut, IntoIter, UniqueView}; +use crate::transform::Transform; use super::{ChunkStorage, block::Block}; @@ -10,6 +10,7 @@ const RAYCAST_STEP: f32 = 0.25; pub struct RaycastReport { pub length: f32, pub position: Vec3, + pub direction: Vec3, pub block_position: IVec3, pub block: Block, } @@ -24,7 +25,13 @@ impl ChunkStorage { let block_position = position.floor().as_ivec3(); if let Some(block) = self.get_block(block_position) { if block.descriptor().raycast_collision { - return Some(RaycastReport { length, position, block_position, block }); + return Some(RaycastReport { + length, + position, + direction, + block_position, + block + }); } } length += RAYCAST_STEP; @@ -56,21 +63,3 @@ pub fn update_raycasts( *report = LookingAtBlock(world.raycast(position, direction, Some(30.))); } } - -pub fn break_block_test_only( - raycast: View, - input: UniqueView, - mut world: UniqueViewMut -) { - if input.action_a { - //get raycast info - let Some(ray) = raycast.iter().next().unwrap().0 else { return }; - //update block - let Some(block) = world.get_block_mut(ray.block_position) else { return }; - *block = Block::Air; - //mark chunk as dirty - let (chunk_pos, _) = ChunkStorage::to_chunk_coords(ray.block_position); - let chunk = world.chunks.get_mut(&chunk_pos).unwrap(); - chunk.dirty = true; - } -} From 1fef7e00cd4c336f40b2f0a970d49342f9e3e377 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 22:28:10 +0100 Subject: [PATCH 76/81] skip placement if both buttons are down --- src/block_placement.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/block_placement.rs b/src/block_placement.rs index 725472f..56d5f92 100644 --- a/src/block_placement.rs +++ b/src/block_placement.rs @@ -12,7 +12,9 @@ pub fn block_placement_system( input: UniqueView, mut world: UniqueViewMut ) { - //this cant process both place and break btw + if input.action_a && input.action_b { + return + } if input.action_a || input.action_b { //get raycast info let Some(ray) = (&main_player, &raycast).iter().next().unwrap().1/**/.0 else { return }; From 665b3b841ef9282f19ffb16dadee0397cf9a9d65 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 22:37:01 +0100 Subject: [PATCH 77/81] prev inputs --- src/block_placement.rs | 13 ++++++------- src/input.rs | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/block_placement.rs b/src/block_placement.rs index 56d5f92..89cdf99 100644 --- a/src/block_placement.rs +++ b/src/block_placement.rs @@ -3,24 +3,23 @@ use shipyard::{UniqueViewMut, UniqueView, View, IntoIter}; use crate::{ player::MainPlayer, world::{raycast::LookingAtBlock, ChunkStorage, block::Block}, - input::Inputs + input::{Inputs, PrevInputs} }; pub fn block_placement_system( main_player: View, raycast: View, input: UniqueView, + prev_input: UniqueView, mut world: UniqueViewMut ) { - if input.action_a && input.action_b { - return - } - if input.action_a || input.action_b { + let action_place = input.action_b && !prev_input.0.action_b; + let action_break = input.action_a && !prev_input.0.action_a; + if action_place ^ action_break { //get raycast info let Some(ray) = (&main_player, &raycast).iter().next().unwrap().1/**/.0 else { return }; //update block - let is_place = input.action_b; - let place_position = if is_place { + let place_position = if action_place { let position = (ray.position - ray.direction * 0.5).floor().as_ivec3(); let Some(block) = world.get_block_mut(position) else { return }; *block = Block::Dirt; diff --git a/src/input.rs b/src/input.rs index 522b569..7f408e9 100644 --- a/src/input.rs +++ b/src/input.rs @@ -13,6 +13,9 @@ pub struct Inputs { pub action_b: bool, } +#[derive(Unique, Clone, Copy, Default, Debug)] +pub struct PrevInputs(pub Inputs); + #[derive(Unique, Clone, Default, Debug)] pub struct RawInputState { pub keyboard_state: HashSet>, @@ -51,7 +54,9 @@ pub fn process_events( pub fn update_input_states ( raw_inputs: UniqueView, mut inputs: UniqueViewMut, + mut prev_inputs: UniqueViewMut, ) { + prev_inputs.0 = *inputs; inputs.movement = Vec2::new( raw_inputs.keyboard_state.contains(&VirtualKeyCode::D) as u32 as f32 - raw_inputs.keyboard_state.contains(&VirtualKeyCode::A) as u32 as f32, @@ -67,6 +72,7 @@ pub fn init_input ( storages: AllStoragesView ) { storages.add_unique(Inputs::default()); + storages.add_unique(PrevInputs::default()); storages.add_unique(RawInputState::default()); } From 827ed16aa175c8012b7fe0a9e2961d99bd7be0d0 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 22:43:25 +0100 Subject: [PATCH 78/81] fix typo --- src/rendering/selection_box.rs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/rendering/selection_box.rs b/src/rendering/selection_box.rs index 4a23eed..febfe47 100644 --- a/src/rendering/selection_box.rs +++ b/src/rendering/selection_box.rs @@ -7,9 +7,7 @@ use glium::{ VertexBuffer, uniform, DrawParameters, BackfaceCullingMode, - Blend, BlendingFunction, - LinearBlendingFactor, - Depth, DepthTest, + Blend, Depth, DepthTest, }; use crate::{ world::raycast::LookingAtBlock, @@ -62,36 +60,27 @@ pub fn render_selection_box( &display.display, BOX_VERTICES ).unwrap(); + let index = IndexBuffer::new( &display.display, PrimitiveType::TrianglesList, CUBE_INDICES ).unwrap(); + //Darken block target.0.draw( &vert, &index, &program.0, &uniform! { - color: [0., 0., 0., 1.], + u_color: [0., 0., 0., 0.5_f32], u_position: lookat.block_position.as_vec3().to_array(), perspective: camera.perspective_matrix.to_cols_array_2d(), view: camera.view_matrix.to_cols_array_2d(), }, &DrawParameters { backface_culling: BackfaceCullingMode::CullClockwise, - blend: Blend { - //for some reason only constant alpha works??? - color: BlendingFunction::Addition { - source: LinearBlendingFactor::ConstantAlpha, - destination: LinearBlendingFactor::OneMinusConstantAlpha, - }, - alpha: BlendingFunction::Addition { - source: LinearBlendingFactor::ConstantAlpha, - destination: LinearBlendingFactor::OneMinusConstantAlpha - }, - constant_value: (0.0, 0.0, 0.0, 0.5) - }, + blend: Blend::alpha_blending(), depth: Depth { test: DepthTest::IfLessOrEqual, //this may be unreliable! ..Default::default() From 5a0e73e2b5acbedd2c4f7c4dc96e78a4e1f2a56b Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 22:55:29 +0100 Subject: [PATCH 79/81] block selector effect --- shaders/selection_box.frag | 1 + 1 file changed, 1 insertion(+) diff --git a/shaders/selection_box.frag b/shaders/selection_box.frag index 9b2ac94..42b54ed 100644 --- a/shaders/selection_box.frag +++ b/shaders/selection_box.frag @@ -5,4 +5,5 @@ uniform vec4 u_color; void main() { color = u_color; + color -= vec4(0, 0, 0, 0.1 * sin(gl_FragCoord.x) * cos(gl_FragCoord.y)); } From 427feecb55c5df5099ea0fca6102cee1404a15e9 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 23:41:34 +0100 Subject: [PATCH 80/81] wtf --- src/world/worldgen.rs | 49 ++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index 7101ceb..0e383d4 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -7,32 +7,43 @@ use super::{ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData { let offset = chunk_position * CHUNK_SIZE as i32; - let mut noise = FastNoise::seeded(seed); - noise.set_fractal_type(FractalType::FBM); - noise.set_frequency(0.1); + + let mut cave_noise = FastNoise::seeded(seed); + cave_noise.set_fractal_type(FractalType::FBM); + cave_noise.set_frequency(0.1); + + let mut dirt_noise = FastNoise::seeded(seed.rotate_left(1)); + dirt_noise.set_fractal_type(FractalType::FBM); + dirt_noise.set_frequency(0.1); let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); - // blocks[0][0][0] = Block::Stone; - // blocks[0][CHUNK_SIZE - 1][0] = Block::Stone; - // blocks[CHUNK_SIZE - 1][0][0] = Block::Stone; - // blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][0] = Block::Stone; - // blocks[0][0][CHUNK_SIZE - 1] = Block::Stone; - // blocks[0][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; - // blocks[CHUNK_SIZE - 1][0][CHUNK_SIZE - 1] = Block::Stone; - // blocks[CHUNK_SIZE - 1][CHUNK_SIZE - 1][CHUNK_SIZE - 1] = Block::Stone; - - for x in 0..CHUNK_SIZE { - for y in 0..CHUNK_SIZE { - for z in 0..CHUNK_SIZE { - let position = ivec3(x as i32, y as i32, z as i32) + offset; - let noise = noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32); - if (0.7..0.8).contains(&noise) { - blocks[x][y][z] = Block::Stone; + if chunk_position.y > 0 { + if chunk_position.y == 1 { + for x in 0..CHUNK_SIZE { + for z in 0..CHUNK_SIZE { + blocks[x][0][z] = Block::Dirt; + blocks[x][1][z] = Block::Grass; + } + } + } + } else { + for x in 0..CHUNK_SIZE { + for y in 0..CHUNK_SIZE { + for z in 0..CHUNK_SIZE { + let position = ivec3(x as i32, y as i32, z as i32) + offset; + let v_cave_noise = cave_noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32) * (-position.y as f32 - 10.0).clamp(0., 1.); + let v_dirt_noise = dirt_noise.get_noise3d(position.x as f32, position.y as f32, position.z as f32) * (-position.y as f32).clamp(0., 1.); + if v_cave_noise > 0.5 { + blocks[x][y][z] = Block::Stone; + } else if v_dirt_noise > 0.5 { + blocks[x][y][z] = Block::Dirt; + } } } } } + blocks } From 1a948b43bea3e39f71b716d74e85c59e60fdb661 Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Sat, 28 Jan 2023 23:43:19 +0100 Subject: [PATCH 81/81] fix world gen --- src/world/worldgen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/world/worldgen.rs b/src/world/worldgen.rs index 0e383d4..471055c 100644 --- a/src/world/worldgen.rs +++ b/src/world/worldgen.rs @@ -18,8 +18,8 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData { let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); - if chunk_position.y > 0 { - if chunk_position.y == 1 { + if chunk_position.y >= 0 { + if chunk_position.y == 0 { for x in 0..CHUNK_SIZE { for z in 0..CHUNK_SIZE { blocks[x][0][z] = Block::Dirt;