diff options
Diffstat (limited to 'src/renderer.rs')
| -rw-r--r-- | src/renderer.rs | 82 |
1 files changed, 74 insertions, 8 deletions
diff --git a/src/renderer.rs b/src/renderer.rs index a86b05b..5820f1c 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,6 +1,9 @@ use std::{convert::TryInto, mem::size_of, num::NonZeroU32}; -use crate::{instance::InstanceId, vertex::SQUARE, Instance, RenderWindowConfig, Vertex}; +use crate::{ + camera::CameraUniform, instance::InstanceId, vertex::SQUARE, Camera, Instance, + RenderWindowConfig, Vertex, +}; use pollster::FutureExt; use thiserror::Error; use wgpu::{include_wgsl, util::DeviceExt}; @@ -48,6 +51,9 @@ pub struct Renderer { instance_buffer: wgpu::Buffer, instance_buffer_size: usize, instances: Vec<Instance>, + camera: Camera, + camera_buffer: wgpu::Buffer, + camera_bind_group: wgpu::BindGroup, window: Window, } @@ -78,17 +84,13 @@ impl Renderer { fn sprite_render_pipeline( device: &wgpu::Device, texture_format: wgpu::TextureFormat, + render_pipeline_layout: &wgpu::PipelineLayout, ) -> wgpu::RenderPipeline { let shader = device.create_shader_module(include_wgsl!("../shaders/sprite.wgsl")); - let render_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Sprite Render Pipeline Layout"), - ..Default::default() - }); device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("Sprite Render Pipeline"), - layout: Some(&render_pipeline_layout), + layout: Some(render_pipeline_layout), // information about the vertex shader vertex: wgpu::VertexState { module: &shader, @@ -183,8 +185,51 @@ impl Renderer { ); surface.configure(&device, &surface_config); + // create the camera + let width = window.inner_size().width; + let height = window.inner_size().height; + let camera = Camera::from_size(width, height); + let camera_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Camera Uniform"), + size: size_of::<CameraUniform>() as wgpu::BufferAddress, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let camera_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Camera Bind Group Layout"), + 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, + }], + }); + + let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Camera Bind Group"), + layout: &camera_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: camera_buffer.as_entire_binding(), + }], + }); + + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Sprite Render Pipeline Layout"), + bind_group_layouts: &[&camera_bind_group_layout], + push_constant_ranges: &[], + }); + // set up a pipeline for sprite rendering - let render_pipeline = Self::sprite_render_pipeline(&device, surface_config.format); + let render_pipeline = + Self::sprite_render_pipeline(&device, surface_config.format, &render_pipeline_layout); // the vertex buffer used for rendering squares let square_vertices = SQUARE @@ -214,6 +259,9 @@ impl Renderer { instance_buffer, instance_buffer_size, instances, + camera, + camera_buffer, + camera_bind_group, window, }) } @@ -231,6 +279,7 @@ impl Renderer { self.surface_config.height = size.height; self.surface_config.width = size.width; + self.camera.set_size(size.width, size.height); self.reconfigure(); } @@ -278,6 +327,11 @@ impl Renderer { InstanceId(index) } + /// Get an immutable reference to an instance + pub fn instance(&self, id: InstanceId) -> Option<&Instance> { + self.instances.get(id.0) + } + /// Get a mutable reference to an instance pub fn instance_mut(&mut self, id: InstanceId) -> Option<&mut Instance> { self.instances.get_mut(id.0) @@ -288,6 +342,14 @@ impl Renderer { self.instances.clear(); } + fn refresh_camera_buffer(&mut self) { + self.queue.write_buffer( + &self.camera_buffer, + 0 as wgpu::BufferAddress, + bytemuck::cast_slice(&self.camera.to_matrix()), + ); + } + /// Renders a new frame to the window /// /// # Errors @@ -295,6 +357,7 @@ impl Renderer { /// A number of problems could occur here. A timeout could occur while /// trying to acquire the next frame. There may also be no more memory left /// that can be used for the new frame. + // TODO this is too big fn render(&mut self) -> Result<(), wgpu::SurfaceError> { // the new texture we can render to let output = self.surface.get_current_texture()?; @@ -316,6 +379,8 @@ impl Renderer { .try_into() .expect("expected less than 3 billion instances"); + self.refresh_camera_buffer(); + { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), @@ -331,6 +396,7 @@ impl Renderer { }); render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &self.camera_bind_group, &[]); render_pass.set_vertex_buffer(0, self.square_vertex_buffer.slice(..)); render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); render_pass.draw(0..self.square_vertices, 0..num_instances); |
