use crate::{Color, ImageHandle};
use std::path::PathBuf;
#[derive(Clone, Debug, PartialEq)]
pub struct Shader {
pub source: ShaderSource,
pub params: Vec<ShaderParam>,
}
impl Shader {
pub fn fromFile(path: impl Into<PathBuf>) -> Self {
Self {
source: ShaderSource::File(path.into()),
params: Vec::new(),
}
}
pub fn fromCode(code: impl Into<String>) -> Self {
Self {
source: ShaderSource::Code(code.into()),
params: Vec::new(),
}
}
pub fn param(mut self, name: impl Into<String>, value: impl IntoShaderValue) -> Self {
self.params.push(ShaderParam {
name: name.into(),
value: value.intoShaderValue(),
});
self
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ShaderSource {
File(PathBuf),
Code(String),
}
#[derive(Clone, Debug, PartialEq)]
pub struct ShaderParam {
pub name: String,
pub value: ShaderValue,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ShaderValue {
Bool(bool),
Int(i64),
Float(f64),
Vector2(f32, f32),
Color(Color),
Texture(ImageHandle),
}
pub trait IntoShaderValue {
fn intoShaderValue(self) -> ShaderValue;
}
impl IntoShaderValue for bool {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Bool(self)
}
}
impl IntoShaderValue for i64 {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Int(self)
}
}
impl IntoShaderValue for i32 {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Int(self as i64)
}
}
impl IntoShaderValue for u32 {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Int(self as i64)
}
}
impl IntoShaderValue for f64 {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Float(self)
}
}
impl IntoShaderValue for f32 {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Float(self as f64)
}
}
impl IntoShaderValue for Color {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Color(self)
}
}
impl IntoShaderValue for ImageHandle {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Texture(self)
}
}
impl IntoShaderValue for &ImageHandle {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Texture(self.clone())
}
}
impl IntoShaderValue for (f32, f32) {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Vector2(self.0, self.1)
}
}
impl IntoShaderValue for (f64, f64) {
fn intoShaderValue(self) -> ShaderValue {
ShaderValue::Vector2(self.0 as f32, self.1 as f32)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shaderStoresParamsInOrder() {
let shader = Shader::fromCode("shader_type canvas_item;")
.param("opacity", 0.8)
.param("enabled", true);
assert_eq!(shader.params.len(), 2);
assert_eq!(shader.params[0].name, "opacity");
assert_eq!(shader.params[1].name, "enabled");
}
}