use atools

This commit is contained in:
bendn 2024-02-12 06:39:32 +07:00
parent 05f0d3d10d
commit 72be3fe0b0
8 changed files with 20 additions and 68 deletions

View file

@ -24,6 +24,7 @@ minifb = { version = "0.25.0", default-features = false, features = [
"wayland", "wayland",
], optional = true } ], optional = true }
wgpu = { version = "0.19.1", default-features = false, optional = true } wgpu = { version = "0.19.1", default-features = false, optional = true }
atools = "0.1.0"
[dev-dependencies] [dev-dependencies]
iai = { git = "https://github.com/bend-n/iai.git" } iai = { git = "https://github.com/bend-n/iai.git" }

View file

@ -109,7 +109,7 @@ trait CopyWithinUnchecked {
/// ///
/// panicless version of [`[T]::copy_within`](`slice::copy_within`), where the slices cant overlap. this uses `memcpy`. /// panicless version of [`[T]::copy_within`](`slice::copy_within`), where the slices cant overlap. this uses `memcpy`.
/// your slices must be in bounds. /// your slices must be in bounds.
/// this isnt a public function, so im not going to say exactly what "in bounds" meeans. /// this isnt a public function, so im not going to say exactly what "in bounds" means.
unsafe fn copy_within_unchecked(&mut self, src: Range<usize>, dest: usize); unsafe fn copy_within_unchecked(&mut self, src: Range<usize>, dest: usize);
} }

View file

@ -1,5 +1,6 @@
//! module for pixel blending ops //! module for pixel blending ops
use super::{convert::PFrom, unfloat, Floatify, PMap, Trunc, Unfloatify}; use super::{convert::PFrom, unfloat, Floatify, Unfloatify};
use atools::prelude::*;
use umath::FF32; use umath::FF32;
/// Trait for blending pixels together. /// Trait for blending pixels together.
@ -26,9 +27,8 @@ impl Blend<4> for [u8; 4] {
self[..3].copy_from_slice( self[..3].copy_from_slice(
&fg.trunc() &fg.trunc()
// SAFETY: no u8 can possibly become INF / NAN // SAFETY: no u8 can possibly become INF / NAN
.pmap(bg.trunc(), |f, b| unsafe { .zip(bg.trunc())
(f * fg[3] + b * bg[3] * (FF32::new(1.0) - fg[3])) / a .map(|(f, b)| unsafe { (f * fg[3] + b * bg[3] * (FF32::new(1.0) - fg[3])) / a })
})
.unfloat(), .unfloat(),
); );
self[3] = unfloat(a); self[3] = unfloat(a);

View file

@ -1,6 +1,5 @@
//! provides From's for pixels. //! provides From's for pixels.
use atools::prelude::*;
use super::{Push, Trunc};
/// Converts a pixel to another pixel. /// Converts a pixel to another pixel.
pub trait PFrom<const N: usize> { pub trait PFrom<const N: usize> {
@ -38,19 +37,19 @@ impl PFrom<4> for Y {
pub type YA = [u8; 2]; pub type YA = [u8; 2];
impl PFrom<1> for YA { impl PFrom<1> for YA {
fn pfrom(f: Y) -> Self { fn pfrom(f: Y) -> Self {
f.and(255) f.join(255)
} }
} }
impl PFrom<3> for YA { impl PFrom<3> for YA {
fn pfrom(f: RGB) -> Self { fn pfrom(f: RGB) -> Self {
Y::pfrom(f).and(255) Y::pfrom(f).join(255)
} }
} }
impl PFrom<4> for YA { impl PFrom<4> for YA {
fn pfrom(f: RGBA) -> Self { fn pfrom(f: RGBA) -> Self {
Y::pfrom(f.trunc()).and(255) Y::pfrom(f.trunc()).join(255)
} }
} }
@ -80,18 +79,18 @@ pub type RGBA = [u8; 4];
impl PFrom<1> for RGBA { impl PFrom<1> for RGBA {
fn pfrom([y]: Y) -> Self { fn pfrom([y]: Y) -> Self {
[y; 3].and(255) [y; 3].join(255)
} }
} }
impl PFrom<2> for RGBA { impl PFrom<2> for RGBA {
fn pfrom([y, a]: YA) -> Self { fn pfrom([y, a]: YA) -> Self {
[y; 3].and(a) [y; 3].join(a)
} }
} }
impl PFrom<3> for RGBA { impl PFrom<3> for RGBA {
fn pfrom(f: [u8; 3]) -> Self { fn pfrom(f: [u8; 3]) -> Self {
f.and(255) f.join(255)
} }
} }

View file

@ -4,6 +4,6 @@ pub mod blending;
mod utility; mod utility;
mod wam; mod wam;
pub use blending::Blend; pub use blending::Blend;
pub(crate) use utility::{float, unfloat, Floatify, PMap, Push, Trunc, Unfloatify}; pub(crate) use utility::{float, unfloat, Floatify, Unfloatify};
pub(crate) use wam::Wam; pub(crate) use wam::Wam;
pub mod convert; pub mod convert;

View file

@ -27,7 +27,7 @@ pub trait Floatify<const N: usize> {
/// computes n / 255 /// computes n / 255
pub fn float(n: u8) -> FF32 { pub fn float(n: u8) -> FF32 {
// SAFETY: 0..=255 / 0..=255 maynt ever be NAN / INF // SAFETY: 0..=255 / 0..=255 mayn't ever be NAN / INF
unsafe { FF32::new(n as f32) / FF32::new(255.0) } unsafe { FF32::new(n as f32) / FF32::new(255.0) }
} }
@ -39,51 +39,3 @@ impl<const N: usize> Floatify<N> for [u8; N] {
#[rustfmt::skip] #[rustfmt::skip]
impl<const N:usize>Floatify<N>for[FF32;N]{fn float(self)->[FF32;N]{self}} impl<const N:usize>Floatify<N>for[FF32;N]{fn float(self)->[FF32;N]{self}}
pub trait PMap<T, R, const N: usize> {
/// think of it like a `a.zip(b).map(f).collect::<[]>()`
fn pmap(self, with: Self, f: impl FnMut(T, T) -> R) -> [R; N];
}
impl<const N: usize, T: Copy, R: Copy> PMap<T, R, N> for [T; N] {
fn pmap(self, with: Self, mut f: impl FnMut(T, T) -> R) -> [R; N] {
let mut iter = self.into_iter().zip(with).map(|(a, b)| f(a, b));
std::array::from_fn(|_| iter.next().unwrap())
}
}
pub trait Trunc<T, const N: usize> {
/// it does `a[..a.len() - 1].try_into().unwrap()`.
fn trunc(&self) -> [T; N - 1];
}
impl<const N: usize, T: Copy> Trunc<T, N> for [T; N] {
fn trunc(&self) -> [T; N - 1] {
self[..N - 1].try_into().unwrap()
}
}
pub trait Push<T, const N: usize> {
fn and(self, and: T) -> [T; N + 1];
}
impl<const N: usize, T> Push<T, N> for [T; N] {
fn and(self, and: T) -> [T; N + 1] {
let mut iter = self.into_iter().chain(std::iter::once(and));
std::array::from_fn(|_| iter.next().unwrap())
}
}
#[test]
fn trunc() {
let x = [1];
assert_eq!(x.trunc(), []);
let x = [1, 2, 3, 4];
assert_eq!(x.trunc(), [1, 2, 3]);
}
#[test]
fn append() {
let x = [1];
assert_eq!(x.and(5), [1, 5]);
}

View file

@ -1,7 +1,7 @@
use super::{float, unfloat};
use atools::prelude::*;
use umath::{generic_float::Constructors, FF32}; use umath::{generic_float::Constructors, FF32};
use super::{float, unfloat, PMap};
pub trait Wam { pub trait Wam {
/// this function weighs the sides and combines /// this function weighs the sides and combines
/// ///
@ -14,7 +14,7 @@ pub trait Wam {
impl<const N: usize> Wam for [u8; N] { impl<const N: usize> Wam for [u8; N] {
unsafe fn wam(self, b: Self, l: FF32, r: FF32) -> Self { unsafe fn wam(self, b: Self, l: FF32, r: FF32) -> Self {
// SAFETY: read [`weigh`] // SAFETY: read [`weigh`]
self.pmap(b, |a, b| unsafe { weigh(a, b, l, r) }) self.zip(b).map(|(a, b)| unsafe { weigh(a, b, l, r) })
} }
} }
@ -23,7 +23,7 @@ impl<const N: usize> Wam for [u8; N] {
/// ///
/// floats must be smart /// floats must be smart
unsafe fn weigh(a: u8, b: u8, l: FF32, r: FF32) -> u8 { unsafe fn weigh(a: u8, b: u8, l: FF32, r: FF32) -> u8 {
// SAFETY: float(x) returns 0..=1, 0..=1 * f32::MAX isnt Inf, but if you add 1.0 and then mul by max again, you get inf (big bad, hence unsafe fn) // SAFETY: float(x) returns 0..=1, 0..=1 * f32::MAX isn't Inf, but if you add 1.0 and then mul by max again, you get inf (big bad, hence unsafe fn)
unsafe { unfloat((float(a) * l + float(b) * r).clamp(FF32::zero(), FF32::one())) } unsafe { unfloat((float(a) * l + float(b) * r).clamp(FF32::zero(), FF32::one())) }
} }

View file

@ -37,7 +37,7 @@ impl<T: AsRef<[u8]>> Image<T, 4> {
} }
impl Image<Box<[u8]>, 4> { impl Image<Box<[u8]>, 4> {
/// Downlodas a purportedly [`TextureFormat::Rgba8Unorm`] image from the gpu. /// Downloads a purportedly [`TextureFormat::Rgba8Unorm`] image from the gpu.
/// # Panics /// # Panics
/// ///
/// When a "error occurs while trying to async map a buffer". /// When a "error occurs while trying to async map a buffer".