diff --git a/Cargo.lock b/Cargo.lock index 396d7028..e45b4338 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,6 +191,20 @@ name = "bytemuck" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] [[package]] name = "calloop" @@ -905,6 +919,7 @@ dependencies = [ name = "oden" version = "0.1.0" dependencies = [ + "bytemuck", "env_logger", "log", "pollster", diff --git a/Cargo.toml b/Cargo.toml index 5cbdfe2a..2ff77136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,4 @@ log = "0.4" wgpu = "0.16" winit = "0.28" pollster = "0.3" +bytemuck = { version = "1.13", features = ["derive"] } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1b039164..9c4d677d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +use bytemuck; +use wgpu::util::DeviceExt; use winit::{ event::*, event_loop::{ControlFlow, EventLoop}, @@ -5,6 +7,60 @@ use winit::{ window::WindowBuilder, }; +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +struct Vertex { + position: [f32; 3], + color: [f32; 3], +} + +// lib.rs +impl Vertex { + fn desc() -> wgpu::VertexBufferLayout<'static> { + wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, + shader_location: 1, + format: wgpu::VertexFormat::Float32x3, + }, + ], + } + } +} + +const VERTICES: &[Vertex] = &[ + Vertex { + position: [-0.0868241, 0.49240386, 0.0], + color: [0.5, 0.0, 0.5], + }, // A + Vertex { + position: [-0.49513406, 0.06958647, 0.0], + color: [0.5, 0.0, 0.5], + }, // B + Vertex { + position: [-0.21918549, -0.44939706, 0.0], + color: [0.5, 0.0, 0.5], + }, // C + Vertex { + position: [0.35966998, -0.3473291, 0.0], + color: [0.5, 0.0, 0.5], + }, // D + Vertex { + position: [0.44147372, 0.2347359, 0.0], + color: [0.5, 0.0, 0.5], + }, // E +]; + +const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4]; + struct State { surface: wgpu::Surface, device: wgpu::Device, @@ -12,6 +68,13 @@ struct State { config: wgpu::SurfaceConfiguration, size: winit::dpi::PhysicalSize, window: Window, + render_pipeline: wgpu::RenderPipeline, + + vertex_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, + num_indices: u32, // Indices in index_buffer + + // Garbage mouse_x: f64, mouse_y: f64, } @@ -86,6 +149,68 @@ impl State { }; surface.configure(&device, &config); + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("Shader"), + source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()), + }); + + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Render Pipeline Layout"), + bind_group_layouts: &[], + 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::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::NON_FILL_POLYGON_MODE + 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, + }, + multiview: None, + }); + + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Vertex Buffer"), + contents: bytemuck::cast_slice(VERTICES), + usage: wgpu::BufferUsages::VERTEX, + }); + let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Index Buffer"), + contents: bytemuck::cast_slice(INDICES), + usage: wgpu::BufferUsages::INDEX, + }); + let num_indices = INDICES.len() as u32; + Self { window, surface, @@ -93,6 +218,11 @@ impl State { queue, config, size, + render_pipeline, + vertex_buffer, + index_buffer, + num_indices, + mouse_x: 0.0, mouse_y: 0.0, } @@ -134,7 +264,7 @@ impl State { let g: f64 = (self.mouse_y / f64::from(self.size.height)).clamp(0.0, 1.0) * 0.2; // END GARBAGE - let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &view, @@ -151,6 +281,11 @@ impl State { })], depth_stencil_attachment: None, }); + + render_pass.set_pipeline(&self.render_pipeline); + 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); } // Submit will accept anything that implements IntoIter diff --git a/src/shader.wgsl b/src/shader.wgsl new file mode 100644 index 00000000..cc394ed9 --- /dev/null +++ b/src/shader.wgsl @@ -0,0 +1,28 @@ +// Vertex shader + +struct VertexInput { + @location(0) position: vec3, + @location(1) color: vec3, +}; + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) color: vec3, +}; + +@vertex +fn vs_main( + model: VertexInput, +) -> VertexOutput { + var out: VertexOutput; + out.color = model.color; + out.clip_position = vec4(model.position, 1.0); + return out; +} + +// Fragment shader + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + return vec4(in.color, 1.0); +}