Page MenuHomec4science

m_direct.c
No OneTemporary

File Metadata

Created
Sun, May 26, 03:39

m_direct.c

#ifndef lint
static const char RCSid[] = "$Id: m_direct.c,v 2.16 2018/11/13 19:58:33 greg Exp $";
#endif
/*
* Routines for light-redirecting materials and
* their associated virtual light sources
*/
#include "copyright.h"
#include "ray.h"
#include "otypes.h"
#include "rtotypes.h"
#include "source.h"
#include "func.h"
/*
* The arguments for MAT_DIRECT1 are:
*
* 5+ coef1 dx1 dy1 dz1 funcfile transform..
* 0
* n A1 A2 .. An
*
* The arguments for MAT_DIRECT2 are:
*
* 9+ coef1 dx1 dy1 dz1 coef2 dx2 dy2 dz2 funcfile transform..
* 0
* n A1 A2 .. An
*/
static int redirect(OBJREC *m, RAY *r, int n);
static int dir_proj(MAT4 pm, OBJREC *o, SRCREC *s, int n);
VSMATERIAL direct1_vs = {dir_proj, 1};
VSMATERIAL direct2_vs = {dir_proj, 2};
#define getdfunc(m) ( (m)->otype == MAT_DIRECT1 ? \
getfunc(m, 4, 0xf, 1) : \
getfunc(m, 8, 0xff, 1) )
int
m_direct( /* shade redirected ray */
OBJREC *m,
RAY *r
)
{
/* check if source ray */
if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
return(1); /* got the wrong guy */
/* compute first projection */
if (m->otype == MAT_DIRECT1 ||
(r->rsrc < 0 || source[r->rsrc].sa.sv.pn == 0))
redirect(m, r, 0);
/* compute second projection */
if (m->otype == MAT_DIRECT2 &&
(r->rsrc < 0 || source[r->rsrc].sa.sv.pn == 1))
redirect(m, r, 1);
return(1);
}
static int
redirect( /* compute n'th ray redirection */
OBJREC *m,
RAY *r,
int n
)
{
MFUNC *mf;
EPNODE **va;
FVECT nsdir;
RAY nr;
double coef;
int j;
/* set up function */
mf = getdfunc(m);
setfunc(m, r);
/* assign direction variable */
if (r->rsrc >= 0) {
SRCREC *sp = source + source[r->rsrc].sa.sv.sn;
if (sp->sflags & SDISTANT)
VCOPY(nsdir, sp->sloc);
else {
for (j = 0; j < 3; j++)
nsdir[j] = sp->sloc[j] - r->rop[j];
normalize(nsdir);
}
multv3(nsdir, nsdir, funcxf.xfm);
varset("DxA", '=', nsdir[0]/funcxf.sca);
varset("DyA", '=', nsdir[1]/funcxf.sca);
varset("DzA", '=', nsdir[2]/funcxf.sca);
} else {
varset("DxA", '=', 0.0);
varset("DyA", '=', 0.0);
varset("DzA", '=', 0.0);
}
/* compute coefficient */
errno = 0;
va = mf->ep + 4*n;
coef = evalue(va[0]);
if ((errno == EDOM) | (errno == ERANGE))
goto computerr;
setcolor(nr.rcoef, coef, coef, coef);
if (rayorigin(&nr, TRANS, r, nr.rcoef) < 0)
return(0);
va++; /* compute direction */
for (j = 0; j < 3; j++) {
nr.rdir[j] = evalue(va[j]);
if (errno == EDOM || errno == ERANGE)
goto computerr;
}
if (mf->fxp != &unitxf)
multv3(nr.rdir, nr.rdir, mf->fxp->xfm);
if (r->rox != NULL)
multv3(nr.rdir, nr.rdir, r->rox->f.xfm);
if (normalize(nr.rdir) == 0.0)
goto computerr;
/* compute value */
if (r->rsrc >= 0)
nr.rsrc = source[r->rsrc].sa.sv.sn;
rayvalue(&nr);
multcolor(nr.rcol, nr.rcoef);
addcolor(r->rcol, nr.rcol);
if (r->ro != NULL && isflat(r->ro->otype))
r->rxt = r->rot + raydistance(&nr);
return(1);
computerr:
objerror(m, WARNING, "compute error");
return(-1);
}
static int
dir_proj( /* compute a director's projection */
MAT4 pm,
OBJREC *o,
SRCREC *s,
int n
)
{
RAY tr;
OBJREC *m;
MFUNC *mf;
EPNODE **va;
FVECT cent, newdir, nv, h;
double coef, olddot, newdot, od;
int i, j;
/* initialize test ray */
getmaxdisk(cent, o);
if (s->sflags & SDISTANT)
for (i = 0; i < 3; i++) {
tr.rdir[i] = -s->sloc[i];
tr.rorg[i] = cent[i] - tr.rdir[i];
}
else {
for (i = 0; i < 3; i++) {
tr.rdir[i] = cent[i] - s->sloc[i];
tr.rorg[i] = s->sloc[i];
}
if (normalize(tr.rdir) == 0.0)
return(0); /* at source! */
}
od = getplaneq(nv, o);
olddot = DOT(tr.rdir, nv);
if (olddot <= FTINY && olddot >= -FTINY)
return(0); /* old dir parallels plane */
tr.rmax = 0.0;
rayorigin(&tr, PRIMARY, NULL, NULL);
if (!(*ofun[o->otype].funp)(o, &tr))
return(0); /* no intersection! */
/* compute redirection */
m = vsmaterial(o);
mf = getdfunc(m);
setfunc(m, &tr);
varset("DxA", '=', 0.0);
varset("DyA", '=', 0.0);
varset("DzA", '=', 0.0);
errno = 0;
va = mf->ep + 4*n;
coef = evalue(va[0]);
if (errno == EDOM || errno == ERANGE)
goto computerr;
if (coef <= FTINY)
return(0); /* insignificant */
va++;
for (i = 0; i < 3; i++) {
newdir[i] = evalue(va[i]);
if (errno == EDOM || errno == ERANGE)
goto computerr;
}
if (mf->fxp != &unitxf)
multv3(newdir, newdir, mf->fxp->xfm);
/* normalization unnecessary */
newdot = DOT(newdir, nv);
if (newdot <= FTINY && newdot >= -FTINY)
return(0); /* new dir parallels plane */
/* everything OK -- compute shear */
for (i = 0; i < 3; i++)
h[i] = newdir[i]/newdot - tr.rdir[i]/olddot;
setident4(pm);
for (j = 0; j < 3; j++) {
for (i = 0; i < 3; i++)
pm[i][j] += nv[i]*h[j];
pm[3][j] = -od*h[j];
}
if ((newdot > 0.0) ^ (olddot > 0.0)) /* add mirroring */
for (j = 0; j < 3; j++) {
for (i = 0; i < 3; i++)
pm[i][j] -= 2.*nv[i]*nv[j];
pm[3][j] += 2.*od*nv[j];
}
return(1);
computerr:
objerror(m, WARNING, "projection compute error");
return(0);
}

Event Timeline