aframe/
shader.rs

1//! Module to provide tools for shader registration as well as built-in shader 
2//! constants.
3
4pub const PORTAL: &'static str = "portal";
5pub const FLAT: &'static str = "flat";
6pub const STANDARD: &'static str = "standard";
7pub const SDF: &'static str = "sdf";
8pub const MSDF: &'static str = "msdf";
9
10use crate::sys::registerShader;
11use crate::utils::*;
12use std::{borrow::Cow, collections::HashMap};
13use serde::{Serialize, Serializer};
14
15/// Provides all the tools necessary to define an Aframe shader. 
16/// The [maplit](https://docs.rs/maplit/1.0.2/maplit/) crate is recommended 
17/// for simplifying shader definitions. See below:
18/// ```ignore
19/// use maplit::*;
20/// use aframe::shader::*;
21///
22/// pub const SIMPLE_VS: &str = include_str!("./SOME_PATH/glsl/simple.vs");
23/// pub const STROBE_FS: &str = include_str!("./SOME_PATH/glsl/strobe.fs");
24///
25/// Shader::new
26/// (
27///     hashmap!
28///     {
29///         "speedMult".into() => ShaderProperty::number(IsUniform::Yes, 1.0.into()),
30///         "alpha".into() => ShaderProperty::number(IsUniform::Yes, 1.0.into()),
31///         "alpha2".into() => ShaderProperty::number(IsUniform::Yes, 1.0.into()),
32///         "color".into() => ShaderProperty::color(IsUniform::Yes, color::BLACK.into()),
33///         "color2".into() => ShaderProperty::color(IsUniform::Yes, color::WHITE.into()),
34///         "iTime".into() => ShaderProperty::time(IsUniform::Yes, None)
35///     }, 
36///     SIMPLE_VS.into(),
37///     STROBE_FS.into()
38///     // Calling `register` will send this data to the AFRAME.registerShader function.
39/// ).register("strobe")?;
40/// ```
41#[derive(Serialize)]
42pub struct Shader<'a, 'b, 'c>
43{
44    pub schema: HashMap<Cow<'a, str>, ShaderProperty>,
45    #[serde(rename = "vertexShader")] 
46    pub vertex_shader: Cow<'b, str>,
47    #[serde(rename = "fragmentShader")] 
48    pub fragment_shader: Cow<'c, str>
49}
50
51impl<'a, 'b, 'c> Shader<'a, 'b, 'c>
52{
53    /// Define a new shader.
54    pub fn new
55    (
56        schema: HashMap<Cow<'a, str>, ShaderProperty>, 
57        vertex_shader: Cow<'b, str>, 
58        fragment_shader: Cow<'c, str>
59    ) -> Self
60    {
61        Shader { schema, vertex_shader, fragment_shader }
62    }
63
64    /// Register a shader in aframe. Warning: Aframe must be initialized before this is called.
65    pub unsafe fn register(&self, name: &str) -> Result<(), serde_wasm_bindgen::Error>
66    {
67        registerShader(name, serde_wasm_bindgen::to_value(self)?);
68        Ok(())
69    }
70}
71
72/// A property for a shader. This includes the shader type, whether or not this 
73/// property is a uniform, and an optional default value.
74#[derive(Serialize)]
75pub struct ShaderProperty
76{
77    #[serde(rename = "type")] 
78    pub shader_type: &'static str,
79    #[serde(skip_serializing_if = "IsUniform::not_uniform")]
80    pub is: IsUniform,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub default: Option<DefaultVal>
83}
84
85impl ShaderProperty
86{
87    pub fn color(is: IsUniform, default: Option<color::Rgb>) -> Self
88    {
89        ShaderProperty{ shader_type: "color", is, default: default.map(color::Rgb::into).map(DefaultVal::Str) }
90    }
91
92    pub fn array(is: IsUniform, default: Option<Vector3>) -> Self
93    {
94        ShaderProperty{ shader_type: "array", is, default: default.map(DefaultVal::Vec3) }
95    }
96
97    pub fn int(is: IsUniform, default: Option<i64>) -> Self
98    {
99        ShaderProperty{ shader_type: "int", is, default: default.map(DefaultVal::Int) }
100    }
101
102    pub fn number(is: IsUniform, default: Option<f64>) -> Self
103    {
104        ShaderProperty{ shader_type: "number", is, default: default.map(DefaultVal::Number) }
105    }
106
107    pub fn map(is: IsUniform, default: Option<Cow<'static, str>>) -> Self
108    {
109        ShaderProperty{ shader_type: "map", is, default: default.map(DefaultVal::Str) }
110    }
111
112    pub fn time(is: IsUniform, default: Option<f64>) -> Self
113    {
114        ShaderProperty{ shader_type: "time", is, default: default.map(DefaultVal::Number) }
115    }
116
117    pub fn vec2(is: IsUniform, default: Option<Vector2>) -> Self
118    {
119        ShaderProperty{ shader_type: "vec2", is, default: default.map(DefaultVal::Vec2) }
120    }
121
122    pub fn vec3(is: IsUniform, default: Option<Vector3>) -> Self
123    {
124        ShaderProperty{ shader_type: "vec3", is, default: default.map(DefaultVal::Vec3) }
125    }
126
127    pub fn vec4(is: IsUniform, default: Option<Vector4>) -> Self
128    {
129        ShaderProperty{ shader_type: "vec4", is, default: default.map(DefaultVal::Vec4) }
130    }
131}
132
133/// Wrapper for possible uniform default values
134pub enum DefaultVal
135{
136    Str(Cow<'static, str>),
137    Number(f64),
138    Int(i64),
139    Vec2(Vector2),
140    Vec3(Vector3),
141    Vec4(Vector4),
142}
143
144impl Serialize for DefaultVal
145{
146    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
147    {
148        match self
149        {
150            Self::Str(s) => s.serialize(serializer),
151            Self::Number(n) => n.serialize(serializer),
152            Self::Int(n) => n.serialize(serializer),
153            Self::Vec2(vec) => vec.serialize(serializer),
154            Self::Vec3(vec) => vec.serialize(serializer),
155            Self::Vec4(vec) => vec.serialize(serializer)
156        }
157    }
158}
159
160/// Enum to make asking whether or not a property is a uniform more readable.
161pub enum IsUniform
162{
163    Yes, No
164}
165impl IsUniform
166{
167    fn not_uniform(&self) -> bool
168    {
169        matches!(self, Self::No)
170    }
171}
172impl Serialize for IsUniform
173{
174    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
175    {
176        match self
177        {
178            Self::Yes => "uniform".serialize(serializer),
179            Self::No => "".serialize(serializer)
180        }
181    }
182}