Skip to main content

grafix_toolbox/kit/opengl/shader/
uniform.rs

1use super::*;
2use crate::math::la;
3
4#[macro_export]
5macro_rules! Uniform {
6	($bind: ident, ($n: expr, $v: expr)) => {{
7		let id = const { $crate::GL::macro_uses::uniforms_use::id($n) };
8		$bind.tap(|b| b.Uniform(id, $v))
9	}};
10}
11
12#[macro_export]
13macro_rules! Uniforms {
14	($shd: ident, $(($n: expr, $v: expr)),+) => {{
15		let b = $shd.Bind();
16		$(let b = Uniform!(b, ($n, $v));)+
17		b
18	}};
19}
20
21pub enum ArgsKind {
22	Uniform,
23	Ubo,
24	Ssbo,
25}
26pub trait UniformArgs {
27	fn apply(&self, _: i32, _: UniCache);
28	fn kind(&self) -> ArgsKind {
29		ArgsKind::Uniform
30	}
31}
32
33macro_rules! impl_uniform {
34	($v: ident, $t: ident, $f: ident) => {
35		impl UniformArgs for $t {
36			fn apply(&self, addr: i32, cached: UniCache) {
37				let apply = || {
38					DEBUG!("Setting GL Uniform {addr} to {self:?} in shader {}", ShaderT::bound_obj());
39					let s = &[*self];
40					$v(gl::$f, addr, s);
41				};
42
43				if let Some(CachedUni::$t(v)) = cached {
44					if v != self {
45						*v = *self;
46						apply();
47					}
48				} else {
49					apply();
50					*cached = Some(CachedUni::$t(*self));
51				}
52			}
53		}
54	};
55}
56fn val<T, S>(f: unsafe fn(i32, i32, *const T), name: i32, slice: &[S]) {
57	GL!(f(name, i32(slice.len()), slice.as_ptr() as *const T));
58}
59fn mat<S>(f: unsafe fn(i32, i32, GLbool, *const f32), name: i32, slice: &[S]) {
60	GL!(f(name, i32(slice.len()), gl::FALSE, slice.as_ptr() as *const f32)); // coulmn-major
61}
62impl_uniform!(val, u32, Uniform1uiv);
63impl_uniform!(val, uVec2, Uniform2uiv);
64impl_uniform!(val, uVec3, Uniform3uiv);
65impl_uniform!(val, uVec4, Uniform4uiv);
66impl_uniform!(val, i32, Uniform1iv);
67impl_uniform!(val, iVec2, Uniform2iv);
68impl_uniform!(val, iVec3, Uniform3iv);
69impl_uniform!(val, iVec4, Uniform4iv);
70impl_uniform!(val, f32, Uniform1fv);
71impl_uniform!(val, Vec2, Uniform2fv);
72impl_uniform!(val, Vec3, Uniform3fv);
73impl_uniform!(val, Vec4, Uniform4fv);
74impl_uniform!(mat, Mat2, UniformMatrix2fv);
75impl_uniform!(mat, Mat3, UniformMatrix3fv);
76impl_uniform!(mat, Mat4, UniformMatrix4fv);
77impl_uniform!(mat, Mat2x3, UniformMatrix2x3fv);
78impl_uniform!(mat, Mat3x2, UniformMatrix3x2fv);
79impl_uniform!(mat, Mat2x4, UniformMatrix2x4fv);
80impl_uniform!(mat, Mat4x2, UniformMatrix4x2fv);
81impl_uniform!(mat, Mat3x4, UniformMatrix3x4fv);
82impl_uniform!(mat, Mat4x3, UniformMatrix4x3fv);
83
84macro_rules! impl_la_adapter {
85	($t: ident, $lat: ident) => {
86		impl UniformArgs for la::$lat {
87			fn apply(&self, addr: i32, cached: UniCache) {
88				$t(*self).apply(addr, cached)
89			}
90		}
91		impl UniformArgs for &la::$lat {
92			fn apply(&self, addr: i32, cached: UniCache) {
93				(*self).apply(addr, cached)
94			}
95		}
96	};
97}
98impl_la_adapter!(Vec2, V2);
99impl_la_adapter!(Vec3, V3);
100impl_la_adapter!(Vec4, V4);
101impl_la_adapter!(Mat3, M3);
102impl_la_adapter!(Mat4, M4);
103
104impl<T: TexType> UniformArgs for GL::TextureBind<'_, T> {
105	fn apply(&self, addr: i32, cached: UniCache) {
106		let u = i32(self.u);
107		let apply = || {
108			DEBUG!("Binding GL texture {addr} to unit {u} in shader {}", ShaderT::bound_obj());
109			GL!(gl::Uniform1i(addr, u));
110		};
111
112		if let Some(CachedUni::TexUnit(unit)) = cached {
113			if *unit != u {
114				DEBUG!("GL texture {addr} was bound to unit {unit}");
115				apply();
116				*unit = u;
117			}
118		} else {
119			apply();
120			*cached = CachedUni::TexUnit(u).pipe(Some);
121		}
122	}
123}
124
125impl UniformArgs for GL::ShdArrBind<'_, Uniform> {
126	fn apply(&self, addr: i32, cached: UniCache) {
127		let l = i32(self.l);
128		let apply = || {
129			let prog = *ShaderT::bound_obj();
130			let addr = -2 - addr;
131			DEBUG!("Binding GL UBO {addr} to location {l} in shader {prog}");
132			GL!(gl::UniformBlockBinding(prog, u32(addr), u32(l)));
133		};
134
135		if let Some(CachedUni::UboLoc(loc)) = cached {
136			if *loc != l {
137				DEBUG!("GL UBO {addr} was bound to location {loc}");
138				apply();
139				*loc = l;
140			}
141		} else {
142			apply();
143			*cached = CachedUni::UboLoc(l).pipe(Some);
144		}
145	}
146	fn kind(&self) -> ArgsKind {
147		ArgsKind::Ubo
148	}
149}
150
151impl UniformArgs for GL::ShdArrBind<'_, ShdStorage> {
152	fn apply(&self, _: i32, _: UniCache) {
153		unreachable!()
154	}
155	fn kind(&self) -> ArgsKind {
156		ArgsKind::Ssbo
157	}
158}
159
160pub mod uniforms_use {
161	pub const fn id(s: &str) -> (u32, &str) {
162		(super::chksum::const_fnv1(s.as_bytes()), s)
163	}
164}
165
166pub type UniCache<'a> = &'a mut Option<CachedUni>;
167
168#[derive(Debug)]
169pub enum CachedUni {
170	u32(u32),
171	uVec2(uVec2),
172	uVec3(uVec3),
173	uVec4(uVec4),
174	i32(i32),
175	iVec2(iVec2),
176	iVec3(iVec3),
177	iVec4(iVec4),
178	f32(f32),
179	Vec2(Vec2),
180	Vec3(Vec3),
181	Vec4(Vec4),
182	Mat2(Mat2),
183	Mat3(Mat3),
184	Mat4(Mat4),
185	Mat2x3(Mat2x3),
186	Mat3x2(Mat3x2),
187	Mat2x4(Mat2x4),
188	Mat4x2(Mat4x2),
189	Mat3x4(Mat3x4),
190	Mat4x3(Mat4x3),
191	TexUnit(i32),
192	UboLoc(i32),
193}