diff --git a/src/main.rs b/src/main.rs index e30afef..3da6b9e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,10 @@ struct Renderer { surface: wgpu::Surface, queue: wgpu::Queue, config: wgpu::SurfaceConfiguration, + camera_uniform: CameraUniform, + camera_buffer: wgpu::Buffer, + camera_bind_group: wgpu::BindGroup, + render_pipeline: wgpu::RenderPipeline, } impl Renderer { @@ -57,6 +61,85 @@ impl Renderer { let mesh_pool = MeshPool::default(); + let camera_uniform = CameraUniform::new(); + + let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Camera Buffer"), + contents: bytemuck::cast_slice(&[camera_uniform]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + let camera_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: Some("Camera Bind Group Layout"), + }); + + let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &camera_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: camera_buffer.as_entire_binding(), + }], + label: Some("Camera Bind Group"), + }); + + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Render Pipeline Layout"), + bind_group_layouts: &[&camera_bind_group_layout], + push_constant_ranges: &[], + }); + + let shader = device.create_shader_module(&wgpu::ShaderModuleDescriptor { + label: Some("Shader"), + source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()), + }); + + 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: &[wgpu::ColorTargetState { + format: config.format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + }], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::LineList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + }); + Self { size, surface, @@ -64,6 +147,10 @@ impl Renderer { queue, config, mesh_pool, + camera_uniform, + camera_buffer, + camera_bind_group, + render_pipeline, } } @@ -81,6 +168,39 @@ impl Renderer { camera: &impl Camera, meshes: &MeshCommands, ) -> 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: &[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: true, + }, + }], + depth_stencil_attachment: None, + }); + } + + self.queue.submit(std::iter::once(encoder.finish())); + output.present(); + Ok(()) } } @@ -137,12 +257,38 @@ struct CameraUniform { vp: [[f32; 4]; 4], } +impl CameraUniform { + pub fn new() -> Self { + Self { + vp: glam::Mat4::IDENTITY.to_cols_array_2d(), + } + } + + pub fn update(&mut self, camera: &impl Camera) { + self.vp = camera.get_vp(); + } +} + #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] struct Vertex { position: [f32; 3], } +impl Vertex { + pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + 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, + }], + } + } +} + type Index = u32; struct MeshData { diff --git a/src/shader.wgsl b/src/shader.wgsl new file mode 100644 index 0000000..67d9726 --- /dev/null +++ b/src/shader.wgsl @@ -0,0 +1,30 @@ +struct CameraUniform { + vp: mat4x4; +}; + +[[group(0), binding(0)]] +var camera: CameraUniform; + +struct VertexInput { + [[location(0)]] position: vec3; +}; + +struct VertexOutput { + [[builtin(position)]] clip_position: vec4; +}; + +[[stage(vertex)]] +fn vs_main( + vertex: VertexInput +) -> VertexOutput { + var out: VertexOutput; + out.clip_position = camera.vp * vec4(vertex.position, 1.0); + return out; +} + +[[stage(fragment)]] +fn fs_main( + frag: VertexOutput, +) -> [[location(0)]] vec4 { + return vec4(1.0); +}