From 280d86c09d933c158e33662660d2727da530c6c9 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 23 Dec 2023 11:01:27 -0800 Subject: [PATCH] Minor edit --- src/main.rs | 10 +- src/render/mod.rs | 19 ++- src/render/pipeline.rs | 140 ++++++++++++++++++ .../shaders/{shader.wgsl => sprite.wgsl} | 19 ++- src/render/shaders/starfield.wgsl | 39 +++++ 5 files changed, 207 insertions(+), 20 deletions(-) create mode 100644 src/render/pipeline.rs rename src/render/shaders/{shader.wgsl => sprite.wgsl} (72%) create mode 100644 src/render/shaders/starfield.wgsl diff --git a/src/main.rs b/src/main.rs index 4589467..d87bde5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,10 +68,14 @@ struct Sprite { impl Sprite { const PARALLAX_STRENGTH: Pfloat = 0.1; + pub fn post_parallax(parallax: Pfloat, pos: Point2, camera: Camera) -> Point2 { + let v = camera.pos.to_vec() - pos.to_vec(); + return pos + (v * parallax * Self::PARALLAX_STRENGTH); + } + /// Returns post-parallax position in game coordinates. - pub fn post_parallax_position(&self, camera: Camera) -> Point2 { - let v = camera.pos.to_vec() - self.pos.to_vec(); - return self.pos + (v * self.parallax * Self::PARALLAX_STRENGTH); + pub fn post_parallax_position(&self, camera: Camera) -> Point2 { + return Self::post_parallax(self.parallax, self.pos, camera); } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 33afad8..dc26b53 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,5 +1,6 @@ mod bufferdata; mod gpustate; +mod pipeline; mod rawtexture; mod texturearray; mod util; @@ -7,7 +8,7 @@ mod util; pub use gpustate::GPUState; pub use texturearray::Texture; -use self::bufferdata::Vertex; +use self::bufferdata::{PlainVertex, TexturedVertex}; use cgmath::Matrix4; /// API correction matrix. @@ -21,6 +22,10 @@ const OPENGL_TO_WGPU_MATRIX: Matrix4 = Matrix4::new( 0.0, 0.0, 0.0, 1.0, ); +const STARFIELD_VERTICES: &[PlainVertex] = &[PlainVertex { + position: [0.0, 0.0, 0.0], +}]; + // The surface we draw sprites on. // Every sprite is an instance of this. // @@ -32,23 +37,23 @@ const OPENGL_TO_WGPU_MATRIX: Matrix4 = Matrix4::new( // Screen coordinates range from -1 to 1, with the origin at the center. // Texture coordinates range from 0 to 1, with the origin at the top-left // and (1,1) at the bottom-right. -const SPRITE_MESH_VERTICES: &[Vertex] = &[ - Vertex { +const SPRITE_VERTICES: &[TexturedVertex] = &[ + TexturedVertex { position: [-1.0, 1.0, 0.0], texture_coords: [0.0, 0.0], }, - Vertex { + TexturedVertex { position: [1.0, 1.0, 0.0], texture_coords: [1.0, 0.0], }, - Vertex { + TexturedVertex { position: [1.0, -1.0, 0.0], texture_coords: [1.0, 1.0], }, - Vertex { + TexturedVertex { position: [-1.0, -1.0, 0.0], texture_coords: [0.0, 1.0], }, ]; -const SPRITE_MESH_INDICES: &[u16] = &[0, 3, 2, 0, 2, 1]; +const SPRITE_INDICES: &[u16] = &[0, 3, 2, 0, 2, 1]; diff --git a/src/render/pipeline.rs b/src/render/pipeline.rs new file mode 100644 index 0000000..8f8139e --- /dev/null +++ b/src/render/pipeline.rs @@ -0,0 +1,140 @@ +use wgpu; + +pub struct PipelineBuilder<'a> { + // These are provided with new() + label: &'a str, + device: &'a wgpu::Device, + + // These have empty defaults + triangle: bool, + vertex_buffers: &'a [wgpu::VertexBufferLayout<'a>], + bind_group_layouts: &'a [&'a wgpu::BindGroupLayout], + + // These must be provided + shader: Option<&'a str>, + format: Option, +} + +impl<'a> PipelineBuilder<'a> { + const VERTEX_MAIN: &'static str = "vertex_shader_main"; + const FRAGMENT_MAIN: &'static str = "fragment_shader_main"; + + pub fn new(label: &'a str, device: &'a wgpu::Device) -> Self { + Self { + label, + device, + + triangle: true, + vertex_buffers: &[], + bind_group_layouts: &[], + + shader: None, + format: None, + } + } + + pub fn set_shader(mut self, shader: &'a str) -> Self { + self.shader = Some(shader); + self + } + + pub fn set_format(mut self, format: wgpu::TextureFormat) -> Self { + self.format = Some(format); + self + } + + pub fn set_triangle(mut self, triangle: bool) -> Self { + self.triangle = triangle; + self + } + + pub fn set_vertex_buffers( + mut self, + vertex_buffers: &'a [wgpu::VertexBufferLayout<'a>], + ) -> Self { + self.vertex_buffers = vertex_buffers; + self + } + + pub fn set_bind_group_layouts( + mut self, + bind_group_layouts: &'a [&'a wgpu::BindGroupLayout], + ) -> Self { + self.bind_group_layouts = bind_group_layouts; + self + } + + pub fn build(self) -> wgpu::RenderPipeline { + // All fields should be set. + // Nones are not checked, they will panic. + + let shader = self + .device + .create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some(&format!("pipeline [{}] shader", self.label)), + source: wgpu::ShaderSource::Wgsl(self.shader.unwrap().into()), + }); + + let pipeline_layout = self + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some(&format!("pipeline [{}] layout", self.label)), + bind_group_layouts: self.bind_group_layouts, + push_constant_ranges: &[], + }); + + let pipeline = self + .device + .create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some(&format!("pipeline [{}]", self.label)), + layout: Some(&pipeline_layout), + depth_stencil: None, + multiview: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + + vertex: wgpu::VertexState { + module: &shader, + entry_point: Self::VERTEX_MAIN, + buffers: self.vertex_buffers, + }, + + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: Self::FRAGMENT_MAIN, + targets: &[Some(wgpu::ColorTargetState { + format: self.format.unwrap(), + blend: Some(wgpu::BlendState::ALPHA_BLENDING), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + + primitive: if self.triangle { + wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + } + } else { + wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::PointList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + } + }, + }); + + return pipeline; + } +} diff --git a/src/render/shaders/shader.wgsl b/src/render/shaders/sprite.wgsl similarity index 72% rename from src/render/shaders/shader.wgsl rename to src/render/shaders/sprite.wgsl index cc3380f..f07026b 100644 --- a/src/render/shaders/shader.wgsl +++ b/src/render/shaders/sprite.wgsl @@ -1,23 +1,22 @@ struct InstanceInput { - @location(5) transform_matrix_0: vec4, - @location(6) transform_matrix_1: vec4, - @location(7) transform_matrix_2: vec4, - @location(8) transform_matrix_3: vec4, - @location(9) texture_idx: u32, + @location(2) transform_matrix_0: vec4, + @location(3) transform_matrix_1: vec4, + @location(4) transform_matrix_2: vec4, + @location(5) transform_matrix_3: vec4, + @location(6) texture_idx: u32, }; - // Vertex shader struct VertexInput { @location(0) position: vec3, - @location(1) tex_coords: vec2, + @location(1) texture_coords: vec2, } struct VertexOutput { @builtin(position) clip_position: vec4, - @location(0) tex_coords: vec2, + @location(0) texture_coords: vec2, @location(1) index: u32, } @@ -34,7 +33,7 @@ fn vertex_shader_main( ); var out: VertexOutput; - out.tex_coords = model.tex_coords; + out.texture_coords = model.texture_coords; out.clip_position = transform_matrix * vec4(model.position, 1.0); out.index = instance.texture_idx; return out; @@ -54,7 +53,7 @@ fn fragment_shader_main(in: VertexOutput) -> @location(0) vec4 { return textureSampleLevel( texture_array[in.index], sampler_array[in.index], - in.tex_coords, + in.texture_coords, 0.0 ).rgba; } \ No newline at end of file diff --git a/src/render/shaders/starfield.wgsl b/src/render/shaders/starfield.wgsl new file mode 100644 index 0000000..4c4982c --- /dev/null +++ b/src/render/shaders/starfield.wgsl @@ -0,0 +1,39 @@ +struct InstanceInput { + @location(2) transform_matrix_0: vec4, + @location(3) transform_matrix_1: vec4, + @location(4) transform_matrix_2: vec4, + @location(5) transform_matrix_3: vec4, +}; + +// Vertex shader + +struct VertexInput { + @location(0) position: vec3, +} + +struct VertexOutput { + @builtin(position) clip_position: vec4, +} + +@vertex +fn vertex_shader_main( + model: VertexInput, + instance: InstanceInput, +) -> VertexOutput { + let transform_matrix = mat4x4( + instance.transform_matrix_0, + instance.transform_matrix_1, + instance.transform_matrix_2, + instance.transform_matrix_3, + ); + + var out: VertexOutput; + out.clip_position = transform_matrix * vec4(model.position, 1.0); + return out; +} + + +@fragment +fn fragment_shader_main(in: VertexOutput) -> @location(0) vec4 { + return vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file