diff --git a/src/circle_shader.wgsl b/src/circle_shader.wgsl index 4b03cae3..c9ca6bea 100644 --- a/src/circle_shader.wgsl +++ b/src/circle_shader.wgsl @@ -1,3 +1,4 @@ +// @include 'util.wgsl' // ---------------------------------------------------------------------------- // Vertex shader // ---------------------------------------------------------------------------- @@ -68,43 +69,3 @@ struct VertexOutput { return vec4(0.0, 0.0, 0.0, 0.0); } } - -// ---------------------------------------------------------------------------- -// Resolution Handling -// ---------------------------------------------------------------------------- - -struct ScreenUniform { - resolution : vec2f, -}; -@group(0) @binding(0) // 1. - var screen : ScreenUniform; - -const RES = vec2f(320.0, 240.0); // The logical resolution of the screen. - -fn adjust_for_resolution(in_pos: vec2) -> vec2 { - // Adjust in_pos for the "resolution" of the screen. - let RES_AR = RES.x / RES.y; // The aspect ratio of the logical screen. - - // the actual resolution of the screen. - let screen_ar = screen.resolution.x / screen.resolution.y; - - // Compute the difference in resolution ... correctly? - // - // nudge is the amount to add to the logical resolution so that the pixels - // stay the same size but we respect the aspect ratio of the screen. (So - // there's more of them in either the x or y direction.) - var nudge = vec2f(0.0); - if (screen_ar > RES_AR) { - nudge.x = (RES.y * screen_ar) - RES.x; - } else { - nudge.y = (RES.x / screen_ar) - RES.y; - } - var new_logical_resolution = RES + nudge; - - // Now we can convert the incoming position to clip space, in the new screen. - let centered = in_pos + (nudge / 2.0); - var position = (2.0 * centered / new_logical_resolution) - 1.0; - position.y = -position.y; - - return position; -} diff --git a/src/lib.rs b/src/lib.rs index 71783e23..8c2fd2fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,12 +202,14 @@ impl GlyphInstance { #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] struct ScreenUniforms { resolution: [f32; 2], + scale: [f32; 2], } impl ScreenUniforms { - fn new(width: u32, height: u32) -> ScreenUniforms { + fn new(width: u32, height: u32, scale_x: f32, scale_y: f32) -> ScreenUniforms { ScreenUniforms { resolution: [width as f32, height as f32], + scale: [scale_x, scale_y], } } } @@ -483,7 +485,7 @@ impl State { label: Some("sprite_bind_group_layout"), }); - let screen_uniform = ScreenUniforms::new(size.width, size.height); + let screen_uniform = ScreenUniforms::new(size.width, size.height, 10.0, 10.0); let screen_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Screen Uniform Buffer"), contents: bytemuck::cast_slice(&[screen_uniform]), @@ -517,10 +519,8 @@ impl State { // ==================================================================== // Sprites // ==================================================================== - let sprite_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Sprite Shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("sprite_shader.wgsl").into()), - }); + let sprite_shader = + Self::load_shader(&device, "Sprite Shader", include_str!("sprite_shader.wgsl")); let sprite_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { @@ -571,10 +571,8 @@ impl State { // ==================================================================== // Circles // ==================================================================== - let circle_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Circle Shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("circle_shader.wgsl").into()), - }); + let circle_shader = + Self::load_shader(&device, "Circle Shader", include_str!("circle_shader.wgsl")); let circle_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { @@ -647,10 +645,8 @@ impl State { label: Some("text_bind_group_layout"), }); - let text_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Text Shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("text_shader.wgsl").into()), - }); + let text_shader = + Self::load_shader(&device, "Text Shader", include_str!("text_shader.wgsl")); let text_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Text Pipeline Layout"), @@ -769,6 +765,15 @@ impl State { } } + fn load_shader(device: &wgpu::Device, label: &str, text: &str) -> wgpu::ShaderModule { + let common = include_str!("util.wgsl"); + + device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some(label), + source: wgpu::ShaderSource::Wgsl([common, text].join("\n").into()), + }) + } + pub fn window(&self) -> &Window { &self.window } @@ -783,7 +788,16 @@ impl State { } fn update(&mut self) { - self.screen_uniform = ScreenUniforms::new(self.size.width, self.size.height); + let w = self.size.width as f32; + let h = self.size.height as f32; + self.screen_uniform.resolution = [w, h]; + + // How do I compute the zoom for an effective resolution? + let z_x = w / 320.0; + let z_y = h / 240.0; + let z = z_y.min(z_x); + self.screen_uniform.scale = [z, z]; + self.queue.write_buffer( &self.screen_uniform_buffer, 0, diff --git a/src/sprite_shader.wgsl b/src/sprite_shader.wgsl index cb2a9a21..c6cf1c7f 100644 --- a/src/sprite_shader.wgsl +++ b/src/sprite_shader.wgsl @@ -1,3 +1,4 @@ +// @include 'util.wgsl' // ---------------------------------------------------------------------------- // Vertex shader // ---------------------------------------------------------------------------- @@ -41,44 +42,3 @@ struct VertexOutput { let tc = vec2(u32(in.tex_coords.x), u32(in.tex_coords.y)); return textureLoad(t_diffuse, tc, 0); } - - -// ---------------------------------------------------------------------------- -// Resolution Handling -// ---------------------------------------------------------------------------- - -struct ScreenUniform { - resolution : vec2f, -}; -@group(0) @binding(0) // 1. - var screen : ScreenUniform; - -const RES = vec2f(320.0, 240.0); // The logical resolution of the screen. - -fn adjust_for_resolution(in_pos: vec2) -> vec2 { - // Adjust in_pos for the "resolution" of the screen. - let RES_AR = RES.x / RES.y; // The aspect ratio of the logical screen. - - // the actual resolution of the screen. - let screen_ar = screen.resolution.x / screen.resolution.y; - - // Compute the difference in resolution ... correctly? - // - // nudge is the amount to add to the logical resolution so that the pixels - // stay the same size but we respect the aspect ratio of the screen. (So - // there's more of them in either the x or y direction.) - var nudge = vec2f(0.0); - if (screen_ar > RES_AR) { - nudge.x = (RES.y * screen_ar) - RES.x; - } else { - nudge.y = (RES.x / screen_ar) - RES.y; - } - var new_logical_resolution = RES + nudge; - - // Now we can convert the incoming position to clip space, in the new screen. - let centered = in_pos + (nudge / 2.0); - var position = (2.0 * centered / new_logical_resolution) - 1.0; - position.y = -position.y; - - return position; -} diff --git a/src/text_shader.wgsl b/src/text_shader.wgsl index 5feb6e23..13c8e661 100644 --- a/src/text_shader.wgsl +++ b/src/text_shader.wgsl @@ -1,3 +1,4 @@ +// @include 'util.wgsl' // ---------------------------------------------------------------------------- // Vertex shader // ---------------------------------------------------------------------------- @@ -59,44 +60,3 @@ struct VertexOutput { ); //return vec4(1.0,1.0,1.0,1.0); } - - -// ---------------------------------------------------------------------------- -// Resolution Handling -// ---------------------------------------------------------------------------- - -struct ScreenUniform { - resolution : vec2f, -}; -@group(0) @binding(0) // 1. - var screen : ScreenUniform; - -const RES = vec2f(320.0, 240.0); // The logical resolution of the screen. - -fn adjust_for_resolution(in_pos: vec2) -> vec2 { - // Adjust in_pos for the "resolution" of the screen. - let RES_AR = RES.x / RES.y; // The aspect ratio of the logical screen. - - // the actual resolution of the screen. - let screen_ar = screen.resolution.x / screen.resolution.y; - - // Compute the difference in resolution ... correctly? - // - // nudge is the amount to add to the logical resolution so that the pixels - // stay the same size but we respect the aspect ratio of the screen. (So - // there's more of them in either the x or y direction.) - var nudge = vec2f(0.0); - if (screen_ar > RES_AR) { - nudge.x = (RES.y * screen_ar) - RES.x; - } else { - nudge.y = (RES.x / screen_ar) - RES.y; - } - var new_logical_resolution = RES + nudge; - - // Now we can convert the incoming position to clip space, in the new screen. - let centered = in_pos + (nudge / 2.0); - var position = (2.0 * centered / new_logical_resolution) - 1.0; - position.y = -position.y; - - return position; -} diff --git a/src/util.wgsl b/src/util.wgsl new file mode 100644 index 00000000..f5008afb --- /dev/null +++ b/src/util.wgsl @@ -0,0 +1,68 @@ +// This file contains utility functions to be used by the other shaders. +// Sorry that WGSL has no direct linking/reference/include function, +// you just kinda have to know it. + +// ---------------------------------------------------------------------------- +// Resolution Handling +// ---------------------------------------------------------------------------- + +struct ScreenUniform { + resolution : vec2f, + zoom : vec2f, +}; +@group(0) @binding(0) // 1. + var screen : ScreenUniform; + +fn adjust_for_resolution(in_pos: vec2) -> vec2 { + // The incoming positions are all in pixel space on the screen, we need to + // convert them into clip space, from (-1,-1) to (1,1). (-1,-1) is in the + // bottom-left corner. + // + // Put result in the range [0-2], where (2,2) is the bottom-right corner + // of the screen. + var result = (in_pos * screen.zoom * 2.0) / screen.resolution; + + // Put result in the range [-1,1] where [1,1] is the bottom-right corner + // of the screen. + result -= 1.0; + + // Put result in the range [-1,1] where [1,1] is the top-right corner of + // the screen. + result.y = -result.y; + + return result; +} + +/** + +const RES = vec2f(320.0, 240.0); // The logical resolution of the screen. + +fn old_adjust_for_resolution(in_pos: vec2) -> vec2 { + // Adjust in_pos for the "resolution" of the screen. + let RES_AR = RES.x / RES.y; // The aspect ratio of the logical screen. + + // the actual resolution of the screen. + let screen_ar = screen.resolution.x / screen.resolution.y; + + // Compute the difference in resolution ... correctly? + // + // nudge is the amount to add to the logical resolution so that the pixels + // stay the same size but we respect the aspect ratio of the screen. (So + // there's more of them in either the x or y direction.) + var nudge = vec2f(0.0); + if (screen_ar > RES_AR) { + nudge.x = (RES.y * screen_ar) - RES.x; + } else { + nudge.y = (RES.x / screen_ar) - RES.y; + } + var new_logical_resolution = RES + nudge; + + // Now we can convert the incoming position to clip space, in the new screen. + let centered = in_pos + (nudge / 2.0); + var position = (2.0 * centered / new_logical_resolution) - 1.0; + position.y = -position.y; + + return position; +} + +*/ \ No newline at end of file