1#![allow(clippy::manual_range_contains)]
2#![allow(clippy::cast_lossless)]
3
4use core::ops::*;
5
6const U16_MAX: f32 = u16::MAX as f32;
7const U8_MAX: f32 = u8::MAX as f32;
8
9#[derive(Debug, Clone)]
10pub enum UNormError {
11 UnnormalizedFloat,
12}
13
14impl core::fmt::Display for UNormError {
15 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16 write!(f, "{:?}", self)
17 }
18}
19
20#[cfg(not(target_arch = "spirv"))]
21impl std::error::Error for UNormError {}
22
23#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
29#[cfg_attr(feature = "with_serde", derive(serde::Serialize, serde::Deserialize))]
30#[cfg_attr(feature = "with_serde", serde(transparent))]
31#[cfg_attr(feature = "with_speedy", derive(speedy::Readable, speedy::Writable))]
32#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
33#[repr(transparent)]
34pub struct UNorm16(pub u16);
35
36impl UNorm16 {
37 #[inline]
38 pub fn new(x: f32) -> Result<Self, UNormError> {
39 if !x.is_nan() && x >= 0.0 && x <= 1.0 {
40 Ok(Self::new_unchecked(x))
41 } else {
42 Err(UNormError::UnnormalizedFloat)
43 }
44 }
45
46 #[inline]
47 pub fn new_clamped(x: f32) -> Self {
48 Self::new_unchecked(x.clamp(0.0, 1.0))
49 }
50
51 #[inline(always)]
52 pub fn new_unchecked(x: f32) -> Self {
53 Self((x * U16_MAX) as u16)
54 }
55
56 #[inline(always)]
57 pub fn to_f32(self) -> f32 {
58 self.0 as f32 / U16_MAX
59 }
60}
61
62impl Add<Self> for UNorm16 {
63 type Output = Self;
64 #[inline]
65 fn add(self, rhs: Self) -> Self::Output {
66 Self(self.0 + rhs.0)
67 }
68}
69
70impl AddAssign for UNorm16 {
71 #[inline]
72 fn add_assign(&mut self, rhs: Self) {
73 self.0 += rhs.0;
74 }
75}
76
77impl Sub<Self> for UNorm16 {
78 type Output = Self;
79 #[inline]
80 fn sub(self, rhs: Self) -> Self::Output {
81 Self(self.0 - rhs.0)
82 }
83}
84
85impl SubAssign for UNorm16 {
86 #[inline]
87 fn sub_assign(&mut self, rhs: Self) {
88 self.0 -= rhs.0;
89 }
90}
91
92impl Mul<Self> for UNorm16 {
93 type Output = Self;
94 #[inline]
95 fn mul(self, rhs: Self) -> Self::Output {
96 let numerator: u32 = self.0 as u32 * rhs.0 as u32;
101 let output: u32 = numerator >> 16;
102 Self(output as u16)
103 }
104}
105
106impl MulAssign for UNorm16 {
107 #[inline]
108 fn mul_assign(&mut self, rhs: Self) {
109 *self = *self * rhs;
110 }
111}
112
113impl Div<Self> for UNorm16 {
114 type Output = Self;
115 #[inline]
116 fn div(self, rhs: Self) -> Self::Output {
117 let output: u32 = ((self.0 as u32) << 16) / (rhs.0 as u32);
123 Self(output as u16)
124 }
125}
126
127impl DivAssign for UNorm16 {
128 #[inline]
129 fn div_assign(&mut self, rhs: Self) {
130 *self = *self / rhs;
131 }
132}
133
134#[cfg(not(target_arch = "spirv"))]
135impl core::fmt::Debug for UNorm16 {
136 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
137 write!(f, "{}", self.to_f32())?;
138 if f.alternate() {
139 write!(f, " ({}/{})", self.0, u16::MAX)?;
140 }
141 Ok(())
142 }
143}
144
145#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
151#[cfg_attr(feature = "with_serde", derive(serde::Serialize, serde::Deserialize))]
152#[cfg_attr(feature = "with_serde", serde(transparent))]
153#[cfg_attr(feature = "with_speedy", derive(speedy::Readable, speedy::Writable))]
154#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
155#[repr(transparent)]
156pub struct UNorm8(pub u8);
157
158impl UNorm8 {
159 #[inline]
160 pub fn new(x: f32) -> Result<Self, UNormError> {
161 if !x.is_nan() && x >= 0.0 && x <= 1.0 {
162 Ok(Self::new_unchecked(x))
163 } else {
164 Err(UNormError::UnnormalizedFloat)
165 }
166 }
167
168 #[inline]
169 pub fn new_clamped(x: f32) -> Self {
170 Self::new_unchecked(x.clamp(0.0, 1.0))
171 }
172
173 #[inline(always)]
174 pub fn new_unchecked(x: f32) -> Self {
175 Self((x * U8_MAX) as u8)
176 }
177
178 #[inline(always)]
179 pub fn to_f32(self) -> f32 {
180 self.0 as f32 / U8_MAX
181 }
182}
183
184impl Add<Self> for UNorm8 {
185 type Output = Self;
186 #[inline]
187 fn add(self, rhs: Self) -> Self::Output {
188 Self(self.0 + rhs.0)
189 }
190}
191
192impl AddAssign for UNorm8 {
193 #[inline]
194 fn add_assign(&mut self, rhs: Self) {
195 self.0 += rhs.0;
196 }
197}
198
199impl Sub<Self> for UNorm8 {
200 type Output = Self;
201 #[inline]
202 fn sub(self, rhs: Self) -> Self::Output {
203 Self(self.0 - rhs.0)
204 }
205}
206
207impl SubAssign for UNorm8 {
208 #[inline]
209 fn sub_assign(&mut self, rhs: Self) {
210 self.0 -= rhs.0;
211 }
212}
213
214impl Mul<Self> for UNorm8 {
215 type Output = Self;
216 #[inline]
217 fn mul(self, rhs: Self) -> Self::Output {
218 let numerator: u32 = self.0 as u32 * rhs.0 as u32;
223 let output: u32 = numerator >> 8;
224 Self(output as u8)
225 }
226}
227
228impl MulAssign for UNorm8 {
229 #[inline]
230 fn mul_assign(&mut self, rhs: Self) {
231 *self = *self * rhs;
232 }
233}
234
235impl Div<Self> for UNorm8 {
236 type Output = Self;
237 #[inline]
238 fn div(self, rhs: Self) -> Self::Output {
239 let output: u32 = ((self.0 as u32) << 8) / (rhs.0 as u32);
245 Self(output as u8)
246 }
247}
248
249impl DivAssign for UNorm8 {
250 #[inline]
251 fn div_assign(&mut self, rhs: Self) {
252 *self = *self / rhs;
253 }
254}
255
256#[cfg(not(target_arch = "spirv"))]
257impl core::fmt::Debug for UNorm8 {
258 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
259 write!(f, "{}", self.to_f32())?;
260 if f.alternate() {
261 write!(f, " ({}/{})", self.0, u8::MAX)?;
262 }
263 Ok(())
264 }
265}