Back to index

radiance  4R0+20100331
func.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: func.c,v 2.23 2009/12/12 00:03:42 greg Exp $";
00003 #endif
00004 /*
00005  *  func.c - interface to calcomp functions.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include <math.h>
00011 
00012 #include  "ray.h"
00013 #include  "paths.h"
00014 #include  "otypes.h"
00015 #include  "func.h"
00016 
00017 
00018 #define  INITFILE    "rayinit.cal"
00019 #define  CALSUF             ".cal"
00020 #define  LCALSUF     4
00021 char  REFVNAME[] = "`FILE_REFCNT";
00022 
00023 XF  unitxf = {                     /* identity transform */
00024        {{1.0, 0.0, 0.0, 0.0},
00025        {0.0, 1.0, 0.0, 0.0},
00026        {0.0, 0.0, 1.0, 0.0},
00027        {0.0, 0.0, 0.0, 1.0}},
00028        1.0
00029 };
00030 
00031 XF  funcxf;                 /* current transformation */
00032 static OBJREC  *fobj = NULL;       /* current function object */
00033 static RAY  *fray = NULL;   /* current function ray */
00034 
00035 static double  l_erf(char *), l_erfc(char *), l_arg(char *);
00036 
00037 
00038 extern MFUNC *
00039 getfunc(      /* get function for this modifier */
00040        OBJREC  *m,
00041        int  ff,
00042        unsigned int  ef,
00043        int  dofwd
00044 )
00045 {
00046        static char  initfile[] = INITFILE;
00047        char  sbuf[MAXSTR];
00048        register char  **arg;
00049        register MFUNC  *f;
00050        int  ne, na;
00051        register int  i;
00052                                    /* check to see if done already */
00053        if ((f = (MFUNC *)m->os) != NULL)
00054               return(f);
00055        fobj = NULL; fray = NULL;
00056        if (initfile[0]) {          /* initialize on first call */
00057               esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_RCONST|E_REDEFW;
00058               esupport &= ~(E_OUTCHAN);
00059               setcontext("");
00060               scompile("Dx=$1;Dy=$2;Dz=$3;", NULL, 0);
00061               scompile("Nx=$4;Ny=$5;Nz=$6;", NULL, 0);
00062               scompile("Px=$7;Py=$8;Pz=$9;", NULL, 0);
00063               scompile("T=$10;Ts=$25;Rdot=$11;", NULL, 0);
00064               scompile("S=$12;Tx=$13;Ty=$14;Tz=$15;", NULL, 0);
00065               scompile("Ix=$16;Iy=$17;Iz=$18;", NULL, 0);
00066               scompile("Jx=$19;Jy=$20;Jz=$21;", NULL, 0);
00067               scompile("Kx=$22;Ky=$23;Kz=$24;", NULL, 0);
00068               scompile("Lu=$26;Lv=$27;", NULL, 0);
00069               funset("arg", 1, '=', l_arg);
00070               funset("erf", 1, ':', l_erf);
00071               funset("erfc", 1, ':', l_erfc);
00072               setnoisefuncs();
00073               setprismfuncs();
00074               loadfunc(initfile);
00075               initfile[0] = '\0';
00076        }
00077        if ((na = m->oargs.nsargs) <= ff)
00078               goto toofew;
00079        arg = m->oargs.sarg;
00080        if ((f = (MFUNC *)calloc(1, sizeof(MFUNC))) == NULL)
00081               goto memerr;
00082        i = strlen(arg[ff]);               /* set up context */
00083        if (i == 1 && arg[ff][0] == '.')
00084               setcontext(f->ctx = "");    /* "." means no file */
00085        else {
00086               strcpy(sbuf,arg[ff]);              /* file name is context */
00087               if (i > LCALSUF && !strcmp(sbuf+i-LCALSUF, CALSUF))
00088                      sbuf[i-LCALSUF] = '\0';     /* remove suffix */
00089               setcontext(f->ctx = savestr(sbuf));
00090               if (!vardefined(REFVNAME)) {       /* file loaded? */
00091                      loadfunc(arg[ff]);
00092                      varset(REFVNAME, '=', 1.0);
00093               } else                      /* reference_count++ */
00094                      varset(REFVNAME, '=', varvalue(REFVNAME)+1.0);
00095        }
00096        curfunc = NULL;                    /* parse expressions */
00097        sprintf(sbuf, "%s \"%s\"", ofun[m->otype].funame, m->oname);
00098        for (i=0, ne=0; ef && i < na; i++, ef>>=1)
00099               if (ef & 1) {               /* flagged as an expression? */
00100                      if (ne >= MAXEXPR)
00101                             objerror(m, INTERNAL, "too many expressions");
00102                      initstr(arg[i], sbuf, 0);
00103                      f->ep[ne++] = getE1();
00104                      if (nextc != EOF)
00105                             syntax("unexpected character");
00106               }
00107        if (ef)
00108               goto toofew;
00109        if (i <= ff)                /* find transform args */
00110               i = ff+1;
00111        while (i < na && arg[i][0] != '-')
00112               i++;
00113        if (i == na)                /* no transform */
00114               f->f = f->b = &unitxf;
00115        else {                      /* get transform */
00116               if ((f->b = (XF *)malloc(sizeof(XF))) == NULL)
00117                      goto memerr;
00118               if (invxf(f->b, na-i, arg+i) != na-i)
00119                      objerror(m, USER, "bad transform");
00120               if (f->b->sca < 0.0)
00121                      f->b->sca = -f->b->sca;
00122               if (dofwd) {                /* do both transforms */
00123                      if ((f->f = (XF *)malloc(sizeof(XF))) == NULL)
00124                             goto memerr;
00125                      xf(f->f, na-i, arg+i);
00126                      if (f->f->sca < 0.0)
00127                             f->f->sca = -f->f->sca;
00128               }
00129        }
00130        m->os = (char *)f;
00131        return(f);
00132 toofew:
00133        objerror(m, USER, "too few string arguments");
00134 memerr:
00135        error(SYSTEM, "out of memory in getfunc");
00136        return NULL; /* pro forma return */
00137 }
00138 
00139 
00140 extern void
00141 freefunc(                   /* free memory associated with modifier */
00142        OBJREC  *m
00143 )
00144 {
00145        register MFUNC  *f;
00146        register int  i;
00147 
00148        if ((f = (MFUNC *)m->os) == NULL)
00149               return;
00150        for (i = 0; f->ep[i] != NULL; i++)
00151               epfree(f->ep[i]);
00152        if (f->ctx[0]) {                   /* done with definitions */
00153               setcontext(f->ctx);
00154               i = varvalue(REFVNAME)-.5;  /* reference_count-- */
00155               if (i > 0)
00156                      varset(REFVNAME, '=', (double)i);
00157               else
00158                      dcleanup(2);         /* remove definitions */
00159               freestr(f->ctx);
00160        }
00161        if (f->b != &unitxf)
00162               free((void *)f->b);
00163        if (f->f != NULL && f->f != &unitxf)
00164               free((void *)f->f);
00165        free((void *)f);
00166        m->os = NULL;
00167 }
00168 
00169 
00170 extern int
00171 setfunc(                    /* set channels for function call */
00172        OBJREC  *m,
00173        register RAY  *r
00174 )
00175 {
00176        static RNUMBER  lastrno = ~0;
00177        register MFUNC  *f;
00178                                    /* get function */
00179        if ((f = (MFUNC *)m->os) == NULL)
00180               objerror(m, CONSISTENCY, "setfunc called before getfunc");
00181                                    /* set evaluator context */
00182        setcontext(f->ctx);
00183                                    /* check to see if matrix set */
00184        if (m == fobj && r->rno == lastrno)
00185               return(0);
00186        fobj = m;
00187        fray = r;
00188        if (r->rox != NULL)
00189               if (f->b != &unitxf) {
00190                      funcxf.sca = r->rox->b.sca * f->b->sca;
00191                      multmat4(funcxf.xfm, r->rox->b.xfm, f->b->xfm);
00192               } else
00193                      funcxf = r->rox->b;
00194        else
00195               funcxf = *(f->b);
00196        lastrno = r->rno;
00197        eclock++;            /* notify expression evaluator */
00198        return(1);
00199 }
00200 
00201 
00202 extern void
00203 loadfunc(                   /* load definition file */
00204        char  *fname
00205 )
00206 {
00207        char  *ffname;
00208 
00209        if ((ffname = getpath(fname, getrlibpath(), R_OK)) == NULL) {
00210               sprintf(errmsg, "cannot find function file \"%s\"", fname);
00211               error(USER, errmsg);
00212        }
00213        fcompile(ffname);
00214 }
00215 
00216 
00217 static double
00218 l_arg(char *nm)                    /* return nth real argument */
00219 {
00220        register int  n;
00221 
00222        if (fobj == NULL)
00223               syntax("arg(n) used in constant expression");
00224 
00225        n = argument(1) + .5;              /* round to integer */
00226 
00227        if (n < 1)
00228               return(fobj->oargs.nfargs);
00229 
00230        if (n > fobj->oargs.nfargs) {
00231               sprintf(errmsg, "missing real argument %d", n);
00232               objerror(fobj, USER, errmsg);
00233        }
00234        return(fobj->oargs.farg[n-1]);
00235 }
00236 
00237 
00238 static double
00239 l_erf(char *nm)                    /* error function */
00240 {
00241        return(erf(argument(1)));
00242 }
00243 
00244 
00245 static double
00246 l_erfc(char *nm)            /* cumulative error function */
00247 {
00248        return(erfc(argument(1)));
00249 }
00250 
00251 
00252 extern double
00253 chanvalue(                  /* return channel n to calcomp */
00254        register int  n
00255 )
00256 {
00257        if (fray == NULL)
00258               syntax("ray parameter used in constant expression");
00259 
00260        if (--n < 0)
00261               goto badchan;
00262 
00263        if (n <= 2)                 /* ray direction */
00264 
00265               return( (     fray->rdir[0]*funcxf.xfm[0][n] +
00266                             fray->rdir[1]*funcxf.xfm[1][n] +
00267                             fray->rdir[2]*funcxf.xfm[2][n]     )
00268                       / funcxf.sca );
00269 
00270        if (n <= 5)                 /* surface normal */
00271 
00272               return( (     fray->ron[0]*funcxf.xfm[0][n-3] +
00273                             fray->ron[1]*funcxf.xfm[1][n-3] +
00274                             fray->ron[2]*funcxf.xfm[2][n-3]    )
00275                       / funcxf.sca );
00276 
00277        if (n <= 8)                 /* intersection */
00278 
00279               return( fray->rop[0]*funcxf.xfm[0][n-6] +
00280                             fray->rop[1]*funcxf.xfm[1][n-6] +
00281                             fray->rop[2]*funcxf.xfm[2][n-6] +
00282                                         funcxf.xfm[3][n-6] );
00283 
00284        if (n == 9)                 /* total distance */
00285               return(raydist(fray,PRIMARY) * funcxf.sca);
00286 
00287        if (n == 10)                /* dot product (range [-1,1]) */
00288               return(       fray->rod <= -1.0 ? -1.0 :
00289                      fray->rod >= 1.0 ? 1.0 :
00290                      fray->rod );
00291 
00292        if (n == 11)                /* scale */
00293               return(funcxf.sca);
00294 
00295        if (n <= 14)                /* origin */
00296               return(funcxf.xfm[3][n-12]);
00297 
00298        if (n <= 17)                /* i unit vector */
00299               return(funcxf.xfm[0][n-15] / funcxf.sca);
00300 
00301        if (n <= 20)                /* j unit vector */
00302               return(funcxf.xfm[1][n-18] / funcxf.sca);
00303 
00304        if (n <= 23)                /* k unit vector */
00305               return(funcxf.xfm[2][n-21] / funcxf.sca);
00306 
00307        if (n == 24)                /* single ray (shadow) distance */
00308               return((fray->rot+raydist(fray->parent,SHADOW)) * funcxf.sca);
00309 
00310        if (n <= 26)                /* local (u,v) coordinates */
00311               return(fray->uv[n-25]);
00312 badchan:
00313        error(USER, "illegal channel number");
00314        return(0.0);
00315 }