1use crate::math::{FusedMultiplyAdd, FusedMultiplyNegAdd};
30use crate::mlaf::{mlaf, neg_mlaf};
31use crate::nd_array::{ArrayFetch, lerp};
32use crate::{Vector3f, Vector3i};
33use num_traits::MulAdd;
34use std::array::from_fn;
35use std::marker::PhantomData;
36use std::ops::{Add, Mul, Neg, Sub};
37
38pub(crate) struct MultidimensionalLut {
39 pub(crate) grid_strides: [u32; 16],
40 pub(crate) grid_filling_size: [u32; 16],
41 pub(crate) grid_scale: [f32; 16],
42 pub(crate) output_inks: usize,
43}
44
45struct FastCube<T, F: ArrayFetch<T>> {
46 fetch: F,
47 _phantom: PhantomData<T>,
48}
49
50struct ArrayFetchVectorN<'a> {
51 array: &'a [f32],
52 x_stride: u32,
53 y_stride: u32,
54 z_stride: u32,
55 output_inks: usize,
56}
57
58#[repr(transparent)]
59#[derive(Copy, Clone, Debug)]
60pub(crate) struct NVector<T, const N: usize> {
61 pub(crate) v: [T; N],
62}
63
64impl<T: Copy, const N: usize> NVector<T, N> {
65 pub(crate) fn from_slice(v: &[T; N]) -> Self {
66 Self { v: *v }
67 }
68}
69
70impl<T: Copy, const N: usize> From<T> for NVector<T, N> {
71 #[inline]
72 fn from(value: T) -> Self {
73 Self { v: [value; N] }
74 }
75}
76
77impl<T: Copy + Add<T, Output = T> + Mul<T, Output = T> + MulAdd<T, Output = T>, const N: usize>
78 FusedMultiplyAdd<NVector<T, N>> for NVector<T, N>
79{
80 #[inline]
81 fn mla(&self, b: NVector<T, N>, c: NVector<T, N>) -> NVector<T, N> {
82 Self {
83 v: from_fn(|i| mlaf(self.v[i], b.v[i], c.v[i])),
84 }
85 }
86}
87
88impl<
89 T: Copy + Add<T, Output = T> + Mul<T, Output = T> + MulAdd<T, Output = T> + Neg<Output = T>,
90 const N: usize,
91> FusedMultiplyNegAdd<NVector<T, N>> for NVector<T, N>
92{
93 #[inline]
94 fn neg_mla(&self, b: NVector<T, N>, c: NVector<T, N>) -> NVector<T, N> {
95 Self {
96 v: from_fn(|i| neg_mlaf(self.v[i], b.v[i], c.v[i])),
97 }
98 }
99}
100
101impl<T: Sub<Output = T> + Default + Copy, const N: usize> Sub<NVector<T, N>> for NVector<T, N> {
102 type Output = Self;
103
104 #[inline]
105 fn sub(self, rhs: NVector<T, N>) -> Self::Output {
106 Self {
107 v: from_fn(|i| self.v[i] - rhs.v[i]),
108 }
109 }
110}
111
112impl<T: Add<Output = T> + Default + Copy, const N: usize> Add<NVector<T, N>> for NVector<T, N> {
113 type Output = Self;
114
115 #[inline]
116 fn add(self, rhs: NVector<T, N>) -> Self::Output {
117 Self {
118 v: from_fn(|i| self.v[i] + rhs.v[i]),
119 }
120 }
121}
122
123impl<T: Mul<Output = T> + Default + Copy, const N: usize> Mul<NVector<T, N>> for NVector<T, N> {
124 type Output = Self;
125
126 #[inline]
127 fn mul(self, rhs: NVector<T, N>) -> Self::Output {
128 Self {
129 v: from_fn(|i| self.v[i] * rhs.v[i]),
130 }
131 }
132}
133
134impl<const N: usize> ArrayFetch<NVector<f32, N>> for ArrayFetchVectorN<'_> {
135 #[inline(always)]
136 fn fetch(&self, x: i32, y: i32, z: i32) -> NVector<f32, N> {
137 let start = (x as u32 * self.x_stride + y as u32 * self.y_stride + z as u32 * self.z_stride)
138 as usize
139 * self.output_inks;
140 let k = &self.array[start..start + N];
141 NVector::<f32, N>::from_slice(k.try_into().unwrap())
142 }
143}
144
145impl<T, F: ArrayFetch<T>> FastCube<T, F>
146where
147 T: Copy
148 + From<f32>
149 + Sub<T, Output = T>
150 + Mul<T, Output = T>
151 + Add<T, Output = T>
152 + FusedMultiplyNegAdd<T>
153 + FusedMultiplyAdd<T>,
154{
155 #[inline(always)]
156 fn tetra(&self, src: Vector3i, src_next: Vector3i, w: Vector3f) -> T {
157 let x = src.v[0];
158 let y = src.v[1];
159 let z = src.v[2];
160
161 let x_n = src_next.v[0];
162 let y_n = src_next.v[1];
163 let z_n = src_next.v[2];
164
165 let rx = w.v[0];
166 let ry = w.v[1];
167 let rz = w.v[2];
168
169 let c0 = self.fetch.fetch(x, y, z);
170 let c2;
171 let c1;
172 let c3;
173 if rx >= ry {
174 if ry >= rz {
175 c1 = self.fetch.fetch(x_n, y, z) - c0;
177 c2 = self.fetch.fetch(x_n, y_n, z) - self.fetch.fetch(x_n, y, z);
178 c3 = self.fetch.fetch(x_n, y_n, z_n) - self.fetch.fetch(x_n, y_n, z);
179 } else if rx >= rz {
180 c1 = self.fetch.fetch(x_n, y, z) - c0;
182 c2 = self.fetch.fetch(x_n, y_n, z_n) - self.fetch.fetch(x_n, y, z_n);
183 c3 = self.fetch.fetch(x_n, y, z_n) - self.fetch.fetch(x_n, y, z);
184 } else {
185 c1 = self.fetch.fetch(x_n, y, z_n) - self.fetch.fetch(x, y, z_n);
187 c2 = self.fetch.fetch(x_n, y_n, z_n) - self.fetch.fetch(x_n, y, z_n);
188 c3 = self.fetch.fetch(x, y, z_n) - c0;
189 }
190 } else if rx >= rz {
191 c1 = self.fetch.fetch(x_n, y_n, z) - self.fetch.fetch(x, y_n, z);
193 c2 = self.fetch.fetch(x, y_n, z) - c0;
194 c3 = self.fetch.fetch(x_n, y_n, z_n) - self.fetch.fetch(x_n, y_n, z);
195 } else if ry >= rz {
196 c1 = self.fetch.fetch(x_n, y_n, z_n) - self.fetch.fetch(x, y_n, z_n);
198 c2 = self.fetch.fetch(x, y_n, z) - c0;
199 c3 = self.fetch.fetch(x, y_n, z_n) - self.fetch.fetch(x, y_n, z);
200 } else {
201 c1 = self.fetch.fetch(x_n, y_n, z_n) - self.fetch.fetch(x, y_n, z_n);
203 c2 = self.fetch.fetch(x, y_n, z_n) - self.fetch.fetch(x, y, z_n);
204 c3 = self.fetch.fetch(x, y, z_n) - c0;
205 }
206 let s0 = c0.mla(c1, T::from(rx));
207 let s1 = s0.mla(c2, T::from(ry));
208 s1.mla(c3, T::from(rz))
209 }
210}
211
212impl MultidimensionalLut {
213 pub(crate) fn new(grid_size: [u8; 16], input_inks: usize, output_inks: usize) -> Self {
214 assert!(input_inks <= 16);
215 let mut grid_strides = [1u32; 16];
216 let mut grid_filling_size = [1u32; 16];
217
218 for (ink, dst_stride) in grid_strides.iter_mut().take(input_inks - 1).enumerate() {
219 let mut stride = 1u32;
220 let how_many = input_inks.saturating_sub(ink).saturating_sub(1);
221 for &grid_stride in grid_size.iter().take(how_many) {
222 stride *= grid_stride as u32;
223 }
224 *dst_stride = stride;
225 }
226
227 for (ink, dst_stride) in grid_filling_size.iter_mut().take(input_inks).enumerate() {
228 let mut stride = output_inks as u32;
229 let how_many = input_inks.saturating_sub(ink).saturating_sub(1);
230 for &grid_stride in grid_size.iter().take(how_many) {
231 stride *= grid_stride as u32;
232 }
233 *dst_stride = stride;
234 }
235
236 let mut grid_strides_f = [0f32; 16];
237
238 for (dst, src) in grid_strides_f
239 .iter_mut()
240 .zip(grid_size.iter())
241 .take(input_inks)
242 {
243 *dst = (*src - 1) as f32;
244 }
245
246 Self {
247 grid_strides,
248 grid_scale: grid_strides_f,
249 grid_filling_size,
250 output_inks,
251 }
252 }
253}
254
255pub(crate) fn linear_4i_vec3f_direct<const N: usize>(
256 lut: &MultidimensionalLut,
257 arr: &[f32],
258 lx: f32,
259 ly: f32,
260 lz: f32,
261 lw: f32,
262) -> NVector<f32, N> {
263 let lin_x = lx.max(0.0).min(1.0);
264 let lin_y = ly.max(0.0).min(1.0);
265 let lin_z = lz.max(0.0).min(1.0);
266 let lin_w = lw.max(0.0).min(1.0);
267
268 let scale_x = lut.grid_scale[0];
269 let scale_y = lut.grid_scale[1];
270 let scale_z = lut.grid_scale[2];
271 let scale_w = lut.grid_scale[3];
272
273 let lx = lin_x * scale_x;
274 let ly = lin_y * scale_y;
275 let lz = lin_z * scale_z;
276 let lw = lin_w * scale_w;
277
278 let x = lx.floor() as i32;
279 let y = ly.floor() as i32;
280 let z = lz.floor() as i32;
281 let w = lw.floor() as i32;
282
283 let src_x = Vector3i { v: [x, y, z] };
284
285 let x_n = lx.ceil() as i32;
286 let y_n = ly.ceil() as i32;
287 let z_n = lz.ceil() as i32;
288 let w_n = lw.ceil() as i32;
289
290 let src_next = Vector3i { v: [x_n, y_n, z_n] };
291
292 let x_w = lx - x as f32;
293 let y_w = ly - y as f32;
294 let z_w = lz - z as f32;
295 let w_w = lw - w as f32;
296
297 let weights = Vector3f { v: [x_w, y_w, z_w] };
298
299 let cube0 = &arr[(w as usize * lut.grid_filling_size[3] as usize)..];
300 let cube1 = &arr[(w_n as usize * lut.grid_filling_size[3] as usize)..];
301
302 let fast_cube0 = FastCube {
303 fetch: ArrayFetchVectorN {
304 array: cube0,
305 x_stride: lut.grid_strides[0],
306 y_stride: lut.grid_strides[1],
307 z_stride: lut.grid_strides[2],
308 output_inks: lut.output_inks,
309 },
310 _phantom: PhantomData,
311 };
312 let fast_cube1 = FastCube {
313 fetch: ArrayFetchVectorN {
314 array: cube1,
315 x_stride: lut.grid_strides[0],
316 y_stride: lut.grid_strides[1],
317 z_stride: lut.grid_strides[2],
318 output_inks: lut.output_inks,
319 },
320 _phantom: PhantomData,
321 };
322 let w0 = fast_cube0.tetra(src_x, src_next, weights);
323 let w1 = fast_cube1.tetra(src_x, src_next, weights);
324 lerp(w0, w1, NVector::<f32, N>::from(w_w))
325}
326
327pub(crate) fn linear_3i_vec3f_direct<const N: usize>(
328 lut: &MultidimensionalLut,
329 arr: &[f32],
330 inputs: &[f32],
331) -> NVector<f32, N> {
332 linear_3i_vec3f(lut, arr, inputs[0], inputs[1], inputs[2])
333}
334
335fn linear_3i_vec3f<const N: usize>(
336 lut: &MultidimensionalLut,
337 arr: &[f32],
338 x: f32,
339 y: f32,
340 z: f32,
341) -> NVector<f32, N> {
342 let lin_x = x.max(0.0).min(1.0);
343 let lin_y = y.max(0.0).min(1.0);
344 let lin_z = z.max(0.0).min(1.0);
345
346 let scale_x = lut.grid_scale[0];
347 let scale_y = lut.grid_scale[1];
348 let scale_z = lut.grid_scale[2];
349
350 let lx = lin_x * scale_x;
351 let ly = lin_y * scale_y;
352 let lz = lin_z * scale_z;
353
354 let x = lx.floor() as i32;
355 let y = ly.floor() as i32;
356 let z = lz.floor() as i32;
357
358 let src_x = Vector3i { v: [x, y, z] };
359
360 let x_n = lx.ceil() as i32;
361 let y_n = ly.ceil() as i32;
362 let z_n = lz.ceil() as i32;
363
364 let src_next = Vector3i { v: [x_n, y_n, z_n] };
365
366 let x_w = lx - x as f32;
367 let y_w = ly - y as f32;
368 let z_w = lz - z as f32;
369
370 let weights = Vector3f { v: [x_w, y_w, z_w] };
371
372 let fast_cube = FastCube {
373 fetch: ArrayFetchVectorN {
374 array: arr,
375 x_stride: lut.grid_strides[0],
376 y_stride: lut.grid_strides[1],
377 z_stride: lut.grid_strides[2],
378 output_inks: lut.output_inks,
379 },
380 _phantom: PhantomData,
381 };
382
383 fast_cube.tetra(src_x, src_next, weights)
384}
385
386pub(crate) fn linear_1i_vec3f<const N: usize>(
387 lut: &MultidimensionalLut,
388 arr: &[f32],
389 inputs: &[f32],
390) -> NVector<f32, N> {
391 let lin_x = inputs[0].max(0.0).min(1.0);
392
393 let scale_x = lut.grid_scale[0];
394
395 let lx = lin_x * scale_x;
396
397 let x = lx.floor() as i32;
398
399 let x_n = lx.ceil() as i32;
400
401 let x_w = lx - x as f32;
402
403 let x_stride = lut.grid_strides[0];
404
405 let offset = |xi: i32| -> usize { (xi as u32 * x_stride) as usize * lut.output_inks };
406
407 let a = NVector::<f32, N>::from_slice(&arr[offset(x)..][..N].try_into().unwrap());
409 let b = NVector::<f32, N>::from_slice(&arr[offset(x_n)..][..N].try_into().unwrap());
410
411 a * NVector::<f32, N>::from(1.0 - x_w) + b * NVector::<f32, N>::from(x_w)
412}
413
414pub(crate) fn linear_2i_vec3f_direct<const N: usize>(
415 lut: &MultidimensionalLut,
416 arr: &[f32],
417 inputs: &[f32],
418) -> NVector<f32, N> {
419 linear_2i_vec3f(lut, arr, inputs[0], inputs[1])
420}
421
422fn linear_2i_vec3f<const N: usize>(
423 lut: &MultidimensionalLut,
424 arr: &[f32],
425 x: f32,
426 y: f32,
427) -> NVector<f32, N> {
428 let lin_x = x.max(0.0).min(1.0);
429 let lin_y = y.max(0.0).min(1.0);
430
431 let scale_x = lut.grid_scale[0];
432 let scale_y = lut.grid_scale[1];
433
434 let lx = lin_x * scale_x;
435 let ly = lin_y * scale_y;
436
437 let x = lx.floor() as i32;
438 let y = ly.floor() as i32;
439
440 let x_n = lx.ceil() as i32;
441 let y_n = ly.ceil() as i32;
442
443 let x_w = lx - x as f32;
444 let y_w = ly - y as f32;
445
446 let x_stride = lut.grid_strides[0];
447 let y_stride = lut.grid_strides[1];
448
449 let offset = |xi: i32, yi: i32| -> usize {
450 (xi as u32 * x_stride + yi as u32 * y_stride) as usize * lut.output_inks
451 };
452
453 let a = NVector::<f32, N>::from_slice(&arr[offset(x, y)..][..N].try_into().unwrap());
455 let b = NVector::<f32, N>::from_slice(&arr[offset(x_n, y)..][..N].try_into().unwrap());
456 let c = NVector::<f32, N>::from_slice(&arr[offset(x, y_n)..][..N].try_into().unwrap());
457 let d = NVector::<f32, N>::from_slice(&arr[offset(x_n, y_n)..][..N].try_into().unwrap());
458
459 let ab = a * NVector::<f32, N>::from(1.0 - x_w) + b * NVector::<f32, N>::from(x_w);
460 let cd = c * NVector::<f32, N>::from(1.0 - x_w) + d * NVector::<f32, N>::from(x_w);
461
462 ab * NVector::<f32, N>::from(1.0 - y_w) + cd * NVector::<f32, N>::from(y_w)
463}
464
465pub(crate) fn linear_4i_vec3f<const N: usize>(
466 lut: &MultidimensionalLut,
467 arr: &[f32],
468 inputs: &[f32],
469) -> NVector<f32, N> {
470 linear_4i_vec3f_direct(lut, arr, inputs[0], inputs[1], inputs[2], inputs[3])
471}
472
473type FHandle<const N: usize> = fn(&MultidimensionalLut, &[f32], &[f32]) -> NVector<f32, N>;
474
475#[inline(never)]
476pub(crate) fn linear_n_i_vec3f<
477 const N: usize,
478 const I: usize,
479 Handle: Fn(&MultidimensionalLut, &[f32], &[f32]) -> NVector<f32, N>,
480>(
481 lut: &MultidimensionalLut,
482 arr: &[f32],
483 inputs: &[f32],
484 handle: Handle,
485) -> NVector<f32, N> {
486 let lin_w = inputs[I];
487
488 let w_c = lin_w.max(0.).min(1.);
489 let scale_p = lut.grid_scale[I];
490 let wf = w_c * scale_p;
491 let w0 = wf.min(scale_p) as usize;
492 let w1 = (wf + 1.).min(scale_p) as usize;
493 let w = wf - w0 as f32;
494
495 let cube0 = &arr[(w0 * lut.grid_filling_size[I] as usize)..];
496 let cube1 = &arr[(w1 * lut.grid_filling_size[I] as usize)..];
497
498 let inputs_sliced = &inputs[0..I];
499 let w0 = handle(lut, cube0, inputs_sliced);
500 let w1 = handle(lut, cube1, inputs_sliced);
501 lerp(w0, w1, NVector::<f32, N>::from(w))
502}
503
504#[inline(never)]
505pub(crate) fn linear_5i_vec3f<const N: usize>(
506 lut: &MultidimensionalLut,
507 arr: &[f32],
508 inputs: &[f32],
509) -> NVector<f32, N> {
510 let lin_w = inputs[4];
511
512 let w_c = lin_w.max(0.).min(1.);
513 let scale_p = lut.grid_scale[4];
514 let wf = w_c * scale_p;
515 let w0 = wf.min(scale_p) as usize;
516 let w1 = (wf + 1.).min(scale_p) as usize;
517 let w = wf - w0 as f32;
518
519 let cube0 = &arr[(w0 * lut.grid_filling_size[4] as usize)..];
520 let cube1 = &arr[(w1 * lut.grid_filling_size[4] as usize)..];
521
522 let w0 = linear_4i_vec3f_direct(lut, cube0, inputs[0], inputs[1], inputs[2], inputs[3]);
523 let w1 = linear_4i_vec3f_direct(lut, cube1, inputs[0], inputs[1], inputs[2], inputs[3]);
524 lerp(w0, w1, NVector::<f32, N>::from(w))
525}
526
527#[inline(never)]
528pub(crate) fn linear_6i_vec3f<const N: usize>(
529 lut: &MultidimensionalLut,
530 arr: &[f32],
531 inputs: &[f32],
532) -> NVector<f32, N> {
533 let f = linear_5i_vec3f::<N>;
534 linear_n_i_vec3f::<N, 5, FHandle<N>>(lut, arr, inputs, f)
535}
536
537#[inline(never)]
538pub(crate) fn linear_7i_vec3f<const N: usize>(
539 lut: &MultidimensionalLut,
540 arr: &[f32],
541 inputs: &[f32],
542) -> NVector<f32, N> {
543 let f = linear_6i_vec3f::<N>;
544 linear_n_i_vec3f::<N, 6, FHandle<N>>(lut, arr, inputs, f)
545}
546
547#[inline(never)]
548pub(crate) fn linear_8i_vec3f<const N: usize>(
549 lut: &MultidimensionalLut,
550 arr: &[f32],
551 inputs: &[f32],
552) -> NVector<f32, N> {
553 let f = linear_7i_vec3f::<N>;
554 linear_n_i_vec3f::<N, 7, FHandle<N>>(lut, arr, inputs, f)
555}
556
557#[inline(never)]
558pub(crate) fn linear_9i_vec3f<const N: usize>(
559 lut: &MultidimensionalLut,
560 arr: &[f32],
561 inputs: &[f32],
562) -> NVector<f32, N> {
563 let f = linear_8i_vec3f::<N>;
564 linear_n_i_vec3f::<N, 8, FHandle<N>>(lut, arr, inputs, f)
565}
566
567#[inline(never)]
568pub(crate) fn linear_10i_vec3f<const N: usize>(
569 lut: &MultidimensionalLut,
570 arr: &[f32],
571 inputs: &[f32],
572) -> NVector<f32, N> {
573 let f = linear_9i_vec3f::<N>;
574 linear_n_i_vec3f::<N, 9, FHandle<N>>(lut, arr, inputs, f)
575}
576
577#[inline(never)]
578pub(crate) fn linear_11i_vec3f<const N: usize>(
579 lut: &MultidimensionalLut,
580 arr: &[f32],
581 inputs: &[f32],
582) -> NVector<f32, N> {
583 let f = linear_10i_vec3f::<N>;
584 linear_n_i_vec3f::<N, 10, FHandle<N>>(lut, arr, inputs, f)
585}
586
587#[inline(never)]
588pub(crate) fn linear_12i_vec3f<const N: usize>(
589 lut: &MultidimensionalLut,
590 arr: &[f32],
591 inputs: &[f32],
592) -> NVector<f32, N> {
593 let f = linear_11i_vec3f::<N>;
594 linear_n_i_vec3f::<N, 11, FHandle<N>>(lut, arr, inputs, f)
595}
596
597#[inline(never)]
598pub(crate) fn linear_13i_vec3f<const N: usize>(
599 lut: &MultidimensionalLut,
600 arr: &[f32],
601 inputs: &[f32],
602) -> NVector<f32, N> {
603 let f = linear_12i_vec3f::<N>;
604 linear_n_i_vec3f::<N, 12, FHandle<N>>(lut, arr, inputs, f)
605}
606
607#[inline(never)]
608pub(crate) fn linear_14i_vec3f<const N: usize>(
609 lut: &MultidimensionalLut,
610 arr: &[f32],
611 inputs: &[f32],
612) -> NVector<f32, N> {
613 let f = linear_13i_vec3f::<N>;
614 linear_n_i_vec3f::<N, 13, FHandle<N>>(lut, arr, inputs, f)
615}
616
617#[inline(never)]
618pub(crate) fn linear_15i_vec3f<const N: usize>(
619 lut: &MultidimensionalLut,
620 arr: &[f32],
621 inputs: &[f32],
622) -> NVector<f32, N> {
623 let f = linear_14i_vec3f::<N>;
624 linear_n_i_vec3f::<N, 14, FHandle<N>>(lut, arr, inputs, f)
625}
626
627#[inline(never)]
628pub(crate) fn tetra_3i_to_any_vec(
629 lut: &MultidimensionalLut,
630 arr: &[f32],
631 x: f32,
632 y: f32,
633 z: f32,
634 dst: &mut [f32],
635 inks: usize,
636) {
637 match inks {
638 1 => {
639 let vec3 = linear_3i_vec3f::<1>(lut, arr, x, y, z);
640 dst[0] = vec3.v[0];
641 }
642 2 => {
643 let vec3 = linear_3i_vec3f::<2>(lut, arr, x, y, z);
644 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
645 *dst = *src;
646 }
647 }
648 3 => {
649 let vec3 = linear_3i_vec3f::<3>(lut, arr, x, y, z);
650 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
651 *dst = *src;
652 }
653 }
654 4 => {
655 let vec3 = linear_3i_vec3f::<4>(lut, arr, x, y, z);
656 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
657 *dst = *src;
658 }
659 }
660 5 => {
661 let vec3 = linear_3i_vec3f::<5>(lut, arr, x, y, z);
662 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
663 *dst = *src;
664 }
665 }
666 6 => {
667 let vec3 = linear_3i_vec3f::<6>(lut, arr, x, y, z);
668 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
669 *dst = *src;
670 }
671 }
672 7 => {
673 let vec3 = linear_3i_vec3f::<7>(lut, arr, x, y, z);
674 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
675 *dst = *src;
676 }
677 }
678 8 => {
679 let vec3 = linear_3i_vec3f::<8>(lut, arr, x, y, z);
680 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
681 *dst = *src;
682 }
683 }
684 9 => {
685 let vec3 = linear_3i_vec3f::<9>(lut, arr, x, y, z);
686 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
687 *dst = *src;
688 }
689 }
690 10 => {
691 let vec3 = linear_3i_vec3f::<10>(lut, arr, x, y, z);
692 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
693 *dst = *src;
694 }
695 }
696 11 => {
697 let vec3 = linear_3i_vec3f::<11>(lut, arr, x, y, z);
698 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
699 *dst = *src;
700 }
701 }
702 12 => {
703 let vec3 = linear_3i_vec3f::<12>(lut, arr, x, y, z);
704 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
705 *dst = *src;
706 }
707 }
708 13 => {
709 let vec3 = linear_3i_vec3f::<13>(lut, arr, x, y, z);
710 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
711 *dst = *src;
712 }
713 }
714 14 => {
715 let vec3 = linear_3i_vec3f::<14>(lut, arr, x, y, z);
716 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
717 *dst = *src;
718 }
719 }
720 15 => {
721 let vec3 = linear_3i_vec3f::<15>(lut, arr, x, y, z);
722 for (dst, src) in dst.iter_mut().zip(vec3.v.iter()) {
723 *dst = *src;
724 }
725 }
726 _ => unreachable!(),
727 }
728}