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
LOOKUP_INDEX(cie_cached_value vin,const gx_cie_vector_cache * pcache,int fbits)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 *
LOOKUP_ENTRY(cie_cached_value vin,const gx_cie_vector_cache * pcache)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
cie_lookup_map3(cie_cached_vector3 * pvec,const gx_cie_vector_cache3_t * pc,const char * cname)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
gx_concretize_CIEDEFG(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)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
gx_concretize_CIEDEF(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)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
gx_remap_CIEABC(const gs_client_color * pc,const gs_color_space * pcs,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)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
gx_concretize_CIEABC(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)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
gx_concretize_CIEA(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)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
gx_cie_remap_finish(cie_cached_vector3 vec3,frac * pconc,const gs_imager_state * pis,const gs_color_space * pcs)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
gx_cie_real_remap_finish(cie_cached_vector3 vec3,frac * pconc,const gs_imager_state * pis,const gs_color_space * pcs)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
float2frac_clamp(floatp x)472 float2frac_clamp(floatp x)
473 {
474 return float2frac((x <= 0 ? 0 : x >= 1 ? 1 : x));
475 }
476 int
gx_cie_xyz_remap_finish(cie_cached_vector3 vec3,frac * pconc,const gs_imager_state * pis,const gs_color_space * pcs)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
cie_lookup_mult3(cie_cached_vector3 * pvec,const gx_cie_vector_cache3_t * pc)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 }
606