Back to index

radiance  4R0+20100331
rv3.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rv3.c,v 2.32 2009/12/12 00:03:42 greg Exp $";
00003 #endif
00004 /*
00005  *  rv3.c - miscellaneous routines for rview.
00006  *
00007  *  External symbols declared in rpaint.h
00008  */
00009 
00010 #include "copyright.h"
00011 
00012 #include <string.h>
00013 
00014 #include  "ray.h"
00015 #include  "rpaint.h"
00016 #include  "random.h"
00017 
00018 #ifndef WFLUSH
00019 #define WFLUSH              64            /* flush after this many primary rays */
00020 #endif
00021 #ifndef WFLUSH1
00022 #define WFLUSH1             512           /* or this many total rays */
00023 #endif
00024 
00025 
00026 #ifdef  SMLFLT
00027 #define  sscanvec(s,v)      (sscanf(s,"%f %f %f",v,v+1,v+2)==3)
00028 #else
00029 #define  sscanvec(s,v)      (sscanf(s,"%lf %lf %lf",v,v+1,v+2)==3)
00030 #endif
00031 
00032 static RNUMBER  niflush;           /* flushes since newimage() */
00033 
00034 int
00035 getrect(                           /* get a box */
00036        char  *s,
00037        RECT  *r
00038 )
00039 {
00040        int  x0, y0, x1, y1;
00041 
00042        if (*s && !strncmp(s, "all", strlen(s))) {
00043               r->l = r->d = 0;
00044               r->r = hresolu;
00045               r->u = vresolu;
00046               return(0);
00047        }
00048        if (sscanf(s, "%d %d %d %d", &x0, &y0, &x1, &y1) != 4) {
00049               if (dev->getcur == NULL)
00050                      return(-1);
00051               (*dev->comout)("Pick first corner\n");
00052               if ((*dev->getcur)(&x0, &y0) == ABORT)
00053                      return(-1);
00054               (*dev->comout)("Pick second corner\n");
00055               if ((*dev->getcur)(&x1, &y1) == ABORT)
00056                      return(-1);
00057        }
00058        if (x0 < x1) {
00059               r->l = x0;
00060               r->r = x1;
00061        } else {
00062               r->l = x1;
00063               r->r = x0;
00064        }
00065        if (y0 < y1) {
00066               r->d = y0;
00067               r->u = y1;
00068        } else {
00069               r->d = y1;
00070               r->u = y0;
00071        }
00072        if (r->l < 0) r->l = 0;
00073        if (r->d < 0) r->d = 0;
00074        if (r->r > hresolu) r->r = hresolu;
00075        if (r->u > vresolu) r->u = vresolu;
00076        if (r->l > r->r) r->l = r->r;
00077        if (r->d > r->u) r->d = r->u;
00078        return(0);
00079 }
00080 
00081 
00082 int
00083 getinterest(         /* get area of interest */
00084        char  *s,
00085        int  direc,
00086        FVECT  vec,
00087        double  *mp
00088 )
00089 {
00090        int  x, y;
00091        RAY  thisray;
00092        int  i;
00093 
00094        if (sscanf(s, "%lf", mp) != 1)
00095               *mp = 1.0;
00096        else if (*mp < -FTINY)             /* negative zoom is reduction */
00097               *mp = -1.0 / *mp;
00098        else if (*mp <= FTINY) {    /* too small */
00099               error(COMMAND, "illegal magnification");
00100               return(-1);
00101        }
00102        if (!sscanvec(sskip(s), vec)) {
00103               if (dev->getcur == NULL)
00104                      return(-1);
00105               (*dev->comout)("Pick view center\n");
00106               if ((*dev->getcur)(&x, &y) == ABORT)
00107                      return(-1);
00108               if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
00109                      &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) {
00110                      error(COMMAND, "not on image");
00111                      return(-1);
00112               }
00113               if (!direc || ourview.type == VT_PAR) {
00114                      rayorigin(&thisray, PRIMARY, NULL, NULL);
00115                      if (!localhit(&thisray, &thescene)) {
00116                             error(COMMAND, "not a local object");
00117                             return(-1);
00118                      }
00119               }
00120               if (direc)
00121                      if (ourview.type == VT_PAR)
00122                             for (i = 0; i < 3; i++)
00123                                    vec[i] = thisray.rop[i] - ourview.vp[i];
00124                      else
00125                             VCOPY(vec, thisray.rdir);
00126               else
00127                      VCOPY(vec, thisray.rop);
00128        } else if (direc) {
00129               for (i = 0; i < 3; i++)
00130                      vec[i] -= ourview.vp[i];
00131               if (normalize(vec) == 0.0) {
00132                      error(COMMAND, "point at view origin");
00133                      return(-1);
00134               }
00135        }
00136        return(0);
00137 }
00138 
00139 
00140 float *              /* keep consistent with COLOR typedef */
00141 greyof(                            /* convert color to greyscale */
00142        COLOR  col
00143 )
00144 {
00145        static COLOR  gcol;
00146        double  b;
00147 
00148        b = bright(col);
00149        setcolor(gcol, b, b, b);
00150        return(gcol);
00151 }
00152 
00153 static void
00154 recolor(                                  /* recolor the given node */
00155        PNODE *p
00156 )
00157 {
00158        while (p->kid != NULL) {           /* need to propogate down */
00159               int  mx = (p->xmin + p->xmax) >> 1;
00160               int  my = (p->ymin + p->ymax) >> 1;
00161               int  ki;
00162               if (p->x >= mx)
00163                      ki = (p->y >= my) ? UR : DR;
00164               else
00165                      ki = (p->y >= my) ? UL : DL;
00166               pcopy(p, p->kid+ki);
00167               p = p->kid + ki;
00168        }
00169 
00170        (*dev->paintr)(greyscale?greyof(p->v):p->v,
00171                      p->xmin, p->ymin, p->xmax, p->ymax);
00172 }
00173 
00174 int
00175 paint(               /* compute and paint a rectangle */
00176        PNODE  *p
00177 )
00178 {
00179        static RAY  thisray;
00180        double  h, v;
00181 
00182        if ((p->xmax <= p->xmin) | (p->ymax <= p->ymin)) {      /* empty */
00183               p->x = p->xmin;
00184               p->y = p->ymin;
00185               setcolor(p->v, 0.0, 0.0, 0.0);
00186               return(0);
00187        }
00188                                           /* jitter ray direction */
00189        p->x = h = p->xmin + (p->xmax-p->xmin)*frandom();
00190        p->y = v = p->ymin + (p->ymax-p->ymin)*frandom();
00191        
00192        if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview,
00193                      h/hresolu, v/vresolu)) < -FTINY) {
00194               setcolor(thisray.rcol, 0.0, 0.0, 0.0);
00195        } else if (nproc == 1) {           /* immediate mode */
00196               ray_trace(&thisray);
00197        } else {                           /* queuing mode */
00198               int    rval;
00199               rayorigin(&thisray, PRIMARY, NULL, NULL);
00200               thisray.rno = (RNUMBER)p;
00201               rval = ray_pqueue(&thisray);
00202               if (!rval)
00203                      return(0);
00204               if (rval < 0)
00205                      return(-1);
00206               p = (PNODE *)thisray.rno;
00207        }
00208 
00209        copycolor(p->v, thisray.rcol);
00210        scalecolor(p->v, exposure);
00211 
00212        recolor(p);                        /* paint it */
00213 
00214        if (dev->flush != NULL) {          /* shall we check for input? */
00215               static RNUMBER       lastflush = 0;
00216               RNUMBER              counter = raynum;
00217               int           flushintvl;
00218               if (nproc == 1) {
00219                      counter = nrays;
00220                      flushintvl = WFLUSH1;
00221               } else if (ambounce == 0)
00222                      flushintvl = nproc*WFLUSH;
00223               else if (niflush < WFLUSH)
00224                      flushintvl = nproc*niflush/(ambounce+1);
00225               else
00226                      flushintvl = nproc*WFLUSH/(ambounce+1);
00227               if (lastflush > counter)
00228                      lastflush = 0;              /* counter wrapped */
00229 
00230               if (counter - lastflush >= flushintvl) {
00231                      lastflush = counter;
00232                      (*dev->flush)();
00233                      niflush++;
00234               }
00235        }
00236        return(1);
00237 }
00238 
00239 
00240 int
00241 waitrays(void)                                   /* finish up pending rays */
00242 {
00243        int    nwaited = 0;
00244        int    rval;
00245        RAY    raydone;
00246 
00247        if (nproc <= 1)                           /* immediate mode? */
00248               return(0);
00249        while ((rval = ray_presult(&raydone, 0)) > 0) {
00250               PNODE  *p = (PNODE *)raydone.rno;
00251               copycolor(p->v, raydone.rcol);
00252               scalecolor(p->v, exposure);
00253               recolor(p);
00254               nwaited++;
00255        }
00256        if (rval < 0)
00257               return(-1);
00258        return(nwaited);
00259 }
00260 
00261 
00262 void
00263 newimage(                                 /* start a new image */
00264        char *s
00265 )
00266 {
00267        extern int    ray_pnprocs;
00268        int           newnp;
00269                                           /* change in nproc? */
00270        if (s != NULL && sscanf(s, "%d", &newnp) == 1 &&
00271                      (newnp > 0) & (newnp != nproc)) {
00272               if (!newparam) {
00273                      if (newnp == 1)
00274                             ray_pclose(0);
00275                      else if (newnp < ray_pnprocs)
00276                             ray_pclose(ray_pnprocs - newnp);
00277                      else
00278                             ray_popen(newnp - ray_pnprocs);
00279               }
00280               nproc = newnp;
00281        }
00282                                           /* free old image */
00283        freepkids(&ptrunk);
00284                                           /* compute resolution */
00285        hresolu = dev->xsiz;
00286        vresolu = dev->ysiz;
00287        normaspect(viewaspect(&ourview), &dev->pixaspect, &hresolu, &vresolu);
00288        ptrunk.xmin = ptrunk.ymin = pframe.l = pframe.d = 0;
00289        ptrunk.xmax = pframe.r = hresolu;
00290        ptrunk.ymax = pframe.u = vresolu;
00291        pdepth = 0;
00292                                           /* clear device */
00293        (*dev->clear)(hresolu, vresolu);
00294 
00295        if (newparam) {                           /* (re)start rendering procs */
00296               if (ray_pnprocs > 0)
00297                      ray_pclose(0);
00298               if (nproc > 1)
00299                      ray_popen(nproc);
00300               newparam = 0;
00301        }
00302        niflush = 0;                       /* get first value */
00303        paint(&ptrunk);
00304 }
00305 
00306 
00307 void
00308 redraw(void)                       /* redraw the image */
00309 {
00310        (*dev->clear)(hresolu, vresolu);
00311        (*dev->comout)("redrawing...\n");
00312        repaint(0, 0, hresolu, vresolu);
00313        (*dev->comout)("\n");
00314 }
00315 
00316 
00317 void
00318 repaint(                           /* repaint a region */
00319        int  xmin,
00320        int  ymin,
00321        int  xmax,
00322        int  ymax
00323 )
00324 {
00325        RECT  reg;
00326 
00327        reg.l = xmin; reg.r = xmax;
00328        reg.d = ymin; reg.u = ymax;
00329 
00330        paintrect(&ptrunk, &reg);
00331 }
00332 
00333 
00334 void
00335 paintrect(                         /* paint picture rectangle */
00336        PNODE  *p,
00337        RECT  *r
00338 )
00339 {
00340        int  mx, my;
00341 
00342        if (p->xmax - p->xmin <= 0 || p->ymax - p->ymin <= 0)
00343               return;
00344 
00345        if (p->kid == NULL) {
00346               (*dev->paintr)(greyscale?greyof(p->v):p->v,
00347                      p->xmin, p->ymin, p->xmax, p->ymax);      /* do this */
00348               return;
00349        }
00350        mx = (p->xmin + p->xmax) >> 1;                          /* do kids */
00351        my = (p->ymin + p->ymax) >> 1;
00352        if (mx > r->l) {
00353               if (my > r->d)
00354                      paintrect(p->kid+DL, r);
00355               if (my < r->u)
00356                      paintrect(p->kid+UL, r);
00357        }
00358        if (mx < r->r) {
00359               if (my > r->d)
00360                      paintrect(p->kid+DR, r);
00361               if (my < r->u)
00362                      paintrect(p->kid+UR, r);
00363        }
00364 }
00365 
00366 
00367 PNODE *
00368 findrect(                          /* find a rectangle */
00369        int  x,
00370        int  y,
00371        PNODE  *p,
00372        int  pd
00373 )
00374 {
00375        int  mx, my;
00376 
00377        while (p->kid != NULL && pd--) {
00378 
00379               mx = (p->xmin + p->xmax) >> 1;
00380               my = (p->ymin + p->ymax) >> 1;
00381 
00382               if (x < mx) {
00383                      if (y < my) {
00384                             p = p->kid+DL;
00385                      } else {
00386                             p = p->kid+UL;
00387                      }
00388               } else {
00389                      if (y < my) {
00390                             p = p->kid+DR;
00391                      } else {
00392                             p = p->kid+UR;
00393                      }
00394               }
00395        }
00396        return(p);
00397 }
00398 
00399 
00400 void
00401 compavg(                           /* recompute averages */
00402        PNODE  *p
00403 )
00404 {
00405        int    i, navg;
00406        
00407        if (p->kid == NULL)
00408               return;
00409 
00410        setcolor(p->v, .0, .0, .0);
00411        navg = 0;
00412        for (i = 0; i < 4; i++) {
00413               if (p->kid[i].xmin >= p->kid[i].xmax) continue;
00414               if (p->kid[i].ymin >= p->kid[i].ymax) continue;
00415               compavg(p->kid+i);
00416               addcolor(p->v, p->kid[i].v);
00417               navg++;
00418        }
00419        if (navg > 1)
00420               scalecolor(p->v, 1./navg);
00421 }
00422 
00423 
00424 void
00425 scalepict(                         /* scale picture values */
00426        PNODE  *p,
00427        double  sf
00428 )
00429 {
00430        scalecolor(p->v, sf);              /* do this node */
00431 
00432        if (p->kid == NULL)
00433               return;
00434                                    /* do children */
00435        scalepict(p->kid+DL, sf);
00436        scalepict(p->kid+DR, sf);
00437        scalepict(p->kid+UL, sf);
00438        scalepict(p->kid+UR, sf);
00439 }
00440 
00441 
00442 void
00443 getpictcolrs(                      /* get scanline from picture */
00444        int  yoff,
00445        COLR  *scan,
00446        PNODE  *p,
00447        int  xsiz,
00448        int  ysiz
00449 )
00450 {
00451        int  mx;
00452        int  my;
00453 
00454        if (p->kid == NULL) {                     /* do this node */
00455               setcolr(scan[0], colval(p->v,RED),
00456                             colval(p->v,GRN),
00457                             colval(p->v,BLU));
00458               for (mx = 1; mx < xsiz; mx++)
00459                      copycolr(scan[mx], scan[0]);
00460               return;
00461        }
00462                                           /* do kids */
00463        mx = xsiz >> 1;
00464        my = ysiz >> 1;
00465        if (yoff < my) {
00466               getpictcolrs(yoff, scan, p->kid+DL, mx, my);
00467               getpictcolrs(yoff, scan+mx, p->kid+DR, xsiz-mx, my);
00468        } else {
00469               getpictcolrs(yoff-my, scan, p->kid+UL, mx, ysiz-my);
00470               getpictcolrs(yoff-my, scan+mx, p->kid+UR, xsiz-mx, ysiz-my);
00471        }
00472 }
00473 
00474 
00475 void
00476 freepkids(                         /* free pnode's children */
00477        PNODE  *p
00478 )
00479 {
00480        if (p->kid == NULL)
00481               return;
00482        freepkids(p->kid+DL);
00483        freepkids(p->kid+DR);
00484        freepkids(p->kid+UL);
00485        freepkids(p->kid+UR);
00486        free((void *)p->kid);
00487        p->kid = NULL;
00488 }
00489 
00490 
00491 void
00492 newview(                                  /* change viewing parameters */
00493        VIEW  *vp
00494 )
00495 {
00496        char  *err;
00497 
00498        if ((err = setview(vp)) != NULL) {
00499               sprintf(errmsg, "view not set - %s", err);
00500               error(COMMAND, errmsg);
00501        } else if (memcmp((char *)vp, (char *)&ourview, sizeof(VIEW))) {
00502               oldview = ourview;
00503               ourview = *vp;
00504               newimage(NULL);
00505        }
00506 }
00507 
00508 
00509 void
00510 moveview(                                 /* move viewpoint */
00511        double  angle,
00512        double  elev,
00513        double  mag,
00514        FVECT  vc
00515 )
00516 {
00517        double  d;
00518        FVECT  v1;
00519        VIEW  nv = ourview;
00520        int  i;
00521 
00522        spinvector(nv.vdir, ourview.vdir, ourview.vup, angle*(PI/180.));
00523        if (elev != 0.0) {
00524               fcross(v1, ourview.vup, nv.vdir);
00525               normalize(v1);
00526               spinvector(nv.vdir, nv.vdir, v1, elev*(PI/180.));
00527        }
00528        if (nv.type == VT_PAR) {
00529               nv.horiz /= mag;
00530               nv.vert /= mag;
00531               d = 0.0;                    /* don't move closer */
00532               for (i = 0; i < 3; i++)
00533                      d += (vc[i] - ourview.vp[i])*ourview.vdir[i];
00534        } else {
00535               d = sqrt(dist2(ourview.vp, vc)) / mag;
00536               if (nv.vfore > FTINY) {
00537                      nv.vfore += d - d*mag;
00538                      if (nv.vfore < 0.0) nv.vfore = 0.0;
00539               }
00540               if (nv.vaft > FTINY) {
00541                      nv.vaft += d - d*mag;
00542                      if (nv.vaft <= nv.vfore) nv.vaft = 0.0;
00543               }
00544               nv.vdist /= mag;
00545        }
00546        for (i = 0; i < 3; i++)
00547               nv.vp[i] = vc[i] - d*nv.vdir[i];
00548        newview(&nv);
00549 }
00550 
00551 
00552 void
00553 pcopy(                             /* copy paint node p1 into p2 */
00554        PNODE  *p1,
00555        PNODE  *p2
00556 )
00557 {
00558        copycolor(p2->v, p1->v);
00559        p2->x = p1->x;
00560        p2->y = p1->y;
00561 }
00562 
00563 
00564 void
00565 zoomview(                          /* zoom in or out */
00566        VIEW  *vp,
00567        double  zf
00568 )
00569 {
00570        switch (vp->type) {
00571        case VT_PAR:                       /* parallel view */
00572               vp->horiz /= zf;
00573               vp->vert /= zf;
00574               return;
00575        case VT_ANG:                       /* angular fisheye */
00576               vp->horiz /= zf;
00577               if (vp->horiz > 360.)
00578                      vp->horiz = 360.;
00579               vp->vert /= zf;
00580               if (vp->vert > 360.)
00581                      vp->vert = 360.;
00582               return;
00583        case VT_PLS:                       /* planisphere fisheye */
00584               vp->horiz = sin((PI/180./2.)*vp->horiz) /
00585                             (1.0 + cos((PI/180./2.)*vp->horiz)) / zf;
00586               vp->horiz *= vp->horiz;
00587               vp->horiz = (2.*180./PI)*acos((1. - vp->horiz) /
00588                                           (1. + vp->horiz));
00589               vp->vert = sin((PI/180./2.)*vp->vert) /
00590                             (1.0 + cos((PI/180./2.)*vp->vert)) / zf;
00591               vp->vert *= vp->vert;
00592               vp->vert = (2.*180./PI)*acos((1. - vp->vert) /
00593                                           (1. + vp->vert));
00594               return;
00595        case VT_CYL:                       /* cylindrical panorama */
00596               vp->horiz /= zf;
00597               if (vp->horiz > 360.)
00598                      vp->horiz = 360.;
00599               vp->vert = atan(tan(vp->vert*(PI/180./2.))/zf) / (PI/180./2.);
00600               return;
00601        case VT_PER:                       /* perspective view */
00602               vp->horiz = atan(tan(vp->horiz*(PI/180./2.))/zf) /
00603                             (PI/180./2.);
00604               vp->vert = atan(tan(vp->vert*(PI/180./2.))/zf) /
00605                             (PI/180./2.);
00606               return;
00607        case VT_HEM:                       /* hemispherical fisheye */
00608               vp->horiz = sin(vp->horiz*(PI/180./2.))/zf;
00609               if (vp->horiz >= 1.0-FTINY)
00610                      vp->horiz = 180.;
00611               else
00612                      vp->horiz = asin(vp->horiz) / (PI/180./2.);
00613               vp->vert = sin(vp->vert*(PI/180./2.))/zf;
00614               if (vp->vert >= 1.0-FTINY)
00615                      vp->vert = 180.;
00616               else
00617                      vp->vert = asin(vp->vert) / (PI/180./2.);
00618               return;
00619        }
00620 }