summaryrefslogtreecommitdiff
path: root/src/renderer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer.rs')
-rw-r--r--src/renderer.rs82
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);