use crate::{Gpu, InstanceData, Vertex};
use std::borrow::Cow;
pub use wgpu::{BlendComponent, BlendFactor, BlendOperation, BlendState, ColorWrites};
pub struct ShaderConfig<'a> {
pub fragment_source: &'a str,
pub shader_fields: &'a [ShaderField],
pub msaa: bool,
pub blend: BlendState,
pub write_mask: ColorWrites,
pub render_to_surface: bool,
}
impl Default for ShaderConfig<'static> {
fn default() -> Self {
Self {
fragment_source: "",
shader_fields: &[],
msaa: true,
blend: BlendState::ALPHA_BLENDING,
write_mask: ColorWrites::ALL,
render_to_surface: false,
}
}
}
pub enum ShaderField {
Sprite,
Uniform,
SpriteSheet,
}
pub struct Shader {
pipeline: wgpu::RenderPipeline,
msaa: bool,
}
impl Shader {
pub const VERTEX: &'static str = include_str!("../../res/shader/vertex.wgsl");
pub const SPRITE: &'static str = include_str!("../../res/shader/sprite.wgsl");
pub const SPRITE_SHEET: &'static str = include_str!("../../res/shader/sprite_sheet.wgsl");
pub const SPRITE_SHEET_UNIFORM: &'static str =
include_str!("../../res/shader/sprite_sheet_uniform.wgsl");
pub const RAINBOW: &'static str = include_str!("../../res/shader/rainbow.wgsl");
pub const GREY: &'static str = include_str!("../../res/shader/grey.wgsl");
pub const BLURR: &'static str = include_str!("../../res/shader/blurr.wgsl");
pub fn new(gpu: &Gpu, config: ShaderConfig) -> Self {
let mut layouts: Vec<&wgpu::BindGroupLayout> = vec![&gpu.base.camera_layout];
for link in config.shader_fields.iter() {
match link {
ShaderField::Uniform => {
layouts.push(&gpu.base.uniform_layout);
}
ShaderField::Sprite => {
layouts.push(&gpu.base.sprite_layout);
}
ShaderField::SpriteSheet => {
layouts.push(&gpu.base.sprite_sheet_layout);
}
}
}
let fragment_shader = gpu
.device
.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(config.fragment_source)),
});
let render_pipeline_layout =
gpu.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &layouts[..],
push_constant_ranges: &[],
});
let buffers = vec![Vertex::desc(), InstanceData::desc()];
let pipeline = gpu
.device
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &gpu.base.vertex_shader,
entry_point: "main",
buffers: &buffers[..],
},
fragment: Some(wgpu::FragmentState {
module: &fragment_shader,
entry_point: "main",
targets: &[Some(wgpu::ColorTargetState {
format: if config.render_to_surface {
gpu.config.format
} else {
wgpu::TextureFormat::Rgba8UnormSrgb
},
blend: Some(config.blend),
write_mask: config.write_mask,
})],
}),
primitive: 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,
},
depth_stencil: None,
multisample: if config.msaa {
gpu.base.multisample
} else {
gpu.base.no_multisample
},
multiview: None,
});
Shader {
pipeline,
msaa: config.msaa,
}
}
pub fn pipeline(&self) -> &wgpu::RenderPipeline {
&self.pipeline
}
pub fn msaa(&self) -> bool {
self.msaa
}
}