From 159e4258e9103481cb06e0ff6533c82ae542af16 Mon Sep 17 00:00:00 2001 From: Arkitu Date: Wed, 25 Sep 2024 19:13:50 +0200 Subject: [PATCH] save --- assets/texture.png | Bin 0 -> 186 bytes src/graphics.rs | 69 ++++++++++++++++++++++++++--- src/graphics/texture.rs | 93 ++++++++++++++++++++++++++++++++++++++++ src/shader.wgsl | 35 +++++++++------ src/state.rs | 4 +- 5 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 assets/texture.png create mode 100644 src/graphics/texture.rs diff --git a/assets/texture.png b/assets/texture.png new file mode 100644 index 0000000000000000000000000000000000000000..8d639837e4e8f368f1fd834840208f199e66a984 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K$eR6JcALo5W7 z6Bw8}Q||u%U;pm!{zo(4)C<&$^t2tw;OIF4bdSRU4z>?j!Py{vp00i_>zopr0DN^P AY5)KL literal 0 HcmV?d00001 diff --git a/src/graphics.rs b/src/graphics.rs index fb564a9..f24c397 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -6,12 +6,22 @@ use winit::{event::{Event, WindowEvent}, window::Window}; use crate::{state::State, App}; +mod texture; +use texture::Texture; + #[repr(C)] #[derive(Clone, Copy, Zeroable, Pod, Debug)] pub struct Vertex { pub pos: [f32; 2], pub color: [f32; 4], - pub effect: u32, // 0: None, 1: Grayscale, 2: Scaled, 3: Grayscale + Scaled + pub tex_coords: [f32; 2], + /// Each bit is used as a flag : + /// 0: Scaled and moved according to camera + /// 1: Grayscale + /// 2: Whiter + /// + /// For exemple 0b110 corresponds to Scaled and Grayscale + pub effect: u32, } impl Vertex { const DESC: VertexBufferLayout<'static> = VertexBufferLayout { @@ -46,7 +56,9 @@ pub struct Graphics<'a> { vertex_buf: Buffer, index_buf: Buffer, uniforms_buf: Buffer, - uniforms_bind_group: BindGroup + uniforms_bind_group: BindGroup, + diffuse_bind_group: BindGroup, + diffuse_texture: Texture } impl<'a> Graphics<'a> { pub async fn init(state: &State, window: Arc) -> Self { @@ -125,7 +137,29 @@ impl<'a> Graphics<'a> { ], label: Some("Uniforms Bind Group"), }); - + 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"), + }); // Load the shaders from disk let shader = device.create_shader_module(include_wgsl!("shader.wgsl")); @@ -133,7 +167,8 @@ impl<'a> Graphics<'a> { let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, bind_group_layouts: &[ - &uniforms_bind_group_layout + &uniforms_bind_group_layout, + &texture_bind_group_layout ], push_constant_ranges: &[], }); @@ -170,6 +205,27 @@ impl<'a> Graphics<'a> { .unwrap(); surface.configure(&device, &surface_config); + + + let diffuse_bytes = include_bytes!("../assets/texture.png"); + let diffuse_texture = Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png"); + 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"), + } + ); + Self { // window, surface_config, @@ -180,7 +236,9 @@ impl<'a> Graphics<'a> { vertex_buf, index_buf, uniforms_buf, - uniforms_bind_group + uniforms_bind_group, + diffuse_bind_group, + diffuse_texture } } pub fn window_event(&mut self, event: &WindowEvent, window: &Window) { @@ -246,6 +304,7 @@ impl<'a> Graphics<'a> { }); rpass.set_pipeline(&self.render_pipeline); rpass.set_bind_group(0, &self.uniforms_bind_group, &[]); + rpass.set_bind_group(1, &self.diffuse_bind_group, &[]); rpass.set_vertex_buffer(0, self.vertex_buf.slice(..)); rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint32); rpass.draw_indexed(0..state.indices.len() as u32, 0, 0..1); diff --git a/src/graphics/texture.rs b/src/graphics/texture.rs new file mode 100644 index 0000000..f183c85 --- /dev/null +++ b/src/graphics/texture.rs @@ -0,0 +1,93 @@ +use image::GenericImageView; + +const TEXTURE_DIMENSIONS: [usize; 2] = [16, 16]; + +#[derive(Debug, Clone, Copy)] +pub enum Color { + Void = 0, + Forest = 1, + Beach = 2, + Grass = 3 +} +impl Into<[f32; 2]> for Color { + fn into(self) -> [f32; 2] { + [(self as usize % TEXTURE_DIMENSIONS[0]) as f32 / TEXTURE_DIMENSIONS[0] as f32, (self as usize / TEXTURE_DIMENSIONS[1]) as f32 / TEXTURE_DIMENSIONS[1] as f32] + } +} + +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 + ) -> Self { + let img = image::load_from_memory(bytes).unwrap(); + Self::from_image(device, queue, &img, Some(label)) + } + + pub fn from_image( + device: &wgpu::Device, + queue: &wgpu::Queue, + img: &image::DynamicImage, + label: Option<&str> + ) -> Self { + 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::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + } + ); + + Self { texture, view, sampler } + } +} diff --git a/src/shader.wgsl b/src/shader.wgsl index 944c794..ef0a053 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -5,40 +5,51 @@ struct Uniforms { @group(0) @binding(0) var uniforms : Uniforms; struct VertexOutput { - @location(0) color: vec4f, + @location(0) tex_coords: vec2f, + @location(1) color: vec4f, @builtin(position) pos: vec4f } @vertex fn vs_main( @location(0) pos: vec2f, - @location(1) color: vec4f, + @location(1) tex_coords: vec2f, @location(2) effect: u32 ) -> VertexOutput { var out: VertexOutput; + return out; +} + +@group(1) @binding(0) +var t_diffuse: texture_2d; +@group(1) @binding(1) +var s_diffuse: sampler; + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4f { + var tex_col = textureSample(t_diffuse, s_diffuse, in.tex_coords); + var color = vec4f((tex_col.rgb * tex_col.a) + (in.color.rgb * in.color.a), tex_col.a + in.color.a); + if effect & 0100u != 0u { + color = vec4f(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a); + } switch effect { case 1u, 3u: { var v = (color.r*0.299) + (color.g*0.587) + (color.b*0.114); - out.color = vec4f(v, v, v, color.a); + color = vec4f(v, v, v, color.a); } case 0u, 2u: { - out.color = color; + color = color; } default: {} } switch effect { case 0u, 1u: { - out.pos = vec4f(pos, 0, 1); + pos = vec4f(pos, 0, 1); } case 2u, 3u: { - out.pos = vec4f((pos - uniforms.camera) * uniforms.zooms, 0, 1); + pos = vec4f((pos - uniforms.camera) * uniforms.zooms, 0, 1); } default: {} } - return out; -} - -@fragment -fn fs_main(v: VertexOutput) -> @location(0) vec4f { - return v.color; + return color; } diff --git a/src/state.rs b/src/state.rs index f3e59f5..afa19ee 100644 --- a/src/state.rs +++ b/src/state.rs @@ -195,7 +195,7 @@ impl State { self.indices = Vec::new(); for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()).filter(|(_,cd)| cd.kind != CellKind::Forest) { - let mut color = cd.color(); + let mut tex_coords = cd.color(); if c.site() == self.selected_tile { color[0] = (color[0]+0.4).clamp(0., 1.); color[1] = (color[1]+0.4).clamp(0., 1.); @@ -204,7 +204,7 @@ impl State { let vs = c.iter_vertices().collect::>(); let i = self.vertices.len() as u32; for v in vs.iter() { - self.vertices.push(Vertex { pos: [v.x as f32, v.y as f32], color, effect:2 }); + self.vertices.push(Vertex { pos: [v.x as f32, v.y as f32], tex_coords, effect:2 }); } for v in 1..(vs.len()-1) as u32 { self.indices.push(i);