Back to index

radiance  4R0+20100331
rtrace.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rtrace.c,v 2.63 2009/12/16 03:30:50 greg Exp $";
00003 #endif
00004 /*
00005  *  rtrace.c - program and variables for individual ray tracing.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 /*
00011  *  Input is in the form:
00012  *
00013  *     xorg   yorg   zorg   xdir   ydir   zdir
00014  *
00015  *  The direction need not be normalized.  Output is flexible.
00016  *  If the direction vector is (0,0,0), then the output is flushed.
00017  *  All values default to ascii representation of real
00018  *  numbers.  Binary representations can be selected
00019  *  with '-ff' for float or '-fd' for double.  By default,
00020  *  radiance is computed.  The '-i' or '-I' options indicate that
00021  *  irradiance values are desired.
00022  */
00023 
00024 #include  <time.h>
00025 
00026 #include  "platform.h"
00027 #include  "ray.h"
00028 #include  "ambient.h"
00029 #include  "source.h"
00030 #include  "otypes.h"
00031 #include  "resolu.h"
00032 #include  "random.h"
00033 
00034 extern int  inform;                /* input format */
00035 extern int  outform;               /* output format */
00036 extern char  *outvals;                    /* output values */
00037 
00038 extern int  imm_irrad;                    /* compute immediate irradiance? */
00039 extern int  lim_dist;                     /* limit distance? */
00040 
00041 extern char  *tralist[];           /* list of modifers to trace (or no) */
00042 extern int  traincl;               /* include == 1, exclude == 0 */
00043 
00044 extern int  hresolu;               /* horizontal resolution */
00045 extern int  vresolu;               /* vertical resolution */
00046 
00047 static int  castonly = 0;
00048 
00049 #ifndef  MAXTSET
00050 #define        MAXTSET      8191          /* maximum number in trace set */
00051 #endif
00052 OBJECT traset[MAXTSET+1]={0};             /* trace include/exclude set */
00053 
00054 static RAY  thisray;               /* for our convenience */
00055 
00056 typedef void putf_t(double v);
00057 static putf_t puta, putd, putf;
00058 
00059 typedef void oputf_t(RAY *r);
00060 static oputf_t  oputo, oputd, oputv, oputV, oputl, oputL, oputc, oputp,
00061               oputn, oputN, oputs, oputw, oputW, oputm, oputM, oputtilde;
00062 
00063 static void setoutput(char *vs);
00064 extern void tranotify(OBJECT obj);
00065 static void bogusray(void);
00066 static void raycast(RAY *r);
00067 static void rayirrad(RAY *r);
00068 static void rtcompute(FVECT org, FVECT dir, double dmax);
00069 static int printvals(RAY *r);
00070 static int getvec(FVECT vec, int fmt, FILE *fp);
00071 static void tabin(RAY *r);
00072 static void ourtrace(RAY *r);
00073 
00074 static oputf_t *ray_out[16], *every_out[16];
00075 static putf_t *putreal;
00076 
00077 
00078 void
00079 quit(                /* quit program */
00080        int  code
00081 )
00082 {
00083        if (ray_pnprocs > 0) /* close children if any */
00084               ray_pclose(0);              
00085 #ifndef  NON_POSIX
00086        else if (!ray_pnprocs) {
00087               headclean();  /* delete header file */
00088               pfclean();    /* clean up persist files */
00089        }
00090 #endif
00091        exit(code);
00092 }
00093 
00094 
00095 char *
00096 formstr(                           /* return format identifier */
00097        int  f
00098 )
00099 {
00100        switch (f) {
00101        case 'a': return("ascii");
00102        case 'f': return("float");
00103        case 'd': return("double");
00104        case 'c': return(COLRFMT);
00105        }
00106        return("unknown");
00107 }
00108 
00109 
00110 extern void
00111 rtrace(                            /* trace rays from file */
00112        char  *fname,
00113        int  nproc
00114 )
00115 {
00116        unsigned long  vcount = (hresolu > 1) ? (unsigned long)hresolu*vresolu
00117                                          : vresolu;
00118        long  nextflush = hresolu;
00119        FILE  *fp;
00120        double d;
00121        FVECT  orig, direc;
00122                                    /* set up input */
00123        if (fname == NULL)
00124               fp = stdin;
00125        else if ((fp = fopen(fname, "r")) == NULL) {
00126               sprintf(errmsg, "cannot open input file \"%s\"", fname);
00127               error(SYSTEM, errmsg);
00128        }
00129        if (inform != 'a')
00130               SET_FILE_BINARY(fp);
00131                                    /* set up output */
00132        setoutput(outvals);
00133        if (imm_irrad)
00134               castonly = 0;
00135        else if (castonly)
00136               nproc = 1;           /* don't bother multiprocessing */
00137        switch (outform) {
00138        case 'a': putreal = puta; break;
00139        case 'f': putreal = putf; break;
00140        case 'd': putreal = putd; break;
00141        case 'c': 
00142               if (strcmp(outvals, "v"))
00143                      error(USER, "color format with value output only");
00144               break;
00145        default:
00146               error(CONSISTENCY, "botched output format");
00147        }
00148        if (nproc > 1) {            /* start multiprocessing */
00149               ray_popen(nproc);
00150               ray_fifo_out = printvals;
00151        }
00152        if (hresolu > 0) {
00153               if (vresolu > 0)
00154                      fprtresolu(hresolu, vresolu, stdout);
00155               fflush(stdout);
00156        }
00157                                    /* process file */
00158        while (getvec(orig, inform, fp) == 0 &&
00159                      getvec(direc, inform, fp) == 0) {
00160 
00161               d = normalize(direc);
00162               if (d == 0.0) {                           /* zero ==> flush */
00163                      if (--nextflush <= 0 || !vcount) {
00164                             if (nproc > 1 && ray_fifo_flush() < 0)
00165                                    error(USER, "lost children");
00166                             bogusray();
00167                             fflush(stdout);
00168                             nextflush = hresolu;
00169                      } else
00170                             bogusray();
00171               } else {                           /* compute and print */
00172                      rtcompute(orig, direc, lim_dist ? d : 0.0);
00173                                                  /* flush if time */
00174                      if (!--nextflush) {
00175                             if (nproc > 1 && ray_fifo_flush() < 0)
00176                                    error(USER, "lost children");
00177                             fflush(stdout);
00178                             nextflush = hresolu;
00179                      }
00180               }
00181               if (ferror(stdout))
00182                      error(SYSTEM, "write error");
00183               if (vcount && !--vcount)           /* check for end */
00184                      break;
00185        }
00186        if (nproc > 1) {                          /* clean up children */
00187               if (ray_fifo_flush() < 0)
00188                      error(USER, "unable to complete processing");
00189               ray_pclose(0);
00190        }
00191        if (fflush(stdout) < 0)
00192               error(SYSTEM, "write error");
00193        if (vcount)
00194               error(USER, "unexpected EOF on input");
00195        if (fname != NULL)
00196               fclose(fp);
00197 }
00198 
00199 
00200 static void
00201 trace_sources(void)                /* trace rays to light sources, also */
00202 {
00203        int    sn;
00204        
00205        for (sn = 0; sn < nsources; sn++)
00206               source[sn].sflags |= SFOLLOW;
00207 }
00208 
00209 
00210 static void
00211 setoutput(                         /* set up output tables */
00212        char  *vs
00213 )
00214 {
00215        oputf_t **table = ray_out;
00216 
00217        castonly = 1;
00218        while (*vs)
00219               switch (*vs++) {
00220               case 'T':                          /* trace sources */
00221                      if (!*vs) break;
00222                      trace_sources();
00223                      /* fall through */
00224               case 't':                          /* trace */
00225                      if (!*vs) break;
00226                      *table = NULL;
00227                      table = every_out;
00228                      trace = ourtrace;
00229                      castonly = 0;
00230                      break;
00231               case 'o':                          /* origin */
00232                      *table++ = oputo;
00233                      break;
00234               case 'd':                          /* direction */
00235                      *table++ = oputd;
00236                      break;
00237               case 'v':                          /* value */
00238                      *table++ = oputv;
00239                      castonly = 0;
00240                      break;
00241               case 'V':                          /* contribution */
00242                      *table++ = oputV;
00243                      if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0))
00244                             error(WARNING,
00245                                    "-otV accuracy depends on -aa 0 -as 0");
00246                      break;
00247               case 'l':                          /* effective distance */
00248                      *table++ = oputl;
00249                      castonly = 0;
00250                      break;
00251               case 'c':                          /* local coordinates */
00252                      *table++ = oputc;
00253                      break;
00254               case 'L':                          /* single ray length */
00255                      *table++ = oputL;
00256                      break;
00257               case 'p':                          /* point */
00258                      *table++ = oputp;
00259                      break;
00260               case 'n':                          /* perturbed normal */
00261                      *table++ = oputn;
00262                      castonly = 0;
00263                      break;
00264               case 'N':                          /* unperturbed normal */
00265                      *table++ = oputN;
00266                      break;
00267               case 's':                          /* surface */
00268                      *table++ = oputs;
00269                      break;
00270               case 'w':                          /* weight */
00271                      *table++ = oputw;
00272                      break;
00273               case 'W':                          /* coefficient */
00274                      *table++ = oputW;
00275                      if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0))
00276                             error(WARNING,
00277                                    "-otW accuracy depends on -aa 0 -as 0");
00278                      break;
00279               case 'm':                          /* modifier */
00280                      *table++ = oputm;
00281                      break;
00282               case 'M':                          /* material */
00283                      *table++ = oputM;
00284                      break;
00285               case '~':                          /* tilde */
00286                      *table++ = oputtilde;
00287                      break;
00288               }
00289        *table = NULL;
00290 }
00291 
00292 
00293 static void
00294 bogusray(void)                     /* print out empty record */
00295 {
00296        thisray.rorg[0] = thisray.rorg[1] = thisray.rorg[2] =
00297        thisray.rdir[0] = thisray.rdir[1] = thisray.rdir[2] = 0.0;
00298        thisray.rmax = 0.0;
00299        rayorigin(&thisray, PRIMARY, NULL, NULL);
00300        printvals(&thisray);
00301 }
00302 
00303 
00304 static void
00305 raycast(                    /* compute first ray intersection only */
00306        RAY *r
00307 )
00308 {
00309        if (!localhit(r, &thescene)) {
00310               if (r->ro == &Aftplane) {   /* clipped */
00311                      r->ro = NULL;
00312                      r->rot = FHUGE;
00313               } else
00314                      sourcehit(r);
00315        }
00316 }
00317 
00318 
00319 static void
00320 rayirrad(                   /* compute irradiance rather than radiance */
00321        RAY *r
00322 )
00323 {
00324        void   (*old_revf)(RAY *) = r->revf;
00325 
00326        r->rot = 1e-5;                     /* pretend we hit surface */
00327        VSUM(r->rop, r->rorg, r->rdir, r->rot);
00328        r->ron[0] = -r->rdir[0];
00329        r->ron[1] = -r->rdir[1];
00330        r->ron[2] = -r->rdir[2];
00331        r->rod = 1.0;
00332                                    /* compute result */
00333        r->revf = raytrace;
00334        (*ofun[Lamb.otype].funp)(&Lamb, r);
00335        r->revf = old_revf;
00336 }
00337 
00338 
00339 static void
00340 rtcompute(                  /* compute and print ray value(s) */
00341        FVECT  org,
00342        FVECT  dir,
00343        double dmax
00344 )
00345 {
00346                                    /* set up ray */
00347        rayorigin(&thisray, PRIMARY, NULL, NULL);
00348        if (imm_irrad) {
00349               VSUM(thisray.rorg, org, dir, 1.1e-4);
00350               thisray.rdir[0] = -dir[0];
00351               thisray.rdir[1] = -dir[1];
00352               thisray.rdir[2] = -dir[2];
00353               thisray.rmax = 0.0;
00354               thisray.revf = rayirrad;
00355        } else {
00356               VCOPY(thisray.rorg, org);
00357               VCOPY(thisray.rdir, dir);
00358               thisray.rmax = dmax;
00359               if (castonly)
00360                      thisray.revf = raycast;
00361        }
00362        if (ray_pnprocs > 1) {             /* multiprocessing FIFO? */
00363               if (ray_fifo_in(&thisray) < 0)
00364                      error(USER, "lost children");
00365               return;
00366        }
00367        samplendx++;                /* else do it ourselves */
00368        rayvalue(&thisray);
00369        printvals(&thisray);
00370 }
00371 
00372 
00373 static int
00374 printvals(                  /* print requested ray values */
00375        RAY  *r
00376 )
00377 {
00378        oputf_t **tp;
00379 
00380        if (ray_out[0] == NULL)
00381               return(0);
00382        for (tp = ray_out; *tp != NULL; tp++)
00383               (**tp)(r);
00384        if (outform == 'a')
00385               putchar('\n');
00386        return(1);
00387 }
00388 
00389 
00390 static int
00391 getvec(              /* get a vector from fp */
00392        FVECT  vec,
00393        int  fmt,
00394        FILE  *fp
00395 )
00396 {
00397        static float  vf[3];
00398        static double  vd[3];
00399        char  buf[32];
00400        int  i;
00401 
00402        switch (fmt) {
00403        case 'a':                                 /* ascii */
00404               for (i = 0; i < 3; i++) {
00405                      if (fgetword(buf, sizeof(buf), fp) == NULL ||
00406                                    !isflt(buf))
00407                             return(-1);
00408                      vec[i] = atof(buf);
00409               }
00410               break;
00411        case 'f':                                 /* binary float */
00412               if (fread((char *)vf, sizeof(float), 3, fp) != 3)
00413                      return(-1);
00414               VCOPY(vec, vf);
00415               break;
00416        case 'd':                                 /* binary double */
00417               if (fread((char *)vd, sizeof(double), 3, fp) != 3)
00418                      return(-1);
00419               VCOPY(vec, vd);
00420               break;
00421        default:
00422               error(CONSISTENCY, "botched input format");
00423        }
00424        return(0);
00425 }
00426 
00427 
00428 void
00429 tranotify(                  /* record new modifier */
00430        OBJECT obj
00431 )
00432 {
00433        static int  hitlimit = 0;
00434        OBJREC  *o = objptr(obj);
00435        char  **tralp;
00436 
00437        if (obj == OVOID) {         /* starting over */
00438               traset[0] = 0;
00439               hitlimit = 0;
00440               return;
00441        }
00442        if (hitlimit || !ismodifier(o->otype))
00443               return;
00444        for (tralp = tralist; *tralp != NULL; tralp++)
00445               if (!strcmp(o->oname, *tralp)) {
00446                      if (traset[0] >= MAXTSET) {
00447                             error(WARNING, "too many modifiers in trace list");
00448                             hitlimit++;
00449                             return;              /* should this be fatal? */
00450                      }
00451                      insertelem(traset, obj);
00452                      return;
00453               }
00454 }
00455 
00456 
00457 static void
00458 ourtrace(                          /* print ray values */
00459        RAY  *r
00460 )
00461 {
00462        oputf_t **tp;
00463 
00464        if (every_out[0] == NULL)
00465               return;
00466        if (r->ro == NULL) {
00467               if (traincl == 1)
00468                      return;
00469        } else if (traincl != -1 && traincl != inset(traset, r->ro->omod))
00470               return;
00471        tabin(r);
00472        for (tp = every_out; *tp != NULL; tp++)
00473               (**tp)(r);
00474        if (outform == 'a')
00475               putchar('\n');
00476 }
00477 
00478 
00479 static void
00480 tabin(                      /* tab in appropriate amount */
00481        RAY  *r
00482 )
00483 {
00484        const RAY  *rp;
00485 
00486        for (rp = r->parent; rp != NULL; rp = rp->parent)
00487               putchar('\t');
00488 }
00489 
00490 
00491 static void
00492 oputo(                      /* print origin */
00493        RAY  *r
00494 )
00495 {
00496        (*putreal)(r->rorg[0]);
00497        (*putreal)(r->rorg[1]);
00498        (*putreal)(r->rorg[2]);
00499 }
00500 
00501 
00502 static void
00503 oputd(                      /* print direction */
00504        RAY  *r
00505 )
00506 {
00507        (*putreal)(r->rdir[0]);
00508        (*putreal)(r->rdir[1]);
00509        (*putreal)(r->rdir[2]);
00510 }
00511 
00512 
00513 static void
00514 oputv(                      /* print value */
00515        RAY  *r
00516 )
00517 {
00518        if (outform == 'c') {
00519               COLR  cout;
00520               setcolr(cout, colval(r->rcol,RED),
00521                             colval(r->rcol,GRN),
00522                             colval(r->rcol,BLU));
00523               fwrite((char *)cout, sizeof(cout), 1, stdout);
00524               return;
00525        }
00526        (*putreal)(colval(r->rcol,RED));
00527        (*putreal)(colval(r->rcol,GRN));
00528        (*putreal)(colval(r->rcol,BLU));
00529 }
00530 
00531 
00532 static void
00533 oputV(                      /* print value contribution */
00534        RAY *r
00535 )
00536 {
00537        double contr[3];
00538 
00539        raycontrib(contr, r, PRIMARY);
00540        multcolor(contr, r->rcol);
00541        (*putreal)(contr[RED]);
00542        (*putreal)(contr[GRN]);
00543        (*putreal)(contr[BLU]);
00544 }
00545 
00546 
00547 static void
00548 oputl(                      /* print effective distance */
00549        RAY  *r
00550 )
00551 {
00552        (*putreal)(r->rt);
00553 }
00554 
00555 
00556 static void
00557 oputL(                      /* print single ray length */
00558        RAY  *r
00559 )
00560 {
00561        (*putreal)(r->rot);
00562 }
00563 
00564 
00565 static void
00566 oputc(                      /* print local coordinates */
00567        RAY  *r
00568 )
00569 {
00570        (*putreal)(r->uv[0]);
00571        (*putreal)(r->uv[1]);
00572 }
00573 
00574 
00575 static void
00576 oputp(                      /* print point */
00577        RAY  *r
00578 )
00579 {
00580        if (r->rot < FHUGE) {
00581               (*putreal)(r->rop[0]);
00582               (*putreal)(r->rop[1]);
00583               (*putreal)(r->rop[2]);
00584        } else {
00585               (*putreal)(0.0);
00586               (*putreal)(0.0);
00587               (*putreal)(0.0);
00588        }
00589 }
00590 
00591 
00592 static void
00593 oputN(                      /* print unperturbed normal */
00594        RAY  *r
00595 )
00596 {
00597        if (r->rot < FHUGE) {
00598               (*putreal)(r->ron[0]);
00599               (*putreal)(r->ron[1]);
00600               (*putreal)(r->ron[2]);
00601        } else {
00602               (*putreal)(0.0);
00603               (*putreal)(0.0);
00604               (*putreal)(0.0);
00605        }
00606 }
00607 
00608 
00609 static void
00610 oputn(                      /* print perturbed normal */
00611        RAY  *r
00612 )
00613 {
00614        FVECT  pnorm;
00615 
00616        if (r->rot >= FHUGE) {
00617               (*putreal)(0.0);
00618               (*putreal)(0.0);
00619               (*putreal)(0.0);
00620               return;
00621        }
00622        raynormal(pnorm, r);
00623        (*putreal)(pnorm[0]);
00624        (*putreal)(pnorm[1]);
00625        (*putreal)(pnorm[2]);
00626 }
00627 
00628 
00629 static void
00630 oputs(                      /* print name */
00631        RAY  *r
00632 )
00633 {
00634        if (r->ro != NULL)
00635               fputs(r->ro->oname, stdout);
00636        else
00637               putchar('*');
00638        putchar('\t');
00639 }
00640 
00641 
00642 static void
00643 oputw(                      /* print weight */
00644        RAY  *r
00645 )
00646 {
00647        (*putreal)(r->rweight);
00648 }
00649 
00650 
00651 static void
00652 oputW(                      /* print coefficient */
00653        RAY  *r
00654 )
00655 {
00656        double contr[3];
00657 
00658        raycontrib(contr, r, PRIMARY);
00659        (*putreal)(contr[RED]);
00660        (*putreal)(contr[GRN]);
00661        (*putreal)(contr[BLU]);
00662 }
00663 
00664 
00665 static void
00666 oputm(                      /* print modifier */
00667        RAY  *r
00668 )
00669 {
00670        if (r->ro != NULL)
00671               if (r->ro->omod != OVOID)
00672                      fputs(objptr(r->ro->omod)->oname, stdout);
00673               else
00674                      fputs(VOIDID, stdout);
00675        else
00676               putchar('*');
00677        putchar('\t');
00678 }
00679 
00680 
00681 static void
00682 oputM(                      /* print material */
00683        RAY  *r
00684 )
00685 {
00686        OBJREC *mat;
00687 
00688        if (r->ro != NULL) {
00689               if ((mat = findmaterial(r->ro)) != NULL)
00690                      fputs(mat->oname, stdout);
00691               else
00692                      fputs(VOIDID, stdout);
00693        } else
00694               putchar('*');
00695        putchar('\t');
00696 }
00697 
00698 
00699 static void
00700 oputtilde(                  /* output tilde (spacer) */
00701        RAY  *r
00702 )
00703 {
00704        fputs("~\t", stdout);
00705 }
00706 
00707 
00708 static void
00709 puta(                       /* print ascii value */
00710        double  v
00711 )
00712 {
00713        printf("%e\t", v);
00714 }
00715 
00716 
00717 static void
00718 putd(v)                            /* print binary double */
00719 double  v;
00720 {
00721        fwrite((char *)&v, sizeof(v), 1, stdout);
00722 }
00723 
00724 
00725 static void
00726 putf(v)                            /* print binary float */
00727 double  v;
00728 {
00729        float f = v;
00730 
00731        fwrite((char *)&f, sizeof(f), 1, stdout);
00732 }