ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/color.c
Revision: 2.40
Committed: Sun Mar 9 19:11:51 2025 UTC (7 weeks, 5 days ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.39: +66 -30 lines
Log Message:
perf: Eliminated calls to ldexp() in favor of exponent multiplier table

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.40 static const char RCSid[] = "$Id: color.c,v 2.39 2025/02/06 02:15:45 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * color.c - routines for color calculations.
6     *
7 greg 2.9 * Externals declared in color.h
8     */
9    
10 greg 2.10 #include "copyright.h"
11 greg 1.1
12     #include <stdio.h>
13 greg 2.9 #include <stdlib.h>
14 greg 2.7 #include <math.h>
15 greg 1.1 #include "color.h"
16 greg 2.14
17     #ifdef getc_unlocked /* avoid horrendous overhead of flockfile */
18 greg 2.15 #undef getc
19     #undef putc
20 greg 2.19 #undef ferror
21 greg 2.14 #define getc getc_unlocked
22     #define putc putc_unlocked
23 greg 2.18 #define ferror ferror_unlocked
24 greg 2.14 #endif
25 greg 1.1
26 greg 2.34 #define MINELEN 17 /* minimum scanline length for encoding */
27 greg 2.6 #define MAXELEN 0x7fff /* maximum scanline length for encoding */
28 greg 1.14 #define MINRUN 4 /* minimum run length */
29    
30 greg 2.40 const float cxponent[256] = { /* exponent look-up */
31     .0f, 2.2958874e-41f, 4.59177481e-41f, 9.18354962e-41f,
32     1.83670992e-40f, 3.67341985e-40f, 7.34683969e-40f, 1.46936794e-39f,
33     2.93873588e-39f, 5.87747175e-39f, 1.17549435e-38f, 2.3509887e-38f,
34     4.7019774e-38f, 9.40395481e-38f, 1.88079096e-37f, 3.76158192e-37f,
35     7.52316385e-37f, 1.50463277e-36f, 3.00926554e-36f, 6.01853108e-36f,
36     1.20370622e-35f, 2.40741243e-35f, 4.81482486e-35f, 9.62964972e-35f,
37     1.92592994e-34f, 3.85185989e-34f, 7.70371978e-34f, 1.54074396e-33f,
38     3.08148791e-33f, 6.16297582e-33f, 1.23259516e-32f, 2.46519033e-32f,
39     4.93038066e-32f, 9.86076132e-32f, 1.97215226e-31f, 3.94430453e-31f,
40     7.88860905e-31f, 1.57772181e-30f, 3.15544362e-30f, 6.31088724e-30f,
41     1.26217745e-29f, 2.5243549e-29f, 5.04870979e-29f, 1.00974196e-28f,
42     2.01948392e-28f, 4.03896783e-28f, 8.07793567e-28f, 1.61558713e-27f,
43     3.23117427e-27f, 6.46234854e-27f, 1.29246971e-26f, 2.58493941e-26f,
44     5.16987883e-26f, 1.03397577e-25f, 2.06795153e-25f, 4.13590306e-25f,
45     8.27180613e-25f, 1.65436123e-24f, 3.30872245e-24f, 6.6174449e-24f,
46     1.32348898e-23f, 2.64697796e-23f, 5.29395592e-23f, 1.05879118e-22f,
47     2.11758237e-22f, 4.23516474e-22f, 8.47032947e-22f, 1.69406589e-21f,
48     3.38813179e-21f, 6.77626358e-21f, 1.35525272e-20f, 2.71050543e-20f,
49     5.42101086e-20f, 1.08420217e-19f, 2.16840434e-19f, 4.33680869e-19f,
50     8.67361738e-19f, 1.73472348e-18f, 3.46944695e-18f, 6.9388939e-18f,
51     1.38777878e-17f, 2.77555756e-17f, 5.55111512e-17f, 1.11022302e-16f,
52     2.22044605e-16f, 4.4408921e-16f, 8.8817842e-16f, 1.77635684e-15f,
53     3.55271368e-15f, 7.10542736e-15f, 1.42108547e-14f, 2.84217094e-14f,
54     5.68434189e-14f, 1.13686838e-13f, 2.27373675e-13f, 4.54747351e-13f,
55     9.09494702e-13f, 1.8189894e-12f, 3.63797881e-12f, 7.27595761e-12f,
56     1.45519152e-11f, 2.91038305e-11f, 5.82076609e-11f, 1.16415322e-10f,
57     2.32830644e-10f, 4.65661287e-10f, 9.31322575e-10f, 1.86264515e-09f,
58     3.7252903e-09f, 7.4505806e-09f, 1.49011612e-08f, 2.98023224e-08f,
59     5.96046448e-08f, 1.1920929e-07f, 2.38418579e-07f, 4.76837158e-07f,
60     9.53674316e-07f, 1.90734863e-06f, 3.81469727e-06f, 7.62939453e-06f,
61     1.52587891e-05f, 3.05175781e-05f, 6.10351562e-05f, 0.000122070312f,
62     0.000244140625f, 0.00048828125f, 0.0009765625f, 0.001953125f,
63     0.00390625f, 0.0078125f, 0.015625f, 0.03125f, 0.0625f, 0.125f,
64     0.25f, 0.5f, 1.f, 2.f, 4.f, 8.f, 16.f, 32.f, 64.f, 128.f, 256.f,
65     512.f, 1024.f, 2048.f, 4096.f, 8192.f, 16384.f, 32768.f, 65536.f,
66     131072.f, 262144.f, 524288.f, 1048576.f, 2097152.f, 4194304.f,
67     8388608.f, 16777216.f, 33554432.f, 67108864.f, 134217728.f,
68     268435456.f, 536870912.f, 1.07374182e+09f, 2.14748365e+09f,
69     4.2949673e+09f, 8.58993459e+09f, 1.71798692e+10f, 3.43597384e+10f,
70     6.87194767e+10f, 1.37438953e+11f, 2.74877907e+11f, 5.49755814e+11f,
71     1.09951163e+12f, 2.19902326e+12f, 4.39804651e+12f, 8.79609302e+12f,
72     1.7592186e+13f, 3.51843721e+13f, 7.03687442e+13f, 1.40737488e+14f,
73     2.81474977e+14f, 5.62949953e+14f, 1.12589991e+15f, 2.25179981e+15f,
74     4.50359963e+15f, 9.00719925e+15f, 1.80143985e+16f, 3.6028797e+16f,
75     7.2057594e+16f, 1.44115188e+17f, 2.88230376e+17f, 5.76460752e+17f,
76     1.1529215e+18f, 2.30584301e+18f, 4.61168602e+18f, 9.22337204e+18f,
77     1.84467441e+19f, 3.68934881e+19f, 7.37869763e+19f, 1.47573953e+20f,
78     2.95147905e+20f, 5.9029581e+20f, 1.18059162e+21f, 2.36118324e+21f,
79     4.72236648e+21f, 9.44473297e+21f, 1.88894659e+22f, 3.77789319e+22f,
80     7.55578637e+22f, 1.51115727e+23f, 3.02231455e+23f, 6.0446291e+23f,
81     1.20892582e+24f, 2.41785164e+24f, 4.83570328e+24f, 9.67140656e+24f,
82     1.93428131e+25f, 3.86856262e+25f, 7.73712525e+25f, 1.54742505e+26f,
83     3.0948501e+26f, 6.1897002e+26f, 1.23794004e+27f, 2.47588008e+27f,
84     4.95176016e+27f, 9.90352031e+27f, 1.98070406e+28f, 3.96140813e+28f,
85     7.92281625e+28f, 1.58456325e+29f, 3.1691265e+29f, 6.338253e+29f,
86     1.2676506e+30f, 2.5353012e+30f, 5.0706024e+30f, 1.01412048e+31f,
87     2.02824096e+31f, 4.05648192e+31f, 8.11296384e+31f, 1.62259277e+32f,
88     3.24518554e+32f, 6.49037107e+32f, 1.29807421e+33f, 2.59614843e+33f,
89     5.19229686e+33f, 1.03845937e+34f, 2.07691874e+34f, 4.15383749e+34f,
90     8.30767497e+34f, 1.66153499e+35f, 3.32306999e+35f, 6.64613998e+35f
91     };
92 greg 2.4
93 greg 2.27 int CNDX[4] = {0,1,2,3}; /* RGBE indices for SCOLOR, SCOLR */
94     float WLPART[4] = {780,588,480,380}; /* RGB wavelength limits+partitions (nm) */
95    
96    
97     int
98     setspectrsamp( /* assign spectral sampling, 1 if good, -1 if bad */
99     int cn[4], /* input cn[3]=nsamps */
100     float wlpt[4] /* input wlpt[0],wlpt[3]=extrema */
101     )
102     {
103     static const float PKWL[3] = {607, 553, 469};
104     int i, j;
105    
106     if (cn[3] < 3)
107     return(-1); /* reject this */
108    
109     if (wlpt[0] < wlpt[3]) {
110     float tf = wlpt[0];
111     wlpt[0] = wlpt[3]; wlpt[3] = tf;
112     }
113     if (wlpt[0] - wlpt[3] < 50.f)
114     return(-1); /* also reject */
115    
116     if (cn[3] > MAXCSAMP)
117     cn[3] = MAXCSAMP;
118    
119     if ((wlpt[3] >= PKWL[2]) | (wlpt[0] <= PKWL[0])) {
120     wlpt[1] = wlpt[0] + 0.333333f*(wlpt[3]-wlpt[0]);
121     wlpt[2] = wlpt[0] + 0.666667f*(wlpt[3]-wlpt[0]);
122     cn[0] = 0; cn[1] = cn[3]/3; cn[2] = cn[3]*2/3;
123     return(0); /* unhappy but non-fatal return value */
124     }
125     wlpt[1] = 588.f; /* tuned for standard green channel */
126     wlpt[2] = 480.f;
127     if (cn[3] == 3) { /* nothing to tune? */
128     cn[0] = 0; cn[1] = 1; cn[2] = 2;
129     } else { /* else find nearest color indices */
130     double curwl[3];
131     memset(curwl, 0, sizeof(curwl));
132     for (i = cn[3]; i--; ) {
133     const float cwl = (i+.5f)/cn[3]*(wlpt[3]-wlpt[0]) + wlpt[0];
134     for (j = 3; j--; )
135     if (fabs(cwl - PKWL[j]) < fabs(curwl[j] - PKWL[j])) {
136     curwl[j] = cwl;
137     cn[j] = i;
138     }
139     }
140     }
141     return(1); /* happy return value */
142     }
143    
144    
145     void
146     setscolor( /* assign spectral color from RGB */
147     SCOLOR scol,
148     double r,
149     double g,
150     double b
151     )
152     {
153 greg 2.39 double step, cwl;
154 greg 2.27 int i;
155    
156 greg 2.39 if (NCSAMP == 3) {
157     setcolor(scol, r, g, b);
158     return;
159     }
160     step = (WLPART[3] - WLPART[0])/(double)NCSAMP;
161     cwl = WLPART[0] + .5*step;
162 greg 2.27 for (i = 0; i < NCSAMP; i++) {
163     if (cwl >= WLPART[1])
164     scol[i] = r;
165     else if (cwl >= WLPART[2])
166     scol[i] = g;
167     else
168     scol[i] = b;
169     cwl += step;
170     }
171     }
172    
173    
174     void
175 greg 2.38 setscolr( /* assign common-exponent spectral from RGB */
176     SCOLR sclr,
177     double r,
178     double g,
179     double b
180     )
181     {
182     SCOLOR scol;
183    
184     setscolor(scol, r, g, b);
185     scolor2scolr(sclr, scol, NCSAMP);
186     }
187    
188    
189     void
190 greg 2.27 scolor2color( /* assign RGB color from spectrum */
191     COLOR col,
192 greg 2.35 const SCOLOR scol, /* uses average over bands */
193 greg 2.27 int ncs,
194 greg 2.30 const float wlpt[4]
195 greg 2.27 )
196     {
197     const double step = (wlpt[3] - wlpt[0])/(double)ncs;
198     double cwl = wlpt[0] + .5*step;
199     int i, j=0, n=0;
200    
201     setcolor(col, 0, 0, 0);
202     for (i = 0; i < ncs; i++) {
203     if (cwl < wlpt[j+1]) {
204     if (n > 1) col[j] /= (COLORV)n;
205     j++;
206     n = 0;
207     }
208     col[j] += scol[i];
209     n++;
210     cwl += step;
211     }
212     if (n > 1) col[j] /= (COLORV)n;
213     }
214    
215    
216     void
217 greg 2.36 scolr2colr( /* assign RGBE from common-exponent spectrum */
218     COLR clr,
219     const SCOLR sclr,
220     int ncs,
221     const float wlpt[4]
222     )
223 greg 2.37 #if 0 /* fancier method seems to be slower(!) */
224 greg 2.36 {
225     const double step = (wlpt[3] - wlpt[0])/(double)ncs;
226     double cwl;
227     int csum[3], cnt[3], eshft;
228     int i, j;
229    
230     csum[0] = csum[1] = csum[2] = 0;
231     cnt[0] = cnt[1] = cnt[2] = 0;
232     cwl = wlpt[j=0] + .5*step;
233     for (i = 0; i < ncs; i++) {
234     csum[j] += sclr[i];
235     ++cnt[j];
236     j += ((cwl += step) < wlpt[j+1]);
237     }
238     eshft = 7; /* compute exponent shift */
239     for (j = 3; (eshft > 0) & (j-- > 0); ) {
240     i = 0;
241     while (csum[j] < 128*cnt[j] >> i)
242     if (++i >= eshft)
243     break;
244     if (eshft > i)
245     eshft = i;
246     }
247     if (sclr[ncs] <= eshft) {
248     clr[RED] = clr[GRN] = clr[BLU] = 0;
249     clr[EXP] = 0;
250     return;
251     }
252     for (j = 3; j--; )
253     clr[j] = (csum[j]<<eshft)/cnt[j];
254    
255     clr[EXP] = sclr[ncs] - eshft;
256     }
257 greg 2.37 #else
258     {
259     SCOLOR scol;
260     COLOR col;
261    
262     scolr2scolor(scol, sclr, ncs);
263     scolor2color(col, scol, ncs, wlpt);
264     setcolr(clr, col[RED], col[GRN], col[BLU]);
265     }
266     #endif
267 greg 2.36
268    
269     void
270 greg 2.27 scolor2colr( /* assign RGBE from spectral color */
271     COLR clr,
272 greg 2.35 const SCOLOR scol, /* uses average over bands */
273 greg 2.27 int ncs,
274 greg 2.30 const float wlpt[4]
275 greg 2.27 )
276     {
277     COLOR col;
278    
279     scolor2color(col, scol, ncs, wlpt);
280     setcolr(clr, col[RED], col[GRN], col[BLU]);
281     }
282    
283    
284     void
285 greg 2.33 scolr2color( /* assign RGB from common exponent */
286     COLOR col,
287 greg 2.35 const SCOLR sclr,
288 greg 2.33 int ncs,
289     const float wlpt[4]
290     )
291     {
292     SCOLOR scol;
293    
294     scolr2scolor(scol, sclr, ncs);
295     scolor2color(col, scol, ncs, wlpt);
296     }
297    
298    
299     void
300 greg 2.27 scolor2scolr( /* float spectrum to common exponent */
301     SCOLR sclr,
302 greg 2.35 const SCOLOR scol,
303 greg 2.27 int ncs
304     )
305     {
306     int i = ncs;
307     COLORV p = scol[--i];
308    
309     while (i)
310     if (scol[--i] > p)
311     p = scol[i];
312     if (p <= 1e-32) {
313     memset(sclr, 0, ncs+1);
314     return;
315     }
316     p = frexp(p, &i) * 256.0 / p;
317     sclr[ncs] = i + COLXS;
318     for (i = ncs; i--; )
319     sclr[i] = (scol[i] > 0) * (int)(scol[i]*p);
320     }
321    
322    
323     void
324     scolr2scolor( /* common exponent to float spectrum */
325     SCOLOR scol,
326 greg 2.35 const SCOLR sclr,
327 greg 2.27 int ncs
328     )
329     {
330     double f;
331     int i;
332    
333     if (sclr[ncs] == 0) {
334     memset(scol, 0, sizeof(COLORV)*ncs);
335     return;
336     }
337 greg 2.40 f = cxponent[sclr[ncs]];
338 greg 2.27
339     for (i = ncs; i--; )
340     scol[i] = (sclr[i] + 0.5)*f;
341     }
342    
343    
344     double
345     scolor_mean( /* compute average for spectral color */
346 greg 2.35 const SCOLOR scol
347 greg 2.27 )
348     {
349     int i = NCSAMP;
350     double sum = 0;
351    
352     while (i--)
353     sum += scol[i];
354    
355     return sum/(double)NCSAMP;
356     }
357    
358    
359     double
360     sintens( /* find maximum value from spectrum */
361 greg 2.35 const SCOLOR scol
362 greg 2.27 )
363     {
364     int i = NCSAMP;
365     COLORV peak = scol[--i];
366    
367     while (i)
368     if (scol[--i] > peak)
369     peak = scol[i];
370    
371     return peak;
372     }
373    
374    
375     void
376     convertscolor( /* spectrum conversion, zero-fill ends */
377     SCOLOR dst, /* destination spectrum */
378     int dnc, /* destination # of spectral samples/intervals */
379     double dwl0, /* starting destination wavelength (longer) */
380     double dwl1, /* ending destination wavelength (shorter) */
381     const COLORV src[], /* source spectrum array */
382     int snc,
383     double swl0, /* long/short wavelengths may be reversed */
384     double swl1
385     )
386     {
387     const int sdir = 1 - 2*(swl0 < swl1);
388     const double sstp = (swl1 - swl0)/(double)snc;
389     const double dstp = (dwl1 - dwl0)/(double)dnc;
390     const double rdstp = 1./dstp;
391     int si, ssi, di;
392     double wl;
393    
394     if ((dnc < 3) | (dwl0 <= dwl1) | (dst == src))
395     return; /* invalid destination */
396    
397     if (dnc == snc && (dwl0-swl0)*(dwl0-swl0) + (dwl1-swl1)*(dwl1-swl1) <= .5) {
398     memcpy(dst, src, sizeof(COLORV)*dnc);
399     return; /* same spectral sampling */
400     }
401     memset(dst, 0, sizeof(COLORV)*dnc);
402     /* set starting positions */
403     if ((sdir>0 ? swl0 : swl1) <= dwl0) {
404     if (sdir > 0) {
405     wl = swl0;
406     ssi = 0;
407     } else {
408     wl = swl1;
409     ssi = snc-1;
410     }
411     si = 0;
412     di = (wl - dwl0)*rdstp;
413     } else {
414     wl = dwl0;
415 greg 2.29 if (sdir > 0) {
416     ssi = si = (wl - swl0)/sstp;
417     } else {
418     si = (wl - swl1)/sstp;
419     ssi = snc-1 - si;
420     }
421 greg 2.27 di = 0;
422     }
423     swl0 += (sdir < 0)*sstp;
424     /* step through intervals */
425     while ((si < snc) & (di < dnc)) {
426     double intvl;
427     if (swl0 + (ssi+sdir)*sstp < dwl0 + (di+1)*dstp) {
428     intvl = dwl0 + (di+1)*dstp - wl;
429     dst[di++] += src[ssi]*intvl*rdstp;
430     } else {
431     intvl = swl0 + (ssi+sdir)*sstp - wl;
432     dst[di] += src[ssi]*intvl*rdstp;
433     ssi += sdir;
434     si++;
435     }
436     wl += intvl;
437     }
438     }
439    
440    
441 greg 2.22 void *
442 greg 2.17 tempbuffer( /* get a temporary buffer */
443 greg 2.27 size_t len
444 greg 2.17 )
445 greg 1.14 {
446 greg 2.27 static void *tempbuf = NULL;
447     static size_t tempbuflen = 0;
448 greg 1.14
449 greg 2.22 if (!len) { /* call to free */
450     if (tempbuflen) {
451 greg 2.20 free(tempbuf);
452 greg 2.22 tempbuf = NULL;
453     tempbuflen = 0;
454     }
455     return(NULL);
456 greg 1.14 }
457 greg 2.22 if (len <= tempbuflen) /* big enough already? */
458     return(tempbuf);
459     /* else free & reallocate */
460     if (tempbuflen)
461     free(tempbuf);
462     tempbuf = malloc(len);
463     tempbuflen = len*(tempbuf != NULL);
464 greg 1.14 return(tempbuf);
465     }
466    
467    
468 greg 2.9 int
469 greg 2.17 fwritecolrs( /* write out a colr scanline */
470     COLR *scanline,
471     int len,
472     FILE *fp
473     )
474 greg 1.1 {
475 greg 2.17 int i, j, beg, cnt = 1;
476 greg 1.14 int c2;
477 greg 1.1
478 schorsch 2.13 if ((len < MINELEN) | (len > MAXELEN)) /* OOBs, write out flat */
479 greg 1.14 return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len);
480 greg 2.2 /* put magic header */
481     putc(2, fp);
482 greg 1.14 putc(2, fp);
483     putc(len>>8, fp);
484 greg 2.21 putc(len&0xff, fp);
485 greg 1.14 /* put components seperately */
486     for (i = 0; i < 4; i++) {
487     for (j = 0; j < len; j += cnt) { /* find next run */
488     for (beg = j; beg < len; beg += cnt) {
489 greg 2.20 for (cnt = 1; (cnt < 127) & (beg+cnt < len) &&
490 greg 1.14 scanline[beg+cnt][i] == scanline[beg][i]; cnt++)
491     ;
492     if (cnt >= MINRUN)
493     break; /* long enough */
494 greg 1.1 }
495 greg 2.20 if ((beg-j > 1) & (beg-j < MINRUN)) {
496 greg 1.15 c2 = j+1;
497     while (scanline[c2++][i] == scanline[j][i])
498     if (c2 == beg) { /* short run */
499     putc(128+beg-j, fp);
500     putc(scanline[j][i], fp);
501     j = beg;
502     break;
503     }
504     }
505     while (j < beg) { /* write out non-run */
506 greg 1.14 if ((c2 = beg-j) > 128) c2 = 128;
507     putc(c2, fp);
508     while (c2--)
509     putc(scanline[j++][i], fp);
510     }
511     if (cnt >= MINRUN) { /* write out run */
512     putc(128+cnt, fp);
513     putc(scanline[beg][i], fp);
514     } else
515     cnt = 0;
516     }
517 greg 1.1 }
518     return(ferror(fp) ? -1 : 0);
519     }
520    
521 greg 2.23 /*
522     * An old-format scanline is either a stream of valid RGBE or XYZE real
523     * pixels or at least one real pixel followed by some number of
524     * invalid real pixels of the form (1,1,1,n), where n is a count.
525     * These can themselves be repeated to create a multibyte repeat
526     * count, with the least significant byte first (little-endian order.)
527     * Repeat counts are limited by the size of an int; if a repetition
528     * leads to an overrun, the rest of the the repetition will be
529     * silently ignored.
530     */
531 greg 2.9 static int
532 greg 2.19 oldreadcolrs( /* read in an old-style colr scanline */
533 greg 2.17 COLR *scanline,
534     int len,
535     FILE *fp
536     )
537 greg 2.9 {
538 greg 2.25 int rshift = 0;
539 greg 2.17 int i;
540 greg 2.9
541     while (len > 0) {
542     scanline[0][RED] = getc(fp);
543     scanline[0][GRN] = getc(fp);
544     scanline[0][BLU] = getc(fp);
545 greg 2.18 scanline[0][EXP] = i = getc(fp);
546     if (i == EOF)
547 greg 2.9 return(-1);
548 greg 2.20 if (scanline[0][GRN] == 1 &&
549     (scanline[0][RED] == 1) &
550 greg 2.25 (scanline[0][BLU] == 1)) {
551 greg 2.20 i = scanline[0][EXP] << rshift;
552     while (i--) {
553 greg 2.9 copycolr(scanline[0], scanline[-1]);
554 greg 2.20 if (--len <= 0)
555     return(0);
556 greg 2.9 scanline++;
557     }
558     rshift += 8;
559     } else {
560     scanline++;
561     len--;
562     rshift = 0;
563     }
564     }
565     return(0);
566     }
567    
568 greg 2.23 /*
569     * There are two scanline formats: old and new. The old format
570     * compresses runs of RGBE or XYZE four-byte real pixels; the new
571     * format breaks the pixels into R, G, B, and E lines (or XYZE lines)
572     * which are individually run-length encoded.
573     *
574     * An old-format scanline always begins with a valid real pixel; at
575     * least one of the RGB (or XYZ) values will have its high-order bit
576     * set. A new-format scanline begins with four bytes which are not a
577     * valid real pixel: (2, 2, lenhigh, lenlow) where lenhigh is always
578     * less than 128 and hence never has a high-order bit set.
579     *
580     * A new-format scanline is broken into its RGBE or XYZE components.
581     * Each is output and run-length encoded separately so that a scanline
582     * is broken into four records. In turn, each record is organized
583     * into chunks of up to 128 characters, which begin with a count byte.
584     * If the count byte is greater than 128, the following data byte is
585     * repeated (count-128) times. If not, the count byte is followed by
586     * that many data bytes.
587     */
588 greg 2.9 int
589 greg 2.17 freadcolrs( /* read in an encoded colr scanline */
590     COLR *scanline,
591     int len,
592     FILE *fp
593     )
594 greg 1.1 {
595 greg 2.17 int i, j;
596 greg 2.6 int code, val;
597 greg 1.14 /* determine scanline type */
598 greg 2.26 if (len <= 0)
599     return(0);
600 greg 1.14 if ((i = getc(fp)) == EOF)
601     return(-1);
602 greg 2.26 scanline[0][RED] = i;
603 greg 1.14 scanline[0][GRN] = getc(fp);
604     scanline[0][BLU] = getc(fp);
605     if ((i = getc(fp)) == EOF)
606     return(-1);
607 greg 2.26 if ((scanline[0][RED] != 2) | (scanline[0][GRN] != 2) |
608     (scanline[0][BLU] & 0x80)) {
609 greg 1.14 scanline[0][EXP] = i;
610     return(oldreadcolrs(scanline+1, len-1, fp));
611     }
612     if ((scanline[0][BLU]<<8 | i) != len)
613     return(-1); /* length mismatch! */
614     /* read each component */
615     for (i = 0; i < 4; i++)
616     for (j = 0; j < len; ) {
617     if ((code = getc(fp)) == EOF)
618     return(-1);
619     if (code > 128) { /* run */
620 greg 2.6 code &= 127;
621 greg 2.9 if ((val = getc(fp)) == EOF)
622     return -1;
623 greg 2.16 if (j + code > len)
624     return -1; /* overrun */
625 greg 2.6 while (code--)
626     scanline[j++][i] = val;
627 greg 2.16 } else { /* non-run */
628     if (j + code > len)
629     return -1; /* overrun */
630 greg 2.9 while (code--) {
631     if ((val = getc(fp)) == EOF)
632     return -1;
633     scanline[j++][i] = val;
634     }
635 greg 2.16 }
636 greg 1.14 }
637 greg 1.1 return(0);
638     }
639    
640    
641 greg 2.30 /* read an nc-component common-exponent color scanline */
642     int
643 greg 2.35 freadscolrs(COLRV *scanline, int nc, int len, FILE *fp)
644 greg 2.30 {
645 greg 2.32 if (nc < 3)
646     return(-1);
647     if (nc == 3)
648     return(freadcolrs((COLR *)scanline, len, fp));
649    
650 greg 2.30 if (fread(scanline, nc+1, len, fp) != len)
651     return(-1);
652     return(0);
653     }
654    
655    
656 greg 2.36 /* read nc-component common-exponent color scan and convert to COLR's */
657     int
658     fread2colrs(COLR *scanline, int len, FILE *fp, int nc, const float wlpt[4])
659     {
660     COLRV *sclrscan;
661     int n;
662    
663     if (nc < 3)
664     return(-1);
665     if (nc == 3)
666     return(freadcolrs(scanline, len, fp));
667    
668     sclrscan = (COLRV *)tempbuffer(sizeof(COLRV)*(nc+1)*len);
669     if (sclrscan == NULL || freadscolrs(sclrscan, nc, len, fp) < 0)
670     return(-1);
671     for (n = len; n--; ) {
672     scolr2colr(*scanline++, sclrscan, nc, wlpt);
673     sclrscan += nc+1;
674     }
675     return(0);
676     }
677    
678    
679 greg 2.31 /* write an common-exponent spectral color scanline */
680 greg 2.30 int
681 greg 2.35 fwritescolrs(const COLRV *sscanline, int nc, int len, FILE *fp)
682 greg 2.30 {
683 greg 2.32 if (nc < 3)
684     return(-1);
685     if (nc == 3)
686     return(fwritecolrs((COLR *)sscanline, len, fp));
687    
688 greg 2.31 if (fwrite(sscanline, nc+1, len, fp) != len)
689 greg 2.30 return(-1);
690     return(0);
691     }
692    
693    
694 greg 2.9 int
695 greg 2.32 fwritescan( /* write out an RGB or XYZ scanline */
696 greg 2.17 COLOR *scanline,
697     int len,
698     FILE *fp
699     )
700 greg 1.1 {
701 greg 1.14 COLR *clrscan;
702     int n;
703 greg 2.17 COLR *sp;
704 greg 1.14 /* get scanline buffer */
705     if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
706     return(-1);
707     clrscan = sp;
708     /* convert scanline */
709     n = len;
710     while (n-- > 0) {
711     setcolr(sp[0], scanline[0][RED],
712 greg 1.1 scanline[0][GRN],
713     scanline[0][BLU]);
714     scanline++;
715 greg 1.14 sp++;
716 greg 1.1 }
717 greg 1.14 return(fwritecolrs(clrscan, len, fp));
718 greg 1.1 }
719    
720    
721 greg 2.9 int
722 greg 2.32 freadscan( /* read in an RGB or XYZ scanline */
723 greg 2.17 COLOR *scanline,
724     int len,
725     FILE *fp
726     )
727 greg 1.1 {
728 greg 2.17 COLR *clrscan;
729 greg 1.14
730     if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
731     return(-1);
732     if (freadcolrs(clrscan, len, fp) < 0)
733     return(-1);
734     /* convert scanline */
735 greg 2.40 while (len-- > 0) {
736     colr_color(scanline[0], clrscan[0]);
737 greg 1.14 scanline++; clrscan++;
738 greg 1.1 }
739     return(0);
740     }
741    
742    
743 greg 2.30 /* read an nc-component color scanline */
744     int
745     freadsscan(COLORV *sscanline, int nc, int len, FILE *fp)
746     {
747 greg 2.35 COLRV *tscn = (COLRV *)tempbuffer((nc+1)*len);
748 greg 2.30 int i;
749    
750     if (tscn == NULL || freadscolrs(tscn, nc, len, fp) < 0)
751     return(-1);
752     for (i = len; i-- > 0; ) {
753     scolr2scolor(sscanline, tscn, nc);
754     sscanline += nc;
755     tscn += nc+1;
756     }
757     return(0);
758     }
759    
760    
761 greg 2.36 /* read an nc-component color scanline and return as RGB */
762     int
763     fread2scan(COLOR *scanline, int len, FILE *fp, int nc, const float wlpt[4])
764     {
765     COLRV *tscn;
766     int i;
767    
768     if (nc < 3)
769     return(-1);
770     if (nc == 3)
771     return(freadscan(scanline, len, fp));
772    
773     tscn = (COLRV *)tempbuffer((nc+1)*len);
774     if (tscn == NULL || freadscolrs(tscn, nc, len, fp) < 0)
775     return(-1);
776     for (i = len; i-- > 0; ) {
777     scolr2color(*scanline++, tscn, nc, wlpt);
778     tscn += nc+1;
779     }
780     return(0);
781     }
782    
783    
784 greg 2.32 /* write an nc-component spectral color scanline */
785 greg 2.30 int
786 greg 2.35 fwritesscan(const COLORV *sscanline, int nc, int len, FILE *fp)
787 greg 2.30 {
788 greg 2.35 COLRV *tscn = (COLRV *)tempbuffer((nc+1)*len);
789 greg 2.30 int i;
790    
791     if (tscn == NULL)
792     return(-1);
793     for (i = 0; i < len; i++) {
794 greg 2.31 scolor2scolr(tscn+i*(nc+1), sscanline, nc);
795     sscanline += nc;
796 greg 2.30 }
797 greg 2.31 return(fwritescolrs(tscn, nc, len, fp));
798 greg 2.30 }
799    
800    
801 greg 2.9 void
802 greg 2.17 setcolr( /* assign a short color value */
803     COLR clr,
804     double r,
805     double g,
806     double b
807     )
808 greg 1.1 {
809     double d;
810     int e;
811    
812     d = r > g ? r : g;
813     if (b > d) d = b;
814    
815 greg 1.4 if (d <= 1e-32) {
816 greg 1.1 clr[RED] = clr[GRN] = clr[BLU] = 0;
817     clr[EXP] = 0;
818     return;
819     }
820    
821 greg 2.21 d = frexp(d, &e) * 256.0 / d;
822 greg 1.1
823 greg 2.27 clr[RED] = (r > 0) * (int)(r*d);
824     clr[GRN] = (g > 0) * (int)(g*d);
825     clr[BLU] = (b > 0) * (int)(b*d);
826 greg 1.1 clr[EXP] = e + COLXS;
827     }
828    
829    
830 greg 2.9 int
831 greg 2.17 bigdiff( /* c1 delta c2 > md? */
832 greg 2.35 const COLOR c1,
833     const COLOR c2,
834 greg 2.17 double md
835     )
836 greg 1.7 {
837 greg 2.17 int i;
838 greg 1.7
839     for (i = 0; i < 3; i++)
840 greg 2.27 if ((colval(c1,i)-colval(c2,i) > md*colval(c2,i)) |
841     (colval(c2,i)-colval(c1,i) > md*colval(c1,i)))
842     return(1);
843     return(0);
844     }
845    
846    
847     int
848     sbigsdiff( /* sc1 delta sc2 > md? */
849 greg 2.35 const SCOLOR c1,
850     const SCOLOR c2,
851 greg 2.27 double md
852     )
853     {
854     int i = NCSAMP;
855    
856     while (i--)
857     if ((c1[i]-c2[i] > md*c2[i]) | (c2[i]-c1[i] > md*c1[i]))
858 greg 1.7 return(1);
859     return(0);
860     }