1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2012 Marti Maria Saguer
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
29 // This module incorporates several interpolation routines, for 1 to 8 channels on input and
30 // up to 65535 channels on output. The user may change those by using the interpolation plug-in
32 // Interpolation routines by default
33 static cmsInterpFunction
DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels
, cmsUInt32Number nOutputChannels
, cmsUInt32Number dwFlags
);
35 // This is the default factory
36 static cmsInterpFnFactory Interpolators
= DefaultInterpolatorsFactory
;
40 cmsBool
_cmsRegisterInterpPlugin(cmsPluginBase
* Data
)
42 cmsPluginInterpolation
* Plugin
= (cmsPluginInterpolation
*) Data
;
46 Interpolators
= DefaultInterpolatorsFactory
;
50 // Set replacement functions
51 Interpolators
= Plugin
->InterpolatorsFactory
;
56 // Set the interpolation method
57 cmsBool
_cmsSetInterpolationRoutine(cmsInterpParams
* p
)
59 // Invoke factory, possibly in the Plug-in
60 p
->Interpolation
= Interpolators(p
-> nInputs
, p
->nOutputs
, p
->dwFlags
);
62 // If unsupported by the plug-in, go for the LittleCMS default.
63 // If happens only if an extern plug-in is being used
64 if (p
->Interpolation
.Lerp16
== NULL
)
65 p
->Interpolation
= DefaultInterpolatorsFactory(p
->nInputs
, p
->nOutputs
, p
->dwFlags
);
67 // Check for valid interpolator (we just check one member of the union)
68 if (p
->Interpolation
.Lerp16
== NULL
) {
75 // This function precalculates as many parameters as possible to speed up the interpolation.
76 cmsInterpParams
* _cmsComputeInterpParamsEx(cmsContext ContextID
,
77 const cmsUInt32Number nSamples
[],
78 int InputChan
, int OutputChan
,
80 cmsUInt32Number dwFlags
)
85 // Check for maximum inputs
86 if (InputChan
> MAX_INPUT_DIMENSIONS
) {
87 cmsSignalError(ContextID
, cmsERROR_RANGE
, "Too many input channels (%d channels, max=%d)", InputChan
, MAX_INPUT_DIMENSIONS
);
91 // Creates an empty object
92 p
= (cmsInterpParams
*) _cmsMallocZero(ContextID
, sizeof(cmsInterpParams
));
93 if (p
== NULL
) return NULL
;
95 // Keep original parameters
96 p
-> dwFlags
= dwFlags
;
97 p
-> nInputs
= InputChan
;
98 p
-> nOutputs
= OutputChan
;
100 p
->ContextID
= ContextID
;
102 // Fill samples per input direction and domain (which is number of nodes minus one)
103 for (i
=0; i
< InputChan
; i
++) {
105 p
-> nSamples
[i
] = nSamples
[i
];
106 p
-> Domain
[i
] = nSamples
[i
] - 1;
109 // Compute factors to apply to each component to index the grid array
110 p
-> opta
[0] = p
-> nOutputs
;
111 for (i
=1; i
< InputChan
; i
++)
112 p
->opta
[i
] = p
->opta
[i
-1] * nSamples
[InputChan
-i
];
115 if (!_cmsSetInterpolationRoutine(p
)) {
116 cmsSignalError(ContextID
, cmsERROR_UNKNOWN_EXTENSION
, "Unsupported interpolation (%d->%d channels)", InputChan
, OutputChan
);
117 _cmsFree(ContextID
, p
);
126 // This one is a wrapper on the anterior, but assuming all directions have same number of nodes
127 cmsInterpParams
* _cmsComputeInterpParams(cmsContext ContextID
, int nSamples
, int InputChan
, int OutputChan
, const void* Table
, cmsUInt32Number dwFlags
)
130 cmsUInt32Number Samples
[MAX_INPUT_DIMENSIONS
];
132 // Fill the auxiliar array
133 for (i
=0; i
< MAX_INPUT_DIMENSIONS
; i
++)
134 Samples
[i
] = nSamples
;
136 // Call the extended function
137 return _cmsComputeInterpParamsEx(ContextID
, Samples
, InputChan
, OutputChan
, Table
, dwFlags
);
141 // Free all associated memory
142 void _cmsFreeInterpParams(cmsInterpParams
* p
)
144 if (p
!= NULL
) _cmsFree(p
->ContextID
, p
);
148 // Inline fixed point interpolation
149 cmsINLINE cmsUInt16Number
LinearInterp(cmsS15Fixed16Number a
, cmsS15Fixed16Number l
, cmsS15Fixed16Number h
)
151 cmsUInt32Number dif
= (cmsUInt32Number
) (h
- l
) * a
+ 0x8000;
152 dif
= (dif
>> 16) + l
;
153 return (cmsUInt16Number
) (dif
);
157 // Linear interpolation (Fixed-point optimized)
159 void LinLerp1D(register const cmsUInt16Number Value
[],
160 register cmsUInt16Number Output
[],
161 register const cmsInterpParams
* p
)
163 cmsUInt16Number y1
, y0
;
166 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p
->Table
;
169 if (Value
[0] == 0xffff) {
171 Output
[0] = LutTable
[p
-> Domain
[0]];
175 val3
= p
-> Domain
[0] * Value
[0];
176 val3
= _cmsToFixedDomain(val3
); // To fixed 15.16
178 cell0
= FIXED_TO_INT(val3
); // Cell is 16 MSB bits
179 rest
= FIXED_REST_TO_INT(val3
); // Rest is 16 LSB bits
181 y0
= LutTable
[cell0
];
182 y1
= LutTable
[cell0
+1];
185 Output
[0] = LinearInterp(rest
, y0
, y1
);
189 // Floating-point version of 1D interpolation
191 void LinLerp1Dfloat(const cmsFloat32Number Value
[],
192 cmsFloat32Number Output
[],
193 const cmsInterpParams
* p
)
195 cmsFloat32Number y1
, y0
;
196 cmsFloat32Number val2
, rest
;
198 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
->Table
;
201 if (Value
[0] == 1.0) {
202 Output
[0] = LutTable
[p
-> Domain
[0]];
206 val2
= p
-> Domain
[0] * Value
[0];
208 cell0
= (int) floor(val2
);
209 cell1
= (int) ceil(val2
);
211 // Rest is 16 LSB bits
214 y0
= LutTable
[cell0
] ;
215 y1
= LutTable
[cell1
] ;
217 Output
[0] = y0
+ (y1
- y0
) * rest
;
222 // Eval gray LUT having only one input channel
224 void Eval1Input(register const cmsUInt16Number Input
[],
225 register cmsUInt16Number Output
[],
226 register const cmsInterpParams
* p16
)
228 cmsS15Fixed16Number fk
;
229 cmsS15Fixed16Number k0
, k1
, rk
, K0
, K1
;
231 cmsUInt32Number OutChan
;
232 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p16
-> Table
;
234 v
= Input
[0] * p16
-> Domain
[0];
235 fk
= _cmsToFixedDomain(v
);
237 k0
= FIXED_TO_INT(fk
);
238 rk
= (cmsUInt16Number
) FIXED_REST_TO_INT(fk
);
240 k1
= k0
+ (Input
[0] != 0xFFFFU
? 1 : 0);
242 K0
= p16
-> opta
[0] * k0
;
243 K1
= p16
-> opta
[0] * k1
;
245 for (OutChan
=0; OutChan
< p16
->nOutputs
; OutChan
++) {
247 Output
[OutChan
] = LinearInterp(rk
, LutTable
[K0
+OutChan
], LutTable
[K1
+OutChan
]);
253 // Eval gray LUT having only one input channel
255 void Eval1InputFloat(const cmsFloat32Number Value
[],
256 cmsFloat32Number Output
[],
257 const cmsInterpParams
* p
)
259 cmsFloat32Number y1
, y0
;
260 cmsFloat32Number val2
, rest
;
262 cmsUInt32Number OutChan
;
263 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
->Table
;
266 if (Value
[0] == 1.0) {
267 Output
[0] = LutTable
[p
-> Domain
[0]];
271 val2
= p
-> Domain
[0] * Value
[0];
273 cell0
= (int) floor(val2
);
274 cell1
= (int) ceil(val2
);
276 // Rest is 16 LSB bits
279 cell0
*= p
-> opta
[0];
280 cell1
*= p
-> opta
[0];
282 for (OutChan
=0; OutChan
< p
->nOutputs
; OutChan
++) {
284 y0
= LutTable
[cell0
+ OutChan
] ;
285 y1
= LutTable
[cell1
+ OutChan
] ;
287 Output
[OutChan
] = y0
+ (y1
- y0
) * rest
;
291 // Bilinear interpolation (16 bits) - cmsFloat32Number version
293 void BilinearInterpFloat(const cmsFloat32Number Input
[],
294 cmsFloat32Number Output
[],
295 const cmsInterpParams
* p
)
298 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
299 # define DENS(i,j) (LutTable[(i)+(j)+OutChan])
301 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
->Table
;
302 cmsFloat32Number px
, py
;
305 int TotalOut
, OutChan
;
306 cmsFloat32Number fx
, fy
,
311 TotalOut
= p
-> nOutputs
;
312 px
= Input
[0] * p
->Domain
[0];
313 py
= Input
[1] * p
->Domain
[1];
315 x0
= (int) _cmsQuickFloor(px
); fx
= px
- (cmsFloat32Number
) x0
;
316 y0
= (int) _cmsQuickFloor(py
); fy
= py
- (cmsFloat32Number
) y0
;
318 X0
= p
-> opta
[1] * x0
;
319 X1
= X0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[1]);
321 Y0
= p
-> opta
[0] * y0
;
322 Y1
= Y0
+ (Input
[1] >= 1.0 ? 0 : p
->opta
[0]);
324 for (OutChan
= 0; OutChan
< TotalOut
; OutChan
++) {
331 dx0
= LERP(fx
, d00
, d10
);
332 dx1
= LERP(fx
, d01
, d11
);
334 dxy
= LERP(fy
, dx0
, dx1
);
336 Output
[OutChan
] = dxy
;
344 // Bilinear interpolation (16 bits) - optimized version
346 void BilinearInterp16(register const cmsUInt16Number Input
[],
347 register cmsUInt16Number Output
[],
348 register const cmsInterpParams
* p
)
351 #define DENS(i,j) (LutTable[(i)+(j)+OutChan])
352 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
354 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p
->Table
;
355 int OutChan
, TotalOut
;
356 cmsS15Fixed16Number fx
, fy
;
359 register int X0
, X1
, Y0
, Y1
;
360 int d00
, d01
, d10
, d11
,
364 TotalOut
= p
-> nOutputs
;
366 fx
= _cmsToFixedDomain((int) Input
[0] * p
-> Domain
[0]);
367 x0
= FIXED_TO_INT(fx
);
368 rx
= FIXED_REST_TO_INT(fx
); // Rest in 0..1.0 domain
371 fy
= _cmsToFixedDomain((int) Input
[1] * p
-> Domain
[1]);
372 y0
= FIXED_TO_INT(fy
);
373 ry
= FIXED_REST_TO_INT(fy
);
376 X0
= p
-> opta
[1] * x0
;
377 X1
= X0
+ (Input
[0] == 0xFFFFU
? 0 : p
->opta
[1]);
379 Y0
= p
-> opta
[0] * y0
;
380 Y1
= Y0
+ (Input
[1] == 0xFFFFU
? 0 : p
->opta
[0]);
382 for (OutChan
= 0; OutChan
< TotalOut
; OutChan
++) {
389 dx0
= LERP(rx
, d00
, d10
);
390 dx1
= LERP(rx
, d01
, d11
);
392 dxy
= LERP(ry
, dx0
, dx1
);
394 Output
[OutChan
] = (cmsUInt16Number
) dxy
;
403 // Trilinear interpolation (16 bits) - cmsFloat32Number version
405 void TrilinearInterpFloat(const cmsFloat32Number Input
[],
406 cmsFloat32Number Output
[],
407 const cmsInterpParams
* p
)
410 # define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
411 # define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
413 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
->Table
;
414 cmsFloat32Number px
, py
, pz
;
416 X0
, Y0
, Z0
, X1
, Y1
, Z1
;
417 int TotalOut
, OutChan
;
418 cmsFloat32Number fx
, fy
, fz
,
419 d000
, d001
, d010
, d011
,
420 d100
, d101
, d110
, d111
,
421 dx00
, dx01
, dx10
, dx11
,
424 TotalOut
= p
-> nOutputs
;
426 // We need some clipping here
442 x0
= (int) _cmsQuickFloor(px
); fx
= px
- (cmsFloat32Number
) x0
;
443 y0
= (int) _cmsQuickFloor(py
); fy
= py
- (cmsFloat32Number
) y0
;
444 z0
= (int) _cmsQuickFloor(pz
); fz
= pz
- (cmsFloat32Number
) z0
;
446 X0
= p
-> opta
[2] * x0
;
447 X1
= X0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[2]);
449 Y0
= p
-> opta
[1] * y0
;
450 Y1
= Y0
+ (Input
[1] >= 1.0 ? 0 : p
->opta
[1]);
452 Z0
= p
-> opta
[0] * z0
;
453 Z1
= Z0
+ (Input
[2] >= 1.0 ? 0 : p
->opta
[0]);
455 for (OutChan
= 0; OutChan
< TotalOut
; OutChan
++) {
457 d000
= DENS(X0
, Y0
, Z0
);
458 d001
= DENS(X0
, Y0
, Z1
);
459 d010
= DENS(X0
, Y1
, Z0
);
460 d011
= DENS(X0
, Y1
, Z1
);
462 d100
= DENS(X1
, Y0
, Z0
);
463 d101
= DENS(X1
, Y0
, Z1
);
464 d110
= DENS(X1
, Y1
, Z0
);
465 d111
= DENS(X1
, Y1
, Z1
);
468 dx00
= LERP(fx
, d000
, d100
);
469 dx01
= LERP(fx
, d001
, d101
);
470 dx10
= LERP(fx
, d010
, d110
);
471 dx11
= LERP(fx
, d011
, d111
);
473 dxy0
= LERP(fy
, dx00
, dx10
);
474 dxy1
= LERP(fy
, dx01
, dx11
);
476 dxyz
= LERP(fz
, dxy0
, dxy1
);
478 Output
[OutChan
] = dxyz
;
486 // Trilinear interpolation (16 bits) - optimized version
488 void TrilinearInterp16(register const cmsUInt16Number Input
[],
489 register cmsUInt16Number Output
[],
490 register const cmsInterpParams
* p
)
493 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
494 #define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
496 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p
->Table
;
497 int OutChan
, TotalOut
;
498 cmsS15Fixed16Number fx
, fy
, fz
;
499 register int rx
, ry
, rz
;
501 register int X0
, X1
, Y0
, Y1
, Z0
, Z1
;
502 int d000
, d001
, d010
, d011
,
503 d100
, d101
, d110
, d111
,
504 dx00
, dx01
, dx10
, dx11
,
507 TotalOut
= p
-> nOutputs
;
509 fx
= _cmsToFixedDomain((int) Input
[0] * p
-> Domain
[0]);
510 x0
= FIXED_TO_INT(fx
);
511 rx
= FIXED_REST_TO_INT(fx
); // Rest in 0..1.0 domain
514 fy
= _cmsToFixedDomain((int) Input
[1] * p
-> Domain
[1]);
515 y0
= FIXED_TO_INT(fy
);
516 ry
= FIXED_REST_TO_INT(fy
);
518 fz
= _cmsToFixedDomain((int) Input
[2] * p
-> Domain
[2]);
519 z0
= FIXED_TO_INT(fz
);
520 rz
= FIXED_REST_TO_INT(fz
);
523 X0
= p
-> opta
[2] * x0
;
524 X1
= X0
+ (Input
[0] == 0xFFFFU
? 0 : p
->opta
[2]);
526 Y0
= p
-> opta
[1] * y0
;
527 Y1
= Y0
+ (Input
[1] == 0xFFFFU
? 0 : p
->opta
[1]);
529 Z0
= p
-> opta
[0] * z0
;
530 Z1
= Z0
+ (Input
[2] == 0xFFFFU
? 0 : p
->opta
[0]);
532 for (OutChan
= 0; OutChan
< TotalOut
; OutChan
++) {
534 d000
= DENS(X0
, Y0
, Z0
);
535 d001
= DENS(X0
, Y0
, Z1
);
536 d010
= DENS(X0
, Y1
, Z0
);
537 d011
= DENS(X0
, Y1
, Z1
);
539 d100
= DENS(X1
, Y0
, Z0
);
540 d101
= DENS(X1
, Y0
, Z1
);
541 d110
= DENS(X1
, Y1
, Z0
);
542 d111
= DENS(X1
, Y1
, Z1
);
545 dx00
= LERP(rx
, d000
, d100
);
546 dx01
= LERP(rx
, d001
, d101
);
547 dx10
= LERP(rx
, d010
, d110
);
548 dx11
= LERP(rx
, d011
, d111
);
550 dxy0
= LERP(ry
, dx00
, dx10
);
551 dxy1
= LERP(ry
, dx01
, dx11
);
553 dxyz
= LERP(rz
, dxy0
, dxy1
);
555 Output
[OutChan
] = (cmsUInt16Number
) dxyz
;
564 // Tetrahedral interpolation, using Sakamoto algorithm.
565 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
567 void TetrahedralInterpFloat(const cmsFloat32Number Input
[],
568 cmsFloat32Number Output
[],
569 const cmsInterpParams
* p
)
571 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
-> Table
;
572 cmsFloat32Number px
, py
, pz
;
574 X0
, Y0
, Z0
, X1
, Y1
, Z1
;
575 cmsFloat32Number rx
, ry
, rz
;
576 cmsFloat32Number c0
, c1
=0, c2
=0, c3
=0;
577 int OutChan
, TotalOut
;
579 TotalOut
= p
-> nOutputs
;
581 // We need some clipping here
597 x0
= (int) _cmsQuickFloor(px
); rx
= (px
- (cmsFloat32Number
) x0
);
598 y0
= (int) _cmsQuickFloor(py
); ry
= (py
- (cmsFloat32Number
) y0
);
599 z0
= (int) _cmsQuickFloor(pz
); rz
= (pz
- (cmsFloat32Number
) z0
);
602 X0
= p
-> opta
[2] * x0
;
603 X1
= X0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[2]);
605 Y0
= p
-> opta
[1] * y0
;
606 Y1
= Y0
+ (Input
[1] >= 1.0 ? 0 : p
->opta
[1]);
608 Z0
= p
-> opta
[0] * z0
;
609 Z1
= Z0
+ (Input
[2] >= 1.0 ? 0 : p
->opta
[0]);
611 for (OutChan
=0; OutChan
< TotalOut
; OutChan
++) {
613 // These are the 6 Tetrahedral
615 c0
= DENS(X0
, Y0
, Z0
);
617 if (rx
>= ry
&& ry
>= rz
) {
619 c1
= DENS(X1
, Y0
, Z0
) - c0
;
620 c2
= DENS(X1
, Y1
, Z0
) - DENS(X1
, Y0
, Z0
);
621 c3
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y1
, Z0
);
625 if (rx
>= rz
&& rz
>= ry
) {
627 c1
= DENS(X1
, Y0
, Z0
) - c0
;
628 c2
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y0
, Z1
);
629 c3
= DENS(X1
, Y0
, Z1
) - DENS(X1
, Y0
, Z0
);
633 if (rz
>= rx
&& rx
>= ry
) {
635 c1
= DENS(X1
, Y0
, Z1
) - DENS(X0
, Y0
, Z1
);
636 c2
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y0
, Z1
);
637 c3
= DENS(X0
, Y0
, Z1
) - c0
;
641 if (ry
>= rx
&& rx
>= rz
) {
643 c1
= DENS(X1
, Y1
, Z0
) - DENS(X0
, Y1
, Z0
);
644 c2
= DENS(X0
, Y1
, Z0
) - c0
;
645 c3
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y1
, Z0
);
649 if (ry
>= rz
&& rz
>= rx
) {
651 c1
= DENS(X1
, Y1
, Z1
) - DENS(X0
, Y1
, Z1
);
652 c2
= DENS(X0
, Y1
, Z0
) - c0
;
653 c3
= DENS(X0
, Y1
, Z1
) - DENS(X0
, Y1
, Z0
);
657 if (rz
>= ry
&& ry
>= rx
) {
659 c1
= DENS(X1
, Y1
, Z1
) - DENS(X0
, Y1
, Z1
);
660 c2
= DENS(X0
, Y1
, Z1
) - DENS(X0
, Y0
, Z1
);
661 c3
= DENS(X0
, Y0
, Z1
) - c0
;
668 Output
[OutChan
] = c0
+ c1
* rx
+ c2
* ry
+ c3
* rz
;
679 void TetrahedralInterp16(register const cmsUInt16Number Input
[],
680 register cmsUInt16Number Output
[],
681 register const cmsInterpParams
* p
)
683 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p
-> Table
;
684 cmsS15Fixed16Number fx
, fy
, fz
;
685 cmsS15Fixed16Number rx
, ry
, rz
;
687 cmsS15Fixed16Number c0
, c1
, c2
, c3
, Rest
;
688 cmsS15Fixed16Number X0
, X1
, Y0
, Y1
, Z0
, Z1
;
689 cmsUInt32Number TotalOut
= p
-> nOutputs
;
691 fx
= _cmsToFixedDomain((int) Input
[0] * p
-> Domain
[0]);
692 fy
= _cmsToFixedDomain((int) Input
[1] * p
-> Domain
[1]);
693 fz
= _cmsToFixedDomain((int) Input
[2] * p
-> Domain
[2]);
695 x0
= FIXED_TO_INT(fx
);
696 y0
= FIXED_TO_INT(fy
);
697 z0
= FIXED_TO_INT(fz
);
699 rx
= FIXED_REST_TO_INT(fx
);
700 ry
= FIXED_REST_TO_INT(fy
);
701 rz
= FIXED_REST_TO_INT(fz
);
703 X0
= p
-> opta
[2] * x0
;
704 X1
= (Input
[0] == 0xFFFFU
? 0 : p
->opta
[2]);
706 Y0
= p
-> opta
[1] * y0
;
707 Y1
= (Input
[1] == 0xFFFFU
? 0 : p
->opta
[1]);
709 Z0
= p
-> opta
[0] * z0
;
710 Z1
= (Input
[2] == 0xFFFFU
? 0 : p
->opta
[0]);
712 LutTable
= &LutTable
[X0
+Y0
+Z0
];
714 // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))
715 // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16
716 // This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16
717 // at the cost of being off by one at 7fff and 17ffe.
723 for (; TotalOut
; TotalOut
--) {
731 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
+ 0x8001;
732 *Output
++ = (cmsUInt16Number
) c0
+ ((Rest
+ (Rest
>>16))>>16);
734 } else if (rz
>= rx
) {
737 for (; TotalOut
; TotalOut
--) {
745 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
+ 0x8001;
746 *Output
++ = (cmsUInt16Number
) c0
+ ((Rest
+ (Rest
>>16))>>16);
751 for (; TotalOut
; TotalOut
--) {
759 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
+ 0x8001;
760 *Output
++ = (cmsUInt16Number
) c0
+ ((Rest
+ (Rest
>>16))>>16);
767 for (; TotalOut
; TotalOut
--) {
775 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
+ 0x8001;
776 *Output
++ = (cmsUInt16Number
) c0
+ ((Rest
+ (Rest
>>16))>>16);
778 } else if (ry
>= rz
) {
781 for (; TotalOut
; TotalOut
--) {
789 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
+ 0x8001;
790 *Output
++ = (cmsUInt16Number
) c0
+ ((Rest
+ (Rest
>>16))>>16);
795 for (; TotalOut
; TotalOut
--) {
803 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
+ 0x8001;
804 *Output
++ = (cmsUInt16Number
) c0
+ ((Rest
+ (Rest
>>16))>>16);
811 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
813 void Eval4Inputs(register const cmsUInt16Number Input
[],
814 register cmsUInt16Number Output
[],
815 register const cmsInterpParams
* p16
)
817 const cmsUInt16Number
* LutTable
;
818 cmsS15Fixed16Number fk
;
819 cmsS15Fixed16Number k0
, rk
;
821 cmsS15Fixed16Number fx
, fy
, fz
;
822 cmsS15Fixed16Number rx
, ry
, rz
;
824 cmsS15Fixed16Number X0
, X1
, Y0
, Y1
, Z0
, Z1
;
826 cmsS15Fixed16Number c0
, c1
, c2
, c3
, Rest
;
827 cmsUInt32Number OutChan
;
828 cmsUInt16Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
831 fk
= _cmsToFixedDomain((int) Input
[0] * p16
-> Domain
[0]);
832 fx
= _cmsToFixedDomain((int) Input
[1] * p16
-> Domain
[1]);
833 fy
= _cmsToFixedDomain((int) Input
[2] * p16
-> Domain
[2]);
834 fz
= _cmsToFixedDomain((int) Input
[3] * p16
-> Domain
[3]);
836 k0
= FIXED_TO_INT(fk
);
837 x0
= FIXED_TO_INT(fx
);
838 y0
= FIXED_TO_INT(fy
);
839 z0
= FIXED_TO_INT(fz
);
841 rk
= FIXED_REST_TO_INT(fk
);
842 rx
= FIXED_REST_TO_INT(fx
);
843 ry
= FIXED_REST_TO_INT(fy
);
844 rz
= FIXED_REST_TO_INT(fz
);
846 K0
= p16
-> opta
[3] * k0
;
847 K1
= K0
+ (Input
[0] == 0xFFFFU
? 0 : p16
->opta
[3]);
849 X0
= p16
-> opta
[2] * x0
;
850 X1
= X0
+ (Input
[1] == 0xFFFFU
? 0 : p16
->opta
[2]);
852 Y0
= p16
-> opta
[1] * y0
;
853 Y1
= Y0
+ (Input
[2] == 0xFFFFU
? 0 : p16
->opta
[1]);
855 Z0
= p16
-> opta
[0] * z0
;
856 Z1
= Z0
+ (Input
[3] == 0xFFFFU
? 0 : p16
->opta
[0]);
858 LutTable
= (cmsUInt16Number
*) p16
-> Table
;
861 for (OutChan
=0; OutChan
< p16
-> nOutputs
; OutChan
++) {
863 c0
= DENS(X0
, Y0
, Z0
);
865 if (rx
>= ry
&& ry
>= rz
) {
867 c1
= DENS(X1
, Y0
, Z0
) - c0
;
868 c2
= DENS(X1
, Y1
, Z0
) - DENS(X1
, Y0
, Z0
);
869 c3
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y1
, Z0
);
873 if (rx
>= rz
&& rz
>= ry
) {
875 c1
= DENS(X1
, Y0
, Z0
) - c0
;
876 c2
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y0
, Z1
);
877 c3
= DENS(X1
, Y0
, Z1
) - DENS(X1
, Y0
, Z0
);
881 if (rz
>= rx
&& rx
>= ry
) {
883 c1
= DENS(X1
, Y0
, Z1
) - DENS(X0
, Y0
, Z1
);
884 c2
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y0
, Z1
);
885 c3
= DENS(X0
, Y0
, Z1
) - c0
;
889 if (ry
>= rx
&& rx
>= rz
) {
891 c1
= DENS(X1
, Y1
, Z0
) - DENS(X0
, Y1
, Z0
);
892 c2
= DENS(X0
, Y1
, Z0
) - c0
;
893 c3
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y1
, Z0
);
897 if (ry
>= rz
&& rz
>= rx
) {
899 c1
= DENS(X1
, Y1
, Z1
) - DENS(X0
, Y1
, Z1
);
900 c2
= DENS(X0
, Y1
, Z0
) - c0
;
901 c3
= DENS(X0
, Y1
, Z1
) - DENS(X0
, Y1
, Z0
);
905 if (rz
>= ry
&& ry
>= rx
) {
907 c1
= DENS(X1
, Y1
, Z1
) - DENS(X0
, Y1
, Z1
);
908 c2
= DENS(X0
, Y1
, Z1
) - DENS(X0
, Y0
, Z1
);
909 c3
= DENS(X0
, Y0
, Z1
) - c0
;
916 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
;
918 Tmp1
[OutChan
] = (cmsUInt16Number
) c0
+ ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest
));
922 LutTable
= (cmsUInt16Number
*) p16
-> Table
;
925 for (OutChan
=0; OutChan
< p16
-> nOutputs
; OutChan
++) {
927 c0
= DENS(X0
, Y0
, Z0
);
929 if (rx
>= ry
&& ry
>= rz
) {
931 c1
= DENS(X1
, Y0
, Z0
) - c0
;
932 c2
= DENS(X1
, Y1
, Z0
) - DENS(X1
, Y0
, Z0
);
933 c3
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y1
, Z0
);
937 if (rx
>= rz
&& rz
>= ry
) {
939 c1
= DENS(X1
, Y0
, Z0
) - c0
;
940 c2
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y0
, Z1
);
941 c3
= DENS(X1
, Y0
, Z1
) - DENS(X1
, Y0
, Z0
);
945 if (rz
>= rx
&& rx
>= ry
) {
947 c1
= DENS(X1
, Y0
, Z1
) - DENS(X0
, Y0
, Z1
);
948 c2
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y0
, Z1
);
949 c3
= DENS(X0
, Y0
, Z1
) - c0
;
953 if (ry
>= rx
&& rx
>= rz
) {
955 c1
= DENS(X1
, Y1
, Z0
) - DENS(X0
, Y1
, Z0
);
956 c2
= DENS(X0
, Y1
, Z0
) - c0
;
957 c3
= DENS(X1
, Y1
, Z1
) - DENS(X1
, Y1
, Z0
);
961 if (ry
>= rz
&& rz
>= rx
) {
963 c1
= DENS(X1
, Y1
, Z1
) - DENS(X0
, Y1
, Z1
);
964 c2
= DENS(X0
, Y1
, Z0
) - c0
;
965 c3
= DENS(X0
, Y1
, Z1
) - DENS(X0
, Y1
, Z0
);
969 if (rz
>= ry
&& ry
>= rx
) {
971 c1
= DENS(X1
, Y1
, Z1
) - DENS(X0
, Y1
, Z1
);
972 c2
= DENS(X0
, Y1
, Z1
) - DENS(X0
, Y0
, Z1
);
973 c3
= DENS(X0
, Y0
, Z1
) - c0
;
980 Rest
= c1
* rx
+ c2
* ry
+ c3
* rz
;
982 Tmp2
[OutChan
] = (cmsUInt16Number
) c0
+ ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest
));
987 for (i
=0; i
< p16
-> nOutputs
; i
++) {
988 Output
[i
] = LinearInterp(rk
, Tmp1
[i
], Tmp2
[i
]);
994 // For more that 3 inputs (i.e., CMYK)
995 // evaluate two 3-dimensional interpolations and then linearly interpolate between them.
999 void Eval4InputsFloat(const cmsFloat32Number Input
[],
1000 cmsFloat32Number Output
[],
1001 const cmsInterpParams
* p
)
1003 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
-> Table
;
1004 cmsFloat32Number rest
;
1005 cmsFloat32Number pk
;
1007 const cmsFloat32Number
* T
;
1009 cmsFloat32Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1013 pk
= Input
[0] * p
->Domain
[0];
1014 k0
= _cmsQuickFloor(pk
);
1015 rest
= pk
- (cmsFloat32Number
) k0
;
1017 K0
= p
-> opta
[3] * k0
;
1018 K1
= K0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[3]);
1021 memmove(&p1
.Domain
[0], &p
->Domain
[1], 3*sizeof(cmsUInt32Number
));
1026 TetrahedralInterpFloat(Input
+ 1, Tmp1
, &p1
);
1030 TetrahedralInterpFloat(Input
+ 1, Tmp2
, &p1
);
1032 for (i
=0; i
< p
-> nOutputs
; i
++)
1034 cmsFloat32Number y0
= Tmp1
[i
];
1035 cmsFloat32Number y1
= Tmp2
[i
];
1037 Output
[i
] = y0
+ (y1
- y0
) * rest
;
1043 void Eval5Inputs(register const cmsUInt16Number Input
[],
1044 register cmsUInt16Number Output
[],
1046 register const cmsInterpParams
* p16
)
1048 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p16
-> Table
;
1049 cmsS15Fixed16Number fk
;
1050 cmsS15Fixed16Number k0
, rk
;
1052 const cmsUInt16Number
* T
;
1054 cmsUInt16Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1058 fk
= _cmsToFixedDomain((cmsS15Fixed16Number
) Input
[0] * p16
-> Domain
[0]);
1059 k0
= FIXED_TO_INT(fk
);
1060 rk
= FIXED_REST_TO_INT(fk
);
1062 K0
= p16
-> opta
[4] * k0
;
1063 K1
= p16
-> opta
[4] * (k0
+ (Input
[0] != 0xFFFFU
? 1 : 0));
1066 memmove(&p1
.Domain
[0], &p16
->Domain
[1], 4*sizeof(cmsUInt32Number
));
1071 Eval4Inputs(Input
+ 1, Tmp1
, &p1
);
1076 Eval4Inputs(Input
+ 1, Tmp2
, &p1
);
1078 for (i
=0; i
< p16
-> nOutputs
; i
++) {
1080 Output
[i
] = LinearInterp(rk
, Tmp1
[i
], Tmp2
[i
]);
1087 void Eval5InputsFloat(const cmsFloat32Number Input
[],
1088 cmsFloat32Number Output
[],
1089 const cmsInterpParams
* p
)
1091 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
-> Table
;
1092 cmsFloat32Number rest
;
1093 cmsFloat32Number pk
;
1095 const cmsFloat32Number
* T
;
1097 cmsFloat32Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1100 pk
= Input
[0] * p
->Domain
[0];
1101 k0
= _cmsQuickFloor(pk
);
1102 rest
= pk
- (cmsFloat32Number
) k0
;
1104 K0
= p
-> opta
[4] * k0
;
1105 K1
= K0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[4]);
1108 memmove(&p1
.Domain
[0], &p
->Domain
[1], 4*sizeof(cmsUInt32Number
));
1113 Eval4InputsFloat(Input
+ 1, Tmp1
, &p1
);
1118 Eval4InputsFloat(Input
+ 1, Tmp2
, &p1
);
1120 for (i
=0; i
< p
-> nOutputs
; i
++) {
1122 cmsFloat32Number y0
= Tmp1
[i
];
1123 cmsFloat32Number y1
= Tmp2
[i
];
1125 Output
[i
] = y0
+ (y1
- y0
) * rest
;
1132 void Eval6Inputs(register const cmsUInt16Number Input
[],
1133 register cmsUInt16Number Output
[],
1134 register const cmsInterpParams
* p16
)
1136 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p16
-> Table
;
1137 cmsS15Fixed16Number fk
;
1138 cmsS15Fixed16Number k0
, rk
;
1140 const cmsUInt16Number
* T
;
1142 cmsUInt16Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1145 fk
= _cmsToFixedDomain((cmsS15Fixed16Number
) Input
[0] * p16
-> Domain
[0]);
1146 k0
= FIXED_TO_INT(fk
);
1147 rk
= FIXED_REST_TO_INT(fk
);
1149 K0
= p16
-> opta
[5] * k0
;
1150 K1
= p16
-> opta
[5] * (k0
+ (Input
[0] != 0xFFFFU
? 1 : 0));
1153 memmove(&p1
.Domain
[0], &p16
->Domain
[1], 5*sizeof(cmsUInt32Number
));
1158 Eval5Inputs(Input
+ 1, Tmp1
, &p1
);
1163 Eval5Inputs(Input
+ 1, Tmp2
, &p1
);
1165 for (i
=0; i
< p16
-> nOutputs
; i
++) {
1167 Output
[i
] = LinearInterp(rk
, Tmp1
[i
], Tmp2
[i
]);
1174 void Eval6InputsFloat(const cmsFloat32Number Input
[],
1175 cmsFloat32Number Output
[],
1176 const cmsInterpParams
* p
)
1178 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
-> Table
;
1179 cmsFloat32Number rest
;
1180 cmsFloat32Number pk
;
1182 const cmsFloat32Number
* T
;
1184 cmsFloat32Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1187 pk
= Input
[0] * p
->Domain
[0];
1188 k0
= _cmsQuickFloor(pk
);
1189 rest
= pk
- (cmsFloat32Number
) k0
;
1191 K0
= p
-> opta
[5] * k0
;
1192 K1
= K0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[5]);
1195 memmove(&p1
.Domain
[0], &p
->Domain
[1], 5*sizeof(cmsUInt32Number
));
1200 Eval5InputsFloat(Input
+ 1, Tmp1
, &p1
);
1205 Eval5InputsFloat(Input
+ 1, Tmp2
, &p1
);
1207 for (i
=0; i
< p
-> nOutputs
; i
++) {
1209 cmsFloat32Number y0
= Tmp1
[i
];
1210 cmsFloat32Number y1
= Tmp2
[i
];
1212 Output
[i
] = y0
+ (y1
- y0
) * rest
;
1218 void Eval7Inputs(register const cmsUInt16Number Input
[],
1219 register cmsUInt16Number Output
[],
1220 register const cmsInterpParams
* p16
)
1222 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p16
-> Table
;
1223 cmsS15Fixed16Number fk
;
1224 cmsS15Fixed16Number k0
, rk
;
1226 const cmsUInt16Number
* T
;
1228 cmsUInt16Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1232 fk
= _cmsToFixedDomain((cmsS15Fixed16Number
) Input
[0] * p16
-> Domain
[0]);
1233 k0
= FIXED_TO_INT(fk
);
1234 rk
= FIXED_REST_TO_INT(fk
);
1236 K0
= p16
-> opta
[6] * k0
;
1237 K1
= p16
-> opta
[6] * (k0
+ (Input
[0] != 0xFFFFU
? 1 : 0));
1240 memmove(&p1
.Domain
[0], &p16
->Domain
[1], 6*sizeof(cmsUInt32Number
));
1245 Eval6Inputs(Input
+ 1, Tmp1
, &p1
);
1250 Eval6Inputs(Input
+ 1, Tmp2
, &p1
);
1252 for (i
=0; i
< p16
-> nOutputs
; i
++) {
1253 Output
[i
] = LinearInterp(rk
, Tmp1
[i
], Tmp2
[i
]);
1259 void Eval7InputsFloat(const cmsFloat32Number Input
[],
1260 cmsFloat32Number Output
[],
1261 const cmsInterpParams
* p
)
1263 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
-> Table
;
1264 cmsFloat32Number rest
;
1265 cmsFloat32Number pk
;
1267 const cmsFloat32Number
* T
;
1269 cmsFloat32Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1272 pk
= Input
[0] * p
->Domain
[0];
1273 k0
= _cmsQuickFloor(pk
);
1274 rest
= pk
- (cmsFloat32Number
) k0
;
1276 K0
= p
-> opta
[6] * k0
;
1277 K1
= K0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[6]);
1280 memmove(&p1
.Domain
[0], &p
->Domain
[1], 6*sizeof(cmsUInt32Number
));
1285 Eval6InputsFloat(Input
+ 1, Tmp1
, &p1
);
1290 Eval6InputsFloat(Input
+ 1, Tmp2
, &p1
);
1293 for (i
=0; i
< p
-> nOutputs
; i
++) {
1295 cmsFloat32Number y0
= Tmp1
[i
];
1296 cmsFloat32Number y1
= Tmp2
[i
];
1298 Output
[i
] = y0
+ (y1
- y0
) * rest
;
1304 void Eval8Inputs(register const cmsUInt16Number Input
[],
1305 register cmsUInt16Number Output
[],
1306 register const cmsInterpParams
* p16
)
1308 const cmsUInt16Number
* LutTable
= (cmsUInt16Number
*) p16
-> Table
;
1309 cmsS15Fixed16Number fk
;
1310 cmsS15Fixed16Number k0
, rk
;
1312 const cmsUInt16Number
* T
;
1314 cmsUInt16Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1317 fk
= _cmsToFixedDomain((cmsS15Fixed16Number
) Input
[0] * p16
-> Domain
[0]);
1318 k0
= FIXED_TO_INT(fk
);
1319 rk
= FIXED_REST_TO_INT(fk
);
1321 K0
= p16
-> opta
[7] * k0
;
1322 K1
= p16
-> opta
[7] * (k0
+ (Input
[0] != 0xFFFFU
? 1 : 0));
1325 memmove(&p1
.Domain
[0], &p16
->Domain
[1], 7*sizeof(cmsUInt32Number
));
1330 Eval7Inputs(Input
+ 1, Tmp1
, &p1
);
1334 Eval7Inputs(Input
+ 1, Tmp2
, &p1
);
1336 for (i
=0; i
< p16
-> nOutputs
; i
++) {
1337 Output
[i
] = LinearInterp(rk
, Tmp1
[i
], Tmp2
[i
]);
1344 void Eval8InputsFloat(const cmsFloat32Number Input
[],
1345 cmsFloat32Number Output
[],
1346 const cmsInterpParams
* p
)
1348 const cmsFloat32Number
* LutTable
= (cmsFloat32Number
*) p
-> Table
;
1349 cmsFloat32Number rest
;
1350 cmsFloat32Number pk
;
1352 const cmsFloat32Number
* T
;
1354 cmsFloat32Number Tmp1
[MAX_STAGE_CHANNELS
], Tmp2
[MAX_STAGE_CHANNELS
];
1357 pk
= Input
[0] * p
->Domain
[0];
1358 k0
= _cmsQuickFloor(pk
);
1359 rest
= pk
- (cmsFloat32Number
) k0
;
1361 K0
= p
-> opta
[7] * k0
;
1362 K1
= K0
+ (Input
[0] >= 1.0 ? 0 : p
->opta
[7]);
1365 memmove(&p1
.Domain
[0], &p
->Domain
[1], 7*sizeof(cmsUInt32Number
));
1370 Eval7InputsFloat(Input
+ 1, Tmp1
, &p1
);
1375 Eval7InputsFloat(Input
+ 1, Tmp2
, &p1
);
1378 for (i
=0; i
< p
-> nOutputs
; i
++) {
1380 cmsFloat32Number y0
= Tmp1
[i
];
1381 cmsFloat32Number y1
= Tmp2
[i
];
1383 Output
[i
] = y0
+ (y1
- y0
) * rest
;
1387 // The default factory
1389 cmsInterpFunction
DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels
, cmsUInt32Number nOutputChannels
, cmsUInt32Number dwFlags
)
1392 cmsInterpFunction Interpolation
;
1393 cmsBool IsFloat
= (dwFlags
& CMS_LERP_FLAGS_FLOAT
);
1394 cmsBool IsTrilinear
= (dwFlags
& CMS_LERP_FLAGS_TRILINEAR
);
1396 memset(&Interpolation
, 0, sizeof(Interpolation
));
1399 if (nInputChannels
>= 4 && nOutputChannels
>= MAX_STAGE_CHANNELS
)
1400 return Interpolation
;
1402 switch (nInputChannels
) {
1404 case 1: // Gray LUT / linear
1406 if (nOutputChannels
== 1) {
1409 Interpolation
.LerpFloat
= LinLerp1Dfloat
;
1411 Interpolation
.Lerp16
= LinLerp1D
;
1417 Interpolation
.LerpFloat
= Eval1InputFloat
;
1419 Interpolation
.Lerp16
= Eval1Input
;
1425 Interpolation
.LerpFloat
= BilinearInterpFloat
;
1427 Interpolation
.Lerp16
= BilinearInterp16
;
1430 case 3: // RGB et al
1435 Interpolation
.LerpFloat
= TrilinearInterpFloat
;
1437 Interpolation
.Lerp16
= TrilinearInterp16
;
1442 Interpolation
.LerpFloat
= TetrahedralInterpFloat
;
1445 Interpolation
.Lerp16
= TetrahedralInterp16
;
1453 Interpolation
.LerpFloat
= Eval4InputsFloat
;
1455 Interpolation
.Lerp16
= Eval4Inputs
;
1460 Interpolation
.LerpFloat
= Eval5InputsFloat
;
1462 Interpolation
.Lerp16
= Eval5Inputs
;
1467 Interpolation
.LerpFloat
= Eval6InputsFloat
;
1469 Interpolation
.Lerp16
= Eval6Inputs
;
1474 Interpolation
.LerpFloat
= Eval7InputsFloat
;
1476 Interpolation
.Lerp16
= Eval7Inputs
;
1481 Interpolation
.LerpFloat
= Eval8InputsFloat
;
1483 Interpolation
.Lerp16
= Eval8Inputs
;
1489 Interpolation
.Lerp16
= NULL
;
1492 return Interpolation
;