Back to index

radiance  4R0+20100331
m_mist.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: m_mist.c,v 2.17 2005/04/19 01:15:06 greg Exp $";
00003 #endif
00004 /*
00005  * Mist volumetric material.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include <string.h>
00011 
00012 #include  "ray.h"
00013 #include  "source.h"
00014 #include  "rtotypes.h"
00015 
00016 /*
00017  *  A mist volume is used to specify a region in the scene where a certain
00018  *  light source (or sources) is going to contribute to scattering.  The
00019  *  material can add to the existing global medium, and override any ray
00020  *  settings for scattering albedo and eccentricity.  Overlapping mist
00021  *  regions should agree w.r.t. albedo and eccentricity, and
00022  *  should have disjoint source lists.
00023  *
00024  *  A pattern, if used, should compute the line integral of extinction,
00025  *  and will modify the first three arguments directly.  This will tend
00026  *  to invalidate results when there are other objects intersected within
00027  *  the mist region.
00028  *
00029  *  The string arguments for MAT_MIST are the identifiers for the important
00030  *  light sources, which will be looked up in the source array.  The last
00031  *  source found matching a name is the one used.  A relayed light source
00032  *  may be indicated by the relay surface name, followed by a '>' character,
00033  *  followed by the relayed source name (which may be another relay).
00034  *
00035  *  Up to five real arguments may be given for MAT_MIST:
00036  *
00037  *     [ext_r  ext_g  ext_b  [albedo_r albedo_g albedo_b [gecc]]]
00038  *
00039  *  The primaries indicate medium extinction per unit length (absorption
00040  *  plus scattering), which is added to the global extinction coefficient, set
00041  *  by the -me option.  The albedo is the ratio of scattering to extinction,
00042  *  and is set globally by the -ma option (salbedo) and overridden here.
00043  *  The Heyney-Greenstein eccentricity parameter (-mg seccg) indicates how much
00044  *  scattering favors the forward direction.  A value of 0 means isotropic
00045  *  scattering.  A value approaching 1 indicates strong forward scattering.
00046  */
00047 
00048 #ifndef  MAXSLIST
00049 #define  MAXSLIST    32     /* maximum sources to check */
00050 #endif
00051 
00052 #define RELAYDELIM   '>'           /* relay delimiter character */
00053 
00054 static int inslist(int  *sl, int  n);
00055 static int srcmatch(SRCREC  *sp, char  *id);
00056 static void add2slist(RAY  *r, int  *sl);
00057 
00058 
00059 static int
00060 inslist(             /* return index of source n if it's in list sl */
00061        register int  *sl,
00062        register int  n
00063 )
00064 {
00065        register int  i;
00066 
00067        for (i = sl[0]; i > 0; i--)
00068               if (sl[i] == n)
00069                      return(i);
00070        return(0);
00071 }
00072 
00073 
00074 static int
00075 srcmatch(     /* check for an id match on a light source */
00076        register SRCREC  *sp,
00077        register char  *id
00078 )
00079 {
00080        register char  *cp;
00081                                           /* check for relay sources */
00082        while ((cp = strchr(id, RELAYDELIM)) != NULL) {
00083               if (!(sp->sflags & SVIRTUAL) || sp->so == NULL)
00084                      return(0);
00085               if (strncmp(id, sp->so->oname, cp-id) || sp->so->oname[cp-id])
00086                      return(0);
00087               id = cp + 1;                       /* relay to next */
00088               sp = source + sp->sa.sv.sn;
00089        }
00090        if (sp->sflags & SVIRTUAL || sp->so == NULL)
00091               return(0);
00092        return(!strcmp(id, sp->so->oname));
00093 }
00094 
00095 
00096 static void
00097 add2slist(    /* add source list to ray's */
00098        register RAY  *r,
00099        register int  *sl
00100 )
00101 {
00102        static int  slspare[MAXSLIST+1];   /* in case of emergence */
00103        register int  i;
00104 
00105        if (sl == NULL || sl[0] == 0)             /* nothing to add */
00106               return;
00107        if (r->slights == NULL)
00108               (r->slights = slspare)[0] = 0;     /* just once per ray path */
00109        for (i = sl[0]; i > 0; i--)
00110               if (!inslist(r->slights, sl[i])) {
00111                      if (r->slights[0] >= MAXSLIST)
00112                             error(INTERNAL,
00113                                    "scattering source list overflow");
00114                      r->slights[++r->slights[0]] = sl[i];
00115               }
00116 }
00117 
00118 
00119 extern int
00120 m_mist(              /* process a ray entering or leaving some mist */
00121        OBJREC  *m,
00122        register RAY  *r
00123 )
00124 {
00125        RAY  p;
00126        int  *myslist = NULL;
00127        int  newslist[MAXSLIST+1];
00128        COLOR  mext;
00129        double  re, ge, be;
00130        register int  i, j;
00131                                    /* check arguments */
00132        if (m->oargs.nfargs > 7)
00133               objerror(m, USER, "bad arguments");
00134                                    /* get source indices */
00135        if (m->oargs.nsargs > 0 && (myslist = (int *)m->os) == NULL) {
00136               if (m->oargs.nsargs > MAXSLIST)
00137                      objerror(m, INTERNAL, "too many sources in list");
00138               myslist = (int *)malloc((m->oargs.nsargs+1)*sizeof(int));
00139               if (myslist == NULL)
00140                      goto memerr;
00141               myslist[0] = 0;                    /* size is first in list */
00142               for (j = 0; j < m->oargs.nsargs; j++) {
00143                      i = nsources;        /* look up each source id */
00144                      while (i--)
00145                             if (srcmatch(source+i, m->oargs.sarg[j]))
00146                                    break;
00147                      if (i < 0) {
00148                             sprintf(errmsg, "unknown source \"%s\"",
00149                                           m->oargs.sarg[j]);
00150                             objerror(m, WARNING, errmsg);
00151                      } else if (inslist(myslist, i)) {
00152                             sprintf(errmsg, "duplicate source \"%s\"",
00153                                           m->oargs.sarg[j]);
00154                             objerror(m, WARNING, errmsg);
00155                      } else
00156                             myslist[++myslist[0]] = i;
00157               }
00158               m->os = (char *)myslist;
00159        }
00160        if (m->oargs.nfargs > 2) {         /* compute extinction */
00161               setcolor(mext, m->oargs.farg[0], m->oargs.farg[1],
00162                             m->oargs.farg[2]);
00163               raytexture(r, m->omod);                   /* get modifiers */
00164               multcolor(mext, r->pcol);
00165        } else
00166               setcolor(mext, 0., 0., 0.);
00167                                           /* start transmitted ray */
00168        if (rayorigin(&p, TRANS, r, NULL) < 0)
00169               return(1);
00170        VCOPY(p.rdir, r->rdir);
00171        p.slights = newslist;
00172        if (r->slights != NULL)                   /* copy old list if one */
00173               for (j = r->slights[0]; j >= 0; j--)
00174                      p.slights[j] = r->slights[j];
00175        else
00176               p.slights[0] = 0;
00177        if (r->rod > 0.) {                 /* entering ray */
00178               addcolor(p.cext, mext);
00179               if (m->oargs.nfargs > 5)
00180                      setcolor(p.albedo, m->oargs.farg[3],
00181                                    m->oargs.farg[4], m->oargs.farg[5]);
00182               if (m->oargs.nfargs > 6)
00183                      p.gecc = m->oargs.farg[6];
00184               add2slist(&p, myslist);                   /* add to list */
00185        } else {                           /* leaving ray */
00186               if (myslist != NULL) {                    /* delete from list */
00187                      for (j = myslist[0]; j > 0; j--)
00188                             if ( (i = inslist(p.slights, myslist[j])) )
00189                                    p.slights[i] = -1;
00190                      for (i = 0, j = 1; j <= p.slights[0]; j++)
00191                             if (p.slights[j] != -1)
00192                                    p.slights[++i] = p.slights[j];
00193                      if (p.slights[0] - i < myslist[0]) {      /* fix old */
00194                             addcolor(r->cext, mext);
00195                             if (m->oargs.nfargs > 5)
00196                                    setcolor(r->albedo, m->oargs.farg[3],
00197                                    m->oargs.farg[4], m->oargs.farg[5]);
00198                             if (m->oargs.nfargs > 6)
00199                                    r->gecc = m->oargs.farg[6];
00200                             add2slist(r, myslist);
00201                      }
00202                      p.slights[0] = i;
00203               }
00204               if ((re = colval(r->cext,RED) - colval(mext,RED)) <
00205                             colval(cextinction,RED))
00206                      re = colval(cextinction,RED);
00207               if ((ge = colval(r->cext,GRN) - colval(mext,GRN)) <
00208                             colval(cextinction,GRN))
00209                      ge = colval(cextinction,GRN);
00210               if ((be = colval(r->cext,BLU) - colval(mext,BLU)) <
00211                             colval(cextinction,BLU))
00212                      be = colval(cextinction,BLU);
00213               setcolor(p.cext, re, ge, be);
00214               if (m->oargs.nfargs > 5)
00215                      copycolor(p.albedo, salbedo);
00216               if (m->oargs.nfargs > 6)
00217                      p.gecc = seccg;
00218        }
00219        rayvalue(&p);                      /* calls rayparticipate() */
00220        copycolor(r->rcol, p.rcol);        /* return value */
00221        r->rt = r->rot + p.rt;
00222        return(1);
00223 memerr:
00224        error(SYSTEM, "out of memory in m_mist");
00225        return 0; /* pro forma return */
00226 }