1#![allow(clippy::cast_lossless)]
24
25pub(crate) mod ext;
29pub(crate) mod lerp;
30pub(crate) mod trig;
31
32pub use math_u16_impls::blend as blend_u16;
33pub use math_u16_impls::brighten_lin as brighten_u16_lin;
34pub use math_u16_impls::brighten_raw as brighten_u16_raw;
35pub use math_u16_impls::brighten_video as brighten_u16_video;
36pub use math_u16_impls::dim_lin as dim_u16_lin;
37pub use math_u16_impls::dim_raw as dim_u16_raw;
38pub use math_u16_impls::dim_video as dim_u16_video;
39pub use math_u16_impls::nscale as nscale_u16;
40pub use math_u16_impls::nscale_x2 as nscale_u16x2;
41pub use math_u16_impls::nscale_x3 as nscale_u16x3;
42pub use math_u16_impls::nscale_x4 as nscale_u16x4;
43pub use math_u16_impls::scale as scale_u16;
44pub use math_u16_impls::scale_video as scale_u16_video;
45pub use math_u8_impls::blend as blend_u8;
46pub use math_u8_impls::brighten_lin as brighten_u8_lin;
47pub use math_u8_impls::brighten_raw as brighten_u8_raw;
48pub use math_u8_impls::brighten_video as brighten_u8_video;
49pub use math_u8_impls::dim_lin as dim_u8_lin;
50pub use math_u8_impls::dim_raw as dim_u8_raw;
51pub use math_u8_impls::dim_video as dim_u8_video;
52pub use math_u8_impls::nscale as nscale_u8;
53pub use math_u8_impls::nscale_x2 as nscale_u8x2;
54pub use math_u8_impls::nscale_x3 as nscale_u8x3;
55pub use math_u8_impls::nscale_x4 as nscale_u8x4;
56pub use math_u8_impls::scale as scale_u8;
57pub use math_u8_impls::scale_video as scale_u8_video;
58
59pub use trig::{sin_u8,cos_u8,sin_u16,cos_u16};
60
61pub trait Trig<Signed> {
63 fn sin(self) -> Signed;
64
65 fn cos(self) -> Signed;
66}
67
68pub trait ScalingInt {
101 fn scale(self, other: Self) -> Self;
116
117 fn scale_video(self, other: Self) -> Self;
134
135 fn dim_raw(self) -> Self;
155
156 fn dim_video(self) -> Self;
170
171 fn dim_lin(self) -> Self;
176
177 fn brighten_raw(self) -> Self;
179
180 fn brighten_video(self) -> Self;
182
183 fn brighten_lin(self) -> Self;
187
188 fn blend(self, b: Self, amount_of_b: Self) -> Self;
190}
191
192macro_rules! doc_comment {
193 ($x:expr, $($tt:tt)*) => {
194 #[doc = $x]
195 $($tt)*
196 };
197}
198
199macro_rules! impl_nscale_ops {
201 ($t:tt, $up:tt, $shift:expr, $mscaler:expr, $($element:tt),*) => {
202 let scaler: $up = 1 as $up + $up::from($mscaler);
203 $( *$element = (((*$element as $up) * scaler) >> $shift) as $t; )*
204 };
205}
206
207macro_rules! impl_scale_ops { ($t:tt, $up:tt, $shift:expr, $max:expr) => (
208 doc_comment!{concat!(
209 "Scale a `", stringify!($t), "` by another."),
210 #[inline(always)]
211 pub const fn scale(i: $t, scale: $t) -> $t {
212 (((i as $up) * (1 as $up + scale as $up)) >> $shift) as $t
213 }
214 }
215
216 doc_comment!{concat!(
217 "Scale a `", stringify!($t), "` by another, but in video mode.",
218 "\n\n",
219 "Video scaling guarantees the output of this function will only be zero",
220 "if-and-only-if at least one of the inputs are zero."),
221 #[inline]
222 pub const fn scale_video(i: $t, scale: $t) -> $t {
223 let x: $t = (((i as $up) * (scale as $up)) >> $shift) as $t;
224 let correction_int: $t = (i != 0) as $t;
225 let correction_scale: $t = (scale != 0) as $t;
226 let correction: $t = correction_int & correction_scale;
227 x + correction as $t
228 }}
229
230 doc_comment!{concat!("Dims a `", stringify!($t), "`."),
231 #[inline(always)]
232 pub const fn dim_raw(x: $t) -> $t {
233 scale(x, x)
234 }}
235
236 doc_comment!{concat!(
237 "Dims a `", stringify!($t), "` in video mode.",
238 "\n\n",
239 "Similar to `scale_video`, the output will only be zero if the input",
240 "is also zero."),
241 #[inline(always)]
242 pub const fn dim_video(x: $t) -> $t {
243 scale_video(x, x)
244 }}
245
246 doc_comment!{concat!(
247 "Dims a `", stringify!($t), "` similar to `dim_raw`, but linearly below a threshold.",
248 "\n\n",
249 "When the input is less than equal to`", stringify!($max / 2), "`, the output is dimmed ",
250 "by halving."),
251 #[inline]
252 pub const fn dim_lin(x: $t) -> $t {
253 const UPPER_BITS: $t = (1 << ($shift - 1));
254 let use_lin = (x & UPPER_BITS) != 0;
255 let scale_x_reg = (use_lin as $t) * scale(x, x);
256 let scale_x_lin = (!use_lin as $t) * (x.wrapping_add(1) / 2);
257 scale_x_reg.wrapping_add(scale_x_lin)
259 }}
260
261 doc_comment!{concat!(
262 "Brightens a `", stringify!($t), "`.",
263 "\n\n",
264 "This is the inverse of `dim_raw`."),
265 #[inline]
266 pub const fn brighten_raw(x: $t) -> $t {
267 let ix = $max - x;
268 $max - dim_raw(ix)
269 }}
270
271 doc_comment!{concat!(
272 "Brightens a `", stringify!($t), "` but in video mode.",
273 "\n\n",
274 "This is the inverse of `dim_video`."),
275 #[inline]
276 pub const fn brighten_video(x: $t) -> $t {
277 let ix = $max - x;
278 $max - dim_video(ix)
279 }}
280
281 doc_comment!{concat!(
282 "Brightens a `", stringify!($t), "`, but linearly below a threshold.",
283 "\n\n",
284 "This is the inverse of `dim_lin`."),
285 #[inline]
286 pub const fn brighten_lin(x: $t) -> $t {
287 let ix = $max - x;
288 $max - dim_lin(ix)
289 }}
290
291 doc_comment!{concat!(
292 "Scales a single `", stringify!($t), "` in place."),
293 #[inline(always)]
294 pub fn nscale(int: &mut $t, scaler: $t) {
295 *int = scale(*int, scaler);
296 }}
297
298 doc_comment!{concat!(
299 "Inplace scaling for two `", stringify!($t), "`'s by the same value."),
300 #[inline(always)]
301 pub fn nscale_x2(int_1: &mut $t, int_2: &mut $t, scaler: $t) {
302 impl_nscale_ops!($t, $up, $shift, scaler, int_1, int_2);
303 }}
304
305 doc_comment!{concat!(
306 "Inplace scaling for three `", stringify!($t), "`'s by the same value."),
307 #[inline]
308 pub fn nscale_x3(int_1: &mut $t, int_2: &mut $t, int_3: &mut $t, scaler: $t) {
309 impl_nscale_ops!($t, $up, $shift, scaler, int_1, int_2, int_3);
310 }}
311
312 doc_comment!{concat!(
313 "Inplace scaling for four `", stringify!($t), "`'s by the same value."),
314 #[inline]
315 pub fn nscale_x4(int_1: &mut $t, int_2: &mut $t, int_3: &mut $t, int_4: &mut $t, scaler: $t) {
316 impl_nscale_ops!($t, $up, $shift, scaler, int_1, int_2, int_3, int_4);
317 }}
318
319
320 doc_comment!{concat!(
321 "Blends a `", stringify!($t), "`another integer by the fraction `amount_of_b`."),
322 #[inline]
323 pub const fn blend(a: $t, b: $t, amount_of_b: $t) -> $t {
324 let amount_of_a: $up = ($max - amount_of_b) as $up;
325 let mut partial: $up = 0;
326 partial += a as $up * amount_of_a as $up;
327 partial += a as $up;
328 partial += b as $up * amount_of_b as $up;
329 partial += b as $up;
330 (partial >> $shift) as $t
331 }}
332 )
333}
334
335macro_rules! impl_scaling_trait_rename {
339 ($t:tt, $fname:ident) => (
340 #[inline(always)]
341 fn $fname(self) -> $t {
342 $fname(self)
343 }
344 );
345 ($t:tt, $param:ident, $fname:ident) => (
346 #[inline(always)]
347 fn $fname(self, $param: $t) -> $t {
348 $fname(self, $param)
349 }
350 );
351
352 ($t:tt, $param_1:ident, $param_2:ident, $fname:ident) => (
353 #[inline(always)]
354 fn $fname(self, $param_1: $t, $param_2: $t) -> $t {
355 $fname(self, $param_1, $param_2)
356 }
357 );
358}
359
360macro_rules! impl_scaling_trait {
361 ($t:tt) => {
362 impl crate::math::ScalingInt for $t {
363 impl_scaling_trait_rename!($t, other, scale);
364 impl_scaling_trait_rename!($t, other, scale_video);
365 impl_scaling_trait_rename!($t, dim_raw);
366 impl_scaling_trait_rename!($t, dim_video);
367 impl_scaling_trait_rename!($t, dim_lin);
368 impl_scaling_trait_rename!($t, brighten_raw);
369 impl_scaling_trait_rename!($t, brighten_video);
370 impl_scaling_trait_rename!($t, brighten_lin);
371 impl_scaling_trait_rename!($t, b, amount_of_b, blend);
372 }
373 };
374}
375
376mod math_u8_impls {
377 impl_scale_ops!(u8, u16, 8, 255);
383 impl_scaling_trait!(u8);
384}
385
386mod math_u16_impls {
387 impl_scale_ops!(u16, u32, 16, 65535);
393 impl_scaling_trait!(u16);
394}