1use std::ops::Range;
5
6use crate::math::{FVec4, IVec, Matrix4};
7use crate::{RenderPass, shader};
8
9#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
11pub struct Index(u8);
12
13impl From<u8> for Index {
14 fn from(value: u8) -> Self {
15 Self(value)
16 }
17}
18
19impl From<Index> for i32 {
20 fn from(value: Index) -> Self {
21 value.0.into()
22 }
23}
24
25#[non_exhaustive]
27#[derive(Debug, PartialEq, Clone, Copy)]
28pub enum Uniform {
29 #[doc(alias = "C3D_FVUnifSet")]
31 Float(FVec4),
32 #[doc(alias = "C3D_FVUnifMtx2x4")]
34 Float2([FVec4; 2]),
35 #[doc(alias = "C3D_FVUnifMtx3x4")]
37 Float3([FVec4; 3]),
38 #[doc(alias = "C3D_FVUnifMtx4x4")]
40 Float4(Matrix4),
41 #[doc(alias = "C3D_BoolUnifSet")]
43 Bool(bool),
44 #[doc(alias = "C3D_IVUnifSet")]
46 Int(IVec),
47}
48impl Uniform {
49 pub fn index_range(&self) -> Range<Index> {
51 match self {
54 Self::Float(_) | Self::Float2(_) | Self::Float3(_) | Self::Float4(_) => {
55 Index(0)..Index(0x60)
56 }
57 Self::Int(_) => Index(0x60)..Index(0x64),
58 Self::Bool(_) => Index(0x68)..Index(0x79),
60 }
61 }
62 #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize {
65 match self {
66 Self::Float(_) => 1,
67 Self::Float2(_) => 2,
68 Self::Float3(_) => 3,
69 Self::Float4(_) => 4,
70 Self::Bool(_) | Uniform::Int(_) => 1,
71 }
72 }
73
74 pub(crate) fn bind(self, _pass: &mut RenderPass, ty: shader::Type, index: Index) {
79 assert!(
80 self.index_range().contains(&index),
81 "tried to bind uniform to an invalid index (index: {:?}, valid range: {:?})",
82 index,
83 self.index_range(),
84 );
85 assert!(
86 self.index_range().end.0 as usize >= self.len() + index.0 as usize,
87 "tried to bind a uniform that would overflow the uniform buffer. index was {:?}, size was {} max is {:?}",
88 index,
89 self.len(),
90 self.index_range().end
91 );
92
93 let set_fvs = |fs: &[FVec4]| {
94 for (off, f) in fs.iter().enumerate() {
95 unsafe {
96 citro3d_sys::C3D_FVUnifSet(
97 ty.into(),
98 (index.0 as usize + off) as i32,
99 f.x(),
100 f.y(),
101 f.z(),
102 f.w(),
103 );
104 }
105 }
106 };
107
108 match self {
109 Self::Bool(b) => unsafe {
110 citro3d_sys::C3D_BoolUnifSet(ty.into(), index.into(), b);
111 },
112 Self::Int(i) => unsafe {
113 citro3d_sys::C3D_IVUnifSet(
114 ty.into(),
115 index.into(),
116 i.x() as i32,
117 i.y() as i32,
118 i.z() as i32,
119 i.w() as i32,
120 );
121 },
122 Self::Float(f) => set_fvs(&[f]),
123 Self::Float2(fs) => {
124 set_fvs(&fs);
125 }
126 Self::Float3(fs) => set_fvs(&fs),
127 Self::Float4(m) => {
128 set_fvs(&m.rows_wzyx());
129 }
130 }
131 }
132}
133
134impl From<Matrix4> for Uniform {
135 fn from(value: Matrix4) -> Self {
136 Self::Float4(value)
137 }
138}
139impl From<[FVec4; 3]> for Uniform {
140 fn from(value: [FVec4; 3]) -> Self {
141 Self::Float3(value)
142 }
143}
144
145impl From<[FVec4; 2]> for Uniform {
146 fn from(value: [FVec4; 2]) -> Self {
147 Self::Float2(value)
148 }
149}
150impl From<FVec4> for Uniform {
151 fn from(value: FVec4) -> Self {
152 Self::Float(value)
153 }
154}
155impl From<IVec> for Uniform {
156 fn from(value: IVec) -> Self {
157 Self::Int(value)
158 }
159}
160impl From<bool> for Uniform {
161 fn from(value: bool) -> Self {
162 Self::Bool(value)
163 }
164}
165impl From<&Matrix4> for Uniform {
166 fn from(value: &Matrix4) -> Self {
167 (*value).into()
168 }
169}
170
171#[cfg(feature = "glam")]
172impl From<glam::Vec4> for Uniform {
173 fn from(value: glam::Vec4) -> Self {
174 Self::Float(value.into())
175 }
176}
177
178#[cfg(feature = "glam")]
179impl From<glam::Mat4> for Uniform {
180 fn from(value: glam::Mat4) -> Self {
181 Self::Float4(value.into())
182 }
183}