home *** CD-ROM | disk | FTP | other *** search
/ gondwana.ecr.mu.oz.au/pub/ / Graphics.tar / Graphics / atomart.tar.gz / atomart.tar / shade.c < prev    next >
C/C++ Source or Header  |  1990-06-27  |  7KB  |  330 lines

  1. /*
  2.  * the shading routines and their utilities
  3.  */
  4. #include <stdio.h>
  5. #include <math.h>
  6. #include "atomart.h"
  7. #include "macro.h"
  8. #include "gram.h"
  9.  
  10. extern object    *oblist;
  11. extern light    *lights;
  12. extern hlist    *fhlist;
  13. extern int    maxhitlevel;
  14.  
  15. extern short    raynumber;
  16.  
  17. extern pixel    backcol;
  18. extern colour    ambient;
  19.  
  20. extern double    power();
  21.  
  22. extern hlist    *trace();
  23.  
  24. extern float    randtable[], *randp, *erandp;
  25.  
  26. /*
  27.  * checklight
  28.  *
  29.  *    is the light l visible to us from loc? TRUE if
  30.  * it is, FALSE if it isn't. lr is returned as the ray
  31.  * hitting l from loc, and col is the intensity value of
  32.  * the light.
  33.  */
  34. int
  35. checklight(l, loc, lr, col, hitlevel)
  36.     light    *l;
  37.     vector    *loc;
  38.     ray    *lr;
  39.     pixel    *col;
  40.     int    hitlevel;
  41. {
  42.     object        *o;
  43.     vector        dir;
  44.     hlist        *hit, *p, *lp;
  45.     register float    dist, fact, t, peturb;
  46.     colour        base;
  47.  
  48.     if (l->type == DIRECTIONAL && l->cosang == 0.0) {
  49.         lr->dir = l->dir;
  50.         lr->org = *loc;
  51.  
  52.         dist = HUGE_DIST;
  53.     } else {
  54.         vsub(lr->dir, l->org, *loc);
  55.         normalise(lr->dir);
  56.  
  57.         dir = lr->dir;
  58.  
  59.         if (l->type == DIRECTIONAL && dprod(dir, l->dir) < l->cosang)
  60.             return(FALSE);
  61.  
  62.         lr->org = *loc;
  63.  
  64.         if (fabs(dir.x) > fabs(dir.y))
  65.             if (fabs(dir.x) > fabs(dir.z))
  66.                 dist = fabs((l->org.x - loc->x) / dir.x);
  67.             else
  68.                 dist = fabs((l->org.z - loc->z) / dir.z);
  69.         else
  70.             if (fabs(dir.y) > fabs(dir.z))
  71.                 dist = fabs((l->org.y - loc->y) / dir.y);
  72.             else
  73.                 dist = fabs((l->org.z - loc->z) / dir.z);
  74.     }
  75.  
  76.         /* aim at a random point on the light's sphere */
  77.     if (l->rad != 0.0 && dist != 0.0) {
  78.         fact = l->rad / dist;
  79.         peturb = (randnum() < 0.5) ? randnum() : -randnum();
  80.         lr->dir.x += peturb * fact;
  81.         peturb = (randnum() < 0.5) ? randnum() : -randnum();
  82.         lr->dir.y += peturb * fact;
  83.         peturb = (randnum() < 0.5) ? randnum() : -randnum();
  84.         lr->dir.z += peturb * fact;
  85.         normalise(lr->dir);
  86.     }
  87.  
  88.     lr->raynumber = raynumber++;
  89.  
  90.     o = l->lasthits[hitlevel];
  91.  
  92.     if (o != (object *)NULL) {
  93.         if ((hit = o->intersects(lr, o)) == (hlist *)NULL)
  94.             hit = trace(lr, oblist);
  95.         else if (hit->t >= dist)
  96.             hit = trace(lr, oblist);
  97.     } else
  98.         hit = trace(lr, oblist);
  99.  
  100.     base.r = l->c.r;
  101.     base.g = l->c.g;
  102.     base.b = l->c.b;
  103.  
  104.     o = (object *)NULL;
  105.  
  106.     while (hit != (hlist *)NULL && hit->obj->s.trans != 0.0) {
  107.         p = hit->nxt;
  108.         if (hit->t < dist && o != hit->obj) {
  109.             o = hit->obj;
  110.             if (p != (hlist *)NULL && p->obj == o && o->s.absorb != 0.0) {
  111.                 fact = 1.0 - o->s.absorb * (p->t - hit->t);
  112.                 if (fact < 0.0)
  113.                     fact = 0.0;
  114.                 base.r *= o->s.trans * fact;
  115.                 base.g *= o->s.trans * fact;
  116.                 base.b *= o->s.trans * fact;
  117.             } else {
  118.                 base.r *= o->s.trans;
  119.                 base.g *= o->s.trans;
  120.                 base.b *= o->s.trans;
  121.             }
  122.         }
  123.  
  124.         release(hit);
  125.  
  126.         if (p == (hlist *)NULL) {
  127.             lr->org.x += lr->dir.x * hit->t;
  128.             lr->org.y += lr->dir.y * hit->t;
  129.             lr->org.z += lr->dir.z * hit->t;
  130.  
  131.             lr->raynumber = raynumber++;
  132.  
  133.             hit = trace(lr, oblist);
  134.         } else {
  135.             hit = p;
  136.         }
  137.     }
  138.  
  139.  
  140.     if (hit != (hlist *)NULL) {
  141.  
  142.         t = hit->t;
  143.  
  144.         if (t >= dist)
  145.             l->lasthits[hitlevel] = (object *)NULL;
  146.         else
  147.             l->lasthits[hitlevel] = hit->obj;
  148.  
  149.         for (lp = hit; lp != (hlist *)NULL; lp = p) {
  150.             p = lp->nxt;
  151.             release(lp);
  152.         }
  153.     } else {
  154.         l->lasthits[hitlevel] = (object *)NULL;
  155.         t = dist;
  156.     }
  157.  
  158.     col->r = base.r;
  159.     col->g = base.g;
  160.     col->b = base.b;
  161.                 /* maybe the light is closer */
  162.     return(t >= dist);
  163. }
  164.  
  165. /*
  166.  * nextobj
  167.  *
  168.  *    return the list of hits where the first hit in the list isn't
  169.  * on object o.
  170.  */
  171. hlist *
  172. nextobj(list, o)
  173.     hlist    *list;
  174.     object    *o;
  175. {
  176.     hlist    *lp;
  177.  
  178.     while (list != (hlist *)NULL && list->obj == o) {
  179.         lp = list;
  180.         list = list->nxt;
  181.         release(lp);
  182.     }
  183.  
  184.     return(list);
  185. }
  186.  
  187. /*
  188.  * shade
  189.  *
  190.  *    returns the shading info for an object with reflection and/or
  191.  * transparency.
  192.  */
  193. void
  194. shade(pix, i, hit, hitlevel)
  195.     pixel        *pix;
  196.     register ray    *i;
  197.     hlist        *hit;
  198.     int        hitlevel;
  199. {
  200.     hlist        *nxthit, *p, *lp;
  201.     light        *l;
  202.     pixel        objcol, othercol;
  203.     ray        lr, ir;
  204.     vector        n, ns, mid;
  205.     tlist        *tp;
  206.     register object    *o;
  207.     register int    count;
  208.     register float    fact, prod, ksfact, kdfact;
  209.  
  210.     ir.dir = i->dir;
  211.     smult(ir.dir, hit->t);
  212.     vadd(ir.org, i->org, ir.dir);
  213.  
  214.     o = hit->obj;
  215.  
  216.     o->normal(&n, &ir.org, o, hit->type);
  217.  
  218.     if (dprod(n, i->dir) > 0.0) /* normal facing away from us */
  219.         smult(n, -1.0);
  220.  
  221.     ir.dir = i->dir;
  222.  
  223.     kdfact = o->s.kd;
  224.     ksfact = o->s.ks;
  225.  
  226.     objcol.r = o->s.c.r;
  227.     objcol.g = o->s.c.g;
  228.     objcol.b = o->s.c.b;
  229.  
  230.     for (tp = o->s.txtlist; tp != (tlist *)NULL; tp = tp->nxt)
  231.         tp->txtcol(o, &tp->txt, &ir.org, &n, &objcol, hit->type);
  232.  
  233.     pix->r = objcol.r * o->s.a.r;
  234.     pix->g = objcol.g * o->s.a.g;
  235.     pix->b = objcol.b * o->s.a.b;
  236.  
  237.     for (l = lights; l != (light *)NULL; l = l->nxt)
  238.         for (count = 0; count != l->rays; count++) { 
  239.             if (checklight(l, &ir.org, &lr, &othercol, hitlevel)) {
  240.                 prod = dprod(n, lr.dir);
  241.                 if (prod > 0.0) {
  242.                     fact = prod * kdfact;
  243.                     pix->r += fact * objcol.r * othercol.r;
  244.                     pix->g += fact * objcol.g * othercol.g;
  245.                     pix->b += fact * objcol.b * othercol.b;
  246.                     if (o->s.ks != 0.0) {
  247.                         ns = n;
  248.                         smult(ns, -2 * prod);
  249.                         vadd(mid, lr.dir, ns);
  250.                         normalise(mid);
  251.                         fact = dprod(ir.dir, mid);
  252.                         if (fact > 0.0) {
  253.                             fact = power(fact, o->s.ksexp) * ksfact;
  254.                             pix->r += fact * othercol.r;
  255.                             pix->g += fact * othercol.g;
  256.                             pix->b += fact * othercol.b;
  257.                         }
  258.                     }
  259.                 }
  260.             }
  261.         }
  262.  
  263.     if (o->s.refl != 0.0 && hitlevel < maxhitlevel) {
  264.  
  265.         prod = 2 * dprod(ir.dir, n);
  266.         smult(n, prod);
  267.         vsub(ir.dir, ir.dir, n);
  268.         normalise(ir.dir);
  269.  
  270.         ir.raynumber = raynumber++;
  271.  
  272.         nxthit = trace(&ir, oblist);
  273.  
  274.         fact = o->s.refl;
  275.  
  276.         if (nxthit != (hlist *)NULL) {
  277.             shade(&objcol, &ir, nxthit, hitlevel + 1);
  278.             pix->r += fact * objcol.r;
  279.             pix->g += fact * objcol.g;
  280.             pix->b += fact * objcol.b;
  281.         } else {
  282.             pix->r += fact * backcol.r;
  283.             pix->g += fact * backcol.g;
  284.             pix->b += fact * backcol.b;
  285.         }
  286.  
  287.         for (lp = nxthit; lp != (hlist *)NULL; lp = p) {
  288.             p = lp->nxt;
  289.             release(lp);
  290.         }
  291.     }
  292.  
  293.     if (o->s.trans != 0.0 && hitlevel < maxhitlevel) {
  294.         fact = o->s.trans;
  295.  
  296.         pix->r = (1.0 - fact) * pix->r;
  297.         pix->g = (1.0 - fact) * pix->g;
  298.         pix->b = (1.0 - fact) * pix->b;
  299.  
  300.         ir.dir = i->dir;
  301.  
  302.         ir.raynumber = raynumber++;
  303.  
  304.         nxthit = trace(&ir, oblist);
  305.  
  306.         if (nxthit != (hlist *)NULL) {
  307.             shade(&objcol, &ir, nxthit, hitlevel + 1);
  308.             pix->r += fact * objcol.r;
  309.             pix->g += fact * objcol.g;
  310.             pix->b += fact * objcol.b;
  311.         } else {
  312.             pix->r += fact * backcol.r;
  313.             pix->g += fact * backcol.g;
  314.             pix->b += fact * backcol.b;
  315.         }
  316.  
  317.         for (lp = nxthit; lp != (hlist *)NULL; lp = p) {
  318.             p = lp->nxt;
  319.             release(lp);
  320.         }
  321.     }
  322.  
  323.     if (pix->r > 1.0) 
  324.         pix->r = 1.0;
  325.     if (pix->g > 1.0)
  326.         pix->g = 1.0;
  327.     if (pix->b > 1.0)
  328.         pix->b = 1.0;
  329. }
  330.