--- ray/src/common/tmapcolrs.c 1997/04/16 20:28:05 3.2 +++ ray/src/common/tmapcolrs.c 2006/05/31 19:27:42 3.25 @@ -1,99 +1,134 @@ -/* Copyright (c) 1997 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: tmapcolrs.c,v 3.25 2006/05/31 19:27:42 greg Exp $"; #endif - /* * Routines for tone mapping on Radiance RGBE and XYZE pictures. - * See tonemap.h for detailed function descriptions. + * + * Externals declared in tonemap.h */ +#include "copyright.h" + #include +#include #include +#include + #include "tmprivat.h" #include "resolu.h" +#ifdef PCOND +#include "rtprocess.h" +#endif +#define GAMTSZ 1024 -extern char *tempbuffer(); +typedef struct { + BYTE gamb[GAMTSZ]; /* gamma lookup table */ + int clfb[3]; /* encoded tm->clf */ + int32 cmatb[3][3]; /* encoded color transform */ + TMbright inpsfb; /* encoded tm->inpsf */ +} COLRDATA; +static MEM_PTR colrInit(TMstruct *); +static void colrNewSpace(TMstruct *); +static gethfunc headline; + +static struct tmPackage colrPkg = { /* our package functions */ + colrInit, colrNewSpace, free +}; +static int colrReg = -1; /* our package registration number */ + #define LOGISZ 260 static TMbright logi[LOGISZ]; -static BYTE photofact[BMESUPPER-BMESLOWER]; int -tmCvColrs(ls, cs, scan, len) /* tone map RGBE/XYZE colors */ -TMbright *ls; -BYTE *cs; -COLR *scan; -int len; +tmCvColrs( /* convert RGBE/XYZE colors */ +TMstruct *tms, +TMbright *ls, +BYTE *cs, +COLR *scan, +int len +) { - static char funcName[] = "tmCvColrs"; - COLR cmon; - register int i, bi, li; + static const char funcName[] = "tmCvColrs"; + int cmon[4]; + register COLRDATA *cd; + register int i, j, li, bi; + int32 vl; - if (tmTop == NULL) + if (tms == NULL) returnErr(TM_E_TMINVAL); - if (ls == NULL | scan == NULL | len <= 0) + if ((ls == NULL) | (scan == NULL) | (len < 0)) returnErr(TM_E_ILLEGAL); - if (tmTop->flags & TM_F_NEEDMAT) { /* need floating point */ - register COLOR *newscan; - newscan = (COLOR *)tempbuffer(len*sizeof(COLOR)); - if (newscan == NULL) - returnErr(TM_E_NOMEM); - for (i = len; i--; ) - colr_color(newscan[i], scan[i]); - return(tmCvColors(ls, cs, newscan, len)); - } - if (logi[0] == 0) { /* build tables if necessary */ + if (colrReg < 0) { /* build tables if necessary */ + colrReg = tmRegPkg(&colrPkg); + if (colrReg < 0) + returnErr(TM_E_CODERR1); for (i = 256; i--; ) logi[i] = TM_BRTSCALE*log((i+.5)/256.) - .5; for (i = 256; i < LOGISZ; i++) - logi[i] = logi[255]; - for (i = BMESLOWER; i < BMESUPPER; i++) - photofact[i-BMESLOWER] = 256. * - (tmLuminance(i) - LMESLOWER) / - (LMESUPPER - LMESLOWER); + logi[i] = 0; + tmMkMesofact(); } + if ((cd = (COLRDATA *)tmPkgData(tms,colrReg)) == NULL) + returnErr(TM_E_NOMEM); for (i = len; i--; ) { - copycolr(cmon, scan[i]); + if (tmNeedMatrix(tms)) { /* apply color xform */ + for (j = 3; j--; ) { + vl = cd->cmatb[j][RED]*(int32)scan[i][RED] + + cd->cmatb[j][GRN]*(int32)scan[i][GRN] + + cd->cmatb[j][BLU]*(int32)scan[i][BLU] ; + if (vl < 0) cmon[j] = vl/0x10000; + else cmon[j] = vl>>16; + } + cmon[EXP] = scan[i][EXP]; + } else + copycolr(cmon, scan[i]); /* world luminance */ - li = ( tmTop->clfb[RED]*cmon[RED] + - tmTop->clfb[GRN]*cmon[GRN] + - tmTop->clfb[BLU]*cmon[BLU] ) >> 8; - bi = BRT2SCALE*(cmon[EXP]-COLXS) + - logi[li] + tmTop->inpsfb; - if (bi < MINBRT) { - bi = MINBRT-1; /* bogus value */ - li++; /* avoid li==0 */ + li = cd->clfb[RED]*cmon[RED] + + cd->clfb[GRN]*cmon[GRN] + + cd->clfb[BLU]*cmon[BLU] ; + if (li >= 0xfff00) li = 255; + else li >>= 12; + bi = BRT2SCALE(cmon[EXP]-COLXS) + cd->inpsfb; + if (li > 0) + bi += logi[li]; + else { + bi += logi[0]; + li = 1; /* avoid /0 */ } ls[i] = bi; if (cs == TM_NOCHROM) /* no color? */ continue; /* mesopic adj. */ - if (tmTop->flags & TM_F_MESOPIC && bi < BMESUPPER) { - register int pf, sli = normscot(cmon); - if (bi < BMESLOWER) + if (tms->flags & TM_F_MESOPIC && bi < BMESUPPER) { + int pf, sli = normscot(cmon); + if (bi < BMESLOWER) { cmon[RED] = cmon[GRN] = cmon[BLU] = sli; - else { - if (tmTop->flags & TM_F_BW) + } else { + if (tms->flags & TM_F_BW) cmon[RED] = cmon[GRN] = cmon[BLU] = li; - pf = photofact[bi-BMESLOWER]; + pf = tmMesofact[bi-BMESLOWER]; sli *= 256 - pf; - cmon[RED] = ( sli + pf*cmon[RED] ) >> 8; - cmon[GRN] = ( sli + pf*cmon[GRN] ) >> 8; - cmon[BLU] = ( sli + pf*cmon[BLU] ) >> 8; + for (j = 3; j--; ) { + cmon[j] = sli + pf*cmon[j]; + if (cmon[j] <= 0) cmon[j] = 0; + else cmon[j] >>= 8; + } } - } else if (tmTop->flags & TM_F_BW) { + } else if (tms->flags & TM_F_BW) { cmon[RED] = cmon[GRN] = cmon[BLU] = li; + } else { + for (j = 3; j--; ) + if (cmon[j] < 0) cmon[j] = 0; } - bi = ( (int4)TM_GAMTSZ*tmTop->clfb[RED]*cmon[RED]/li ) >> 8; - cs[3*i ] = bi>=TM_GAMTSZ ? 255 : tmTop->gamb[bi]; - bi = ( (int4)TM_GAMTSZ*tmTop->clfb[GRN]*cmon[GRN]/li ) >> 8; - cs[3*i+1] = bi>=TM_GAMTSZ ? 255 : tmTop->gamb[bi]; - bi = ( (int4)TM_GAMTSZ*tmTop->clfb[BLU]*cmon[BLU]/li ) >> 8; - cs[3*i+2] = bi>=TM_GAMTSZ ? 255 : tmTop->gamb[bi]; + bi = ( (int32)GAMTSZ*cd->clfb[RED]*cmon[RED]/li ) >> 12; + cs[3*i ] = bi>=GAMTSZ ? 255 : cd->gamb[bi]; + bi = ( (int32)GAMTSZ*cd->clfb[GRN]*cmon[GRN]/li ) >> 12; + cs[3*i+1] = bi>=GAMTSZ ? 255 : cd->gamb[bi]; + bi = ( (int32)GAMTSZ*cd->clfb[BLU]*cmon[BLU]/li ) >> 12; + cs[3*i+2] = bi>=GAMTSZ ? 255 : cd->gamb[bi]; } returnOK; } @@ -113,11 +148,13 @@ static struct radhead { static int -headline(s, rh) /* grok a header line */ -register char *s; -register struct radhead *rh; +headline( /* grok a header line */ + register char *s, + void *vrh +) { char fmt[32]; + register struct radhead *rh = vrh; if (formatval(fmt, s)) { if (!strcmp(fmt, COLRFMT)) @@ -126,27 +163,31 @@ register struct radhead *rh; rh->format = FMTCIE; else rh->format = FMTBAD; - return; + return(0); } if (isexpos(s)) { rh->expos *= exposval(s); - return; + return(0); } if (isprims(s)) { primsval(rh->mypri, s); rh->primp = rh->mypri; - return; + return(0); } + return(0); } int -tmLoadPicture(lpp, cpp, xp, yp, fname, fp) /* convert Radiance picture */ -TMbright **lpp; -BYTE **cpp; -int *xp, *yp; -char *fname; -FILE *fp; +tmLoadPicture( /* convert Radiance picture */ +TMstruct *tms, +TMbright **lpp, +BYTE **cpp, +int *xp, +int *yp, +char *fname, +FILE *fp +) { char *funcName = fname==NULL ? "tmLoadPicture" : fname; FILE *inpf; @@ -155,17 +196,19 @@ FILE *fp; COLR *scanin = NULL; int i; /* check arguments */ - if (tmTop == NULL) + if (tms == NULL) returnErr(TM_E_TMINVAL); - if (lpp == NULL | xp == NULL | yp == NULL | - (fname == NULL & fp == TM_GETFILE)) + if ((lpp == NULL) | (xp == NULL) | (yp == NULL) | + ((fname == NULL) & (fp == TM_GETFILE))) returnErr(TM_E_ILLEGAL); *xp = *yp = 0; /* error precaution */ - if ((inpf = fp) == TM_GETFILE && (inpf = fopen(fname, "r")) == NULL) + if ((inpf = fp) == TM_GETFILE && (inpf = fopen(fname, "rb")) == NULL) returnErr(TM_E_BADFILE); + *lpp = NULL; + if (cpp != TM_NOCHROMP) *cpp = NULL; info = rhdefault; /* get our header */ - getheader(inpf, headline, (char *)&info); - if (info.format == FMTBAD | info.expos <= 0. || + getheader(inpf, headline, &info); + if ((info.format == FMTBAD) | (info.expos <= 0.) || fgetresolu(xp, yp, inpf) < 0) { err = TM_E_BADFILE; goto done; } @@ -176,7 +219,7 @@ FILE *fp; else if (info.format == FMTCIE) info.primp = TM_XYZPRIM; /* prepare library */ - if ((err = tmSetSpace(info.primp, 1./info.expos)) != TM_E_OK) + if ((err = tmSetSpace(tms, info.primp, 1./info.expos, NULL)) != TM_E_OK) goto done; err = TM_E_NOMEM; /* allocate arrays */ *lpp = (TMbright *)malloc(sizeof(TMbright) * *xp * *yp); @@ -195,7 +238,7 @@ FILE *fp; if (freadcolrs(scanin, *xp, inpf) < 0) { err = TM_E_BADFILE; break; } - err = tmCvColrs(*lpp + (i * *xp), + err = tmCvColrs(tms, *lpp + (i * *xp), cpp==TM_NOCHROMP ? TM_NOCHROM : *cpp + (i * 3 * *xp), scanin, *xp); if (err != TM_E_OK) @@ -205,14 +248,20 @@ done: /* clean up */ if (fp == NULL) fclose(inpf); if (scanin != NULL) - free((char *)scanin); - if (err != TM_E_OK) + free((MEM_PTR)scanin); + if (err != TM_E_OK) { + if (*lpp != NULL) + free((MEM_PTR)*lpp); + if (cpp != TM_NOCHROMP && *cpp != NULL) + free((MEM_PTR)*cpp); returnErr(err); + } returnOK; } -int /* run pcond to map picture */ +#ifdef PCOND +static int /* run pcond to map picture */ dopcond(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname) BYTE **psp; int *xp, *yp; @@ -222,7 +271,8 @@ double gamval, Lddyn, Ldmax; char *fname; { char *funcName = fname; - char cmdbuf[512]; + TMstruct *tms = NULL; + char cmdbuf[1024]; FILE *infp; register COLR *scan; register BYTE *rp; @@ -232,26 +282,26 @@ char *fname; if (setcolrcor(pow, 1./gamval) < 0) returnErr(TM_E_NOMEM); /* create command */ - strcpy(cmdbuf, "pcond "); + strcpy(cmdbuf, PCOND); if (flags & TM_F_HCONTR) - strcat(cmdbuf, "-s "); + strcat(cmdbuf, " -s"); if (flags & TM_F_MESOPIC) - strcat(cmdbuf, "-c "); + strcat(cmdbuf, " -c"); if (flags & TM_F_LINEAR) - strcat(cmdbuf, "-l "); + strcat(cmdbuf, " -l"); if (flags & TM_F_ACUITY) - strcat(cmdbuf, "-a "); + strcat(cmdbuf, " -a"); if (flags & TM_F_VEIL) - strcat(cmdbuf, "-v "); + strcat(cmdbuf, " -v"); if (flags & TM_F_CWEIGHT) - strcat(cmdbuf, "-w "); - sprintf(cmdbuf+strlen(cmdbuf), - "-p %f %f %f %f %f %f %f %f -d %f -u %f %s", - monpri[RED][CIEX], monpri[RED][CIEY], - monpri[GRN][CIEX], monpri[GRN][CIEY], - monpri[BLU][CIEX], monpri[BLU][CIEY], - monpri[WHT][CIEX], monpri[WHT][CIEY], - Lddyn, Ldmax, fname); + strcat(cmdbuf, " -w"); + if (monpri != stdprims) + sprintf(cmdbuf+strlen(cmdbuf), " -p %f %f %f %f %f %f %f %f", + monpri[RED][CIEX], monpri[RED][CIEY], + monpri[GRN][CIEX], monpri[GRN][CIEY], + monpri[BLU][CIEX], monpri[BLU][CIEY], + monpri[WHT][CIEX], monpri[WHT][CIEY]); + sprintf(cmdbuf+strlen(cmdbuf), " -d %f -u %f %s", Lddyn, Ldmax, fname); /* start pcond */ if ((infp = popen(cmdbuf, "r")) == NULL) returnErr(TM_E_BADFILE); @@ -267,7 +317,7 @@ char *fname; rp = (BYTE *)malloc(sizeof(BYTE) * *xp * *yp); else rp = (BYTE *)malloc(3*sizeof(BYTE) * *xp * *yp); - if ((*psp = rp) == NULL | scan == NULL) { + if (((*psp = rp) == NULL) | (scan == NULL)) { pclose(infp); returnErr(TM_E_NOMEM); } @@ -275,8 +325,8 @@ char *fname; for (y = 0; y < *yp; y++) { if (freadcolrs(scan, *xp, infp) < 0) { pclose(infp); - free((char *)scan); - free((char *)*psp); + free((MEM_PTR)scan); + free((MEM_PTR)*psp); *psp = NULL; returnErr(TM_E_BADFILE); } @@ -291,10 +341,11 @@ char *fname; *rp++ = scan[x][BLU]; } } - free((char *)scan); + free((MEM_PTR)scan); pclose(infp); returnOK; } +#endif int /* map a Radiance picture */ @@ -308,61 +359,103 @@ char *fname; FILE *fp; { char *funcName = fname==NULL ? "tmMapPicture" : fname; - FILE *inpf; + TMstruct *tms; BYTE *cp; TMbright *lp; int err; /* check arguments */ - if (psp == NULL | xp == NULL | yp == NULL | monpri == NULL | - (fname == NULL & fp == TM_GETFILE)) + if ((psp == NULL) | (xp == NULL) | (yp == NULL) | (monpri == NULL) | + ((fname == NULL) & (fp == TM_GETFILE))) returnErr(TM_E_ILLEGAL); /* set defaults */ if (gamval < MINGAM) gamval = DEFGAM; if (Lddyn < MINLDDYN) Lddyn = DEFLDDYN; if (Ldmax < MINLDMAX) Ldmax = DEFLDMAX; if (flags & TM_F_BW) monpri = stdprims; +#ifdef PCOND /* check for pcond run */ if (fp == TM_GETFILE && flags & TM_F_UNIMPL) return( dopcond(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname) ); +#endif /* initialize tone mapping */ - if (tmInit(flags, monpri, gamval) == NULL) + if ((tms = tmInit(flags, monpri, gamval)) == NULL) returnErr(TM_E_NOMEM); /* load & convert picture */ - err = tmLoadPicture(&lp, (flags&TM_F_BW) ? TM_NOCHROMP : &cp, + err = tmLoadPicture(tms, &lp, (flags&TM_F_BW) ? TM_NOCHROMP : &cp, xp, yp, fname, fp); if (err != TM_E_OK) { - tmDone(NULL); + tmDone(tms); return(err); } /* allocate space for result */ if (flags & TM_F_BW) { *psp = (BYTE *)malloc(sizeof(BYTE) * *xp * *yp); if (*psp == NULL) { - free((char *)lp); - tmDone(NULL); + free((MEM_PTR)lp); + tmDone(tms); returnErr(TM_E_NOMEM); } cp = TM_NOCHROM; } else *psp = cp; /* compute color mapping */ - err = tmAddHisto(lp, *xp * *yp, 1); + err = tmAddHisto(tms, lp, *xp * *yp, 1); if (err != TM_E_OK) goto done; - err = tmComputeMapping(gamval, Lddyn, Ldmax); + err = tmComputeMapping(tms, gamval, Lddyn, Ldmax); if (err != TM_E_OK) goto done; /* map colors */ - err = tmMapPixels(*psp, lp, cp, *xp * *yp); + err = tmMapPixels(tms, *psp, lp, cp, *xp * *yp); done: /* clean up */ - free((char *)lp); - tmDone(NULL); + free((MEM_PTR)lp); + tmDone(tms); if (err != TM_E_OK) { /* free memory on error */ - free((char *)*psp); + free((MEM_PTR)*psp); *psp = NULL; returnErr(err); } returnOK; +} + + +static void +colrNewSpace(tms) /* color space changed for tone mapping */ +register TMstruct *tms; +{ + register COLRDATA *cd; + double d; + int i, j; + + cd = (COLRDATA *)tms->pd[colrReg]; + for (i = 3; i--; ) + cd->clfb[i] = 0x1000*tms->clf[i] + .5; + cd->inpsfb = tmCvLuminance(tms->inpsf); + for (i = 3; i--; ) + for (j = 3; j--; ) { + d = tms->cmat[i][j] / tms->inpsf; + cd->cmatb[i][j] = 0x10000*d + (d<0. ? -.5 : .5); + } +} + + +static MEM_PTR +colrInit(tms) /* initialize private data for tone mapping */ +register TMstruct *tms; +{ + register COLRDATA *cd; + register int i; + /* allocate our data */ + cd = (COLRDATA *)malloc(sizeof(COLRDATA)); + if (cd == NULL) + return(NULL); + tms->pd[colrReg] = (MEM_PTR)cd; + /* compute gamma table */ + for (i = GAMTSZ; i--; ) + cd->gamb[i] = 256.*pow((i+.5)/GAMTSZ, 1./tms->mongam); + /* compute color and scale factors */ + colrNewSpace(tms); + return((MEM_PTR)cd); }