maia_wasm/render/
uniform.rs

1use std::cell::Cell;
2use web_sys::{WebGl2RenderingContext, WebGlProgram, WebGlUniformLocation};
3
4/// WebGL2 uniform.
5///
6/// This associates an identifier for a WebGL2 uniform with a data value that
7/// can be accessed and modified using inner mutability.
8///
9/// Usually, the type `T` would be [`Copy`].
10pub struct Uniform<T> {
11    name: String,
12    data: Cell<T>,
13}
14
15impl<T> Uniform<T> {
16    /// Creates a new WebGL2 uniform.
17    ///
18    /// The `name` corresponds to the identifier of the uniform, and `data`
19    /// gives its initial value.
20    pub fn new(name: String, data: T) -> Uniform<T> {
21        Uniform {
22            name,
23            data: Cell::new(data),
24        }
25    }
26
27    /// Returns the name (identifier) of the uniform.
28    pub fn name(&self) -> &str {
29        &self.name
30    }
31
32    /// Modifies the data of the uniform.
33    ///
34    /// This function sets the value of the uniform to `value`.
35    pub fn set_data(&self, value: T) {
36        self.data.set(value)
37    }
38}
39
40impl<T: Copy> Uniform<T> {
41    /// Returns the data of the uniform.
42    ///
43    /// This function returns a copy of the value of the uniform.
44    pub fn get_data(&self) -> T {
45        self.data.get()
46    }
47}
48
49/// Trait that abstracts WebGL2 uniforms.
50///
51/// This trait is implemented by objects that represent a WebGL2 uniform and its
52/// value, and which know how to set the value of the uniform if given a WebGL2
53/// program with such uniform.
54pub trait UniformValue {
55    /// Set the value of the uniform.
56    ///
57    /// If the `program` contains the uniform represented by `self`, this
58    /// function sets the value of the uniform to the value stored by `self`. If
59    /// the program does not contain the uniform, this function does nothing.
60    fn set_uniform(&self, gl: &WebGl2RenderingContext, program: &WebGlProgram);
61}
62
63impl<T: UniformType + Copy> UniformValue for Uniform<T> {
64    fn set_uniform(&self, gl: &WebGl2RenderingContext, program: &WebGlProgram) {
65        if let Some(location) = gl.get_uniform_location(program, self.name()) {
66            self.get_data().uniform(gl, Some(&location))
67        }
68    }
69}
70
71/// Trait that links native Rust types with WebGL2 uniform types.
72pub trait UniformType {
73    /// Sets the value of the uniform.
74    ///
75    /// This function sets the value of the WebGL2 uniform in `location` to the
76    /// value of `self` using one of the `uniform{1,2,3,4}{f,i,ui}` WebGL2
77    /// functions as appropriate.
78    fn uniform(&self, gl: &WebGl2RenderingContext, location: Option<&WebGlUniformLocation>);
79}
80
81macro_rules! impl_uniform {
82    ($t:ty, $fun:ident, $sel:ident, $($things:expr),+) => {
83        #[doc = concat!("Uniform type corresponding to `", stringify!($fun), "`.")]
84	impl UniformType for $t {
85	    fn uniform(&$sel, gl: &WebGl2RenderingContext, location: Option<&WebGlUniformLocation>) {
86		gl.$fun(location, $($things,)+)
87	    }
88	}
89    }
90}
91
92impl_uniform!(f32, uniform1f, self, *self);
93impl_uniform!(i32, uniform1i, self, *self);
94impl_uniform!(u32, uniform1ui, self, *self);
95impl_uniform!((f32, f32), uniform2f, self, self.0, self.1);
96impl_uniform!((i32, i32), uniform2i, self, self.0, self.1);
97impl_uniform!((u32, u32), uniform2ui, self, self.0, self.1);
98impl_uniform!((f32, f32, f32), uniform3f, self, self.0, self.1, self.2);
99impl_uniform!((i32, i32, i32), uniform3i, self, self.0, self.1, self.2);
100impl_uniform!((u32, u32, u32), uniform3ui, self, self.0, self.1, self.2);
101impl_uniform!(
102    (f32, f32, f32, f32),
103    uniform4f,
104    self,
105    self.0,
106    self.1,
107    self.2,
108    self.3
109);
110impl_uniform!(
111    (i32, i32, i32, i32),
112    uniform4i,
113    self,
114    self.0,
115    self.1,
116    self.2,
117    self.3
118);
119impl_uniform!(
120    (u32, u32, u32, u32),
121    uniform4ui,
122    self,
123    self.0,
124    self.1,
125    self.2,
126    self.3
127);