ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tonemap.c
Revision: 3.10
Committed: Tue Feb 25 02:47:22 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 3.9: +1 -56 lines
Log Message:
Replaced inline copyright notice with #include "copyright.h"

File Contents

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