noise_functions/math/
traits.rs

1#[cfg(feature = "nightly-simd")]
2use core::simd::{num::SimdFloat, prelude::SimdPartialOrd, LaneCount, Simd, SimdElement, SupportedLaneCount};
3
4pub trait Dot {
5    type Output;
6    fn dot(lhs: Self, rhs: Self) -> Self::Output;
7}
8
9#[inline(always)]
10pub fn dot<T: Dot>(lhs: T, rhs: T) -> T::Output {
11    Dot::dot(lhs, rhs)
12}
13
14#[inline(always)]
15pub fn length_squared<T: Dot + Copy>(value: T) -> T::Output {
16    dot(value, value)
17}
18
19#[allow(dead_code)]
20pub fn length<T: Dot<Output = f32> + Copy>(value: T) -> T::Output {
21    crate::math::sqrt(length_squared(value))
22}
23
24pub trait FloorToInt {
25    type Output;
26    fn floor_to_int(self) -> Self::Output;
27}
28
29impl FloorToInt for f32 {
30    type Output = i32;
31
32    #[inline(always)]
33    fn floor_to_int(self) -> Self::Output {
34        if self >= 0.0 {
35            self as i32
36        } else {
37            (self as i32).wrapping_sub(1)
38        }
39    }
40}
41
42#[cfg(feature = "nightly-simd")]
43impl<const LANES: usize> FloorToInt for Simd<f32, LANES>
44where
45    LaneCount<LANES>: SupportedLaneCount,
46{
47    type Output = Simd<i32, LANES>;
48
49    #[inline(always)]
50    fn floor_to_int(self) -> Self::Output {
51        let int = unsafe { self.to_int_unchecked::<i32>() };
52        int - self.simd_ge(splat(0.0)).select(splat(0), splat(1))
53    }
54}
55
56#[inline(always)]
57pub fn floor_to_int<T: FloorToInt>(value: T) -> T::Output {
58    FloorToInt::floor_to_int(value)
59}
60
61pub trait RoundToInt {
62    type Output;
63    fn round_to_int(self) -> Self::Output;
64}
65
66impl RoundToInt for f32 {
67    type Output = i32;
68
69    #[inline(always)]
70    fn round_to_int(self) -> Self::Output {
71        if self >= 0.0 {
72            (self + 0.5) as i32
73        } else {
74            (self - 0.5) as i32
75        }
76    }
77}
78
79#[cfg(feature = "nightly-simd")]
80impl<const LANES: usize> RoundToInt for Simd<f32, LANES>
81where
82    LaneCount<LANES>: SupportedLaneCount,
83{
84    type Output = Simd<i32, LANES>;
85
86    #[inline(always)]
87    fn round_to_int(self) -> Self::Output {
88        let f = self + self.simd_ge(splat(0.0)).select(splat(0.5), splat(-0.5));
89        unsafe { f.to_int_unchecked() }
90    }
91}
92
93#[inline(always)]
94pub fn round_to_int<T: RoundToInt>(value: T) -> T::Output {
95    RoundToInt::round_to_int(value)
96}
97
98pub trait InterpQuintic {
99    fn interp_quintic(self) -> Self;
100}
101
102impl InterpQuintic for f32 {
103    #[inline(always)]
104    fn interp_quintic(self) -> Self {
105        self * self * self * (self * (self * 6.0 - 15.0) + 10.0)
106    }
107}
108
109#[cfg(feature = "nightly-simd")]
110impl<const LANES: usize> InterpQuintic for Simd<f32, LANES>
111where
112    LaneCount<LANES>: SupportedLaneCount,
113{
114    #[inline(always)]
115    fn interp_quintic(self) -> Self {
116        self * self * self * (self * (self * splat(6.0) - splat(15.0)) + splat(10.0))
117    }
118}
119
120#[inline(always)]
121pub fn interp_quintic<T: InterpQuintic>(value: T) -> T {
122    InterpQuintic::interp_quintic(value)
123}
124
125pub trait InterpHermite {
126    fn interp_hermite(self) -> Self;
127}
128
129impl InterpHermite for f32 {
130    #[inline(always)]
131    fn interp_hermite(self) -> Self {
132        self * self * (3.0 - 2.0 * self)
133    }
134}
135
136#[cfg(feature = "nightly-simd")]
137impl<const LANES: usize> InterpHermite for Simd<f32, LANES>
138where
139    LaneCount<LANES>: SupportedLaneCount,
140{
141    #[inline(always)]
142    fn interp_hermite(self) -> Self {
143        self * self * (splat(3.0) - splat(2.0) * self)
144    }
145}
146
147#[inline(always)]
148pub fn interp_hermite<T: InterpHermite>(value: T) -> T {
149    InterpHermite::interp_hermite(value)
150}
151
152pub trait Lerp<T = Self> {
153    type Output;
154    fn lerp(a: Self, b: Self, t: T) -> Self::Output;
155}
156
157impl Lerp for f32 {
158    type Output = Self;
159
160    #[inline(always)]
161    fn lerp(a: Self, b: Self, t: Self) -> Self::Output {
162        a + t * (b - a)
163    }
164}
165
166#[inline(always)]
167pub fn lerp<T, V: Lerp<T>>(a: V, b: V, t: T) -> V::Output {
168    Lerp::lerp(a, b, t)
169}
170
171#[cfg(feature = "nightly-simd")]
172impl<const LANES: usize> Lerp for Simd<f32, LANES>
173where
174    LaneCount<LANES>: SupportedLaneCount,
175{
176    type Output = Self;
177
178    #[inline(always)]
179    fn lerp(a: Self, b: Self, t: Self) -> Self::Output {
180        a + t * (b - a)
181    }
182}
183
184#[cfg(feature = "nightly-simd")]
185impl<const LANES: usize> Lerp<f32> for Simd<f32, LANES>
186where
187    LaneCount<LANES>: SupportedLaneCount,
188{
189    type Output = Self;
190
191    #[inline(always)]
192    fn lerp(a: Self, b: Self, t: f32) -> Self::Output {
193        a + Simd::splat(t) * (b - a)
194    }
195}
196
197#[cfg(feature = "nightly-simd")]
198pub(crate) fn splat<T, const LANES: usize>(value: T) -> Simd<T, LANES>
199where
200    T: SimdElement,
201    LaneCount<LANES>: SupportedLaneCount,
202{
203    Simd::splat(value)
204}
205
206#[inline(always)]
207pub fn fast_min(a: f32, b: f32) -> f32 {
208    if a < b {
209        a
210    } else {
211        b
212    }
213}
214
215#[allow(dead_code)]
216#[inline(always)]
217pub fn fast_max(a: f32, b: f32) -> f32 {
218    if a > b {
219        a
220    } else {
221        b
222    }
223}