Back to index

radiance  4R0+20100331
glareval.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: glareval.c,v 2.12 2006/05/29 16:47:54 greg Exp $";
00003 #endif
00004 /*
00005  * Compute pixels for glare calculation
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include <stdlib.h>
00011 #include <string.h>
00012 
00013 #include "rtprocess.h" /* Windows: must come first because of conflicts */
00014 #include "glare.h"
00015 
00016                                    /* maximum rtrace buffer size */
00017 #define MAXPIX              (4096/(6*sizeof(float)))
00018 
00019 #define MAXSBUF             786432 /* maximum total size of scanline buffer */
00020 #define HSIZE        317    /* size of scanline hash table */
00021 #define NRETIRE             16     /* number of scanlines to retire at once */
00022 
00023 static SUBPROC       rt_pd = SP_INACTIVE; /* process id & descriptors for rtrace */
00024 
00025 FILE   *pictfp = NULL;             /* picture file pointer */
00026 double exposure;            /* picture exposure */
00027 int    pxsiz, pysiz;        /* picture dimensions */
00028 
00029 static int    curpos;              /* current scanline */
00030 static long   *scanpos;     /* scanline positions */
00031 
00032 typedef struct scan {
00033        int    y;            /* scanline position */
00034        long   lused;        /* for LRU replacement */
00035        struct scan   *next; /* next in this hash or free list */
00036        /* followed by the scanline data */
00037 } SCAN;                     /* buffered scanline */
00038 
00039 #define       scandata(sl)  ((COLR *)((sl)+1))
00040 #define shash(y)     ((y)%HSIZE)
00041 
00042 static int    maxpix;              /* maximum number of pixels to buffer */
00043 
00044 static SCAN   *freelist;           /* scanline free list */
00045 static SCAN   *hashtab[HSIZE];     /* scanline hash table */
00046 
00047 static long   scanbufsiz;          /* size of allocated scanline buffer */
00048 
00049 static long   ncall = 0L;   /* number of calls to getpictscan */
00050 static long   nread = 0L;   /* number of scanlines read */
00051 static long   nrecl = 0L;   /* number of scanlines reclaimed */
00052 
00053 static int    wrongformat = 0;
00054 
00055 static SCAN * claimscan(int y); 
00056 static COLR * getpictscan(int      y);
00057 static double pict_val(FVECT       vd);
00058 static void rt_compute(float       *pb, int      np);
00059 static gethfunc getexpos;
00060 static SCAN * scanretire(void);
00061 static void initscans(void);
00062 static void donescans(void);
00063 
00064 
00065 static SCAN *
00066 claimscan(                  /* claim scanline from buffers */
00067        int    y
00068 )
00069 {
00070        int    hi = shash(y);
00071        SCAN   *slast;
00072        register SCAN *sl;
00073 
00074        for (sl = hashtab[hi]; sl != NULL; sl = sl->next)
00075               if (sl->y == y)                           /* active scanline */
00076                      return(sl);
00077        for (slast = NULL, sl = freelist; sl != NULL; slast = sl, sl = sl->next)
00078               if (sl->y == -1 || sl->y == y || sl->next == NULL) {
00079                      if (slast == NULL)          /* remove from free */
00080                             freelist = sl->next;
00081                      else
00082                             slast->next = sl->next;
00083                      if (sl->y == y) {           /* reclaim */
00084                             sl->next = hashtab[hi];
00085                             hashtab[hi] = sl;
00086                             nrecl++;
00087                      }
00088                      return(sl);
00089               }
00090        return(scanretire());              /* need more free scanlines */
00091 }
00092 
00093 
00094 static COLR *
00095 getpictscan(                /* get picture scanline */
00096        int    y
00097 )
00098 {
00099        register SCAN *sl;
00100        register int  i;
00101                                    /* first check our buffers */
00102        sl = claimscan(y);
00103        if (sl == NULL)
00104               memerr("claimscan()");
00105        sl->lused = ncall++;
00106        if (sl->y == y)                    /* scan hit */
00107               return(scandata(sl));
00108                                    /* else read in replacement */
00109        if (scanpos[y] < 0) {                     /* need to search */
00110               for (i = y+1; i < curpos; i++)
00111                      if (scanpos[i] >= 0) {
00112                             if (fseek(pictfp, scanpos[i], 0) < 0)
00113                                    goto seekerr;
00114                             curpos = i;
00115                             break;
00116                      }
00117               while (curpos >= y) {
00118                      scanpos[curpos] = ftell(pictfp);
00119                      if (freadcolrs(scandata(sl), pxsiz, pictfp) < 0)
00120                             goto readerr;
00121                      nread++;
00122                      curpos--;
00123               }
00124        } else {
00125               if (curpos != y && fseek(pictfp, scanpos[y], 0) < 0)
00126                      goto seekerr;
00127               if (freadcolrs(scandata(sl), pxsiz, pictfp) < 0)
00128                      goto readerr;
00129               nread++;
00130               curpos = y-1;
00131        }
00132        sl->y = y;
00133        i = shash(y);               /* add to hash list */
00134        sl->next = hashtab[i];
00135        hashtab[i] = sl;
00136        return(scandata(sl));
00137 readerr:
00138        fprintf(stderr, "%s: picture read error\n", progname);
00139        exit(1);
00140 seekerr:
00141        fprintf(stderr, "%s: picture seek error\n", progname);
00142        exit(1);
00143 }
00144 
00145 
00146 #ifdef DEBUG
00147 void
00148 pict_stats(void)                   /* print out picture read statistics */
00149 {
00150        static long   lastcall = 0L;       /* ncall at last report */
00151        static long   lastread = 0L;       /* nread at last report */
00152        static long   lastrecl = 0L;       /* nrecl at last report */
00153 
00154        if (ncall == lastcall)
00155               return;
00156        fprintf(stderr, "%s: %ld scanlines read (%ld reclaimed) in %ld calls\n",
00157               progname, nread-lastread, nrecl-lastrecl, ncall-lastcall);
00158        lastcall = ncall;
00159        lastread = nread;
00160        lastrecl = nrecl;
00161 }
00162 #endif
00163 
00164 
00165 static double
00166 pict_val(                   /* find picture value for view direction */
00167        FVECT  vd
00168 )
00169 {
00170        FVECT  pp;
00171        FVECT  ip;
00172        COLOR  res;
00173 
00174        if (pictfp == NULL)
00175               return(-1.0);
00176        pp[0] = pictview.vp[0] + vd[0];
00177        pp[1] = pictview.vp[1] + vd[1];
00178        pp[2] = pictview.vp[2] + vd[2];
00179        viewloc(ip, &pictview, pp);
00180        if (ip[2] <= FTINY || ip[0] < 0. || ip[0] >= 1. ||
00181                      ip[1] < 0. || ip[1] >= 1.)
00182               return(-1.0);
00183        colr_color(res, getpictscan((int)(ip[1]*pysiz))[(int)(ip[0]*pxsiz)]);
00184        return(luminance(res)/exposure);
00185 }
00186 
00187 
00188 extern double
00189 getviewpix(          /* compute single view pixel */
00190        int    vh,
00191        int    vv
00192 )
00193 {
00194        FVECT  dir;
00195        float  rt_buf[12];
00196        double res;
00197 
00198        if (compdir(dir, vh, vv) < 0)
00199               return(-1.0);
00200        npixinvw++;
00201        if ((res = pict_val(dir)) >= 0.0)
00202               return(res);
00203        if (rt_pd.r == -1) {
00204               npixmiss++;
00205               return(-1.0);
00206        }
00207        rt_buf[0] = ourview.vp[0];
00208        rt_buf[1] = ourview.vp[1];
00209        rt_buf[2] = ourview.vp[2];
00210        rt_buf[3] = dir[0];
00211        rt_buf[4] = dir[1];
00212        rt_buf[5] = dir[2];
00213        rt_compute(rt_buf, 1);
00214        return(luminance(rt_buf));
00215 }
00216 
00217 
00218 extern void
00219 getviewspan(         /* compute a span of view pixels */
00220        int    vv,
00221        float  *vb
00222 )
00223 {
00224        float  rt_buf[6*MAXPIX];    /* rtrace send/receive buffer */
00225        register int  n;            /* number of pixels in buffer */
00226        short  buf_vh[MAXPIX];             /* pixel positions */
00227        FVECT  dir;
00228        register int  vh;
00229 
00230 #ifdef DEBUG
00231        if (verbose)
00232               fprintf(stderr, "%s: computing view span at %d...\n",
00233                             progname, vv);
00234 #endif
00235        n = 0;
00236        for (vh = -hsize; vh <= hsize; vh++) {
00237               if (compdir(dir, vh, vv) < 0) {           /* not in view */
00238                      vb[vh+hsize] = -1.0;
00239                      continue;
00240               }
00241               npixinvw++;
00242               if ((vb[vh+hsize] = pict_val(dir)) >= 0.0)
00243                      continue;
00244               if (rt_pd.r == -1) {        /* missing information */
00245                      npixmiss++;
00246                      continue;
00247               }
00248                                           /* send to rtrace */
00249               if (n >= maxpix) {                 /* flush */
00250                      rt_compute(rt_buf, n);
00251                      while (n-- > 0)
00252                             vb[buf_vh[n]+hsize] = luminance(rt_buf+3*n);
00253               }
00254               rt_buf[6*n] = ourview.vp[0];
00255               rt_buf[6*n+1] = ourview.vp[1];
00256               rt_buf[6*n+2] = ourview.vp[2];
00257               rt_buf[6*n+3] = dir[0];
00258               rt_buf[6*n+4] = dir[1];
00259               rt_buf[6*n+5] = dir[2];
00260               buf_vh[n++] = vh;
00261        }
00262 #ifdef DEBUG
00263        if (verbose)
00264               pict_stats();
00265 #endif
00266        if (n > 0) {                       /* process pending buffer */
00267               rt_compute(rt_buf, n);
00268               while (n-- > 0)
00269                      vb[buf_vh[n]+hsize] = luminance(rt_buf+3*n);
00270        }
00271 }
00272 
00273 
00274 static void
00275 rt_compute(          /* process buffer through rtrace */
00276        float  *pb,
00277        int    np
00278 )
00279 {
00280 #ifdef DEBUG
00281        if (verbose && np > 1)
00282               fprintf(stderr, "%s: sending %d samples to rtrace...\n",
00283                             progname, np);
00284 #endif
00285        memset(pb+6*np, '\0', 6*sizeof(float));
00286        if (process(&rt_pd, (char *)pb, (char *)pb, 3*sizeof(float)*(np+1),
00287                      6*sizeof(float)*(np+1)) < 3*sizeof(float)*(np+1)) {
00288               fprintf(stderr, "%s: rtrace communication error\n",
00289                             progname);
00290               exit(1);
00291        }
00292 }
00293 
00294 
00295 static int
00296 getexpos(                   /* get exposure from header line */
00297        char   *s,
00298        void   *p
00299 )
00300 {
00301        char   fmt[32];
00302 
00303        if (isexpos(s))
00304               exposure *= exposval(s);
00305        else if (isformat(s)) {
00306               formatval(fmt, s);
00307               wrongformat = strcmp(fmt, COLRFMT);
00308        }
00309        return(0);
00310 }
00311 
00312 
00313 extern void
00314 open_pict(                  /* open picture file */
00315        char   *fn
00316 )
00317 {
00318        if ((pictfp = fopen(fn, "r")) == NULL) {
00319               fprintf(stderr, "%s: cannot open\n", fn);
00320               exit(1);
00321        }
00322        exposure = 1.0;
00323        getheader(pictfp, getexpos, NULL);
00324        if (wrongformat || !fscnresolu(&pxsiz, &pysiz, pictfp)) {
00325               fprintf(stderr, "%s: incompatible picture format\n", fn);
00326               exit(1);
00327        }
00328        initscans();
00329 }
00330 
00331 
00332 extern void
00333 close_pict(void)                   /* done with picture */
00334 {
00335        if (pictfp == NULL)
00336               return;
00337        fclose(pictfp);
00338        donescans();
00339        pictfp = NULL;
00340 }
00341 
00342 
00343 extern void
00344 fork_rtrace(                /* open pipe and start rtrace */
00345        char   *av[]
00346 )
00347 {
00348        int    rval;
00349 
00350        rval = open_process(&rt_pd, av);
00351        if (rval < 0) {
00352               perror(progname);
00353               exit(1);
00354        }
00355        if (rval == 0) {
00356               fprintf(stderr, "%s: command not found\n", av[0]);
00357               exit(1);
00358        }
00359        maxpix = rval/(6*sizeof(float));
00360        if (maxpix > MAXPIX)
00361               maxpix = MAXPIX;
00362        maxpix--;
00363 }
00364 
00365 
00366 extern void
00367 done_rtrace(void)                  /* wait for rtrace to finish */
00368 {
00369        int    status;
00370 
00371        status = close_process(&rt_pd);
00372        if (status > 0) {
00373               fprintf(stderr, "%s: bad status (%d) from rtrace\n",
00374                             progname, status);
00375               exit(1);
00376        }
00377        rt_pd.r = -1;
00378 }
00379 
00380 
00381 static SCAN *
00382 scanretire(void)                   /* retire old scanlines to free list */
00383 {
00384        SCAN   *sold[NRETIRE];
00385        int    n;
00386        int    h;
00387        register SCAN *sl;
00388        register int  i;
00389                                    /* grab the NRETIRE oldest scanlines */
00390        sold[n = 0] = NULL;
00391        for (h = 0; h < HSIZE; h++)
00392               for (sl = hashtab[h]; sl != NULL; sl = sl->next) {
00393                      for (i = n; i && sold[i-1]->lused > sl->lused; i--)
00394                             if (i < NRETIRE)
00395                                    sold[i] = sold[i-1];
00396                      if (i < NRETIRE) {
00397                             sold[i] = sl;
00398                             if (n < NRETIRE)     /* grow list */
00399                                    n++;
00400                      }
00401               }
00402                                    /* put scanlines into free list */
00403        for (i = 0; i < n; i++) {
00404               h = shash(sold[i]->y);
00405               sl = hashtab[h];
00406               if (sl == sold[i])
00407                      hashtab[h] = sl->next;
00408               else {
00409                      while (sl->next != sold[i]) /* IS in list */
00410                             sl = sl->next;
00411                      sl->next = sold[i]->next;
00412               }
00413               if (i > 0) {         /* save oldest as return value */
00414                      sold[i]->next = freelist;
00415                      freelist = sold[i];
00416               }
00417        }
00418        return(sold[0]);
00419 }
00420 
00421 
00422 static char   *scan_buf;
00423 
00424 
00425 static void
00426 initscans(void)                           /* initialize scanline buffers */
00427 {
00428        int    scansize;
00429        register SCAN *ptr;
00430        register int  i;
00431                                    /* initialize positions */
00432        scanpos = (long *)bmalloc(pysiz*sizeof(long));
00433        if (scanpos == NULL)
00434               memerr("scanline positions");
00435        for (i = pysiz-1; i >= 0; i--)
00436               scanpos[i] = -1L;
00437        curpos = pysiz-1;
00438                                    /* clear hash table */
00439        for (i = 0; i < HSIZE; i++)
00440               hashtab[i] = NULL;
00441                                    /* allocate scanline buffers */
00442        scansize = sizeof(SCAN) + pxsiz*sizeof(COLR);
00443 #ifdef ALIGNT
00444        scansize = scansize+(sizeof(ALIGNT)-1) & ~(sizeof(ALIGNT)-1);
00445 #endif
00446        i = MAXSBUF / scansize;            /* compute number to allocate */
00447        if (i > HSIZE)
00448               i = HSIZE;
00449        scanbufsiz = i*scansize;
00450        scan_buf = bmalloc(scanbufsiz);    /* get in one big chunk */
00451        if (scan_buf == NULL)
00452               memerr("scanline buffers");
00453        ptr = (SCAN *)scan_buf;
00454        freelist = NULL;            /* build our free list */
00455        while (i-- > 0) {
00456               ptr->y = -1;
00457               ptr->lused = -1;
00458               ptr->next = freelist;
00459               freelist = ptr;
00460               ptr = (SCAN *)((char *)ptr + scansize);   /* beware of C bugs */
00461        }
00462 }
00463 
00464 
00465 static void
00466 donescans(void)                           /* free up scanlines */
00467 {
00468        bfree(scan_buf, scanbufsiz);
00469        bfree((char *)scanpos, pysiz*sizeof(long));
00470 }