diff --git a/Cargo.lock b/Cargo.lock index 8ceea60..f3a4dff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,9 +321,9 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block2" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ "objc2", ] @@ -417,9 +417,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "cfg_aliases" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "codespan-reporting" @@ -1200,15 +1200,15 @@ dependencies = [ [[package]] name = "objc-sys" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da284c198fb9b7b0603f8635185e85fbd5b64ee154b1ed406d489077de2d6d60" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ "objc-sys", "objc2-encode", @@ -1216,21 +1216,172 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.5.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.5.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2", "objc2", - "objc2-core-data", "objc2-foundation", ] [[package]] name = "objc2-core-data" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.5.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.5.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.5.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.5.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.5.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2", "objc2", @@ -1238,20 +1389,16 @@ dependencies = [ ] [[package]] -name = "objc2-encode" -version = "4.0.1" +name = "objc2-user-notifications" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" - -[[package]] -name = "objc2-foundation" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ + "bitflags 2.5.0", "block2", - "dispatch", "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] @@ -2123,9 +2270,9 @@ dependencies = [ [[package]] name = "wgpu" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ff1bfee408e1028e2e3acbf6d32d98b08a5a059ccbf5f33305534453ba5d3e" +checksum = "90e37c7b9921b75dfd26dd973fdcbce36f13dfa6e2dc82aece584e0ed48c355c" dependencies = [ "arrayvec", "cfg-if", @@ -2149,9 +2296,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6a86eaa5e763e59c73cf9e97d55fffd4dfda69fd8bda19589fcf851ddfef1f" +checksum = "d59e0d5fc509601c69e4e1fa06c1eb3c4c9f12956a5e30c79b61ef1c1be7daf0" dependencies = [ "arrayvec", "bit-vec", @@ -2176,9 +2323,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d71c8ae05170583049b65ee562fd839fdc0b3e9ddb84f4e40c9d5f8ea0d4c8c" +checksum = "6aa24c3889f885a3fb9133b454c8418bfcfaadcfe4ed3be96ac80e76703b863b" dependencies = [ "android_system_properties", "arrayvec", @@ -2494,17 +2641,18 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" -version = "0.30.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e6d5d66cbf702e0dd820302144f51b69a95acdc495dd98ca280ff206562b1" +checksum = "763759577d7e92f618ecaca2f5fe415512cae924cfc9460d1c48e1c616c716aa" dependencies = [ "ahash", "android-activity", "atomic-waker", "bitflags 2.5.0", + "block2", "bytemuck", "calloop", - "cfg_aliases 0.2.0", + "cfg_aliases 0.2.1", "concurrent-queue", "core-foundation", "core-graphics", @@ -2517,6 +2665,7 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", + "objc2-ui-kit", "orbclient", "percent-encoding", "pin-project", diff --git a/Cargo.toml b/Cargo.toml index d2cb9f5..31e6447 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ pollster = "0.3" rand = "0.8.5" simba = "0.8.1" smaa = "0.14.0" -wgpu = "0.20" +wgpu = "0.20.1" bevy_ecs = "0.13.2" bevy_derive = "0.13.2" -winit = {version="0.30", features=["serde"]} +winit = {version="0.30.1", features=["serde"]} diff --git a/src/client/mod.rs b/src/client/mod.rs index 0c3f708..7c41803 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -22,7 +22,11 @@ use crate::{ }; use self::{input::Input, render::Renderer, ClientState}; -use std::{collections::HashMap, sync::Arc, time::{Duration, Instant}}; +use std::{ + collections::HashMap, + sync::Arc, + time::{Duration, Instant}, +}; use winit::{ event::WindowEvent, window::{Window, WindowAttributes}, @@ -44,6 +48,7 @@ pub struct Client<'a> { systems: ClientSystems, target: Instant, frame_time: Duration, + the_thing: bool, } pub struct ClientSystems { @@ -86,6 +91,7 @@ impl Client<'_> { server_id_map: HashMap::new(), target: Instant::now(), frame_time: FRAME_TIME, + the_thing: false, } } @@ -106,6 +112,13 @@ impl Client<'_> { .expect("WHAT"); self.world.clear_trackers(); + if self.state.camera.pos.y < -10.0 { + self.the_thing = !self.the_thing; + if self.the_thing == true { + let thing = include_bytes!("../../../../videos/meme/rab_falls_and_dies.mp4"); + } + } + if now >= self.target { self.target += self.frame_time; let mut commands = std::mem::take(&mut self.render_commands); diff --git a/src/client/render/command.rs b/src/client/render/command.rs index c8f846c..b8d2a75 100644 --- a/src/client/render/command.rs +++ b/src/client/render/command.rs @@ -3,6 +3,7 @@ use crate::client::camera::Camera; use super::{voxel::VoxelColor, Renderer}; use bevy_ecs::entity::Entity; use nalgebra::{Rotation3, Vector3}; +use ndarray::Array3; use std::sync::Arc; use winit::window::Window; @@ -19,7 +20,7 @@ pub struct CreateVoxelGrid { pub pos: Vector3, pub orientation: Rotation3, pub dimensions: Vector3, - pub grid: Vec, + pub grid: Array3, } #[derive(Debug, Clone)] diff --git a/src/client/render/mod.rs b/src/client/render/mod.rs index cdd5b94..afc77c5 100644 --- a/src/client/render/mod.rs +++ b/src/client/render/mod.rs @@ -1,14 +1,16 @@ mod command; mod util; pub mod voxel; +pub mod voxel_poly; pub use command::*; +use util::Texture; use super::camera::Camera; use crate::client::rsc::CLEAR_COLOR; use nalgebra::Vector2; use smaa::{SmaaMode, SmaaTarget}; -use voxel::VoxelPipeline; +use voxel_poly::VoxelPipeline; use winit::dpi::PhysicalSize; pub struct Renderer<'a> { @@ -22,6 +24,7 @@ pub struct Renderer<'a> { voxel_pipeline: VoxelPipeline, smaa_target: SmaaTarget, camera: Camera, + depth_texture: Texture, } impl<'a> Renderer<'a> { @@ -67,7 +70,7 @@ impl<'a> Renderer<'a> { format: surface_format, width: size.width, height: size.height, - present_mode: surface_caps.present_modes[0], + present_mode: wgpu::PresentMode::AutoVsync, alpha_mode: surface_caps.alpha_modes[0], view_formats: vec![], desired_maximum_frame_latency: 2, @@ -87,10 +90,12 @@ impl<'a> Renderer<'a> { SmaaMode::Smaa1X, ); + let depth_texture = Texture::create_depth_texture(&device, &config, "depth_texture"); + Self { camera: Camera::default(), size: Vector2::new(size.width, size.height), - voxel_pipeline: VoxelPipeline::new(&device, &config.format), + voxel_pipeline: VoxelPipeline::new(&device, &config), staging_belt, surface, encoder: Self::create_encoder(&device), @@ -98,6 +103,7 @@ impl<'a> Renderer<'a> { config, queue, smaa_target, + depth_texture, } } @@ -127,7 +133,14 @@ impl<'a> Renderer<'a> { store: wgpu::StoreOp::Store, }, })], - depth_stencil_attachment: None, + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_texture.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), timestamp_writes: None, occlusion_query_set: None, }); @@ -149,6 +162,8 @@ impl<'a> Renderer<'a> { self.smaa_target .resize(&self.device, size.width, size.height); + self.depth_texture = + Texture::create_depth_texture(&self.device, &self.config, "depth_texture"); self.voxel_pipeline.update_view( &self.device, &mut self.encoder, diff --git a/src/client/render/util/instance.rs b/src/client/render/util/instance.rs index 3d1ade7..12904d4 100644 --- a/src/client/render/util/instance.rs +++ b/src/client/render/util/instance.rs @@ -5,7 +5,7 @@ use super::buf::{ArrBuf, ArrBufUpdate, BufMove}; pub struct Instances { buf: ArrBuf, location: u32, - attrs: [VertexAttribute; 1], + attrs: Vec, } impl Instances { @@ -24,7 +24,7 @@ impl Instances { device: &wgpu::Device, label: &str, location: u32, - format: wgpu::VertexFormat, + attrs: &[wgpu::VertexAttribute], ) -> Self { Self { buf: ArrBuf::init( @@ -33,11 +33,26 @@ impl Instances { BufferUsages::VERTEX, ), location, - attrs: [wgpu::VertexAttribute { - format, - offset: 0, - shader_location: location, - }], + attrs: attrs.to_vec(), + } + } + + pub fn init_with( + device: &wgpu::Device, + label: &str, + location: u32, + attrs: &[wgpu::VertexAttribute], + data: &[T], + ) -> Self { + Self { + buf: ArrBuf::init_with( + device, + &(label.to_owned() + " Instance"), + BufferUsages::VERTEX, + data, + ), + location, + attrs: attrs.to_vec(), } } @@ -56,4 +71,8 @@ impl Instances { pub fn mov(&mut self, mov: BufMove) { self.buf.mov(mov); } + + pub fn len(&self) -> usize { + self.buf.len() + } } diff --git a/src/client/render/util/mod.rs b/src/client/render/util/mod.rs index 66b2637..cc11480 100644 --- a/src/client/render/util/mod.rs +++ b/src/client/render/util/mod.rs @@ -2,8 +2,12 @@ mod buf; mod instance; mod storage; mod uniform; +mod vertex; +mod texture; pub use buf::*; pub use instance::*; pub use storage::*; pub use uniform::*; +pub use vertex::*; +pub use texture::*; diff --git a/src/client/render/util/storage.rs b/src/client/render/util/storage.rs index afbf80f..9b73cd4 100644 --- a/src/client/render/util/storage.rs +++ b/src/client/render/util/storage.rs @@ -1,12 +1,12 @@ use super::buf::{ArrBuf, ArrBufUpdate, BufMove}; use wgpu::BufferUsages; -pub struct Storage { +pub struct Storage { binding: u32, buf: ArrBuf, } -impl Storage { +impl Storage { pub fn init(device: &wgpu::Device, label: &str, binding: u32) -> Self { Self { buf: ArrBuf::init( @@ -30,7 +30,7 @@ impl Storage { } } -impl Storage { +impl Storage { pub fn bind_group_layout_entry(&self) -> wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry { binding: self.binding, diff --git a/src/client/render/util/texture.rs b/src/client/render/util/texture.rs new file mode 100644 index 0000000..a72b490 --- /dev/null +++ b/src/client/render/util/texture.rs @@ -0,0 +1,55 @@ +pub struct Texture { + pub texture: wgpu::Texture, + pub view: wgpu::TextureView, + pub sampler: wgpu::Sampler, +} + +impl Texture { + pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; // 1. + + pub fn create_depth_texture( + device: &wgpu::Device, + config: &wgpu::SurfaceConfiguration, + label: &str, + ) -> Self { + let size = wgpu::Extent3d { + // 2. + width: config.width, + height: config.height, + depth_or_array_layers: 1, + }; + let desc = wgpu::TextureDescriptor { + label: Some(label), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::DEPTH_FORMAT, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT // 3. + | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }; + let texture = device.create_texture(&desc); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + // 4. + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + compare: Some(wgpu::CompareFunction::LessEqual), // 5. + lod_min_clamp: 0.0, + lod_max_clamp: 100.0, + ..Default::default() + }); + + Self { + texture, + view, + sampler, + } + } +} diff --git a/src/client/render/util/uniform.rs b/src/client/render/util/uniform.rs index 6c806ee..c78342d 100644 --- a/src/client/render/util/uniform.rs +++ b/src/client/render/util/uniform.rs @@ -23,6 +23,17 @@ impl Uniform { } impl Uniform { + pub fn init_with(device: &wgpu::Device, name: &str, binding: u32, data: &[T]) -> Self { + Self { + buffer: device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some(&(name.to_owned() + " Uniform Buf")), + contents: bytemuck::cast_slice(data), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }), + binding, + ty: PhantomData, + } + } pub fn bind_group_layout_entry(&self) -> wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry { binding: self.binding, diff --git a/src/client/render/util/vertex.rs b/src/client/render/util/vertex.rs new file mode 100644 index 0000000..9d892fc --- /dev/null +++ b/src/client/render/util/vertex.rs @@ -0,0 +1,86 @@ +use wgpu::{BufferUsages, VertexAttribute}; + +use super::buf::{ArrBuf, ArrBufUpdate, BufMove}; + +pub struct Vertices { + buf: ArrBuf, + location: u32, + attrs: [VertexAttribute; 1], +} + +impl Vertices { + pub fn update( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, + size: usize, + updates: &[ArrBufUpdate], + ) -> bool { + self.buf.update(device, encoder, belt, size, updates) + } + + pub fn init( + device: &wgpu::Device, + label: &str, + location: u32, + format: wgpu::VertexFormat, + ) -> Self { + Self { + buf: ArrBuf::init( + device, + &(label.to_owned() + " Instance"), + BufferUsages::VERTEX, + ), + location, + attrs: [wgpu::VertexAttribute { + format, + offset: 0, + shader_location: location, + }], + } + } + + pub fn init_with( + device: &wgpu::Device, + label: &str, + location: u32, + format: wgpu::VertexFormat, + data: &[T], + ) -> Self { + Self { + buf: ArrBuf::init_with( + device, + &(label.to_owned() + " Instance"), + BufferUsages::VERTEX, + data, + ), + location, + attrs: [wgpu::VertexAttribute { + format, + offset: 0, + shader_location: location, + }], + } + } + + pub fn set_in<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_vertex_buffer(self.location, self.buf.buffer().slice(..)); + } + + pub fn desc(&self) -> wgpu::VertexBufferLayout { + wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &self.attrs, + } + } + + pub fn mov(&mut self, mov: BufMove) { + self.buf.mov(mov); + } + + pub fn len(&self) -> usize { + self.buf.len() + } +} diff --git a/src/client/render/voxel/mod.rs b/src/client/render/voxel/mod.rs index 82a2a5d..35ca5a7 100644 --- a/src/client/render/voxel/mod.rs +++ b/src/client/render/voxel/mod.rs @@ -150,7 +150,7 @@ impl VoxelPipeline { let updates = [ArrBufUpdate { offset, - data: &grid, + data: &grid.as_slice().unwrap(), }]; let size = offset + grid.len(); self.voxels.update(device, encoder, belt, size, &updates); @@ -226,7 +226,6 @@ impl VoxelPipeline { width: size.x, height: size.y, zoom: camera.scale, - padding: 0, transform, }; self.view.update(device, encoder, belt, data) diff --git a/src/client/render/voxel/shader.wgsl b/src/client/render/voxel/shader.wgsl index 087a443..51f1a87 100644 --- a/src/client/render/voxel/shader.wgsl +++ b/src/client/render/voxel/shader.wgsl @@ -6,15 +6,13 @@ struct GlobalLight { struct VertexOutput { @builtin(position) clip_position: vec4, - @location(0) tex_coords: vec2, }; struct View { + transform: mat4x4, width: u32, height: u32, zoom: f32, - padding: u32, - transform: mat4x4, }; struct VoxelGroup { diff --git a/src/client/render/voxel/view.rs b/src/client/render/voxel/view.rs index 909571d..cb892b2 100644 --- a/src/client/render/voxel/view.rs +++ b/src/client/render/voxel/view.rs @@ -3,11 +3,10 @@ use nalgebra::Transform3; #[repr(C, align(16))] #[derive(Clone, Copy, PartialEq, bytemuck::Zeroable)] pub struct View { + pub transform: Transform3, pub width: u32, pub height: u32, pub zoom: f32, - pub padding: u32, - pub transform: Transform3, } unsafe impl bytemuck::Pod for View {} @@ -18,7 +17,6 @@ impl Default for View { width: 1, height: 1, zoom: 1.0, - padding: 0, transform: Transform3::identity(), } } diff --git a/src/client/render/voxel_poly/group.rs b/src/client/render/voxel_poly/group.rs new file mode 100644 index 0000000..f574a18 --- /dev/null +++ b/src/client/render/voxel_poly/group.rs @@ -0,0 +1,11 @@ +use nalgebra::{Transform3, Vector3}; + +#[repr(C, align(16))] +#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Zeroable, Default)] +pub struct FaceGroup { + pub transform: Transform3, + pub dimensions: Vector3, + pub face: u32, +} + +unsafe impl bytemuck::Pod for FaceGroup {} diff --git a/src/client/render/voxel_poly/instance.rs b/src/client/render/voxel_poly/instance.rs new file mode 100644 index 0000000..4c29adb --- /dev/null +++ b/src/client/render/voxel_poly/instance.rs @@ -0,0 +1,12 @@ +use bytemuck::Zeroable; + +use crate::client::render::voxel::VoxelColor; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Zeroable)] +pub struct VoxelFace { + pub index: u32, + pub color: VoxelColor, +} + +unsafe impl bytemuck::Pod for VoxelFace {} diff --git a/src/client/render/voxel_poly/mod.rs b/src/client/render/voxel_poly/mod.rs index 00729ca..3b1545d 100644 --- a/src/client/render/voxel_poly/mod.rs +++ b/src/client/render/voxel_poly/mod.rs @@ -1,26 +1,47 @@ -use super::uniform::Uniform; -use nalgebra::{Projective3, Translation3, Rotation3}; - -mod view; mod color; -mod vertex; +mod group; +mod instance; mod square; +mod view; + +use core::panic; + +use group::FaceGroup; +use instance::VoxelFace; +use nalgebra::{Perspective3, Transform3, Translation3, Vector2, Vector3}; +use view::View; +use wgpu::{SurfaceConfiguration, VertexAttribute, VertexFormat}; + +use crate::client::camera::Camera; + +use super::{ + util::{Instances, Texture, Uniform}, + CreateVoxelGrid, UpdateGridTransform, +}; pub struct VoxelPipeline { pipeline: wgpu::RenderPipeline, view: Uniform, bind_group_layout: wgpu::BindGroupLayout, - bind_group: wgpu::BindGroup, - voxel_groups: Storage, - voxels: Storage, - arst: bool, + bind_groups: Vec, + vertices: Vec>, } -const WIDTH: u32 = 300; -const HEIGHT: u32 = 300; +const INSTANCE_ATTRS: [wgpu::VertexAttribute; 2] = [ + VertexAttribute { + format: VertexFormat::Uint32, + offset: 0, + shader_location: 0, + }, + VertexAttribute { + format: VertexFormat::Uint32, + offset: 4, + shader_location: 1, + }, +]; impl VoxelPipeline { - pub fn new(device: &wgpu::Device, format: &wgpu::TextureFormat) -> Self { + pub fn new(device: &wgpu::Device, config: &SurfaceConfiguration) -> Self { // shaders let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("Tile Shader"), @@ -28,29 +49,19 @@ impl VoxelPipeline { }); let view = Uniform::::init(device, "view", 0); - let voxels = Storage::init(device, "voxels", 1); - let voxel_groups = Storage::init(device, "voxel groups", 2); + let example_faces = + Instances::::init(device, "voxel groups", 0, &INSTANCE_ATTRS); + let example_group = Uniform::::init(device, "voxel group", 1); // bind groups let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[ view.bind_group_layout_entry(), - voxels.bind_group_layout_entry(), - voxel_groups.bind_group_layout_entry(), + example_group.bind_group_layout_entry(), ], label: Some("tile_bind_group_layout"), }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - entries: &[ - view.bind_group_entry(), - voxels.bind_group_entry(), - voxel_groups.bind_group_entry(), - ], - label: Some("tile_bind_group"), - }); - // pipeline let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { @@ -65,14 +76,14 @@ impl VoxelPipeline { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - buffers: &[], + buffers: &[example_faces.desc()], compilation_options: wgpu::PipelineCompilationOptions::default(), }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { - format: *format, + format: config.format, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, })], @@ -82,12 +93,18 @@ impl VoxelPipeline { topology: wgpu::PrimitiveTopology::TriangleStrip, strip_index_format: None, front_face: wgpu::FrontFace::Ccw, - cull_mode: None, + cull_mode: Some(wgpu::Face::Back), polygon_mode: wgpu::PolygonMode::Fill, unclipped_depth: false, conservative: false, }, - depth_stencil: None, + depth_stencil: Some(wgpu::DepthStencilState { + format: Texture::DEPTH_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), multisample: wgpu::MultisampleState { count: 1, mask: !0, @@ -99,165 +116,123 @@ impl VoxelPipeline { Self { pipeline: render_pipeline, view, - bind_group, bind_group_layout, - voxels, - voxel_groups, - arst: false, + bind_groups: Vec::new(), + vertices: Vec::new(), } } - pub fn update( + pub fn update_view( &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, - update_data: &RenderUpdateData, + size: Vector2, + camera: &Camera, ) { - if !self.arst { - let lx = 15; - let ly = 10; - let lz = 10; - let mut data = vec![VoxelColor::none(); lx * ly * lz]; - for x in 0..lx { - for y in 0..ly { - data[x + y * lx] = VoxelColor { - r: (x as f32 / lx as f32 * 255.0) as u8, - g: (y as f32 / ly as f32 * 255.0) as u8, - b: 0, - a: 100, - }; - } - } - for x in 0..lx { - for y in 0..ly { - data[x + y * lx + 3 * lx * ly] = VoxelColor { - r: (x as f32 / lx as f32 * 255.0) as u8, - g: (y as f32 / ly as f32 * 255.0) as u8, - b: 100, - a: 255, - }; - } - } - for i in 0..lx.min(ly.min(lz)) { - data[i + i * lx + i * lx * ly] = VoxelColor::white(); - } - - let lx2 = 1000; - let ly2 = 2; - let lz2 = 1000; - let offset2 = data.len(); - let mut data2 = vec![VoxelColor::none(); lx2 * ly2 * lz2]; - let paint = VoxelColor { - r: 255, - g: 0, - b: 255, - a: 255, - }; - for x in 0..lx2 { - data2[x + (ly2 - 1) * lx2] = paint; - data2[x + (ly2 - 1) * lx2 + (lz2 - 1) * lx2 * ly2] = paint; - } - for z in 0..lz2 { - data2[(ly2 - 1) * lx2 + z * lx2 * ly2] = paint; - data2[lx2 - 1 + (ly2 - 1) * lx2 + z * lx2 * ly2] = paint; - } - for x in 0..lx2 { - for z in 0..lz2 { - data2[x + z * lx2 * ly2] = rand::random(); - } - } - data.append(&mut data2); - let lx3 = 3; - let ly3 = 3; - let lz3 = 3; - let offset3 = data.len(); - data.append(&mut vec![ - VoxelColor { - r: 255, - g: 0, - b: 255, - a: 255, - }; - lx3 * ly3 * lz3 - ]); - self.voxels.update( - device, - encoder, - belt, - data.len(), - &[ArrBufUpdate { offset: 0, data }], - ); - let proj = Projective3::identity() - * Translation3::new(0.0, 0.0, 20.0) - * Rotation3::from_axis_angle(&Vector3::y_axis(), 0.5) - * Translation3::new(-(lx as f32 / 2.0), -(ly as f32 / 2.0), -(lz as f32 / 2.0)); - let group = VoxelGroup { - transform: proj, - transform_inv: proj.inverse(), - dimensions: Vector3::new(lx as u32, ly as u32, lz as u32), - offset: 0, - }; - let proj2 = Projective3::identity() - * Translation3::new(0.0, -2.1, 20.0) - * Translation3::new( - -(lx2 as f32 / 2.0), - -(ly2 as f32 / 2.0), - -(lz2 as f32 / 2.0), - ); - let group2 = VoxelGroup { - transform: proj2, - transform_inv: proj2.inverse(), - dimensions: Vector3::new(lx2 as u32, ly2 as u32, lz2 as u32), - offset: offset2 as u32, - }; - let proj3 = Projective3::identity() - * Translation3::new(0.0, 0.0, 16.5) - * Rotation3::from_axis_angle(&Vector3::y_axis(), std::f32::consts::PI / 4.0) - * Rotation3::from_axis_angle( - &UnitVector3::new_normalize(Vector3::new(1.0, 0.0, 1.0)), - std::f32::consts::PI / 4.0, - ) - * Translation3::new( - -(lx3 as f32 / 2.0), - -(ly3 as f32 / 2.0), - -(lz3 as f32 / 2.0), - ); - let group3 = VoxelGroup { - transform: proj3, - transform_inv: proj3.inverse(), - dimensions: Vector3::new(lx3 as u32, ly3 as u32, lz3 as u32), - offset: offset3 as u32, - }; - let groups = vec![group, group2, group3]; - self.voxel_groups.update( - device, - encoder, - belt, - groups.len(), - &[ArrBufUpdate { - offset: 0, - data: groups, - }], - ); - self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &self.bind_group_layout, - entries: &[ - self.view.bind_group_entry(), - self.voxels.bind_group_entry(), - self.voxel_groups.bind_group_entry(), - ], - label: Some("tile_bind_group"), - }); - - self.arst = true; - } - self.view.update(device, encoder, belt, update_data); + let mut transform = (Translation3::from(camera.pos) * camera.orientation) + .inverse() + .to_matrix(); + transform = transform.append_nonuniform_scaling(&Vector3::new(1.0, 1.0, -1.0)); + let projection = Perspective3::new( + size.x as f32 / size.y as f32, + std::f32::consts::PI / 2.0, + 0.1, + 1000.0, + ); + transform = projection.as_matrix() * transform; + let data = View { + width: size.x, + height: size.y, + zoom: camera.scale, + transform, + }; + self.view.update(device, encoder, belt, data) } pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &self.bind_group, &[]); - render_pass.draw(0..4, 0..1); + for i in 0..self.bind_groups.len() { + render_pass.set_bind_group(0, &self.bind_groups[i], &[]); + let vertices = &self.vertices[i]; + vertices.set_in(render_pass); + render_pass.draw(0..4, 0..vertices.len() as u32); + } + } + + pub fn add_group( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, + CreateVoxelGrid { + id, + pos, + orientation, + dimensions, + grid, + }: CreateVoxelGrid, + ) { + let proj = Transform3::identity() + * Translation3::from(pos) + * orientation + * Translation3::from(-dimensions.cast() / 2.0); + for face in 0..6 { + let group = FaceGroup { + dimensions: dimensions.cast(), + transform: proj, + face, + }; + let uniform = Uniform::init_with(device, "voxel group", 1, &[group]); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &self.bind_group_layout, + entries: &[self.view.bind_group_entry(), uniform.bind_group_entry()], + label: Some("voxel bind group"), + }); + self.bind_groups.push(bind_group); + + let mut data = Vec::new(); + let n_offset = match face % 3 { + 0 => 1, + 1 => dimensions.z * dimensions.y, + 2 => dimensions.z, + _ => 0, + } as i32 + * ((face as i32 / 3) * 2 - 1); + let face_dir = (face as i32 / 3) * 2 - 1; + for (i, ((x, y, z), color)) in grid.indexed_iter().enumerate() { + let neighbor = match face { + 0 => if z > 0 {Some((x, y, z - 1))} else {None}, + 2 => if y > 0 {Some((x, y - 1, z))} else {None}, + 1 => if x > 0 {Some((x - 1, y, z))} else {None}, + 3 => if z < dimensions.z - 1 {Some((x, y, z + 1))} else {None}, + 5 => if y < dimensions.y - 1 {Some((x, y + 1, z))} else {None}, + 4 => if x < dimensions.x - 1 {Some((x + 1, y, z))} else {None}, + _ => panic!("what"), + }.map(|p| grid.get(p).unwrap()); + if color.a > 0 && !neighbor.is_some_and(|c| c.a == color.a) { + data.push(VoxelFace { + index: i as u32, + color: *color, + }); + } + } + self.vertices.push(Instances::init_with( + device, + "vvvvv", + 0, + &INSTANCE_ATTRS, + &data, + )); + } + } + + pub fn update_transform( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + staging_belt: &mut wgpu::util::StagingBelt, + update: UpdateGridTransform, + ) { } } diff --git a/src/client/render/voxel_poly/shader.wgsl b/src/client/render/voxel_poly/shader.wgsl index acecf17..9206e92 100644 --- a/src/client/render/voxel_poly/shader.wgsl +++ b/src/client/render/voxel_poly/shader.wgsl @@ -1,10 +1,20 @@ // Vertex shader +struct InstanceInput { + @location(0) index: u32, + @location(1) color: u32, +}; + struct VertexOutput { @builtin(position) clip_position: vec4, - @location(0) tex_coords: vec2, + @location(0) color: vec4, }; +struct VoxelFace { + index: u32, + color: u32, +} + struct View { transform: mat4x4, width: u32, @@ -14,31 +24,51 @@ struct View { struct VoxelGroup { transform: mat4x4, - transform_inv: mat4x4, dimensions: vec3, - offset: u32, + face: u32, }; @group(0) @binding(0) var view: View; @group(0) @binding(1) -var voxels: array; -@group(0) @binding(2) -var voxel_groups: array; +var group: VoxelGroup; + +const DIRECTIONS = array( + vec3(1.0, 1.0, 0.0), + vec3(0.0, 1.0, 1.0), + vec3(1.0, 0.0, 1.0), +); @vertex fn vs_main( @builtin(vertex_index) vi: u32, - @builtin(instance_index) ii: u32, + in: InstanceInput ) -> VertexOutput { var out: VertexOutput; - var pos = vec2( - f32(vi % 2u) * 2.0 - 1.0, - f32(vi / 2u) * 2.0 - 1.0, - ) ; - out.clip_position = vec4(pos.x, pos.y, 0.0, 1.0); - out.tex_coords = pos; + let invert = select(0.0, 1.0, group.face / 3 == 1); + let invert_mult = 1.0 - invert * 2.0; + var square_pos = vec2( + f32(vi % 2u), + invert + invert_mult * f32(vi / 2u), + ); + var cube_pos = vec3(invert); + square_pos *= invert_mult; + cube_pos[(group.face) % 3] += square_pos.x; + cube_pos[(group.face + 1) % 3] += square_pos.y; + var pos = vec4( + cube_pos, + 1.0, + ); + pos += vec4( + f32(in.index / (group.dimensions.z * group.dimensions.y)), + f32((in.index / group.dimensions.z) % group.dimensions.y), + f32(in.index % group.dimensions.z), + 0.0, + ); + pos = view.transform * group.transform * pos; + out.clip_position = pos; + out.color = unpack4x8unorm(in.color); return out; } @@ -48,22 +78,5 @@ fn vs_main( fn fs_main( in: VertexOutput, ) -> @location(0) vec4 { - // get position of the pixel; eye at origin, pixel on plane z = 1 - let win_dim = vec2(f32(view.width), f32(view.height)); - let aspect = win_dim.y / win_dim.x; - let pixel_pos = vec3( - (in.clip_position.xy / win_dim - vec2(0.5)) * vec2(2.0, -2.0 * aspect), - 1.0 - ); - - // move to position in world - let pos = view.transform * vec4(pixel_pos, 1.0); - let dir = view.transform * vec4(normalize(pixel_pos), 0.0); - - var color = trace_full(pos, dir); - let light_mult = clamp((-dot(dir.xyz, normalize(GLOBAL_LIGHT)) - 0.99) * 200.0, 0.0, 1.0); - let sky_color = light_mult * vec3(1.0, 1.0, 1.0); - color += vec4(sky_color * (1.0 - color.a), 1.0 - color.a); - color.a = 1.0; - return color; + return in.color; } diff --git a/src/client/render/voxel_poly/vertex.rs b/src/client/render/voxel_poly/vertex.rs deleted file mode 100644 index e43134d..0000000 --- a/src/client/render/voxel_poly/vertex.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[repr(C)] -#[derive(Copy, Clone, Debug)] -struct Vertex { - position: [f32; 3], - color: [f32; 3], -} diff --git a/src/client/render/voxel_poly/view.rs b/src/client/render/voxel_poly/view.rs index 91c5a37..cdee865 100644 --- a/src/client/render/voxel_poly/view.rs +++ b/src/client/render/voxel_poly/view.rs @@ -1,11 +1,9 @@ -use nalgebra::{Transform3, Translation3}; - -use crate::client::render::uniform::UniformData; +use nalgebra::Matrix4; #[repr(C, align(16))] #[derive(Clone, Copy, PartialEq, bytemuck::Zeroable)] pub struct View { - pub transform: Transform3, + pub transform: Matrix4, pub width: u32, pub height: u32, pub zoom: f32, @@ -19,29 +17,7 @@ impl Default for View { width: 1, height: 1, zoom: 1.0, - transform: Transform3::identity(), - } - } -} - -impl UniformData for View { - fn update(&mut self, data: &crate::client::render::RenderUpdateData) -> bool { - let camera = data.state.camera; - let new = Transform3::identity() * Translation3::from(camera.pos) * camera.orientation; - if new == self.transform - && data.size.width == self.width - && data.size.height == self.height - && camera.scale == self.zoom - { - false - } else { - *self = Self { - width: data.size.width, - height: data.size.height, - zoom: camera.scale, - transform: new, - }; - true + transform: Matrix4::identity(), } } } diff --git a/src/client/system/render.rs b/src/client/system/render.rs index c2b0448..fa6f36f 100644 --- a/src/client/system/render.rs +++ b/src/client/system/render.rs @@ -1,3 +1,5 @@ +use std::ops::Deref; + use bevy_ecs::{ entity::Entity, query::{Added, Changed, Or}, @@ -31,7 +33,7 @@ pub fn add_grid( grid.len_of(Axis(1)), grid.len_of(Axis(2)), ), - grid: grid.iter().cloned().collect(), + grid: grid.deref().clone(), })); } } diff --git a/src/world/chunk.rs b/src/world/chunk.rs new file mode 100644 index 0000000..bf727f9 --- /dev/null +++ b/src/world/chunk.rs @@ -0,0 +1,7 @@ +use crate::client::render::voxel::VoxelColor; + +use super::component::TrackedGrid; + +pub struct Chunk { + grid: TrackedGrid +} diff --git a/src/world/mod.rs b/src/world/mod.rs index 4e42b45..6289ee5 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -1,2 +1,3 @@ pub mod component; pub mod generation; +pub mod chunk;