1use crate::{RGB, RGBA};
2
3pub trait ChannelArray<const N: usize>: Copy {
20 fn to_array(self) -> [f32; N];
22 fn from_array(arr: [f32; N]) -> Self;
24}
25
26impl ChannelArray<4> for RGBA {
27 fn to_array(self) -> [f32; 4] { [self.0, self.1, self.2, self.3] }
28 fn from_array(a: [f32; 4]) -> Self { RGBA(a[0], a[1], a[2], a[3]) }
29}
30
31impl ChannelArray<3> for RGB {
32 fn to_array(self) -> [f32; 3] { [self.0, self.1, self.2] }
33 fn from_array(a: [f32; 3]) -> Self { RGB(a[0], a[1], a[2]) }
34}
35
36pub fn channel_lerp<T: ChannelArray<N>, const N: usize>(a: T, b: T, t: f32) -> T {
46 let (a, b) = (a.to_array(), b.to_array());
47 let t = t.clamp(0.0, 1.0);
48 let mut out = [0.0f32; N];
49 for i in 0..N { out[i] = a[i] + (b[i] - a[i]) * t; }
50 T::from_array(out)
51}
52
53pub fn channel_add<T: ChannelArray<N>, const N: usize>(a: T, b: T) -> T {
55 let (a, b) = (a.to_array(), b.to_array());
56 let mut out = [0.0f32; N];
57 for i in 0..N { out[i] = a[i] + b[i]; }
58 T::from_array(out)
59}
60
61pub fn channel_sub<T: ChannelArray<N>, const N: usize>(a: T, b: T) -> T {
63 let (a, b) = (a.to_array(), b.to_array());
64 let mut out = [0.0f32; N];
65 for i in 0..N { out[i] = a[i] - b[i]; }
66 T::from_array(out)
67}
68
69pub fn channel_mul<T: ChannelArray<N>, const N: usize>(a: T, b: T) -> T {
71 let (a, b) = (a.to_array(), b.to_array());
72 let mut out = [0.0f32; N];
73 for i in 0..N { out[i] = a[i] * b[i]; }
74 T::from_array(out)
75}
76
77pub fn channel_mul_scalar<T: ChannelArray<N>, const N: usize>(a: T, s: f32) -> T {
79 let a = a.to_array();
80 let mut out = [0.0f32; N];
81 for i in 0..N { out[i] = a[i] * s; }
82 T::from_array(out)
83}
84
85pub fn channel_div_scalar<T: ChannelArray<N>, const N: usize>(a: T, s: f32) -> T {
89 channel_mul_scalar(a, 1.0 / s)
90}
91
92macro_rules! impl_channel_ops {
93 ($ty:ty, $n:literal) => {
94 impl std::ops::Add for $ty {
95 type Output = Self;
96 fn add(self, rhs: Self) -> Self { channel_add(self, rhs) }
97 }
98 impl std::ops::Sub for $ty {
99 type Output = Self;
100 fn sub(self, rhs: Self) -> Self { channel_sub(self, rhs) }
101 }
102 impl std::ops::Mul<f32> for $ty {
103 type Output = Self;
104 fn mul(self, rhs: f32) -> Self { channel_mul_scalar(self, rhs) }
105 }
106 impl std::ops::Mul for $ty {
107 type Output = Self;
108 fn mul(self, rhs: Self) -> Self { channel_mul(self, rhs) }
109 }
110 impl std::ops::Div<f32> for $ty {
111 type Output = Self;
112 fn div(self, rhs: f32) -> Self { channel_div_scalar(self, rhs) }
113 }
114 impl From<[f32; $n]> for $ty {
115 fn from(arr: [f32; $n]) -> Self { Self::from_array(arr) }
116 }
117 impl From<$ty> for [f32; $n] {
118 fn from(c: $ty) -> Self { c.to_array() }
119 }
120 };
121}
122
123impl_channel_ops!(RGBA, 4);
124impl_channel_ops!(RGB, 3);
125
126impl From<(f32, f32, f32, f32)> for RGBA {
127 fn from(t: (f32, f32, f32, f32)) -> Self { RGBA(t.0, t.1, t.2, t.3) }
128}
129
130impl From<(f32, f32, f32)> for RGB {
131 fn from(t: (f32, f32, f32)) -> Self { RGB(t.0, t.1, t.2) }
132}