Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1992, 2000 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gsciemap.c,v 1.16 2005/03/16 12:27:42 igor Exp $ */
18
/* CIE color rendering */
19
#include "math_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gxcspace.h"		/* for gxcie.c */
23
#include "gxarith.h"
24
#include "gxcie.h"
25
#include "gxdevice.h"		/* for gxcmap.h */
26
#include "gxcmap.h"
27
#include "gxistate.h"
28
 
29
/*
30
 * Compute a cache index as (vin - base) * factor.
31
 * vin, base, factor, and the result are cie_cached_values.
32
 * We know that the result doesn't exceed (gx_cie_cache_size - 1) << fbits.
33
 *
34
 * Since this operation is extremely time-critical, we don't rely on the
35
 * compiler providing 'inline'.
36
 */
37
#define LOOKUP_INDEX_(vin, pcache, fbits)\
38
  (cie_cached_value)\
39
  ((vin) <= (pcache)->vecs.params.base ? 0 :\
40
   (vin) >= (pcache)->vecs.params.limit ? (gx_cie_cache_size - 1) << (fbits) :\
41
   cie_cached_product2int( ((vin) - (pcache)->vecs.params.base),\
42
			   (pcache)->vecs.params.factor, fbits ))
43
#define LOOKUP_ENTRY_(vin, pcache)\
44
  (&(pcache)->vecs.values[(int)LOOKUP_INDEX(vin, pcache, 0)])
45
#ifdef DEBUG
46
private cie_cached_value
47
LOOKUP_INDEX(cie_cached_value vin, const gx_cie_vector_cache *pcache,
48
	     int fbits)
49
{
50
    return LOOKUP_INDEX_(vin, pcache, fbits);
51
}
52
private const cie_cached_vector3 *
53
LOOKUP_ENTRY(cie_cached_value vin, const gx_cie_vector_cache *pcache)
54
{
55
    return LOOKUP_ENTRY_(vin, pcache);
56
}
57
#else  /* !DEBUG */
58
#  define LOOKUP_INDEX(vin, pcache, fbits)  LOOKUP_INDEX_(vin, pcache, fbits)
59
#  define LOOKUP_ENTRY(vin, pcache)         LOOKUP_ENTRY_(vin, pcache)
60
#endif /* DEBUG */
61
 
62
/*
63
 * Call the remap_finish procedure in the structure without going through
64
 * the extra level of procedure.
65
 */
66
#ifdef DEBUG
67
#  define GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs)\
68
    gx_cie_remap_finish(vec3, pconc, pis, pcs)
69
#else
70
#  define GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs)\
71
    ((pis)->cie_joint_caches->remap_finish(vec3, pconc, pis, pcs))
72
#endif
73
 
74
/* Forward references */
75
private void cie_lookup_mult3(cie_cached_vector3 *,
76
			      const gx_cie_vector_cache3_t *);
77
 
78
#ifdef DEBUG
79
private void
80
cie_lookup_map3(cie_cached_vector3 * pvec,
81
		const gx_cie_vector_cache3_t * pc, const char *cname)
82
{
83
    if_debug5('c', "[c]lookup %s 0x%lx [%g %g %g]\n",
84
	      (const char *)cname, (ulong) pc,
85
	      cie_cached2float(pvec->u), cie_cached2float(pvec->v),
86
	      cie_cached2float(pvec->w));
87
    cie_lookup_mult3(pvec, pc);
88
    if_debug3('c', "        =[%g %g %g]\n",
89
	      cie_cached2float(pvec->u), cie_cached2float(pvec->v),
90
	      cie_cached2float(pvec->w));
91
}
92
#else
93
#  define cie_lookup_map3(pvec, pc, cname) cie_lookup_mult3(pvec, pc)
94
#endif
95
 
96
/* Render a CIEBasedDEFG color. */
97
int
98
gx_concretize_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs,
99
		      frac * pconc, const gs_imager_state * pis)
100
{
101
    const gs_cie_defg *pcie = pcs->params.defg;
102
    int i;
103
    fixed hijk[4];
104
    frac abc[3];
105
    cie_cached_vector3 vec3;
106
 
107
    if_debug4('c', "[c]concretize DEFG [%g %g %g %g]\n",
108
	      pc->paint.values[0], pc->paint.values[1],
109
	      pc->paint.values[2], pc->paint.values[3]);
110
    CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
111
 
112
    /*
113
     * Apply DecodeDEFG, including restriction to RangeHIJK and scaling to
114
     * the Table dimensions.
115
     */
116
    for (i = 0; i < 4; ++i) {
117
	int tdim = pcie->Table.dims[i] - 1;
118
	double factor = pcie->caches_defg.DecodeDEFG[i].floats.params.factor;
119
	double v0 = pc->paint.values[i];
120
	const gs_range *const rangeDEFG = &pcie->RangeDEFG.ranges[i];
121
	double value =
122
	    (v0 < rangeDEFG->rmin ? 0.0 :
123
	     v0 > rangeDEFG->rmax ? factor :
124
	     (v0 - rangeDEFG->rmin) * factor /
125
	       (rangeDEFG->rmax - rangeDEFG->rmin));
126
	int vi = (int)value;
127
	double vf = value - vi;
128
	double v = pcie->caches_defg.DecodeDEFG[i].floats.values[vi];
129
 
130
	if (vf != 0 && vi < factor)
131
	    v += vf *
132
		(pcie->caches_defg.DecodeDEFG[i].floats.values[vi + 1] - v);
133
	v = (v < 0 ? 0 : v > tdim ? tdim : v);
134
	hijk[i] = float2fixed(v);
135
    }
136
    /* Apply Table. */
137
    gx_color_interpolate_linear(hijk, &pcie->Table, abc);
138
 
139
#define SCALE_TO_RANGE(range, frac) ( \
140
       float2cie_cached(((range).rmax - (range).rmin) * frac2float(frac) + \
141
	    (range).rmin) \
142
    )
143
    /* Scale the abc[] frac values to RangeABC cie_cached result */
144
    vec3.u = SCALE_TO_RANGE(pcie->RangeABC.ranges[0], abc[0]); 
145
    vec3.v = SCALE_TO_RANGE(pcie->RangeABC.ranges[1], abc[1]); 
146
    vec3.w = SCALE_TO_RANGE(pcie->RangeABC.ranges[2], abc[2]); 
147
    /* Apply DecodeABC and MatrixABC. */
148
    if (!pis->cie_joint_caches->skipDecodeABC)
149
	cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC,
150
			"Decode/MatrixABC");
151
    GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs);
152
    return 0;
153
}
154
 
155
/* Render a CIEBasedDEF color. */
156
int
157
gx_concretize_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs,
158
		     frac * pconc, const gs_imager_state * pis)
159
{
160
    const gs_cie_def *pcie = pcs->params.def;
161
    int i;
162
    fixed hij[3];
163
    frac abc[3];
164
    cie_cached_vector3 vec3;
165
 
166
    if_debug3('c', "[c]concretize DEF [%g %g %g]\n",
167
	      pc->paint.values[0], pc->paint.values[1],
168
	      pc->paint.values[2]);
169
    CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
170
 
171
    /*
172
     * Apply DecodeDEF, including restriction to RangeHIJ and scaling to
173
     * the Table dimensions.
174
     */
175
    for (i = 0; i < 3; ++i) {
176
	int tdim = pcie->Table.dims[i] - 1;
177
	double factor = pcie->caches_def.DecodeDEF[i].floats.params.factor;
178
	double v0 = pc->paint.values[i];
179
	const gs_range *const rangeDEF = &pcie->RangeDEF.ranges[i];
180
	double value =
181
	    (v0 < rangeDEF->rmin ? 0.0 :
182
	     v0 > rangeDEF->rmax ? factor :
183
	     (v0 - rangeDEF->rmin) * factor /
184
	       (rangeDEF->rmax - rangeDEF->rmin));
185
	int vi = (int)value;
186
	double vf = value - vi;
187
	double v = pcie->caches_def.DecodeDEF[i].floats.values[vi];
188
 
189
	if (vf != 0 && vi < factor)
190
	    v += vf *
191
		(pcie->caches_def.DecodeDEF[i].floats.values[vi + 1] - v);
192
	v = (v < 0 ? 0 : v > tdim ? tdim : v);
193
	hij[i] = float2fixed(v);
194
    }
195
    /* Apply Table. */
196
    gx_color_interpolate_linear(hij, &pcie->Table, abc);
197
    /* Scale the abc[] frac values to RangeABC cie_cached result */
198
    vec3.u = SCALE_TO_RANGE(pcie->RangeABC.ranges[0], abc[0]); 
199
    vec3.v = SCALE_TO_RANGE(pcie->RangeABC.ranges[1], abc[1]); 
200
    vec3.w = SCALE_TO_RANGE(pcie->RangeABC.ranges[2], abc[2]); 
201
    /* Apply DecodeABC and MatrixABC. */
202
    if (!pis->cie_joint_caches->skipDecodeABC)
203
	cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC,
204
			"Decode/MatrixABC");
205
    GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs);
206
    return 0;
207
}
208
#undef SCALE_TO_RANGE
209
 
210
/* Render a CIEBasedABC color. */
211
/* We provide both remap and concretize, but only the former */
212
/* needs to be efficient. */
213
int
214
gx_remap_CIEABC(const gs_client_color * pc, const gs_color_space * pcs,
215
	gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
216
		gs_color_select_t select)
217
{
218
    frac conc[4];
219
    cie_cached_vector3 vec3;
220
 
221
    if_debug3('c', "[c]remap CIEABC [%g %g %g]\n",
222
	      pc->paint.values[0], pc->paint.values[1],
223
	      pc->paint.values[2]);
224
    CIE_CHECK_RENDERING(pcs, conc, pis, goto map3);
225
    vec3.u = float2cie_cached(pc->paint.values[0]);
226
    vec3.v = float2cie_cached(pc->paint.values[1]);
227
    vec3.w = float2cie_cached(pc->paint.values[2]);
228
 
229
    /* Apply DecodeABC and MatrixABC. */
230
    if (!pis->cie_joint_caches->skipDecodeABC) {
231
	const gs_cie_abc *pcie = pcs->params.abc;
232
 
233
	cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC,
234
			"Decode/MatrixABC");
235
    }
236
    switch (GX_CIE_REMAP_FINISH(vec3 /* LMN */, conc, pis, pcs)) {
237
	case 4:
238
	    if_debug4('c', "[c]=CMYK [%g %g %g %g]\n",
239
		      frac2float(conc[0]), frac2float(conc[1]),
240
		      frac2float(conc[2]), frac2float(conc[3]));
241
	    gx_remap_concrete_cmyk(conc[0], conc[1], conc[2], conc[3],
242
				   pdc, pis, dev, select);
243
	    goto done;
244
	default:	/* Can't happen. */
245
	    return_error(gs_error_unknownerror);
246
	case 3:
247
	    ;
248
    }
249
map3:
250
    if_debug3('c', "[c]=RGB [%g %g %g]\n",
251
	      frac2float(conc[0]), frac2float(conc[1]),
252
	      frac2float(conc[2]));
253
    gx_remap_concrete_rgb(conc[0], conc[1], conc[2], pdc, pis,
254
			  dev, select);
255
done:
256
    /* Save original color space and color info into dev color */
257
    pdc->ccolor.paint.values[0] = pc->paint.values[0];
258
    pdc->ccolor.paint.values[1] = pc->paint.values[1];
259
    pdc->ccolor.paint.values[2] = pc->paint.values[2];
260
    pdc->ccolor_valid = true;
261
    return 0;
262
}
263
int
264
gx_concretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs,
265
		     frac * pconc, const gs_imager_state * pis)
266
{
267
    const gs_cie_abc *pcie = pcs->params.abc;
268
    cie_cached_vector3 vec3;
269
 
270
    if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n",
271
	      pc->paint.values[0], pc->paint.values[1],
272
	      pc->paint.values[2]);
273
    CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
274
 
275
    vec3.u = float2cie_cached(pc->paint.values[0]);
276
    vec3.v = float2cie_cached(pc->paint.values[1]);
277
    vec3.w = float2cie_cached(pc->paint.values[2]);
278
    if (!pis->cie_joint_caches->skipDecodeABC)
279
	cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC,
280
			"Decode/MatrixABC");
281
    GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs);
282
    return 0;
283
}
284
 
285
/* Render a CIEBasedA color. */
286
int
287
gx_concretize_CIEA(const gs_client_color * pc, const gs_color_space * pcs,
288
		   frac * pconc, const gs_imager_state * pis)
289
{
290
    const gs_cie_a *pcie = pcs->params.a;
291
    cie_cached_value a = float2cie_cached(pc->paint.values[0]);
292
    cie_cached_vector3 vlmn;
293
 
294
    if_debug1('c', "[c]concretize CIEA %g\n", pc->paint.values[0]);
295
    CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
296
 
297
    /* Apply DecodeA and MatrixA. */
298
    if (!pis->cie_joint_caches->skipDecodeABC)
299
	vlmn = *LOOKUP_ENTRY(a, &pcie->caches.DecodeA);
300
    else
301
	vlmn.u = vlmn.v = vlmn.w = a;
302
    GX_CIE_REMAP_FINISH(vlmn, pconc, pis, pcs);
303
    return 0;
304
}
305
 
306
/* Call the remap_finish procedure in the joint_caches structure. */
307
int
308
gx_cie_remap_finish(cie_cached_vector3 vec3, frac * pconc,
309
		    const gs_imager_state * pis,
310
		    const gs_color_space *pcs)
311
{
312
    return pis->cie_joint_caches->remap_finish(vec3, pconc, pis, pcs);
313
}
314
 
315
/* Finish remapping a CIEBased color. */
316
/* Return 3 if RGB, 4 if CMYK. */
317
/* this procedure is exported for the benefit of gsicc.c */
318
int
319
gx_cie_real_remap_finish(cie_cached_vector3 vec3, frac * pconc,
320
			 const gs_imager_state * pis,
321
			 const gs_color_space *pcs)
322
{
323
    const gs_cie_render *pcrd = pis->cie_render;
324
    const gx_cie_joint_caches *pjc = pis->cie_joint_caches;
325
    const gs_const_string *table = pcrd->RenderTable.lookup.table;
326
    int tabc[3];		/* indices for final EncodeABC lookup */
327
 
328
    /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */
329
    if (!pjc->skipDecodeLMN)
330
	cie_lookup_map3(&vec3 /* LMN => PQR */, &pjc->DecodeLMN,
331
			"Decode/MatrixLMN+MatrixPQR");
332
 
333
    /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */
334
    if (!pjc->skipPQR)
335
	cie_lookup_map3(&vec3 /* PQR => LMN */, &pjc->TransformPQR,
336
			"Transform/Matrix'PQR+MatrixLMN");
337
 
338
    /* Apply EncodeLMN and MatrixABC(encode). */
339
    if (!pjc->skipEncodeLMN)
340
	cie_lookup_map3(&vec3 /* LMN => ABC */, &pcrd->caches.EncodeLMN,
341
			"EncodeLMN+MatrixABC");
342
 
343
    /* MatrixABCEncode includes the scaling of the EncodeABC */
344
    /* cache index. */
345
#define SET_TABC(i, t)\
346
  BEGIN\
347
    tabc[i] = cie_cached2int(vec3 /*ABC*/.t - pcrd->EncodeABC_base[i],\
348
			     _cie_interpolate_bits);\
349
    if ((uint)tabc[i] > (gx_cie_cache_size - 1) << _cie_interpolate_bits)\
350
	tabc[i] = (tabc[i] < 0 ? 0 :\
351
		   (gx_cie_cache_size - 1) << _cie_interpolate_bits);\
352
  END
353
    SET_TABC(0, u);
354
    SET_TABC(1, v);
355
    SET_TABC(2, w);
356
#undef SET_TABC
357
    if (table == 0) {
358
	/*
359
	 * No further transformation.
360
	 * The final mapping step includes both restriction to
361
	 * the range [0..1] and conversion to fracs.
362
	 */
363
#define EABC(i)\
364
  cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.fracs.values, tabc[i])
365
	pconc[0] = EABC(0);
366
	pconc[1] = EABC(1);
367
	pconc[2] = EABC(2);
368
#undef EABC
369
	return 3;
370
    } else {
371
	/*
372
	 * Use the RenderTable.
373
	 */
374
	int m = pcrd->RenderTable.lookup.m;
375
 
376
#define RT_LOOKUP(j, i) pcrd->caches.RenderTableT[j].fracs.values[i]
377
#ifdef CIE_RENDER_TABLE_INTERPOLATE
378
 
379
	/*
380
	 * The final mapping step includes restriction to the
381
	 * ranges [0..dims[c]] as ints with interpolation bits.
382
	 */
383
	fixed rfix[3];
384
	const int s = _fixed_shift - _cie_interpolate_bits;
385
 
386
#define EABC(i)\
387
  cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.ints.values, tabc[i])
388
#define FABC(i, s)\
389
  ((s) > 0) ? (EABC(i) << (s)) : (EABC(i) >> -(s))
390
	rfix[0] = FABC(0, s);
391
	rfix[1] = FABC(1, s);
392
	rfix[2] = FABC(2, s);
393
#undef FABC
394
#undef EABC
395
	if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n",
396
		  cie_cached2float(vec3.u), cie_cached2float(vec3.v),
397
		  cie_cached2float(vec3.w), fixed2float(rfix[0]),
398
		  fixed2float(rfix[1]), fixed2float(rfix[2]));
399
	gx_color_interpolate_linear(rfix, &pcrd->RenderTable.lookup,
400
				    pconc);
401
	if_debug3('c', "[c]  interpolated => %g,%g,%g\n",
402
		  frac2float(pconc[0]), frac2float(pconc[1]),
403
		  frac2float(pconc[2]));
404
	if (!pcrd->caches.RenderTableT_is_identity) {
405
	    /* Map the interpolated values. */
406
#define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size)
407
	    pconc[0] = RT_LOOKUP(0, frac2cache_index(pconc[0]));
408
	    pconc[1] = RT_LOOKUP(1, frac2cache_index(pconc[1]));
409
	    pconc[2] = RT_LOOKUP(2, frac2cache_index(pconc[2]));
410
	    if (m > 3)
411
		pconc[3] = RT_LOOKUP(3, frac2cache_index(pconc[3]));
412
#undef frac2cache_index
413
	}
414
 
415
#else /* !CIE_RENDER_TABLE_INTERPOLATE */
416
 
417
	/*
418
	 * The final mapping step includes restriction to the ranges
419
	 * [0..dims[c]], plus scaling of the indices in the strings.
420
	 */
421
#define RI(i)\
422
  pcrd->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits]
423
	int ia = RI(0);
424
	int ib = RI(1);		/* pre-multiplied by m * NC */
425
	int ic = RI(2);		/* pre-multiplied by m */
426
	const byte *prtc = table[ia].data + ib + ic;
427
 
428
	/* (*pcrd->RenderTable.T)(prtc, m, pcrd, pconc); */
429
 
430
	if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n",
431
		  cie_cached2float(vec3.u), cie_cached2float(vec3.v),
432
		  cie_cached2float(vec3.w), ia, ib, ic);
433
	if (pcrd->caches.RenderTableT_is_identity) {
434
	    pconc[0] = byte2frac(prtc[0]);
435
	    pconc[1] = byte2frac(prtc[1]);
436
	    pconc[2] = byte2frac(prtc[2]);
437
	    if (m > 3)
438
		pconc[3] = byte2frac(prtc[3]);
439
	} else {
440
#if gx_cie_log2_cache_size == 8
441
#  define byte2cache_index(b) (b)
442
#else
443
# if gx_cie_log2_cache_size > 8
444
#  define byte2cache_index(b)\
445
    ( ((b) << (gx_cie_log2_cache_size - 8)) +\
446
      ((b) >> (16 - gx_cie_log2_cache_size)) )
447
# else				/* < 8 */
448
#  define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size))
449
# endif
450
#endif
451
	    pconc[0] = RT_LOOKUP(0, byte2cache_index(prtc[0]));
452
	    pconc[1] = RT_LOOKUP(1, byte2cache_index(prtc[1]));
453
	    pconc[2] = RT_LOOKUP(2, byte2cache_index(prtc[2]));
454
	    if (m > 3)
455
		pconc[3] = RT_LOOKUP(3, byte2cache_index(prtc[3]));
456
#undef byte2cache_index
457
	}
458
 
459
#endif /* !CIE_RENDER_TABLE_INTERPOLATE */
460
#undef RI
461
#undef RT_LOOKUP
462
	return m;
463
    }
464
}
465
 
466
/*
467
 * Finish "remapping" a CIEBased color only to the XYZ intermediate values.
468
 * Note that we can't currently represent values outside the range [0..1]:
469
 * this is a bug that we will have to address someday.
470
 */
471
private frac
472
float2frac_clamp(floatp x)
473
{
474
    return float2frac((x <= 0 ? 0 : x >= 1 ? 1 : x));
475
}
476
int
477
gx_cie_xyz_remap_finish(cie_cached_vector3 vec3, frac * pconc,
478
			const gs_imager_state * pis,
479
			const gs_color_space *pcs)
480
{
481
    const gx_cie_joint_caches *pjc = pis->cie_joint_caches;
482
 
483
    /*
484
     * All the steps through DecodeABC/MatrixABC have been applied, i.e.,
485
     * vec3 is LMN values.  Just apply DecodeLMN/MatrixLMN.
486
     */
487
    if (!pjc->skipDecodeLMN)
488
	cie_lookup_map3(&vec3 /* LMN => XYZ */, &pjc->DecodeLMN,
489
			"Decode/MatrixLMN");
490
 
491
 
492
    pconc[0] = float2frac_clamp(cie_cached2float(vec3.u));
493
    pconc[1] = float2frac_clamp(cie_cached2float(vec3.v));
494
    pconc[2] = float2frac_clamp(cie_cached2float(vec3.w));
495
    return 3;
496
}
497
 
498
/* Look up 3 values in a cache, with cached post-multiplication. */
499
private void
500
cie_lookup_mult3(cie_cached_vector3 * pvec,
501
		 const gx_cie_vector_cache3_t * pc)
502
{
503
#ifdef CIE_CACHE_INTERPOLATE
504
    cie_cached_value u, v, w;
505
 
506
#ifdef CIE_CACHE_USE_FIXED
507
#  define LOOKUP_INTERPOLATE_BETWEEN(v0, v1, i, ftemp)\
508
     cie_interpolate_between(v0, v1, i)
509
#else
510
    float ftemp;
511
 
512
#  define LOOKUP_INTERPOLATE_BETWEEN(v0, v1, i)\
513
     ((v0) + ((v1) - (v0)) *\
514
      ((ftemp = float_rshift(i, _cie_interpolate_bits)), ftemp - (int)ftemp))
515
#endif
516
 
517
	 /*
518
	  * Defining a macro for the entire component calculation would
519
	  * minimize source code, but it would make the result impossible
520
	  * to trace or debug.  We use smaller macros instead, and run
521
	  * the usual risks associated with having 3 copies of the code.
522
	  * Note that pvec and pc are free variables in these macros.
523
	  */
524
 
525
#define I_IN_RANGE(j, n)\
526
  (pvec->n >= pc->interpolation_ranges[j].rmin &&\
527
   pvec->n < pc->interpolation_ranges[j].rmax)
528
#define I_INDEX(j, n)\
529
  LOOKUP_INDEX(pvec->n, &pc->caches[j], _cie_interpolate_bits)
530
#define I_ENTRY(i, j)\
531
  &pc->caches[j].vecs.values[(int)cie_cached_rshift(i, _cie_interpolate_bits)]
532
#define I_ENTRY1(i, p)\
533
  (i >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ? p : p + 1)
534
 
535
    if (I_IN_RANGE(0, u)) {
536
	cie_cached_value i = I_INDEX(0, u);
537
	const cie_cached_vector3 *p = I_ENTRY(i, 0);
538
	const cie_cached_vector3 *p1 = I_ENTRY1(i, p);
539
 
540
	if_debug0('C', "[c]Interpolating u.\n");
541
	u = LOOKUP_INTERPOLATE_BETWEEN(p->u, p1->u, i);
542
	v = LOOKUP_INTERPOLATE_BETWEEN(p->v, p1->v, i);
543
	w = LOOKUP_INTERPOLATE_BETWEEN(p->w, p1->w, i);
544
    } else {
545
	const cie_cached_vector3 *p = LOOKUP_ENTRY(pvec->u, &pc->caches[0]);
546
 
547
	if_debug0('C', "[c]Not interpolating u.\n");
548
	u = p->u, v = p->v, w = p->w;
549
    }
550
 
551
    if (I_IN_RANGE(1, v)) {
552
	cie_cached_value i = I_INDEX(1, v);
553
	const cie_cached_vector3 *p = I_ENTRY(i, 1);
554
	const cie_cached_vector3 *p1 = I_ENTRY1(i, p);
555
 
556
	if_debug0('C', "[c]Interpolating v.\n");
557
	u += LOOKUP_INTERPOLATE_BETWEEN(p->u, p1->u, i);
558
	v += LOOKUP_INTERPOLATE_BETWEEN(p->v, p1->v, i);
559
	w += LOOKUP_INTERPOLATE_BETWEEN(p->w, p1->w, i);
560
    } else {
561
	const cie_cached_vector3 *p = LOOKUP_ENTRY(pvec->v, &pc->caches[1]);
562
 
563
	if_debug0('C', "[c]Not interpolating v.\n");
564
	u += p->u, v += p->v, w += p->w;
565
    }
566
 
567
    if (I_IN_RANGE(2, w)) {
568
	cie_cached_value i = I_INDEX(2, w);
569
	const cie_cached_vector3 *p = I_ENTRY(i, 2);
570
	const cie_cached_vector3 *p1 = I_ENTRY1(i, p);
571
 
572
	if_debug0('C', "[c]Interpolating w.\n");
573
	u += LOOKUP_INTERPOLATE_BETWEEN(p->u, p1->u, i);
574
	v += LOOKUP_INTERPOLATE_BETWEEN(p->v, p1->v, i);
575
	w += LOOKUP_INTERPOLATE_BETWEEN(p->w, p1->w, i);
576
    } else {
577
	const cie_cached_vector3 *p = LOOKUP_ENTRY(pvec->w, &pc->caches[2]);
578
 
579
	if_debug0('C', "[c]Not interpolating w.\n");
580
	u += p->u, v += p->v, w += p->w;
581
    }
582
 
583
#undef I_IN_RANGE
584
#undef I_INDEX
585
#undef I_ENTRY
586
#undef I_ENTRY1
587
 
588
    pvec->u = u;
589
    pvec->v = v;
590
    pvec->w = w;
591
 
592
#else  /* no interpolation */
593
 
594
    const cie_cached_vector3 *pu = LOOKUP_ENTRY(pvec->u, &pc->caches[0]);
595
    const cie_cached_vector3 *pv = LOOKUP_ENTRY(pvec->v, &pc->caches[1]);
596
    const cie_cached_vector3 *pw = LOOKUP_ENTRY(pvec->w, &pc->caches[2]);
597
 
598
    if_debug0('C', "[c]Not interpolating.\n");
599
 
600
    pvec->u = pu->u + pv->u + pw->u;
601
    pvec->v = pu->v + pv->v + pw->v;
602
    pvec->w = pu->w + pv->w + pw->w;
603
 
604
#endif /* (no) interpolation */
605
}