ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tmapluv.c
Revision: 3.3
Committed: Sun Dec 20 16:38:29 1998 UTC (25 years, 4 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.2: +2 -2 lines
Log Message:
added TM_NOBRT macro for undefined brightnesses

File Contents

# Content
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 COLOR XYZ, RGB;
72 /* 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 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 }
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] = TM_NOBRT; /* 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 j = tmTop->flags&TM_F_BW || ls[i]<BMESLOWER
202 ? 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 if (tmTop->flags&TM_F_BW || ls[i]<BMESLOWER
258 || (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 uvp[0] = U_NEU; uvp[1] = V_NEU;
266 }
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] = TM_NOBRT; /* 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 }