diff --git a/Cargo.toml b/Cargo.toml index 84d588d..81b4777 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,4 @@ env_logger = "0.10" strum = { version = "0.24", features = ["derive"] } glam = { version = "0.22", features = ["debug-glam-assert", "mint", "fast-math"] } hashbrown = "0.13" +simdnoise = "3.1" diff --git a/src/game/controller.rs b/src/game/controller.rs index da4623a..c188a98 100644 --- a/src/game/controller.rs +++ b/src/game/controller.rs @@ -109,7 +109,7 @@ impl Default for Controls { fn default() -> Self { Self { inputs: Default::default(), - speed: 10., + speed: 40., sensitivity: 2., } } diff --git a/src/game/options.rs b/src/game/options.rs index d4d0c26..d9fae77 100644 --- a/src/game/options.rs +++ b/src/game/options.rs @@ -5,7 +5,7 @@ pub struct GameOptions { impl Default for GameOptions { fn default() -> Self { Self { - render_distance: 8, + render_distance: 16, } } } diff --git a/src/game/shaders/chunk.rs b/src/game/shaders/chunk.rs index c865391..9172605 100644 --- a/src/game/shaders/chunk.rs +++ b/src/game/shaders/chunk.rs @@ -23,7 +23,8 @@ pub const VERTEX_SHADER: &str = r#" void main() { mat4 modelview = view * model; - v_normal = transpose(inverse(mat3(modelview))) * normal; + //v_normal = transpose(inverse(mat3(modelview))) * normal; + v_normal = normal; v_uv = uv; gl_Position = perspective * modelview * vec4(position, 1.0); } @@ -32,10 +33,12 @@ pub const FRAGMENT_SHADER: &str = r#" #version 150 core in vec2 v_uv; + in vec3 v_normal; out vec4 color; uniform sampler2D tex; void main() { color = texture(tex, v_uv); + color *= vec4(vec3(abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z)), 1.); } "#; diff --git a/src/game/world.rs b/src/game/world.rs index 0dcba11..3e7b657 100644 --- a/src/game/world.rs +++ b/src/game/world.rs @@ -26,7 +26,7 @@ const NEGATIVE_X_NEIGHBOR: usize = 1; const POSITIVE_Z_NEIGHBOR: usize = 2; const NEGATIVE_Z_NEIGHBOR: usize = 3; -const MAX_TASKS: usize = 8; +const MAX_TASKS: usize = 4; pub struct World { pub chunks: HashMap, @@ -68,7 +68,7 @@ impl World { write: true, ..Default::default() }, - //backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise, + backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockwise, ..Default::default() }; for (&position, chunk) in &self.chunks { diff --git a/src/game/world/chunk.rs b/src/game/world/chunk.rs index e7f54e5..481b04b 100644 --- a/src/game/world/chunk.rs +++ b/src/game/world/chunk.rs @@ -5,7 +5,7 @@ use crate::game::{ shaders::chunk::Vertex as ChunkVertex }; -pub const CHUNK_SIZE: usize = 16; +pub const CHUNK_SIZE: usize = 32; pub const CHUNK_HEIGHT: usize = 255; pub enum ChunkState { diff --git a/src/game/world/thread.rs b/src/game/world/thread.rs index 3e5b0cc..b051112 100644 --- a/src/game/world/thread.rs +++ b/src/game/world/thread.rs @@ -28,8 +28,8 @@ impl WorldThreading { self.load_tasks.len() + self.mesh_tasks.len() } pub fn queue_load(&mut self, position: IVec2) { - let handle = thread::spawn(|| { - world_gen::generate_chunk() + 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); diff --git a/src/game/world/thread/mesh_gen.rs b/src/game/world/thread/mesh_gen.rs index b1175ae..617ef77 100644 --- a/src/game/world/thread/mesh_gen.rs +++ b/src/game/world/thread/mesh_gen.rs @@ -28,14 +28,14 @@ const CUBE_FACE_VERTICES: [[Vec3A; 4]; 6] = [ [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.)] + [vec3a(0., 0., 1.), vec3a(0., 0., 0.), vec3a(1., 0., 1.), vec3a(1., 0., 0.)], ]; pub const CUBE_FACE_NORMALS: [[f32; 3]; 6] = [ - [0., 1., 0.], - [0., 0., -1.], + [0., 1., 0.], + [0., 0., -1.], [-1., 0., 0.], - [1., 0., 0.], - [0., 0., 1.], + [1., 0., 0.], + [0., 0., 1.], [0., -1., 0.] ]; pub const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; @@ -98,7 +98,8 @@ pub fn generate_mesh(position: IVec2, chunk_data: ChunkData, neighbors: [ChunkDa for y in 0..CHUNK_HEIGHT { for z in 0..CHUNK_SIZE { let coord = ivec3(x as i32, y as i32, z as i32); - if get_block(coord).descriptor().render.is_none() { + let descriptor = get_block(coord).descriptor(); + if descriptor.render.is_none() { continue } for face in CubeFace::iter() { @@ -110,11 +111,29 @@ pub fn generate_mesh(position: IVec2, chunk_data: ChunkData, neighbors: [ChunkDa get_block(facing_coord).descriptor().render.is_none() }; if show { + let texures = descriptor.render.unwrap().1; + let texture_id = 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, + }; + //TODO replace with a proper texture resolver (or calculate uvs in a shader!) + //this is temporary! + //also this can only resolve textures on the first row. + const TEX_WIDTH: f32 = 16. / 640.; + const TEX_HEIGHT: f32 = 16. / 404.; + let x1 = TEX_WIDTH * texture_id as f32; + let x2 = x1 + TEX_WIDTH as f32; + let y1 = 1. - TEX_HEIGHT; + let y2 = 1.; builer.add_face(face, coord, [ - vec2(0., 0.), - vec2(0., 1.), - vec2(1., 0.), - vec2(1., 1.), + vec2(x1, y1), + vec2(x1, y2), + vec2(x2, y1), + vec2(x2, y2), ]); } } diff --git a/src/game/world/thread/world_gen.rs b/src/game/world/thread/world_gen.rs index dc47b2d..8abf905 100644 --- a/src/game/world/thread/world_gen.rs +++ b/src/game/world/thread/world_gen.rs @@ -1,8 +1,35 @@ +use glam::IVec2; +use simdnoise::NoiseBuilder; use crate::game::{ world::chunk::{ChunkData, CHUNK_SIZE, CHUNK_HEIGHT}, blocks::Block }; -pub fn generate_chunk() -> ChunkData { - Box::new([[[Block::Stone; CHUNK_SIZE]; CHUNK_HEIGHT]; CHUNK_SIZE]) +const TERRAIN_HEIGHT_MIN: f32 = 64.; +const TERRAIN_HEIGHT_MAX: f32 = 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 height_noise = NoiseBuilder::ridge_2d_offset(world_xz.x, CHUNK_SIZE, world_xz.y, CHUNK_SIZE) + .with_freq(0.01) + .with_octaves(4) + .with_seed(seed as i32) + .generate_scaled(TERRAIN_HEIGHT_MIN, TERRAIN_HEIGHT_MAX); + + //put everything together + for x in 0..CHUNK_SIZE { + for z in 0..CHUNK_SIZE { + let heightmap = height_noise[x + z * CHUNK_SIZE] as usize; + for y in 0..heightmap { + chunk[x][y][z] = Block::Dirt; + } + chunk[x][heightmap][z] = Block::Grass; + } + } + + //return generated world + chunk }