Back to index

radiance  4R0+20100331
rv2.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rv2.c,v 2.59 2009/01/14 20:27:00 greg Exp $";
00003 #endif
00004 /*
00005  *  rv2.c - command routines used in tracing a view.
00006  *
00007  *  External symbols declared in rpaint.h
00008  */
00009 
00010 #include "copyright.h"
00011 
00012 #include  <ctype.h>
00013 #include  <string.h>
00014 
00015 #include  "platform.h"
00016 #include  "ray.h"
00017 #include  "source.h"
00018 #include  "ambient.h"
00019 #include  "otypes.h"
00020 #include  "rpaint.h"
00021 
00022 extern int  psample;               /* pixel sample size */
00023 extern double  maxdiff;                   /* max. sample difference */
00024 
00025 #define  CTRL(c)     ((c)-'@')
00026 
00027 #ifdef  SMLFLT
00028 #define  sscanvec(s,v)      (sscanf(s,"%f %f %f",v,v+1,v+2)==3)
00029 #else
00030 #define  sscanvec(s,v)      (sscanf(s,"%lf %lf %lf",v,v+1,v+2)==3)
00031 #endif
00032 
00033 extern char  rifname[128];         /* rad input file name */
00034 
00035 extern char  *progname;
00036 extern char  *octname;
00037 
00038 
00039 void
00040 getframe(                          /* get a new frame */
00041        char  *s
00042 )
00043 {
00044        if (getrect(s, &pframe) < 0)
00045               return;
00046        pdepth = 0;
00047 }
00048 
00049 
00050 void
00051 getrepaint(                        /* get area and repaint */
00052        char  *s
00053 )
00054 {
00055        RECT  box;
00056 
00057        if (getrect(s, &box) < 0)
00058               return;
00059        paintrect(&ptrunk, &box);
00060 }
00061 
00062 
00063 void
00064 getview(                           /* get/show view parameters */
00065        char  *s
00066 )
00067 {
00068        FILE  *fp;
00069        char  buf[128];
00070        char  *fname;
00071        int  change = 0;
00072        VIEW  nv = ourview;
00073 
00074        while (isspace(*s))
00075               s++;
00076        if (*s == '-') {                   /* command line parameters */
00077               if (sscanview(&nv, s))
00078                      newview(&nv);
00079               else
00080                      error(COMMAND, "bad view option(s)");
00081               return;
00082        }
00083        if (sscanf(s, "%s", buf) == 1) {   /* write parameters to a file */
00084               if ((fname = getpath(buf, NULL, 0)) == NULL ||
00085                             (fp = fopen(fname, "a")) == NULL) {
00086                      sprintf(errmsg, "cannot open \"%s\"", buf);
00087                      error(COMMAND, errmsg);
00088                      return;
00089               }
00090               fputs(progname, fp);
00091               fprintview(&ourview, fp);
00092               fputs(sskip(s), fp);
00093               putc('\n', fp);
00094               fclose(fp);
00095               return;
00096        }
00097        sprintf(buf, "view type (%c): ", ourview.type);
00098        (*dev->comout)(buf);
00099        (*dev->comin)(buf, NULL);
00100        if (buf[0] == CTRL('C')) return;
00101        if (buf[0] && buf[0] != ourview.type) {
00102               nv.type = buf[0];
00103               change++;
00104        }
00105        sprintf(buf, "view point (%.6g %.6g %.6g): ",
00106                      ourview.vp[0], ourview.vp[1], ourview.vp[2]);
00107        (*dev->comout)(buf);
00108        (*dev->comin)(buf, NULL);
00109        if (buf[0] == CTRL('C')) return;
00110        if (sscanvec(buf, nv.vp))
00111               change++;
00112        sprintf(buf, "view direction (%.6g %.6g %.6g): ",
00113                      ourview.vdir[0]*ourview.vdist,
00114                      ourview.vdir[1]*ourview.vdist,
00115                      ourview.vdir[2]*ourview.vdist);
00116        (*dev->comout)(buf);
00117        (*dev->comin)(buf, NULL);
00118        if (buf[0] == CTRL('C')) return;
00119        if (sscanvec(buf, nv.vdir)) {
00120               nv.vdist = 1.;
00121               change++;
00122        }
00123        sprintf(buf, "view up (%.6g %.6g %.6g): ",
00124                      ourview.vup[0], ourview.vup[1], ourview.vup[2]);
00125        (*dev->comout)(buf);
00126        (*dev->comin)(buf, NULL);
00127        if (buf[0] == CTRL('C')) return;
00128        if (sscanvec(buf, nv.vup))
00129               change++;
00130        sprintf(buf, "view horiz and vert size (%.6g %.6g): ",
00131                      ourview.horiz, ourview.vert);
00132        (*dev->comout)(buf);
00133        (*dev->comin)(buf, NULL);
00134        if (buf[0] == CTRL('C')) return;
00135        if (sscanf(buf, "%lf %lf", &nv.horiz, &nv.vert) == 2)
00136               change++;
00137        sprintf(buf, "fore and aft clipping plane (%.6g %.6g): ",
00138                      ourview.vfore, ourview.vaft);
00139        (*dev->comout)(buf);
00140        (*dev->comin)(buf, NULL);
00141        if (buf[0] == CTRL('C')) return;
00142        if (sscanf(buf, "%lf %lf", &nv.vfore, &nv.vaft) == 2)
00143               change++;
00144        sprintf(buf, "view shift and lift (%.6g %.6g): ",
00145                      ourview.hoff, ourview.voff);
00146        (*dev->comout)(buf);
00147        (*dev->comin)(buf, NULL);
00148        if (buf[0] == CTRL('C')) return;
00149        if (sscanf(buf, "%lf %lf", &nv.hoff, &nv.voff) == 2)
00150               change++;
00151        if (change)
00152               newview(&nv);
00153 }
00154 
00155 
00156 void
00157 lastview(                          /* return to a previous view */
00158        char  *s
00159 )
00160 {
00161        char  buf[128];
00162        char  *fname;
00163        int  success;
00164        VIEW  nv;
00165 
00166        if (sscanf(s, "%s", buf) == 1) {   /* get parameters from a file */
00167               nv = stdview;
00168               if ((fname = getpath(buf, "", R_OK)) == NULL ||
00169                             (success = viewfile(fname, &nv, NULL)) == -1) {
00170                      sprintf(errmsg, "cannot open \"%s\"", buf);
00171                      error(COMMAND, errmsg);
00172                      return;
00173               }
00174               if (!success)
00175                      error(COMMAND, "wrong file format");
00176               else
00177                      newview(&nv);
00178               return;
00179        }
00180        if (oldview.type == 0) {    /* no old view! */
00181               error(COMMAND, "no previous view");
00182               return;
00183        }
00184        nv = ourview;
00185        ourview = oldview;
00186        oldview = nv;
00187        newimage(NULL);
00188 }
00189 
00190 
00191 void
00192 saveview(                          /* save view to rad file */
00193        char  *s
00194 )
00195 {
00196        char  view[64];
00197        char  *fname;
00198        FILE  *fp;
00199 
00200        if (*atos(view, sizeof(view), s)) {
00201               if (isint(view)) {
00202                      error(COMMAND, "cannot write view by number");
00203                      return;
00204               }
00205               s = sskip(s);
00206        }
00207        while (isspace(*s))
00208               s++;
00209        if (*s)
00210               atos(rifname, sizeof(rifname), s);
00211        else if (rifname[0] == '\0') {
00212               error(COMMAND, "no previous rad file");
00213               return;
00214        }
00215        if ((fname = getpath(rifname, NULL, 0)) == NULL ||
00216                      (fp = fopen(fname, "a")) == NULL) {
00217               sprintf(errmsg, "cannot open \"%s\"", rifname);
00218               error(COMMAND, errmsg);
00219               return;
00220        }
00221        fputs("view= ", fp);
00222        fputs(view, fp);
00223        fprintview(&ourview, fp);
00224        putc('\n', fp);
00225        fclose(fp);
00226 }
00227 
00228 
00229 void
00230 loadview(                          /* load view from rad file */
00231        char  *s
00232 )
00233 {
00234        char  buf[512];
00235        char  *fname;
00236        FILE  *fp;
00237        VIEW  nv;
00238 
00239        strcpy(buf, "rad -n -s -V -v ");
00240        if (sscanf(s, "%s", buf+strlen(buf)) == 1)
00241               s = sskip(s);
00242        else
00243               strcat(buf, "1");
00244        if (*s)
00245               atos(rifname, sizeof(rifname), s);
00246        else if (rifname[0] == '\0') {
00247               error(COMMAND, "no previous rad file");
00248               return;
00249        }
00250        if ((fname = getpath(rifname, "", R_OK)) == NULL) {
00251               sprintf(errmsg, "cannot access \"%s\"", rifname);
00252               error(COMMAND, errmsg);
00253               return;
00254        }
00255        sprintf(buf+strlen(buf), " %s", fname);
00256        if ((fp = popen(buf, "r")) == NULL) {
00257               error(COMMAND, "cannot run rad");
00258               return;
00259        }
00260        buf[0] = '\0';
00261        fgets(buf, sizeof(buf), fp);
00262        pclose(fp);
00263        nv = stdview;
00264        if (!sscanview(&nv, buf)) {
00265               error(COMMAND, "rad error -- no such view?");
00266               return;
00267        }
00268        newview(&nv);
00269 }
00270 
00271 
00272 void
00273 getaim(                            /* aim camera */
00274        char  *s
00275 )
00276 {
00277        VIEW  nv = ourview;
00278        double  zfact;
00279 
00280        if (getinterest(s, 1, nv.vdir, &zfact) < 0)
00281               return;
00282        zoomview(&nv, zfact);
00283        newview(&nv);
00284 }
00285 
00286 
00287 void
00288 getfocus(                          /* set focus distance */
00289        char *s
00290 )
00291 {
00292        char  buf[64];
00293        double dist;
00294 
00295        if (sscanf(s, "%lf", &dist) < 1) {
00296               int    x, y;
00297               RAY    thisray;
00298               if (dev->getcur == NULL)
00299                      return;
00300               (*dev->comout)("Pick focus point\n");
00301               if ((*dev->getcur)(&x, &y) == ABORT)
00302                      return;
00303               if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
00304                      &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) {
00305                      error(COMMAND, "not on image");
00306                      return;
00307               }
00308               rayorigin(&thisray, PRIMARY, NULL, NULL);
00309               if (!localhit(&thisray, &thescene)) {
00310                      error(COMMAND, "not a local object");
00311                      return;
00312               }
00313               dist = thisray.rot;
00314        } else if (dist <= .0) {
00315               error(COMMAND, "focus distance must be positive");
00316               return;
00317        }
00318        ourview.vdist = dist;
00319        sprintf(buf, "Focus distance set to %f\n", dist);
00320        (*dev->comout)(buf);
00321 }
00322 
00323 
00324 void
00325 getmove(                           /* move camera */
00326        char  *s
00327 )
00328 {
00329        FVECT  vc;
00330        double  mag;
00331 
00332        if (getinterest(s, 0, vc, &mag) < 0)
00333               return;
00334        moveview(0.0, 0.0, mag, vc);
00335 }
00336 
00337 
00338 void
00339 getrotate(                         /* rotate camera */
00340        char  *s
00341 )
00342 {
00343        VIEW  nv = ourview;
00344        FVECT  v1;
00345        double  angle, elev, zfact;
00346        
00347        elev = 0.0; zfact = 1.0;
00348        if (sscanf(s, "%lf %lf %lf", &angle, &elev, &zfact) < 1) {
00349               error(COMMAND, "missing angle");
00350               return;
00351        }
00352        spinvector(nv.vdir, ourview.vdir, ourview.vup, angle*(PI/180.));
00353        if (elev != 0.0) {
00354               fcross(v1, nv.vdir, ourview.vup);
00355               normalize(v1);
00356               spinvector(nv.vdir, nv.vdir, v1, elev*(PI/180.));
00357        }
00358        zoomview(&nv, zfact);
00359        newview(&nv);
00360 }
00361 
00362 
00363 void
00364 getpivot(                          /* pivot viewpoint */
00365        char  *s
00366 )
00367 {
00368        FVECT  vc;
00369        double  angle, elev, mag;
00370 
00371        elev = 0.0;
00372        if (sscanf(s, "%lf %lf", &angle, &elev) < 1) {
00373               error(COMMAND, "missing angle");
00374               return;
00375        }
00376        if (getinterest(sskip2(s,2), 0, vc, &mag) < 0)
00377               return;
00378        moveview(angle, elev, mag, vc);
00379 }
00380 
00381 
00382 void
00383 getexposure(                       /* get new exposure */
00384        char  *s
00385 )
00386 {
00387        char  buf[128];
00388        char  *cp;
00389        int  x, y;
00390        PNODE  *p = &ptrunk;
00391        int  adapt = 0;
00392        double  e = 1.0;
00393 
00394        for (cp = s; isspace(*cp); cp++)
00395               ;
00396        if (*cp == '@') {
00397               adapt++;
00398               while (isspace(*++cp))
00399                      ;
00400        }
00401        if (*cp == '\0') {          /* normalize to point */
00402               if (dev->getcur == NULL)
00403                      return;
00404               (*dev->comout)("Pick point for exposure\n");
00405               if ((*dev->getcur)(&x, &y) == ABORT)
00406                      return;
00407               p = findrect(x, y, &ptrunk, -1);
00408        } else {
00409               if (*cp == '=') {    /* absolute setting */
00410                      p = NULL;
00411                      e = 1.0/exposure;
00412                      for (cp++; isspace(*cp); cp++)
00413                             ;
00414                      if (*cp == '\0') {   /* interactive */
00415                             sprintf(buf, "exposure (%f): ", exposure);
00416                             (*dev->comout)(buf);
00417                             (*dev->comin)(buf, NULL);
00418                             for (cp = buf; isspace(*cp); cp++)
00419                                    ;
00420                             if (*cp == '\0')
00421                                    return;
00422                      }
00423               }
00424               if (*cp == '+' || *cp == '-')      /* f-stops */
00425                      e *= pow(2.0, atof(cp));
00426               else                        /* multiplier */
00427                      e *= atof(cp);
00428        }
00429        if (p != NULL) {            /* relative setting */
00430               compavg(p);
00431               if (bright(p->v) < 1e-15) {
00432                      error(COMMAND, "cannot normalize to zero");
00433                      return;
00434               }
00435               if (adapt)
00436                      e *= 106./pow(1.219+pow(luminance(p->v)/exposure,.4),2.5)/exposure;
00437               else
00438                      e *= 0.5 / bright(p->v);
00439        }
00440        if (e <= FTINY || fabs(1.0 - e) <= FTINY)
00441               return;
00442        scalepict(&ptrunk, e);
00443        exposure *= e;
00444        redraw();
00445 }
00446 
00447 typedef union {int i; double d; COLOR C;} *MyUptr;
00448 #define  FEQ(x,y)     (fabs((x)-(y)) <= FTINY)
00449 
00450 int
00451 getparam(            /* get variable from user */
00452        char  *str,
00453        char  *dsc,
00454        int  typ,
00455        void  *p
00456 )
00457 {
00458        MyUptr  ptr = (MyUptr)p;
00459        int  i0;
00460        double  d0, d1, d2;
00461        char  buf[48];
00462 
00463        switch (typ) {
00464        case 'i':                   /* integer */
00465               if (sscanf(str, "%d", &i0) != 1) {
00466                      (*dev->comout)(dsc);
00467                      sprintf(buf, " (%d): ", ptr->i);
00468                      (*dev->comout)(buf);
00469                      (*dev->comin)(buf, NULL);
00470                      if (sscanf(buf, "%d", &i0) != 1)
00471                             return(0);
00472               }
00473               if (ptr->i == i0)
00474                      return(0);
00475               ptr->i = i0;
00476               break;
00477        case 'r':                   /* real */
00478               if (sscanf(str, "%lf", &d0) != 1) {
00479                      (*dev->comout)(dsc);
00480                      sprintf(buf, " (%.6g): ", ptr->d);
00481                      (*dev->comout)(buf);
00482                      (*dev->comin)(buf, NULL);
00483                      if (sscanf(buf, "%lf", &d0) != 1)
00484                             return(0);
00485               }
00486               if (FEQ(ptr->d, d0))
00487                      return(0);
00488               ptr->d = d0;
00489               break;
00490        case 'b':                   /* boolean */
00491               if (sscanf(str, "%1s", buf) != 1) {
00492                      (*dev->comout)(dsc);
00493                      sprintf(buf, "? (%c): ", ptr->i ? 'y' : 'n');
00494                      (*dev->comout)(buf);
00495                      (*dev->comin)(buf, NULL);
00496                      if (buf[0] == '\0')
00497                             return(0);
00498               }
00499               if (strchr("yY+1tTnN-0fF", buf[0]) == NULL)
00500                      return(0);
00501               i0 = strchr("yY+1tT", buf[0]) != NULL;
00502               if (ptr->i == i0)
00503                      return(0);
00504               ptr->i = i0;
00505               break;
00506        case 'C':                   /* color */
00507               if (sscanf(str, "%lf %lf %lf", &d0, &d1, &d2) != 3) {
00508                      (*dev->comout)(dsc);
00509                      sprintf(buf, " (%.6g %.6g %.6g): ",
00510                                    colval(ptr->C,RED),
00511                                    colval(ptr->C,GRN),
00512                                    colval(ptr->C,BLU));
00513                      (*dev->comout)(buf);
00514                      (*dev->comin)(buf, NULL);
00515                      if (sscanf(buf, "%lf %lf %lf", &d0, &d1, &d2) != 3)
00516                             return(0);
00517               }
00518               if (FEQ(colval(ptr->C,RED), d0) &&
00519                             FEQ(colval(ptr->C,GRN), d1) &&
00520                             FEQ(colval(ptr->C,BLU), d2))
00521                      return(0);
00522               setcolor(ptr->C, d0, d1, d2);
00523               break;
00524        default:
00525               return(0);           /* shouldn't happen */
00526        }
00527        newparam++;
00528        return(1);
00529 }
00530 
00531 
00532 void
00533 setparam(                          /* get/set program parameter */
00534        char  *s
00535 )
00536 {
00537        int  prev_newp = newparam;
00538        char  buf[128];
00539        
00540        if (s[0] == '\0') {
00541               (*dev->comout)(
00542               "aa ab ad ar as av aw b bv dc dv dj ds dt i lr lw me ma mg ms ps pt sj st u: ");
00543               (*dev->comin)(buf, NULL);
00544               s = buf;
00545        }
00546        switch (s[0]) {
00547        case 'u':                   /* uncorrelated sampling */
00548               getparam(s+1, "uncorrelated sampling", 'b',
00549                             (void *)&rand_samp);
00550               break;
00551        case 'l':                   /* limit */
00552               switch (s[1]) {
00553               case 'w':                   /* weight */
00554                      getparam(s+2, "limit weight", 'r',
00555                                    (void *)&minweight);
00556                      break;
00557               case 'r':                   /* reflection */
00558                      getparam(s+2, "limit reflection", 'i',
00559                                    (void *)&maxdepth);
00560                      break;
00561               default:
00562                      goto badparam;
00563               }
00564               break;
00565        case 'd':                   /* direct */
00566               switch (s[1]) {
00567               case 'j':                   /* jitter */
00568                      getparam(s+2, "direct jitter", 'r',
00569                                    (void *)&dstrsrc);
00570                      break;
00571               case 'c':                   /* certainty */
00572                      getparam(s+2, "direct certainty", 'r',
00573                                    (void *)&shadcert);
00574                      break;
00575               case 't':                   /* threshold */
00576                      getparam(s+2, "direct threshold", 'r',
00577                                    (void *)&shadthresh);
00578                      break;
00579               case 'v':                   /* visibility */
00580                      getparam(s+2, "direct visibility", 'b',
00581                                    (void *)&directvis);
00582                      break;
00583               case 's':                   /* sampling */
00584                      getparam(s+2, "direct sampling", 'r',
00585                                    (void *)&srcsizerat);
00586                      break;
00587               default:
00588                      goto badparam;
00589               }
00590               break;
00591        case 'b':                   /* back faces or black and white */
00592               switch (s[1]) {
00593               case 'v':                   /* back face visibility */
00594                      getparam(s+2, "back face visibility", 'b',
00595                                    (void *)&backvis);
00596                      break;
00597               case '\0':                  /* black and white */
00598               case ' ':
00599               case 'y': case 'Y': case 't': case 'T': case '1': case '+':
00600               case 'n': case 'N': case 'f': case 'F': case '0': case '-':
00601                      getparam(s+1, "black and white", 'b',
00602                                    (void *)&greyscale);
00603                      newparam = prev_newp;
00604                      break;
00605               default:
00606                      goto badparam;
00607               }
00608               break;
00609        case 'i':                   /* irradiance */
00610               getparam(s+1, "irradiance", 'b',
00611                             (void *)&do_irrad);
00612               break;
00613        case 'a':                   /* ambient */
00614               switch (s[1]) {
00615               case 'v':                   /* value */
00616                      getparam(s+2, "ambient value", 'C',
00617                                    (void *)ambval);
00618                      break;
00619               case 'w':                   /* weight */
00620                      getparam(s+2, "ambient value weight", 'i',
00621                                    (void *)&ambvwt);
00622                      break;
00623               case 'a':                   /* accuracy */
00624                      if (getparam(s+2, "ambient accuracy", 'r',
00625                                    (void *)&ambacc))
00626                             setambacc(ambacc);
00627                      break;
00628               case 'd':                   /* divisions */
00629                      getparam(s+2, "ambient divisions", 'i',
00630                                    (void *)&ambdiv);
00631                      break;
00632               case 's':                   /* samples */
00633                      getparam(s+2, "ambient super-samples", 'i',
00634                                    (void *)&ambssamp);
00635                      break;
00636               case 'b':                   /* bounces */
00637                      getparam(s+2, "ambient bounces", 'i',
00638                                    (void *)&ambounce);
00639                      break;
00640               case 'r':
00641                      if (getparam(s+2, "ambient resolution", 'i',
00642                                    (void *)&ambres))
00643                             setambres(ambres);
00644                      break;
00645               default:
00646                      goto badparam;
00647               }
00648               break;
00649        case 'm':                   /* medium */
00650               switch (s[1]) {
00651               case 'e':                   /* extinction coefficient */
00652                      getparam(s+2, "extinction coefficient", 'C',
00653                                    (void *)cextinction);
00654                      break;
00655               case 'a':                   /* scattering albedo */
00656                      getparam(s+2, "scattering albedo", 'C',
00657                                    (void *)salbedo);
00658                      break;
00659               case 'g':                   /* scattering eccentricity */
00660                      getparam(s+2, "scattering eccentricity", 'r',
00661                                    (void *)&seccg);
00662                      break;
00663               case 's':                   /* sampling distance */
00664                      getparam(s+2, "mist sampling distance", 'r',
00665                                    (void *)&ssampdist);
00666                      break;
00667               default:
00668                      goto badparam;
00669               }
00670               break;
00671        case 'p':                   /* pixel */
00672               switch (s[1]) {
00673               case 's':                   /* sample */
00674                      if (getparam(s+2, "pixel sample", 'i',
00675                                    (void *)&psample))
00676                             pdepth = 0;
00677                      break;
00678               case 't':                   /* threshold */
00679                      if (getparam(s+2, "pixel threshold", 'r',
00680                                    (void *)&maxdiff))
00681                             pdepth = 0;
00682                      break;
00683               default:
00684                      goto badparam;
00685               }
00686               newparam = prev_newp;
00687               break;
00688        case 's':                   /* specular */
00689               switch (s[1]) {
00690               case 'j':                   /* jitter */
00691                      getparam(s+2, "specular jitter", 'r',
00692                                    (void *)&specjitter);
00693                      break;
00694               case 't':                   /* threshold */
00695                      getparam(s+2, "specular threshold", 'r',
00696                                    (void *)&specthresh);
00697                      break;
00698               default:
00699                      goto badparam;
00700               }
00701               break;
00702        case '\0':                  /* nothing */
00703               break;
00704        default:;
00705 badparam:
00706               *sskip(s) = '\0';
00707               sprintf(errmsg, "%s: unknown variable", s);
00708               error(COMMAND, errmsg);
00709               break;
00710        }
00711 }
00712 
00713 
00714 void
00715 traceray(                          /* trace a single ray */
00716        char  *s
00717 )
00718 {
00719        char  buf[128];
00720        int  x, y;
00721        OBJREC *ino;
00722        RAY  thisray;
00723 
00724        thisray.rmax = 0.0;
00725 
00726        if (!sscanvec(s, thisray.rorg) ||
00727                      !sscanvec(sskip2(s,3), thisray.rdir)) {
00728 
00729               if (dev->getcur == NULL)
00730                      return;
00731               (*dev->comout)("Pick ray\n");
00732               if ((*dev->getcur)(&x, &y) == ABORT)
00733                      return;
00734 
00735               if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
00736                      &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) {
00737                      error(COMMAND, "not on image");
00738                      return;
00739               }
00740 
00741        } else if (normalize(thisray.rdir) == 0.0) {
00742               error(COMMAND, "zero ray direction");
00743               return;
00744        }
00745 
00746        ray_trace(&thisray);
00747 
00748        if (thisray.ro == NULL)
00749               (*dev->comout)("ray hit nothing");
00750        else {
00751               OBJREC *mat = NULL;
00752               OBJREC *mod = NULL;
00753               char   matspec[256];
00754               matspec[0] = '\0';
00755               if (thisray.ro->omod != OVOID) {
00756                      mod = objptr(thisray.ro->omod);
00757                      mat = findmaterial(mod);
00758               }
00759               if (thisray.rod < 0.0)
00760                      strcpy(matspec, "back of ");
00761               if (mod != NULL) {
00762                      strcat(matspec, mod->oname);
00763                      if (mat != mod && mat != NULL)
00764                             sprintf(matspec+strlen(matspec),
00765                                    " (%s)", mat->oname);
00766               } else
00767                      strcat(matspec, VOIDID);
00768               sprintf(buf, "ray hit %s %s \"%s\"", matspec,
00769                             ofun[thisray.ro->otype].funame,
00770                             thisray.ro->oname);
00771               if ((ino = objptr(thisray.robj)) != thisray.ro)
00772                      sprintf(buf+strlen(buf), " in %s \"%s\"",
00773                                    ofun[ino->otype].funame, ino->oname);
00774               (*dev->comout)(buf);
00775               (*dev->comin)(buf, NULL);
00776               if (thisray.rot >= FHUGE)
00777                      (*dev->comout)("at infinity");
00778               else {
00779                      sprintf(buf, "at (%.6g %.6g %.6g) (%.6g)",
00780                                    thisray.rop[0], thisray.rop[1],
00781                                    thisray.rop[2], thisray.rt);
00782                      (*dev->comout)(buf);
00783               }
00784               (*dev->comin)(buf, NULL);
00785               sprintf(buf, "value (%.5g %.5g %.5g) (%.3gL)",
00786                             colval(thisray.rcol,RED),
00787                             colval(thisray.rcol,GRN),
00788                             colval(thisray.rcol,BLU),
00789                             luminance(thisray.rcol));
00790               (*dev->comout)(buf);
00791        }
00792        (*dev->comin)(buf, NULL);
00793 }
00794 
00795 
00796 void
00797 writepict(                         /* write the picture to a file */
00798        char  *s
00799 )
00800 {
00801        static char  buf[128];
00802        char  *fname;
00803        FILE  *fp;
00804        COLR  *scanline;
00805        int  y;
00806 
00807        while (isspace(*s))
00808               s++;
00809        if (*s)
00810               atos(buf, sizeof(buf), s);
00811        else if (buf[0] == '\0') {
00812               error(COMMAND, "no file");
00813               return;
00814        }
00815        if ((fname = getpath(buf, NULL, 0)) == NULL ||
00816                      (fp = fopen(fname, "w")) == NULL) {
00817               sprintf(errmsg, "cannot open \"%s\"", buf);
00818               error(COMMAND, errmsg);
00819               return;
00820        }
00821        SET_FILE_BINARY(fp);
00822        (*dev->comout)("writing \"");
00823        (*dev->comout)(fname);
00824        (*dev->comout)("\"...\n");
00825                                           /* write header */
00826        newheader("RADIANCE", fp);
00827        fputs(progname, fp);
00828        fprintview(&ourview, fp);
00829        if (octname != NULL)
00830               fprintf(fp, " %s\n", octname);
00831        else
00832               putc('\n', fp);
00833        fprintf(fp, "SOFTWARE= %s\n", VersionID);
00834        fputnow(fp);
00835        if (exposure != 1.0)
00836               fputexpos(exposure, fp);
00837        if (dev->pixaspect != 1.0)
00838               fputaspect(dev->pixaspect, fp);
00839        fputformat(COLRFMT, fp);
00840        putc('\n', fp);
00841        fprtresolu(hresolu, vresolu, fp);
00842 
00843        scanline = (COLR *)malloc(hresolu*sizeof(COLR));
00844        if (scanline == NULL) {
00845               error(COMMAND, "not enough memory!");
00846               fclose(fp);
00847               unlink(fname);
00848               return;
00849        }
00850        for (y = vresolu-1; y >= 0; y--) {
00851               getpictcolrs(y, scanline, &ptrunk, hresolu, vresolu);
00852               if (fwritecolrs(scanline, hresolu, fp) < 0)
00853                      break;
00854        }
00855        free((void *)scanline);
00856        if (fclose(fp) < 0)
00857               error(COMMAND, "write error");
00858 }