--- ray/src/common/tmapcolrs.c 2004/10/23 18:55:52 3.16 +++ ray/src/common/tmapcolrs.c 2024/11/21 17:15:54 3.39 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: tmapcolrs.c,v 3.16 2004/10/23 18:55:52 schorsch Exp $"; +static const char RCSid[] = "$Id: tmapcolrs.c,v 3.39 2024/11/21 17:15:54 greg Exp $"; #endif /* * Routines for tone mapping on Radiance RGBE and XYZE pictures. @@ -9,29 +9,27 @@ static const char RCSid[] = "$Id: tmapcolrs.c,v 3.16 2 #include "copyright.h" -#include -#include +#include #include -#include +#ifdef PCOND +#include "paths.h" +#endif #include "tmprivat.h" +#include "rtio.h" #include "resolu.h" -#include "rtprocess.h" -#ifndef TM_PIC_CTRANS -#define TM_PIC_CTRANS 1 /* transform colors? (expensive) */ -#endif +#define GAMTSZ 4096 -#define GAMTSZ 1024 - typedef struct { - BYTE gamb[GAMTSZ]; /* gamma lookup table */ - COLR clfb; /* encoded tm->clf */ + uby8 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(struct tmStruct *); -static void colrNewSpace(struct tmStruct *); +static void * colrInit(TMstruct *); +static void colrNewSpace(TMstruct *); static gethfunc headline; static struct tmPackage colrPkg = { /* our package functions */ @@ -39,88 +37,103 @@ static struct tmPackage colrPkg = { /* our package fun }; static int colrReg = -1; /* our package registration number */ -#define LOGISZ 260 -static TMbright logi[LOGISZ]; +static TMbright logi[256]; int -tmCvColrs(ls, cs, scan, len) /* convert RGBE/XYZE colors */ -TMbright *ls; -BYTE *cs; -COLR *scan; -int len; +tmCvColrs( /* convert RGBE/XYZE colors */ +TMstruct *tms, +TMbright *ls, +uby8 *cs, +COLR *scan, +int len +) { - static char funcName[] = "tmCvColrs"; - COLR cmon; - register COLRDATA *cd; - register int i, bi, li; + static const char funcName[] = "tmCvColrs"; + int cmon[4]; + COLRDATA *cd; + int i, j, bi; + int32 li, vl; - if (tmTop == NULL) + if (tms == NULL) returnErr(TM_E_TMINVAL); if ((ls == NULL) | (scan == NULL) | (len < 0)) returnErr(TM_E_ILLEGAL); -#if TM_PIC_CTRANS - if (tmNeedMatrix(tmTop)) { /* need floating point */ -#else - if (tmTop->inppri == TM_XYZPRIM) { /* no way around this */ -#endif - 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 (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] = 0; tmMkMesofact(); } - if ((cd = (COLRDATA *)tmPkgData(tmTop,colrReg)) == NULL) + 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 */ + bi = 0; + 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/(int32)0x10000; + else if ((cmon[j] = vl>>16) > bi) + bi = cmon[j]; + } + cmon[EXP] = scan[i][EXP]; + while (bi >= 256) { /* handle overflow */ + cmon[EXP]++; + for (j = 3; j--; ) cmon[j] >>= 1; + bi >>= 1; + } + } else + copycolr(cmon, scan[i]); /* world luminance */ - li = ( cd->clfb[RED]*cmon[RED] + - cd->clfb[GRN]*cmon[GRN] + - cd->clfb[BLU]*cmon[BLU] ) >> 8; - bi = BRT2SCALE(cmon[EXP]-COLXS) + - logi[li] + cd->inpsfb; - if (li <= 0) { - bi = TM_NOBRT; /* bogus value */ - li = 1; /* avoid li==0 */ + li = cd->clfb[RED]*(int32)cmon[RED] + + cd->clfb[GRN]*(int32)cmon[GRN] + + cd->clfb[BLU]*(int32)cmon[BLU] ; + if (li >= 1L<<(12+8)) 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 = 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) { - cmon[RED] = cmon[GRN] = cmon[BLU] = li; + } else if (tms->flags & TM_F_BW) { + for (j = 3; j--; ) + cs[3*i+j] = tms->cdiv[j]/(TM_BRES>>8); + continue; + } else { + for (j = 3; j--; ) + cmon[j] *= (cmon[j] > 0); } - bi = ( (int32)GAMTSZ*cd->clfb[RED]*cmon[RED]/li ) >> 8; + bi = ( (uint32)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 ) >> 8; + bi = ( (uint32)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 ) >> 8; + bi = ( (uint32)GAMTSZ*cd->clfb[BLU]*cmon[BLU]/li ) >> 12; cs[3*i+2] = bi>=GAMTSZ ? 255 : cd->gamb[bi]; } returnOK; @@ -129,31 +142,36 @@ int len; #define FMTRGB 1 /* Input is RGBE */ #define FMTCIE 2 /* Input is CIE XYZE */ -#define FMTUNK 3 /* Input format is unspecified */ -#define FMTBAD 4 /* Input is not a recognized format */ +#define FMTSPEC 3 /* Input is N-component spectral data */ +#define FMTUNK 0 /* Input format is unspecified */ +#define FMTBAD (-1) /* Input is not a recognized format */ static struct radhead { int format; /* FMTRGB, FMTCIE, FMTUNK, FMTBAD */ double expos; /* input exposure value */ RGBPRIMP primp; /* input primaries */ RGBPRIMS mypri; /* custom primaries */ -} rhdefault = {FMTUNK, 1., stdprims, STDPRIMS}; + int ncs; /* number of color samples */ + float wpt[4]; /* spectral partition */ +} rhdefault = {FMTUNK, 1., stdprims, STDPRIMS, 3, {0,0,0,0}}; static int headline( /* grok a header line */ - register char *s, + char *s, void *vrh ) { - char fmt[32]; - register struct radhead *rh = vrh; + char fmt[MAXFMTLEN]; + struct radhead *rh = vrh; if (formatval(fmt, s)) { if (!strcmp(fmt, COLRFMT)) rh->format = FMTRGB; else if (!strcmp(fmt, CIEFMT)) rh->format = FMTCIE; + else if (!strcmp(fmt, SPECFMT)) + rh->format = FMTSPEC; else rh->format = FMTBAD; return(0); @@ -167,17 +185,28 @@ headline( /* grok a header line */ rh->primp = rh->mypri; return(0); } + if (isncomp(s)) { + rh->ncs = ncompval(s); + return(0); + } + if (iswlsplit(s)) { + wlsplitval(rh->wpt, s); + 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, +uby8 **cpp, +int *xp, +int *yp, +char *fname, +FILE *fp +) { char *funcName = fname==NULL ? "tmLoadPicture" : fname; FILE *inpf; @@ -186,13 +215,13 @@ 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))) 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; @@ -202,21 +231,28 @@ FILE *fp; fgetresolu(xp, yp, inpf) < 0) { err = TM_E_BADFILE; goto done; } - if (info.format == FMTUNK) /* assume RGBE format */ + if (info.format == FMTSPEC) { /* valid spectrum? */ + if (info.ncs <= 3) { + err = TM_E_BADFILE; goto done; + } + if (info.wpt[0] == 0) + memcpy(info.wpt, WLPART, sizeof(info.wpt)); + } else if (info.format == FMTUNK) /* assume RGBE format? */ info.format = FMTRGB; - if (info.format == FMTRGB) - info.expos /= WHTEFFICACY; - else if (info.format == FMTCIE) + + if (info.format == FMTCIE) info.primp = TM_XYZPRIM; + else + info.expos /= WHTEFFICACY; /* prepare library */ - if ((err = tmSetSpace(info.primp, 1./info.expos)) != TM_E_OK) + if ((err = tmSetSpace(tms, info.primp, 1./info.expos)) != TM_E_OK) goto done; err = TM_E_NOMEM; /* allocate arrays */ *lpp = (TMbright *)malloc(sizeof(TMbright) * *xp * *yp); if (*lpp == NULL) goto done; if (cpp != TM_NOCHROMP) { - *cpp = (BYTE *)malloc(3*sizeof(BYTE) * *xp * *yp); + *cpp = (uby8 *)malloc(3*sizeof(uby8) * *xp * *yp); if (*cpp == NULL) goto done; } @@ -225,10 +261,10 @@ FILE *fp; goto done; err = TM_E_BADFILE; /* read & convert scanlines */ for (i = 0; i < *yp; i++) { - if (freadcolrs(scanin, *xp, inpf) < 0) { + if (fread2colrs(scanin, *xp, inpf, info.ncs, info.wpt) < 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) @@ -238,12 +274,12 @@ done: /* clean up */ if (fp == NULL) fclose(inpf); if (scanin != NULL) - free((MEM_PTR)scanin); + free(scanin); if (err != TM_E_OK) { if (*lpp != NULL) - free((MEM_PTR)*lpp); + free(*lpp); if (cpp != TM_NOCHROMP && *cpp != NULL) - free((MEM_PTR)*cpp); + free(*cpp); returnErr(err); } returnOK; @@ -253,7 +289,7 @@ done: /* clean up */ #ifdef PCOND static int /* run pcond to map picture */ dopcond(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname) -BYTE **psp; +uby8 **psp; int *xp, *yp; int flags; RGBPRIMP monpri; @@ -261,12 +297,13 @@ double gamval, Lddyn, Ldmax; char *fname; { char *funcName = fname; + TMstruct *tms = NULL; char cmdbuf[1024]; FILE *infp; - register COLR *scan; - register BYTE *rp; + COLR *scan; + uby8 *rp; int y; - register int x; + int x; /* set up gamma correction */ if (setcolrcor(pow, 1./gamval) < 0) returnErr(TM_E_NOMEM); @@ -303,9 +340,9 @@ char *fname; /* allocate arrays */ scan = (COLR *)malloc(sizeof(COLR) * *xp); if (flags & TM_F_BW) - rp = (BYTE *)malloc(sizeof(BYTE) * *xp * *yp); + rp = (uby8 *)malloc(sizeof(uby8) * *xp * *yp); else - rp = (BYTE *)malloc(3*sizeof(BYTE) * *xp * *yp); + rp = (uby8 *)malloc(3*sizeof(uby8) * *xp * *yp); if (((*psp = rp) == NULL) | (scan == NULL)) { pclose(infp); returnErr(TM_E_NOMEM); @@ -314,8 +351,8 @@ char *fname; for (y = 0; y < *yp; y++) { if (freadcolrs(scan, *xp, infp) < 0) { pclose(infp); - free((MEM_PTR)scan); - free((MEM_PTR)*psp); + free(scan); + free(*psp); *psp = NULL; returnErr(TM_E_BADFILE); } @@ -330,7 +367,7 @@ char *fname; *rp++ = scan[x][BLU]; } } - free((MEM_PTR)scan); + free(scan); pclose(infp); returnOK; } @@ -339,7 +376,7 @@ char *fname; int /* map a Radiance picture */ tmMapPicture(psp, xp, yp, flags, monpri, gamval, Lddyn, Ldmax, fname, fp) -BYTE **psp; +uby8 **psp; int *xp, *yp; int flags; RGBPRIMP monpri; @@ -348,7 +385,8 @@ char *fname; FILE *fp; { char *funcName = fname==NULL ? "tmMapPicture" : fname; - BYTE *cp; + TMstruct *tms = NULL; + uby8 *cp; TMbright *lp; int err; /* check arguments */ @@ -367,41 +405,41 @@ FILE *fp; 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); + *psp = (uby8 *)malloc(sizeof(uby8) * *xp * *yp); if (*psp == NULL) { - free((MEM_PTR)lp); - tmDone(NULL); + free(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((MEM_PTR)lp); - tmDone(NULL); + free(lp); + tmDone(tms); if (err != TM_E_OK) { /* free memory on error */ - free((MEM_PTR)*psp); + free(*psp); *psp = NULL; returnErr(err); } @@ -411,36 +449,39 @@ done: /* clean up */ static void colrNewSpace(tms) /* color space changed for tone mapping */ -register struct tmStruct *tms; +TMstruct *tms; { - register COLRDATA *cd; + COLRDATA *cd; double d; + int i, j; cd = (COLRDATA *)tms->pd[colrReg]; - cd->clfb[RED] = 256.*tms->clf[RED] + .5; - cd->clfb[GRN] = 256.*tms->clf[GRN] + .5; - cd->clfb[BLU] = 256.*tms->clf[BLU] + .5; - cd->clfb[EXP] = COLXS; - d = TM_BRTSCALE*log(tms->inpsf); - cd->inpsfb = d<0. ? d-.5 : d+.5; + 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 +static void * colrInit(tms) /* initialize private data for tone mapping */ -register struct tmStruct *tms; +TMstruct *tms; { - register COLRDATA *cd; - register int i; + COLRDATA *cd; + int i; /* allocate our data */ cd = (COLRDATA *)malloc(sizeof(COLRDATA)); if (cd == NULL) return(NULL); - tms->pd[colrReg] = (MEM_PTR)cd; + tms->pd[colrReg] = (void *)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); + return((void *)cd); }