--- ray/src/rt/m_mist.c 1995/12/08 21:27:10 2.1 +++ ray/src/rt/m_mist.c 2005/04/19 01:15:06 2.17 @@ -1,16 +1,17 @@ -/* Copyright (c) 1995 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: m_mist.c,v 2.17 2005/04/19 01:15:06 greg Exp $"; #endif - /* * Mist volumetric material. */ -#include "ray.h" +#include "copyright.h" +#include + +#include "ray.h" #include "source.h" +#include "rtotypes.h" /* * A mist volume is used to specify a region in the scene where a certain @@ -33,28 +34,33 @@ static char SCCSid[] = "$SunId$ LBL"; * * Up to five real arguments may be given for MAT_MIST: * - * [ext_r ext_g ext_b [albedo [gecc]]] + * [ext_r ext_g ext_b [albedo_r albedo_g albedo_b [gecc]]] * * The primaries indicate medium extinction per unit length (absorption - * plus scattering). The albedo is the ratio of scattering to extinction, + * plus scattering), which is added to the global extinction coefficient, set + * by the -me option. The albedo is the ratio of scattering to extinction, * and is set globally by the -ma option (salbedo) and overridden here. * The Heyney-Greenstein eccentricity parameter (-mg seccg) indicates how much * scattering favors the forward direction. A value of 0 means isotropic * scattering. A value approaching 1 indicates strong forward scattering. */ -#define MAXSLIST 32 /* maximum sources to check */ +#ifndef MAXSLIST +#define MAXSLIST 32 /* maximum sources to check */ +#endif + #define RELAYDELIM '>' /* relay delimiter character */ -extern COLOR cextinction; /* global coefficient of extinction */ -extern double salbedo; /* global scattering albedo */ -extern double seccg; /* global scattering eccentricity */ +static int inslist(int *sl, int n); +static int srcmatch(SRCREC *sp, char *id); +static void add2slist(RAY *r, int *sl); static int -inslist(sl, n) /* return index of source n if it's in list sl */ -register int *sl; -register int n; +inslist( /* return index of source n if it's in list sl */ + register int *sl, + register int n +) { register int i; @@ -66,38 +72,56 @@ register int n; static int -srcmatch(sn, id) /* check for an id match on a light source */ -register int sn; -char *id; +srcmatch( /* check for an id match on a light source */ + register SRCREC *sp, + register char *id +) { - extern char *index(); register char *cp; -again: - if (source[sn].so == NULL) /* just in case */ - return(0); - if ((cp = index(id, RELAYDELIM)) != NULL) { /* relay source */ - if (!(source[sn].sflags & SVIRTUAL)) + /* check for relay sources */ + while ((cp = strchr(id, RELAYDELIM)) != NULL) { + if (!(sp->sflags & SVIRTUAL) || sp->so == NULL) return(0); - *cp = '\0'; - if (strcmp(id, source[sn].so->oname)) { - *cp = RELAYDELIM; + if (strncmp(id, sp->so->oname, cp-id) || sp->so->oname[cp-id]) return(0); - } - *cp = RELAYDELIM; - id = cp + 1; /* recurse */ - sn = source[sn].sa.sv.sn; - goto again; + id = cp + 1; /* relay to next */ + sp = source + sp->sa.sv.sn; } - if (source[sn].sflags & SVIRTUAL) + if (sp->sflags & SVIRTUAL || sp->so == NULL) return(0); - return(!strcmp(id, source[sn].so->oname)); + return(!strcmp(id, sp->so->oname)); } -m_mist(m, r) /* process a ray entering or leaving some mist */ -OBJREC *m; -register RAY *r; +static void +add2slist( /* add source list to ray's */ + register RAY *r, + register int *sl +) { + static int slspare[MAXSLIST+1]; /* in case of emergence */ + register int i; + + if (sl == NULL || sl[0] == 0) /* nothing to add */ + return; + if (r->slights == NULL) + (r->slights = slspare)[0] = 0; /* just once per ray path */ + for (i = sl[0]; i > 0; i--) + if (!inslist(r->slights, sl[i])) { + if (r->slights[0] >= MAXSLIST) + error(INTERNAL, + "scattering source list overflow"); + r->slights[++r->slights[0]] = sl[i]; + } +} + + +extern int +m_mist( /* process a ray entering or leaving some mist */ + OBJREC *m, + register RAY *r +) +{ RAY p; int *myslist = NULL; int newslist[MAXSLIST+1]; @@ -105,27 +129,31 @@ register RAY *r; double re, ge, be; register int i, j; /* check arguments */ - if (m->oargs.nfargs > 5) + if (m->oargs.nfargs > 7) objerror(m, USER, "bad arguments"); - if (m->oargs.nsargs > MAXSLIST) - objerror(m, USER, "too many sources in list"); /* get source indices */ if (m->oargs.nsargs > 0 && (myslist = (int *)m->os) == NULL) { + if (m->oargs.nsargs > MAXSLIST) + objerror(m, INTERNAL, "too many sources in list"); myslist = (int *)malloc((m->oargs.nsargs+1)*sizeof(int)); if (myslist == NULL) goto memerr; - myslist[0] = m->oargs.nsargs; /* size is first in set */ - for (j = myslist[0]; j > 0; j--) { + myslist[0] = 0; /* size is first in list */ + for (j = 0; j < m->oargs.nsargs; j++) { i = nsources; /* look up each source id */ while (i--) - if (srcmatch(i, m->oargs.sarg[j-1])) + if (srcmatch(source+i, m->oargs.sarg[j])) break; if (i < 0) { sprintf(errmsg, "unknown source \"%s\"", - m->oargs.sarg[j-1]); + m->oargs.sarg[j]); objerror(m, WARNING, errmsg); + } else if (inslist(myslist, i)) { + sprintf(errmsg, "duplicate source \"%s\"", + m->oargs.sarg[j]); + objerror(m, WARNING, errmsg); } else - myslist[j] = i; + myslist[++myslist[0]] = i; } m->os = (char *)myslist; } @@ -137,49 +165,56 @@ register RAY *r; } else setcolor(mext, 0., 0., 0.); /* start transmitted ray */ - if (rayorigin(&p, r, TRANS, 1.) < 0) + if (rayorigin(&p, TRANS, r, NULL) < 0) return(1); VCOPY(p.rdir, r->rdir); p.slights = newslist; - if (r->slights != NULL) + if (r->slights != NULL) /* copy old list if one */ for (j = r->slights[0]; j >= 0; j--) p.slights[j] = r->slights[j]; else p.slights[0] = 0; if (r->rod > 0.) { /* entering ray */ addcolor(p.cext, mext); - if (m->oargs.nfargs > 3) - p.albedo = m->oargs.farg[3]; - if (m->oargs.nfargs > 4) - p.gecc = m->oargs.farg[4]; - if (myslist != NULL) /* add to list */ - for (j = myslist[0]; j > 0; j--) - if (!inslist(p.slights, myslist[j])) { - if (p.slights[0] >= MAXSLIST) - error(USER, - "scattering source list overflow"); - p.slights[++p.slights[0]] = myslist[j]; - } + if (m->oargs.nfargs > 5) + setcolor(p.albedo, m->oargs.farg[3], + m->oargs.farg[4], m->oargs.farg[5]); + if (m->oargs.nfargs > 6) + p.gecc = m->oargs.farg[6]; + add2slist(&p, myslist); /* add to list */ } else { /* leaving ray */ - re = colval(r->cext,RED) - colval(mext,RED); - ge = colval(r->cext,GRN) - colval(mext,GRN); - be = colval(r->cext,BLU) - colval(mext,BLU); - setcolor(p.cext, re<0. ? 0. : re, - ge<0. ? 0. : ge, - be<0. ? 0. : be); - if (m->oargs.nfargs > 3) - p.albedo = salbedo; - if (m->oargs.nfargs > 4) - p.gecc = seccg; if (myslist != NULL) { /* delete from list */ for (j = myslist[0]; j > 0; j--) - if (i = inslist(p.slights, myslist[j])) + if ( (i = inslist(p.slights, myslist[j])) ) p.slights[i] = -1; for (i = 0, j = 1; j <= p.slights[0]; j++) if (p.slights[j] != -1) p.slights[++i] = p.slights[j]; + if (p.slights[0] - i < myslist[0]) { /* fix old */ + addcolor(r->cext, mext); + if (m->oargs.nfargs > 5) + setcolor(r->albedo, m->oargs.farg[3], + m->oargs.farg[4], m->oargs.farg[5]); + if (m->oargs.nfargs > 6) + r->gecc = m->oargs.farg[6]; + add2slist(r, myslist); + } p.slights[0] = i; } + if ((re = colval(r->cext,RED) - colval(mext,RED)) < + colval(cextinction,RED)) + re = colval(cextinction,RED); + if ((ge = colval(r->cext,GRN) - colval(mext,GRN)) < + colval(cextinction,GRN)) + ge = colval(cextinction,GRN); + if ((be = colval(r->cext,BLU) - colval(mext,BLU)) < + colval(cextinction,BLU)) + be = colval(cextinction,BLU); + setcolor(p.cext, re, ge, be); + if (m->oargs.nfargs > 5) + copycolor(p.albedo, salbedo); + if (m->oargs.nfargs > 6) + p.gecc = seccg; } rayvalue(&p); /* calls rayparticipate() */ copycolor(r->rcol, p.rcol); /* return value */ @@ -187,4 +222,5 @@ register RAY *r; return(1); memerr: error(SYSTEM, "out of memory in m_mist"); + return 0; /* pro forma return */ }