--- ray/src/common/tonemap.c 1997/04/15 20:04:43 3.2 +++ ray/src/common/tonemap.c 1997/12/01 09:52:00 3.7 @@ -18,12 +18,21 @@ static char SCCSid[] = "$SunId$ LBL"; struct tmStruct *tmTop = NULL; /* current tone mapping stack */ + /* our list of conversion packages */ +struct tmPackage *tmPkg[TM_MAXPKG]; +int tmNumPkgs = 0; /* number of registered packages */ +int tmLastError; /* last error incurred by library */ +char *tmLastFunction; /* error-generating function name */ + + int tmErrorReturn(func, err) /* error return (with message) */ char *func; int err; { + tmLastFunction = func; + tmLastError = err; if (tmTop != NULL && tmTop->flags & TM_F_NOSTDERR) return(err); fputs(func, stderr); @@ -62,32 +71,29 @@ double gamval; tmnew->clf[GRN] = cmat[1][1]; tmnew->clf[BLU] = cmat[1][2]; } - tmnew->clfb[RED] = 256.*tmnew->clf[RED] + .5; - tmnew->clfb[GRN] = 256.*tmnew->clf[GRN] + .5; - tmnew->clfb[BLU] = 256.*tmnew->clf[BLU] + .5; - tmnew->clfb[EXP] = COLXS; /* set gamma value */ if (gamval < MINGAM) tmnew->mongam = DEFGAM; else tmnew->mongam = gamval; - for (i = TM_GAMTSZ; i--; ) - tmnew->gamb[i] = 256.*pow((i+.5)/TM_GAMTSZ, 1./tmnew->mongam); + /* set color divisors */ + for (i = 0; i < 3; i++) + tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam); + /* set input transform */ tmnew->inppri = tmnew->monpri; tmnew->cmat[0][0] = tmnew->cmat[1][1] = tmnew->cmat[2][2] = tmnew->inpsf = WHTEFFICACY; - tmnew->inpsfb = TM_BRTSCALE*log(tmnew->inpsf) + .5; tmnew->cmat[0][1] = tmnew->cmat[0][2] = tmnew->cmat[1][0] = tmnew->cmat[1][2] = tmnew->cmat[2][0] = tmnew->cmat[2][1] = 0.; - tmnew->flags &= ~TM_F_NEEDMAT; - tmnew->brmin = tmnew->brmax = 0; + tmnew->hbrmin = tmnew->hbrmax = 0; tmnew->histo = NULL; + tmnew->mbrmin = tmnew->mbrmax = 0; tmnew->lumap = NULL; - tmnew->tmprev = NULL; - - tmnew->flags |= TM_F_INITED; - /* make it current */ + /* zero private data */ + for (i = TM_MAXPKG; i--; ) + tmnew->pd[i] = NULL; + /* make tmnew current */ tmnew->tmprev = tmTop; return(tmTop = tmnew); } @@ -110,15 +116,12 @@ double sf; returnOK; tmTop->inppri = pri; /* let's set it */ tmTop->inpsf = sf; - tmTop->inpsfb = TM_BRTSCALE*log(sf) + (sf>=1. ? .5 : -.5); if (tmTop->flags & TM_F_BW) { /* color doesn't matter */ tmTop->monpri = tmTop->inppri; /* eliminate xform */ if (tmTop->inppri == TM_XYZPRIM) { tmTop->clf[CIEX] = tmTop->clf[CIEZ] = 0.; tmTop->clf[CIEY] = 1.; - tmTop->clfb[CIEX] = tmTop->clfb[CIEZ] = 0; - tmTop->clfb[CIEY] = 255; } else { comprgb2xyzmat(tmTop->cmat, tmTop->monpri); tmTop->clf[RED] = tmTop->cmat[1][0]; @@ -142,10 +145,17 @@ double sf; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) tmTop->cmat[i][j] *= tmTop->inpsf; - if (tmTop->inppri != tmTop->monpri) - tmTop->flags |= TM_F_NEEDMAT; - else - tmTop->flags &= ~TM_F_NEEDMAT; + /* set color divisors */ + for (i = 0; i < 3; i++) + if (tmTop->clf[i] > .001) + tmTop->cdiv[i] = + 256.*pow(tmTop->clf[i], 1./tmTop->mongam); + else + tmTop->cdiv[i] = 1; + /* notify packages */ + for (i = tmNumPkgs; i--; ) + if (tmTop->pd[i] != NULL && tmPkg[i]->NewSpace != NULL) + (*tmPkg[i]->NewSpace)(tmTop); returnOK; } @@ -155,7 +165,7 @@ tmClearHisto() /* clear current histogram */ { if (tmTop == NULL || tmTop->histo == NULL) return; - free((char *)tmTop->histo); + free((MEM_PTR)tmTop->histo); tmTop->histo = NULL; } @@ -168,6 +178,7 @@ COLOR *scan; int len; { static char funcName[] = "tmCvColors"; + static COLOR csmall = {1e-6, 1e-6, 1e-6}; COLOR cmon; double lum, slum; register double d; @@ -178,7 +189,7 @@ int len; if (ls == NULL | scan == NULL | len <= 0) returnErr(TM_E_ILLEGAL); for (i = len; i--; ) { - if (tmTop->flags & TM_F_NEEDMAT) /* get monitor RGB */ + if (tmNeedMatrix(tmTop)) /* get monitor RGB */ colortrans(cmon, tmTop->cmat, scan[i]); else { cmon[RED] = tmTop->inpsf*scan[i][RED]; @@ -190,7 +201,7 @@ int len; tmTop->clf[GRN]*cmon[GRN] + tmTop->clf[BLU]*cmon[BLU] ; /* check range */ - if (clipgamut(cmon, lum, CGAMUT_LOWER, cblack, cwhite)) + if (clipgamut(cmon, lum, CGAMUT_LOWER, csmall, cwhite)) lum = tmTop->clf[RED]*cmon[RED] + tmTop->clf[GRN]*cmon[GRN] + tmTop->clf[BLU]*cmon[BLU] ; @@ -223,14 +234,14 @@ int len; cmon[RED] = cmon[GRN] = cmon[BLU] = lum; } d = tmTop->clf[RED]*cmon[RED]/lum; - /* cs[3*i ] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */ - cs[3*i ] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)]; + cs[3*i ] = d>=.999 ? 255 : + (int)(256.*pow(d, 1./tmTop->mongam)); d = tmTop->clf[GRN]*cmon[GRN]/lum; - /* cs[3*i+1] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */ - cs[3*i+1] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)]; + cs[3*i+1] = d>=.999 ? 255 : + (int)(256.*pow(d, 1./tmTop->mongam)); d = tmTop->clf[BLU]*cmon[BLU]/lum; - /* cs[3*i+2] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */ - cs[3*i+2] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)]; + cs[3*i+2] = d>=.999 ? 255 : + (int)(256.*pow(d, 1./tmTop->mongam)); } returnOK; } @@ -243,7 +254,7 @@ int len; int wt; { static char funcName[] = "tmAddHisto"; - int sum, oldorig, oldlen, horig, hlen; + int oldorig, oldlen, horig, hlen; register int i, j; if (len <= 0) @@ -256,22 +267,22 @@ int wt; ; if (i < 0) returnOK; - tmTop->brmin = tmTop->brmax = ls[i]; + tmTop->hbrmin = tmTop->hbrmax = ls[i]; oldlen = 0; } else { - oldorig = (tmTop->brmin-MINBRT)/HISTEP; - oldlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - oldorig; + oldorig = (tmTop->hbrmin-MINBRT)/HISTEP; + oldlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - oldorig; } for (i = len; i--; ) { if ((j = ls[i]) < MINBRT) continue; - if (j < tmTop->brmin) - tmTop->brmin = j; - else if (j > tmTop->brmax) - tmTop->brmax = j; + if (j < tmTop->hbrmin) + tmTop->hbrmin = j; + else if (j > tmTop->hbrmax) + tmTop->hbrmax = j; } - horig = (tmTop->brmin-MINBRT)/HISTEP; - hlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - horig; + horig = (tmTop->hbrmin-MINBRT)/HISTEP; + hlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - horig; if (hlen > oldlen) { /* (re)allocate histogram */ register int *newhist = (int *)calloc(hlen, sizeof(int)); if (newhist == NULL) @@ -279,13 +290,9 @@ int wt; if (oldlen) { /* copy and free old */ for (i = oldlen, j = i+oldorig-horig; i; ) newhist[--j] = tmTop->histo[--i]; - free((char *)tmTop->histo); + free((MEM_PTR)tmTop->histo); } tmTop->histo = newhist; - if (tmTop->lumap != NULL) { /* invalid tone map */ - free((char *)tmTop->lumap); - tmTop->lumap = NULL; - } } if (wt == 0) returnOK; @@ -343,9 +350,9 @@ double Ldmax; Ldmin = Ldmax/Lddyn; logLddyn = log(Lddyn); Ldavg = sqrt(Ldmax*Ldmin); - i = (tmTop->brmin-MINBRT)/HISTEP; + i = (tmTop->hbrmin-MINBRT)/HISTEP; brt0 = MINBRT + HISTEP/2 + i*HISTEP; - histlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - i; + histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i; /* histogram total and mean */ histot = 0; sum = 0; j = brt0 + histlen*HISTEP; @@ -371,7 +378,7 @@ double Ldmax; sum += histo[i]; } cumf[i] = 1.; - Tr = histot * (double)(tmTop->brmax - tmTop->brmin) / + Tr = histot * (double)(tmTop->hbrmax - tmTop->hbrmin) / ((double)histlen*TM_BRTSCALE) / logLddyn; ceiling = Tr + 1.; trimmings = 0; /* clip to envelope */ @@ -392,12 +399,14 @@ double Ldmax; trimmings > threshold); } /* allocate luminance map */ - if (tmTop->lumap == NULL) { - tmTop->lumap = (unsigned short *)malloc( - (tmTop->brmax-tmTop->brmin+1)*sizeof(unsigned short) ); - if (tmTop->lumap == NULL) - returnErr(TM_E_NOMEM); - } + if (tmTop->lumap != NULL) + free((MEM_PTR)tmTop->lumap); + tmTop->mbrmin = tmTop->hbrmin; + tmTop->mbrmax = tmTop->hbrmax; + tmTop->lumap = (unsigned short *)malloc( + (tmTop->mbrmax-tmTop->mbrmin+1)*sizeof(unsigned short) ); + if (tmTop->lumap == NULL) + returnErr(TM_E_NOMEM); if (tmTop->flags & TM_F_LINEAR || histot <= threshold) { /* linear tone mapping */ if (tmTop->flags & TM_F_HCONTR) @@ -405,14 +414,14 @@ double Ldmax; else d = Ldavg / Lwavg; d = log(d/Ldmax); - for (i = tmTop->brmax-tmTop->brmin+1; i--; ) + for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; ) tmTop->lumap[i] = 256. * exp( - ( d + (tmTop->brmin+i)/(double)TM_BRTSCALE ) + ( d + (tmTop->mbrmin+i)/(double)TM_BRTSCALE ) / gamval ); } else { /* histogram adjustment */ - for (i = tmTop->brmax-tmTop->brmin+1; i--; ) { - j = d = (double)i/(tmTop->brmax-tmTop->brmin)*histlen; + for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; ) { + j = d = (double)i/(tmTop->mbrmax-tmTop->mbrmin)*histlen; d -= (double)j; Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1])); d = (Ld - Ldmin)/(Ldmax - Ldmin); @@ -420,8 +429,8 @@ double Ldmax; } } if (!(tmTop->flags & TM_F_LINEAR)) { - free((char *)histo); - free((char *)cumf); + free((MEM_PTR)histo); + free((MEM_PTR)cumf); } returnOK; } @@ -435,30 +444,26 @@ register BYTE *cs; int len; { static char funcName[] = "tmMapPixels"; - int rdiv, gdiv, bdiv; - register int li, pv; + register int4 li, pv; if (tmTop == NULL || tmTop->lumap == NULL) returnErr(TM_E_TMINVAL); if (ps == NULL | ls == NULL | len <= 0) returnErr(TM_E_ILLEGAL); - rdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[RED])>>8]; - gdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[GRN])>>8]; - bdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[BLU])>>8]; while (len--) { - if ((li = *ls++) < tmTop->brmin) - li = tmTop->brmin; - else if (li > tmTop->brmax) - li = tmTop->brmax; - li = tmTop->lumap[li - tmTop->brmin]; + if ((li = *ls++) < tmTop->mbrmin) + li = tmTop->mbrmin; + else if (li > tmTop->mbrmax) + li = tmTop->mbrmax; + li = tmTop->lumap[li - tmTop->mbrmin]; if (cs == TM_NOCHROM) *ps++ = li>255 ? 255 : li; else { - pv = *cs++ * li / rdiv; + pv = *cs++ * li / tmTop->cdiv[RED]; *ps++ = pv>255 ? 255 : pv; - pv = *cs++ * li / gdiv; + pv = *cs++ * li / tmTop->cdiv[GRN]; *ps++ = pv>255 ? 255 : pv; - pv = *cs++ * li / bdiv; + pv = *cs++ * li / tmTop->cdiv[BLU]; *ps++ = pv>255 ? 255 : pv; } } @@ -500,13 +505,50 @@ register struct tmStruct *tms; } +struct tmStruct * +tmDup() /* duplicate top tone mapping */ +{ + int len; + register int i; + register struct tmStruct *tmnew; + + if (tmTop == NULL) /* anything to duplicate? */ + return(NULL); + tmnew = (struct tmStruct *)malloc(sizeof(struct tmStruct)); + if (tmnew == NULL) + return(NULL); + *tmnew = *tmTop; /* copy everything */ + if (tmnew->histo != NULL) { /* duplicate histogram */ + len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 - + (tmnew->hbrmin-MINBRT)/HISTEP; + tmnew->histo = (int *)malloc(len*sizeof(int)); + if (tmnew->histo != NULL) + for (i = len; i--; ) + tmnew->histo[i] = tmTop->histo[i]; + } + if (tmnew->lumap != NULL) { /* duplicate luminance mapping */ + len = tmnew->mbrmax-tmnew->mbrmin+1; + tmnew->lumap = (unsigned short *)malloc( + len*sizeof(unsigned short) ); + if (tmnew->lumap != NULL) + for (i = len; i--; ) + tmnew->lumap[i] = tmTop->lumap[i]; + } + /* clear package data */ + for (i = tmNumPkgs; i--; ) + tmnew->pd[i] = NULL; + tmnew->tmprev = tmTop; /* make copy current */ + return(tmTop = tmnew); +} + + int tmPush(tms) /* push tone mapping on top of stack */ register struct tmStruct *tms; { static char funcName[] = "tmPush"; /* check validity */ - if (tms == NULL || !(tms->flags & TM_F_INITED)) + if (tms == NULL) returnErr(TM_E_ILLEGAL); if (tms == tmTop) /* check necessity */ returnOK; @@ -523,6 +565,7 @@ void tmDone(tms) /* done with tone mapping -- destroy it */ register struct tmStruct *tms; { + register int i; /* NULL arg. is equiv. to tmTop */ if (tms == NULL && (tms = tmTop) == NULL) return; @@ -530,9 +573,12 @@ register struct tmStruct *tms; (void)tmPull(tms); /* free tables */ if (tms->histo != NULL) - free((char *)tms->histo); + free((MEM_PTR)tms->histo); if (tms->lumap != NULL) - free((char *)tms->lumap); - tms->flags = 0; - free((char *)tms); /* free basic structure */ + free((MEM_PTR)tms->lumap); + /* free private data */ + for (i = tmNumPkgs; i--; ) + if (tms->pd[i] != NULL) + (*tmPkg[i]->Free)(tms->pd[i]); + free((MEM_PTR)tms); /* free basic structure */ }