#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AlphaMode {
Opaque,
Mask(f32),
Blend,
}
impl AlphaMode {
#[inline]
pub const fn pipeline_alpha(self) -> PipelineAlphaMode {
match self {
Self::Opaque => PipelineAlphaMode::Opaque,
Self::Mask(_) => PipelineAlphaMode::Mask,
Self::Blend => PipelineAlphaMode::Blend,
}
}
#[inline]
pub const fn is_transparent(self) -> bool {
matches!(self, Self::Blend)
}
#[inline]
pub const fn cutoff(self) -> Option<f32> {
match self {
Self::Mask(cutoff) => Some(cutoff),
Self::Opaque | Self::Blend => None,
}
}
}
impl Default for AlphaMode {
#[inline]
fn default() -> Self {
Self::Opaque
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PipelineAlphaMode {
#[default]
Opaque,
Mask,
Blend,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ShaderKind {
#[default]
Pbr,
Physical,
Unlit,
Lambert,
Toon,
Normal,
Wireframe,
Depth,
Line,
Points,
Custom(u64),
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PipelineKey {
pub shader: ShaderKind,
pub alpha: PipelineAlphaMode,
pub feature_bits: u64,
}
impl PipelineKey {
#[inline]
pub const fn new(shader: ShaderKind, alpha: PipelineAlphaMode, feature_bits: u64) -> Self {
Self {
shader,
alpha,
feature_bits,
}
}
#[inline]
pub const fn with_feature(mut self, feature: u64) -> Self {
self.feature_bits |= feature;
self
}
#[inline]
pub const fn has_feature(self, feature: u64) -> bool {
self.feature_bits & feature != 0
}
}
pub const FEATURE_DOUBLE_SIDED: u64 = 1 << 0;
pub const FEATURE_ALBEDO_TEXTURE: u64 = 1 << 1;
pub const FEATURE_METALLIC_ROUGHNESS_TEXTURE: u64 = 1 << 2;
pub const FEATURE_NORMAL_TEXTURE: u64 = 1 << 3;
pub const FEATURE_OCCLUSION_TEXTURE: u64 = 1 << 4;
pub const FEATURE_EMISSIVE_TEXTURE: u64 = 1 << 5;
pub const FEATURE_GRADIENT_TEXTURE: u64 = 1 << 6;
pub const FEATURE_CLEARCOAT: u64 = 1 << 7;
pub const FEATURE_SHEEN: u64 = 1 << 8;
pub const FEATURE_TRANSMISSION: u64 = 1 << 9;
pub const FEATURE_IRIDESCENCE: u64 = 1 << 10;
pub const FEATURE_FLAT_SHADING: u64 = 1 << 11;
pub const FEATURE_WORLD_SPACE: u64 = 1 << 12;
pub const FEATURE_WIREFRAME: u64 = 1 << 13;
pub const FEATURE_DASHED: u64 = 1 << 14;
pub const FEATURE_SIZE_ATTENUATION: u64 = 1 << 15;
pub const FEATURE_CUSTOM_TEXTURES: u64 = 1 << 16;
pub const FEATURE_VERTEX_COLORS: u64 = 1 << 17;
pub const FEATURE_OUTLINE: u64 = 1 << 18;
pub trait Material: Send + Sync + 'static {
fn pipeline_key(&self) -> PipelineKey;
fn is_transparent(&self) -> bool;
fn double_sided(&self) -> bool;
fn alpha_cutoff(&self) -> Option<f32>;
}
#[inline]
pub(crate) const fn double_sided_bit(double_sided: bool) -> u64 {
if double_sided {
FEATURE_DOUBLE_SIDED
} else {
0
}
}
#[inline]
pub(crate) const fn option_texture_bit<T>(texture: &Option<T>, feature: u64) -> u64 {
if texture.is_some() { feature } else { 0 }
}
#[inline]
pub(crate) fn stable_shader_id(vertex_wgsl: &str, fragment_wgsl: &str) -> u64 {
const OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
const PRIME: u64 = 0x0000_0100_0000_01b3;
let mut hash = OFFSET;
for byte in vertex_wgsl.as_bytes() {
hash ^= *byte as u64;
hash = hash.wrapping_mul(PRIME);
}
hash ^= 0xff;
hash = hash.wrapping_mul(PRIME);
for byte in fragment_wgsl.as_bytes() {
hash ^= *byte as u64;
hash = hash.wrapping_mul(PRIME);
}
hash
}