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

# User Rev Content
1 greg 3.1 #ifndef lint
2 greg 3.15 static const char RCSid[] = "$Id: tonemap.c,v 3.14 2003/09/18 20:18:19 greg Exp $";
3 greg 3.1 #endif
4     /*
5     * Tone mapping functions.
6     * See tonemap.h for detailed function descriptions.
7 greg 3.9 * Added von Kries white-balance calculations 10/01 (GW).
8     *
9     * Externals declared in tonemap.h
10     */
11    
12 greg 3.10 #include "copyright.h"
13 greg 3.1
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 greg 3.4 /* our list of conversion packages */
24     struct tmPackage *tmPkg[TM_MAXPKG];
25     int tmNumPkgs = 0; /* number of registered packages */
26 greg 3.1
27 gregl 3.5 int tmLastError; /* last error incurred by library */
28     char *tmLastFunction; /* error-generating function name */
29 greg 3.4
30 gregl 3.5
31 greg 3.1 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 greg 3.15 if (tmnew->flags & TM_F_BW)
47     tmnew->flags &= ~TM_F_MESOPIC;
48 greg 3.1 /* 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 greg 3.9 comprgb2xyzWBmat(cmat, tmnew->monpri=monpri);
56 greg 3.1 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 greg 3.4 /* set color divisors */
66     for (i = 0; i < 3; i++)
67     tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);
68    
69 greg 3.1 /* 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 greg 3.9 tmnew->hbrmin = 10; tmnew->hbrmax = -10;
76 greg 3.1 tmnew->histo = NULL;
77 greg 3.9 tmnew->mbrmin = 10; tmnew->mbrmax = -10;
78 greg 3.1 tmnew->lumap = NULL;
79 greg 3.4 /* zero private data */
80     for (i = TM_MAXPKG; i--; )
81     tmnew->pd[i] = NULL;
82     /* make tmnew current */
83 greg 3.1 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 greg 3.9 comprgb2xyzWBmat(tmTop->cmat, tmTop->monpri);
113 greg 3.1 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 greg 3.9 compxyz2rgbWBmat(tmTop->cmat, tmTop->monpri);
124 greg 3.1
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 greg 3.9 comprgb2rgbWBmat(tmTop->cmat, tmTop->inppri, tmTop->monpri);
130 greg 3.1 }
131     for (i = 0; i < 3; i++)
132     for (j = 0; j < 3; j++)
133     tmTop->cmat[i][j] *= tmTop->inpsf;
134 greg 3.4 /* 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 greg 3.1 returnOK;
146     }
147    
148    
149     void
150     tmClearHisto() /* clear current histogram */
151     {
152     if (tmTop == NULL || tmTop->histo == NULL)
153     return;
154 greg 3.4 free((MEM_PTR)tmTop->histo);
155 greg 3.1 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 greg 3.12 static COLOR csmall = {.5*MINLUM, .5*MINLUM, .5*MINLUM};
168 greg 3.1 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 schorsch 3.13 if ((ls == NULL) | (scan == NULL) | (len < 0))
176 greg 3.1 returnErr(TM_E_ILLEGAL);
177     for (i = len; i--; ) {
178 greg 3.15 if (tmNeedMatrix(tmTop)) { /* get monitor RGB */
179 greg 3.1 colortrans(cmon, tmTop->cmat, scan[i]);
180 greg 3.15 } else {
181 greg 3.1 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 greg 3.4 if (clipgamut(cmon, lum, CGAMUT_LOWER, csmall, cwhite))
191 greg 3.1 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 greg 3.4 cs[3*i ] = d>=.999 ? 255 :
224     (int)(256.*pow(d, 1./tmTop->mongam));
225 greg 3.1 d = tmTop->clf[GRN]*cmon[GRN]/lum;
226 greg 3.4 cs[3*i+1] = d>=.999 ? 255 :
227     (int)(256.*pow(d, 1./tmTop->mongam));
228 greg 3.1 d = tmTop->clf[BLU]*cmon[BLU]/lum;
229 greg 3.4 cs[3*i+2] = d>=.999 ? 255 :
230     (int)(256.*pow(d, 1./tmTop->mongam));
231 greg 3.1 }
232     returnOK;
233     }
234    
235    
236     int
237 greg 3.9 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 schorsch 3.13 if ((ls == NULL) | (scan == NULL) | (len < 0))
249 greg 3.9 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 greg 3.1 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 greg 3.9 int oldorig=0, oldlen, horig, hlen;
269 greg 3.1 register int i, j;
270    
271     if (tmTop == NULL)
272     returnErr(TM_E_TMINVAL);
273 gwlarson 3.8 if (len < 0)
274     returnErr(TM_E_ILLEGAL);
275     if (len == 0)
276     returnOK;
277 greg 3.1 /* first, grow limits */
278     if (tmTop->histo == NULL) {
279     for (i = len; i-- && ls[i] < MINBRT; )
280     ;
281     if (i < 0)
282     returnOK;
283 gregl 3.6 tmTop->hbrmin = tmTop->hbrmax = ls[i];
284 greg 3.1 oldlen = 0;
285     } else {
286 gregl 3.6 oldorig = (tmTop->hbrmin-MINBRT)/HISTEP;
287     oldlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - oldorig;
288 greg 3.1 }
289     for (i = len; i--; ) {
290     if ((j = ls[i]) < MINBRT)
291     continue;
292 gregl 3.6 if (j < tmTop->hbrmin)
293     tmTop->hbrmin = j;
294     else if (j > tmTop->hbrmax)
295     tmTop->hbrmax = j;
296 greg 3.1 }
297 gregl 3.6 horig = (tmTop->hbrmin-MINBRT)/HISTEP;
298     hlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - horig;
299 greg 3.1 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 greg 3.2 for (i = oldlen, j = i+oldorig-horig; i; )
305     newhist[--j] = tmTop->histo[--i];
306 greg 3.4 free((MEM_PTR)tmTop->histo);
307 greg 3.1 }
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 greg 3.9 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 greg 3.1 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 greg 3.9 int brt0, histlen, threshold, ceiling, trimmings;
394 greg 3.1 double logLddyn, Ldmin, Ldavg, Lwavg, Tr, Lw, Ld;
395 greg 3.11 int32 histot;
396 greg 3.9 double sum;
397 greg 3.1 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 gregl 3.6 i = (tmTop->hbrmin-MINBRT)/HISTEP;
411 greg 3.1 brt0 = MINBRT + HISTEP/2 + i*HISTEP;
412 gregl 3.6 histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i;
413 greg 3.1 /* histogram total and mean */
414     histot = 0; sum = 0;
415     j = brt0 + histlen*HISTEP;
416     for (i = histlen; i--; ) {
417 greg 3.2 histot += tmTop->histo[i];
418     sum += (j -= HISTEP) * tmTop->histo[i];
419 greg 3.1 }
420 greg 3.14 threshold = histot*0.005 + .5;
421 greg 3.1 if (threshold < 4)
422     returnErr(TM_E_TMFAIL);
423     Lwavg = tmLuminance( (double)sum / histot );
424 greg 3.9 /* 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 schorsch 3.13 if ((histo == NULL) | (cumf == NULL))
434 greg 3.9 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 greg 3.2 }
457 greg 3.9 if (histo[i] > ceiling) {
458     trimmings += histo[i] - ceiling;
459     histo[i] = ceiling;
460 greg 3.1 }
461     }
462 greg 3.9 /* 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 greg 3.1 }
477 greg 3.9 free((MEM_PTR)histo); /* clean up and return */
478     free((MEM_PTR)cumf);
479 greg 3.1 returnOK;
480 greg 3.9 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 greg 3.1 }
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 greg 3.11 register int32 li, pv;
498 greg 3.1
499     if (tmTop == NULL || tmTop->lumap == NULL)
500     returnErr(TM_E_TMINVAL);
501 schorsch 3.13 if ((ps == NULL) | (ls == NULL) | (len < 0))
502 greg 3.1 returnErr(TM_E_ILLEGAL);
503     while (len--) {
504 greg 3.9 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 greg 3.1 if (cs == TM_NOCHROM)
512     *ps++ = li>255 ? 255 : li;
513     else {
514 greg 3.4 pv = *cs++ * li / tmTop->cdiv[RED];
515 greg 3.1 *ps++ = pv>255 ? 255 : pv;
516 greg 3.4 pv = *cs++ * li / tmTop->cdiv[GRN];
517 greg 3.1 *ps++ = pv>255 ? 255 : pv;
518 greg 3.4 pv = *cs++ * li / tmTop->cdiv[BLU];
519 greg 3.1 *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 schorsch 3.13 if ((tms == NULL) | (tmTop == NULL))
544 greg 3.1 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 greg 3.3 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 gregl 3.6 len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 -
575     (tmnew->hbrmin-MINBRT)/HISTEP;
576 greg 3.3 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 gregl 3.6 len = tmnew->mbrmax-tmnew->mbrmin+1;
583 greg 3.3 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 greg 3.4 /* clear package data */
590     for (i = tmNumPkgs; i--; )
591     tmnew->pd[i] = NULL;
592 greg 3.3 tmnew->tmprev = tmTop; /* make copy current */
593     return(tmTop = tmnew);
594     }
595    
596    
597 greg 3.1 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 greg 3.4 if (tms == NULL)
604 greg 3.1 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 greg 3.4 register int i;
621 greg 3.1 /* 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 greg 3.4 free((MEM_PTR)tms->histo);
629 greg 3.1 if (tms->lumap != NULL)
630 greg 3.4 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 greg 3.9 }
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 greg 3.1 }