ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tonemap.c
(Generate patch)

Comparing ray/src/common/tonemap.c (file contents):
Revision 3.1 by greg, Tue Apr 15 16:53:01 1997 UTC vs.
Revision 3.6 by gregl, Mon Nov 17 14:02:12 1997 UTC

# Line 18 | Line 18 | static char SCCSid[] = "$SunId$ LBL";
18  
19   struct tmStruct *tmTop = NULL;          /* current tone mapping stack */
20  
21 +                                        /* our list of conversion packages */
22 + struct tmPackage        *tmPkg[TM_MAXPKG];
23 + int     tmNumPkgs = 0;                  /* number of registered packages */
24  
25 + int     tmLastError;                    /* last error incurred by library */
26 + char    *tmLastFunction;                /* error-generating function name */
27 +
28 +
29   int
30   tmErrorReturn(func, err)                /* error return (with message) */
31   char    *func;
32   int     err;
33   {
34 <        if (tmTop != NULL && tmTop->flags & TM_F_NOERRS)
34 >        tmLastFunction = func;
35 >        tmLastError = err;
36 >        if (tmTop != NULL && tmTop->flags & TM_F_NOSTDERR)
37                  return(err);
38          fputs(func, stderr);
39          fputs(": ", stderr);
# Line 62 | Line 71 | double gamval;
71                  tmnew->clf[GRN] = cmat[1][1];
72                  tmnew->clf[BLU] = cmat[1][2];
73          }
65        tmnew->clfb[RED] = 256.*tmnew->clf[RED] + .5;
66        tmnew->clfb[GRN] = 256.*tmnew->clf[GRN] + .5;
67        tmnew->clfb[BLU] = 256.*tmnew->clf[BLU] + .5;
68        tmnew->clfb[EXP] = COLXS;
74                                                  /* set gamma value */
75          if (gamval < MINGAM)
76                  tmnew->mongam = DEFGAM;
77          else
78                  tmnew->mongam = gamval;
79 <        for (i = TM_GAMTSZ; i--; )
80 <                tmnew->gamb[i] = 256.*pow((i+.5)/TM_GAMTSZ, 1./tmnew->mongam);
79 >                                                /* set color divisors */
80 >        for (i = 0; i < 3; i++)
81 >                tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);
82 >
83                                                  /* set input transform */
84          tmnew->inppri = tmnew->monpri;
85          tmnew->cmat[0][0] = tmnew->cmat[1][1] = tmnew->cmat[2][2] =
86                          tmnew->inpsf = WHTEFFICACY;
80        tmnew->inpsfb = TM_BRTSCALE*log(tmnew->inpsf) + .5;
87          tmnew->cmat[0][1] = tmnew->cmat[0][2] = tmnew->cmat[1][0] =
88          tmnew->cmat[1][2] = tmnew->cmat[2][0] = tmnew->cmat[2][1] = 0.;
89 <        tmnew->flags &= ~TM_F_NEEDMAT;
84 <        tmnew->brmin = tmnew->brmax = 0;
89 >        tmnew->hbrmin = tmnew->hbrmax = 0;
90          tmnew->histo = NULL;
91 +        tmnew->mbrmin = tmnew->mbrmax = 0;
92          tmnew->lumap = NULL;
93 <        tmnew->tmprev = NULL;
94 <
95 <        tmnew->flags |= TM_F_INITED;
96 <                                                /* make it current */
93 >                                                /* zero private data */
94 >        for (i = TM_MAXPKG; i--; )
95 >                tmnew->pd[i] = NULL;
96 >                                                /* make tmnew current */
97          tmnew->tmprev = tmTop;
98          return(tmTop = tmnew);
99   }
# Line 110 | Line 116 | double sf;
116                  returnOK;
117          tmTop->inppri = pri;                    /* let's set it */
118          tmTop->inpsf = sf;
113        tmTop->inpsfb = TM_BRTSCALE*log(sf) + (sf>=1. ? .5 : -.5);
119  
120          if (tmTop->flags & TM_F_BW) {           /* color doesn't matter */
121                  tmTop->monpri = tmTop->inppri;          /* eliminate xform */
122                  if (tmTop->inppri == TM_XYZPRIM) {
123                          tmTop->clf[CIEX] = tmTop->clf[CIEZ] = 0.;
124                          tmTop->clf[CIEY] = 1.;
120                        tmTop->clfb[CIEX] = tmTop->clfb[CIEZ] = 0;
121                        tmTop->clfb[CIEY] = 255;
125                  } else {
126                          comprgb2xyzmat(tmTop->cmat, tmTop->monpri);
127                          tmTop->clf[RED] = tmTop->cmat[1][0];
# Line 142 | Line 145 | double sf;
145          for (i = 0; i < 3; i++)
146                  for (j = 0; j < 3; j++)
147                          tmTop->cmat[i][j] *= tmTop->inpsf;
148 <        if (tmTop->inppri != tmTop->monpri)
149 <                tmTop->flags |= TM_F_NEEDMAT;
150 <        else
151 <                tmTop->flags &= ~TM_F_NEEDMAT;
148 >                                                /* set color divisors */
149 >        for (i = 0; i < 3; i++)
150 >                if (tmTop->clf[i] > .001)
151 >                        tmTop->cdiv[i] =
152 >                                256.*pow(tmTop->clf[i], 1./tmTop->mongam);
153 >                else
154 >                        tmTop->cdiv[i] = 1;
155 >                                                /* notify packages */
156 >        for (i = tmNumPkgs; i--; )
157 >                if (tmTop->pd[i] != NULL && tmPkg[i]->NewSpace != NULL)
158 >                        (*tmPkg[i]->NewSpace)(tmTop);
159          returnOK;
160   }
161  
# Line 155 | Line 165 | tmClearHisto()                 /* clear current histogram */
165   {
166          if (tmTop == NULL || tmTop->histo == NULL)
167                  return;
168 <        free((char *)tmTop->histo);
168 >        free((MEM_PTR)tmTop->histo);
169          tmTop->histo = NULL;
170   }
171  
# Line 168 | Line 178 | COLOR  *scan;
178   int     len;
179   {
180          static char     funcName[] = "tmCvColors";
181 +        static COLOR    csmall = {1e-6, 1e-6, 1e-6};
182          COLOR   cmon;
183          double  lum, slum;
184          register double d;
# Line 178 | Line 189 | int    len;
189          if (ls == NULL | scan == NULL | len <= 0)
190                  returnErr(TM_E_ILLEGAL);
191          for (i = len; i--; ) {
192 <                if (tmTop->flags & TM_F_NEEDMAT)        /* get monitor RGB */
192 >                if (tmNeedMatrix(tmTop))                /* get monitor RGB */
193                          colortrans(cmon, tmTop->cmat, scan[i]);
194                  else {
195                          cmon[RED] = tmTop->inpsf*scan[i][RED];
# Line 190 | Line 201 | int    len;
201                          tmTop->clf[GRN]*cmon[GRN] +
202                          tmTop->clf[BLU]*cmon[BLU] ;
203                                                          /* check range */
204 <                if (clipgamut(cmon, lum, CGAMUT_LOWER, cblack, cwhite))
204 >                if (clipgamut(cmon, lum, CGAMUT_LOWER, csmall, cwhite))
205                          lum =   tmTop->clf[RED]*cmon[RED] +
206                                  tmTop->clf[GRN]*cmon[GRN] +
207                                  tmTop->clf[BLU]*cmon[BLU] ;
# Line 223 | Line 234 | int    len;
234                          cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
235                  }
236                  d = tmTop->clf[RED]*cmon[RED]/lum;
237 <                /* cs[3*i  ] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
238 <                cs[3*i  ] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
237 >                cs[3*i  ] = d>=.999 ? 255 :
238 >                                (int)(256.*pow(d, 1./tmTop->mongam));
239                  d = tmTop->clf[GRN]*cmon[GRN]/lum;
240 <                /* cs[3*i+1] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
241 <                cs[3*i+1] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
240 >                cs[3*i+1] = d>=.999 ? 255 :
241 >                                (int)(256.*pow(d, 1./tmTop->mongam));
242                  d = tmTop->clf[BLU]*cmon[BLU]/lum;
243 <                /* cs[3*i+2] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
244 <                cs[3*i+2] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
243 >                cs[3*i+2] = d>=.999 ? 255 :
244 >                                (int)(256.*pow(d, 1./tmTop->mongam));
245          }
246          returnOK;
247   }
# Line 256 | Line 267 | int    wt;
267                          ;
268                  if (i < 0)
269                          returnOK;
270 <                tmTop->brmin = tmTop->brmax = ls[i];
270 >                tmTop->hbrmin = tmTop->hbrmax = ls[i];
271                  oldlen = 0;
272          } else {
273 <                oldorig = (tmTop->brmin-MINBRT)/HISTEP;
274 <                oldlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - oldorig;
273 >                oldorig = (tmTop->hbrmin-MINBRT)/HISTEP;
274 >                oldlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - oldorig;
275          }
276          for (i = len; i--; ) {
277                  if ((j = ls[i]) < MINBRT)
278                          continue;
279 <                if (j < tmTop->brmin)
280 <                        tmTop->brmin = j;
281 <                else if (j > tmTop->brmax)
282 <                        tmTop->brmax = j;
279 >                if (j < tmTop->hbrmin)
280 >                        tmTop->hbrmin = j;
281 >                else if (j > tmTop->hbrmax)
282 >                        tmTop->hbrmax = j;
283          }
284 <        horig = (tmTop->brmin-MINBRT)/HISTEP;
285 <        hlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - horig;
284 >        horig = (tmTop->hbrmin-MINBRT)/HISTEP;
285 >        hlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - horig;
286          if (hlen > oldlen) {                    /* (re)allocate histogram */
287                  register int    *newhist = (int *)calloc(hlen, sizeof(int));
288                  if (newhist == NULL)
289                          returnErr(TM_E_NOMEM);
290                  if (oldlen) {                   /* copy and free old */
291 <                        for (i = oldlen, j = i+oldorig-horig; i--; )
292 <                                newhist[--j] = tmTop->histo[i];
293 <                        free((char *)tmTop->histo);
291 >                        for (i = oldlen, j = i+oldorig-horig; i; )
292 >                                newhist[--j] = tmTop->histo[--i];
293 >                        free((MEM_PTR)tmTop->histo);
294                  }
295                  tmTop->histo = newhist;
285                if (tmTop->lumap != NULL) {     /* invalid tone map */
286                        free((char *)tmTop->lumap);
287                        tmTop->lumap = NULL;
288                }
296          }
297          if (wt == 0)
298                  returnOK;
# Line 343 | Line 350 | double Ldmax;
350          Ldmin = Ldmax/Lddyn;
351          logLddyn = log(Lddyn);
352          Ldavg = sqrt(Ldmax*Ldmin);
353 <        i = (tmTop->brmin-MINBRT)/HISTEP;
353 >        i = (tmTop->hbrmin-MINBRT)/HISTEP;
354          brt0 = MINBRT + HISTEP/2 + i*HISTEP;
355 <        histlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - i;
349 <                                        /* allocate temporary tables */
350 <        histo = (int *)malloc(histlen*sizeof(int));
351 <        cumf = (float *)malloc((histlen+1)*sizeof(float));
352 <        if (histo == NULL | cumf == NULL)
353 <                returnErr(TM_E_NOMEM);
355 >        histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i;
356                                          /* histogram total and mean */
357          histot = 0; sum = 0;
358          j = brt0 + histlen*HISTEP;
359          for (i = histlen; i--; ) {
360 <                histot += (histo[i] = tmTop->histo[i]);
361 <                sum += (j -= HISTEP) * histo[i];
360 >                histot += tmTop->histo[i];
361 >                sum += (j -= HISTEP) * tmTop->histo[i];
362          }
363          threshold = histot*.025 + .5;
364          if (threshold < 4)
365                  returnErr(TM_E_TMFAIL);
366          Lwavg = tmLuminance( (double)sum / histot );
367 <        do {                            /* iterate to solution */
368 <                sum = 0;                /* compute cumulative probability */
369 <                for (i = 0; i < histlen; i++) {
370 <                        cumf[i] = (double)sum/histot;
371 <                        sum += histo[i];
372 <                }
373 <                cumf[i] = 1.;
374 <                Tr = histot * (double)(tmTop->brmax - tmTop->brmin) /
367 >        if (!(tmTop->flags & TM_F_LINEAR)) {    /* clamp histogram */
368 >                histo = (int *)malloc(histlen*sizeof(int));
369 >                cumf = (float *)malloc((histlen+1)*sizeof(float));
370 >                if (histo == NULL | cumf == NULL)
371 >                        returnErr(TM_E_NOMEM);
372 >                for (i = histlen; i--; )        /* make malleable copy */
373 >                        histo[i] = tmTop->histo[i];
374 >                do {                            /* iterate to solution */
375 >                        sum = 0;                /* cumulative probability */
376 >                        for (i = 0; i < histlen; i++) {
377 >                                cumf[i] = (double)sum/histot;
378 >                                sum += histo[i];
379 >                        }
380 >                        cumf[i] = 1.;
381 >                        Tr = histot * (double)(tmTop->hbrmax - tmTop->hbrmin) /
382                                  ((double)histlen*TM_BRTSCALE) / logLddyn;
383 <                ceiling = Tr + 1.;
384 <                trimmings = 0;                  /* clip to envelope */
385 <                for (i = histlen; i--; ) {
386 <                        if (tmTop->flags & TM_F_HCONTR) {
387 <                                Lw = tmLuminance(brt0 + i*HISTEP);
388 <                                Ld = Ldmin * exp( logLddyn *
383 >                        ceiling = Tr + 1.;
384 >                        trimmings = 0;                  /* clip to envelope */
385 >                        for (i = histlen; i--; ) {
386 >                                if (tmTop->flags & TM_F_HCONTR) {
387 >                                        Lw = tmLuminance(brt0 + i*HISTEP);
388 >                                        Ld = Ldmin * exp( logLddyn *
389                                                  .5*(cumf[i]+cumf[i+1]) );
390 <                                ceiling = Tr * (htcontrs(Ld) * Lw) /
390 >                                        ceiling = Tr * (htcontrs(Ld) * Lw) /
391                                                  (htcontrs(Lw) * Ld) + 1.;
392 +                                }
393 +                                if (histo[i] > ceiling) {
394 +                                        trimmings += histo[i] - ceiling;
395 +                                        histo[i] = ceiling;
396 +                                }
397                          }
398 <                        if (histo[i] > ceiling) {
399 <                                trimmings += histo[i] - ceiling;
386 <                                histo[i] = ceiling;
387 <                        }
388 <                }
389 <        } while ((histot -= trimmings) > threshold && trimmings > threshold);
390 <
391 <        if (tmTop->lumap == NULL) {             /* allocate luminance map */
392 <                tmTop->lumap = (unsigned short *)malloc(
393 <                        (tmTop->brmax-tmTop->brmin+1)*sizeof(unsigned short) );
394 <                if (tmTop->lumap == NULL)
395 <                        returnErr(TM_E_NOMEM);
398 >                } while ((histot -= trimmings) > threshold &&
399 >                                                trimmings > threshold);
400          }
401 +                                                /* allocate luminance map */
402 +        if (tmTop->lumap != NULL)
403 +                free((MEM_PTR)tmTop->lumap);
404 +        tmTop->mbrmin = tmTop->hbrmin;
405 +        tmTop->mbrmax = tmTop->hbrmax;
406 +        tmTop->lumap = (unsigned short *)malloc(
407 +                (tmTop->mbrmax-tmTop->mbrmin+1)*sizeof(unsigned short) );
408 +        if (tmTop->lumap == NULL)
409 +                returnErr(TM_E_NOMEM);
410          if (tmTop->flags & TM_F_LINEAR || histot <= threshold) {
411                                                  /* linear tone mapping */
412                  if (tmTop->flags & TM_F_HCONTR)
# Line 401 | Line 414 | double Ldmax;
414                  else
415                          d = Ldavg / Lwavg;
416                  d = log(d/Ldmax);
417 <                for (i = tmTop->brmax-tmTop->brmin+1; i--; )
417 >                for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; )
418                          tmTop->lumap[i] = 256. * exp(
419 <                                ( d + (tmTop->brmin+i)/(double)TM_BRTSCALE )
419 >                                ( d + (tmTop->mbrmin+i)/(double)TM_BRTSCALE )
420                                  / gamval );
421          } else {
422                                                  /* histogram adjustment */
423 <                for (i = tmTop->brmax-tmTop->brmin+1; i--; ) {
424 <                        j = d = (double)i/(tmTop->brmax-tmTop->brmin)*histlen;
423 >                for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; ) {
424 >                        j = d = (double)i/(tmTop->mbrmax-tmTop->mbrmin)*histlen;
425                          d -= (double)j;
426                          Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1]));
427                          d = (Ld - Ldmin)/(Ldmax - Ldmin);
428                          tmTop->lumap[i] = 256.*pow(d, 1./gamval);
429                  }
430          }
431 <        free((char *)histo);
432 <        free((char *)cumf);
431 >        if (!(tmTop->flags & TM_F_LINEAR)) {
432 >                free((MEM_PTR)histo);
433 >                free((MEM_PTR)cumf);
434 >        }
435          returnOK;
436   }
437  
# Line 429 | Line 444 | register BYTE  *cs;
444   int     len;
445   {
446          static char     funcName[] = "tmMapPixels";
447 <        int     rdiv, gdiv, bdiv;
433 <        register int    li, pv;
447 >        register int4   li, pv;
448  
449          if (tmTop == NULL || tmTop->lumap == NULL)
450                  returnErr(TM_E_TMINVAL);
451          if (ps == NULL | ls == NULL | len <= 0)
452                  returnErr(TM_E_ILLEGAL);
439        rdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[RED])>>8];
440        gdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[GRN])>>8];
441        bdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[BLU])>>8];
453          while (len--) {
454 <                if ((li = *ls++) < tmTop->brmin)
455 <                        li = tmTop->brmin;
456 <                else if (li > tmTop->brmax)
457 <                        li = tmTop->brmax;
458 <                li = tmTop->lumap[li - tmTop->brmin];
454 >                if ((li = *ls++) < tmTop->mbrmin)
455 >                        li = tmTop->mbrmin;
456 >                else if (li > tmTop->mbrmax)
457 >                        li = tmTop->mbrmax;
458 >                li = tmTop->lumap[li - tmTop->mbrmin];
459                  if (cs == TM_NOCHROM)
460                          *ps++ = li>255 ? 255 : li;
461                  else {
462 <                        pv = *cs++ * li / rdiv;
462 >                        pv = *cs++ * li / tmTop->cdiv[RED];
463                          *ps++ = pv>255 ? 255 : pv;
464 <                        pv = *cs++ * li / gdiv;
464 >                        pv = *cs++ * li / tmTop->cdiv[GRN];
465                          *ps++ = pv>255 ? 255 : pv;
466 <                        pv = *cs++ * li / bdiv;
466 >                        pv = *cs++ * li / tmTop->cdiv[BLU];
467                          *ps++ = pv>255 ? 255 : pv;
468                  }
469          }
# Line 494 | Line 505 | register struct tmStruct       *tms;
505   }
506  
507  
508 + struct tmStruct *
509 + tmDup()                         /* duplicate top tone mapping */
510 + {
511 +        int     len;
512 +        register int    i;
513 +        register struct tmStruct        *tmnew;
514 +
515 +        if (tmTop == NULL)              /* anything to duplicate? */
516 +                return(NULL);
517 +        tmnew = (struct tmStruct *)malloc(sizeof(struct tmStruct));
518 +        if (tmnew == NULL)
519 +                return(NULL);
520 +        *tmnew = *tmTop;                /* copy everything */
521 +        if (tmnew->histo != NULL) {     /* duplicate histogram */
522 +                len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 -
523 +                                (tmnew->hbrmin-MINBRT)/HISTEP;
524 +                tmnew->histo = (int *)malloc(len*sizeof(int));
525 +                if (tmnew->histo != NULL)
526 +                        for (i = len; i--; )
527 +                                tmnew->histo[i] = tmTop->histo[i];
528 +        }
529 +        if (tmnew->lumap != NULL) {     /* duplicate luminance mapping */
530 +                len = tmnew->mbrmax-tmnew->mbrmin+1;
531 +                tmnew->lumap = (unsigned short *)malloc(
532 +                                                len*sizeof(unsigned short) );
533 +                if (tmnew->lumap != NULL)
534 +                        for (i = len; i--; )
535 +                                tmnew->lumap[i] = tmTop->lumap[i];
536 +        }
537 +                                        /* clear package data */
538 +        for (i = tmNumPkgs; i--; )
539 +                tmnew->pd[i] = NULL;
540 +        tmnew->tmprev = tmTop;          /* make copy current */
541 +        return(tmTop = tmnew);
542 + }
543 +
544 +
545   int
546   tmPush(tms)                     /* push tone mapping on top of stack */
547   register struct tmStruct        *tms;
548   {
549          static char     funcName[] = "tmPush";
550                                          /* check validity */
551 <        if (tms == NULL || !(tms->flags & TM_F_INITED))
551 >        if (tms == NULL)
552                  returnErr(TM_E_ILLEGAL);
553          if (tms == tmTop)               /* check necessity */
554                  returnOK;
# Line 517 | Line 565 | void
565   tmDone(tms)                     /* done with tone mapping -- destroy it */
566   register struct tmStruct        *tms;
567   {
568 +        register int    i;
569                                          /* NULL arg. is equiv. to tmTop */
570          if (tms == NULL && (tms = tmTop) == NULL)
571                  return;
# Line 524 | Line 573 | register struct tmStruct       *tms;
573          (void)tmPull(tms);
574                                          /* free tables */
575          if (tms->histo != NULL)
576 <                free((char *)tms->histo);
576 >                free((MEM_PTR)tms->histo);
577          if (tms->lumap != NULL)
578 <                free((char *)tms->lumap);
579 <        tms->flags = 0;
580 <        free((char *)tms);              /* free basic structure */
578 >                free((MEM_PTR)tms->lumap);
579 >                                        /* free private data */
580 >        for (i = tmNumPkgs; i--; )
581 >                if (tms->pd[i] != NULL)
582 >                        (*tmPkg[i]->Free)(tms->pd[i]);
583 >        free((MEM_PTR)tms);             /* free basic structure */
584   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines