use crate::Image;
pub const MAX_IMAGE_SHADER_EXTRA_TEXTURES: usize = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ImageShaderBlendMode {
#[default]
Alpha,
Add,
Replace,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImageShaderDesc {
pub source: String,
pub uses_extra_textures: bool,
pub blend_mode: ImageShaderBlendMode,
pub internal_prelude: bool,
pub extra_texture_names: [Option<String>; 4],
pub history_slot: Option<usize>,
pub screen_slot: Option<usize>,
}
impl ImageShaderDesc {
pub fn from_wgsl(source: impl Into<String>) -> Self {
Self {
source: source.into(),
uses_extra_textures: false,
blend_mode: ImageShaderBlendMode::Alpha,
internal_prelude: false,
extra_texture_names: Default::default(),
history_slot: None,
screen_slot: None,
}
}
pub fn with_internal_prelude(mut self, enabled: bool) -> Self {
self.internal_prelude = enabled;
self
}
pub fn with_texture_alias(mut self, slot: usize, name: impl Into<String>) -> Self {
if slot < 4 {
self.extra_texture_names[slot] = Some(name.into());
}
self
}
pub fn with_history_slot(mut self, slot: usize) -> Self {
if slot < 4 {
self.history_slot = Some(slot);
}
self
}
pub fn with_screen_slot(mut self, slot: usize) -> Self {
if slot < 4 {
self.screen_slot = Some(slot);
}
self
}
pub fn with_extra_textures(mut self, enabled: bool) -> Self {
self.uses_extra_textures = enabled;
self
}
pub fn with_blend_mode(mut self, blend_mode: ImageShaderBlendMode) -> Self {
self.blend_mode = blend_mode;
self
}
pub(crate) fn uses_extra_textures(&self) -> bool {
self.uses_extra_textures
}
}
#[derive(Debug, Clone, Copy)]
pub enum ImageShaderInput {
None,
Image(Image),
Screen,
History,
}
impl Default for ImageShaderInput {
fn default() -> Self {
Self::None
}
}
impl PartialEq for ImageShaderInput {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::None, Self::None)
| (Self::Screen, Self::Screen)
| (Self::History, Self::History) => true,
(Self::Image(lhs), Self::Image(rhs)) => lhs.id() == rhs.id(),
_ => false,
}
}
}
impl Eq for ImageShaderInput {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImageShaderBindings {
pub(crate) extra_inputs: [ImageShaderInput; MAX_IMAGE_SHADER_EXTRA_TEXTURES],
pub(crate) history: bool,
pub(crate) screen: bool,
pub(crate) named_inputs: std::collections::HashMap<String, ImageShaderInput>,
}
impl Default for ImageShaderBindings {
fn default() -> Self {
Self {
extra_inputs: Default::default(),
history: false,
screen: false,
named_inputs: Default::default(),
}
}
}
impl ImageShaderBindings {
pub fn new() -> Self {
Self::default()
}
pub fn with_extra_image(mut self, slot: usize, image: Image) -> Self {
if slot < MAX_IMAGE_SHADER_EXTRA_TEXTURES {
self.extra_inputs[slot] = ImageShaderInput::Image(image);
}
self
}
pub fn with_screen_at_slot(mut self, slot: usize) -> Self {
if slot < MAX_IMAGE_SHADER_EXTRA_TEXTURES {
self.extra_inputs[slot] = ImageShaderInput::Screen;
}
self
}
pub fn with_history_at_slot(mut self, slot: usize) -> Self {
if slot < MAX_IMAGE_SHADER_EXTRA_TEXTURES {
self.extra_inputs[slot] = ImageShaderInput::History;
}
self
}
pub fn with_screen(mut self) -> Self {
self.screen = true;
self
}
pub fn with_history(mut self) -> Self {
self.history = true;
self
}
pub fn with_image(mut self, name: impl Into<String>, image: Image) -> Self {
self.named_inputs.insert(name.into(), ImageShaderInput::Image(image));
self
}
}
#[cfg(test)]
mod tests {
use super::{ImageShaderBlendMode, ImageShaderDesc};
#[test]
fn image_shader_desc_clamps_extra_texture_count() {
let desc = ImageShaderDesc::from_wgsl("shader").with_extra_textures(true);
assert!(desc.uses_extra_textures);
}
#[test]
fn image_shader_desc_defaults_match_full_wgsl_registration() {
let desc = ImageShaderDesc::from_wgsl("shader");
assert!(!desc.uses_extra_textures);
assert!(!desc.internal_prelude);
assert_eq!(desc.blend_mode, ImageShaderBlendMode::Alpha);
}
}