1use std::ops::Range;
5
6use crate::math::{FVec4, IVec, Matrix4};
7use crate::{Frame, shader};
8
9#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
11pub struct Index(u8);
12
13impl Index {
14 pub fn inner(&self) -> u8 {
15 self.0
16 }
17}
18
19impl From<u8> for Index {
20 fn from(value: u8) -> Self {
21 Self(value)
22 }
23}
24
25impl From<Index> for i32 {
26 fn from(value: Index) -> Self {
27 value.0.into()
28 }
29}
30
31#[non_exhaustive]
33#[derive(Debug, PartialEq, Clone, Copy)]
34pub enum Uniform<'a> {
35 #[doc(alias = "C3D_FVUnifSet")]
37 Float(FVec4),
38 #[doc(alias = "C3D_FVUnifMtx2x4")]
40 Float2([FVec4; 2]),
41 #[doc(alias = "C3D_FVUnifMtx3x4")]
43 Float3([FVec4; 3]),
44 #[doc(alias = "C3D_FVUnifMtx4x4")]
46 Float4(Matrix4),
47 FloatArray(&'a [FVec4]),
49 Float4Array(&'a [Matrix4]),
51 #[doc(alias = "C3D_BoolUnifSet")]
53 Bool(bool),
54 #[doc(alias = "C3D_IVUnifSet")]
56 Int(IVec),
57
58 #[cfg(feature = "glam")]
59 GlamFloatArray(&'a [glam::Vec4]),
60 #[cfg(feature = "glam")]
61 GlamMatrixArray(&'a [glam::Mat4]),
62}
63impl Uniform<'_> {
64 pub fn index_range(&self) -> Range<Index> {
66 match self {
69 Self::Float(_)
70 | Self::Float2(_)
71 | Self::Float3(_)
72 | Self::Float4(_)
73 | Self::FloatArray(_)
74 | Self::Float4Array(_) => Index(0)..Index(0x60),
75 Self::Int(_) => Index(0x60)..Index(0x64),
76 Self::Bool(_) => Index(0x68)..Index(0x79),
78
79 #[cfg(feature = "glam")]
80 Self::GlamFloatArray(_) | Self::GlamMatrixArray(_) => Index(0)..Index(0x60),
81 }
82 }
83 #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize {
86 match self {
87 Self::Float(_) => 1,
88 Self::Float2(_) => 2,
89 Self::Float3(_) => 3,
90 Self::Float4(_) => 4,
91 Self::FloatArray(arr) => arr.len(),
92 Self::Float4Array(arr) => 4 * arr.len(),
93 Self::Bool(_) | Uniform::Int(_) => 1,
94
95 #[cfg(feature = "glam")]
96 Self::GlamFloatArray(arr) => arr.len(),
97 #[cfg(feature = "glam")]
98 Self::GlamMatrixArray(arr) => 4 * arr.len(),
99 }
100 }
101
102 pub(crate) fn bind(self, _frame: &mut Frame, ty: shader::Type, index: Index) {
107 assert!(
108 self.index_range().contains(&index),
109 "tried to bind uniform to an invalid index (index: {:?}, valid range: {:?})",
110 index,
111 self.index_range(),
112 );
113 assert!(
114 self.index_range().end.0 as usize >= self.len() + index.0 as usize,
115 "tried to bind a uniform that would overflow the uniform buffer. index was {:?}, size was {} max is {:?}",
116 index,
117 self.len(),
118 self.index_range().end
119 );
120
121 unsafe {
122 match self {
123 Self::Bool(b) => citro3d_sys::C3D_BoolUnifSet(ty.into(), index.into(), b),
124 Self::Int(i) => citro3d_sys::C3D_IVUnifSet(
125 ty.into(),
126 index.into(),
127 i.x() as i32,
128 i.y() as i32,
129 i.z() as i32,
130 i.w() as i32,
131 ),
132 Self::Float(f) => set_float_uniforms([f], self.len(), ty, index),
133 Self::Float2(fs) => {
134 set_float_uniforms(fs, self.len(), ty, index);
135 }
136 Self::Float3(fs) => set_float_uniforms(fs, self.len(), ty, index),
137 Self::Float4(m) => {
138 set_float_uniforms(m.rows_wzyx(), self.len(), ty, index);
139 }
140 Self::FloatArray(arr) => {
141 set_float_uniforms(arr.iter().copied(), self.len(), ty, index);
142 }
143 Self::Float4Array(arr) => {
144 set_float_uniforms(
145 arr.iter().flat_map(|m| m.rows_wzyx()),
146 self.len(),
147 ty,
148 index,
149 );
150 }
151 #[cfg(feature = "glam")]
152 Self::GlamFloatArray(arr) => {
153 set_float_uniforms(arr.iter().copied(), self.len(), ty, index);
154 }
155 #[cfg(feature = "glam")]
156 Self::GlamMatrixArray(arr) => {
157 set_float_uniforms(
158 arr.iter()
159 .copied()
160 .flat_map(|m| [m.row(0), m.row(1), m.row(2), m.row(3)]),
161 self.len(),
162 ty,
163 index,
164 );
165 }
166 }
167 }
168 }
169}
170
171unsafe fn set_float_uniforms<I: IntoIterator<Item: Into<[f32; 4]>>>(
174 fs: I,
175 max_len: usize,
176 ty: shader::Type,
177 index: Index,
178) {
179 let vecs =
180 unsafe { citro3d_sys::C3D_FVUnifWritePtr(ty.into(), index.0 as i32, max_len as i32) };
181 let vecs = unsafe { core::slice::from_raw_parts_mut(vecs, max_len) };
182
183 for (i, f) in fs.into_iter().enumerate() {
184 let f: [f32; 4] = f.into();
185 vecs[i].__bindgen_anon_1.x = f[0];
186 vecs[i].__bindgen_anon_1.y = f[1];
187 vecs[i].__bindgen_anon_1.z = f[2];
188 vecs[i].__bindgen_anon_1.w = f[3];
189 }
190}
191
192impl From<Matrix4> for Uniform<'static> {
193 fn from(value: Matrix4) -> Self {
194 Self::Float4(value)
195 }
196}
197impl<'a> From<&'a [Matrix4]> for Uniform<'a> {
198 fn from(value: &'a [Matrix4]) -> Self {
199 Self::Float4Array(value)
200 }
201}
202impl From<[FVec4; 3]> for Uniform<'static> {
203 fn from(value: [FVec4; 3]) -> Self {
204 Self::Float3(value)
205 }
206}
207impl From<[FVec4; 2]> for Uniform<'static> {
208 fn from(value: [FVec4; 2]) -> Self {
209 Self::Float2(value)
210 }
211}
212impl<'a> From<&'a [FVec4]> for Uniform<'a> {
213 fn from(value: &'a [FVec4]) -> Self {
214 Self::FloatArray(value)
215 }
216}
217impl From<FVec4> for Uniform<'static> {
218 fn from(value: FVec4) -> Self {
219 Self::Float(value)
220 }
221}
222impl From<IVec> for Uniform<'static> {
223 fn from(value: IVec) -> Self {
224 Self::Int(value)
225 }
226}
227impl From<bool> for Uniform<'static> {
228 fn from(value: bool) -> Self {
229 Self::Bool(value)
230 }
231}
232impl From<&Matrix4> for Uniform<'static> {
233 fn from(value: &Matrix4) -> Self {
234 (*value).into()
235 }
236}
237
238#[cfg(feature = "glam")]
239impl From<glam::Vec4> for Uniform<'static> {
240 fn from(value: glam::Vec4) -> Self {
241 Self::Float(value.into())
242 }
243}
244
245#[cfg(feature = "glam")]
246impl<'a> From<&'a [glam::Vec4]> for Uniform<'a> {
247 fn from(value: &'a [glam::Vec4]) -> Self {
248 Self::GlamFloatArray(value)
249 }
250}
251
252#[cfg(feature = "glam")]
253impl<'a> From<&'a Vec<glam::Vec4>> for Uniform<'a> {
254 fn from(value: &'a Vec<glam::Vec4>) -> Self {
255 Self::GlamFloatArray(value.as_slice())
256 }
257}
258
259#[cfg(feature = "glam")]
260impl From<glam::Mat4> for Uniform<'static> {
261 fn from(value: glam::Mat4) -> Self {
262 Self::Float4(value.into())
263 }
264}
265
266#[cfg(feature = "glam")]
267impl<'a> From<&'a [glam::Mat4]> for Uniform<'a> {
268 fn from(value: &'a [glam::Mat4]) -> Self {
269 Self::GlamMatrixArray(value)
270 }
271}