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