home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
RADIANCE
/
SRC
/
RT
/
FUNC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-07
|
8KB
|
321 lines
/* Copyright (c) 1992 Regents of the University of California */
#ifndef lint
static char SCCSid[] = "@(#)func.c 2.7 9/26/92 LBL";
#endif
/*
* func.c - interface to calcomp functions.
*
* 4/7/86
*/
#include "ray.h"
#include "otypes.h"
#include "func.h"
#define INITFILE "rayinit.cal"
#define REFVNAME "`FILE_REFCNT"
#define CALSUF ".cal"
#define LCALSUF 4
XF unitxf = { /* identity transform */
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
1.0
};
XF funcxf; /* current transformation */
static OBJREC *fobj = NULL; /* current function object */
static RAY *fray = NULL; /* current function ray */
static double l_erf(), l_erfc(), l_arg();
MFUNC *
getfunc(m, ff, ef, dofwd) /* get function for this modifier */
OBJREC *m;
int ff;
unsigned ef;
int dofwd;
{
extern EPNODE *curfunc;
static char initfile[] = INITFILE;
char sbuf[MAXSTR];
register char **arg;
register MFUNC *f;
int ne, na;
register int i;
/* check to see if done already */
if ((f = (MFUNC *)m->os) != NULL)
return(f);
fobj = NULL; fray = NULL;
if (initfile[0]) { /* initialize on first call */
setcontext("");
scompile("Dx=$1;Dy=$2;Dz=$3;", NULL, 0);
scompile("Nx=$4;Ny=$5;Nz=$6;", NULL, 0);
scompile("Px=$7;Py=$8;Pz=$9;", NULL, 0);
scompile("T=$10;Ts=$25;Rdot=$11;", NULL, 0);
scompile("S=$12;Tx=$13;Ty=$14;Tz=$15;", NULL, 0);
scompile("Ix=$16;Iy=$17;Iz=$18;", NULL, 0);
scompile("Jx=$19;Jy=$20;Jz=$21;", NULL, 0);
scompile("Kx=$22;Ky=$23;Kz=$24;", NULL, 0);
funset("arg", 1, '=', l_arg);
funset("erf", 1, ':', l_erf);
funset("erfc", 1, ':', l_erfc);
setnoisefuncs();
loadfunc(initfile);
initfile[0] = '\0';
}
if ((na = m->oargs.nsargs) <= ff)
goto toofew;
arg = m->oargs.sarg;
if ((f = (MFUNC *)calloc(1, sizeof(MFUNC))) == NULL)
goto memerr;
i = strlen(arg[ff]); /* set up context */
if (i == 1 && arg[ff][0] == '.')
setcontext(f->ctx = ""); /* "." means no file */
else {
strcpy(sbuf,arg[ff]); /* file name is context */
if (i > LCALSUF && !strcmp(sbuf+i-LCALSUF, CALSUF))
sbuf[i-LCALSUF] = '\0'; /* remove suffix */
setcontext(f->ctx = savestr(sbuf));
if (!vardefined(REFVNAME)) { /* file loaded? */
loadfunc(arg[ff]);
varset(REFVNAME, '=', 1.0);
} else /* reference_count++ */
varset(REFVNAME, '=', varvalue(REFVNAME)+1.0);
}
curfunc = NULL; /* parse expressions */
sprintf(sbuf, "%s \"%s\"", ofun[m->otype].funame, m->oname);
for (i=0, ne=0; ef && i < na; i++, ef>>=1)
if (ef & 1) { /* flagged as an expression? */
if (ne >= MAXEXPR)
objerror(m, INTERNAL, "too many expressions");
initstr(arg[i], sbuf, 0);
f->ep[ne++] = getE1();
if (nextc != EOF)
syntax("unexpected character");
}
if (ef)
goto toofew;
if (i <= ff) /* find transform args */
i = ff+1;
while (i < na && arg[i][0] != '-')
i++;
if (i == na) /* no transform */
f->f = f->b = &unitxf;
else { /* get transform */
if ((f->b = (XF *)malloc(sizeof(XF))) == NULL)
goto memerr;
if (invxf(f->b, na-i, arg+i) != na-i)
objerror(m, USER, "bad transform");
if (f->b->sca < 0.0)
f->b->sca = -f->b->sca;
if (dofwd) { /* do both transforms */
if ((f->f = (XF *)malloc(sizeof(XF))) == NULL)
goto memerr;
xf(f->f, na-i, arg+i);
if (f->f->sca < 0.0)
f->f->sca = -f->f->sca;
}
}
m->os = (char *)f;
return(f);
toofew:
objerror(m, USER, "too few string arguments");
memerr:
error(SYSTEM, "out of memory in getfunc");
}
freefunc(m) /* free memory associated with modifier */
OBJREC *m;
{
register MFUNC *f;
register int i;
if ((f = (MFUNC *)m->os) == NULL)
return;
for (i = 0; f->ep[i] != NULL; i++)
epfree(f->ep[i]);
if (f->ctx[0]) { /* done with definitions */
setcontext(f->ctx);
i = varvalue(REFVNAME)-.5; /* reference_count-- */
if (i > 0)
varset(REFVNAME, '=', (double)i);
else
dcleanup(2); /* remove definitions */
freestr(f->ctx);
}
if (f->b != &unitxf)
free((char *)f->b);
if (f->f != NULL && f->f != &unitxf)
free((char *)f->f);
free((char *)f);
m->os = NULL;
}
setfunc(m, r) /* set channels for function call */
OBJREC *m;
register RAY *r;
{
static long lastrno = -1;
register MFUNC *f;
/* get function */
if ((f = (MFUNC *)m->os) == NULL)
error(m, CONSISTENCY, "setfunc called before getfunc");
/* set evaluator context */
setcontext(f->ctx);
/* check to see if matrix set */
if (m == fobj && r->rno == lastrno)
return(0);
fobj = m;
fray = r;
if (r->rox != NULL)
if (f->b != &unitxf) {
funcxf.sca = r->rox->b.sca * f->b->sca;
multmat4(funcxf.xfm, r->rox->b.xfm, f->b->xfm);
} else
copystruct(&funcxf, &r->rox->b);
else
copystruct(&funcxf, f->b);
lastrno = r->rno;
eclock++; /* notify expression evaluator */
return(1);
}
loadfunc(fname) /* load definition file */
char *fname;
{
extern char *libpath; /* library search path */
char *ffname;
if ((ffname = getpath(fname, libpath, R_OK)) == NULL) {
sprintf(errmsg, "cannot find function file \"%s\"", fname);
error(USER, errmsg);
}
fcompile(ffname);
}
static double
l_arg() /* return nth real argument */
{
extern double argument();
register int n;
if (fobj == NULL)
syntax("arg(n) used in constant expression");
n = argument(1) + .5; /* round to integer */
if (n < 1)
return(fobj->oargs.nfargs);
if (n > fobj->oargs.nfargs) {
sprintf(errmsg, "missing real argument %d", n);
objerror(fobj, USER, errmsg);
}
return(fobj->oargs.farg[n-1]);
}
static double
l_erf() /* error function */
{
extern double erf();
return(erf(argument(1)));
}
static double
l_erfc() /* cumulative error function */
{
extern double erfc();
return(erfc(argument(1)));
}
double
chanvalue(n) /* return channel n to calcomp */
register int n;
{
double sum;
register RAY *r;
if (fray == NULL)
syntax("ray parameter used in constant expression");
if (--n < 0)
goto badchan;
if (n < 3) /* ray direction */
return( ( fray->rdir[0]*funcxf.xfm[0][n] +
fray->rdir[1]*funcxf.xfm[1][n] +
fray->rdir[2]*funcxf.xfm[2][n] )
/ funcxf.sca );
if (n < 6) /* surface normal */
return( ( fray->ron[0]*funcxf.xfm[0][n-3] +
fray->ron[1]*funcxf.xfm[1][n-3] +
fray->ron[2]*funcxf.xfm[2][n-3] )
/ funcxf.sca );
if (n < 9) /* intersection */
return( fray->rop[0]*funcxf.xfm[0][n-6] +
fray->rop[1]*funcxf.xfm[1][n-6] +
fray->rop[2]*funcxf.xfm[2][n-6] +
funcxf.xfm[3][n-6] );
if (n == 9) { /* total distance */
sum = fray->rot;
for (r = fray->parent; r != NULL; r = r->parent)
sum += r->rot;
return(sum * funcxf.sca);
}
if (n == 10) /* dot product (range [-1,1]) */
return( fray->rod <= -1.0 ? -1.0 :
fray->rod >= 1.0 ? 1.0 :
fray->rod );
if (n == 11) /* scale */
return(funcxf.sca);
if (n < 15) /* origin */
return(funcxf.xfm[3][n-12]);
if (n < 18) /* i unit vector */
return(funcxf.xfm[0][n-15] / funcxf.sca);
if (n < 21) /* j unit vector */
return(funcxf.xfm[1][n-15] / funcxf.sca);
if (n < 24) /* k unit vector */
return(funcxf.xfm[2][n-21] / funcxf.sca);
if (n == 24) { /* single ray (shadow) distance */
sum = fray->rot;
for (r = fray->parent; r != NULL && r->crtype&SHADOW;
r = r->parent)
sum += r->rot;
return(sum * funcxf.sca);
}
badchan:
error(USER, "illegal channel number");
}