Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/invaders/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,16 @@ fn main() -> Result<(), Error> {
Arc::new(window)
};

let pixels = {
let mut pixels = {
let window_size = window.inner_size();
let surface_texture =
SurfaceTexture::new(window_size.width, window_size.height, Arc::clone(&window));
Pixels::new(WIDTH as u32, HEIGHT as u32, surface_texture)?
};

// Use the fill scaling mode which supports non-integer scaling.
pixels.set_scaling_mode(pixels::ScalingMode::Fill);

let game = Game::new(pixels, debug);

let res = game_loop(
Expand Down
1 change: 1 addition & 0 deletions shaders/scale.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ struct VertexOutput {

struct Locals {
transform: mat4x4<f32>,
input_size: vec4<f32>
}
@group(0) @binding(2) var<uniform> r_locals: Locals;

Expand Down
40 changes: 40 additions & 0 deletions shaders/scale_fill.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Vertex shader bindings

struct VertexOutput {
@location(0) tex_coord: vec2<f32>,
@builtin(position) position: vec4<f32>,
}

struct Locals {
transform: mat4x4<f32>,
input_size: vec4<f32>
}
@group(0) @binding(2) var<uniform> r_locals: Locals;

@vertex
fn vs_main(
@location(0) position: vec2<f32>,
) -> VertexOutput {
var out: VertexOutput;
// Output tex coord in texel coordinates (0..width, 0..height)
out.tex_coord = fma(position, vec2<f32>(0.5, -0.5), vec2<f32>(0.5, 0.5)) * r_locals.input_size.xy;
out.position = r_locals.transform * vec4<f32>(position, 0.0, 1.0);
return out;
}

// Fragment shader bindings

@group(0) @binding(0) var r_tex_color: texture_2d<f32>;
@group(0) @binding(1) var r_tex_sampler: sampler;

@fragment
fn fs_main(@location(0) tex_coord: vec2<f32>) -> @location(0) vec4<f32> {
let half = vec2<f32>(0.5);
let one = vec2<f32>(1.0);
let zero = vec2<f32>(0.0);
let texels_per_pixel = vec2<f32>(dpdx(tex_coord.x), dpdy(tex_coord.y));
let tex_coord_fract = fract(tex_coord);
let tex_coord_x = clamp(tex_coord_fract / texels_per_pixel, zero, half) + clamp((tex_coord_fract - one) / texels_per_pixel + half, zero, half);
let tex_coord_final = (floor(tex_coord) + tex_coord_x) * r_locals.input_size.zw;
return textureSample(r_tex_color, r_tex_sampler, tex_coord_final);
}
7 changes: 6 additions & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::renderers::{ScalingMatrix, ScalingRenderer};
use crate::{Error, Pixels, PixelsContext, SurfaceSize, SurfaceTexture, TextureError};
use crate::{Error, Pixels, PixelsContext, ScalingMode, SurfaceSize, SurfaceTexture, TextureError};

/// A builder to help create customized pixel buffers.
pub struct PixelsBuilder<'req, 'dev, 'win, W: wgpu::WindowHandle + 'win> {
Expand Down Expand Up @@ -309,6 +309,7 @@ impl<'req, 'dev, 'win, W: wgpu::WindowHandle + 'win> PixelsBuilder<'req, 'dev, '
let surface_size = self.surface_texture.size;
let clear_color = self.clear_color;
let blend_state = self.blend_state;
let scaling_mode = ScalingMode::PixelPerfect;
let (scaling_matrix_inverse, texture_extent, texture, scaling_renderer, pixels_buffer_size) =
create_backing_texture(
&device,
Expand All @@ -322,6 +323,7 @@ impl<'req, 'dev, 'win, W: wgpu::WindowHandle + 'win> PixelsBuilder<'req, 'dev, '
// Clear color and blending values
clear_color,
blend_state,
scaling_mode,
)?;

// Create the pixel buffer
Expand Down Expand Up @@ -432,6 +434,7 @@ pub(crate) fn create_backing_texture(
render_texture_format: wgpu::TextureFormat,
clear_color: wgpu::Color,
blend_state: wgpu::BlendState,
scaling_mode: ScalingMode,
) -> Result<
(
ultraviolet::Mat4,
Expand All @@ -447,6 +450,7 @@ pub(crate) fn create_backing_texture(
let scaling_matrix_inverse = ScalingMatrix::new(
(width as f32, height as f32),
(surface_size.width as f32, surface_size.height as f32),
scaling_mode,
)
.transform
.inversed();
Expand Down Expand Up @@ -477,6 +481,7 @@ pub(crate) fn create_backing_texture(
render_texture_format,
clear_color,
blend_state,
scaling_mode,
);

let texture_format_size = texture_format_size(backing_texture_format);
Expand Down
29 changes: 29 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ struct SurfaceSize {
height: u32,
}

/// The scaling mode controls the scaling behavior of [`renderers::ScalingRenderer`].
#[derive(Debug, Copy, Clone)]
pub enum ScalingMode {
/// The buffer is scaled up, if needed, to the nearest integer multiple of the buffer size.
PixelPerfect,
/// Fill the screen while preserving aspect ratio. The renderer effectively scales the buffer
/// to the nearest integer multiple first, then linearly interpolates to fit.
Fill,
}

/// Provides the internal state for custom shaders.
///
/// A reference to this struct is given to the `render_function` closure when using
Expand Down Expand Up @@ -295,6 +305,23 @@ impl<'win> Pixels<'win> {
self.context.scaling_renderer.clear_color = color;
}

/// Set the scaling mode.
///
/// Controls how the pixel buffer is scaled to the screen.
///
/// ```no_run
/// # use pixels::{Pixels, ScalingMode};
/// # let window = pixels_mocks::Window;
/// # let surface_texture = pixels::SurfaceTexture::new(1920, 1080, &window);
/// let mut pixels = Pixels::new(640, 480, surface_texture)?;
/// // Scale the buffer up to fill the screen while preserving aspect ratio.
/// pixels.set_scaling_mode(ScalingMode::Fill);
/// # Ok::<(), pixels::Error>(())
/// ```
pub fn set_scaling_mode(&mut self, scaling_mode: ScalingMode) {
self.context.scaling_renderer.scaling_mode = scaling_mode;
}

/// Returns a reference of the `wgpu` adapter used by the crate.
///
/// The adapter can be used to retrieve runtime information about the host system
Expand Down Expand Up @@ -343,6 +370,7 @@ impl<'win> Pixels<'win> {
self.render_texture_format,
self.context.scaling_renderer.clear_color,
self.blend_state,
self.context.scaling_renderer.scaling_mode,
)?;

self.scaling_matrix_inverse = scaling_matrix_inverse;
Expand Down Expand Up @@ -387,6 +415,7 @@ impl<'win> Pixels<'win> {
self.context.texture_extent.height as f32,
),
(width as f32, height as f32),
self.context.scaling_renderer.scaling_mode,
)
.transform
.inversed();
Expand Down
Loading
Loading