diff --git a/Cargo.toml b/Cargo.toml index 9951fb5..ed02bf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ strum = { version = "0.24", features = ["derive"] } glam = { version = "0.22", features = ["debug-glam-assert", "mint", "fast-math"] } hashbrown = "0.13" simdnoise = "3.1" +rayon = "1.6" [features] default = [] diff --git a/assets/blocks/bedrock.png b/assets/blocks/bedrock.png new file mode 100644 index 0000000..adc9ab2 Binary files /dev/null and b/assets/blocks/bedrock.png differ diff --git a/assets/blocks/dirt.png b/assets/blocks/dirt.png new file mode 100644 index 0000000..16bdc70 Binary files /dev/null and b/assets/blocks/dirt.png differ diff --git a/assets/blocks/grass.png b/assets/blocks/grass.png new file mode 100644 index 0000000..e6defab Binary files /dev/null and b/assets/blocks/grass.png differ diff --git a/assets/blocks/grass_side.png b/assets/blocks/grass_side.png new file mode 100644 index 0000000..f1f364a Binary files /dev/null and b/assets/blocks/grass_side.png differ diff --git a/assets/blocks/leaf.png b/assets/blocks/leaf.png new file mode 100644 index 0000000..d1f60be Binary files /dev/null and b/assets/blocks/leaf.png differ diff --git a/assets/blocks/sand.png b/assets/blocks/sand.png new file mode 100644 index 0000000..640008f Binary files /dev/null and b/assets/blocks/sand.png differ diff --git a/assets/blocks/stone.png b/assets/blocks/stone.png new file mode 100644 index 0000000..39e4d4e Binary files /dev/null and b/assets/blocks/stone.png differ diff --git a/assets/blocks/tall_grass.png b/assets/blocks/tall_grass.png new file mode 100644 index 0000000..77eaf8e Binary files /dev/null and b/assets/blocks/tall_grass.png differ diff --git a/assets/blocks/torch.png b/assets/blocks/torch.png new file mode 100644 index 0000000..a951bc0 Binary files /dev/null and b/assets/blocks/torch.png differ diff --git a/assets/blocks/tree.png b/assets/blocks/tree.png new file mode 100644 index 0000000..b38f5c6 Binary files /dev/null and b/assets/blocks/tree.png differ diff --git a/assets/blocks/tree_top.png b/assets/blocks/tree_top.png new file mode 100644 index 0000000..e24a1aa Binary files /dev/null and b/assets/blocks/tree_top.png differ diff --git a/assets/spritesheet.png b/assets/spritesheet.png deleted file mode 100644 index aef1fb9..0000000 Binary files a/assets/spritesheet.png and /dev/null differ diff --git a/src/game/assets/textures.rs b/src/game/assets/textures.rs index e595503..b75c066 100644 --- a/src/game/assets/textures.rs +++ b/src/game/assets/textures.rs @@ -1,5 +1,8 @@ -use std::{fs, io}; -use glium::texture::{RawImage2d, SrgbTexture2d}; +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); @@ -25,14 +28,53 @@ fn load_png(file_path: &str, display: &glium::Display) -> SrgbTexture2d { 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 counter = counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + log::info!("loading texture {}/{}: {}", counter, file_paths.len(), file_path.to_str().unwrap()); + + //Load file + let data = fs::read(file_path).expect("Failed to load texture"); + + //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 + ); + + raw_image + }).collect(); + SrgbTexture2dArray::new(display, raw_images).unwrap() +} + pub struct Textures { - pub block_atlas: SrgbTexture2d + 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 { - block_atlas: load_png("assets/spritesheet.png", display) + blocks: load_png_array(&[ + "./assets/blocks/stone.png".into(), + "./assets/blocks/dirt.png".into(), + "./assets/blocks/grass.png".into(), + "./assets/blocks/grass_side.png".into(), + "./assets/blocks/sand.png".into(), + "./assets/blocks/bedrock.png".into(), + "./assets/blocks/tree.png".into(), + "./assets/blocks/tree_top.png".into(), + "./assets/blocks/leaf.png".into(), + "./assets/blocks/torch.png".into(), + "./assets/blocks/tall_grass.png".into(), + ], display) } } } diff --git a/src/game/shaders/chunk.rs b/src/game/shaders/chunk.rs index 6519030..03c47e6 100644 --- a/src/game/shaders/chunk.rs +++ b/src/game/shaders/chunk.rs @@ -5,43 +5,30 @@ 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); +implement_vertex!(Vertex, position, normal, uv, tex_index); -//TODO store vertex data in a more compact way -pub const VERTEX_SHADER: &str = r#" - #version 150 core +pub const VERTEX_SHADER: &str = include_str!("./glsl/chunk.vert"); +pub const FRAGMENT_SHADER: &str = include_str!("./glsl/chunk.frag"); - 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; +// pub const VERTEX_SHADER: &str = r#" +// #version 150 core - 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); - } -"#; -pub const FRAGMENT_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; - in vec2 v_uv; - in vec3 v_normal; - out vec4 color; - uniform sampler2D tex; - - void main() { - // base color from texture - color = texture(tex, v_uv); - - //basic lighting - color *= vec4(vec3(abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z)), 1.); - } -"#; +// 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 index 799f51d..336dab8 100644 --- a/src/game/shaders/colored2d.rs +++ b/src/game/shaders/colored2d.rs @@ -6,22 +6,5 @@ pub struct Vertex { } implement_vertex!(Vertex, position); -pub const VERTEX_SHADER: &str = r#" - #version 150 core - - in vec2 position; - - void main() { - gl_Position = vec4(position, 0., 1.); - } -"#; -pub const FRAGMENT_SHADER: &str = r#" - #version 150 core - - out vec4 color; - uniform vec4 u_color; - - void main() { - color = u_color; - } -"#; +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 new file mode 100644 index 0000000..e07b5e1 --- /dev/null +++ b/src/game/shaders/glsl/chunk.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/src/game/shaders/glsl/chunk.vert b/src/game/shaders/glsl/chunk.vert new file mode 100644 index 0000000..b9a51ab --- /dev/null +++ b/src/game/shaders/glsl/chunk.vert @@ -0,0 +1,18 @@ +#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 vec3 position_offset; +uniform mat4 perspective; +uniform mat4 view; + +void main() { + v_normal = normal; + v_tex_index = tex_index; + gl_Position = perspective * view * vec4(position, 1.0) * vec4(position_offset, 1.0); +} diff --git a/src/game/shaders/glsl/colored2d.frag b/src/game/shaders/glsl/colored2d.frag new file mode 100644 index 0000000..9b2ac94 --- /dev/null +++ b/src/game/shaders/glsl/colored2d.frag @@ -0,0 +1,8 @@ +#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 new file mode 100644 index 0000000..af1807e --- /dev/null +++ b/src/game/shaders/glsl/colored2d.vert @@ -0,0 +1,7 @@ +#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 index 0b0be45..57a489e 100644 --- a/src/game/world.rs +++ b/src/game/world.rs @@ -95,7 +95,7 @@ impl World { ], view: view, perspective: perspective, - tex: Sampler(&assets.textures.block_atlas, sampler) + tex: Sampler(&assets.textures.blocks, sampler) }, &draw_parameters ).unwrap(); diff --git a/src/game/world/thread/mesh_gen.rs b/src/game/world/thread/mesh_gen.rs index 4584bd4..cafc76b 100644 --- a/src/game/world/thread/mesh_gen.rs +++ b/src/game/world/thread/mesh_gen.rs @@ -30,7 +30,7 @@ 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.)], ]; -pub const CUBE_FACE_NORMALS: [[f32; 3]; 6] = [ +const CUBE_FACE_NORMALS: [[f32; 3]; 6] = [ [0., 1., 0.], [0., 0., -1.], [-1., 0., 0.], @@ -38,7 +38,14 @@ pub const CUBE_FACE_NORMALS: [[f32; 3]; 6] = [ [0., 0., 1.], [0., -1., 0.] ]; -pub const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; +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 { @@ -51,7 +58,7 @@ impl MeshBuilder { Self::default() } - pub fn add_face(&mut self, face: CubeFace, coord: IVec3, uvs: [Vec2; 4]) { + pub fn add_face(&mut self, face: CubeFace, coord: IVec3, texture: u8) { let coord = coord.as_vec3a(); let face_index = face as usize; @@ -63,7 +70,8 @@ impl MeshBuilder { self.vertex_buffer.push(Vertex { position: (coord + vert[i]).to_array(), normal: norm, - uv: uvs[i].to_array() + uv: UV_COORDS[i], + tex_index: texture }); } @@ -112,7 +120,7 @@ pub fn generate_mesh(position: IVec2, chunk_data: ChunkData, neighbors: [ChunkDa }; if show { let texures = descriptor.render.unwrap().1; - let texture_id = match face { + let texture_index = match face { CubeFace::Top => texures.top, CubeFace::Front => texures.front, CubeFace::Left => texures.left, @@ -120,22 +128,7 @@ pub fn generate_mesh(position: IVec2, chunk_data: ChunkData, neighbors: [ChunkDa 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(x1, y1), - vec2(x1, y2), - vec2(x2, y1), - vec2(x2, y2), - ]); + builer.add_face(face, coord, texture_index); } } }