diff --git a/kubi-logging/src/lib.rs b/kubi-logging/src/lib.rs index 71242dc..0b03e77 100644 --- a/kubi-logging/src/lib.rs +++ b/kubi-logging/src/lib.rs @@ -9,7 +9,7 @@ pub fn init() { use env_logger::{fmt::Color, Builder, Env}; let env = Env::default() - .filter_or("RUST_LOG", "trace,gilrs=warn,rusty_xinput=warn,wgpu=warn,wgpu_core=warn,wgpu_hal=warn,hui=info,hui-winit=info,hui-glium=info,hui-wgpu=info"); + .filter_or("RUST_LOG", "trace,gilrs=warn,rusty_xinput=warn,wgpu=warn,wgpu_core=warn,wgpu_hal=warn,hui=info,hui-winit=info,hui-glium=info,hui-wgpu=info,naga=warn"); Builder::from_env(env) .format(|buf, record| { let mut level_style = buf.style(); diff --git a/kubi/shaders/world.wgsl b/kubi/shaders/world.wgsl index 6587883..cfe54ae 100644 --- a/kubi/shaders/world.wgsl +++ b/kubi/shaders/world.wgsl @@ -1,9 +1,9 @@ -// struct Uniforms { -// transform: mat4x4; -// }; +struct CameraUniform { + view_proj: mat4x4, +}; -// @group(1) @binding(0) -// var uniforms: Uniforms; +@group(1) @binding(0) +var camera: CameraUniform; struct VertexInput { @location(0) position: vec3, @@ -26,7 +26,7 @@ fn vs_main( ) -> VertexOutput { var out: VertexOutput; out.uv = in.uv; - out.clip_position = vec4(in.position, 1.0); + out.clip_position = camera.view_proj * vec4(in.position, 1.0); return out; } diff --git a/kubi/src/lib.rs b/kubi/src/lib.rs index e708b19..ba75b14 100644 --- a/kubi/src/lib.rs +++ b/kubi/src/lib.rs @@ -79,8 +79,11 @@ use player_controller::{debug_switch_ctl_type, update_player_controllers}; // clear_background, entities::render_entities, init_window_size, primitives::init_primitives, resize_renderer, selection_box::render_selection_box, sumberge::render_submerged_view, update_window_size, world::{draw_current_chunk_border, draw_world, draw_world_trans, init_trans_chunk_queue}, BackgroundColor, RenderTarget, Renderer // }; use rendering::{ - init_window_size, render_master, resize_renderer, update_window_size, - world::{init_trans_chunk_queue, TransChunkQueue}, + init_render_states, + init_window_size, + render_master, + resize_renderer, + update_window_size, BackgroundColor, Renderer, }; use block_placement::update_block_placement; @@ -116,7 +119,7 @@ fn startup() -> Workload { init_window_size, kubi_ui_init, load_prefabs, - //init_primitives, + init_render_states, insert_lock_state, init_state, initialize_from_args, @@ -139,7 +142,6 @@ fn update() -> Workload { process_inputs, kubi_ui_begin, ( - init_trans_chunk_queue.run_if_missing_unique::(), init_game_world.run_if_missing_unique::(), ( spawn_player.run_if_storage_empty::(), diff --git a/kubi/src/prefabs.rs b/kubi/src/prefabs.rs index 5d521e5..d4060e4 100644 --- a/kubi/src/prefabs.rs +++ b/kubi/src/prefabs.rs @@ -38,6 +38,7 @@ impl AssetPaths for BlockTexture { #[derive(Unique)] pub struct TexturePrefabs { pub block_diffuse_texture: wgpu::Texture, + pub block_diffuse_bind_group_layout: wgpu::BindGroupLayout, pub block_diffuse_bind_group: wgpu::BindGroup, } @@ -107,6 +108,7 @@ pub fn load_prefabs( }); storages.add_unique_non_send_sync(TexturePrefabs { block_diffuse_texture, + block_diffuse_bind_group_layout, block_diffuse_bind_group, }); diff --git a/kubi/src/rendering.rs b/kubi/src/rendering.rs index 843e93b..8a7b89f 100644 --- a/kubi/src/rendering.rs +++ b/kubi/src/rendering.rs @@ -1,16 +1,50 @@ -use shipyard::{AllStoragesView, AllStoragesViewMut, IntoIter, Unique, UniqueView, UniqueViewMut, View}; +use shipyard::{AllStoragesView, AllStoragesViewMut, IntoIter, IntoWorkload, Unique, UniqueView, UniqueViewMut, View, Workload}; use winit::dpi::PhysicalSize; -use glam::{Vec3, UVec2}; +use glam::{mat4, vec4, Mat4, UVec2, Vec3}; use crate::{events::WindowResizedEvent, state::is_ingame}; mod renderer; pub use renderer::Renderer; -pub mod primitives; +use self::camera::update_camera_unform_buffer; + pub mod world; -pub mod selection_box; -pub mod entities; -pub mod sumberge; +pub mod camera; +//pub mod primitives; +//pub mod selection_box; +//pub mod entities; +//pub mod sumberge; + +pub const WGPU_COORDINATE_SYSTEM: Mat4 = mat4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, 0.5, 0.5), + vec4(0.0, 0.0, 0.0, 1.0), +); + +// #[repr(C)] +// #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +// struct TrasnformUniformData { +// pub transform: [[f32; 4]; 4], +// } + +// impl TrasnformUniformData { +// pub const LAYOUT: &wgpu::Layou +// } + +// impl From for TrasnformUniformData { +// fn from(mat: Mat4) -> Self { +// Self { +// transform: mat.to_cols_array_2d(), +// } +// } +// } + +// impl From for TrasnformUniformData { +// fn from(value: Transform) -> Self { +// value.0.into() +// } +// } pub struct BufferPair { pub index: wgpu::Buffer, @@ -28,6 +62,13 @@ pub struct RenderCtx<'a> { pub surface_view: &'a wgpu::TextureView, } +pub fn init_render_states() -> Workload { + ( + camera::init_camera_uniform_buffer, + world::init_world_render_state, + ).into_workload() +} + pub fn render_master(storages: AllStoragesViewMut) { let renderer = storages.borrow::>().unwrap(); @@ -66,6 +107,10 @@ pub fn render_master(storages: AllStoragesViewMut) { }; if storages.run(is_ingame) { + //XXX: probably should be in pre_update or sth + storages.run(update_camera_unform_buffer); + + //TODO init world render state on demand storages.run_with_data(world::draw_world, &mut data); } diff --git a/kubi/src/rendering/camera.rs b/kubi/src/rendering/camera.rs new file mode 100644 index 0000000..0fb47b9 --- /dev/null +++ b/kubi/src/rendering/camera.rs @@ -0,0 +1,84 @@ +use bytemuck::{Pod, Zeroable}; +use kubi_shared::transform::Transform; +use shipyard::{AllStoragesView, IntoIter, Unique, UniqueView, View}; +use wgpu::util::DeviceExt; +use crate::camera::{self, Camera}; + +use super::{Renderer, WGPU_COORDINATE_SYSTEM}; + +#[derive(Debug, Clone, Copy, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct CameraUniformData { + pub view_proj: [[f32; 4]; 4], +} + + +//TODO if multiple cameras, buffer per camera +#[derive(Unique)] +pub struct CameraUniformBuffer { + pub camera_uniform_buffer: wgpu::Buffer, + pub camera_bind_group_layout: wgpu::BindGroupLayout, + pub camera_bind_group: wgpu::BindGroup, +} + +impl CameraUniformBuffer { + pub fn init(renderer: &Renderer, data: CameraUniformData) -> Self { + let camera_uniform_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("camera_uniform_buffer"), + contents: bytemuck::cast_slice(&[data]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + let camera_bind_group_layout = renderer.device().create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("camera_bind_group_layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + ], + }); + + let camera_bind_group = renderer.device().create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("camera_bind_group"), + layout: &camera_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: camera_uniform_buffer.as_entire_binding(), + }, + ], + }); + + Self { camera_uniform_buffer, camera_bind_group_layout, camera_bind_group } + } + + pub fn init_default(renderer: &Renderer) -> Self { + Self::init(renderer, CameraUniformData::default()) + } + + pub fn update(&self, renderer: &Renderer, data: CameraUniformData) { + renderer.queue().write_buffer(&self.camera_uniform_buffer, 0, bytemuck::cast_slice(&[data])); + } +} + +pub fn init_camera_uniform_buffer(storages: AllStoragesView) { + let renderer = storages.borrow::>().unwrap(); + storages.add_unique(CameraUniformBuffer::init_default(&renderer)); +} + +pub fn update_camera_unform_buffer( + renderer: UniqueView, + camera_uniform_buffer: UniqueView, + camera: View, +) { + let Some(camera) = camera.iter().next() else { return }; + let proj = camera.view_matrix * camera.perspective_matrix * WGPU_COORDINATE_SYSTEM; + camera_uniform_buffer.update(&renderer, CameraUniformData { view_proj: proj.to_cols_array_2d() }); +} diff --git a/kubi/src/rendering/shaders.rs b/kubi/src/rendering/shaders.rs deleted file mode 100644 index e69de29..0000000 diff --git a/kubi/src/rendering/world.rs b/kubi/src/rendering/world.rs index 17d20ec..33ea5fe 100644 --- a/kubi/src/rendering/world.rs +++ b/kubi/src/rendering/world.rs @@ -1,57 +1,44 @@ -use bytemuck::{Pod, Zeroable}; use glam::{IVec3, Vec3}; use shipyard::{AllStoragesView, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View}; use kubi_shared::{chunk::CHUNK_SIZE, transform::Transform}; -use wgpu::util::RenderEncoder; use crate::{ camera::Camera, prefabs::TexturePrefabs, settings::GameSettings, world::{ChunkMeshStorage, ChunkStorage}, }; -use super::{RenderCtx, Renderer}; +use super::{camera::CameraUniformBuffer, RenderCtx, WGPU_COORDINATE_SYSTEM}; -#[derive(Clone, Copy, Pod, Zeroable)] -#[repr(C, packed)] -pub struct ChunkVertex { - pub position: [f32; 3], - pub normal: [f32; 3], - pub uv: [f32; 2], - pub tex_index: u8, -} - -impl ChunkVertex { - pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { - array_stride: std::mem::size_of::() as wgpu::BufferAddress, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![ - 0 => Float32x3, - 1 => Float32x3, - 2 => Float32x2, - 3 => Uint32, - ], - }; -} +mod pipeline; +mod vertex; +pub use vertex::ChunkVertex; #[derive(Unique)] -pub struct TransChunkQueue(pub Vec); +pub struct WorldRenderState { + pub pipeline: wgpu::RenderPipeline, + pub trans_chunk_queue: Vec, +} -pub fn init_trans_chunk_queue(storages: AllStoragesView) { - storages.add_unique(TransChunkQueue(Vec::with_capacity(512))); +pub fn init_world_render_state(storages: AllStoragesView) { + storages.add_unique(WorldRenderState { + pipeline: storages.run(pipeline::init_world_pipeline), + trans_chunk_queue: Vec::with_capacity(512), + }) } pub fn draw_world( ctx: &mut RenderCtx, + mut state: UniqueViewMut, textures: UniqueView, chunks: UniqueView, meshes: NonSendSync>, - transform: View, + //transform: View, camera: View, + camera_ubo: UniqueView, settings: UniqueView, - mut trans_queue: UniqueViewMut, ) { let camera = camera.iter().next().expect("No cameras in the scene"); - let camera_matrix = camera.view_matrix * camera.perspective_matrix; + let matrix = WGPU_COORDINATE_SYSTEM * camera.view_matrix * camera.perspective_matrix; let mut render_pass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("draw_world"), @@ -66,6 +53,10 @@ pub fn draw_world( ..Default::default() }); + render_pass.set_pipeline(&state.pipeline); + render_pass.set_bind_group(0, &textures.block_diffuse_bind_group, &[]); + render_pass.set_bind_group(1, &camera_ubo.camera_bind_group, &[]); + for (&position, chunk) in &chunks.chunks { if let Some(key) = chunk.mesh_index { let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); @@ -85,10 +76,8 @@ pub fn draw_world( //Draw chunk mesh if mesh.main.index.size() > 0 { - //TODO render_pass.set_index_buffer(mesh.main.index.slice(..), wgpu::IndexFormat::Uint32); render_pass.set_vertex_buffer(0, mesh.main.vertex.slice(..)); - render_pass.set_bind_group(0, &textures.block_diffuse_bind_group, &[]); render_pass.draw_indexed(0..mesh.main.index_len, 0, 0..1); } diff --git a/kubi/src/rendering/world/pipeline.rs b/kubi/src/rendering/world/pipeline.rs new file mode 100644 index 0000000..f6b1a80 --- /dev/null +++ b/kubi/src/rendering/world/pipeline.rs @@ -0,0 +1,59 @@ +use shipyard::{Unique, UniqueView}; +use crate::{ + prefabs::TexturePrefabs, + rendering::{camera::CameraUniformBuffer, world::ChunkVertex, Renderer} +}; + +pub fn init_world_pipeline( + ren: UniqueView, + textures: UniqueView, + camera_ubo: UniqueView, +) -> wgpu::RenderPipeline { + let shader = ren.device().create_shader_module( + wgpu::include_wgsl!("../../../shaders/world.wgsl") + ); + + let world_pipeline_layout = ren.device().create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("world_pipeline_layout"), + bind_group_layouts: &[ + &textures.block_diffuse_bind_group_layout, + &camera_ubo.camera_bind_group_layout, + ], + push_constant_ranges: &[], + }); + + ren.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("world_pipeline"), + layout: Some(&world_pipeline_layout), + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + compilation_options: wgpu::PipelineCompilationOptions::default(), + targets: &[Some(wgpu::ColorTargetState { + format: ren.surface_config().format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + compilation_options: wgpu::PipelineCompilationOptions::default(), + buffers: &[ + ChunkVertex::LAYOUT, + ], + }, + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + cull_mode: Some(wgpu::Face::Back), + front_face: wgpu::FrontFace::Cw, + unclipped_depth: false, + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + }) +} diff --git a/kubi/src/rendering/world/vertex.rs b/kubi/src/rendering/world/vertex.rs new file mode 100644 index 0000000..ad1544c --- /dev/null +++ b/kubi/src/rendering/world/vertex.rs @@ -0,0 +1,23 @@ +use bytemuck::{Pod, Zeroable}; + +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C, packed)] +pub struct ChunkVertex { + pub position: [f32; 3], + pub normal: [f32; 3], + pub uv: [f32; 2], + pub tex_index: u32, +} + +impl ChunkVertex { + pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &wgpu::vertex_attr_array![ + 0 => Float32x3, + 1 => Float32x3, + 2 => Float32x2, + 3 => Uint32, + ], + }; +} diff --git a/kubi/src/world/mesh.rs b/kubi/src/world/mesh.rs index 24e2f2d..3b43116 100644 --- a/kubi/src/world/mesh.rs +++ b/kubi/src/world/mesh.rs @@ -1,4 +1,4 @@ -use glam::{IVec3, ivec3}; +use glam::{ivec3, IVec3, Vec3}; use strum::IntoEnumIterator; use kubi_shared::block::{Block, RenderType, Transparency}; use crate::world::chunk::CHUNK_SIZE; @@ -10,7 +10,7 @@ mod builder; use data::MeshGenData; use builder::{MeshBuilder, CubeFace, DiagonalFace}; -pub fn generate_mesh(data: MeshGenData) -> ( +pub fn generate_mesh(position: IVec3, data: MeshGenData) -> ( (Vec, Vec), (Vec, Vec), ) { @@ -32,7 +32,7 @@ pub fn generate_mesh(data: MeshGenData) -> ( } }; - let mut builder = MeshBuilder::new(); + let mut builder = MeshBuilder::new_with_offset((position * CHUNK_SIZE as i32).as_vec3()); let mut trans_builder = MeshBuilder::new(); for x in 0..CHUNK_SIZE as i32 { diff --git a/kubi/src/world/mesh/builder.rs b/kubi/src/world/mesh/builder.rs index 561342c..88cddf5 100644 --- a/kubi/src/world/mesh/builder.rs +++ b/kubi/src/world/mesh/builder.rs @@ -1,176 +1,182 @@ -use strum::EnumIter; -use glam::{Vec3, vec3, IVec3, ivec3}; -use std::f32::consts::FRAC_1_SQRT_2; -use crate::rendering::world::ChunkVertex; - -#[repr(usize)] -#[derive(Clone, Copy, Debug, EnumIter)] -pub enum CubeFace { - Top = 0, - Front = 4, - Left = 2, - Right = 3, - Back = 1, - Bottom = 5, -} -impl CubeFace { - pub const fn normal(self) -> IVec3 { - CUBE_FACE_NORMALS_IVEC3[self as usize] - } -} - -const CUBE_FACE_VERTICES: [[Vec3; 4]; 6] = [ - [vec3(0., 1., 0.), vec3(0., 1., 1.), vec3(1., 1., 0.), vec3(1., 1., 1.)], - [vec3(0., 0., 0.), vec3(0., 1., 0.), vec3(1., 0., 0.), vec3(1., 1., 0.)], - [vec3(0., 0., 1.), vec3(0., 1., 1.), vec3(0., 0., 0.), vec3(0., 1., 0.)], - [vec3(1., 0., 0.), vec3(1., 1., 0.), vec3(1., 0., 1.), vec3(1., 1., 1.)], - [vec3(1., 0., 1.), vec3(1., 1., 1.), vec3(0., 0., 1.), vec3(0., 1., 1.)], - [vec3(0., 0., 1.), vec3(0., 0., 0.), vec3(1., 0., 1.), vec3(1., 0., 0.)], -]; -const CUBE_FACE_NORMALS_IVEC3: [IVec3; 6] = [ - ivec3( 0, 1, 0), - ivec3( 0, 0, -1), - ivec3(-1, 0, 0), - ivec3( 1, 0, 0), - ivec3( 0, 0, 1), - ivec3( 0, -1, 0) -]; -const CUBE_FACE_NORMALS: [Vec3; 6] = [ - vec3(0., 1., 0.), - vec3(0., 0., -1.), - vec3(-1.,0., 0.), - vec3(1., 0., 0.), - vec3(0., 0., 1.), - vec3(0., -1.,0.) -]; -const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; - -#[repr(usize)] -pub enum DiagonalFace { - RigthZ = 0, - LeftZ = 1, -} -const CROSS_FACES: [[Vec3; 4]; 2] = [ - [ - vec3(0., 0., 0.), - vec3(0., 1., 0.), - vec3(1., 0., 1.), - vec3(1., 1., 1.), - ], - [ - vec3(0., 0., 1.), - vec3(0., 1., 1.), - vec3(1., 0., 0.), - vec3(1., 1., 0.), - ] -]; -const CROSS_FACE_NORMALS: [Vec3; 2] = [ - vec3(-FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), - vec3( FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), -]; -const CROSS_FACE_NORMALS_BACK: [Vec3; 2] = [ - vec3( FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), - vec3(-FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), -]; -const CROSS_FACE_INDICES: [u32; 12] = [ - 0, 1, 2, 2, 1, 3, //Front side - 6, 5, 4, 7, 5, 6, //Back side -]; - - -const UV_COORDS: [[f32; 2]; 4] = [ - [0., 0.], - [0., 1.], - [1., 0.], - [1., 1.], -]; - -#[derive(Default)] -pub 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_vec3(); - let face_index = face as usize; - - //Push vertices - 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)); - - //Increment idx counter - self.idx_counter += 4; - } - - pub fn add_diagonal_face(&mut self, coord: IVec3, face_type: DiagonalFace, front_texture: u8, back_texture: u8) { - //Push vertices - let face_type = face_type as usize; - let vertices = CROSS_FACES[face_type]; - let normal_front = CROSS_FACE_NORMALS[face_type].to_array(); - let normal_back = CROSS_FACE_NORMALS_BACK[face_type].to_array(); - self.vertex_buffer.reserve(8); - for i in 0..4 { //push front vertices - self.vertex_buffer.push(ChunkVertex { - position: (coord.as_vec3() + vertices[i]).to_array(), - normal: normal_front, - uv: UV_COORDS[i], - tex_index: front_texture - }) - } - for i in 0..4 { //push back vertices - self.vertex_buffer.push(ChunkVertex { - position: (coord.as_vec3() + vertices[i]).to_array(), - normal: normal_back, - uv: UV_COORDS[i], - tex_index: back_texture - }) - } - - //Push indices - self.index_buffer.extend_from_slice(&CROSS_FACE_INDICES.map(|x| x + self.idx_counter)); - - //Increment idx counter - self.idx_counter += 8; - } - - pub fn add_model(&mut self, position: Vec3, vertices: &[ChunkVertex], indices: Option<&[u32]>) { - //push vertices - self.vertex_buffer.extend(vertices.iter().map(|vertex| { - let mut vertex = *vertex; - vertex.position[0] += position.x; - vertex.position[0] += position.y; - vertex.position[0] += position.z; - vertex - })); - //push indices - if let Some(indices) = indices { - self.index_buffer.extend(indices.iter().map(|x| x + self.idx_counter)); - } else { - self.index_buffer.extend(0..(self.vertex_buffer.len() as u32)); - } - //increment idx counter - self.idx_counter += vertices.len() as u32; - } - - pub fn finish(self) -> (Vec, Vec) { - (self.vertex_buffer, self.index_buffer) - } -} +use strum::EnumIter; +use glam::{ivec3, vec3, IVec3, Vec3}; +use std::f32::consts::FRAC_1_SQRT_2; +use crate::rendering::world::ChunkVertex; + +#[repr(usize)] +#[derive(Clone, Copy, Debug, EnumIter)] +pub enum CubeFace { + Top = 0, + Front = 4, + Left = 2, + Right = 3, + Back = 1, + Bottom = 5, +} +impl CubeFace { + pub const fn normal(self) -> IVec3 { + CUBE_FACE_NORMALS_IVEC3[self as usize] + } +} + +const CUBE_FACE_VERTICES: [[Vec3; 4]; 6] = [ + [vec3(0., 1., 0.), vec3(0., 1., 1.), vec3(1., 1., 0.), vec3(1., 1., 1.)], + [vec3(0., 0., 0.), vec3(0., 1., 0.), vec3(1., 0., 0.), vec3(1., 1., 0.)], + [vec3(0., 0., 1.), vec3(0., 1., 1.), vec3(0., 0., 0.), vec3(0., 1., 0.)], + [vec3(1., 0., 0.), vec3(1., 1., 0.), vec3(1., 0., 1.), vec3(1., 1., 1.)], + [vec3(1., 0., 1.), vec3(1., 1., 1.), vec3(0., 0., 1.), vec3(0., 1., 1.)], + [vec3(0., 0., 1.), vec3(0., 0., 0.), vec3(1., 0., 1.), vec3(1., 0., 0.)], +]; +const CUBE_FACE_NORMALS_IVEC3: [IVec3; 6] = [ + ivec3( 0, 1, 0), + ivec3( 0, 0, -1), + ivec3(-1, 0, 0), + ivec3( 1, 0, 0), + ivec3( 0, 0, 1), + ivec3( 0, -1, 0) +]; +const CUBE_FACE_NORMALS: [Vec3; 6] = [ + vec3(0., 1., 0.), + vec3(0., 0., -1.), + vec3(-1.,0., 0.), + vec3(1., 0., 0.), + vec3(0., 0., 1.), + vec3(0., -1.,0.) +]; +const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; + +#[repr(usize)] +pub enum DiagonalFace { + RigthZ = 0, + LeftZ = 1, +} +const CROSS_FACES: [[Vec3; 4]; 2] = [ + [ + vec3(0., 0., 0.), + vec3(0., 1., 0.), + vec3(1., 0., 1.), + vec3(1., 1., 1.), + ], + [ + vec3(0., 0., 1.), + vec3(0., 1., 1.), + vec3(1., 0., 0.), + vec3(1., 1., 0.), + ] +]; +const CROSS_FACE_NORMALS: [Vec3; 2] = [ + vec3(-FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), + vec3( FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), +]; +const CROSS_FACE_NORMALS_BACK: [Vec3; 2] = [ + vec3( FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), + vec3(-FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), +]; +const CROSS_FACE_INDICES: [u32; 12] = [ + 0, 1, 2, 2, 1, 3, //Front side + 6, 5, 4, 7, 5, 6, //Back side +]; + + +const UV_COORDS: [[f32; 2]; 4] = [ + [0., 0.], + [0., 1.], + [1., 0.], + [1., 1.], +]; + +#[derive(Default)] +pub struct MeshBuilder { + offset: Vec3, + vertex_buffer: Vec, + index_buffer: Vec, + idx_counter: u32, +} +impl MeshBuilder { + pub fn new() -> Self { + Self::default() + } + + pub fn new_with_offset(offset: Vec3) -> Self { + Self { offset, ..Self::new() } + } + + pub fn add_face(&mut self, face: CubeFace, coord: IVec3, texture: u8) { + let coord = coord.as_vec3(); + let face_index = face as usize; + + //Push vertices + 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] + self.offset).to_array(), + normal: norm.to_array(), + uv: UV_COORDS[i], + tex_index: texture as u32 + }); + } + + //Push indices + self.index_buffer.extend_from_slice(&CUBE_FACE_INDICES.map(|x| x + self.idx_counter)); + + //Increment idx counter + self.idx_counter += 4; + } + + pub fn add_diagonal_face(&mut self, coord: IVec3, face_type: DiagonalFace, front_texture: u8, back_texture: u8) { + //Push vertices + let face_type = face_type as usize; + let vertices = CROSS_FACES[face_type]; + let normal_front = CROSS_FACE_NORMALS[face_type].to_array(); + let normal_back = CROSS_FACE_NORMALS_BACK[face_type].to_array(); + self.vertex_buffer.reserve(8); + for i in 0..4 { //push front vertices + self.vertex_buffer.push(ChunkVertex { + position: (coord.as_vec3() + vertices[i] + self.offset).to_array(), + normal: normal_front, + uv: UV_COORDS[i], + tex_index: front_texture as u32 + }) + } + for i in 0..4 { //push back vertices + self.vertex_buffer.push(ChunkVertex { + position: (coord.as_vec3() + vertices[i] + self.offset).to_array(), + normal: normal_back, + uv: UV_COORDS[i], + tex_index: back_texture as u32 + }) + } + + //Push indices + self.index_buffer.extend_from_slice(&CROSS_FACE_INDICES.map(|x| x + self.idx_counter)); + + //Increment idx counter + self.idx_counter += 8; + } + + //XXX: needs offset supprt + // pub fn add_model(&mut self, position: Vec3, vertices: &[ChunkVertex], indices: Option<&[u32]>) { + // //push vertices + // self.vertex_buffer.extend(vertices.iter().map(|vertex| { + // let mut vertex = *vertex; + // vertex.position[0] += position.x; + // vertex.position[0] += position.y; + // vertex.position[0] += position.z; + // vertex + // })); + // //push indices + // if let Some(indices) = indices { + // self.index_buffer.extend(indices.iter().map(|x| x + self.idx_counter)); + // } else { + // self.index_buffer.extend(0..(self.vertex_buffer.len() as u32)); + // } + // //increment idx counter + // self.idx_counter += vertices.len() as u32; + // } + + pub fn finish(self) -> (Vec, Vec) { + (self.vertex_buffer, self.index_buffer) + } +} diff --git a/kubi/src/world/tasks.rs b/kubi/src/world/tasks.rs index 87bda90..a481f5f 100644 --- a/kubi/src/world/tasks.rs +++ b/kubi/src/world/tasks.rs @@ -63,7 +63,7 @@ impl ChunkTaskManager { let ( (vertices, indices), (trans_vertices, trans_indices), - ) = generate_mesh(data); + ) = generate_mesh(position, data); ChunkTaskResponse::GeneratedMesh { position, vertices, indices,