Skip to content

Commit

Permalink
Toggleable Shaders
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacMarovitz committed Jan 30, 2024
1 parent a355b75 commit 3346797
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 56 deletions.
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use serde::{Deserialize, Serialize};
use winit::keyboard::Key;
use crate::context::Shader;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Config {
Expand All @@ -10,6 +11,7 @@ pub struct Config {
pub audio: Audio,
pub input: Input,
pub palette: Palette,
pub shader: Shader
}

impl Default for Config {
Expand Down Expand Up @@ -53,6 +55,7 @@ impl Default for Config {
},
light: Color { r: 8, g: 41, b: 85 },
},
shader: Shader::None
}
}
}
Expand Down
22 changes: 20 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
use std::sync::Arc;
use serde::{Deserialize, Serialize};
use crate::components::ppu::{SCREEN_H, SCREEN_W};
use wgpu::util::DeviceExt;
use winit::dpi::PhysicalSize;
use winit::window::Window;

#[derive(Deserialize, Serialize, Debug, Clone)]
pub enum Shader {
None,
MonoLCD,
LCD
}

impl Shader {
fn source(&self) -> &str {
match *self {
Shader::None => include_str!("shaders/none.wgsl"),
Shader::MonoLCD => include_str!("shaders/mono_lcd.wgsl"),
Shader::LCD => include_str!("shaders/lcd.wgsl")
}
}
}

#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
struct Vertex {
Expand Down Expand Up @@ -58,7 +76,7 @@ pub struct Context {
}

impl Context {
pub async fn new(window: Arc<Window>) -> Self {
pub async fn new(window: Arc<Window>, shader: Shader) -> Self {
let size = window.inner_size();

let instance = wgpu::Instance::default();
Expand Down Expand Up @@ -204,7 +222,7 @@ impl Context {

let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shader.wgsl").into()),
source: wgpu::ShaderSource::Wgsl((include_str!("shaders/shader.wgsl").to_owned() + shader.source()).into()),
});

let render_pipeline_layout =
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async fn main() -> Result<(), impl std::error::Error> {
.build(&event_loop)
.unwrap();

let context = Arc::new(Mutex::new(Context::new(Arc::new(window)).await));
let context = Arc::new(Mutex::new(Context::new(Arc::new(window), config.clone().shader).await));
let (input_tx, mut input_rx) = mpsc::unbounded_channel::<(JoypadButton, bool)>();

{
Expand Down
77 changes: 77 additions & 0 deletions src/shaders/lcd.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// =============================================================================== //
// //
// LCD Shader //
// Derived from: https://github.com/LIJI32/SameBoy/blob/master/Shaders/LCD.fsh //
// //
// =============================================================================== //

const COLOR_LOW: f32 = 0.6;
const COLOR_HIGH: f32 = 1.0;
const SCANLINE_DEPTH_2: f32 = 0.2;

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var position = in.tex_coords;

var pos = fract(position * globals.input_resolution);
var sub_pos = fract(position * globals.input_resolution * 6);

var center = textureSample(t_diffuse, s_diffuse, position, vec2(0, 0));
var left = textureSample(t_diffuse, s_diffuse, position, vec2(-1, 0));
var right = textureSample(t_diffuse, s_diffuse, position, vec2(1, 0));

if (pos.y < 1.0 / 6.0) {
center = mix(center, textureSample(t_diffuse, s_diffuse, position, vec2( 0, -1)), 0.5 - sub_pos.y / 2.0);
left = mix(left, textureSample(t_diffuse, s_diffuse, position, vec2(-1, -1)), 0.5 - sub_pos.y / 2.0);
right = mix(right, textureSample(t_diffuse, s_diffuse, position, vec2( 1, -1)), 0.5 - sub_pos.y / 2.0);
center *= sub_pos.y * SCANLINE_DEPTH_2 + (1 - SCANLINE_DEPTH_2);
left *= sub_pos.y * SCANLINE_DEPTH_2 + (1 - SCANLINE_DEPTH_2);
right *= sub_pos.y * SCANLINE_DEPTH_2 + (1 - SCANLINE_DEPTH_2);
}
else if (pos.y > 5.0 / 6.0) {
center = mix(center, textureSample(t_diffuse, s_diffuse, position, vec2( 0, 1)), sub_pos.y / 2.0);
left = mix(left, textureSample(t_diffuse, s_diffuse, position, vec2(-1, 1)), sub_pos.y / 2.0);
right = mix(right, textureSample(t_diffuse, s_diffuse, position, vec2( 1, 1)), sub_pos.y / 2.0);
center *= (1.0 - sub_pos.y) * SCANLINE_DEPTH_2 + (1 - SCANLINE_DEPTH_2);
left *= (1.0 - sub_pos.y) * SCANLINE_DEPTH_2 + (1 - SCANLINE_DEPTH_2);
right *= (1.0 - sub_pos.y) * SCANLINE_DEPTH_2 + (1 - SCANLINE_DEPTH_2);
}


var midleft = mix(left, center, 0.5);
var midright = mix(right, center, 0.5);

var ret = vec4(0.0, 0.0, 0.0, 0.0);
if (pos.x < 1.0 / 6.0) {
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1),
vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
sub_pos.x);
}
else if (pos.x < 2.0 / 6.0) {
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
sub_pos.x);
}
else if (pos.x < 3.0 / 6.0) {
ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.b, 1),
sub_pos.x);
}
else if (pos.x < 4.0 / 6.0) {
ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1),
vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * center.b, 1),
sub_pos.x);
}
else if (pos.x < 5.0 / 6.0) {
ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1),
vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
sub_pos.x);
}
else {
ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
vec4(COLOR_HIGH * right.r, COLOR_LOW * right.g , COLOR_HIGH * center.b, 1),
sub_pos.x);
}

return ret;
}
59 changes: 59 additions & 0 deletions src/shaders/mono_lcd.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// =============================================================================== //
// //
// Mono LCD Shader //
// Derived from: https://github.com/LIJI32/SameBoy/blob/master/Shaders/MonoLCD.fsh //
// //
// =============================================================================== //

const SCANLINE_DEPTH: f32 = 0.25;
const BLOOM: f32 = 0.4;

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var position = in.tex_coords;

var pixel = position * globals.input_resolution - vec2(0.5, 0.5);

var q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / globals.input_resolution);
var q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / globals.input_resolution);
var q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / globals.input_resolution);
var q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / globals.input_resolution);

var s = vec2(smoothstep(0.0, 1.0, fract(pixel.x)), smoothstep(0.0, 1.0, fract(pixel.y)));

var r1 = mix(q11, q21, s.x);
var r2 = mix(q12, q22, s.x);

var pos = fract(position * globals.input_resolution);
var sub_pos = fract(position * globals.input_resolution * 6);

var multiplier: f32 = 1.0;

if (pos.y < 1.0 / 6.0) {
multiplier *= sub_pos.y * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}
else if (pos.y > 5.0 / 6.0) {
multiplier *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}

if (pos.x < 1.0 / 6.0) {
multiplier *= sub_pos.x * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}
else if (pos.x > 5.0 / 6.0) {
multiplier *= (1.0 - sub_pos.x) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}

var pre_shadow = mix(textureSample(t_diffuse, s_diffuse, position) * multiplier, mix(r1, r2, s.y), BLOOM);
pixel += vec2(-0.6, -0.8);

q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / globals.input_resolution);
q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / globals.input_resolution);
q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / globals.input_resolution);
q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / globals.input_resolution);

r1 = mix(q11, q21, fract(pixel.x));
r2 = mix(q12, q22, fract(pixel.x));

var shadow = mix(r1, r2, fract(pixel.y));
return mix(min(shadow, pre_shadow), pre_shadow, 0.75);
}
4 changes: 4 additions & 0 deletions src/shaders/none.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
}
53 changes: 0 additions & 53 deletions src/shaders/shader.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -29,56 +29,3 @@ var t_diffuse: texture_2d<f32>;
var s_diffuse: sampler;
@group(0) @binding(2)
var<uniform> globals: Globals;

const SCANLINE_DEPTH: f32 = 0.25;
const BLOOM: f32 = 0.4;

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var position = in.tex_coords;

var pixel = position * globals.input_resolution - vec2(0.5, 0.5);

var q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / globals.input_resolution);
var q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / globals.input_resolution);
var q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / globals.input_resolution);
var q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / globals.input_resolution);

var s = vec2(smoothstep(0.0, 1.0, fract(pixel.x)), smoothstep(0.0, 1.0, fract(pixel.y)));

var r1 = mix(q11, q21, s.x);
var r2 = mix(q12, q22, s.x);

var pos = fract(position * globals.input_resolution);
var sub_pos = fract(position * globals.input_resolution * 6);

var multiplier: f32 = 1.0;

if (pos.y < 1.0 / 6.0) {
multiplier *= sub_pos.y * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}
else if (pos.y > 5.0 / 6.0) {
multiplier *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}

if (pos.x < 1.0 / 6.0) {
multiplier *= sub_pos.x * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}
else if (pos.x > 5.0 / 6.0) {
multiplier *= (1.0 - sub_pos.x) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
}

var pre_shadow = mix(textureSample(t_diffuse, s_diffuse, position) * multiplier, mix(r1, r2, s.y), BLOOM);
pixel += vec2(-0.6, -0.8);

q11 = textureSample(t_diffuse, s_diffuse, (floor(pixel) + 0.5) / globals.input_resolution);
q12 = textureSample(t_diffuse, s_diffuse, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / globals.input_resolution);
q21 = textureSample(t_diffuse, s_diffuse, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / globals.input_resolution);
q22 = textureSample(t_diffuse, s_diffuse, (ceil(pixel) + 0.5) / globals.input_resolution);

r1 = mix(q11, q21, fract(pixel.x));
r2 = mix(q12, q22, fract(pixel.x));

var shadow = mix(r1, r2, fract(pixel.y));
return mix(min(shadow, pre_shadow), pre_shadow, 0.75);
}

0 comments on commit 3346797

Please sign in to comment.