From 15c39e3c0546554da5ab3e17d34b25552680a777 Mon Sep 17 00:00:00 2001 From: STP Date: Sun, 12 Nov 2023 20:21:47 -0500 Subject: [PATCH] used pixels instead of state --- Cargo.lock | 293 ++++++++++++++++++++++++++++++++--- Cargo.toml | 1 + src/camera.rs | 38 ++++- src/main.rs | 13 +- src/primitive.rs | 14 +- src/ray.rs | 5 +- src/state.rs | 387 ----------------------------------------------- src/texture.rs | 79 ---------- 8 files changed, 322 insertions(+), 508 deletions(-) delete mode 100644 src/state.rs delete mode 100644 src/texture.rs diff --git a/Cargo.lock b/Cargo.lock index 5b85bad..9207bf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -419,6 +419,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "d3d12" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f0de2f5a8e7bd4a9eec0e3c781992a4ce1724f68aec7d7a3715344de8b39da" +dependencies = [ + "bitflags 1.3.2", + "libloading 0.7.4", + "winapi", +] + [[package]] name = "d3d12" version = "0.7.0" @@ -623,6 +634,18 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glow" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glow" version = "0.13.0" @@ -644,6 +667,16 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "gpu-alloc" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22beaafc29b38204457ea030f6fb7a84c9e4dd1b86e311ba0542533453d87f62" +dependencies = [ + "bitflags 1.3.2", + "gpu-alloc-types 0.2.0", +] + [[package]] name = "gpu-alloc" version = "0.6.0" @@ -651,7 +684,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ "bitflags 2.4.1", - "gpu-alloc-types", + "gpu-alloc-types 0.3.0", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +dependencies = [ + "bitflags 1.3.2", ] [[package]] @@ -663,6 +705,19 @@ dependencies = [ "bitflags 2.4.1", ] +[[package]] +name = "gpu-allocator" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +dependencies = [ + "backtrace", + "log", + "thiserror", + "winapi", + "windows 0.44.0", +] + [[package]] name = "gpu-allocator" version = "0.23.0" @@ -674,7 +729,7 @@ dependencies = [ "presser", "thiserror", "winapi", - "windows", + "windows 0.51.1", ] [[package]] @@ -685,7 +740,7 @@ checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ "bitflags 2.4.1", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.14.2", ] [[package]] @@ -697,6 +752,12 @@ dependencies = [ "bitflags 2.4.1", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.2" @@ -755,6 +816,16 @@ dependencies = [ "png", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg 1.1.0", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.1.0" @@ -762,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.2", ] [[package]] @@ -818,6 +889,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading 0.7.4", + "pkg-config", +] + [[package]] name = "khronos-egl" version = "6.0.0" @@ -943,6 +1025,20 @@ dependencies = [ "autocfg 1.1.0", ] +[[package]] +name = "metal" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-graphics-types", + "foreign-types 0.3.2", + "log", + "objc", +] + [[package]] name = "metal" version = "0.27.0" @@ -986,6 +1082,26 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "naga" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbcc2e0513220fd2b598e6068608d4462db20322c0e77e47f6f488dfcfc279cb" +dependencies = [ + "bit-set", + "bitflags 1.3.2", + "codespan-reporting", + "hexf-parse", + "indexmap 1.9.3", + "log", + "num-traits", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + [[package]] name = "naga" version = "0.14.0" @@ -996,7 +1112,7 @@ dependencies = [ "bitflags 2.4.1", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 2.1.0", "log", "num-traits", "rustc-hash", @@ -1350,6 +1466,20 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pixels" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba8189b31db4f12fbf0d4a8eab2d7d7343a504a8d8a7ea4b14ffb2e6129136a" +dependencies = [ + "bytemuck", + "pollster", + "raw-window-handle", + "thiserror", + "ultraviolet", + "wgpu 0.16.3", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -1620,9 +1750,10 @@ dependencies = [ "lazy_static", "log", "nalgebra", + "pixels", "pollster", "roots", - "wgpu", + "wgpu 0.18.0", "winit", ] @@ -1875,7 +2006,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -1892,6 +2023,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ultraviolet" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a28554d13eb5daba527cc1b91b6c341372a0ae45ed277ffb2c6fbc04f319d7e" +dependencies = [ + "wide", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -2077,6 +2217,30 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wgpu" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480c965c9306872eb6255fa55e4b4953be55a8b64d57e61d7ff840d3dcc051cd" +dependencies = [ + "arrayvec", + "cfg-if", + "js-sys", + "log", + "naga 0.12.3", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core 0.16.1", + "wgpu-hal 0.16.2", + "wgpu-types 0.16.1", +] + [[package]] name = "wgpu" version = "0.18.0" @@ -2088,7 +2252,7 @@ dependencies = [ "flume", "js-sys", "log", - "naga", + "naga 0.14.0", "parking_lot", "profiling", "raw-window-handle", @@ -2097,9 +2261,32 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "wgpu-core", - "wgpu-hal", - "wgpu-types", + "wgpu-core 0.18.0", + "wgpu-hal 0.18.0", + "wgpu-types 0.18.0", +] + +[[package]] +name = "wgpu-core" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f478237b4bf0d5b70a39898a66fa67ca3a007d79f2520485b8b0c3dfc46f8c2" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.4.1", + "codespan-reporting", + "log", + "naga 0.12.3", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal 0.16.2", + "wgpu-types 0.16.1", ] [[package]] @@ -2113,7 +2300,7 @@ dependencies = [ "bitflags 2.4.1", "codespan-reporting", "log", - "naga", + "naga 0.14.0", "parking_lot", "profiling", "raw-window-handle", @@ -2121,8 +2308,50 @@ dependencies = [ "smallvec", "thiserror", "web-sys", - "wgpu-hal", - "wgpu-types", + "wgpu-hal 0.18.0", + "wgpu-types 0.18.0", +] + +[[package]] +name = "wgpu-hal" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecb3258078e936deee14fd4e0febe1cfe9bbb5ffef165cb60218d2ee5eb4448" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.4.1", + "block", + "core-graphics-types", + "d3d12 0.6.0", + "foreign-types 0.3.2", + "glow 0.12.3", + "gpu-alloc 0.5.4", + "gpu-allocator 0.22.0", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl 4.1.0", + "libc", + "libloading 0.8.1", + "log", + "metal 0.24.0", + "naga 0.12.3", + "objc", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types 0.16.1", + "winapi", ] [[package]] @@ -2138,20 +2367,20 @@ dependencies = [ "bitflags 2.4.1", "block", "core-graphics-types", - "d3d12", - "glow", + "d3d12 0.7.0", + "glow 0.13.0", "glutin_wgl_sys", - "gpu-alloc", - "gpu-allocator", + "gpu-alloc 0.6.0", + "gpu-allocator 0.23.0", "gpu-descriptor", "hassle-rs", "js-sys", - "khronos-egl", + "khronos-egl 6.0.0", "libc", "libloading 0.8.1", "log", - "metal", - "naga", + "metal 0.27.0", + "naga 0.14.0", "objc", "once_cell", "parking_lot", @@ -2164,10 +2393,21 @@ dependencies = [ "thiserror", "wasm-bindgen", "web-sys", - "wgpu-types", + "wgpu-types 0.18.0", "winapi", ] +[[package]] +name = "wgpu-types" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c153280bb108c2979eb5c7391cb18c56642dd3c072e55f52065e13e2a1252a" +dependencies = [ + "bitflags 2.4.1", + "js-sys", + "web-sys", +] + [[package]] name = "wgpu-types" version = "0.18.0" @@ -2226,6 +2466,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows" version = "0.51.1" diff --git a/Cargo.toml b/Cargo.toml index f1449ce..7c49043 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,4 @@ nalgebra = "0.32.3" roots = "0.0.8" lazy_static = "1.4.0" arc = "0.0.1" +pixels = "0.13.0" diff --git a/src/camera.rs b/src/camera.rs index 696d92a..1c8a04d 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,4 +1,5 @@ -use crate::EPSILON; +use crate::ray::Ray; +use crate::{EPSILON, INFINITY}; use nalgebra as nm; use nalgebra::Matrix4; use nalgebra::Point3; @@ -12,7 +13,7 @@ pub const OPENGL_TO_WGPU_MATRIX: Matrix4 = Matrix4::new( 0.0, 0.0, 0.0, 1.0, ); -struct Camera { +pub struct Camera { eye: Point3, target: Point3, up: Vector3, @@ -23,7 +24,7 @@ struct Camera { } impl Camera { - fn new( + pub fn new( eye: Point3, target: Point3, up: Vector3, @@ -31,7 +32,7 @@ impl Camera { aspect: f32, ) -> Self { let znear = EPSILON; - let zfar = 1.0 / EPSILON; + let zfar = INFINITY; Camera { eye, target, @@ -43,9 +44,34 @@ impl Camera { } } - fn build_mvp_matrix(&self, model: Matrix4) -> Matrix4 { + pub fn build_view_projection_matrix(&self) -> Matrix4 { let view = Matrix4::look_at_lh(&self.eye, &self.target, &self.up); let proj = Matrix4::new_perspective(self.aspect, self.fovy, self.znear, self.zfar); - return OPENGL_TO_WGPU_MATRIX * proj * view * model; + proj * view + } + pub fn build_inverse_view_projection_matrix(&self) -> Matrix4 { + let view_proj = self.build_view_projection_matrix(); + view_proj.try_inverse().expect("Cannot invert!") + } + pub fn cast_rays(&self, width: usize, height: usize) -> Vec { + let inverse_matrix = self.build_inverse_view_projection_matrix(); + let dx = 2.0 / width as f32; + let dy = 2.0 / height as f32; + + let mut rays = Vec::with_capacity(width as usize * height as usize); + + for i in 0..width { + for j in 0..height { + let x = -1.0 + i as f32 * dx; + let y = 1.0 - j as f32 * dy; + + let a = inverse_matrix.transform_point(&Point3::new(x, y, -1.0)); + let b = inverse_matrix.transform_vector(&Vector3::new(0.0, 0.0, 1.0)); + + let ray = Ray { a, b }; + rays.push(ray); + } + } + rays } } diff --git a/src/main.rs b/src/main.rs index 1538cfe..1c2724b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,19 +2,22 @@ #![allow(unused_imports)] #![allow(unused_variables)] //Use linear algebra module -use state::run; +use display::run; //Cameras mod camera; +mod display; +mod light; mod primitive; mod ray; -mod state; -mod texture; -mod vertex; +mod scene; +// mod state; +// mod texture; +// mod vertex; const EPSILON: f32 = 1e-7; const INFINITY: f32 = 1e7; fn main() { - pollster::block_on(run()); + run().expect(""); } diff --git a/src/primitive.rs b/src/primitive.rs index e43a34a..cbc1400 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -12,16 +12,16 @@ lazy_static! { } // MATERIAL ----------------------------------------------------------------- -struct Material { +pub struct Material { kd: Vector3, ks: Vector3, shininess: f32, } impl Material { - fn new(kd: Vector3, ks: Vector3, shininess: f32) -> Self { + pub fn new(kd: Vector3, ks: Vector3, shininess: f32) -> Self { Material { kd, ks, shininess } } - fn magenta() -> Self { + pub fn magenta() -> Self { let kd = Vector3::new(1.0, 0.0, 1.0); let ks = Vector3::new(0.0, 1.0, 1.0); let shininess = 0.5; @@ -29,14 +29,14 @@ impl Material { } } // INTERSECTION ----------------------------------------------------------------- -struct Intersection { +pub struct Intersection { point: Point3, normal: Vector3, distance: f32, // Information about an intersection } impl Intersection { - fn new(point: Point3, normal: Vector3, t: f32) -> Self { + pub fn new(point: Point3, normal: Vector3, t: f32) -> Self { Intersection { point, normal, @@ -69,7 +69,7 @@ impl BoundingBox { } } // PRIMITIVE TRAIT ----------------------------------------------------------------- -trait Primitive<'a> { +pub trait Primitive<'a> { fn intersect_ray(&self, ray: &Ray) -> Option; fn interesct_bounding_box(&self, ray: &Ray) -> Option>; fn get_material(self) -> &'a Material; @@ -722,7 +722,7 @@ impl<'a> Primitive<'a> for Mesh<'a> { } } - return closest_intersect; + closest_intersect } fn get_material(self) -> &'a Material { diff --git a/src/ray.rs b/src/ray.rs index 3d5bc2a..b10d480 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -8,8 +8,9 @@ pub struct Ray { } impl Ray { - pub fn new(_a: Point3, _b: Vector3) -> Ray { - Ray { a: _a, b: _b } + pub fn new(a: Point3, b: Vector3) -> Ray { + let b = b.normalize(); + Ray { a, b } } pub fn at_t(&self, t: f32) -> Point3 { self.a + self.b * t diff --git a/src/state.rs b/src/state.rs deleted file mode 100644 index 3823c80..0000000 --- a/src/state.rs +++ /dev/null @@ -1,387 +0,0 @@ -use crate::texture::Texture; -use crate::vertex::Vertex; -use std::{fs, iter}; -use wgpu::util::DeviceExt; -use winit::{ - event::*, - event_loop::{ControlFlow, EventLoop}, - window::{Window, WindowBuilder}, -}; - -struct State { - surface: wgpu::Surface, - device: wgpu::Device, - queue: wgpu::Queue, - config: wgpu::SurfaceConfiguration, - size: winit::dpi::PhysicalSize, - render_pipeline: wgpu::RenderPipeline, - window: Window, - //Vertex buffer - num_vertices: u32, - vertex_buffer: wgpu::Buffer, - //Indicies buffer - num_indices: u32, - index_buffer: wgpu::Buffer, - diffuse_bind_group: wgpu::BindGroup, - diffuse_texture: Texture, // NEW -} - -impl State { - async fn new(window: Window) -> Self { - let size = window.inner_size(); - // The instance is a handle to our GPU - // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends: wgpu::Backends::all(), - ..Default::default() - }); - - // # Safety - // - // The surface needs to live as long as the window that created it. - // State owns the window so this should be safe. - 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 { - label: None, - features: wgpu::Features::empty(), - // WebGL doesn't support all of wgpu's features, so if - // we're building for the web we'll have to disable some. - limits: if cfg!(target_arch = "wasm32") { - wgpu::Limits::downlevel_webgl2_defaults() - } else { - wgpu::Limits::default() - }, - }, - None, // Trace path - ) - .await - .unwrap(); - - let surface_caps = surface.get_capabilities(&adapter); - // Shader code in this tutorial assumes an Srgb surface texture. Using a different - // one will result all the colors comming out darker. If you want to support non - // Srgb surfaces, you'll need to account for that when drawing to the frame. - let surface_format = surface_caps - .formats - .iter() - .copied() - .find(|f| f.is_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![], - }; - - surface.configure(&device, &config); - - let diffuse_bytes = include_bytes!("happy-tree.png"); // CHANGED! - let diffuse_texture = - Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap(); // CHANGED! - - let texture_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - // This should match the filterable field of the - // corresponding Texture entry above. - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - ], - label: Some("texture_bind_group_layout"), - }); - - let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &texture_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), // CHANGED! - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), // CHANGED! - }, - ], - label: Some("diffuse_bind_group"), - }); - - let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shader.wgsl").into()), - }); - - let render_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Render Pipeline Layout"), - bind_group_layouts: &[&texture_bind_group_layout], // NEW! - push_constant_ranges: &[], - }); - - let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Render Pipeline"), - layout: Some(&render_pipeline_layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "vs_main", - buffers: &[Vertex::desc()], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: Some(wgpu::Face::Back), - // Setting this to anything other than Fill requires Features::POLYGON_MODE_LINE - // or Features::POLYGON_MODE_POINT - polygon_mode: wgpu::PolygonMode::Fill, - // Requires Features::DEPTH_CLIP_CONTROL - unclipped_depth: false, - // Requires Features::CONSERVATIVE_RASTERIZATION - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - - // If the pipeline will be used with a multiview render pass, this - // indicates how many array layers the attachments will have. - multiview: None, - }); - - const VERTICES: &[Vertex] = &[ - Vertex { - position: [-0.0868241, 0.49240386, 0.0], - tex_coords: [0.4131759, 0.99240386], - }, // A - Vertex { - position: [-0.49513406, 0.06958647, 0.0], - tex_coords: [0.0048659444, 0.56958647], - }, // B - Vertex { - position: [-0.21918549, -0.44939706, 0.0], - tex_coords: [0.28081453, 0.05060294], - }, // C - Vertex { - position: [0.35966998, -0.3473291, 0.0], - tex_coords: [0.85967, 0.1526709], - }, // D - Vertex { - position: [0.44147372, 0.2347359, 0.0], - tex_coords: [0.9414737, 0.7347359], - }, // E - ]; - const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4]; - - let num_indices = INDICES.len() as u32; - let num_vertices = VERTICES.len() as u32; - - let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Index Buffer"), - contents: bytemuck::cast_slice(INDICES), - usage: wgpu::BufferUsages::INDEX, - }); - - let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Vertex Buffer"), - contents: bytemuck::cast_slice(VERTICES), - usage: wgpu::BufferUsages::VERTEX, - }); - - Self { - surface, - device, - queue, - config, - render_pipeline, - size, - window, - num_vertices, - vertex_buffer, - num_indices, - index_buffer, - diffuse_bind_group, - diffuse_texture, - } - } - - fn window(&self) -> &Window { - &self.window - } - - pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { - if new_size.width > 0 && new_size.height > 0 { - self.size = new_size; - self.config.width = new_size.width; - self.config.height = new_size.height; - self.surface.configure(&self.device, &self.config); - } - } - - fn input(&mut self, event: &WindowEvent) -> bool { - match event { - WindowEvent::KeyboardInput { - input: - KeyboardInput { - state, - virtual_keycode: Some(VirtualKeyCode::Space), - .. - }, - .. - } => true, - _ => false, - } - } - - fn update(&mut self) {} - - fn render(&mut self) -> 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: Some("Render Encoder"), - }); - - { - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.1, - g: 0.2, - b: 0.3, - a: 1.0, - }), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - occlusion_query_set: None, - timestamp_writes: None, - }); - - render_pass.set_pipeline(&self.render_pipeline); - render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]); // NEW! - render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); - render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16); - - render_pass.draw_indexed(0..self.num_indices, 0, 0..1); - } - - self.queue.submit(iter::once(encoder.finish())); - output.present(); - - Ok(()) - } -} - -pub async fn run() { - env_logger::init(); - let event_loop = EventLoop::new(); - let window = WindowBuilder::new().build(&event_loop).unwrap(); - // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(window).await; - - event_loop.run(move |event, _, control_flow| { - match event { - Event::WindowEvent { - ref event, - window_id, - } if window_id == state.window().id() => { - if !state.input(event) { - match event { - WindowEvent::CloseRequested - | WindowEvent::KeyboardInput { - input: - KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(VirtualKeyCode::Escape), - .. - }, - .. - } => *control_flow = ControlFlow::Exit, - WindowEvent::Resized(physical_size) => { - state.resize(*physical_size); - } - WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { - // new_inner_size is &mut so w have to dereference it twice - state.resize(**new_inner_size); - } - _ => {} - } - } - } - Event::RedrawRequested(window_id) if window_id == state.window().id() => { - state.update(); - match state.render() { - Ok(_) => {} - // Reconfigure the surface if it's lost or outdated - Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => { - state.resize(state.size) - } - // The system is out of memory, we should probably quit - Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit, - // We're ignoring timeouts - Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"), - } - } - Event::MainEventsCleared => { - // RedrawRequested will only trigger once, unless we manually - // request it. - state.window().request_redraw(); - } - _ => {} - } - }); -} diff --git a/src/texture.rs b/src/texture.rs deleted file mode 100644 index f3d869c..0000000 --- a/src/texture.rs +++ /dev/null @@ -1,79 +0,0 @@ -use anyhow::*; -use image::GenericImageView; - -pub struct Texture { - pub texture: wgpu::Texture, - pub view: wgpu::TextureView, - pub sampler: wgpu::Sampler, -} - -impl Texture { - pub fn from_bytes( - device: &wgpu::Device, - queue: &wgpu::Queue, - bytes: &[u8], - label: &str, - ) -> Result { - let img = image::load_from_memory(bytes)?; - Self::from_image(device, queue, &img, Some(label)) - } - - pub fn from_image( - device: &wgpu::Device, - queue: &wgpu::Queue, - img: &image::DynamicImage, - label: Option<&str>, - ) -> Result { - let rgba = img.to_rgba8(); - let dimensions = img.dimensions(); - - let size = wgpu::Extent3d { - width: dimensions.0, - height: dimensions.1, - depth_or_array_layers: 1, - }; - let texture = device.create_texture(&wgpu::TextureDescriptor { - label, - size, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - view_formats: &[], - }); - - queue.write_texture( - wgpu::ImageCopyTexture { - aspect: wgpu::TextureAspect::All, - texture: &texture, - mip_level: 0, - origin: wgpu::Origin3d::ZERO, - }, - &rgba, - wgpu::ImageDataLayout { - offset: 0, - bytes_per_row: Some(4 * dimensions.0), - rows_per_image: Some(dimensions.1), - }, - size, - ); - - let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); - let 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::Nearest, - mipmap_filter: wgpu::FilterMode::Nearest, - ..Default::default() - }); - - Ok(Self { - texture, - view, - sampler, - }) - } -}