From ef8c75b9dc47142527fc1741d75cf34c66c3ac9d Mon Sep 17 00:00:00 2001 From: Lizzy Fleckenstein Date: Tue, 16 May 2023 15:20:39 +0200 Subject: Split state.rs and add debug menu --- Cargo.lock | 172 +++++++++++++++++++++++++++++-- Cargo.toml | 2 + assets/font/bold-italic.otf | Bin 0 -> 11772 bytes assets/font/bold.otf | Bin 0 -> 11164 bytes assets/font/info.txt | 2 + assets/font/italic.otf | Bin 0 -> 12100 bytes assets/font/regular.otf | Bin 0 -> 11016 bytes src/gfx.rs | 89 +++++++++++----- src/gfx/camera.rs | 67 ++++++++++++ src/gfx/debug_menu.rs | 57 +++++++++++ src/gfx/font.rs | 44 ++++++++ src/gfx/gpu.rs | 168 ++++++++++++++++++++++++++++++ src/gfx/map.rs | 89 ++++++++-------- src/gfx/map/mesh.rs | 2 +- src/gfx/state.rs | 243 -------------------------------------------- 15 files changed, 617 insertions(+), 318 deletions(-) create mode 100644 assets/font/bold-italic.otf create mode 100644 assets/font/bold.otf create mode 100644 assets/font/info.txt create mode 100644 assets/font/italic.otf create mode 100644 assets/font/regular.otf create mode 100644 src/gfx/camera.rs create mode 100644 src/gfx/debug_menu.rs create mode 100644 src/gfx/font.rs create mode 100644 src/gfx/gpu.rs delete mode 100644 src/gfx/state.rs diff --git a/Cargo.lock b/Cargo.lock index a3511eb..132816f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,6 +86,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayref" version = "0.3.6" @@ -286,7 +295,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7" dependencies = [ - "approx", + "approx 0.3.2", "num-traits", "rand 0.6.5", "serde", @@ -317,7 +326,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6107f6be76c2269a9c8d89e707a66122bd3086f987fa508133a5f774e8ac4ced" dependencies = [ - "approx", + "approx 0.3.2", "bit-set", "cgmath", "num", @@ -415,6 +424,30 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg 1.1.0", + "cfg-if", + "crossbeam-utils", + "memoffset 0.8.0", + "scopeguard", +] + [[package]] name = "crossbeam-utils" version = "0.8.15" @@ -528,6 +561,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + [[package]] name = "enumset" version = "1.0.12" @@ -599,6 +638,12 @@ dependencies = [ "vecmath", ] +[[package]] +name = "fps_counter" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aaba7ff514ee9d802b562927f80b1e94e93d8e74c31b134c9c3762dabf1a36b" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -732,9 +777,9 @@ checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "glow" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8edf6019dff2d92ad27c1e3ff82ad50a0aea5b01370353cc928bfdc33e95925c" +checksum = "4e007a07a24de5ecae94160f141029e9a347282cfe25d1d58d85d845cf3130f1" dependencies = [ "js-sys", "slotmap", @@ -742,6 +787,44 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glyph_brush" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edefd123f28a0b1d41ec4a489c2b43020b369180800977801611084f342978d" +dependencies = [ + "glyph_brush_draw_cache", + "glyph_brush_layout", + "ordered-float", + "rustc-hash", + "twox-hash", +] + +[[package]] +name = "glyph_brush_draw_cache" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6010675390f6889e09a21e2c8b575b3ee25667ea8237a8d59423f73cb8c28610" +dependencies = [ + "ab_glyph", + "crossbeam-channel", + "crossbeam-deque", + "linked-hash-map", + "rayon", + "rustc-hash", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38" +dependencies = [ + "ab_glyph", + "approx 0.5.1", + "xi-unicode", +] + [[package]] name = "gpu-alloc" version = "0.5.3" @@ -975,6 +1058,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "lock_api" version = "0.4.9" @@ -1033,6 +1122,15 @@ dependencies = [ "autocfg 1.1.0", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "metal" version = "0.24.0" @@ -1083,6 +1181,7 @@ dependencies = [ "collision", "crossbeam-channel", "fps-camera", + "fps_counter", "futures", "guillotiere", "image", @@ -1097,6 +1196,7 @@ dependencies = [ "threadpool", "tokio", "wgpu", + "wgpu_glyph", "winit", ] @@ -1214,7 +1314,7 @@ dependencies = [ "bitflags", "cfg-if", "libc", - "memoffset", + "memoffset 0.6.5", ] [[package]] @@ -1227,7 +1327,7 @@ dependencies = [ "bitflags", "cfg-if", "libc", - "memoffset", + "memoffset 0.6.5", ] [[package]] @@ -1454,6 +1554,15 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ordered-float" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc2dbde8f8a79f2102cc474ceb0ad68e3b80b85289ea62389b60e66777e4213" +dependencies = [ + "num-traits", +] + [[package]] name = "owned_ttf_parser" version = "0.18.1" @@ -1744,6 +1853,28 @@ dependencies = [ "cty", ] +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -2166,6 +2297,17 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "rand 0.8.5", + "static_assertions", +] + [[package]] name = "typenum" version = "1.16.0" @@ -2495,6 +2637,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wgpu_glyph" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25440d5f32ec39de49c57c15c2d3f9133a7939b069b5ad07e5afd8b78fb8adc" +dependencies = [ + "bytemuck", + "glyph_brush", + "log", + "wgpu", +] + [[package]] name = "widestring" version = "0.5.1" @@ -2677,6 +2831,12 @@ dependencies = [ "nom", ] +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + [[package]] name = "xml-rs" version = "0.8.4" diff --git a/Cargo.toml b/Cargo.toml index e93a015..e4d5af9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ cgmath = "0.17.0" collision = "0.20.1" crossbeam-channel = "0.5.8" fps-camera = "0.1.2" +fps_counter = "2.0.0" futures = { version = "0.3.26" } guillotiere = "0.6.2" image = { version = "0.24.5", features = ["jpeg", "png", "bmp", "tga"], default-features = false } @@ -29,4 +30,5 @@ srp = { git = "https://github.com/minetest-rust/PAKEs.git" } threadpool = "1.8.1" tokio = { version = "1.25.0", features = ["rt", "rt-multi-thread", "signal"] } wgpu = "0.15.1" +wgpu_glyph = "0.19.0" winit = "0.28.1" diff --git a/assets/font/bold-italic.otf b/assets/font/bold-italic.otf new file mode 100644 index 0000000..1f74f38 Binary files /dev/null and b/assets/font/bold-italic.otf differ diff --git a/assets/font/bold.otf b/assets/font/bold.otf new file mode 100644 index 0000000..87b124c Binary files /dev/null and b/assets/font/bold.otf differ diff --git a/assets/font/info.txt b/assets/font/info.txt new file mode 100644 index 0000000..5238883 --- /dev/null +++ b/assets/font/info.txt @@ -0,0 +1,2 @@ +license: Public Domain +link: https://www.fontspace.com/minecraft-font-f28180 \ No newline at end of file diff --git a/assets/font/italic.otf b/assets/font/italic.otf new file mode 100644 index 0000000..6801bd8 Binary files /dev/null and b/assets/font/italic.otf differ diff --git a/assets/font/regular.otf b/assets/font/regular.otf new file mode 100644 index 0000000..54f08ad Binary files /dev/null and b/assets/font/regular.otf differ diff --git a/src/gfx.rs b/src/gfx.rs index ce7ae2e..c465baa 100644 --- a/src/gfx.rs +++ b/src/gfx.rs @@ -8,9 +8,12 @@ use winit::{ platform::run_return::EventLoopExtRunReturn, }; +mod camera; +mod debug_menu; +mod font; +mod gpu; mod map; mod media; -mod state; mod util; pub async fn run( @@ -23,51 +26,80 @@ pub async fn run( window.set_cursor_visible(false); - let mut state = state::State::new(&window).await; + let mut gpu = gpu::Gpu::new(&window).await; let mut map: Option = None; + let mut font = font::Font::new(&gpu); + let mut debug_menu = debug_menu::DebugMenu::new(); let mut media = media::MediaMgr::new(); + let mut camera = camera::Camera::new(&gpu); let mut nodedefs = None; - let mut last_frame = Instant::now(); - + let mut fps_counter = fps_counter::FPSCounter::new(); let mut game_paused = false; - event_loop.run_return(move |event, _, flow| match event { + event_loop.run_return(|event, _, flow| match event { MainEventsCleared => window.request_redraw(), RedrawRequested(id) if id == window.id() => { let now = Instant::now(); let dt = now - last_frame; last_frame = now; - state.update(dt); + debug_menu.fps = fps_counter.tick(); + camera.update(&gpu, dt); if let Some(map) = &mut map { - map.update(&mut state); + map.update(&gpu); } net_events .send(NetEvent::PlayerPos( - state.camera.position.into(), - Rad(state.camera.yaw).into(), - Rad(state.camera.pitch).into(), + camera.first_person.position.into(), + Rad(camera.first_person.yaw).into(), + Rad(camera.first_person.pitch).into(), )) .ok(); + let mut render = || { + let size = (gpu.config.width as f32, gpu.config.height as f32); + let mut frame = gpu::Frame::new(&mut gpu)?; + + { + let mut pass = frame.pass(); + if let Some(map) = &mut map { + map.render(&camera, &mut debug_menu, &mut pass); + } + } + + debug_menu.render(size, &camera, &mut font); + font.submit(&mut frame); + + frame.finish(); + font.cleanup(); + + Ok(()) + }; + use wgpu::SurfaceError::*; - match state.render(&map) { + match render() { Ok(_) => {} - Err(Lost) => state.configure_surface(), + Err(Lost) => gpu.configure_surface(), Err(OutOfMemory) => *flow = ExitWithCode(0), Err(err) => eprintln!("gfx error: {err:?}"), } } WindowEvent { - ref event, + event, window_id: id, } if id == window.id() => match event { CloseRequested => *flow = ExitWithCode(0), - Resized(size) => state.resize(*size), - ScaleFactorChanged { new_inner_size, .. } => state.resize(**new_inner_size), + Resized(size) + | ScaleFactorChanged { + new_inner_size: &mut size, + .. + } => { + gpu.resize(size); + camera.resize(size); + } KeyboardInput { input: winit::event::KeyboardInput { @@ -80,11 +112,15 @@ pub async fn run( use fps_camera::Actions; use winit::event::{ElementState, VirtualKeyCode as Key}; - if key == &Key::Escape && key_state == &ElementState::Pressed { + if key == Key::Escape && key_state == ElementState::Pressed { game_paused = !game_paused; window.set_cursor_visible(game_paused); } + if key == Key::F3 && key_state == ElementState::Pressed { + debug_menu.enabled = !debug_menu.enabled; + } + if !game_paused { let actions = match key { Key::W => Actions::MOVE_FORWARD, @@ -97,8 +133,8 @@ pub async fn run( }; match key_state { - ElementState::Pressed => state.camera.enable_actions(actions), - ElementState::Released => state.camera.disable_action(actions), + ElementState::Pressed => camera.first_person.enable_actions(actions), + ElementState::Released => camera.first_person.disable_action(actions), } } } @@ -109,11 +145,13 @@ pub async fn run( .. } => { if !game_paused { - state.camera.update_mouse(-delta.0 as f32, delta.1 as f32); + camera + .first_person + .update_mouse(-delta.0 as f32, delta.1 as f32); window .set_cursor_position(winit::dpi::PhysicalPosition::new( - state.config.width / 2, - state.config.height / 2, + gpu.config.width / 2, + gpu.config.height / 2, )) .ok(); } @@ -131,7 +169,8 @@ pub async fn run( if finished { map = Some(map::MapRender::new( - &mut state, + &mut gpu, + &camera, &media, nodedefs.take().unwrap_or_default(), )); @@ -140,9 +179,9 @@ pub async fn run( } } PlayerPos(pos, pitch, yaw) => { - state.camera.position = pos.into(); - state.camera.pitch = Rad::::from(pitch).0; - state.camera.yaw = Rad::::from(yaw).0; + camera.first_person.position = pos.into(); + camera.first_person.pitch = Rad::::from(pitch).0; + camera.first_person.yaw = Rad::::from(yaw).0; } }, _ => {} diff --git a/src/gfx/camera.rs b/src/gfx/camera.rs new file mode 100644 index 0000000..874c9fc --- /dev/null +++ b/src/gfx/camera.rs @@ -0,0 +1,67 @@ +use super::{gpu::Gpu, util::MatrixUniform}; +use cgmath::{prelude::*, Deg, Matrix4, Rad}; +use collision::Frustum; +use fps_camera::{FirstPerson, FirstPersonSettings}; +use std::time::Duration; + +pub struct Camera { + pub fov: Rad, + pub view: Matrix4, + pub proj: Matrix4, + pub frustum: Frustum, + pub first_person: FirstPerson, + pub uniform: MatrixUniform, + pub layout: wgpu::BindGroupLayout, +} + +impl Camera { + pub fn new(gpu: &Gpu) -> Self { + let first_person = FirstPerson::new( + [0.0, 0.0, 0.0], + FirstPersonSettings { + speed_horizontal: 10.0, + speed_vertical: 10.0, + mouse_sensitivity_horizontal: 1.0, + mouse_sensitivity_vertical: 1.0, + }, + ); + + let layout = MatrixUniform::layout(&gpu.device, "camera"); + let uniform = MatrixUniform::new(&gpu.device, &layout, Matrix4::identity(), "camera", true); + + Self { + fov: Deg(90.0).into(), + proj: Matrix4::identity(), + view: Matrix4::identity(), + frustum: Frustum::from_matrix4(Matrix4::identity()).unwrap(), + first_person, + uniform, + layout, + } + } + + pub fn update(&mut self, gpu: &Gpu, dt: Duration) { + self.first_person.yaw += Rad::from(Deg(180.0)).0; + self.first_person.yaw *= -1.0; + + let cam = self.first_person.camera(dt.as_secs_f32()); + + self.first_person.yaw *= -1.0; + self.first_person.yaw -= Rad::from(Deg(180.0)).0; + + self.first_person.position = cam.position; + + self.view = Matrix4::from(cam.orthogonal()); + self.uniform.set(&gpu.queue, self.proj * self.view); + } + + pub fn resize(&mut self, size: winit::dpi::PhysicalSize) { + self.proj = cgmath::perspective( + self.fov, + size.width as f32 / size.height as f32, + 0.1, + 100000.0, + ); + self.frustum = Frustum::from_matrix4(self.proj).unwrap(); + } +} diff --git a/src/gfx/debug_menu.rs b/src/gfx/debug_menu.rs new file mode 100644 index 0000000..daca08d --- /dev/null +++ b/src/gfx/debug_menu.rs @@ -0,0 +1,57 @@ +use super::{camera::Camera, font::Font}; +use cgmath::{Deg, Rad}; +use wgpu_glyph::{Section, Text}; + +pub struct DebugMenu { + pub enabled: bool, + pub fps: usize, +} + +impl DebugMenu { + pub fn new() -> Self { + Self { + enabled: false, + fps: 0, + } + } + + pub fn render(&self, bounds: (f32, f32), camera: &Camera, font: &mut Font) { + if !self.enabled { + return; + } + + let mut offset = 0.0; + + let mut add_text = |txt: &str| { + offset += 2.0; + + font.add(Section { + screen_position: (2.0, offset), + bounds, + text: vec![Text::new(txt) + .with_color([1.0, 1.0, 1.0, 1.0]) + .with_scale(20.0)], + ..Section::default() + }); + + offset += 20.0; + }; + + let angle = |x| Deg::from(Rad(x)).0; + + let pos = camera.first_person.position; + + add_text(&format!( + "{} {}", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION") + )); + add_text(&format!("{} FPS", self.fps)); + add_text(&format!("({:.1}, {:.1}, {:.1})", pos[0], pos[1], pos[2])); + add_text(&format!( + "yaw: {:.1}°", + (angle(camera.first_person.yaw) + 360.0) % 360.0 + )); + add_text(&format!("pitch: {:.1}°", angle(camera.first_person.pitch))); + } +} diff --git a/src/gfx/font.rs b/src/gfx/font.rs new file mode 100644 index 0000000..6875a3b --- /dev/null +++ b/src/gfx/font.rs @@ -0,0 +1,44 @@ +use super::gpu::{Frame, Gpu}; + +pub struct Font { + glyph_brush: wgpu_glyph::GlyphBrush<()>, + staging_belt: wgpu::util::StagingBelt, +} + +impl Font { + pub fn new(gpu: &Gpu) -> Self { + Self { + glyph_brush: wgpu_glyph::GlyphBrushBuilder::using_font( + wgpu_glyph::ab_glyph::FontArc::try_from_slice(include_bytes!( + "../../assets/font/regular.otf" + )) + .unwrap(), + ) + .build(&gpu.device, gpu.config.format), + staging_belt: wgpu::util::StagingBelt::new(1024), + } + } + + pub fn add(&mut self, section: wgpu_glyph::Section) { + self.glyph_brush.queue(section); + } + + pub fn submit(&mut self, frame: &mut Frame) { + self.glyph_brush + .draw_queued( + &frame.gpu.device, + &mut self.staging_belt, + &mut frame.encoder, + &frame.view, + frame.gpu.config.width, + frame.gpu.config.height, + ) + .unwrap(); + + self.staging_belt.finish(); + } + + pub fn cleanup(&mut self) { + self.staging_belt.recall(); + } +} diff --git a/src/gfx/gpu.rs b/src/gfx/gpu.rs new file mode 100644 index 0000000..f187fee --- /dev/null +++ b/src/gfx/gpu.rs @@ -0,0 +1,168 @@ +pub struct Frame<'a> { + pub gpu: &'a mut Gpu, + pub encoder: wgpu::CommandEncoder, + pub output: wgpu::SurfaceTexture, + pub view: wgpu::TextureView, +} + +impl<'a> Frame<'a> { + pub fn new(gpu: &'a mut Gpu) -> Result { + let output = gpu.surface.get_current_texture()?; + let view = output + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + + let encoder = gpu + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + Ok(Self { + gpu, + encoder, + output, + view, + }) + } + + pub fn pass(&mut self) -> wgpu::RenderPass { + self.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &self.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0x87 as f64 / 255.0, + g: 0xCE as f64 / 255.0, + b: 0xEB as f64 / 255.0, + a: 1.0, + }), + store: true, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.gpu.depth_texture, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }), + }) + } + + pub fn finish(self) { + self.gpu.queue.submit(Some(self.encoder.finish())); + self.output.present(); + } +} + +pub struct Gpu { + pub surface: wgpu::Surface, + pub device: wgpu::Device, + pub queue: wgpu::Queue, + pub config: wgpu::SurfaceConfiguration, + pub depth_texture: wgpu::TextureView, +} + +impl Gpu { + pub async fn new(window: &winit::window::Window) -> Self { + let size = window.inner_size(); + + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::Backends::all(), + dx12_shader_compiler: Default::default(), + }); + + let surface = unsafe { instance.create_surface(window) }.unwrap(); + + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::default(), + compatible_surface: Some(&surface), + force_fallback_adapter: false, + }) + .await + .unwrap(); + + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: Default::default(), + label: None, + }, + None, + ) + .await + .unwrap(); + + let surface_caps = surface.get_capabilities(&adapter); + let surface_format = surface_caps + .formats + .iter() + .copied() + .find(|f| f.describe().srgb) + .unwrap_or(surface_caps.formats[0]); + + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width: size.width, + height: size.height, + present_mode: surface_caps.present_modes[0], + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + }; + + let depth_texture = Self::create_depth_texture(&config, &device); + + let mut state = Self { + surface, + device, + queue, + config, + depth_texture, + }; + + state.resize(size); + + state + } + + pub fn create_depth_texture( + config: &wgpu::SurfaceConfiguration, + device: &wgpu::Device, + ) -> wgpu::TextureView { + device + .create_texture(&wgpu::TextureDescriptor { + label: Some("depth texture"), + size: wgpu::Extent3d { + width: config.width, + height: config.height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth32Float, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT + | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }) + .create_view(&wgpu::TextureViewDescriptor::default()) + } + + pub fn resize(&mut self, size: winit::dpi::PhysicalSize) { + if size.width > 0 && size.height > 0 { + self.config.width = size.width; + self.config.height = size.height; + self.configure_surface(); + self.depth_texture = Self::create_depth_texture(&self.config, &self.device); + } + } + + pub fn configure_surface(&mut self) { + self.surface.configure(&self.device, &self.config); + } +} diff --git a/src/gfx/map.rs b/src/gfx/map.rs index 7bd5dd3..04865a6 100644 --- a/src/gfx/map.rs +++ b/src/gfx/map.rs @@ -1,7 +1,9 @@ mod atlas; mod mesh; -use super::{media::MediaMgr, state::State, util::MatrixUniform}; +use super::{ + camera::Camera, debug_menu::DebugMenu, gpu::Gpu, media::MediaMgr, util::MatrixUniform, +}; use atlas::create_atlas; use cgmath::{prelude::*, Matrix4, Point3, Vector3}; use collision::{prelude::*, Aabb3, Relation}; @@ -101,13 +103,13 @@ struct BlockMesh { } impl BlockMesh { - fn new(state: &State, vertices: &[Vertex]) -> Option { + fn new(gpu: &Gpu, vertices: &[Vertex]) -> Option { if vertices.is_empty() { return None; } Some(BlockMesh { - vertex_buffer: state + vertex_buffer: gpu .device .create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("mapblock.vertex_buffer"), @@ -136,10 +138,15 @@ fn block_float_pos(pos: Point3) -> Point3 { } impl MapRender { - pub fn render<'a>(&'a self, state: &'a State, pass: &mut wgpu::RenderPass<'a>) { + pub fn render<'a>( + &'a self, + camera: &'a Camera, + debug_menu: &mut DebugMenu, + pass: &mut wgpu::RenderPass<'a>, + ) { pass.set_pipeline(&self.pipeline); pass.set_bind_group(0, &self.atlas, &[]); - pass.set_bind_group(1, &state.camera_uniform.bind_group, &[]); + pass.set_bind_group(1, &camera.uniform.bind_group, &[]); struct BlendEntry<'a> { dist: f32, @@ -157,9 +164,9 @@ impl MapRender { let fpos = block_float_pos(pos); let one = Vector3::new(1.0, 1.0, 1.0); - let aabb = Aabb3::new(fpos - one * 0.5, fpos + one * 15.5).transform(&state.view); + let aabb = Aabb3::new(fpos - one * 0.5, fpos + one * 15.5).transform(&camera.view); - if state.frustum.contains(&aabb) == Relation::Out { + if camera.frustum.contains(&aabb) == Relation::Out { continue; } @@ -170,7 +177,7 @@ impl MapRender { if let Some(mesh) = &model.mesh_blend { blend.push(BlendEntry { index, - dist: (state.view * (fpos + one * 8.5).to_homogeneous()) + dist: (camera.view * (fpos + one * 8.5).to_homogeneous()) .truncate() .magnitude(), mesh, @@ -191,7 +198,7 @@ impl MapRender { } } - pub fn update(&mut self, state: &mut State) { + pub fn update(&mut self, gpu: &Gpu) { for (pos, _) in self .blocks_defer .drain_filter(|_, v| v.time.elapsed().as_millis() > 100) @@ -208,10 +215,10 @@ impl MapRender { self.block_models.insert( pos, BlockModel { - mesh: BlockMesh::new(state, &data.vertices), - mesh_blend: BlockMesh::new(state, &data.vertices_blend), + mesh: BlockMesh::new(gpu, &data.vertices), + mesh_blend: BlockMesh::new(gpu, &data.vertices_blend), transform: MatrixUniform::new( - &state.device, + &gpu.device, &self.model, Matrix4::from_translation(block_float_pos(pos).to_vec()), "mapblock", @@ -277,7 +284,12 @@ impl MapRender { } } - pub fn new(state: &mut State, media: &MediaMgr, mut nodes: HashMap) -> Self { + pub fn new( + gpu: &mut Gpu, + camera: &Camera, + media: &MediaMgr, + mut nodes: HashMap, + ) -> Self { let (atlas_img, atlas_slices) = create_atlas(&mut nodes, media); let atlas_size = wgpu::Extent3d { @@ -286,7 +298,7 @@ impl MapRender { depth_or_array_layers: 1, }; - let atlas_texture = state.device.create_texture(&wgpu::TextureDescriptor { + let atlas_texture = gpu.device.create_texture(&wgpu::TextureDescriptor { size: atlas_size, mip_level_count: 1, sample_count: 1, @@ -297,7 +309,7 @@ impl MapRender { view_formats: &[], }); - state.queue.write_texture( + gpu.queue.write_texture( wgpu::ImageCopyTexture { texture: &atlas_texture, mip_level: 0, @@ -315,7 +327,7 @@ impl MapRender { let atlas_view = atlas_texture.create_view(&wgpu::TextureViewDescriptor::default()); - let atlas_sampler = state.device.create_sampler(&wgpu::SamplerDescriptor { + let atlas_sampler = gpu.device.create_sampler(&wgpu::SamplerDescriptor { address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge, @@ -328,8 +340,7 @@ impl MapRender { }); let atlas_bind_group_layout = - state - .device + gpu.device .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[ wgpu::BindGroupLayoutEntry { @@ -352,7 +363,7 @@ impl MapRender { label: Some("atlas.bind_group_layout"), }); - let atlas_bind_group = state.device.create_bind_group(&wgpu::BindGroupDescriptor { + let atlas_bind_group = gpu.device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &atlas_bind_group_layout, entries: &[ wgpu::BindGroupEntry { @@ -367,26 +378,25 @@ impl MapRender { label: Some("atlas.bind_group"), }); - let model_bind_group_layout = MatrixUniform::layout(&state.device, "mapblock"); + let model_bind_group_layout = MatrixUniform::layout(&gpu.device, "mapblock"); - let shader = state + let shader = gpu .device .create_shader_module(wgpu::include_wgsl!("../../assets/shaders/map.wgsl")); - let pipeline_layout = - state - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: None, - bind_group_layouts: &[ - &atlas_bind_group_layout, - &model_bind_group_layout, - &state.camera_bind_group_layout, - ], - push_constant_ranges: &[], - }); + let pipeline_layout = gpu + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[ + &atlas_bind_group_layout, + &model_bind_group_layout, + &camera.layout, + ], + push_constant_ranges: &[], + }); - let pipeline = state + let pipeline = gpu .device .create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: None, @@ -400,15 +410,8 @@ impl MapRender { module: &shader, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { - format: state.config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha: wgpu::BlendComponent::OVER, - }), + format: gpu.config.format, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, })], }), diff --git a/src/gfx/map/mesh.rs b/src/gfx/map/mesh.rs index 139b6c7..3d56ad8 100644 --- a/src/gfx/map/mesh.rs +++ b/src/gfx/map/mesh.rs @@ -93,7 +93,7 @@ pub(super) fn create_mesh( if let Some(ndef) = &mkinfo.nodes[ncontent as usize] { if match draw_type { DrawType::Cube => ndef.draw_type == DrawType::Cube, - DrawType::Liquid => ncontent == content, + DrawType::Liquid => ndef.draw_type == DrawType::Cube || ncontent == content, _ => false, } { continue; diff --git a/src/gfx/state.rs b/src/gfx/state.rs deleted file mode 100644 index b307d85..0000000 --- a/src/gfx/state.rs +++ /dev/null @@ -1,243 +0,0 @@ -use super::util::MatrixUniform; -use cgmath::{prelude::*, Deg, Matrix4, Rad}; -use collision::Frustum; -use fps_camera::{FirstPerson, FirstPersonSettings}; -use std::time::Duration; - -pub struct State { - pub surface: wgpu::Surface, - pub device: wgpu::Device, - pub queue: wgpu::Queue, - pub config: wgpu::SurfaceConfiguration, - pub fov: Rad, - pub view: Matrix4, - pub proj: Matrix4, - pub frustum: Frustum, - pub camera: FirstPerson, - pub camera_uniform: MatrixUniform, - pub camera_bind_group_layout: wgpu::BindGroupLayout, - pub depth_texture: wgpu::Texture, - pub depth_view: wgpu::TextureView, - pub depth_sampler: wgpu::Sampler, -} - -impl State { - pub async fn new(window: &winit::window::Window) -> Self { - let size = window.inner_size(); - - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends: wgpu::Backends::all(), - dx12_shader_compiler: Default::default(), - }); - - let surface = unsafe { instance.create_surface(window) }.unwrap(); - - let adapter = instance - .request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::default(), - compatible_surface: Some(&surface), - force_fallback_adapter: false, - }) - .await - .unwrap(); - - let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - features: wgpu::Features::empty(), - limits: Default::default(), - label: None, - }, - None, - ) - .await - .unwrap(); - - let surface_caps = surface.get_capabilities(&adapter); - let surface_format = surface_caps - .formats - .iter() - .copied() - .find(|f| f.describe().srgb) - .unwrap_or(surface_caps.formats[0]); - - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width: size.width, - height: size.height, - present_mode: surface_caps.present_modes[0], - alpha_mode: surface_caps.alpha_modes[0], - view_formats: vec![], - }; - - let (depth_texture, depth_view, depth_sampler) = - Self::create_depth_texture(&config, &device); - - let camera = FirstPerson::new( - [0.0, 0.0, 0.0], - FirstPersonSettings { - speed_horizontal: 10.0, - speed_vertical: 10.0, - mouse_sensitivity_horizontal: 1.0, - mouse_sensitivity_vertical: 1.0, - }, - ); - - let camera_bind_group_layout = MatrixUniform::layout(&device, "camera"); - - let camera_uniform = MatrixUniform::new( - &device, - &camera_bind_group_layout, - Matrix4::identity(), - "camera", - true, - ); - - let mut state = Self { - surface, - device, - queue, - config, - fov: Deg(90.0).into(), - proj: Matrix4::identity(), - view: Matrix4::identity(), - frustum: Frustum::from_matrix4(Matrix4::identity()).unwrap(), - camera, - camera_uniform, - camera_bind_group_layout, - depth_texture, - depth_view, - depth_sampler, - }; - - state.resize(size); - - state - } - - pub fn create_depth_texture( - config: &wgpu::SurfaceConfiguration, - device: &wgpu::Device, - ) -> (wgpu::Texture, wgpu::TextureView, wgpu::Sampler) { - let depth_size = wgpu::Extent3d { - width: config.width, - height: config.height, - depth_or_array_layers: 1, - }; - let depth_descriptor = wgpu::TextureDescriptor { - label: Some("depth texture"), - size: depth_size, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Depth32Float, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, - view_formats: &[], - }; - let depth_texture = device.create_texture(&depth_descriptor); - - let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); - let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor { - 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), - lod_min_clamp: 0.0, - lod_max_clamp: 100.0, - ..Default::default() - }); - - (depth_texture, depth_view, depth_sampler) - } - - pub fn resize(&mut self, size: winit::dpi::PhysicalSize) { - if size.width > 0 && size.height > 0 { - self.config.width = size.width; - self.config.height = size.height; - self.configure_surface(); - self.update_projection(); - (self.depth_texture, self.depth_view, self.depth_sampler) = - Self::create_depth_texture(&self.config, &self.device); - } - } - - pub fn configure_surface(&mut self) { - self.surface.configure(&self.device, &self.config); - } - - pub fn update_projection(&mut self) { - self.proj = cgmath::perspective( - self.fov, - self.config.width as f32 / self.config.height as f32, - 0.1, - 100000.0, - ); - self.frustum = Frustum::from_matrix4(self.proj).unwrap(); - } - - pub fn update(&mut self, dt: Duration) { - self.camera.yaw += Rad::from(Deg(180.0)).0; - self.camera.yaw *= -1.0; - - let cam = self.camera.camera(dt.as_secs_f32()); - - self.camera.yaw *= -1.0; - self.camera.yaw -= Rad::from(Deg(180.0)).0; - - self.camera.position = cam.position; - - self.view = Matrix4::from(cam.orthogonal()); - self.camera_uniform.set(&self.queue, self.proj * self.view); - } - - pub fn render(&self, map: &Option) -> Result<(), wgpu::SurfaceError> { - let output = self.surface.get_current_texture()?; - let view = output - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - - { - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0x87 as f64 / 255.0, - g: 0xCE as f64 / 255.0, - b: 0xEB as f64 / 255.0, - a: 1.0, - }), - store: true, - }, - })], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: true, - }), - stencil_ops: None, - }), - }); - - if let Some(map) = map.as_ref() { - map.render(self, &mut render_pass); - } - } - - self.queue.submit(std::iter::once(encoder.finish())); - output.present(); - - Ok(()) - } -} -- cgit v1.2.3