ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tonemap.c
Revision: 3.15
Committed: Thu Jul 22 17:48:52 2004 UTC (19 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6, rad3R6P1
Changes since 3.14: +5 -3 lines
Log Message:
Added check for incompatible use of TM_F_MESOPIC with TM_F_BW

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: tonemap.c,v 3.14 2003/09/18 20:18:19 greg Exp $";
3 #endif
4 /*
5 * Tone mapping functions.
6 * See tonemap.h for detailed function descriptions.
7 * Added von Kries white-balance calculations 10/01 (GW).
8 *
9 * Externals declared in tonemap.h
10 */
11
12 #include "copyright.h"
13
14 #include <stdio.h>
15 #include <math.h>
16 #include "tmprivat.h"
17 #include "tmerrmsg.h"
18
19 #define exp10(x) exp(M_LN10*(x))
20
21 struct tmStruct *tmTop = NULL; /* current tone mapping stack */
22
23 /* our list of conversion packages */
24 struct tmPackage *tmPkg[TM_MAXPKG];
25 int tmNumPkgs = 0; /* number of registered packages */
26
27 int tmLastError; /* last error incurred by library */
28 char *tmLastFunction; /* error-generating function name */
29
30
31 struct tmStruct *
32 tmInit(flags, monpri, gamval) /* initialize new tone mapping */
33 int flags;
34 RGBPRIMP monpri;
35 double gamval;
36 {
37 COLORMAT cmat;
38 register struct tmStruct *tmnew;
39 register int i;
40 /* allocate structure */
41 tmnew = (struct tmStruct *)malloc(sizeof(struct tmStruct));
42 if (tmnew == NULL)
43 return(NULL);
44
45 tmnew->flags = flags & ~TM_F_UNIMPL;
46 if (tmnew->flags & TM_F_BW)
47 tmnew->flags &= ~TM_F_MESOPIC;
48 /* set monitor transform */
49 if (monpri == NULL || monpri == stdprims || tmnew->flags & TM_F_BW) {
50 tmnew->monpri = stdprims;
51 tmnew->clf[RED] = rgb2xyzmat[1][0];
52 tmnew->clf[GRN] = rgb2xyzmat[1][1];
53 tmnew->clf[BLU] = rgb2xyzmat[1][2];
54 } else {
55 comprgb2xyzWBmat(cmat, tmnew->monpri=monpri);
56 tmnew->clf[RED] = cmat[1][0];
57 tmnew->clf[GRN] = cmat[1][1];
58 tmnew->clf[BLU] = cmat[1][2];
59 }
60 /* set gamma value */
61 if (gamval < MINGAM)
62 tmnew->mongam = DEFGAM;
63 else
64 tmnew->mongam = gamval;
65 /* set color divisors */
66 for (i = 0; i < 3; i++)
67 tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);
68
69 /* set input transform */
70 tmnew->inppri = tmnew->monpri;
71 tmnew->cmat[0][0] = tmnew->cmat[1][1] = tmnew->cmat[2][2] =
72 tmnew->inpsf = WHTEFFICACY;
73 tmnew->cmat[0][1] = tmnew->cmat[0][2] = tmnew->cmat[1][0] =
74 tmnew->cmat[1][2] = tmnew->cmat[2][0] = tmnew->cmat[2][1] = 0.;
75 tmnew->hbrmin = 10; tmnew->hbrmax = -10;
76 tmnew->histo = NULL;
77 tmnew->mbrmin = 10; tmnew->mbrmax = -10;
78 tmnew->lumap = NULL;
79 /* zero private data */
80 for (i = TM_MAXPKG; i--; )
81 tmnew->pd[i] = NULL;
82 /* make tmnew current */
83 tmnew->tmprev = tmTop;
84 return(tmTop = tmnew);
85 }
86
87
88 int
89 tmSetSpace(pri, sf) /* set input color space for conversions */
90 RGBPRIMP pri;
91 double sf;
92 {
93 static char funcName[] = "tmSetSpace";
94 register int i, j;
95 /* error check */
96 if (tmTop == NULL)
97 returnErr(TM_E_TMINVAL);
98 if (sf <= 1e-12)
99 returnErr(TM_E_ILLEGAL);
100 /* check if no change */
101 if (pri == tmTop->inppri && FEQ(sf, tmTop->inpsf))
102 returnOK;
103 tmTop->inppri = pri; /* let's set it */
104 tmTop->inpsf = sf;
105
106 if (tmTop->flags & TM_F_BW) { /* color doesn't matter */
107 tmTop->monpri = tmTop->inppri; /* eliminate xform */
108 if (tmTop->inppri == TM_XYZPRIM) {
109 tmTop->clf[CIEX] = tmTop->clf[CIEZ] = 0.;
110 tmTop->clf[CIEY] = 1.;
111 } else {
112 comprgb2xyzWBmat(tmTop->cmat, tmTop->monpri);
113 tmTop->clf[RED] = tmTop->cmat[1][0];
114 tmTop->clf[GRN] = tmTop->cmat[1][1];
115 tmTop->clf[BLU] = tmTop->cmat[1][2];
116 }
117 tmTop->cmat[0][0] = tmTop->cmat[1][1] = tmTop->cmat[2][2] =
118 tmTop->inpsf;
119 tmTop->cmat[0][1] = tmTop->cmat[0][2] = tmTop->cmat[1][0] =
120 tmTop->cmat[1][2] = tmTop->cmat[2][0] = tmTop->cmat[2][1] = 0.;
121
122 } else if (tmTop->inppri == TM_XYZPRIM) /* input is XYZ */
123 compxyz2rgbWBmat(tmTop->cmat, tmTop->monpri);
124
125 else { /* input is RGB */
126 if (tmTop->inppri != tmTop->monpri &&
127 PRIMEQ(tmTop->inppri, tmTop->monpri))
128 tmTop->inppri = tmTop->monpri; /* no xform */
129 comprgb2rgbWBmat(tmTop->cmat, tmTop->inppri, tmTop->monpri);
130 }
131 for (i = 0; i < 3; i++)
132 for (j = 0; j < 3; j++)
133 tmTop->cmat[i][j] *= tmTop->inpsf;
134 /* set color divisors */
135 for (i = 0; i < 3; i++)
136 if (tmTop->clf[i] > .001)
137 tmTop->cdiv[i] =
138 256.*pow(tmTop->clf[i], 1./tmTop->mongam);
139 else
140 tmTop->cdiv[i] = 1;
141 /* notify packages */
142 for (i = tmNumPkgs; i--; )
143 if (tmTop->pd[i] != NULL && tmPkg[i]->NewSpace != NULL)
144 (*tmPkg[i]->NewSpace)(tmTop);
145 returnOK;
146 }
147
148
149 void
150 tmClearHisto() /* clear current histogram */
151 {
152 if (tmTop == NULL || tmTop->histo == NULL)
153 return;
154 free((MEM_PTR)tmTop->histo);
155 tmTop->histo = NULL;
156 }
157
158
159 int
160 tmCvColors(ls, cs, scan, len) /* convert float colors */
161 TMbright *ls;
162 BYTE *cs;
163 COLOR *scan;
164 int len;
165 {
166 static char funcName[] = "tmCvColors";
167 static COLOR csmall = {.5*MINLUM, .5*MINLUM, .5*MINLUM};
168 COLOR cmon;
169 double lum, slum;
170 register double d;
171 register int i;
172
173 if (tmTop == NULL)
174 returnErr(TM_E_TMINVAL);
175 if ((ls == NULL) | (scan == NULL) | (len < 0))
176 returnErr(TM_E_ILLEGAL);
177 for (i = len; i--; ) {
178 if (tmNeedMatrix(tmTop)) { /* get monitor RGB */
179 colortrans(cmon, tmTop->cmat, scan[i]);
180 } else {
181 cmon[RED] = tmTop->inpsf*scan[i][RED];
182 cmon[GRN] = tmTop->inpsf*scan[i][GRN];
183 cmon[BLU] = tmTop->inpsf*scan[i][BLU];
184 }
185 /* world luminance */
186 lum = tmTop->clf[RED]*cmon[RED] +
187 tmTop->clf[GRN]*cmon[GRN] +
188 tmTop->clf[BLU]*cmon[BLU] ;
189 /* check range */
190 if (clipgamut(cmon, lum, CGAMUT_LOWER, csmall, cwhite))
191 lum = tmTop->clf[RED]*cmon[RED] +
192 tmTop->clf[GRN]*cmon[GRN] +
193 tmTop->clf[BLU]*cmon[BLU] ;
194 if (lum < MINLUM) {
195 ls[i] = MINBRT-1; /* bogus value */
196 lum = MINLUM;
197 } else {
198 d = TM_BRTSCALE*log(lum); /* encode it */
199 ls[i] = d>0. ? (int)(d+.5) : (int)(d-.5);
200 }
201 if (cs == TM_NOCHROM) /* no color? */
202 continue;
203 if (tmTop->flags & TM_F_MESOPIC && lum < LMESUPPER) {
204 slum = scotlum(cmon); /* mesopic adj. */
205 if (lum < LMESLOWER)
206 cmon[RED] = cmon[GRN] = cmon[BLU] = slum;
207 else {
208 d = (lum - LMESLOWER)/(LMESUPPER - LMESLOWER);
209 if (tmTop->flags & TM_F_BW)
210 cmon[RED] = cmon[GRN] =
211 cmon[BLU] = d*lum;
212 else
213 scalecolor(cmon, d);
214 d = (1.-d)*slum;
215 cmon[RED] += d;
216 cmon[GRN] += d;
217 cmon[BLU] += d;
218 }
219 } else if (tmTop->flags & TM_F_BW) {
220 cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
221 }
222 d = tmTop->clf[RED]*cmon[RED]/lum;
223 cs[3*i ] = d>=.999 ? 255 :
224 (int)(256.*pow(d, 1./tmTop->mongam));
225 d = tmTop->clf[GRN]*cmon[GRN]/lum;
226 cs[3*i+1] = d>=.999 ? 255 :
227 (int)(256.*pow(d, 1./tmTop->mongam));
228 d = tmTop->clf[BLU]*cmon[BLU]/lum;
229 cs[3*i+2] = d>=.999 ? 255 :
230 (int)(256.*pow(d, 1./tmTop->mongam));
231 }
232 returnOK;
233 }
234
235
236 int
237 tmCvGrays(ls, scan, len) /* convert float gray values */
238 TMbright *ls;
239 float *scan;
240 int len;
241 {
242 static char funcName[] = "tmCvGrays";
243 register double d;
244 register int i;
245
246 if (tmTop == NULL)
247 returnErr(TM_E_TMINVAL);
248 if ((ls == NULL) | (scan == NULL) | (len < 0))
249 returnErr(TM_E_ILLEGAL);
250 for (i = len; i--; )
251 if (scan[i] <= TM_NOLUM) {
252 ls[i] = TM_NOBRT; /* bogus value */
253 } else {
254 d = TM_BRTSCALE*log(scan[i]); /* encode it */
255 ls[i] = d>0. ? (int)(d+.5) : (int)(d-.5);
256 }
257 returnOK;
258 }
259
260
261 int
262 tmAddHisto(ls, len, wt) /* add values to histogram */
263 register TMbright *ls;
264 int len;
265 int wt;
266 {
267 static char funcName[] = "tmAddHisto";
268 int oldorig=0, oldlen, horig, hlen;
269 register int i, j;
270
271 if (tmTop == NULL)
272 returnErr(TM_E_TMINVAL);
273 if (len < 0)
274 returnErr(TM_E_ILLEGAL);
275 if (len == 0)
276 returnOK;
277 /* first, grow limits */
278 if (tmTop->histo == NULL) {
279 for (i = len; i-- && ls[i] < MINBRT; )
280 ;
281 if (i < 0)
282 returnOK;
283 tmTop->hbrmin = tmTop->hbrmax = ls[i];
284 oldlen = 0;
285 } else {
286 oldorig = (tmTop->hbrmin-MINBRT)/HISTEP;
287 oldlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - oldorig;
288 }
289 for (i = len; i--; ) {
290 if ((j = ls[i]) < MINBRT)
291 continue;
292 if (j < tmTop->hbrmin)
293 tmTop->hbrmin = j;
294 else if (j > tmTop->hbrmax)
295 tmTop->hbrmax = j;
296 }
297 horig = (tmTop->hbrmin-MINBRT)/HISTEP;
298 hlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - horig;
299 if (hlen > oldlen) { /* (re)allocate histogram */
300 register int *newhist = (int *)calloc(hlen, sizeof(int));
301 if (newhist == NULL)
302 returnErr(TM_E_NOMEM);
303 if (oldlen) { /* copy and free old */
304 for (i = oldlen, j = i+oldorig-horig; i; )
305 newhist[--j] = tmTop->histo[--i];
306 free((MEM_PTR)tmTop->histo);
307 }
308 tmTop->histo = newhist;
309 }
310 if (wt == 0)
311 returnOK;
312 for (i = len; i--; ) /* add in new counts */
313 if (ls[i] >= MINBRT)
314 tmTop->histo[ (ls[i]-MINBRT)/HISTEP - horig ] += wt;
315 returnOK;
316 }
317
318
319 static double
320 htcontrs(La) /* human threshold contrast sensitivity, dL(La) */
321 double La;
322 {
323 double l10La, l10dL;
324 /* formula taken from Ferwerda et al. [SG96] */
325 if (La < 1.148e-4)
326 return(1.38e-3);
327 l10La = log10(La);
328 if (l10La < -1.44) /* rod response regime */
329 l10dL = pow(.405*l10La + 1.6, 2.18) - 2.86;
330 else if (l10La < -.0184)
331 l10dL = l10La - .395;
332 else if (l10La < 1.9) /* cone response regime */
333 l10dL = pow(.249*l10La + .65, 2.7) - .72;
334 else
335 l10dL = l10La - 1.255;
336
337 return(exp10(l10dL));
338 }
339
340
341 static int
342 tmNewMap()
343 {
344 if (tmTop->lumap != NULL && (tmTop->mbrmax - tmTop->mbrmin) !=
345 (tmTop->hbrmax - tmTop->hbrmin)) {
346 free((MEM_PTR)tmTop->lumap);
347 tmTop->lumap = NULL;
348 }
349 tmTop->mbrmin = tmTop->hbrmin;
350 tmTop->mbrmax = tmTop->hbrmax;
351 if (tmTop->mbrmin > tmTop->mbrmax)
352 return 0;
353 if (tmTop->lumap == NULL)
354 tmTop->lumap = (unsigned short *)malloc(sizeof(unsigned short)*
355 (tmTop->mbrmax-tmTop->mbrmin+1));
356 return(tmTop->lumap != NULL);
357 }
358
359
360 int
361 tmFixedMapping(expmult, gamval)
362 double expmult;
363 double gamval;
364 {
365 static char funcName[] = "tmFixedMapping";
366 double d;
367 register int i;
368
369 if (!tmNewMap())
370 returnErr(TM_E_NOMEM);
371 if (expmult <= .0)
372 expmult = 1.;
373 if (gamval < MINGAM)
374 gamval = tmTop->mongam;
375 d = log(expmult/tmTop->inpsf);
376 for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; )
377 tmTop->lumap[i] = 256. * exp(
378 ( d + (tmTop->mbrmin+i)*(1./TM_BRTSCALE) )
379 / gamval );
380 returnOK;
381 }
382
383
384 int
385 tmComputeMapping(gamval, Lddyn, Ldmax)
386 double gamval;
387 double Lddyn;
388 double Ldmax;
389 {
390 static char funcName[] = "tmComputeMapping";
391 int *histo;
392 float *cumf;
393 int brt0, histlen, threshold, ceiling, trimmings;
394 double logLddyn, Ldmin, Ldavg, Lwavg, Tr, Lw, Ld;
395 int32 histot;
396 double sum;
397 register double d;
398 register int i, j;
399
400 if (tmTop == NULL || tmTop->histo == NULL)
401 returnErr(TM_E_TMINVAL);
402 /* check arguments */
403 if (Lddyn < MINLDDYN) Lddyn = DEFLDDYN;
404 if (Ldmax < MINLDMAX) Ldmax = DEFLDMAX;
405 if (gamval < MINGAM) gamval = tmTop->mongam;
406 /* compute handy values */
407 Ldmin = Ldmax/Lddyn;
408 logLddyn = log(Lddyn);
409 Ldavg = sqrt(Ldmax*Ldmin);
410 i = (tmTop->hbrmin-MINBRT)/HISTEP;
411 brt0 = MINBRT + HISTEP/2 + i*HISTEP;
412 histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i;
413 /* histogram total and mean */
414 histot = 0; sum = 0;
415 j = brt0 + histlen*HISTEP;
416 for (i = histlen; i--; ) {
417 histot += tmTop->histo[i];
418 sum += (j -= HISTEP) * tmTop->histo[i];
419 }
420 threshold = histot*0.005 + .5;
421 if (threshold < 4)
422 returnErr(TM_E_TMFAIL);
423 Lwavg = tmLuminance( (double)sum / histot );
424 /* allocate space for mapping */
425 if (!tmNewMap())
426 returnErr(TM_E_NOMEM);
427 /* use linear tone mapping? */
428 if (tmTop->flags & TM_F_LINEAR)
429 goto linearmap;
430 /* clamp histogram */
431 histo = (int *)malloc(histlen*sizeof(int));
432 cumf = (float *)malloc((histlen+2)*sizeof(float));
433 if ((histo == NULL) | (cumf == NULL))
434 returnErr(TM_E_NOMEM);
435 cumf[histlen+1] = 1.; /* guard for assignment code */
436 for (i = histlen; i--; ) /* make malleable copy */
437 histo[i] = tmTop->histo[i];
438 do { /* iterate to solution */
439 sum = 0; /* cumulative probability */
440 for (i = 0; i < histlen; i++) {
441 cumf[i] = (double)sum/histot;
442 sum += histo[i];
443 }
444 cumf[histlen] = 1.;
445 Tr = histot * (double)(tmTop->hbrmax - tmTop->hbrmin) /
446 ((double)histlen*TM_BRTSCALE) / logLddyn;
447 ceiling = Tr + 1.;
448 trimmings = 0; /* clip to envelope */
449 for (i = histlen; i--; ) {
450 if (tmTop->flags & TM_F_HCONTR) {
451 Lw = tmLuminance(brt0 + i*HISTEP);
452 Ld = Ldmin * exp( logLddyn *
453 .5*(cumf[i]+cumf[i+1]) );
454 ceiling = Tr * (htcontrs(Ld) * Lw) /
455 (htcontrs(Lw) * Ld) + 1.;
456 }
457 if (histo[i] > ceiling) {
458 trimmings += histo[i] - ceiling;
459 histo[i] = ceiling;
460 }
461 }
462 /* check if we're out of data */
463 if ((histot -= trimmings) <= threshold) {
464 free((MEM_PTR)histo);
465 free((MEM_PTR)cumf);
466 goto linearmap;
467 }
468 } while (trimmings > threshold);
469 /* assign tone-mapping */
470 for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; ) {
471 j = d = (double)i/(tmTop->mbrmax-tmTop->mbrmin)*histlen;
472 d -= (double)j;
473 Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1]));
474 d = (Ld - Ldmin)/(Ldmax - Ldmin);
475 tmTop->lumap[i] = 256.*pow(d, 1./gamval);
476 }
477 free((MEM_PTR)histo); /* clean up and return */
478 free((MEM_PTR)cumf);
479 returnOK;
480 linearmap: /* linear tone-mapping */
481 if (tmTop->flags & TM_F_HCONTR)
482 d = htcontrs(Ldavg) / htcontrs(Lwavg);
483 else
484 d = Ldavg / Lwavg;
485 return(tmFixedMapping(tmTop->inpsf*d/Ldmax, gamval));
486 }
487
488
489 int
490 tmMapPixels(ps, ls, cs, len)
491 register BYTE *ps;
492 TMbright *ls;
493 register BYTE *cs;
494 int len;
495 {
496 static char funcName[] = "tmMapPixels";
497 register int32 li, pv;
498
499 if (tmTop == NULL || tmTop->lumap == NULL)
500 returnErr(TM_E_TMINVAL);
501 if ((ps == NULL) | (ls == NULL) | (len < 0))
502 returnErr(TM_E_ILLEGAL);
503 while (len--) {
504 if ((li = *ls++) < tmTop->mbrmin) {
505 li = 0;
506 } else {
507 if (li > tmTop->mbrmax)
508 li = tmTop->mbrmax;
509 li = tmTop->lumap[li - tmTop->mbrmin];
510 }
511 if (cs == TM_NOCHROM)
512 *ps++ = li>255 ? 255 : li;
513 else {
514 pv = *cs++ * li / tmTop->cdiv[RED];
515 *ps++ = pv>255 ? 255 : pv;
516 pv = *cs++ * li / tmTop->cdiv[GRN];
517 *ps++ = pv>255 ? 255 : pv;
518 pv = *cs++ * li / tmTop->cdiv[BLU];
519 *ps++ = pv>255 ? 255 : pv;
520 }
521 }
522 returnOK;
523 }
524
525
526 struct tmStruct *
527 tmPop() /* pop top tone mapping off stack */
528 {
529 register struct tmStruct *tms;
530
531 if ((tms = tmTop) != NULL)
532 tmTop = tms->tmprev;
533 return(tms);
534 }
535
536
537 int
538 tmPull(tms) /* pull a tone mapping from stack */
539 register struct tmStruct *tms;
540 {
541 register struct tmStruct *tms2;
542 /* special cases first */
543 if ((tms == NULL) | (tmTop == NULL))
544 return(0);
545 if (tms == tmTop) {
546 tmTop = tms->tmprev;
547 tms->tmprev = NULL;
548 return(1);
549 }
550 for (tms2 = tmTop; tms2->tmprev != NULL; tms2 = tms2->tmprev)
551 if (tms == tms2->tmprev) { /* remove it */
552 tms2->tmprev = tms->tmprev;
553 tms->tmprev = NULL;
554 return(1);
555 }
556 return(0); /* not found on stack */
557 }
558
559
560 struct tmStruct *
561 tmDup() /* duplicate top tone mapping */
562 {
563 int len;
564 register int i;
565 register struct tmStruct *tmnew;
566
567 if (tmTop == NULL) /* anything to duplicate? */
568 return(NULL);
569 tmnew = (struct tmStruct *)malloc(sizeof(struct tmStruct));
570 if (tmnew == NULL)
571 return(NULL);
572 *tmnew = *tmTop; /* copy everything */
573 if (tmnew->histo != NULL) { /* duplicate histogram */
574 len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 -
575 (tmnew->hbrmin-MINBRT)/HISTEP;
576 tmnew->histo = (int *)malloc(len*sizeof(int));
577 if (tmnew->histo != NULL)
578 for (i = len; i--; )
579 tmnew->histo[i] = tmTop->histo[i];
580 }
581 if (tmnew->lumap != NULL) { /* duplicate luminance mapping */
582 len = tmnew->mbrmax-tmnew->mbrmin+1;
583 tmnew->lumap = (unsigned short *)malloc(
584 len*sizeof(unsigned short) );
585 if (tmnew->lumap != NULL)
586 for (i = len; i--; )
587 tmnew->lumap[i] = tmTop->lumap[i];
588 }
589 /* clear package data */
590 for (i = tmNumPkgs; i--; )
591 tmnew->pd[i] = NULL;
592 tmnew->tmprev = tmTop; /* make copy current */
593 return(tmTop = tmnew);
594 }
595
596
597 int
598 tmPush(tms) /* push tone mapping on top of stack */
599 register struct tmStruct *tms;
600 {
601 static char funcName[] = "tmPush";
602 /* check validity */
603 if (tms == NULL)
604 returnErr(TM_E_ILLEGAL);
605 if (tms == tmTop) /* check necessity */
606 returnOK;
607 /* pull if already in stack */
608 (void)tmPull(tms);
609 /* push it on top */
610 tms->tmprev = tmTop;
611 tmTop = tms;
612 returnOK;
613 }
614
615
616 void
617 tmDone(tms) /* done with tone mapping -- destroy it */
618 register struct tmStruct *tms;
619 {
620 register int i;
621 /* NULL arg. is equiv. to tmTop */
622 if (tms == NULL && (tms = tmTop) == NULL)
623 return;
624 /* take out of stack if present */
625 (void)tmPull(tms);
626 /* free tables */
627 if (tms->histo != NULL)
628 free((MEM_PTR)tms->histo);
629 if (tms->lumap != NULL)
630 free((MEM_PTR)tms->lumap);
631 /* free private data */
632 for (i = tmNumPkgs; i--; )
633 if (tms->pd[i] != NULL)
634 (*tmPkg[i]->Free)(tms->pd[i]);
635 free((MEM_PTR)tms); /* free basic structure */
636 }
637
638 /******************** Shared but Private library routines *********************/
639
640 BYTE tmMesofact[BMESUPPER-BMESLOWER];
641
642 void
643 tmMkMesofact() /* build mesopic lookup factor table */
644 {
645 register int i;
646
647 if (tmMesofact[BMESUPPER-BMESLOWER-1])
648 return;
649
650 for (i = BMESLOWER; i < BMESUPPER; i++)
651 tmMesofact[i-BMESLOWER] = 256. *
652 (tmLuminance(i) - LMESLOWER) /
653 (LMESUPPER - LMESLOWER);
654 }
655
656
657 int
658 tmErrorReturn(func, err) /* error return (with message) */
659 char *func;
660 int err;
661 {
662 tmLastFunction = func;
663 tmLastError = err;
664 if (tmTop != NULL && tmTop->flags & TM_F_NOSTDERR)
665 return(err);
666 fputs(func, stderr);
667 fputs(": ", stderr);
668 fputs(tmErrorMessage[err], stderr);
669 fputs("!\n", stderr);
670 return(err);
671 }