noise_functions/math/
traits.rs1#[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}