--- ray/src/common/tonemap.c 1997/04/15 16:53:01 3.1 +++ ray/src/common/tonemap.c 1997/11/12 13:25:48 3.5 @@ -18,13 +18,22 @@ 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; { - if (tmTop != NULL && tmTop->flags & TM_F_NOERRS) + tmLastFunction = func; + tmLastError = err; + if (tmTop != NULL && tmTop->flags & TM_F_NOSTDERR) return(err); fputs(func, stderr); fputs(": ", stderr); @@ -62,32 +71,28 @@ 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->histo = NULL; 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 +115,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 +144,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 +164,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 +177,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 +188,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 +200,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 +233,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; } @@ -277,13 +287,13 @@ int wt; if (newhist == NULL) returnErr(TM_E_NOMEM); if (oldlen) { /* copy and free old */ - for (i = oldlen, j = i+oldorig-horig; i--; ) - newhist[--j] = tmTop->histo[i]; - free((char *)tmTop->histo); + for (i = oldlen, j = i+oldorig-horig; i; ) + newhist[--j] = tmTop->histo[--i]; + free((MEM_PTR)tmTop->histo); } tmTop->histo = newhist; if (tmTop->lumap != NULL) { /* invalid tone map */ - free((char *)tmTop->lumap); + free((MEM_PTR)tmTop->lumap); tmTop->lumap = NULL; } } @@ -346,49 +356,53 @@ double Ldmax; i = (tmTop->brmin-MINBRT)/HISTEP; brt0 = MINBRT + HISTEP/2 + i*HISTEP; histlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - i; - /* allocate temporary tables */ - histo = (int *)malloc(histlen*sizeof(int)); - cumf = (float *)malloc((histlen+1)*sizeof(float)); - if (histo == NULL | cumf == NULL) - returnErr(TM_E_NOMEM); /* histogram total and mean */ histot = 0; sum = 0; j = brt0 + histlen*HISTEP; for (i = histlen; i--; ) { - histot += (histo[i] = tmTop->histo[i]); - sum += (j -= HISTEP) * histo[i]; + histot += tmTop->histo[i]; + sum += (j -= HISTEP) * tmTop->histo[i]; } threshold = histot*.025 + .5; if (threshold < 4) returnErr(TM_E_TMFAIL); Lwavg = tmLuminance( (double)sum / histot ); - do { /* iterate to solution */ - sum = 0; /* compute cumulative probability */ - for (i = 0; i < histlen; i++) { - cumf[i] = (double)sum/histot; - sum += histo[i]; - } - cumf[i] = 1.; - Tr = histot * (double)(tmTop->brmax - tmTop->brmin) / + if (!(tmTop->flags & TM_F_LINEAR)) { /* clamp histogram */ + histo = (int *)malloc(histlen*sizeof(int)); + cumf = (float *)malloc((histlen+1)*sizeof(float)); + if (histo == NULL | cumf == NULL) + returnErr(TM_E_NOMEM); + for (i = histlen; i--; ) /* make malleable copy */ + histo[i] = tmTop->histo[i]; + do { /* iterate to solution */ + sum = 0; /* cumulative probability */ + for (i = 0; i < histlen; i++) { + cumf[i] = (double)sum/histot; + sum += histo[i]; + } + cumf[i] = 1.; + Tr = histot * (double)(tmTop->brmax - tmTop->brmin) / ((double)histlen*TM_BRTSCALE) / logLddyn; - ceiling = Tr + 1.; - trimmings = 0; /* clip to envelope */ - for (i = histlen; i--; ) { - if (tmTop->flags & TM_F_HCONTR) { - Lw = tmLuminance(brt0 + i*HISTEP); - Ld = Ldmin * exp( logLddyn * + ceiling = Tr + 1.; + trimmings = 0; /* clip to envelope */ + for (i = histlen; i--; ) { + if (tmTop->flags & TM_F_HCONTR) { + Lw = tmLuminance(brt0 + i*HISTEP); + Ld = Ldmin * exp( logLddyn * .5*(cumf[i]+cumf[i+1]) ); - ceiling = Tr * (htcontrs(Ld) * Lw) / + ceiling = Tr * (htcontrs(Ld) * Lw) / (htcontrs(Lw) * Ld) + 1.; + } + if (histo[i] > ceiling) { + trimmings += histo[i] - ceiling; + histo[i] = ceiling; + } } - if (histo[i] > ceiling) { - trimmings += histo[i] - ceiling; - histo[i] = ceiling; - } - } - } while ((histot -= trimmings) > threshold && trimmings > threshold); - - if (tmTop->lumap == NULL) { /* allocate luminance map */ + } while ((histot -= trimmings) > threshold && + 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) @@ -415,8 +429,10 @@ double Ldmax; tmTop->lumap[i] = 256.*pow(d, 1./gamval); } } - free((char *)histo); - free((char *)cumf); + if (!(tmTop->flags & TM_F_LINEAR)) { + free((MEM_PTR)histo); + free((MEM_PTR)cumf); + } returnOK; } @@ -429,16 +445,12 @@ 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; @@ -448,11 +460,11 @@ int len; 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; } } @@ -494,13 +506,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->brmax-MINBRT)/HISTEP + 1 - + (tmnew->brmin-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->brmax-tmnew->brmin+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; @@ -517,6 +566,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; @@ -524,9 +574,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 */ }