diff --git a/Cargo.lock b/Cargo.lock index 7d23ffd..7766202 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,15 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ab_glyph" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a933731feda8b460bdad9a9e43bb386baba6ec593d2bc19716ef3c75c09085c" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser 0.12.0", +] + [[package]] name = "ab_glyph_rasterizer" version = "0.1.4" @@ -816,6 +826,45 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glyph_brush" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e3f00b8574a76fb6c50890c48da03946ca50e4372a2778737922666a2238221" +dependencies = [ + "glyph_brush_draw_cache", + "glyph_brush_layout", + "log", + "ordered-float", + "rustc-hash", + "twox-hash", +] + +[[package]] +name = "glyph_brush_draw_cache" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2c82074cafb68b9e459c50c655f7eedcb92d6ee7166813802934bc6fc29fa3" +dependencies = [ + "ab_glyph", + "crossbeam-channel", + "crossbeam-deque", + "linked-hash-map", + "rayon", + "rustc-hash", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bc06d530bf20c1902f1b02799ab7372ff43f6119770c49b0bc3f21bd148820" +dependencies = [ + "ab_glyph", + "approx", + "xi-unicode", +] + [[package]] name = "gpu-alloc" version = "0.3.0" @@ -1025,6 +1074,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "lock_api" version = "0.4.3" @@ -1373,13 +1428,31 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +[[package]] +name = "ordered-float" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8919aecb97e5ee9aceef27e24f39c46b11831130f4a6b7b091ec5de0de12" +dependencies = [ + "num-traits", +] + [[package]] name = "owned_ttf_parser" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" dependencies = [ - "ttf-parser", + "ttf-parser 0.6.2", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3c7a20e3f122223e68eef6ca58e39bc1ea8a1d83418ba4c2c1ba189d2ee355" +dependencies = [ + "ttf-parser 0.12.0", ] [[package]] @@ -1637,6 +1710,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rusttype" version = "0.9.2" @@ -1644,7 +1723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" dependencies = [ "ab_glyph_rasterizer", - "owned_ttf_parser", + "owned_ttf_parser 0.6.0", ] [[package]] @@ -1758,6 +1837,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "storage-map" version = "0.3.0" @@ -1868,6 +1953,23 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +[[package]] +name = "ttf-parser" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e00391c1f3d171490a3f8bd79999b0002ae38d3da0d6a3a306c754b053d71b" + +[[package]] +name = "twox-hash" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" +dependencies = [ + "cfg-if 0.1.10", + "rand 0.7.3", + "static_assertions", +] + [[package]] name = "unicode-xid" version = "0.2.1" @@ -2117,6 +2219,18 @@ dependencies = [ "bitflags", ] +[[package]] +name = "wgpu_glyph" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "354c1f79e09923724a6006a6953c3946522b84f7a9ec202b7e8001f274fd4bd5" +dependencies = [ + "bytemuck", + "glyph_brush", + "log", + "wgpu", +] + [[package]] name = "wgpufun" version = "0.1.0" @@ -2133,6 +2247,7 @@ dependencies = [ "rand 0.8.3", "shaderc", "wgpu", + "wgpu_glyph", "winit", ] @@ -2256,6 +2371,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" +[[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.3" diff --git a/Cargo.toml b/Cargo.toml index f2aec99..6ce601b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] winit = "0.24" wgpu = "0.7" +wgpu_glyph = "0.11" futures = "0.3" bytemuck = { version = "1.5", features = [ "derive" ] } byteorder = "1.4" @@ -17,6 +18,7 @@ cgmath = "0.18" rand = "0.8" noise = "0.7" + [build-dependencies] anyhow = "1.0" fs_extra = "1.1" diff --git a/assets/font.ttf b/assets/font.ttf new file mode 100644 index 0000000..9d65196 Binary files /dev/null and b/assets/font.ttf differ diff --git a/src/main.rs b/src/main.rs index 7093130..4e220ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ fn main() { .build(&events) .expect("Failed to create window"); - let mut renderer = futures::executor::block_on(Renderer::new(&window)); + let mut renderer = Renderer::new(&window); let mut app = App::new(&mut renderer); // Stats @@ -84,9 +84,11 @@ fn main() { // Display FPS let elapsed = fps_timer.elapsed().as_secs_f64(); - if elapsed >= 1.5 { - let fps = (fps_counter as f64) / elapsed; - println!("FPS: {}", (fps*100.0_f64).floor()/100.0); + if elapsed >= 0.5 { + let mut fps = (fps_counter as f64) / elapsed; + fps = (fps*100.0_f64).floor() / 100.0; + renderer.ui.set_fps(fps as f32); + fps_timer = std::time::Instant::now(); fps_counter = 0; } diff --git a/src/renderer/buffers/content.rs b/src/renderer/buffers/content.rs index 9fcdc0d..032fd52 100644 --- a/src/renderer/buffers/content.rs +++ b/src/renderer/buffers/content.rs @@ -20,7 +20,6 @@ pub struct Content { impl Content { pub fn new(device: &wgpu::Device) -> Self { - // Create node buffer let node_buffer = vec![0_u32; (NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE) as usize].into_boxed_slice(); @@ -43,10 +42,6 @@ impl Content { ); // Bind layout - // let sampler_entry = wgpu::BindGroupLayoutEntry { - // binding: 0,visibility: wgpu::ShaderStage::FRAGMENT, count: None, - // ty: wgpu::BindingType::Sampler { comparison: false, filtering: false }, - // }; let texture_entry = wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, count: None, ty: wgpu::BindingType::Texture { multisampled: false, view_dimension: wgpu::TextureViewDimension::D3, sample_type: wgpu::TextureSampleType::Uint }, @@ -56,8 +51,6 @@ impl Content { label: None, entries: &[ wgpu::BindGroupLayoutEntry { binding: 0, ..texture_entry }, wgpu::BindGroupLayoutEntry { binding: 1, ..texture_entry }, - //wgpu::BindGroupLayoutEntry { binding: 2, ..sampler_entry }, - //wgpu::BindGroupLayoutEntry { binding: 3, ..sampler_entry }, ], } ); @@ -69,8 +62,6 @@ impl Content { entries: &[ wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureView(&node_texture.create_view(&wgpu::TextureViewDescriptor::default())) }, wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::TextureView(&block_texture.create_view(&wgpu::TextureViewDescriptor::default())) }, - //wgpu::BindGroupEntry { binding: 2, resource: wgpu::BindingResource::Sampler(&device.create_sampler(&Default::default())) }, - //wgpu::BindGroupEntry { binding: 3, resource: wgpu::BindingResource::Sampler(&device.create_sampler(&Default::default())) } ], } ); diff --git a/src/renderer/buffers/materials.rs b/src/renderer/buffers/materials.rs index b960050..51edbfe 100644 --- a/src/renderer/buffers/materials.rs +++ b/src/renderer/buffers/materials.rs @@ -37,39 +37,33 @@ impl Materials { // Create buffer let buffer = device.create_buffer_init( &wgpu::util::BufferInitDescriptor { - label: Some("Materials buffer"), - contents: bytemuck::cast_slice(&materials), + label: Some("Materials buffer"), contents: bytemuck::cast_slice(&materials), usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, } ); - // Create bind group - let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - } + // Bind layout + let buffer_entry = wgpu::BindGroupLayoutEntry { + binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, count: None, + ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None }, + }; + let bind_layout = device.create_bind_group_layout( + &wgpu::BindGroupLayoutDescriptor { + label: None, entries: &[ + wgpu::BindGroupLayoutEntry { binding: 0, ..buffer_entry }, ], - label: Some("Materials buffer layout"), - }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: buffer.as_entire_binding(), - } - ], - label: Some("Materials buffer group"), }); + // Bind group + let bind_group = device.create_bind_group( + &wgpu::BindGroupDescriptor { + label: Some("Materials buffer group"),layout: &bind_layout, + entries: &[ + wgpu::BindGroupEntry { binding: 0, resource: buffer.as_entire_binding() } + ], + } + ); + // Done Materials { buffer, materials, bind_layout, bind_group } } diff --git a/src/renderer/buffers/uniform.rs b/src/renderer/buffers/uniform.rs index 3889c51..78b57d4 100644 --- a/src/renderer/buffers/uniform.rs +++ b/src/renderer/buffers/uniform.rs @@ -47,39 +47,32 @@ impl Uniform { // Create buffer let buffer = device.create_buffer_init( &wgpu::util::BufferInitDescriptor { - label: Some("Uniform buffer"), - contents: bytemuck::cast_slice(&[values]), + label: Some("Uniform buffer"), contents: bytemuck::cast_slice(&[values]), usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, } ); - // Create bind group + // Bind layout + let buffer_entry = wgpu::BindGroupLayoutEntry { + binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, count: None, + ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None }, + }; let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - } + label: None, entries: &[ + wgpu::BindGroupLayoutEntry { binding: 0, ..buffer_entry } ], - label: Some("Uniform buffer layout"), - }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: buffer.as_entire_binding(), - } - ], - label: Some("Uniform buffer group"), }); + // Bind group + let bind_group = device.create_bind_group( + &wgpu::BindGroupDescriptor { + label: None, layout: &bind_layout, + entries: &[ + wgpu::BindGroupEntry { binding: 0, resource: buffer.as_entire_binding(), } + ], + } + ); + // Done Uniform { buffer, values, bind_layout, bind_group } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 169bf4c..13e473c 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,3 +1,4 @@ +use wgpu_glyph::Text; use winit::{window::Window, dpi::PhysicalSize}; pub mod buffers; use buffers::Buffers; @@ -6,6 +7,8 @@ use passes::{RaytracePass, PostprocessPass}; pub mod camera; use camera::Camera; pub mod content_view; +mod ui; +use ui::UserInterface; pub struct Renderer { surface: wgpu::Surface, @@ -17,6 +20,7 @@ pub struct Renderer { texture: wgpu::TextureView, raytrace_pass: RaytracePass, postprocess_pass: PostprocessPass, + pub ui: UserInterface, // Buffers buffers: Buffers, // Other @@ -29,18 +33,21 @@ impl Renderer { /* * Initializes renderer and all buffers */ - pub async fn new(window: &Window) -> Self { + pub fn new(window: &Window) -> Self { // Create surface let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); let surface = unsafe { instance.create_surface(window) }; // Pick and initialize device - let adapter_options = wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, compatible_surface: Some(&surface) }; - let adapter = instance.request_adapter(&adapter_options).await.unwrap(); - let device_desc = wgpu::DeviceDescriptor { features: wgpu::Features::empty(), limits: wgpu::Limits::default(), label: None }; - let (device, queue) = adapter.request_device(&device_desc, None).await.unwrap(); - + let (adapter, mut device, queue) = futures::executor::block_on(async { + let adapter_options = wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, compatible_surface: Some(&surface) }; + let adapter = instance.request_adapter(&adapter_options).await.unwrap(); + let device_desc = wgpu::DeviceDescriptor { features: wgpu::Features::empty(), limits: wgpu::Limits::default(), label: None }; + let (device, queue) = adapter.request_device(&device_desc, None).await.unwrap(); + (adapter, device, queue) + }); + // Create swapchain let window_size = window.inner_size(); let swapchain_desc = wgpu::SwapChainDescriptor { @@ -75,12 +82,13 @@ impl Renderer { let buffers = Buffers::new(&device); let raytrace_pass = RaytracePass::new(&device, &swapchain_desc, &buffers); let postprocess_pass = PostprocessPass::new(&device, &swapchain_desc, &texture); + let ui = UserInterface::new(&mut device, swapchain_desc.format); // Other let start = std::time::Instant::now(); println!("Renderer initialized"); - Self { surface, device, queue, swapchain_desc, swapchain, texture, raytrace_pass, postprocess_pass, buffers, camera, start } + Self { surface, device, queue, swapchain_desc, swapchain, texture, raytrace_pass, postprocess_pass, ui, buffers, camera, start } } /* @@ -114,12 +122,13 @@ impl Renderer { // Create encoder that will build command buffer for us let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"),}); - self.raytrace_pass.render(&mut encoder, &mut self.buffers, &self.texture);//&frame.view); self.postprocess_pass.render(&mut encoder, &frame.view); + self.ui.render(&self.device, &mut encoder, &frame.view, 1280, 720); // Submit encoder (command buffer) self.queue.submit(std::iter::once(encoder.finish())); + self.ui.recall(); // Return ok Ok(()) diff --git a/src/renderer/passes/ui.rs b/src/renderer/passes/ui.rs new file mode 100644 index 0000000..4112dfe --- /dev/null +++ b/src/renderer/passes/ui.rs @@ -0,0 +1,9 @@ +use crate::renderer::buffers::Buffers; + +pub struct UserInterfacePass { + pub pipeline: wgpu::RenderPipeline +} + +impl UserInterfacePass { + +} \ No newline at end of file diff --git a/src/renderer/ui.rs b/src/renderer/ui.rs new file mode 100644 index 0000000..a1c6614 --- /dev/null +++ b/src/renderer/ui.rs @@ -0,0 +1,56 @@ +use wgpu_glyph::{GlyphBrush, ab_glyph::FontArc, GlyphBrushBuilder, Section, Text}; +use wgpu::util::StagingBelt; +use futures::executor::LocalPool; +use futures::task::SpawnExt; + +const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; + +pub struct UserInterface { + // Glyph drawing + staging_belt: StagingBelt, + local_pool: LocalPool, + brush: GlyphBrush<()>, + // Texts + fps_text: String +} + +impl UserInterface { + + pub fn new(device: &mut wgpu::Device, render_format: wgpu::TextureFormat) -> Self { + let font = FontArc::try_from_slice(include_bytes!("../../assets/font.ttf")).unwrap(); + Self { + staging_belt: StagingBelt::new(1024), + local_pool: LocalPool::new(), + brush: GlyphBrushBuilder::using_font(font).build(device, render_format), + fps_text: "-".to_string() + } + } + + fn print(&mut self, x: u32, y: u32, msg: &str) { + let text = Text::new(msg).with_color(WHITE); + self.brush.queue(Section { + screen_position: (x as f32, y as f32), + bounds: (text.scale.x * text.text.len() as f32, text.scale.y), + text: vec![text], + ..Section::default() + }); + } + + pub fn set_fps(&mut self, fps: f32) { + self.fps_text = format!("FPS: {}", fps); + } + + pub fn render(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, target: &wgpu::TextureView, width: u32, height: u32) { + // Print texts + self.print(5, 5, &self.fps_text.clone()); + // Draw + self.brush.draw_queued(&device, &mut self.staging_belt, encoder, target, width, height).expect("Draw queued"); + self.staging_belt.finish(); + } + + pub fn recall(&mut self) { + // Reset staging belt after drawing + self.local_pool.spawner().spawn(self.staging_belt.recall()).expect("Recall staging belt"); + self.local_pool.run_until_stalled(); + } +} \ No newline at end of file diff --git a/src/shaders/raytrace/.bin/main.frag.spv b/src/shaders/raytrace/.bin/main.frag.spv index bbac134..c7c65e8 100644 Binary files a/src/shaders/raytrace/.bin/main.frag.spv and b/src/shaders/raytrace/.bin/main.frag.spv differ diff --git a/src/shaders/raytrace/main.frag b/src/shaders/raytrace/main.frag index 5aaffbd..5bef744 100644 --- a/src/shaders/raytrace/main.frag +++ b/src/shaders/raytrace/main.frag @@ -36,7 +36,7 @@ vec3 solve() // Calculate ray direction vec3 view_dir = (_ProjMatrixInv * vec4(_InUV, 0, 1)).xyz; vec3 rayDir = normalize(_ViewMatrix * vec4(view_dir,0)).xyz; - Ray primaryRay = Ray((_CamPos + vec3(16, 0, 16)) / SCALE, rayDir); + Ray primaryRay = Ray(_CamPos / SCALE, rayDir); // Raycast HitResult primary = castNodes(primaryRay, 100);