use askama::Template;
use crate::{
render_passes::material_opaque::shader::cache_key::{
ShaderCacheKeyMaterialOpaque, ShaderCacheKeyMaterialOpaqueEmpty,
},
shaders::{AwsmShaderError, Result},
};
#[derive(Debug)]
pub struct ShaderTemplateMaterialOpaque {
pub bind_groups: ShaderTemplateMaterialOpaqueBindGroups,
pub compute: ShaderTemplateMaterialOpaqueCompute,
}
#[derive(Template, Debug)]
#[template(
path = "material_opaque_wgsl/bind_groups.wgsl",
whitespace = "minimize"
)]
pub struct ShaderTemplateMaterialOpaqueBindGroups {
pub texture_pool_arrays_len: u32,
pub texture_pool_samplers_len: u32,
pub debug: ShaderTemplateMaterialOpaqueDebug,
pub mipmap: MipmapMode,
pub multisampled_geometry: bool,
pub msaa_sample_count: u32, }
#[derive(Template, Debug)]
#[template(path = "material_opaque_wgsl/compute.wgsl", whitespace = "minimize")]
pub struct ShaderTemplateMaterialOpaqueCompute {
pub texture_pool_arrays_len: u32,
pub texture_pool_samplers_len: u32,
pub debug: ShaderTemplateMaterialOpaqueDebug,
pub mipmap: MipmapMode,
pub multisampled_geometry: bool,
pub msaa_sample_count: u32, }
impl ShaderTemplateMaterialOpaqueCompute {
pub fn has_lighting_ibl(&self) -> bool {
match self.debug.lighting {
ShaderTemplateMaterialOpaqueDebugLighting::None => true,
ShaderTemplateMaterialOpaqueDebugLighting::IblOnly => true,
ShaderTemplateMaterialOpaqueDebugLighting::PunctualOnly => false,
}
}
pub fn has_lighting_punctual(&self) -> bool {
match self.debug.lighting {
ShaderTemplateMaterialOpaqueDebugLighting::None => true,
ShaderTemplateMaterialOpaqueDebugLighting::IblOnly => false,
ShaderTemplateMaterialOpaqueDebugLighting::PunctualOnly => true,
}
}
}
impl TryFrom<&ShaderCacheKeyMaterialOpaque> for ShaderTemplateMaterialOpaque {
type Error = AwsmShaderError;
fn try_from(value: &ShaderCacheKeyMaterialOpaque) -> Result<Self> {
let texture_pool_arrays_len = value.texture_pool_arrays_len;
let texture_pool_samplers_len = value.texture_pool_samplers_len;
let mipmap = if value.mipmaps {
MipmapMode::Gradient
} else {
MipmapMode::None
};
let multisampled_geometry = value.msaa_sample_count.is_some();
let msaa_sample_count = value.msaa_sample_count.unwrap_or_default();
let debug = ShaderTemplateMaterialOpaqueDebug::new();
let _self = Self {
bind_groups: ShaderTemplateMaterialOpaqueBindGroups {
texture_pool_arrays_len,
texture_pool_samplers_len,
mipmap,
multisampled_geometry,
msaa_sample_count,
debug,
},
compute: ShaderTemplateMaterialOpaqueCompute {
texture_pool_arrays_len,
texture_pool_samplers_len,
mipmap,
multisampled_geometry,
msaa_sample_count,
debug,
},
};
Ok(_self)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MipmapMode {
None,
Gradient,
}
impl MipmapMode {
pub fn suffix(&self) -> &'static str {
match self {
MipmapMode::Gradient => "_grad",
MipmapMode::None => "_no_mips",
}
}
pub fn sample_fn(&self) -> &'static str {
match self {
MipmapMode::Gradient => "texture_pool_sample_grad",
MipmapMode::None => "texture_pool_sample_no_mips",
}
}
pub fn is_gradient(&self) -> bool {
matches!(self, MipmapMode::Gradient)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct ShaderTemplateMaterialOpaqueDebug {
mips: bool,
n_dot_v: bool,
normals: bool,
base_color: bool,
view_direction: bool,
irradiance_sample: bool,
msaa_detect_edges: bool,
lighting: ShaderTemplateMaterialOpaqueDebugLighting,
}
impl ShaderTemplateMaterialOpaqueDebug {
pub fn new() -> Self {
Self { ..Self::default() }
}
pub fn any(&self) -> bool {
self.mips
|| self.n_dot_v
|| self.normals
|| self.base_color
|| self.view_direction
|| self.irradiance_sample
|| self.msaa_detect_edges
|| !matches!(
self.lighting,
ShaderTemplateMaterialOpaqueDebugLighting::None
)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub enum ShaderTemplateMaterialOpaqueDebugLighting {
#[default]
None,
IblOnly,
PunctualOnly,
}
impl ShaderTemplateMaterialOpaque {
pub fn into_source(self) -> Result<String> {
let bind_groups_source = self.bind_groups.render()?;
let compute_source = self.compute.render()?;
let source = format!("{}\n{}", bind_groups_source, compute_source);
Ok(source)
}
#[cfg(debug_assertions)]
pub fn debug_label(&self) -> Option<&str> {
Some("Material Opaque")
}
}
impl TryFrom<&ShaderCacheKeyMaterialOpaqueEmpty> for ShaderTemplateMaterialOpaqueEmpty {
type Error = AwsmShaderError;
fn try_from(value: &ShaderCacheKeyMaterialOpaqueEmpty) -> Result<Self> {
Ok(Self {
texture_pool_arrays_len: value.texture_pool_arrays_len,
texture_pool_samplers_len: value.texture_pool_samplers_len,
multisampled_geometry: value.msaa_sample_count.is_some(),
unlit: true,
})
}
}
#[derive(Template, Debug)]
#[template(path = "material_opaque_wgsl/empty.wgsl", whitespace = "minimize")]
pub struct ShaderTemplateMaterialOpaqueEmpty {
pub texture_pool_arrays_len: u32,
pub texture_pool_samplers_len: u32,
pub multisampled_geometry: bool,
pub unlit: bool,
}
impl ShaderTemplateMaterialOpaqueEmpty {
pub fn into_source(self) -> Result<String> {
let source = self.render()?;
Ok(source)
}
#[cfg(debug_assertions)]
pub fn debug_label(&self) -> Option<&str> {
Some("Material Opaque Empty")
}
pub fn has_lighting_ibl(&self) -> bool {
false
}
pub fn has_lighting_punctual(&self) -> bool {
false
}
}