home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / NEWS / RADIANCE / SRC / RT / AMBIENT.C < prev    next >
C/C++ Source or Header  |  1993-10-07  |  10KB  |  447 lines

  1. /* Copyright (c) 1992 Regents of the University of California */
  2.  
  3. #ifndef lint
  4. static char SCCSid[] = "@(#)ambient.c 2.14 11/3/92 LBL";
  5. #endif
  6.  
  7. /*
  8.  *  ambient.c - routines dealing with ambient (inter-reflected) component.
  9.  *
  10.  *     5/9/86
  11.  */
  12.  
  13. #include  "ray.h"
  14.  
  15. #include  "octree.h"
  16.  
  17. #include  "otypes.h"
  18.  
  19. #include  "ambient.h"
  20.  
  21. #include  "random.h"
  22.  
  23. #define     OCTSCALE    0.5    /* ceil((valid rad.)/(cube size)) */
  24.  
  25. typedef struct ambtree {
  26.     AMBVAL    *alist;        /* ambient value list */
  27.     struct ambtree    *kid;    /* 8 child nodes */
  28. }  AMBTREE;            /* ambient octree */
  29.  
  30. extern CUBE  thescene;        /* contains space boundaries */
  31.  
  32. #define     MAXASET    511    /* maximum number of elements in ambient set */
  33. OBJECT    ambset[MAXASET+1]={0};    /* ambient include/exclude set */
  34.  
  35. double    maxarad;        /* maximum ambient radius */
  36. double    minarad;        /* minimum ambient radius */
  37.  
  38. static AMBTREE    atrunk;        /* our ambient trunk node */
  39.  
  40. static FILE  *ambfp = NULL;    /* ambient file pointer */
  41.  
  42. #define     AMBFLUSH    (BUFSIZ/AMBVALSIZ)
  43.  
  44. #define     newambval()    (AMBVAL *)bmalloc(sizeof(AMBVAL))
  45.  
  46. #define     newambtree()    (AMBTREE *)calloc(8, sizeof(AMBTREE))
  47.  
  48. extern long  ftell(), lseek();
  49. static int  initambfile(), avsave(), avinsert(), ambsync();
  50.  
  51.  
  52. setambres(ar)                /* set ambient resolution */
  53. int  ar;
  54. {
  55.                         /* set min & max radii */
  56.     if (ar <= 0) {
  57.         minarad = 0.0;
  58.         maxarad = thescene.cusize / 2.0;
  59.     } else {
  60.         minarad = thescene.cusize / ar;
  61.         maxarad = 16.0 * minarad;        /* heuristic */
  62.         if (maxarad > thescene.cusize / 2.0)
  63.             maxarad = thescene.cusize / 2.0;
  64.     }
  65.     if (maxarad <= FTINY)
  66.         maxarad = .001;
  67. }
  68.  
  69.  
  70. setambient(afile)            /* initialize calculation */
  71. char  *afile;
  72. {
  73.     long  headlen;
  74.     AMBVAL    amb;
  75.                         /* init ambient limits */
  76.     setambres(ambres);
  77.                         /* open ambient file */
  78.     if (afile != NULL)
  79.         if ((ambfp = fopen(afile, "r+")) != NULL) {
  80.             initambfile(0);
  81.             headlen = ftell(ambfp);
  82.             while (readambval(&amb, ambfp))
  83.                 avinsert(&amb, &atrunk, thescene.cuorg,
  84.                         thescene.cusize);
  85.                             /* align */
  86.             fseek(ambfp, -((ftell(ambfp)-headlen)%AMBVALSIZ), 1);
  87.         } else if ((ambfp = fopen(afile, "w+")) != NULL)
  88.             initambfile(1);
  89.         else {
  90.             sprintf(errmsg, "cannot open ambient file \"%s\"",
  91.                     afile);
  92.             error(SYSTEM, errmsg);
  93.         }
  94. }
  95.  
  96.  
  97. ambnotify(obj)            /* record new modifier */
  98. OBJECT    obj;
  99. {
  100.     static int  hitlimit = 0;
  101.     register OBJREC     *o = objptr(obj);
  102.     register char  **amblp;
  103.  
  104.     if (hitlimit || !ismodifier(o->otype))
  105.         return;
  106.     for (amblp = amblist; *amblp != NULL; amblp++)
  107.         if (!strcmp(o->oname, *amblp)) {
  108.             if (ambset[0] >= MAXASET) {
  109.                 error(WARNING, "too many modifiers in ambient list");
  110.                 hitlimit++;
  111.                 return;        /* should this be fatal? */
  112.             }
  113.             insertelem(ambset, obj);
  114.             return;
  115.         }
  116. }
  117.  
  118.  
  119. ambient(acol, r)        /* compute ambient component for ray */
  120. COLOR  acol;
  121. register RAY  *r;
  122. {
  123.     static int  rdepth = 0;            /* ambient recursion */
  124.     double    d;
  125.  
  126.     if (ambdiv <= 0)            /* no ambient calculation */
  127.         goto dumbamb;
  128.                         /* check number of bounces */
  129.     if (rdepth >= ambounce)
  130.         goto dumbamb;
  131.                         /* check ambient list */
  132.     if (ambincl != -1 && r->ro != NULL &&
  133.             ambincl != inset(ambset, r->ro->omod))
  134.         goto dumbamb;
  135.  
  136.     if (ambacc <= FTINY) {            /* no ambient storage */
  137.         rdepth++;
  138.         d = doambient(acol, r, r->rweight, NULL, NULL);
  139.         rdepth--;
  140.         if (d == 0.0)
  141.             goto dumbamb;
  142.         return;
  143.     }
  144.                         /* get ambient value */
  145.     setcolor(acol, 0.0, 0.0, 0.0);
  146.     d = sumambient(acol, r, rdepth,
  147.             &atrunk, thescene.cuorg, thescene.cusize);
  148.     if (d > FTINY)
  149.         scalecolor(acol, 1.0/d);
  150.     else {
  151.         d = makeambient(acol, r, rdepth++);
  152.         rdepth--;
  153.     }
  154.     if (d > FTINY)
  155.         return;
  156. dumbamb:                    /* return global value */
  157.     copycolor(acol, ambval);
  158. }
  159.  
  160.  
  161. double
  162. sumambient(acol, r, al, at, c0, s)    /* get interpolated ambient value */
  163. COLOR  acol;
  164. register RAY  *r;
  165. int  al;
  166. AMBTREE     *at;
  167. FVECT  c0;
  168. double    s;
  169. {
  170.     double    d, e1, e2, wt, wsum;
  171.     COLOR  ct;
  172.     FVECT  ck0;
  173.     int  i;
  174.     register int  j;
  175.     register AMBVAL     *av;
  176.                     /* do this node */
  177.     wsum = 0.0;
  178.     for (av = at->alist; av != NULL; av = av->next) {
  179.         /*
  180.          *  Ambient level test.
  181.          */
  182.         if (av->lvl > al || av->weight < r->rweight-FTINY)
  183.             continue;
  184.         /*
  185.          *  Ambient radius test.
  186.          */
  187.         e1 = 0.0;
  188.         for (j = 0; j < 3; j++) {
  189.             d = av->pos[j] - r->rop[j];
  190.             e1 += d * d;
  191.         }
  192.         e1 /= av->rad * av->rad;
  193.         if (e1 > ambacc*ambacc*1.21)
  194.             continue;
  195.         /*
  196.          *  Normal direction test.
  197.          */
  198.         e2 = (1.0 - DOT(av->dir, r->ron)) * r->rweight;
  199.         if (e2 < 0.0) e2 = 0.0;
  200.         if (e1 + e2 > ambacc*ambacc*1.21)
  201.             continue;
  202.         /*
  203.          *  Ray behind test.
  204.          */
  205.         d = 0.0;
  206.         for (j = 0; j < 3; j++)
  207.             d += (r->rop[j] - av->pos[j]) *
  208.                     (av->dir[j] + r->ron[j]);
  209.         if (d*0.5 < -minarad*ambacc-.001)
  210.             continue;
  211.         /*
  212.          *  Jittering final test reduces image artifacts.
  213.          */
  214.         wt = sqrt(e1) + sqrt(e2);
  215.         wt *= .9 + .2*urand(9015+samplendx);
  216.         if (wt > ambacc)
  217.             continue;
  218.         if (wt <= 1e-3)
  219.             wt = 1e3;
  220.         else
  221.             wt = 1.0 / wt;
  222.         wsum += wt;
  223.         extambient(ct, av, r->rop, r->ron);
  224.         scalecolor(ct, wt);
  225.         addcolor(acol, ct);
  226.     }
  227.     if (at->kid == NULL)
  228.         return(wsum);
  229.                     /* do children */
  230.     s *= 0.5;
  231.     for (i = 0; i < 8; i++) {
  232.         for (j = 0; j < 3; j++) {
  233.             ck0[j] = c0[j];
  234.             if (1<<j & i)
  235.                 ck0[j] += s;
  236.             if (r->rop[j] < ck0[j] - OCTSCALE*s)
  237.                 break;
  238.             if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
  239.                 break;
  240.         }
  241.         if (j == 3)
  242.             wsum += sumambient(acol, r, al, at->kid+i, ck0, s);
  243.     }
  244.     return(wsum);
  245. }
  246.  
  247.  
  248. double
  249. makeambient(acol, r, al)    /* make a new ambient value */
  250. COLOR  acol;
  251. register RAY  *r;
  252. int  al;
  253. {
  254.     AMBVAL    amb;
  255.     FVECT    gp, gd;
  256.                         /* compute weight */
  257.     amb.weight = pow(AVGREFL, (double)al);
  258.     if (r->rweight < 0.2*amb.weight)    /* heuristic */
  259.         amb.weight = r->rweight;
  260.                         /* compute ambient */
  261.     amb.rad = doambient(acol, r, amb.weight, gp, gd);
  262.     if (amb.rad == 0.0)
  263.         return(0.0);
  264.                         /* store it */
  265.     VCOPY(amb.pos, r->rop);
  266.     VCOPY(amb.dir, r->ron);
  267.     amb.lvl = al;
  268.     copycolor(amb.val, acol);
  269.     VCOPY(amb.gpos, gp);
  270.     VCOPY(amb.gdir, gd);
  271.                         /* insert into tree */
  272.     avsave(&amb);                /* and save to file */
  273.     return(amb.rad);
  274. }
  275.  
  276.  
  277. extambient(cr, ap, pv, nv)        /* extrapolate value at pv, nv */
  278. COLOR  cr;
  279. register AMBVAL     *ap;
  280. FVECT  pv, nv;
  281. {
  282.     FVECT  v1, v2;
  283.     register int  i;
  284.     double    d;
  285.  
  286.     d = 1.0;            /* zeroeth order */
  287.                     /* gradient due to translation */
  288.     for (i = 0; i < 3; i++)
  289.         d += ap->gpos[i]*(pv[i]-ap->pos[i]);
  290.                     /* gradient due to rotation */
  291.     VCOPY(v1, ap->dir);
  292.     fcross(v2, v1, nv);
  293.     d += DOT(ap->gdir, v2);
  294.     if (d <= 0.0) {
  295.         setcolor(cr, 0.0, 0.0, 0.0);
  296.         return;
  297.     }
  298.     copycolor(cr, ap->val);
  299.     scalecolor(cr, d);
  300. }
  301.  
  302.  
  303. static
  304. initambfile(creat)        /* initialize ambient file */
  305. int  creat;
  306. {
  307.     extern char  *progname, *octname, VersionID[];
  308.  
  309. #ifdef MSDOS
  310.     setmode(fileno(ambfp), O_BINARY);
  311. #endif
  312.     setbuf(ambfp, bmalloc(BUFSIZ));
  313.     if (creat) {            /* new file */
  314.         fprintf(ambfp, "%s -av %g %g %g -ab %d -aa %g ",
  315.                 progname, colval(ambval,RED),
  316.                 colval(ambval,GRN), colval(ambval,BLU),
  317.                 ambounce, ambacc);
  318.         fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
  319.                 ambdiv, ambssamp, ambres,
  320.                 octname==NULL ? "" : octname);
  321.         fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
  322.         fputformat(AMBFMT, ambfp);
  323.         putc('\n', ambfp);
  324.         putambmagic(ambfp);
  325.         fflush(ambfp);
  326. #ifndef     NIX
  327.         sync();            /* protect against NFS buffering */
  328. #endif
  329.     } else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
  330.         error(USER, "bad ambient file");
  331. }
  332.  
  333.  
  334. static
  335. avsave(av)                /* insert and save an ambient value */
  336. AMBVAL    *av;
  337. {
  338.     static int  nunflshed = 0;
  339.  
  340.     avinsert(av, &atrunk, thescene.cuorg, thescene.cusize);
  341.     if (ambfp == NULL)
  342.         return;
  343.     if (writambval(av, ambfp) < 0)
  344.         goto writerr;
  345.     if (++nunflshed >= AMBFLUSH) {
  346.         if (ambsync() == EOF)
  347.             goto writerr;
  348.         nunflshed = 0;
  349.     }
  350.     return;
  351. writerr:
  352.     error(SYSTEM, "error writing ambient file");
  353. }
  354.  
  355.  
  356. static
  357. avinsert(aval, at, c0, s)        /* insert ambient value in a tree */
  358. AMBVAL    *aval;
  359. register AMBTREE  *at;
  360. FVECT  c0;
  361. double    s;
  362. {
  363.     FVECT  ck0;
  364.     int  branch;
  365.     register AMBVAL     *av;
  366.     register int  i;
  367.  
  368.     if ((av = newambval()) == NULL)
  369.         goto memerr;
  370.     copystruct(av, aval);
  371.     VCOPY(ck0, c0);
  372.     while (s*(OCTSCALE/2) > av->rad*ambacc) {
  373.         if (at->kid == NULL)
  374.             if ((at->kid = newambtree()) == NULL)
  375.                 goto memerr;
  376.         s *= 0.5;
  377.         branch = 0;
  378.         for (i = 0; i < 3; i++)
  379.             if (av->pos[i] > ck0[i] + s) {
  380.                 ck0[i] += s;
  381.                 branch |= 1 << i;
  382.             }
  383.         at = at->kid + branch;
  384.     }
  385.     av->next = at->alist;
  386.     at->alist = av;
  387.     return;
  388. memerr:
  389.     error(SYSTEM, "out of memory in avinsert");
  390. }
  391.  
  392.  
  393. #ifdef    NIX
  394.  
  395. static
  396. ambsync()            /* flush ambient file */
  397. {
  398.     return(fflush(ambfp));
  399. }
  400.  
  401. #else
  402.  
  403. #include  <sys/types.h>
  404. #include  <sys/stat.h>
  405.  
  406. static
  407. ambsync()            /* synchronize ambient file */
  408. {
  409.     static FILE  *ambinp = NULL;
  410.     struct flock  fls;
  411.     struct stat  sts;
  412. #define    flen    sts.st_size
  413.     AMBVAL    avs;
  414.     long  lastpos;
  415.     register int  n;
  416.                 /* gain exclusive access */
  417.     fls.l_type = F_WRLCK;
  418.     fls.l_whence = 0;
  419.     fls.l_start = 0L;
  420.     fls.l_len = 0L;
  421.     if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
  422.         error(SYSTEM, "cannot lock ambient file");
  423.                 /* see if file has grown */
  424.     lastpos = lseek(fileno(ambfp), 0L, 1);    /* get previous position */
  425.     if (fstat(fileno(ambfp), &sts) < 0)    /* get current length */
  426.         error(SYSTEM, "cannot stat ambient file");
  427.     if (n = (flen - lastpos)/AMBVALSIZ) {    /* file has grown */
  428.         if (ambinp == NULL) {        /* use duplicate file */
  429.             ambinp = fdopen(dup(fileno(ambfp)), "r");
  430.             if (ambinp == NULL)
  431.                 error(SYSTEM, "fdopen failed in ambsync");
  432.         }
  433.         while (n--) {            /* load contributed values */
  434.             readambval(&avs, ambinp);
  435.             avinsert(&avs,&atrunk,thescene.cuorg,thescene.cusize);
  436.         }                /* moves shared file pointer */
  437.         if (n = (flen - lastpos)%AMBVALSIZ)    /* alignment */
  438.             lseek(fileno(ambfp), flen-n, 0);
  439.     }
  440.     n = fflush(ambfp);            /* calls write() at last */
  441.     fls.l_type = F_UNLCK;            /* release file */
  442.     fcntl(fileno(ambfp), F_SETLKW, &fls);
  443.     return(n);
  444. }
  445.  
  446. #endif
  447.