Files
argyllcms/imdi/imdi_utl.h
2026-08-20 20:28:40 +01:00

263 lines
7.5 KiB
C

#ifndef IMDI_UTL_H
#define IMDI_UTL_H
/* Integer Multi-Dimensional Interpolation */
/*
* Copyright 2000 - 2007 Graeme W. Gill
* All rights reserved.
*
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
* see the License.txt file for licencing details.
*/
#include <limits.h>
/* Common utility definitions used at both generation and runtime. */
#define IXDI 10 /* maximum input channels/dimensions allowed */
#define IXDO 10 /* maximum output channels/dimensions allowed */
#if IXDI > IXDO /* Maximum of either DI or DO */
# define IXDIDO IXDI
#else
# define IXDIDO IXDO
#endif
#define ALLOW64 /* Allow declarations but not use of 64 bit types */
#ifndef FORCE64
# undef FORCE64 /* Use 64 bit, even on architectures where it's */
/* not a native size. ALLOW64 must be defined */
#endif
/* ------------------------------------------------------ */
#if defined(ALLOW64) && (ULONG_MAX == 0xffffffffffffffffUL || defined(FORCE64))
#ifndef USE64
#pragma message("Using 64 bit integer color kernel")
#endif /* USE64 */
#define USE64 /* Use 64 bits if it's natural or forced */
#endif
/* ------------------------------------------------------- */
/* Macros combination counter */
/* Declare the counter name nn, combinations out of total */
/* Maximum combinations is DI+2 */
#define COMBO(nn, comb, total) \
int nn[IXDI+2]; /* counter value */ \
int nn##_cmb = (comb); /* number of combinations*/ \
int nn##_tot = (total); /* out of total possible */ \
int nn##_e /* dimension index */
/* Set total to new setting */
#define CB_SETT(nn, total) \
nn##_tot = (total) /* total possible */
/* Set combinations to new setting */
#define CB_SETC(nn, comb) \
nn##_cmb = (comb) /* number of combinations*/
/* Set the counter to its initial value */
#define CB_INIT(nn) \
{ \
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
nn[nn##_e] = nn##_cmb-nn##_e-1; \
nn##_e = 0; \
}
/* Increment the counter value */
#define CB_INC(nn) \
{ \
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
nn[nn##_e]++; \
if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
int nn##_ee; /* No carry */ \
for (nn##_ee = nn##_e-1; nn##_ee >= 0; nn##_ee--) \
nn[nn##_ee] = nn[nn##_ee+1] + 1; \
break; \
} \
} \
}
/* After increment, expression is TRUE if counter is done */
#define CB_DONE(nn) \
(nn##_e >= nn##_cmb)
/* ------------------------------------------------------- */
/* Macros simplex combination counter. */
/* Based on COMBO, but skips invalid simplex combinations */
#define XCOMBO(nn, comb, total) \
COMBO(nn, comb, total)
/* Set total to new setting */
#define XCB_SETT(nn, total) \
CB_SETT(nn, total)
/* Set combinations to new setting */
#define XCB_SETC(nn, comb) \
CB_SETC(nn, comb)
/* Set the counter to its initial value */
#define XCB_INIT(nn) \
{ \
int nn##_ii; \
\
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
nn[nn##_e] = nn##_cmb-nn##_e-1; \
for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii])\
break; /* Went from 0 to 1 */ \
} \
if (nn##_ii < nn##_cmb) { /* Fix invalid combination */ \
XCB_INC(nn); \
} \
nn##_e = 0; \
}
/* Increment the counter value */
#define XCB_INC(nn) \
{ \
int nn##_ii = 0; \
\
while (nn##_ii < nn##_cmb) { \
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
nn[nn##_e]++; \
if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
int nn##_ee; /* No carry */ \
for (nn##_ee = nn##_e-1; nn##_ee >= 0; nn##_ee--) \
nn[nn##_ee] = nn[nn##_ee+1] + 1; \
break; \
} \
} \
if (nn##_e >= nn##_cmb) \
break; /* Done */ \
\
/* Reject invalid combinations */ \
for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii]) \
break; /* Went from 0 to 1 */ \
} \
} \
}
/* After increment, expression is TRUE if counter is done */
#define XCB_DONE(nn) \
CB_DONE(nn)
/* ------------------------------------------------------- */
/* Macro pseudo-hilbert counter */
/* This multi-dimensional count sequence is a distributed */
/* Gray code sequence, with direction reversal on every */
/* alternate power of 2 scale. */
/* It is intended to aid cache coherence in multi-dimensional */
/* regular sampling. It approximates the Hilbert curve sequence. */
#define PHILBERT(nn) \
int nn[IXDIDO];/* counter value */ \
int nn##di; /* Dimensionality */ \
unsigned nn##res; /* Resolution per coordinate */ \
unsigned nn##bits; /* Bits per coordinate */ \
unsigned nn##ix; /* Current binary index */ \
unsigned nn##tmask; /* Total 2^n count mask */ \
unsigned nn##count; /* Usable count */
/* Init counter for dimenion di, resolution res */
#define PH_INIT(nn, pdi, pres) \
{ \
int nn##e; \
\
nn##di = pdi; \
nn##res = (unsigned)pres; \
\
/* Compute bits */ \
for (nn##bits = 0; (1u << nn##bits) < nn##res; nn##bits++) \
; \
\
/* Compute the total count mask */ \
nn##tmask = ((1u << (nn##bits * nn##di))-1); \
\
/* Compute usable count */ \
nn##count = 1; \
for (nn##e = 0; nn##e < nn##di; nn##e++) \
nn##count *= nn##res; \
\
nn##ix = 0; \
for (nn##e = 0; nn##e < nn##di; nn##e++) \
nn[nn##e] = 0; \
}
/* Increment the counter value */
#define PH_INC(nn) \
{ \
int nn##e; \
do { \
unsigned int nn##b; \
int nn##gix; /* Gray code index */ \
\
nn##ix = (nn##ix + 1) & nn##tmask; \
\
/* Convert to gray code index */ \
nn##gix = nn##ix ^ (nn##ix >> 1); \
\
for (nn##e = 0; nn##e < nn##di; nn##e++) \
nn[nn##e] = 0; \
\
/* Distribute bits */ \
for (nn##b = 0; nn##b < nn##bits; nn##b++) { \
if (nn##b & 1) { /* In reverse order */ \
for (nn##e = nn##di-1; nn##e >= 0; nn##e--) { \
nn[nn##e] |= (nn##gix & 1) << nn##b; \
nn##gix >>= 1; \
} \
} else { /* In normal order */ \
for (nn##e = 0; nn##e < nn##di; nn##e++) { \
nn[nn##e] |= (nn##gix & 1) << nn##b; \
nn##gix >>= 1; \
} \
} \
} \
\
/* Convert from Gray to binary coordinates */ \
for (nn##e = 0; nn##e < nn##di; nn##e++) { \
unsigned nn##sh, nn##tv; \
\
for(nn##sh = 1, nn##tv = nn[nn##e];; nn##sh <<= 1) { \
unsigned nn##ptv = nn##tv; \
nn##tv ^= (nn##tv >> nn##sh); \
if (nn##ptv <= 1 || nn##sh == 16) \
break; \
} \
/* Filter - increment again if outside cube range */ \
if (nn##tv >= nn##res) \
break; \
nn[nn##e] = nn##tv; \
} \
\
} while (nn##e < nn##di); \
\
}
/* After increment, expression is TRUE if counter has looped back to start. */
#define PH_LOOPED(nn) \
(nn##ix == 0) \
/* ------------------------------------------------------- */
#endif /* IMDI_UTL_H */