ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tmapluv.c
Revision: 3.2
Committed: Mon Oct 26 17:07:05 1998 UTC (25 years, 6 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.1: +19 -7 lines
Log Message:
implemented mesopic color shift

File Contents

# User Rev Content
1 gwlarson 3.1 /* Copyright (c) 1998 Silicon Graphics, Inc. */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ SGI";
5     #endif
6    
7     /*
8     * Routines for tone-mapping LogLuv encoded pixels.
9     */
10    
11     #include <stdio.h>
12     #include <math.h>
13     #include "tiffio.h"
14     #include "tmprivat.h"
15     #include "uvcode.h"
16    
17     #ifndef BSD
18     #define bzero(d,n) (void)memset(d,0,n)
19     #endif
20     #define uvflgop(p,uv,op) ((p)->rgbflg[(uv)>>5] op (1L<<((uv)&0x1f)))
21     #define isuvset(p,uv) uvflgop(p,uv,&)
22     #define setuv(p,uv) uvflgop(p,uv,|=)
23     #define clruv(p,uv) uvflgop(p,uv,&=~)
24     #define clruvall(p) bzero((MEM_PTR)(p)->rgbflg,sizeof((p)->rgbflg))
25    
26     #define U_NEU 0.210526316
27     #define V_NEU 0.473684211
28    
29     static MEM_PTR luv32Init();
30     static void luv32NewSpace();
31     static MEM_PTR luv24Init();
32     static void luv24NewSpace();
33     extern void free();
34    
35     typedef struct {
36     int offset; /* computed luminance offset */
37     BYTE rgbval[1<<16][3]; /* computed RGB value for given uv */
38     uint32 rgbflg[1<<(16-5)]; /* flags for computed values */
39     } LUV32DATA; /* LogLuv 32-bit conversion data */
40    
41     #define UVSCALE 410.
42     #define UVNEU ((int)(UVSCALE*U_NEU)<<8 \
43     | (int)(UVSCALE*V_NEU))
44    
45     static struct tmPackage luv32Pkg = { /* 32-bit package functions */
46     luv32Init, luv32NewSpace, free
47     };
48     static int luv32Reg = -1; /* 32-bit package reg. number */
49    
50     typedef struct {
51     int offset; /* computed luminance offset */
52     BYTE rgbval[1<<14][3]; /* computed rgb value for uv index */
53     uint32 rgbflg[1<<(14-5)]; /* flags for computed values */
54     } LUV24DATA; /* LogLuv 24-bit conversion data */
55    
56     static struct tmPackage luv24Pkg = { /* 24-bit package functions */
57     luv24Init, luv24NewSpace, free
58     };
59     static int luv24Reg = -1; /* 24-bit package reg. number */
60    
61     static int uv14neu = -1; /* neutral index for 14-bit (u',v') */
62    
63    
64     static
65     uv2rgb(rgb, tm, uvp) /* compute RGB from uv coordinate */
66     BYTE rgb[3];
67     register struct tmStruct *tm;
68     double uvp[2];
69     { /* Should check that tm->inppri==TM_XYZPRIM beforehand... */
70     double d, x, y;
71 gwlarson 3.2 COLOR XYZ, RGB;
72 gwlarson 3.1 /* convert to XYZ */
73     d = 1./(6.*uvp[0] - 16.*uvp[1] + 12.);
74     x = 9.*uvp[0] * d;
75     y = 4.*uvp[1] * d;
76     XYZ[CIEY] = 1./tm->inpsf;
77     XYZ[CIEX] = x/y * XYZ[CIEY];
78     XYZ[CIEZ] = (1.-x-y)/y * XYZ[CIEY];
79     /* convert to RGB and clip */
80     colortrans(RGB, tm->cmat, XYZ);
81     clipgamut(RGB, XYZ[CIEY], CGAMUT_LOWER, cblack, cwhite);
82     /* perform final scaling & gamma */
83     d = tm->clf[RED] * RGB[RED];
84     rgb[RED] = d>=.999 ? 255 : (int)(256.*pow(d, 1./tm->mongam));
85     d = tm->clf[GRN] * RGB[GRN];
86     rgb[GRN] = d>=.999 ? 255 : (int)(256.*pow(d, 1./tm->mongam));
87     d = tm->clf[BLU] * RGB[BLU];
88     rgb[BLU] = d>=.999 ? 255 : (int)(256.*pow(d, 1./tm->mongam));
89     }
90    
91    
92     static TMbright
93     compmeshift(li, uvp) /* compute mesopic color shift */
94     TMbright li; /* encoded world luminance */
95     double uvp[2]; /* world (u',v') -> returned desaturated */
96     {
97 gwlarson 3.2 double scotrat, d;
98    
99     if (li >= BMESUPPER)
100     return(li);
101     scotrat = 1.33/9.*(6.*uvp[0]-16.*uvp[1]+12.)/uvp[0] - 1.68;
102     if (li <= BMESLOWER) {
103     d = 0.;
104     uvp[0] = U_NEU; uvp[1] = V_NEU;
105     } else {
106     d = (tmLuminance(li) - LMESLOWER)/(LMESUPPER - LMESLOWER);
107     uvp[0] = d*uvp[0] + (1.-d)*U_NEU;
108     uvp[1] = d*uvp[1] + (1.-d)*V_NEU;
109     }
110     d = li + (double)TM_BRTSCALE*log(d + (1.-d)*scotrat/2.26);
111     return((TMbright)(d+.5));
112 gwlarson 3.1 }
113    
114    
115     static int
116     uvpencode(uvp) /* encode (u',v') coordinates */
117     double uvp[2];
118     {
119     register int vi, ui;
120    
121     if (uvp[1] < UV_VSTART)
122     return(-1);
123     vi = (uvp[1] - UV_VSTART)*(1./UV_SQSIZ);
124     if (vi >= UV_NVS)
125     return(-1);
126     if (uvp[0] < uv_row[vi].ustart)
127     return(-1);
128     ui = (uvp[0] - uv_row[vi].ustart)*(1./UV_SQSIZ);
129     if (ui >= uv_row[vi].nus)
130     return(-1);
131     return(uv_row[vi].ncum + ui);
132     }
133    
134    
135     static int
136     uvpdecode(uvp, c) /* decode (u',v') index */
137     double uvp[2];
138     int c;
139     {
140     int upper, lower;
141     register int ui, vi;
142    
143     if (c < 0 || c >= UV_NDIVS)
144     return(-1);
145     lower = 0; /* binary search */
146     upper = UV_NVS;
147     do {
148     vi = (lower + upper) >> 1;
149     ui = c - uv_row[vi].ncum;
150     if (ui > 0)
151     lower = vi;
152     else if (ui < 0)
153     upper = vi;
154     else
155     break;
156     } while (upper - lower > 1);
157     vi = lower;
158     ui = c - uv_row[vi].ncum;
159     uvp[0] = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
160     uvp[1] = UV_VSTART + (vi+.5)*UV_SQSIZ;
161     return(0);
162     }
163    
164    
165     int
166     tmCvLuv32(ls, cs, luvs, len) /* convert raw 32-bit LogLuv values */
167     TMbright *ls;
168     BYTE *cs;
169     uint32 *luvs;
170     int len;
171     {
172     static char funcName[] = "tmCvLuv32";
173     double uvp[2];
174     register LUV32DATA *ld;
175     register int i, j;
176     /* check arguments */
177     if (tmTop == NULL)
178     returnErr(TM_E_TMINVAL);
179     if (ls == NULL | luvs == NULL | len < 0)
180     returnErr(TM_E_ILLEGAL);
181     /* check package registration */
182     if (luv32Reg < 0 && (luv32Reg = tmRegPkg(&luv32Pkg)) < 0)
183     returnErr(TM_E_CODERR1);
184     /* get package data */
185     if ((ld = (LUV32DATA *)tmPkgData(tmTop,luv32Reg)) == NULL)
186     returnErr(TM_E_NOMEM);
187     /* convert each pixel */
188     for (i = len; i--; ) {
189     j = luvs[i] >> 16; /* get luminance */
190     if (j & 0x8000) /* negative luminance */
191     ls[i] = MINBRT-1; /* assign bogus value */
192     else /* else convert to lnL */
193     ls[i] = (BRT2SCALE*j >> 8) - ld->offset;
194     if (cs == TM_NOCHROM) /* no color? */
195     continue;
196     /* get chrominance */
197     if (tmTop->flags & TM_F_MESOPIC && ls[i] < BMESUPPER) {
198     uvp[0] = 1./UVSCALE*((luvs[i]>>8 & 0xff) + .5);
199     uvp[1] = 1./UVSCALE*((luvs[i] & 0xff) + .5);
200     ls[i] = compmeshift(ls[i], uvp);
201 gwlarson 3.2 j = tmTop->flags&TM_F_BW || ls[i]<BMESLOWER
202 gwlarson 3.1 ? UVNEU
203     : (int)(uvp[0]*UVSCALE)<<8
204     | (int)(uvp[1]*UVSCALE);
205     } else {
206     j = tmTop->flags&TM_F_BW ? UVNEU : luvs[i]&0xffff;
207     }
208     if (!isuvset(ld, j)) {
209     uvp[0] = 1./UVSCALE*((luvs[i]>>8 & 0xff) + .5);
210     uvp[1] = 1./UVSCALE*((luvs[i] & 0xff) + .5);
211     uv2rgb(ld->rgbval[j], tmTop, uvp);
212     setuv(ld, j);
213     }
214     cs[3*i ] = ld->rgbval[j][RED];
215     cs[3*i+1] = ld->rgbval[j][GRN];
216     cs[3*i+2] = ld->rgbval[j][BLU];
217     }
218     returnOK;
219     }
220    
221    
222     int
223     tmCvLuv24(ls, cs, luvs, len) /* convert raw 24-bit LogLuv values */
224     TMbright *ls;
225     BYTE *cs;
226     uint32 *luvs;
227     int len;
228     {
229     char funcName[] = "tmCvLuv24";
230     double uvp[2];
231     register LUV24DATA *ld;
232     register int i, j;
233     /* check arguments */
234     if (tmTop == NULL)
235     returnErr(TM_E_TMINVAL);
236     if (ls == NULL | luvs == NULL | len < 0)
237     returnErr(TM_E_ILLEGAL);
238     /* check package registration */
239     if (luv24Reg < 0 && (luv24Reg = tmRegPkg(&luv24Pkg)) < 0)
240     returnErr(TM_E_CODERR1);
241     /* get package data */
242     if ((ld = (LUV24DATA *)tmPkgData(tmTop,luv24Reg)) == NULL)
243     returnErr(TM_E_NOMEM);
244     /* convert each pixel */
245     for (i = len; i--; ) {
246     j = luvs[i] >> 14; /* get luminance */
247     ls[i] = (BRT2SCALE*j >> 6) - ld->offset;
248     if (cs == TM_NOCHROM) /* no color? */
249     continue;
250     /* get chrominance */
251     if (tmTop->flags & TM_F_MESOPIC && ls[i] < BMESUPPER) {
252     if (uvpdecode(uvp, luvs[i]&0x3fff) < 0) {
253     uvp[0] = U_NEU; /* should barf? */
254     uvp[1] = V_NEU;
255     }
256     ls[i] = compmeshift(ls[i], uvp);
257 gwlarson 3.2 if (tmTop->flags&TM_F_BW || ls[i]<BMESLOWER
258 gwlarson 3.1 || (j = uvpencode(uvp)) < 0)
259     j = uv14neu;
260     } else {
261     j = tmTop->flags&TM_F_BW ? uv14neu : luvs[i]&0x3fff;
262     }
263     if (!isuvset(ld, j)) {
264     if (uvpdecode(uvp, j) < 0) {
265 gwlarson 3.2 uvp[0] = U_NEU; uvp[1] = V_NEU;
266 gwlarson 3.1 }
267     uv2rgb(ld->rgbval[j], tmTop, uvp);
268     setuv(ld, j);
269     }
270     cs[3*i ] = ld->rgbval[j][RED];
271     cs[3*i+1] = ld->rgbval[j][GRN];
272     cs[3*i+2] = ld->rgbval[j][BLU];
273     }
274     returnOK;
275     }
276    
277    
278     int
279     tmCvL16(ls, l16s, len) /* convert 16-bit LogL values */
280     TMbright *ls;
281     uint16 *l16s;
282     int len;
283     {
284     static char funcName[] = "tmCvL16";
285     static double lastsf;
286     static int offset;
287     register int i;
288     /* check arguments */
289     if (tmTop == NULL)
290     returnErr(TM_E_TMINVAL);
291     if (ls == NULL | l16s == NULL | len < 0)
292     returnErr(TM_E_ILLEGAL);
293     /* check scaling offset */
294     if (!FEQ(tmTop->inpsf, lastsf)) {
295     offset = BRT2SCALE*64;
296     if (tmTop->inpsf > 1.0001)
297     offset -= (int)(TM_BRTSCALE*log(tmTop->inpsf)+.5);
298     else if (tmTop->inpsf < 0.9999)
299     offset -= (int)(TM_BRTSCALE*log(tmTop->inpsf)-.5);
300     lastsf = tmTop->inpsf;
301     }
302     /* convert each pixel */
303     for (i = len; i--; ) {
304     if (l16s[i] & 0x8000) /* negative luminance */
305     ls[i] = MINBRT-1; /* assign bogus value */
306     else /* else convert to lnL */
307     ls[i] = (BRT2SCALE*l16s[i] >> 8) - offset;
308     }
309     returnOK;
310     }
311    
312    
313     static void
314     luv32NewSpace(tm) /* initialize 32-bit LogLuv color space */
315     struct tmStruct *tm;
316     {
317     register LUV32DATA *ld;
318    
319     if (tm->inppri != TM_XYZPRIM) { /* panic time! */
320     fputs("Improper input color space in luv32NewSpace!\n", stderr);
321     exit(1);
322     }
323     ld = (LUV32DATA *)tm->pd[luv32Reg];
324     ld->offset = BRT2SCALE*64;
325     if (tm->inpsf > 1.0001)
326     ld->offset -= (int)(TM_BRTSCALE*log(tmTop->inpsf)+.5);
327     else if (tm->inpsf < 0.9999)
328     ld->offset -= (int)(TM_BRTSCALE*log(tmTop->inpsf)-.5);
329     clruvall(ld);
330     }
331    
332    
333     static MEM_PTR
334     luv32Init(tm) /* allocate data for 32-bit LogLuv decoder */
335     struct tmStruct *tm;
336     {
337     register LUV32DATA *ld;
338    
339     ld = (LUV32DATA *)malloc(sizeof(LUV32DATA));
340     if (ld == NULL)
341     return(NULL);
342     tm->pd[luv32Reg] = (MEM_PTR)ld;
343     luv32NewSpace(tm);
344     return((MEM_PTR)ld);
345     }
346    
347    
348     static void
349     luv24NewSpace(tm) /* initialize 24-bit LogLuv color space */
350     struct tmStruct *tm;
351     {
352     register LUV24DATA *ld;
353     double uvp[2];
354    
355     if (tm->inppri != TM_XYZPRIM) { /* panic time! */
356     fputs("Improper input color space in luv24NewSpace!\n", stderr);
357     exit(1);
358     }
359     ld = (LUV24DATA *)tm->pd[luv24Reg];
360     ld->offset = BRT2SCALE*12;
361     if (tm->inpsf > 1.0001)
362     ld->offset -= (int)(TM_BRTSCALE*log(tmTop->inpsf)+.5);
363     else if (tm->inpsf < 0.9999)
364     ld->offset -= (int)(TM_BRTSCALE*log(tmTop->inpsf)-.5);
365     clruvall(ld);
366     }
367    
368    
369     static MEM_PTR
370     luv24Init(tm) /* allocate data for 24-bit LogLuv decoder */
371     struct tmStruct *tm;
372     {
373     register LUV24DATA *ld;
374    
375     ld = (LUV24DATA *)malloc(sizeof(LUV24DATA));
376     if (ld == NULL)
377     return(NULL);
378     tm->pd[luv24Reg] = (MEM_PTR)ld;
379     if (uv14neu < 0) { /* initialize neutral color index */
380     double uvp[2];
381     uvp[0] = U_NEU; uvp[1] = V_NEU;
382     uv14neu = uvpencode(uvp);
383     }
384     luv24NewSpace(tm);
385     return((MEM_PTR)ld);
386     }