#![allow(clippy::cast_lossless)]
pub(crate) mod ext;
pub(crate) mod lerp;
pub(crate) mod trig;
pub use math_u16_impls::blend as blend_u16;
pub use math_u16_impls::brighten_lin as brighten_u16_lin;
pub use math_u16_impls::brighten_raw as brighten_u16_raw;
pub use math_u16_impls::brighten_video as brighten_u16_video;
pub use math_u16_impls::dim_lin as dim_u16_lin;
pub use math_u16_impls::dim_raw as dim_u16_raw;
pub use math_u16_impls::dim_video as dim_u16_video;
pub use math_u16_impls::nscale as nscale_u16;
pub use math_u16_impls::nscale_x2 as nscale_u16x2;
pub use math_u16_impls::nscale_x3 as nscale_u16x3;
pub use math_u16_impls::nscale_x4 as nscale_u16x4;
pub use math_u16_impls::scale as scale_u16;
pub use math_u16_impls::scale_video as scale_u16_video;
pub use math_u8_impls::blend as blend_u8;
pub use math_u8_impls::brighten_lin as brighten_u8_lin;
pub use math_u8_impls::brighten_raw as brighten_u8_raw;
pub use math_u8_impls::brighten_video as brighten_u8_video;
pub use math_u8_impls::dim_lin as dim_u8_lin;
pub use math_u8_impls::dim_raw as dim_u8_raw;
pub use math_u8_impls::dim_video as dim_u8_video;
pub use math_u8_impls::nscale as nscale_u8;
pub use math_u8_impls::nscale_x2 as nscale_u8x2;
pub use math_u8_impls::nscale_x3 as nscale_u8x3;
pub use math_u8_impls::nscale_x4 as nscale_u8x4;
pub use math_u8_impls::scale as scale_u8;
pub use math_u8_impls::scale_video as scale_u8_video;
pub use trig::{sin_u8,cos_u8,sin_u16,cos_u16};
pub trait Trig<Signed> {
fn sin(self) -> Signed;
fn cos(self) -> Signed;
}
pub trait ScalingInt {
fn scale(self, other: Self) -> Self;
fn scale_video(self, other: Self) -> Self;
fn dim_raw(self) -> Self;
fn dim_video(self) -> Self;
fn dim_lin(self) -> Self;
fn brighten_raw(self) -> Self;
fn brighten_video(self) -> Self;
fn brighten_lin(self) -> Self;
fn blend(self, b: Self, amount_of_b: Self) -> Self;
}
macro_rules! doc_comment {
($x:expr, $($tt:tt)*) => {
#[doc = $x]
$($tt)*
};
}
macro_rules! impl_nscale_ops {
($t:tt, $up:tt, $shift:expr, $mscaler:expr, $($element:tt),*) => {
let scaler: $up = 1 as $up + $up::from($mscaler);
$( *$element = (((*$element as $up) * scaler) >> $shift) as $t; )*
};
}
macro_rules! impl_scale_ops { ($t:tt, $up:tt, $shift:expr, $max:expr) => (
doc_comment!{concat!(
"Scale a `", stringify!($t), "` by another."),
#[inline(always)]
pub const fn scale(i: $t, scale: $t) -> $t {
(((i as $up) * (1 as $up + scale as $up)) >> $shift) as $t
}
}
doc_comment!{concat!(
"Scale a `", stringify!($t), "` by another, but in video mode.",
"\n\n",
"Video scaling guarantees the output of this function will only be zero",
"if-and-only-if at least one of the inputs are zero."),
#[inline]
pub const fn scale_video(i: $t, scale: $t) -> $t {
let x: $t = (((i as $up) * (scale as $up)) >> $shift) as $t;
let correction_int: $t = (i != 0) as $t;
let correction_scale: $t = (scale != 0) as $t;
let correction: $t = correction_int & correction_scale;
x + correction as $t
}}
doc_comment!{concat!("Dims a `", stringify!($t), "`."),
#[inline(always)]
pub const fn dim_raw(x: $t) -> $t {
scale(x, x)
}}
doc_comment!{concat!(
"Dims a `", stringify!($t), "` in video mode.",
"\n\n",
"Similar to `scale_video`, the output will only be zero if the input",
"is also zero."),
#[inline(always)]
pub const fn dim_video(x: $t) -> $t {
scale_video(x, x)
}}
doc_comment!{concat!(
"Dims a `", stringify!($t), "` similar to `dim_raw`, but linearly below a threshold.",
"\n\n",
"When the input is less than equal to`", stringify!($max / 2), "`, the output is dimmed ",
"by halving."),
#[inline]
pub const fn dim_lin(x: $t) -> $t {
const UPPER_BITS: $t = (1 << ($shift - 1));
let use_lin = (x & UPPER_BITS) != 0;
let scale_x_reg = (use_lin as $t) * scale(x, x);
let scale_x_lin = (!use_lin as $t) * (x.wrapping_add(1) / 2);
scale_x_reg.wrapping_add(scale_x_lin)
}}
doc_comment!{concat!(
"Brightens a `", stringify!($t), "`.",
"\n\n",
"This is the inverse of `dim_raw`."),
#[inline]
pub const fn brighten_raw(x: $t) -> $t {
let ix = $max - x;
$max - dim_raw(ix)
}}
doc_comment!{concat!(
"Brightens a `", stringify!($t), "` but in video mode.",
"\n\n",
"This is the inverse of `dim_video`."),
#[inline]
pub const fn brighten_video(x: $t) -> $t {
let ix = $max - x;
$max - dim_video(ix)
}}
doc_comment!{concat!(
"Brightens a `", stringify!($t), "`, but linearly below a threshold.",
"\n\n",
"This is the inverse of `dim_lin`."),
#[inline]
pub const fn brighten_lin(x: $t) -> $t {
let ix = $max - x;
$max - dim_lin(ix)
}}
doc_comment!{concat!(
"Scales a single `", stringify!($t), "` in place."),
#[inline(always)]
pub fn nscale(int: &mut $t, scaler: $t) {
*int = scale(*int, scaler);
}}
doc_comment!{concat!(
"Inplace scaling for two `", stringify!($t), "`'s by the same value."),
#[inline(always)]
pub fn nscale_x2(int_1: &mut $t, int_2: &mut $t, scaler: $t) {
impl_nscale_ops!($t, $up, $shift, scaler, int_1, int_2);
}}
doc_comment!{concat!(
"Inplace scaling for three `", stringify!($t), "`'s by the same value."),
#[inline]
pub fn nscale_x3(int_1: &mut $t, int_2: &mut $t, int_3: &mut $t, scaler: $t) {
impl_nscale_ops!($t, $up, $shift, scaler, int_1, int_2, int_3);
}}
doc_comment!{concat!(
"Inplace scaling for four `", stringify!($t), "`'s by the same value."),
#[inline]
pub fn nscale_x4(int_1: &mut $t, int_2: &mut $t, int_3: &mut $t, int_4: &mut $t, scaler: $t) {
impl_nscale_ops!($t, $up, $shift, scaler, int_1, int_2, int_3, int_4);
}}
doc_comment!{concat!(
"Blends a `", stringify!($t), "`another integer by the fraction `amount_of_b`."),
#[inline]
pub const fn blend(a: $t, b: $t, amount_of_b: $t) -> $t {
let amount_of_a: $up = ($max - amount_of_b) as $up;
let mut partial: $up = 0;
partial += a as $up * amount_of_a as $up;
partial += a as $up;
partial += b as $up * amount_of_b as $up;
partial += b as $up;
(partial >> $shift) as $t
}}
)
}
macro_rules! impl_scaling_trait_rename {
($t:tt, $fname:ident) => (
#[inline(always)]
fn $fname(self) -> $t {
$fname(self)
}
);
($t:tt, $param:ident, $fname:ident) => (
#[inline(always)]
fn $fname(self, $param: $t) -> $t {
$fname(self, $param)
}
);
($t:tt, $param_1:ident, $param_2:ident, $fname:ident) => (
#[inline(always)]
fn $fname(self, $param_1: $t, $param_2: $t) -> $t {
$fname(self, $param_1, $param_2)
}
);
}
macro_rules! impl_scaling_trait {
($t:tt) => {
impl crate::math::ScalingInt for $t {
impl_scaling_trait_rename!($t, other, scale);
impl_scaling_trait_rename!($t, other, scale_video);
impl_scaling_trait_rename!($t, dim_raw);
impl_scaling_trait_rename!($t, dim_video);
impl_scaling_trait_rename!($t, dim_lin);
impl_scaling_trait_rename!($t, brighten_raw);
impl_scaling_trait_rename!($t, brighten_video);
impl_scaling_trait_rename!($t, brighten_lin);
impl_scaling_trait_rename!($t, b, amount_of_b, blend);
}
};
}
mod math_u8_impls {
impl_scale_ops!(u8, u16, 8, 255);
impl_scaling_trait!(u8);
}
mod math_u16_impls {
impl_scale_ops!(u16, u32, 16, 65535);
impl_scaling_trait!(u16);
}