This commit is contained in:
Arkitu 2024-09-25 19:13:50 +02:00
parent 5143aed677
commit 159e4258e9
5 changed files with 182 additions and 19 deletions

BIN
assets/texture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

View File

@ -6,12 +6,22 @@ use winit::{event::{Event, WindowEvent}, window::Window};
use crate::{state::State, App}; use crate::{state::State, App};
mod texture;
use texture::Texture;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Zeroable, Pod, Debug)] #[derive(Clone, Copy, Zeroable, Pod, Debug)]
pub struct Vertex { pub struct Vertex {
pub pos: [f32; 2], pub pos: [f32; 2],
pub color: [f32; 4], 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 { impl Vertex {
const DESC: VertexBufferLayout<'static> = VertexBufferLayout { const DESC: VertexBufferLayout<'static> = VertexBufferLayout {
@ -46,7 +56,9 @@ pub struct Graphics<'a> {
vertex_buf: Buffer, vertex_buf: Buffer,
index_buf: Buffer, index_buf: Buffer,
uniforms_buf: Buffer, uniforms_buf: Buffer,
uniforms_bind_group: BindGroup uniforms_bind_group: BindGroup,
diffuse_bind_group: BindGroup,
diffuse_texture: Texture
} }
impl<'a> Graphics<'a> { impl<'a> Graphics<'a> {
pub async fn init(state: &State, window: Arc<Window>) -> Self { pub async fn init(state: &State, window: Arc<Window>) -> Self {
@ -125,7 +137,29 @@ impl<'a> Graphics<'a> {
], ],
label: Some("Uniforms Bind Group"), 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 // Load the shaders from disk
let shader = device.create_shader_module(include_wgsl!("shader.wgsl")); 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 { let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None, label: None,
bind_group_layouts: &[ bind_group_layouts: &[
&uniforms_bind_group_layout &uniforms_bind_group_layout,
&texture_bind_group_layout
], ],
push_constant_ranges: &[], push_constant_ranges: &[],
}); });
@ -170,6 +205,27 @@ impl<'a> Graphics<'a> {
.unwrap(); .unwrap();
surface.configure(&device, &surface_config); 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 { Self {
// window, // window,
surface_config, surface_config,
@ -180,7 +236,9 @@ impl<'a> Graphics<'a> {
vertex_buf, vertex_buf,
index_buf, index_buf,
uniforms_buf, uniforms_buf,
uniforms_bind_group uniforms_bind_group,
diffuse_bind_group,
diffuse_texture
} }
} }
pub fn window_event(&mut self, event: &WindowEvent, window: &Window) { 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_pipeline(&self.render_pipeline);
rpass.set_bind_group(0, &self.uniforms_bind_group, &[]); 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_vertex_buffer(0, self.vertex_buf.slice(..));
rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint32); rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint32);
rpass.draw_indexed(0..state.indices.len() as u32, 0, 0..1); rpass.draw_indexed(0..state.indices.len() as u32, 0, 0..1);

93
src/graphics/texture.rs Normal file
View File

@ -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 }
}
}

View File

@ -5,40 +5,51 @@ struct Uniforms {
@group(0) @binding(0) var<uniform> uniforms : Uniforms; @group(0) @binding(0) var<uniform> uniforms : Uniforms;
struct VertexOutput { struct VertexOutput {
@location(0) color: vec4f, @location(0) tex_coords: vec2f,
@location(1) color: vec4f,
@builtin(position) pos: vec4f @builtin(position) pos: vec4f
} }
@vertex @vertex
fn vs_main( fn vs_main(
@location(0) pos: vec2f, @location(0) pos: vec2f,
@location(1) color: vec4f, @location(1) tex_coords: vec2f,
@location(2) effect: u32 @location(2) effect: u32
) -> VertexOutput { ) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
return out;
}
@group(1) @binding(0)
var t_diffuse: texture_2d<f32>;
@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 { switch effect {
case 1u, 3u: { case 1u, 3u: {
var v = (color.r*0.299) + (color.g*0.587) + (color.b*0.114); 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: { case 0u, 2u: {
out.color = color; color = color;
} }
default: {} default: {}
} }
switch effect { switch effect {
case 0u, 1u: { case 0u, 1u: {
out.pos = vec4f(pos, 0, 1); pos = vec4f(pos, 0, 1);
} }
case 2u, 3u: { case 2u, 3u: {
out.pos = vec4f((pos - uniforms.camera) * uniforms.zooms, 0, 1); pos = vec4f((pos - uniforms.camera) * uniforms.zooms, 0, 1);
} }
default: {} default: {}
} }
return out; return color;
}
@fragment
fn fs_main(v: VertexOutput) -> @location(0) vec4f {
return v.color;
} }

View File

@ -195,7 +195,7 @@ impl State {
self.indices = Vec::new(); 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) { 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 { if c.site() == self.selected_tile {
color[0] = (color[0]+0.4).clamp(0., 1.); color[0] = (color[0]+0.4).clamp(0., 1.);
color[1] = (color[1]+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::<Vec<_>>(); let vs = c.iter_vertices().collect::<Vec<_>>();
let i = self.vertices.len() as u32; let i = self.vertices.len() as u32;
for v in vs.iter() { 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 { for v in 1..(vs.len()-1) as u32 {
self.indices.push(i); self.indices.push(i);