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