Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/lcms2/src/cmsintrp.c
4391 views
1
//---------------------------------------------------------------------------------
2
//
3
// Little Color Management System
4
// Copyright (c) 1998-2024 Marti Maria Saguer
5
//
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:
12
//
13
// The above copyright notice and this permission notice shall be included in
14
// all copies or substantial portions of the Software.
15
//
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.
23
//
24
//---------------------------------------------------------------------------------
25
//
26
27
#include "lcms2_internal.h"
28
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
31
32
// Some people may want to compile as C++ with all warnings on, in this case make compiler silent
33
#ifdef _MSC_VER
34
# if (_MSC_VER >= 1400)
35
# pragma warning( disable : 4365 )
36
# endif
37
#endif
38
39
// Interpolation routines by default
40
static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
41
42
// This is the default factory
43
_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL };
44
45
// The interpolation plug-in memory chunk allocator/dup
46
void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)
47
{
48
void* from;
49
50
_cmsAssert(ctx != NULL);
51
52
if (src != NULL) {
53
from = src ->chunks[InterpPlugin];
54
}
55
else {
56
static _cmsInterpPluginChunkType InterpPluginChunk = { NULL };
57
58
from = &InterpPluginChunk;
59
}
60
61
_cmsAssert(from != NULL);
62
ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType));
63
}
64
65
66
// Main plug-in entry
67
cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data)
68
{
69
cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
70
_cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
71
72
if (Data == NULL) {
73
74
ptr ->Interpolators = NULL;
75
return TRUE;
76
}
77
78
// Set replacement functions
79
ptr ->Interpolators = Plugin ->InterpolatorsFactory;
80
return TRUE;
81
}
82
83
84
// Set the interpolation method
85
cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)
86
{
87
_cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
88
89
p ->Interpolation.Lerp16 = NULL;
90
91
// Invoke factory, possibly in the Plug-in
92
if (ptr ->Interpolators != NULL)
93
p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
94
95
// If unsupported by the plug-in, go for the LittleCMS default.
96
// If happens only if an extern plug-in is being used
97
if (p ->Interpolation.Lerp16 == NULL)
98
p ->Interpolation = DefaultInterpolatorsFactory(p ->nInputs, p ->nOutputs, p ->dwFlags);
99
100
// Check for valid interpolator (we just check one member of the union)
101
if (p ->Interpolation.Lerp16 == NULL) {
102
return FALSE;
103
}
104
105
return TRUE;
106
}
107
108
109
// This function precalculates as many parameters as possible to speed up the interpolation.
110
cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
111
const cmsUInt32Number nSamples[],
112
cmsUInt32Number InputChan, cmsUInt32Number OutputChan,
113
const void *Table,
114
cmsUInt32Number dwFlags)
115
{
116
cmsInterpParams* p;
117
cmsUInt32Number i;
118
119
// Check for maximum inputs
120
if (InputChan > MAX_INPUT_DIMENSIONS) {
121
cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", InputChan, MAX_INPUT_DIMENSIONS);
122
return NULL;
123
}
124
125
// Creates an empty object
126
p = (cmsInterpParams*) _cmsMallocZero(ContextID, sizeof(cmsInterpParams));
127
if (p == NULL) return NULL;
128
129
// Keep original parameters
130
p -> dwFlags = dwFlags;
131
p -> nInputs = InputChan;
132
p -> nOutputs = OutputChan;
133
p ->Table = Table;
134
p ->ContextID = ContextID;
135
136
// Fill samples per input direction and domain (which is number of nodes minus one)
137
for (i=0; i < InputChan; i++) {
138
139
p -> nSamples[i] = nSamples[i];
140
p -> Domain[i] = nSamples[i] - 1;
141
}
142
143
// Compute factors to apply to each component to index the grid array
144
p -> opta[0] = p -> nOutputs;
145
for (i=1; i < InputChan; i++)
146
p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
147
148
149
if (!_cmsSetInterpolationRoutine(ContextID, p)) {
150
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
151
_cmsFree(ContextID, p);
152
return NULL;
153
}
154
155
// All seems ok
156
return p;
157
}
158
159
160
// This one is a wrapper on the anterior, but assuming all directions have same number of nodes
161
cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples,
162
cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags)
163
{
164
int i;
165
cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
166
167
// Fill the auxiliary array
168
for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
169
Samples[i] = nSamples;
170
171
// Call the extended function
172
return _cmsComputeInterpParamsEx(ContextID, Samples, InputChan, OutputChan, Table, dwFlags);
173
}
174
175
176
// Free all associated memory
177
void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p)
178
{
179
if (p != NULL) _cmsFree(p ->ContextID, p);
180
}
181
182
183
// Inline fixed point interpolation
184
cmsINLINE CMS_NO_SANITIZE cmsUInt16Number LinearInterp(cmsS15Fixed16Number a, cmsS15Fixed16Number l, cmsS15Fixed16Number h)
185
{
186
cmsUInt32Number dif = (cmsUInt32Number) (h - l) * a + 0x8000;
187
dif = (dif >> 16) + l;
188
return (cmsUInt16Number) (dif);
189
}
190
191
192
// Linear interpolation (Fixed-point optimized)
193
static
194
void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],
195
CMSREGISTER cmsUInt16Number Output[],
196
CMSREGISTER const cmsInterpParams* p)
197
{
198
cmsUInt16Number y1, y0;
199
int cell0, rest;
200
int val3;
201
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
202
203
// if last value or just one point
204
if (Value[0] == 0xffff || p->Domain[0] == 0) {
205
206
Output[0] = LutTable[p -> Domain[0]];
207
}
208
else
209
{
210
val3 = p->Domain[0] * Value[0];
211
val3 = _cmsToFixedDomain(val3); // To fixed 15.16
212
213
cell0 = FIXED_TO_INT(val3); // Cell is 16 MSB bits
214
rest = FIXED_REST_TO_INT(val3); // Rest is 16 LSB bits
215
216
y0 = LutTable[cell0];
217
y1 = LutTable[cell0 + 1];
218
219
Output[0] = LinearInterp(rest, y0, y1);
220
}
221
}
222
223
// To prevent out of bounds indexing
224
cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v)
225
{
226
return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v);
227
}
228
229
// Floating-point version of 1D interpolation
230
static
231
void LinLerp1Dfloat(const cmsFloat32Number Value[],
232
cmsFloat32Number Output[],
233
const cmsInterpParams* p)
234
{
235
cmsFloat32Number y1, y0;
236
cmsFloat32Number val2, rest;
237
int cell0, cell1;
238
const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
239
240
val2 = fclamp(Value[0]);
241
242
// if last value...
243
if (val2 == 1.0 || p->Domain[0] == 0) {
244
Output[0] = LutTable[p -> Domain[0]];
245
}
246
else
247
{
248
val2 *= p->Domain[0];
249
250
cell0 = (int)floor(val2);
251
cell1 = (int)ceil(val2);
252
253
// Rest is 16 LSB bits
254
rest = val2 - cell0;
255
256
y0 = LutTable[cell0];
257
y1 = LutTable[cell1];
258
259
Output[0] = y0 + (y1 - y0) * rest;
260
}
261
}
262
263
264
265
// Eval gray LUT having only one input channel
266
static CMS_NO_SANITIZE
267
void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],
268
CMSREGISTER cmsUInt16Number Output[],
269
CMSREGISTER const cmsInterpParams* p16)
270
{
271
cmsS15Fixed16Number fk;
272
cmsS15Fixed16Number k0, k1, rk, K0, K1;
273
int v;
274
cmsUInt32Number OutChan;
275
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
276
277
278
// if last value...
279
if (Input[0] == 0xffff || p16->Domain[0] == 0) {
280
281
cmsUInt32Number y0 = p16->Domain[0] * p16->opta[0];
282
283
for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
284
Output[OutChan] = LutTable[y0 + OutChan];
285
}
286
}
287
else
288
{
289
290
v = Input[0] * p16->Domain[0];
291
fk = _cmsToFixedDomain(v);
292
293
k0 = FIXED_TO_INT(fk);
294
rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
295
296
k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
297
298
K0 = p16->opta[0] * k0;
299
K1 = p16->opta[0] * k1;
300
301
for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
302
303
Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
304
}
305
}
306
}
307
308
309
310
// Eval gray LUT having only one input channel
311
static
312
void Eval1InputFloat(const cmsFloat32Number Value[],
313
cmsFloat32Number Output[],
314
const cmsInterpParams* p)
315
{
316
cmsFloat32Number y1, y0;
317
cmsFloat32Number val2, rest;
318
int cell0, cell1;
319
cmsUInt32Number OutChan;
320
const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
321
322
val2 = fclamp(Value[0]);
323
324
// if last value...
325
if (val2 == 1.0 || p->Domain[0] == 0) {
326
327
cmsUInt32Number start = p->Domain[0] * p->opta[0];
328
329
for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
330
Output[OutChan] = LutTable[start + OutChan];
331
}
332
}
333
else
334
{
335
val2 *= p->Domain[0];
336
337
cell0 = (int)floor(val2);
338
cell1 = (int)ceil(val2);
339
340
// Rest is 16 LSB bits
341
rest = val2 - cell0;
342
343
cell0 *= p->opta[0];
344
cell1 *= p->opta[0];
345
346
for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
347
348
y0 = LutTable[cell0 + OutChan];
349
y1 = LutTable[cell1 + OutChan];
350
351
Output[OutChan] = y0 + (y1 - y0) * rest;
352
}
353
}
354
}
355
356
// Bilinear interpolation (16 bits) - cmsFloat32Number version
357
static
358
void BilinearInterpFloat(const cmsFloat32Number Input[],
359
cmsFloat32Number Output[],
360
const cmsInterpParams* p)
361
362
{
363
# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
364
# define DENS(i,j) (LutTable[(i)+(j)+OutChan])
365
366
const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
367
cmsFloat32Number px, py;
368
int x0, y0,
369
X0, Y0, X1, Y1;
370
int TotalOut, OutChan;
371
cmsFloat32Number fx, fy,
372
d00, d01, d10, d11,
373
dx0, dx1,
374
dxy;
375
376
TotalOut = p -> nOutputs;
377
px = fclamp(Input[0]) * p->Domain[0];
378
py = fclamp(Input[1]) * p->Domain[1];
379
380
x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
381
y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
382
383
X0 = p -> opta[1] * x0;
384
X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[1]);
385
386
Y0 = p -> opta[0] * y0;
387
Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[0]);
388
389
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
390
391
d00 = DENS(X0, Y0);
392
d01 = DENS(X0, Y1);
393
d10 = DENS(X1, Y0);
394
d11 = DENS(X1, Y1);
395
396
dx0 = LERP(fx, d00, d10);
397
dx1 = LERP(fx, d01, d11);
398
399
dxy = LERP(fy, dx0, dx1);
400
401
Output[OutChan] = dxy;
402
}
403
404
405
# undef LERP
406
# undef DENS
407
}
408
409
// Bilinear interpolation (16 bits) - optimized version
410
static CMS_NO_SANITIZE
411
void BilinearInterp16(CMSREGISTER const cmsUInt16Number Input[],
412
CMSREGISTER cmsUInt16Number Output[],
413
CMSREGISTER const cmsInterpParams* p)
414
415
{
416
#define DENS(i,j) (LutTable[(i)+(j)+OutChan])
417
#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
418
419
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
420
int OutChan, TotalOut;
421
cmsS15Fixed16Number fx, fy;
422
CMSREGISTER int rx, ry;
423
int x0, y0;
424
CMSREGISTER int X0, X1, Y0, Y1;
425
426
int d00, d01, d10, d11,
427
dx0, dx1,
428
dxy;
429
430
TotalOut = p -> nOutputs;
431
432
fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
433
x0 = FIXED_TO_INT(fx);
434
rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
435
436
437
fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
438
y0 = FIXED_TO_INT(fy);
439
ry = FIXED_REST_TO_INT(fy);
440
441
442
X0 = p -> opta[1] * x0;
443
X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[1]);
444
445
Y0 = p -> opta[0] * y0;
446
Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[0]);
447
448
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
449
450
d00 = DENS(X0, Y0);
451
d01 = DENS(X0, Y1);
452
d10 = DENS(X1, Y0);
453
d11 = DENS(X1, Y1);
454
455
dx0 = LERP(rx, d00, d10);
456
dx1 = LERP(rx, d01, d11);
457
458
dxy = LERP(ry, dx0, dx1);
459
460
Output[OutChan] = (cmsUInt16Number) dxy;
461
}
462
463
464
# undef LERP
465
# undef DENS
466
}
467
468
469
// Trilinear interpolation (16 bits) - cmsFloat32Number version
470
static
471
void TrilinearInterpFloat(const cmsFloat32Number Input[],
472
cmsFloat32Number Output[],
473
const cmsInterpParams* p)
474
475
{
476
# define LERP(a,l,h) (cmsFloat32Number) ((l)+(((h)-(l))*(a)))
477
# define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
478
479
const cmsFloat32Number* LutTable = (cmsFloat32Number*) p ->Table;
480
cmsFloat32Number px, py, pz;
481
int x0, y0, z0,
482
X0, Y0, Z0, X1, Y1, Z1;
483
int TotalOut, OutChan;
484
485
cmsFloat32Number fx, fy, fz,
486
d000, d001, d010, d011,
487
d100, d101, d110, d111,
488
dx00, dx01, dx10, dx11,
489
dxy0, dxy1, dxyz;
490
491
TotalOut = p -> nOutputs;
492
493
// We need some clipping here
494
px = fclamp(Input[0]) * p->Domain[0];
495
py = fclamp(Input[1]) * p->Domain[1];
496
pz = fclamp(Input[2]) * p->Domain[2];
497
498
x0 = (int) floor(px); fx = px - (cmsFloat32Number) x0; // We need full floor functionality here
499
y0 = (int) floor(py); fy = py - (cmsFloat32Number) y0;
500
z0 = (int) floor(pz); fz = pz - (cmsFloat32Number) z0;
501
502
X0 = p -> opta[2] * x0;
503
X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
504
505
Y0 = p -> opta[1] * y0;
506
Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
507
508
Z0 = p -> opta[0] * z0;
509
Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
510
511
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
512
513
d000 = DENS(X0, Y0, Z0);
514
d001 = DENS(X0, Y0, Z1);
515
d010 = DENS(X0, Y1, Z0);
516
d011 = DENS(X0, Y1, Z1);
517
518
d100 = DENS(X1, Y0, Z0);
519
d101 = DENS(X1, Y0, Z1);
520
d110 = DENS(X1, Y1, Z0);
521
d111 = DENS(X1, Y1, Z1);
522
523
524
dx00 = LERP(fx, d000, d100);
525
dx01 = LERP(fx, d001, d101);
526
dx10 = LERP(fx, d010, d110);
527
dx11 = LERP(fx, d011, d111);
528
529
dxy0 = LERP(fy, dx00, dx10);
530
dxy1 = LERP(fy, dx01, dx11);
531
532
dxyz = LERP(fz, dxy0, dxy1);
533
534
Output[OutChan] = dxyz;
535
}
536
537
538
# undef LERP
539
# undef DENS
540
}
541
542
// Trilinear interpolation (16 bits) - optimized version
543
static CMS_NO_SANITIZE
544
void TrilinearInterp16(CMSREGISTER const cmsUInt16Number Input[],
545
CMSREGISTER cmsUInt16Number Output[],
546
CMSREGISTER const cmsInterpParams* p)
547
548
{
549
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
550
#define LERP(a,l,h) (cmsUInt16Number) (l + ROUND_FIXED_TO_INT(((h-l)*a)))
551
552
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
553
int OutChan, TotalOut;
554
cmsS15Fixed16Number fx, fy, fz;
555
CMSREGISTER int rx, ry, rz;
556
int x0, y0, z0;
557
CMSREGISTER int X0, X1, Y0, Y1, Z0, Z1;
558
int d000, d001, d010, d011,
559
d100, d101, d110, d111,
560
dx00, dx01, dx10, dx11,
561
dxy0, dxy1, dxyz;
562
563
TotalOut = p -> nOutputs;
564
565
fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
566
x0 = FIXED_TO_INT(fx);
567
rx = FIXED_REST_TO_INT(fx); // Rest in 0..1.0 domain
568
569
570
fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
571
y0 = FIXED_TO_INT(fy);
572
ry = FIXED_REST_TO_INT(fy);
573
574
fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
575
z0 = FIXED_TO_INT(fz);
576
rz = FIXED_REST_TO_INT(fz);
577
578
579
X0 = p -> opta[2] * x0;
580
X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
581
582
Y0 = p -> opta[1] * y0;
583
Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
584
585
Z0 = p -> opta[0] * z0;
586
Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
587
588
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
589
590
d000 = DENS(X0, Y0, Z0);
591
d001 = DENS(X0, Y0, Z1);
592
d010 = DENS(X0, Y1, Z0);
593
d011 = DENS(X0, Y1, Z1);
594
595
d100 = DENS(X1, Y0, Z0);
596
d101 = DENS(X1, Y0, Z1);
597
d110 = DENS(X1, Y1, Z0);
598
d111 = DENS(X1, Y1, Z1);
599
600
601
dx00 = LERP(rx, d000, d100);
602
dx01 = LERP(rx, d001, d101);
603
dx10 = LERP(rx, d010, d110);
604
dx11 = LERP(rx, d011, d111);
605
606
dxy0 = LERP(ry, dx00, dx10);
607
dxy1 = LERP(ry, dx01, dx11);
608
609
dxyz = LERP(rz, dxy0, dxy1);
610
611
Output[OutChan] = (cmsUInt16Number) dxyz;
612
}
613
614
615
# undef LERP
616
# undef DENS
617
}
618
619
620
// Tetrahedral interpolation, using Sakamoto algorithm.
621
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
622
static
623
void TetrahedralInterpFloat(const cmsFloat32Number Input[],
624
cmsFloat32Number Output[],
625
const cmsInterpParams* p)
626
{
627
const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
628
cmsFloat32Number px, py, pz;
629
int x0, y0, z0,
630
X0, Y0, Z0, X1, Y1, Z1;
631
cmsFloat32Number rx, ry, rz;
632
cmsFloat32Number c0, c1=0, c2=0, c3=0;
633
int OutChan, TotalOut;
634
635
TotalOut = p -> nOutputs;
636
637
// We need some clipping here
638
px = fclamp(Input[0]) * p->Domain[0];
639
py = fclamp(Input[1]) * p->Domain[1];
640
pz = fclamp(Input[2]) * p->Domain[2];
641
642
x0 = (int) floor(px); rx = (px - (cmsFloat32Number) x0); // We need full floor functionality here
643
y0 = (int) floor(py); ry = (py - (cmsFloat32Number) y0);
644
z0 = (int) floor(pz); rz = (pz - (cmsFloat32Number) z0);
645
646
647
X0 = p -> opta[2] * x0;
648
X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
649
650
Y0 = p -> opta[1] * y0;
651
Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
652
653
Z0 = p -> opta[0] * z0;
654
Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
655
656
for (OutChan=0; OutChan < TotalOut; OutChan++) {
657
658
// These are the 6 Tetrahedral
659
660
c0 = DENS(X0, Y0, Z0);
661
662
if (rx >= ry && ry >= rz) {
663
664
c1 = DENS(X1, Y0, Z0) - c0;
665
c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
666
c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
667
668
}
669
else
670
if (rx >= rz && rz >= ry) {
671
672
c1 = DENS(X1, Y0, Z0) - c0;
673
c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
674
c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
675
676
}
677
else
678
if (rz >= rx && rx >= ry) {
679
680
c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
681
c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
682
c3 = DENS(X0, Y0, Z1) - c0;
683
684
}
685
else
686
if (ry >= rx && rx >= rz) {
687
688
c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
689
c2 = DENS(X0, Y1, Z0) - c0;
690
c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
691
692
}
693
else
694
if (ry >= rz && rz >= rx) {
695
696
c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
697
c2 = DENS(X0, Y1, Z0) - c0;
698
c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
699
700
}
701
else
702
if (rz >= ry && ry >= rx) {
703
704
c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
705
c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
706
c3 = DENS(X0, Y0, Z1) - c0;
707
708
}
709
else {
710
c1 = c2 = c3 = 0;
711
}
712
713
Output[OutChan] = c0 + c1 * rx + c2 * ry + c3 * rz;
714
}
715
716
}
717
718
#undef DENS
719
720
static CMS_NO_SANITIZE
721
void TetrahedralInterp16(CMSREGISTER const cmsUInt16Number Input[],
722
CMSREGISTER cmsUInt16Number Output[],
723
CMSREGISTER const cmsInterpParams* p)
724
{
725
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p -> Table;
726
cmsS15Fixed16Number fx, fy, fz;
727
cmsS15Fixed16Number rx, ry, rz;
728
int x0, y0, z0;
729
cmsS15Fixed16Number c0, c1, c2, c3, Rest;
730
cmsUInt32Number X0, X1, Y0, Y1, Z0, Z1;
731
cmsUInt32Number TotalOut = p -> nOutputs;
732
733
fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
734
fy = _cmsToFixedDomain((int) Input[1] * p -> Domain[1]);
735
fz = _cmsToFixedDomain((int) Input[2] * p -> Domain[2]);
736
737
x0 = FIXED_TO_INT(fx);
738
y0 = FIXED_TO_INT(fy);
739
z0 = FIXED_TO_INT(fz);
740
741
rx = FIXED_REST_TO_INT(fx);
742
ry = FIXED_REST_TO_INT(fy);
743
rz = FIXED_REST_TO_INT(fz);
744
745
X0 = p -> opta[2] * x0;
746
X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]);
747
748
Y0 = p -> opta[1] * y0;
749
Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]);
750
751
Z0 = p -> opta[0] * z0;
752
Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
753
754
LutTable += X0+Y0+Z0;
755
756
// Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))
757
// which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16
758
// This can be replaced by: t = Rest+0x8001, x = (t + (t>>16))>>16
759
// at the cost of being off by one at 7fff and 17ffe.
760
761
if (rx >= ry) {
762
if (ry >= rz) {
763
Y1 += X1;
764
Z1 += Y1;
765
for (; TotalOut; TotalOut--) {
766
c1 = LutTable[X1];
767
c2 = LutTable[Y1];
768
c3 = LutTable[Z1];
769
c0 = *LutTable++;
770
c3 -= c2;
771
c2 -= c1;
772
c1 -= c0;
773
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
774
*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
775
}
776
} else if (rz >= rx) {
777
X1 += Z1;
778
Y1 += X1;
779
for (; TotalOut; TotalOut--) {
780
c1 = LutTable[X1];
781
c2 = LutTable[Y1];
782
c3 = LutTable[Z1];
783
c0 = *LutTable++;
784
c2 -= c1;
785
c1 -= c3;
786
c3 -= c0;
787
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
788
*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
789
}
790
} else {
791
Z1 += X1;
792
Y1 += Z1;
793
for (; TotalOut; TotalOut--) {
794
c1 = LutTable[X1];
795
c2 = LutTable[Y1];
796
c3 = LutTable[Z1];
797
c0 = *LutTable++;
798
c2 -= c3;
799
c3 -= c1;
800
c1 -= c0;
801
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
802
*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
803
}
804
}
805
} else {
806
if (rx >= rz) {
807
X1 += Y1;
808
Z1 += X1;
809
for (; TotalOut; TotalOut--) {
810
c1 = LutTable[X1];
811
c2 = LutTable[Y1];
812
c3 = LutTable[Z1];
813
c0 = *LutTable++;
814
c3 -= c1;
815
c1 -= c2;
816
c2 -= c0;
817
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
818
*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
819
}
820
} else if (ry >= rz) {
821
Z1 += Y1;
822
X1 += Z1;
823
for (; TotalOut; TotalOut--) {
824
c1 = LutTable[X1];
825
c2 = LutTable[Y1];
826
c3 = LutTable[Z1];
827
c0 = *LutTable++;
828
c1 -= c3;
829
c3 -= c2;
830
c2 -= c0;
831
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
832
*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
833
}
834
} else {
835
Y1 += Z1;
836
X1 += Y1;
837
for (; TotalOut; TotalOut--) {
838
c1 = LutTable[X1];
839
c2 = LutTable[Y1];
840
c3 = LutTable[Z1];
841
c0 = *LutTable++;
842
c1 -= c2;
843
c2 -= c3;
844
c3 -= c0;
845
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
846
*Output++ = (cmsUInt16Number) c0 + ((Rest + (Rest>>16))>>16);
847
}
848
}
849
}
850
}
851
852
853
#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
854
static CMS_NO_SANITIZE
855
void Eval4Inputs(CMSREGISTER const cmsUInt16Number Input[],
856
CMSREGISTER cmsUInt16Number Output[],
857
CMSREGISTER const cmsInterpParams* p16)
858
{
859
const cmsUInt16Number* LutTable;
860
cmsS15Fixed16Number fk;
861
cmsS15Fixed16Number k0, rk;
862
int K0, K1;
863
cmsS15Fixed16Number fx, fy, fz;
864
cmsS15Fixed16Number rx, ry, rz;
865
int x0, y0, z0;
866
cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
867
cmsUInt32Number i;
868
cmsS15Fixed16Number c0, c1, c2, c3, Rest;
869
cmsUInt32Number OutChan;
870
cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
871
872
873
fk = _cmsToFixedDomain((int) Input[0] * p16 -> Domain[0]);
874
fx = _cmsToFixedDomain((int) Input[1] * p16 -> Domain[1]);
875
fy = _cmsToFixedDomain((int) Input[2] * p16 -> Domain[2]);
876
fz = _cmsToFixedDomain((int) Input[3] * p16 -> Domain[3]);
877
878
k0 = FIXED_TO_INT(fk);
879
x0 = FIXED_TO_INT(fx);
880
y0 = FIXED_TO_INT(fy);
881
z0 = FIXED_TO_INT(fz);
882
883
rk = FIXED_REST_TO_INT(fk);
884
rx = FIXED_REST_TO_INT(fx);
885
ry = FIXED_REST_TO_INT(fy);
886
rz = FIXED_REST_TO_INT(fz);
887
888
K0 = p16 -> opta[3] * k0;
889
K1 = K0 + (Input[0] == 0xFFFFU ? 0 : p16->opta[3]);
890
891
X0 = p16 -> opta[2] * x0;
892
X1 = X0 + (Input[1] == 0xFFFFU ? 0 : p16->opta[2]);
893
894
Y0 = p16 -> opta[1] * y0;
895
Y1 = Y0 + (Input[2] == 0xFFFFU ? 0 : p16->opta[1]);
896
897
Z0 = p16 -> opta[0] * z0;
898
Z1 = Z0 + (Input[3] == 0xFFFFU ? 0 : p16->opta[0]);
899
900
LutTable = (cmsUInt16Number*) p16 -> Table;
901
LutTable += K0;
902
903
for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
904
905
c0 = DENS(X0, Y0, Z0);
906
907
if (rx >= ry && ry >= rz) {
908
909
c1 = DENS(X1, Y0, Z0) - c0;
910
c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
911
c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
912
913
}
914
else
915
if (rx >= rz && rz >= ry) {
916
917
c1 = DENS(X1, Y0, Z0) - c0;
918
c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
919
c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
920
921
}
922
else
923
if (rz >= rx && rx >= ry) {
924
925
c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
926
c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
927
c3 = DENS(X0, Y0, Z1) - c0;
928
929
}
930
else
931
if (ry >= rx && rx >= rz) {
932
933
c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
934
c2 = DENS(X0, Y1, Z0) - c0;
935
c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
936
937
}
938
else
939
if (ry >= rz && rz >= rx) {
940
941
c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
942
c2 = DENS(X0, Y1, Z0) - c0;
943
c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
944
945
}
946
else
947
if (rz >= ry && ry >= rx) {
948
949
c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
950
c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
951
c3 = DENS(X0, Y0, Z1) - c0;
952
953
}
954
else {
955
c1 = c2 = c3 = 0;
956
}
957
958
Rest = c1 * rx + c2 * ry + c3 * rz;
959
960
Tmp1[OutChan] = (cmsUInt16Number)(c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
961
}
962
963
964
LutTable = (cmsUInt16Number*) p16 -> Table;
965
LutTable += K1;
966
967
for (OutChan=0; OutChan < p16 -> nOutputs; OutChan++) {
968
969
c0 = DENS(X0, Y0, Z0);
970
971
if (rx >= ry && ry >= rz) {
972
973
c1 = DENS(X1, Y0, Z0) - c0;
974
c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0);
975
c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
976
977
}
978
else
979
if (rx >= rz && rz >= ry) {
980
981
c1 = DENS(X1, Y0, Z0) - c0;
982
c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
983
c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0);
984
985
}
986
else
987
if (rz >= rx && rx >= ry) {
988
989
c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1);
990
c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1);
991
c3 = DENS(X0, Y0, Z1) - c0;
992
993
}
994
else
995
if (ry >= rx && rx >= rz) {
996
997
c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0);
998
c2 = DENS(X0, Y1, Z0) - c0;
999
c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0);
1000
1001
}
1002
else
1003
if (ry >= rz && rz >= rx) {
1004
1005
c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1006
c2 = DENS(X0, Y1, Z0) - c0;
1007
c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0);
1008
1009
}
1010
else
1011
if (rz >= ry && ry >= rx) {
1012
1013
c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1);
1014
c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1);
1015
c3 = DENS(X0, Y0, Z1) - c0;
1016
1017
}
1018
else {
1019
c1 = c2 = c3 = 0;
1020
}
1021
1022
Rest = c1 * rx + c2 * ry + c3 * rz;
1023
1024
Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
1025
}
1026
1027
1028
1029
for (i=0; i < p16 -> nOutputs; i++) {
1030
Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
1031
}
1032
}
1033
#undef DENS
1034
1035
1036
// For more that 3 inputs (i.e., CMYK)
1037
// evaluate two 3-dimensional interpolations and then linearly interpolate between them.
1038
static
1039
void Eval4InputsFloat(const cmsFloat32Number Input[],
1040
cmsFloat32Number Output[],
1041
const cmsInterpParams* p)
1042
{
1043
const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
1044
cmsFloat32Number rest;
1045
cmsFloat32Number pk;
1046
int k0, K0, K1;
1047
const cmsFloat32Number* T;
1048
cmsUInt32Number i;
1049
cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
1050
cmsInterpParams p1;
1051
1052
pk = fclamp(Input[0]) * p->Domain[0];
1053
k0 = _cmsQuickFloor(pk);
1054
rest = pk - (cmsFloat32Number) k0;
1055
1056
K0 = p -> opta[3] * k0;
1057
K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[3]);
1058
1059
p1 = *p;
1060
memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number));
1061
1062
T = LutTable + K0;
1063
p1.Table = T;
1064
1065
TetrahedralInterpFloat(Input + 1, Tmp1, &p1);
1066
1067
T = LutTable + K1;
1068
p1.Table = T;
1069
TetrahedralInterpFloat(Input + 1, Tmp2, &p1);
1070
1071
for (i=0; i < p -> nOutputs; i++)
1072
{
1073
cmsFloat32Number y0 = Tmp1[i];
1074
cmsFloat32Number y1 = Tmp2[i];
1075
1076
Output[i] = y0 + (y1 - y0) * rest;
1077
}
1078
}
1079
1080
#define EVAL_FNS(N,NM) static CMS_NO_SANITIZE \
1081
void Eval##N##Inputs(CMSREGISTER const cmsUInt16Number Input[], CMSREGISTER cmsUInt16Number Output[], CMSREGISTER const cmsInterpParams* p16)\
1082
{\
1083
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;\
1084
cmsS15Fixed16Number fk;\
1085
cmsS15Fixed16Number k0, rk;\
1086
int K0, K1;\
1087
const cmsUInt16Number* T;\
1088
cmsUInt32Number i;\
1089
cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\
1090
cmsInterpParams p1;\
1091
\
1092
fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);\
1093
k0 = FIXED_TO_INT(fk);\
1094
rk = FIXED_REST_TO_INT(fk);\
1095
\
1096
K0 = p16 -> opta[NM] * k0;\
1097
K1 = p16 -> opta[NM] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));\
1098
\
1099
p1 = *p16;\
1100
memmove(&p1.Domain[0], &p16 ->Domain[1], NM*sizeof(cmsUInt32Number));\
1101
\
1102
T = LutTable + K0;\
1103
p1.Table = T;\
1104
\
1105
Eval##NM##Inputs(Input + 1, Tmp1, &p1);\
1106
\
1107
T = LutTable + K1;\
1108
p1.Table = T;\
1109
\
1110
Eval##NM##Inputs(Input + 1, Tmp2, &p1);\
1111
\
1112
for (i=0; i < p16 -> nOutputs; i++) {\
1113
\
1114
Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);\
1115
}\
1116
}\
1117
\
1118
static void Eval##N##InputsFloat(const cmsFloat32Number Input[], \
1119
cmsFloat32Number Output[],\
1120
const cmsInterpParams * p)\
1121
{\
1122
const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;\
1123
cmsFloat32Number rest;\
1124
cmsFloat32Number pk;\
1125
int k0, K0, K1;\
1126
const cmsFloat32Number* T;\
1127
cmsUInt32Number i;\
1128
cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\
1129
cmsInterpParams p1;\
1130
\
1131
pk = fclamp(Input[0]) * p->Domain[0];\
1132
k0 = _cmsQuickFloor(pk);\
1133
rest = pk - (cmsFloat32Number) k0;\
1134
\
1135
K0 = p -> opta[NM] * k0;\
1136
K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[NM]);\
1137
\
1138
p1 = *p;\
1139
memmove(&p1.Domain[0], &p ->Domain[1], NM*sizeof(cmsUInt32Number));\
1140
\
1141
T = LutTable + K0;\
1142
p1.Table = T;\
1143
\
1144
Eval##NM##InputsFloat(Input + 1, Tmp1, &p1);\
1145
\
1146
T = LutTable + K1;\
1147
p1.Table = T;\
1148
\
1149
Eval##NM##InputsFloat(Input + 1, Tmp2, &p1);\
1150
\
1151
for (i=0; i < p -> nOutputs; i++) {\
1152
\
1153
cmsFloat32Number y0 = Tmp1[i];\
1154
cmsFloat32Number y1 = Tmp2[i];\
1155
\
1156
Output[i] = y0 + (y1 - y0) * rest;\
1157
}\
1158
}
1159
1160
1161
/**
1162
* Thanks to Carles Llopis for the templating idea
1163
*/
1164
EVAL_FNS(5, 4)
1165
EVAL_FNS(6, 5)
1166
EVAL_FNS(7, 6)
1167
EVAL_FNS(8, 7)
1168
EVAL_FNS(9, 8)
1169
EVAL_FNS(10, 9)
1170
EVAL_FNS(11, 10)
1171
EVAL_FNS(12, 11)
1172
EVAL_FNS(13, 12)
1173
EVAL_FNS(14, 13)
1174
EVAL_FNS(15, 14)
1175
1176
1177
// The default factory
1178
static
1179
cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags)
1180
{
1181
1182
cmsInterpFunction Interpolation;
1183
cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT);
1184
cmsBool IsTrilinear = (dwFlags & CMS_LERP_FLAGS_TRILINEAR);
1185
1186
memset(&Interpolation, 0, sizeof(Interpolation));
1187
1188
// Safety check
1189
if (nInputChannels >= 4 && nOutputChannels >= MAX_STAGE_CHANNELS)
1190
return Interpolation;
1191
1192
switch (nInputChannels) {
1193
1194
case 1: // Gray LUT / linear
1195
1196
if (nOutputChannels == 1) {
1197
1198
if (IsFloat)
1199
Interpolation.LerpFloat = LinLerp1Dfloat;
1200
else
1201
Interpolation.Lerp16 = LinLerp1D;
1202
1203
}
1204
else {
1205
1206
if (IsFloat)
1207
Interpolation.LerpFloat = Eval1InputFloat;
1208
else
1209
Interpolation.Lerp16 = Eval1Input;
1210
}
1211
break;
1212
1213
case 2: // Duotone
1214
if (IsFloat)
1215
Interpolation.LerpFloat = BilinearInterpFloat;
1216
else
1217
Interpolation.Lerp16 = BilinearInterp16;
1218
break;
1219
1220
case 3: // RGB et al
1221
1222
if (IsTrilinear) {
1223
1224
if (IsFloat)
1225
Interpolation.LerpFloat = TrilinearInterpFloat;
1226
else
1227
Interpolation.Lerp16 = TrilinearInterp16;
1228
}
1229
else {
1230
1231
if (IsFloat)
1232
Interpolation.LerpFloat = TetrahedralInterpFloat;
1233
else {
1234
1235
Interpolation.Lerp16 = TetrahedralInterp16;
1236
}
1237
}
1238
break;
1239
1240
case 4: // CMYK lut
1241
1242
if (IsFloat)
1243
Interpolation.LerpFloat = Eval4InputsFloat;
1244
else
1245
Interpolation.Lerp16 = Eval4Inputs;
1246
break;
1247
1248
case 5: // 5 Inks
1249
if (IsFloat)
1250
Interpolation.LerpFloat = Eval5InputsFloat;
1251
else
1252
Interpolation.Lerp16 = Eval5Inputs;
1253
break;
1254
1255
case 6: // 6 Inks
1256
if (IsFloat)
1257
Interpolation.LerpFloat = Eval6InputsFloat;
1258
else
1259
Interpolation.Lerp16 = Eval6Inputs;
1260
break;
1261
1262
case 7: // 7 inks
1263
if (IsFloat)
1264
Interpolation.LerpFloat = Eval7InputsFloat;
1265
else
1266
Interpolation.Lerp16 = Eval7Inputs;
1267
break;
1268
1269
case 8: // 8 inks
1270
if (IsFloat)
1271
Interpolation.LerpFloat = Eval8InputsFloat;
1272
else
1273
Interpolation.Lerp16 = Eval8Inputs;
1274
break;
1275
1276
case 9:
1277
if (IsFloat)
1278
Interpolation.LerpFloat = Eval9InputsFloat;
1279
else
1280
Interpolation.Lerp16 = Eval9Inputs;
1281
break;
1282
1283
case 10:
1284
if (IsFloat)
1285
Interpolation.LerpFloat = Eval10InputsFloat;
1286
else
1287
Interpolation.Lerp16 = Eval10Inputs;
1288
break;
1289
1290
case 11:
1291
if (IsFloat)
1292
Interpolation.LerpFloat = Eval11InputsFloat;
1293
else
1294
Interpolation.Lerp16 = Eval11Inputs;
1295
break;
1296
1297
case 12:
1298
if (IsFloat)
1299
Interpolation.LerpFloat = Eval12InputsFloat;
1300
else
1301
Interpolation.Lerp16 = Eval12Inputs;
1302
break;
1303
1304
case 13:
1305
if (IsFloat)
1306
Interpolation.LerpFloat = Eval13InputsFloat;
1307
else
1308
Interpolation.Lerp16 = Eval13Inputs;
1309
break;
1310
1311
case 14:
1312
if (IsFloat)
1313
Interpolation.LerpFloat = Eval14InputsFloat;
1314
else
1315
Interpolation.Lerp16 = Eval14Inputs;
1316
break;
1317
1318
case 15:
1319
if (IsFloat)
1320
Interpolation.LerpFloat = Eval15InputsFloat;
1321
else
1322
Interpolation.Lerp16 = Eval15Inputs;
1323
break;
1324
1325
default:
1326
Interpolation.Lerp16 = NULL;
1327
}
1328
1329
return Interpolation;
1330
}
1331
1332