Back to index

radiance  4R0+20100331
parser.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: parser.c,v 1.28 2003/11/15 17:54:06 schorsch Exp $";
00003 #endif
00004 /*
00005  * Parse an MGF file, converting or discarding unsupported entities
00006  */
00007 
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <math.h>
00011 #include <ctype.h>
00012 #include <string.h>
00013 #include "parser.h"
00014 #include "lookup.h"
00015 #include "messages.h"
00016 
00017 /*
00018  * Global definitions of variables declared in parser.h
00019  */
00020                      /* entity names */
00021 
00022 char   mg_ename[MG_NENTITIES][MG_MAXELEN] = MG_NAMELIST;
00023 
00024                      /* Handler routines for each entity */
00025 
00026 int    (*mg_ehand[MG_NENTITIES])();
00027 
00028                      /* Handler routine for unknown entities */
00029 
00030 int    (*mg_uhand)() = mg_defuhand;
00031 
00032 unsigned      mg_nunknown;  /* count of unknown entities */
00033 
00034                      /* error messages */
00035 
00036 char   *mg_err[MG_NERRS] = MG_ERRLIST;
00037 
00038 MG_FCTXT      *mg_file;     /* current file context pointer */
00039 
00040 int    mg_nqcdivs = MG_NQCD;       /* number of divisions per quarter circle */
00041 
00042 /*
00043  * The idea with this parser is to compensate for any missing entries in
00044  * mg_ehand with alternate handlers that express these entities in terms
00045  * of others that the calling program can handle.
00046  * 
00047  * In some cases, no alternate handler is possible because the entity
00048  * has no approximate equivalent.  These entities are simply discarded.
00049  *
00050  * Certain entities are dependent on others, and mg_init() will fail
00051  * if the supported entities are not consistent.
00052  *
00053  * Some alternate entity handlers require that earlier entities be
00054  * noted in some fashion, and we therefore keep another array of
00055  * parallel support handlers to assist in this effort.
00056  */
00057 
00058 /* temporary settings for testing */
00059 #define e_ies e_any_toss
00060                             /* alternate handler routines */
00061 
00062 static void make_axes(FVECT u, FVECT v, FVECT w);
00063 static int put_cxy(void);
00064 static int put_cspec(void);
00065 
00066 static int e_any_toss(int ac, char **av); /* discard an unwanted entity */
00067 static int e_cspec(int ac, char **av); /* handle spectral color */
00068 static int e_cmix(int ac, char **av); /* handle mixing of colors */
00069 static int e_cct(int ac, char **av); /* handle color temperature */
00070 
00071 
00072                             /* alternate handler support functions */
00073 
00074 static int    (*e_supp[MG_NENTITIES])(int ac, char **av);
00075 
00076 static char   FLTFMT[] = "%.12g";
00077 
00078 static int    warpconends;         /* hack for generating good normals */
00079 
00080 
00081 void
00082 mg_init(void)               /* initialize alternate entity handlers */
00083 {
00084        unsigned long ineed = 0, uneed = 0;
00085        register int  i;
00086                                    /* pick up slack */
00087        if (mg_ehand[MG_E_IES] == NULL)
00088               mg_ehand[MG_E_IES] = e_ies;
00089        if (mg_ehand[MG_E_INCLUDE] == NULL)
00090               mg_ehand[MG_E_INCLUDE] = e_include;
00091        if (mg_ehand[MG_E_SPH] == NULL) {
00092               mg_ehand[MG_E_SPH] = e_sph;
00093               ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
00094        } else
00095               uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
00096        if (mg_ehand[MG_E_CYL] == NULL) {
00097               mg_ehand[MG_E_CYL] = e_cyl;
00098               ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
00099        } else
00100               uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
00101        if (mg_ehand[MG_E_CONE] == NULL) {
00102               mg_ehand[MG_E_CONE] = e_cone;
00103               ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
00104        } else
00105               uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
00106        if (mg_ehand[MG_E_RING] == NULL) {
00107               mg_ehand[MG_E_RING] = e_ring;
00108               ineed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX;
00109        } else
00110               uneed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX|1L<<MG_E_XF;
00111        if (mg_ehand[MG_E_PRISM] == NULL) {
00112               mg_ehand[MG_E_PRISM] = e_prism;
00113               ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
00114        } else
00115               uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
00116        if (mg_ehand[MG_E_TORUS] == NULL) {
00117               mg_ehand[MG_E_TORUS] = e_torus;
00118               ineed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX;
00119        } else
00120               uneed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX|1L<<MG_E_XF;
00121        if (mg_ehand[MG_E_FACE] == NULL)
00122               mg_ehand[MG_E_FACE] = mg_ehand[MG_E_FACEH];
00123        else if (mg_ehand[MG_E_FACEH] == NULL)
00124               mg_ehand[MG_E_FACEH] = e_faceh;
00125        if (mg_ehand[MG_E_COLOR] != NULL) {
00126               if (mg_ehand[MG_E_CMIX] == NULL) {
00127                      mg_ehand[MG_E_CMIX] = e_cmix;
00128                      ineed |= 1L<<MG_E_COLOR|1L<<MG_E_CXY|1L<<MG_E_CSPEC|1L<<MG_E_CMIX|1L<<MG_E_CCT;
00129               }
00130               if (mg_ehand[MG_E_CSPEC] == NULL) {
00131                      mg_ehand[MG_E_CSPEC] = e_cspec;
00132                      ineed |= 1L<<MG_E_COLOR|1L<<MG_E_CXY|1L<<MG_E_CSPEC|1L<<MG_E_CMIX|1L<<MG_E_CCT;
00133               }
00134               if (mg_ehand[MG_E_CCT] == NULL) {
00135                      mg_ehand[MG_E_CCT] = e_cct;
00136                      ineed |= 1L<<MG_E_COLOR|1L<<MG_E_CXY|1L<<MG_E_CSPEC|1L<<MG_E_CMIX|1L<<MG_E_CCT;
00137               }
00138        }
00139                                    /* check for consistency */
00140        if (mg_ehand[MG_E_FACE] != NULL)
00141               uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
00142        if (mg_ehand[MG_E_CXY] != NULL || mg_ehand[MG_E_CSPEC] != NULL ||
00143                      mg_ehand[MG_E_CMIX] != NULL)
00144               uneed |= 1L<<MG_E_COLOR;
00145        if (mg_ehand[MG_E_RD] != NULL || mg_ehand[MG_E_TD] != NULL ||
00146                      mg_ehand[MG_E_IR] != NULL ||
00147                      mg_ehand[MG_E_ED] != NULL || 
00148                      mg_ehand[MG_E_RS] != NULL ||
00149                      mg_ehand[MG_E_TS] != NULL ||
00150                      mg_ehand[MG_E_SIDES] != NULL)
00151               uneed |= 1L<<MG_E_MATERIAL;
00152        for (i = 0; i < MG_NENTITIES; i++)
00153               if (uneed & 1L<<i && mg_ehand[i] == NULL) {
00154                      fprintf(stderr, "Missing support for \"%s\" entity\n",
00155                                    mg_ename[i]);
00156                      exit(1);
00157               }
00158                                    /* add support as needed */
00159        if (ineed & 1L<<MG_E_VERTEX && mg_ehand[MG_E_VERTEX] != c_hvertex)
00160               e_supp[MG_E_VERTEX] = c_hvertex;
00161        if (ineed & 1L<<MG_E_POINT && mg_ehand[MG_E_POINT] != c_hvertex)
00162               e_supp[MG_E_POINT] = c_hvertex;
00163        if (ineed & 1L<<MG_E_NORMAL && mg_ehand[MG_E_NORMAL] != c_hvertex)
00164               e_supp[MG_E_NORMAL] = c_hvertex;
00165        if (ineed & 1L<<MG_E_COLOR && mg_ehand[MG_E_COLOR] != c_hcolor)
00166               e_supp[MG_E_COLOR] = c_hcolor;
00167        if (ineed & 1L<<MG_E_CXY && mg_ehand[MG_E_CXY] != c_hcolor)
00168               e_supp[MG_E_CXY] = c_hcolor;
00169        if (ineed & 1L<<MG_E_CSPEC && mg_ehand[MG_E_CSPEC] != c_hcolor)
00170               e_supp[MG_E_CSPEC] = c_hcolor;
00171        if (ineed & 1L<<MG_E_CMIX && mg_ehand[MG_E_CMIX] != c_hcolor)
00172               e_supp[MG_E_CMIX] = c_hcolor;
00173        if (ineed & 1L<<MG_E_CCT && mg_ehand[MG_E_CCT] != c_hcolor)
00174               e_supp[MG_E_CCT] = c_hcolor;
00175                                    /* discard remaining entities */
00176        for (i = 0; i < MG_NENTITIES; i++)
00177               if (mg_ehand[i] == NULL)
00178                      mg_ehand[i] = e_any_toss;
00179 }
00180 
00181 
00182 int
00183 mg_entity(                  /* get entity number from its name */
00184        char   *name
00185 )
00186 {
00187        static LUTAB  ent_tab = LU_SINIT(NULL,NULL);     /* lookup table */
00188        register char *cp;
00189 
00190        if (!ent_tab.tsiz) {        /* initialize hash table */
00191               if (!lu_init(&ent_tab, MG_NENTITIES))
00192                      return(-1);          /* what to do? */
00193               for (cp = mg_ename[MG_NENTITIES-1]; cp >= mg_ename[0];
00194                             cp -= sizeof(mg_ename[0]))
00195                      lu_find(&ent_tab, cp)->key = cp;
00196        }
00197        cp = lu_find(&ent_tab, name)->key;
00198        if (cp == NULL)
00199               return(-1);
00200        return((cp - mg_ename[0])/sizeof(mg_ename[0]));
00201 }
00202 
00203 
00204 int
00205 mg_handle(           /* pass entity to appropriate handler */
00206        register int  en,
00207        int    ac,
00208        char   **av
00209 )
00210 {
00211        int    rv;
00212 
00213        if (en < 0 && (en = mg_entity(av[0])) < 0) {     /* unknown entity */
00214               if (mg_uhand != NULL)
00215                      return((*mg_uhand)(ac, av));
00216               return(MG_EUNK);
00217        }
00218        if (e_supp[en] != NULL) {                 /* support handler */
00219               if ((rv = (*e_supp[en])(ac, av)) != MG_OK)
00220                      return(rv);
00221        }
00222        return((*mg_ehand[en])(ac, av));          /* assigned handler */
00223 }
00224 
00225 
00226 int
00227 mg_open(                    /* open new input file */
00228        register MG_FCTXT    *ctx,
00229        char   *fn
00230 )
00231 {
00232        static int    nfids;
00233        register char *cp;
00234 
00235        ctx->fid = ++nfids;
00236        ctx->lineno = 0;
00237        if (fn == NULL) {
00238               strcpy(ctx->fname, "<stdin>");
00239               ctx->fp = stdin;
00240               ctx->prev = mg_file;
00241               mg_file = ctx;
00242               return(MG_OK);
00243        }
00244                                    /* get name relative to this context */
00245        if (fn[0] != '/' && mg_file != NULL &&
00246                      (cp = strrchr(mg_file->fname, '/')) != NULL) {
00247               strcpy(ctx->fname, mg_file->fname);
00248               strcpy(ctx->fname+(cp-mg_file->fname+1), fn);
00249        } else
00250               strcpy(ctx->fname, fn);
00251        ctx->fp = fopen(ctx->fname, "r");
00252        if (ctx->fp == NULL)
00253               return(MG_ENOFILE);
00254        ctx->prev = mg_file;        /* establish new context */
00255        mg_file = ctx;
00256        return(MG_OK);
00257 }
00258 
00259 
00260 void
00261 mg_close(void)                     /* close input file */
00262 {
00263        register MG_FCTXT    *ctx = mg_file;
00264 
00265        mg_file = ctx->prev;        /* restore enclosing context */
00266        if (ctx->fp != stdin)              /* close file if it's a file */
00267               fclose(ctx->fp);
00268 }
00269 
00270 
00271 void
00272 mg_fgetpos(                 /* get current position in input file */
00273        register MG_FPOS     *pos
00274 )
00275 {
00276        pos->fid = mg_file->fid;
00277        pos->lineno = mg_file->lineno;
00278        pos->offset = ftell(mg_file->fp);
00279 }
00280 
00281 
00282 int
00283 mg_fgoto(                   /* reposition input file pointer */
00284        register MG_FPOS     *pos
00285 )
00286 {
00287        if (pos->fid != mg_file->fid)
00288               return(MG_ESEEK);
00289        if (pos->lineno == mg_file->lineno)
00290               return(MG_OK);
00291        if (mg_file->fp == stdin)
00292               return(MG_ESEEK);    /* cannot seek on standard input */
00293        if (fseek(mg_file->fp, pos->offset, 0) == EOF)
00294               return(MG_ESEEK);
00295        mg_file->lineno = pos->lineno;
00296        return(MG_OK);
00297 }
00298 
00299 
00300 int
00301 mg_read(void)               /* read next line from file */
00302 {
00303        register int  len = 0;
00304 
00305        do {
00306               if (fgets(mg_file->inpline+len,
00307                             MG_MAXLINE-len, mg_file->fp) == NULL)
00308                      return(len);
00309               len += strlen(mg_file->inpline+len);
00310               if (len >= MG_MAXLINE-1)
00311                      return(len);
00312               mg_file->lineno++;
00313        } while (len > 1 && mg_file->inpline[len-2] == '\\');
00314 
00315        return(len);
00316 }
00317 
00318 
00319 int
00320 mg_parse(void)                     /* parse current input line */
00321 {
00322        char   abuf[MG_MAXLINE];
00323        char   *argv[MG_MAXARGC];
00324        register char *cp, *cp2, **ap;
00325                                    /* copy line, removing escape chars */
00326        cp = abuf; cp2 = mg_file->inpline;
00327        while ((*cp++ = *cp2++))
00328               if (cp2[0] == '\n' && cp2[-1] == '\\')
00329                      cp--;
00330        cp = abuf; ap = argv;              /* break into words */
00331        for ( ; ; ) {
00332               while (isspace(*cp))
00333                      *cp++ = '\0';
00334               if (!*cp)
00335                      break;
00336               if (ap - argv >= MG_MAXARGC-1)
00337                      return(MG_EARGC);
00338               *ap++ = cp;
00339               while (*++cp && !isspace(*cp))
00340                      ;
00341        }
00342        if (ap == argv)
00343               return(MG_OK);              /* no words in line */
00344        *ap = NULL;
00345                                    /* else handle it */
00346        return(mg_handle(-1, ap-argv, argv));
00347 }
00348 
00349 
00350 int
00351 mg_load(                    /* load an MGF file */
00352        char   *fn
00353 )
00354 {
00355        MG_FCTXT      cntxt;
00356        int    rval;
00357        register int  nbr;
00358 
00359        if ((rval = mg_open(&cntxt, fn)) != MG_OK) {
00360               fprintf(stderr, "%s: %s\n", fn, mg_err[rval]);
00361               return(rval);
00362        }
00363        while ((nbr = mg_read()) > 0) {    /* parse each line */
00364               if (nbr >= MG_MAXLINE-1) {
00365                      fprintf(stderr, "%s: %d: %s\n", cntxt.fname,
00366                                    cntxt.lineno, mg_err[rval=MG_ELINE]);
00367                      break;
00368               }
00369               if ((rval = mg_parse()) != MG_OK) {
00370                      fprintf(stderr, "%s: %d: %s:\n%s", cntxt.fname,
00371                                    cntxt.lineno, mg_err[rval],
00372                                    cntxt.inpline);
00373                      break;
00374               }
00375        }
00376        mg_close();
00377        return(rval);
00378 }
00379 
00380 
00381 int
00382 mg_defuhand(         /* default handler for unknown entities */
00383        int    ac,
00384        char   **av
00385 )
00386 {
00387        if (mg_nunknown++ == 0)            /* report first incident */
00388               fprintf(stderr, "%s: %d: %s: %s\n", mg_file->fname,
00389                             mg_file->lineno, mg_err[MG_EUNK], av[0]);
00390        return(MG_OK);
00391 }
00392 
00393 
00394 void
00395 mg_clear(void)                     /* clear parser history */
00396 {
00397        c_clearall();               /* clear context tables */
00398        while (mg_file != NULL)            /* reset our file context */
00399               mg_close();
00400 }
00401 
00402 
00403 /****************************************************************************
00404  *     The following routines handle unsupported entities
00405  */
00406 
00407 
00408 static int
00409 e_any_toss(          /* discard an unwanted entity */
00410        int    ac,
00411        char   **av
00412 )
00413 {
00414        return(MG_OK);
00415 }
00416 
00417 
00418 int
00419 e_include(           /* include file */
00420        int    ac,
00421        char   **av
00422 )
00423 {
00424        char   *xfarg[MG_MAXARGC];
00425        MG_FCTXT      ictx;
00426        XF_SPEC       *xf_orig = xf_context;
00427        register int  rv;
00428 
00429        if (ac < 2)
00430               return(MG_EARGC);
00431        if ((rv = mg_open(&ictx, av[1])) != MG_OK)
00432               return(rv);
00433        if (ac > 2) {
00434               register int  i;
00435 
00436               xfarg[0] = mg_ename[MG_E_XF];
00437               for (i = 1; i < ac-1; i++)
00438                      xfarg[i] = av[i+1];
00439               xfarg[ac-1] = NULL;
00440               if ((rv = mg_handle(MG_E_XF, ac-1, xfarg)) != MG_OK) {
00441                      mg_close();
00442                      return(rv);
00443               }
00444        }
00445        do {
00446               while ((rv = mg_read()) > 0) {
00447                      if (rv >= MG_MAXLINE-1) {
00448                             fprintf(stderr, "%s: %d: %s\n", ictx.fname,
00449                                           ictx.lineno, mg_err[MG_ELINE]);
00450                             mg_close();
00451                             return(MG_EINCL);
00452                      }
00453                      if ((rv = mg_parse()) != MG_OK) {
00454                             fprintf(stderr, "%s: %d: %s:\n%s", ictx.fname,
00455                                           ictx.lineno, mg_err[rv],
00456                                           ictx.inpline);
00457                             mg_close();
00458                             return(MG_EINCL);
00459                      }
00460               }
00461               if (ac > 2)
00462                      if ((rv = mg_handle(MG_E_XF, 1, xfarg)) != MG_OK) {
00463                             mg_close();
00464                             return(rv);
00465                      }
00466        } while (xf_context != xf_orig);
00467        mg_close();
00468        return(MG_OK);
00469 }
00470 
00471 
00472 int
00473 e_faceh(                    /* replace face+holes with single contour */
00474        int    ac,
00475        char   **av
00476 )
00477 {
00478        char   *newav[MG_MAXARGC];
00479        int    lastp = 0;
00480        register int  i, j;
00481 
00482        newav[0] = mg_ename[MG_E_FACE];
00483        for (i = 1; i < ac; i++)
00484               if (av[i][0] == '-') {
00485                      if (i < 4)
00486                             return(MG_EARGC);
00487                      if (i >= ac-1)
00488                             break;
00489                      if (!lastp)
00490                             lastp = i-1;
00491                      for (j = i+1; j < ac-1 && av[j+1][0] != '-'; j++)
00492                             ;
00493                      if (j - i < 3)
00494                             return(MG_EARGC);
00495                      newav[i] = av[j];    /* connect hole loop */
00496               } else
00497                      newav[i] = av[i];    /* hole or perimeter vertex */
00498        if (lastp)
00499               newav[i++] = av[lastp];            /* finish seam to outside */
00500        newav[i] = NULL;
00501        return(mg_handle(MG_E_FACE, i, newav));
00502 }
00503 
00504 
00505 static void
00506 make_axes(           /* compute u and v given w (normalized) */
00507        FVECT  u,
00508        FVECT  v,
00509        FVECT  w
00510 )
00511 {
00512        register int  i;
00513 
00514        v[0] = v[1] = v[2] = 0.;
00515        for (i = 0; i < 3; i++)
00516               if (w[i] < .6 && w[i] > -.6)
00517                      break;
00518        v[i] = 1.;
00519        fcross(u, v, w);
00520        normalize(u);
00521        fcross(v, w, u);
00522 }
00523 
00524 
00525 int
00526 e_sph(               /* expand a sphere into cones */
00527        int    ac,
00528        char   **av
00529 )
00530 {
00531        static char   p2x[24], p2y[24], p2z[24], r1[24], r2[24];
00532        static char   *v1ent[5] = {mg_ename[MG_E_VERTEX],"_sv1","=","_sv2"};
00533        static char   *v2ent[4] = {mg_ename[MG_E_VERTEX],"_sv2","="};
00534        static char   *p2ent[5] = {mg_ename[MG_E_POINT],p2x,p2y,p2z};
00535        static char   *conent[6] = {mg_ename[MG_E_CONE],"_sv1",r1,"_sv2",r2};
00536        register C_VERTEX    *cv;
00537        register int  i;
00538        int    rval;
00539        double rad;
00540        double theta;
00541 
00542        if (ac != 3)
00543               return(MG_EARGC);
00544        if ((cv = c_getvert(av[1])) == NULL)
00545               return(MG_EUNDEF);
00546        if (!isflt(av[2]))
00547               return(MG_ETYPE);
00548        rad = atof(av[2]);
00549                                    /* initialize */
00550        warpconends = 1;
00551        if ((rval = mg_handle(MG_E_VERTEX, 3, v2ent)) != MG_OK)
00552               return(rval);
00553        sprintf(p2x, FLTFMT, cv->p[0]);
00554        sprintf(p2y, FLTFMT, cv->p[1]);
00555        sprintf(p2z, FLTFMT, cv->p[2]+rad);
00556        if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
00557               return(rval);
00558        r2[0] = '0'; r2[1] = '\0';
00559        for (i = 1; i <= 2*mg_nqcdivs; i++) {
00560               theta = i*(PI/2)/mg_nqcdivs;
00561               if ((rval = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
00562                      return(rval);
00563               sprintf(p2z, FLTFMT, cv->p[2]+rad*cos(theta));
00564               if ((rval = mg_handle(MG_E_VERTEX, 2, v2ent)) != MG_OK)
00565                      return(rval);
00566               if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
00567                      return(rval);
00568               strcpy(r1, r2);
00569               sprintf(r2, FLTFMT, rad*sin(theta));
00570               if ((rval = mg_handle(MG_E_CONE, 5, conent)) != MG_OK)
00571                      return(rval);
00572        }
00573        warpconends = 0;
00574        return(MG_OK);
00575 }
00576 
00577 
00578 int
00579 e_torus(                    /* expand a torus into cones */
00580        int    ac,
00581        char   **av
00582 )
00583 {
00584        static char   p2[3][24], r1[24], r2[24];
00585        static char   *v1ent[5] = {mg_ename[MG_E_VERTEX],"_tv1","=","_tv2"};
00586        static char   *v2ent[5] = {mg_ename[MG_E_VERTEX],"_tv2","="};
00587        static char   *p2ent[5] = {mg_ename[MG_E_POINT],p2[0],p2[1],p2[2]};
00588        static char   *conent[6] = {mg_ename[MG_E_CONE],"_tv1",r1,"_tv2",r2};
00589        register C_VERTEX    *cv;
00590        register int  i, j;
00591        int    rval;
00592        int    sgn;
00593        double minrad, maxrad, avgrad;
00594        double theta;
00595 
00596        if (ac != 4)
00597               return(MG_EARGC);
00598        if ((cv = c_getvert(av[1])) == NULL)
00599               return(MG_EUNDEF);
00600        if (is0vect(cv->n))
00601               return(MG_EILL);
00602        if (!isflt(av[2]) || !isflt(av[3]))
00603               return(MG_ETYPE);
00604        minrad = atof(av[2]);
00605        round0(minrad);
00606        maxrad = atof(av[3]);
00607                                    /* check orientation */
00608        if (minrad > 0.)
00609               sgn = 1;
00610        else if (minrad < 0.)
00611               sgn = -1;
00612        else if (maxrad > 0.)
00613               sgn = 1;
00614        else if (maxrad < 0.)
00615               sgn = -1;
00616        else
00617               return(MG_EILL);
00618        if (sgn*(maxrad-minrad) <= 0.)
00619               return(MG_EILL);
00620                                    /* initialize */
00621        warpconends = 1;
00622        v2ent[3] = av[1];
00623        for (j = 0; j < 3; j++)
00624               sprintf(p2[j], FLTFMT, cv->p[j] +
00625                             .5*sgn*(maxrad-minrad)*cv->n[j]);
00626        if ((rval = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
00627               return(rval);
00628        if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
00629               return(rval);
00630        sprintf(r2, FLTFMT, avgrad=.5*(minrad+maxrad));
00631                                    /* run outer section */
00632        for (i = 1; i <= 2*mg_nqcdivs; i++) {
00633               theta = i*(PI/2)/mg_nqcdivs;
00634               if ((rval = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
00635                      return(rval);
00636               for (j = 0; j < 3; j++)
00637                      sprintf(p2[j], FLTFMT, cv->p[j] +
00638                             .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
00639               if ((rval = mg_handle(MG_E_VERTEX, 2, v2ent)) != MG_OK)
00640                      return(rval);
00641               if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
00642                      return(rval);
00643               strcpy(r1, r2);
00644               sprintf(r2, FLTFMT, avgrad + .5*(maxrad-minrad)*sin(theta));
00645               if ((rval = mg_handle(MG_E_CONE, 5, conent)) != MG_OK)
00646                      return(rval);
00647        }
00648                                    /* run inner section */
00649        sprintf(r2, FLTFMT, -.5*(minrad+maxrad));
00650        for ( ; i <= 4*mg_nqcdivs; i++) {
00651               theta = i*(PI/2)/mg_nqcdivs;
00652               for (j = 0; j < 3; j++)
00653                      sprintf(p2[j], FLTFMT, cv->p[j] +
00654                             .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
00655               if ((rval = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
00656                      return(rval);
00657               if ((rval = mg_handle(MG_E_VERTEX, 2, v2ent)) != MG_OK)
00658                      return(rval);
00659               if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
00660                      return(rval);
00661               strcpy(r1, r2);
00662               sprintf(r2, FLTFMT, -avgrad - .5*(maxrad-minrad)*sin(theta));
00663               if ((rval = mg_handle(MG_E_CONE, 5, conent)) != MG_OK)
00664                      return(rval);
00665        }
00666        warpconends = 0;
00667        return(MG_OK);
00668 }
00669 
00670 
00671 int
00672 e_cyl(               /* replace a cylinder with equivalent cone */
00673        int    ac,
00674        char   **av
00675 )
00676 {
00677        static char   *avnew[6] = {mg_ename[MG_E_CONE]};
00678 
00679        if (ac != 4)
00680               return(MG_EARGC);
00681        avnew[1] = av[1];
00682        avnew[2] = av[2];
00683        avnew[3] = av[3];
00684        avnew[4] = av[2];
00685        return(mg_handle(MG_E_CONE, 5, avnew));
00686 }
00687 
00688 
00689 int
00690 e_ring(                     /* turn a ring into polygons */
00691        int    ac,
00692        char   **av
00693 )
00694 {
00695        static char   p3[3][24], p4[3][24];
00696        static char   *nzent[5] = {mg_ename[MG_E_NORMAL],"0","0","0"};
00697        static char   *v1ent[5] = {mg_ename[MG_E_VERTEX],"_rv1","="};
00698        static char   *v2ent[5] = {mg_ename[MG_E_VERTEX],"_rv2","=","_rv3"};
00699        static char   *v3ent[4] = {mg_ename[MG_E_VERTEX],"_rv3","="};
00700        static char   *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
00701        static char   *v4ent[4] = {mg_ename[MG_E_VERTEX],"_rv4","="};
00702        static char   *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
00703        static char   *fent[6] = {mg_ename[MG_E_FACE],"_rv1","_rv2","_rv3","_rv4"};
00704        register C_VERTEX    *cv;
00705        register int  i, j;
00706        FVECT  u, v;
00707        double minrad, maxrad;
00708        int    rv;
00709        double theta, d;
00710 
00711        if (ac != 4)
00712               return(MG_EARGC);
00713        if ((cv = c_getvert(av[1])) == NULL)
00714               return(MG_EUNDEF);
00715        if (is0vect(cv->n))
00716               return(MG_EILL);
00717        if (!isflt(av[2]) || !isflt(av[3]))
00718               return(MG_ETYPE);
00719        minrad = atof(av[2]);
00720        round0(minrad);
00721        maxrad = atof(av[3]);
00722        if (minrad < 0. || maxrad <= minrad)
00723               return(MG_EILL);
00724                                    /* initialize */
00725        make_axes(u, v, cv->n);
00726        for (j = 0; j < 3; j++)
00727               sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*u[j]);
00728        if ((rv = mg_handle(MG_E_VERTEX, 3, v3ent)) != MG_OK)
00729               return(rv);
00730        if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
00731               return(rv);
00732        if (minrad == 0.) {         /* closed */
00733               v1ent[3] = av[1];
00734               if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
00735                      return(rv);
00736               if ((rv = mg_handle(MG_E_NORMAL, 4, nzent)) != MG_OK)
00737                      return(rv);
00738               for (i = 1; i <= 4*mg_nqcdivs; i++) {
00739                      theta = i*(PI/2)/mg_nqcdivs;
00740                      if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
00741                             return(rv);
00742                      for (j = 0; j < 3; j++)
00743                             sprintf(p3[j], FLTFMT, cv->p[j] +
00744                                           maxrad*u[j]*cos(theta) +
00745                                           maxrad*v[j]*sin(theta));
00746                      if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
00747                             return(rv);
00748                      if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
00749                             return(rv);
00750                      if ((rv = mg_handle(MG_E_FACE, 4, fent)) != MG_OK)
00751                             return(rv);
00752               }
00753        } else {                    /* open */
00754               if ((rv = mg_handle(MG_E_VERTEX, 3, v4ent)) != MG_OK)
00755                      return(rv);
00756               for (j = 0; j < 3; j++)
00757                      sprintf(p4[j], FLTFMT, cv->p[j] + minrad*u[j]);
00758               if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
00759                      return(rv);
00760               v1ent[3] = "_rv4";
00761               for (i = 1; i <= 4*mg_nqcdivs; i++) {
00762                      theta = i*(PI/2)/mg_nqcdivs;
00763                      if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
00764                             return(rv);
00765                      if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
00766                             return(rv);
00767                      for (j = 0; j < 3; j++) {
00768                             d = u[j]*cos(theta) + v[j]*sin(theta);
00769                             sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*d);
00770                             sprintf(p4[j], FLTFMT, cv->p[j] + minrad*d);
00771                      }
00772                      if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
00773                             return(rv);
00774                      if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
00775                             return(rv);
00776                      if ((rv = mg_handle(MG_E_VERTEX, 2, v4ent)) != MG_OK)
00777                             return(rv);
00778                      if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
00779                             return(rv);
00780                      if ((rv = mg_handle(MG_E_FACE, 5, fent)) != MG_OK)
00781                             return(rv);
00782               }
00783        }
00784        return(MG_OK);
00785 }
00786 
00787 
00788 int
00789 e_cone(                     /* turn a cone into polygons */
00790        int    ac,
00791        char   **av
00792 )
00793 {
00794        static char   p3[3][24], p4[3][24], n3[3][24], n4[3][24];
00795        static char   *v1ent[5] = {mg_ename[MG_E_VERTEX],"_cv1","="};
00796        static char   *v2ent[5] = {mg_ename[MG_E_VERTEX],"_cv2","=","_cv3"};
00797        static char   *v3ent[4] = {mg_ename[MG_E_VERTEX],"_cv3","="};
00798        static char   *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
00799        static char   *n3ent[5] = {mg_ename[MG_E_NORMAL],n3[0],n3[1],n3[2]};
00800        static char   *v4ent[4] = {mg_ename[MG_E_VERTEX],"_cv4","="};
00801        static char   *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
00802        static char   *n4ent[5] = {mg_ename[MG_E_NORMAL],n4[0],n4[1],n4[2]};
00803        static char   *fent[6] = {mg_ename[MG_E_FACE],"_cv1","_cv2","_cv3","_cv4"};
00804        char   *v1n;
00805        register C_VERTEX    *cv1, *cv2;
00806        register int  i, j;
00807        FVECT  u, v, w;
00808        double rad1, rad2;
00809        int    sgn;
00810        double n1off, n2off;
00811        double d;
00812        int    rv;
00813        double theta;
00814 
00815        if (ac != 5)
00816               return(MG_EARGC);
00817        if ((cv1 = c_getvert(av[1])) == NULL ||
00818                      (cv2 = c_getvert(av[3])) == NULL)
00819               return(MG_EUNDEF);
00820        v1n = av[1];
00821        if (!isflt(av[2]) || !isflt(av[4]))
00822               return(MG_ETYPE);
00823        rad1 = atof(av[2]);
00824        round0(rad1);
00825        rad2 = atof(av[4]);
00826        round0(rad2);
00827        if (rad1 == 0.) {
00828               if (rad2 == 0.)
00829                      return(MG_EILL);
00830        } else if (rad2 != 0.) {
00831               if ((rad1 < 0.) ^ (rad2 < 0.))
00832                      return(MG_EILL);
00833        } else {                    /* swap */
00834               C_VERTEX      *cv;
00835 
00836               cv = cv1;
00837               cv1 = cv2;
00838               cv2 = cv;
00839               v1n = av[3];
00840               d = rad1;
00841               rad1 = rad2;
00842               rad2 = d;
00843        }
00844        sgn = rad2 < 0. ? -1 : 1;
00845                                    /* initialize */
00846        for (j = 0; j < 3; j++)
00847               w[j] = cv1->p[j] - cv2->p[j];
00848        if ((d = normalize(w)) == 0.)
00849               return(MG_EILL);
00850        n1off = n2off = (rad2 - rad1)/d;
00851        if (warpconends) {          /* hack for e_sph and e_torus */
00852               d = atan(n2off) - (PI/4)/mg_nqcdivs;
00853               if (d <= -PI/2+FTINY)
00854                      n2off = -FHUGE;
00855               else
00856                      n2off = tan(d);
00857        }
00858        make_axes(u, v, w);
00859        for (j = 0; j < 3; j++) {
00860               sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*u[j]);
00861               if (n2off <= -FHUGE)
00862                      sprintf(n3[j], FLTFMT, -w[j]);
00863               else
00864                      sprintf(n3[j], FLTFMT, u[j] + w[j]*n2off);
00865        }
00866        if ((rv = mg_handle(MG_E_VERTEX, 3, v3ent)) != MG_OK)
00867               return(rv);
00868        if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
00869               return(rv);
00870        if ((rv = mg_handle(MG_E_NORMAL, 4, n3ent)) != MG_OK)
00871               return(rv);
00872        if (rad1 == 0.) {           /* triangles */
00873               v1ent[3] = v1n;
00874               if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
00875                      return(rv);
00876               for (j = 0; j < 3; j++)
00877                      sprintf(n4[j], FLTFMT, w[j]);
00878               if ((rv = mg_handle(MG_E_NORMAL, 4, n4ent)) != MG_OK)
00879                      return(rv);
00880               for (i = 1; i <= 4*mg_nqcdivs; i++) {
00881                      theta = sgn*i*(PI/2)/mg_nqcdivs;
00882                      if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
00883                             return(rv);
00884                      for (j = 0; j < 3; j++) {
00885                             d = u[j]*cos(theta) + v[j]*sin(theta);
00886                             sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
00887                             if (n2off > -FHUGE)
00888                                    sprintf(n3[j], FLTFMT, d + w[j]*n2off);
00889                      }
00890                      if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
00891                             return(rv);
00892                      if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
00893                             return(rv);
00894                      if (n2off > -FHUGE &&
00895                      (rv = mg_handle(MG_E_NORMAL, 4, n3ent)) != MG_OK)
00896                             return(rv);
00897                      if ((rv = mg_handle(MG_E_FACE, 4, fent)) != MG_OK)
00898                             return(rv);
00899               }
00900        } else {                    /* quads */
00901               v1ent[3] = "_cv4";
00902               if (warpconends) {          /* hack for e_sph and e_torus */
00903                      d = atan(n1off) + (PI/4)/mg_nqcdivs;
00904                      if (d >= PI/2-FTINY)
00905                             n1off = FHUGE;
00906                      else
00907                             n1off = tan(atan(n1off)+(PI/4)/mg_nqcdivs);
00908               }
00909               for (j = 0; j < 3; j++) {
00910                      sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*u[j]);
00911                      if (n1off >= FHUGE)
00912                             sprintf(n4[j], FLTFMT, w[j]);
00913                      else
00914                             sprintf(n4[j], FLTFMT, u[j] + w[j]*n1off);
00915               }
00916               if ((rv = mg_handle(MG_E_VERTEX, 3, v4ent)) != MG_OK)
00917                      return(rv);
00918               if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
00919                      return(rv);
00920               if ((rv = mg_handle(MG_E_NORMAL, 4, n4ent)) != MG_OK)
00921                      return(rv);
00922               for (i = 1; i <= 4*mg_nqcdivs; i++) {
00923                      theta = sgn*i*(PI/2)/mg_nqcdivs;
00924                      if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
00925                             return(rv);
00926                      if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
00927                             return(rv);
00928                      for (j = 0; j < 3; j++) {
00929                             d = u[j]*cos(theta) + v[j]*sin(theta);
00930                             sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
00931                             if (n2off > -FHUGE)
00932                                    sprintf(n3[j], FLTFMT, d + w[j]*n2off);
00933                             sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*d);
00934                             if (n1off < FHUGE)
00935                                    sprintf(n4[j], FLTFMT, d + w[j]*n1off);
00936                      }
00937                      if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
00938                             return(rv);
00939                      if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
00940                             return(rv);
00941                      if (n2off > -FHUGE &&
00942                      (rv = mg_handle(MG_E_NORMAL, 4, n3ent)) != MG_OK)
00943                             return(rv);
00944                      if ((rv = mg_handle(MG_E_VERTEX, 2, v4ent)) != MG_OK)
00945                             return(rv);
00946                      if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
00947                             return(rv);
00948                      if (n1off < FHUGE &&
00949                      (rv = mg_handle(MG_E_NORMAL, 4, n4ent)) != MG_OK)
00950                             return(rv);
00951                      if ((rv = mg_handle(MG_E_FACE, 5, fent)) != MG_OK)
00952                             return(rv);
00953               }
00954        }
00955        return(MG_OK);
00956 }
00957 
00958 
00959 int
00960 e_prism(                    /* turn a prism into polygons */
00961        int    ac,
00962        char   **av
00963 )
00964 {
00965        static char   p[3][24];
00966        static char   *vent[5] = {mg_ename[MG_E_VERTEX],NULL,"="};
00967        static char   *pent[5] = {mg_ename[MG_E_POINT],p[0],p[1],p[2]};
00968        static char   *znorm[5] = {mg_ename[MG_E_NORMAL],"0","0","0"};
00969        char   *newav[MG_MAXARGC], nvn[MG_MAXARGC-1][8];
00970        double length;
00971        int    hasnorm;
00972        FVECT  v1, v2, v3, norm;
00973        register C_VERTEX    *cv;
00974        C_VERTEX      *cv0;
00975        int    rv;
00976        register int  i, j;
00977                                           /* check arguments */
00978        if (ac < 5)
00979               return(MG_EARGC);
00980        if (!isflt(av[ac-1]))
00981               return(MG_ETYPE);
00982        length = atof(av[ac-1]);
00983        if (length <= FTINY && length >= -FTINY)
00984               return(MG_EILL);
00985                                           /* compute face normal */
00986        if ((cv0 = c_getvert(av[1])) == NULL)
00987               return(MG_EUNDEF);
00988        hasnorm = 0;
00989        norm[0] = norm[1] = norm[2] = 0.;
00990        v1[0] = v1[1] = v1[2] = 0.;
00991        for (i = 2; i < ac-1; i++) {
00992               if ((cv = c_getvert(av[i])) == NULL)
00993                      return(MG_EUNDEF);
00994               hasnorm += !is0vect(cv->n);
00995               v2[0] = cv->p[0] - cv0->p[0];
00996               v2[1] = cv->p[1] - cv0->p[1];
00997               v2[2] = cv->p[2] - cv0->p[2];
00998               fcross(v3, v1, v2);
00999               norm[0] += v3[0];
01000               norm[1] += v3[1];
01001               norm[2] += v3[2];
01002               VCOPY(v1, v2);
01003        }
01004        if (normalize(norm) == 0.)
01005               return(MG_EILL);
01006                                           /* create moved vertices */
01007        for (i = 1; i < ac-1; i++) {
01008               sprintf(nvn[i-1], "_pv%d", i);
01009               vent[1] = nvn[i-1];
01010               vent[3] = av[i];
01011               if ((rv = mg_handle(MG_E_VERTEX, 4, vent)) != MG_OK)
01012                      return(rv);
01013               cv = c_getvert(av[i]);             /* checked above */
01014               for (j = 0; j < 3; j++)
01015                      sprintf(p[j], FLTFMT, cv->p[j] - length*norm[j]);
01016               if ((rv = mg_handle(MG_E_POINT, 4, pent)) != MG_OK)
01017                      return(rv);
01018        }
01019                                           /* make faces */
01020        newav[0] = mg_ename[MG_E_FACE];
01021                                           /* do the side faces */
01022        newav[5] = NULL;
01023        newav[3] = av[ac-2];
01024        newav[4] = nvn[ac-3];
01025        for (i = 1; i < ac-1; i++) {
01026               newav[1] = nvn[i-1];
01027               newav[2] = av[i];
01028               if ((rv = mg_handle(MG_E_FACE, 5, newav)) != MG_OK)
01029                      return(rv);
01030               newav[3] = newav[2];
01031               newav[4] = newav[1];
01032        }
01033                                           /* do top face */
01034        for (i = 1; i < ac-1; i++) {
01035               if (hasnorm) {                     /* zero normals */
01036                      vent[1] = nvn[i-1];
01037                      if ((rv = mg_handle(MG_E_VERTEX, 2, vent)) != MG_OK)
01038                             return(rv);
01039                      if ((rv = mg_handle(MG_E_NORMAL, 4, znorm)) != MG_OK)
01040                             return(rv);
01041               }
01042               newav[ac-1-i] = nvn[i-1];   /* reverse */
01043        }
01044        if ((rv = mg_handle(MG_E_FACE, ac-1, newav)) != MG_OK)
01045               return(rv);
01046                                           /* do bottom face */
01047        if (hasnorm)
01048               for (i = 1; i < ac-1; i++) {
01049                      vent[1] = nvn[i-1];
01050                      vent[3] = av[i];
01051                      if ((rv = mg_handle(MG_E_VERTEX, 4, vent)) != MG_OK)
01052                             return(rv);
01053                      if ((rv = mg_handle(MG_E_NORMAL, 4, znorm)) != MG_OK)
01054                             return(rv);
01055                      newav[i] = nvn[i-1];
01056               }
01057        else
01058               for (i = 1; i < ac-1; i++)
01059                      newav[i] = av[i];
01060        newav[i] = NULL;
01061        if ((rv = mg_handle(MG_E_FACE, i, newav)) != MG_OK)
01062               return(rv);
01063        return(MG_OK);
01064 }
01065 
01066 
01067 static int
01068 put_cxy(void)               /* put out current xy chromaticities */
01069 {
01070        static char   xbuf[24], ybuf[24];
01071        static char   *ccom[4] = {mg_ename[MG_E_CXY], xbuf, ybuf};
01072 
01073        sprintf(xbuf, "%.4f", c_ccolor->cx);
01074        sprintf(ybuf, "%.4f", c_ccolor->cy);
01075        return(mg_handle(MG_E_CXY, 3, ccom));
01076 }
01077 
01078 
01079 static int
01080 put_cspec(void)                    /* put out current color spectrum */
01081 {
01082        char   wl[2][6], vbuf[C_CNSS][24];
01083        char   *newav[C_CNSS+4];
01084        double sf;
01085        register int  i;
01086 
01087        if (mg_ehand[MG_E_CSPEC] != c_hcolor) {
01088               sprintf(wl[0], "%d", C_CMINWL);
01089               sprintf(wl[1], "%d", C_CMAXWL);
01090               newav[0] = mg_ename[MG_E_CSPEC];
01091               newav[1] = wl[0];
01092               newav[2] = wl[1];
01093               sf = (double)C_CNSS / c_ccolor->ssum;
01094               for (i = 0; i < C_CNSS; i++) {
01095                      sprintf(vbuf[i], "%.4f", sf*c_ccolor->ssamp[i]);
01096                      newav[i+3] = vbuf[i];
01097               }
01098               newav[C_CNSS+3] = NULL;
01099               if ((i = mg_handle(MG_E_CSPEC, C_CNSS+3, newav)) != MG_OK)
01100                      return(i);
01101        }
01102        return(MG_OK);
01103 }
01104 
01105 
01106 static int
01107 e_cspec(                    /* handle spectral color */
01108        int    ac,
01109        char   **av
01110 )
01111 {
01112                             /* convert to xy chromaticity */
01113        c_ccvt(c_ccolor, C_CSXY);
01114                             /* if it's really their handler, use it */
01115        if (mg_ehand[MG_E_CXY] != c_hcolor)
01116               return(put_cxy());
01117        return(MG_OK);
01118 }
01119 
01120 
01121 static int
01122 e_cmix(                     /* handle mixing of colors */
01123        int    ac,
01124        char   **av
01125 )
01126 {
01127        /*
01128         * Contorted logic works as follows:
01129         *     1. the colors are already mixed in c_hcolor() support function
01130         *     2. if we would handle a spectral result, make sure it's not
01131         *     3. if c_hcolor() would handle a spectral result, don't bother
01132         *     4. otherwise, make cspec entity and pass it to their handler
01133         *     5. if we have only xy results, handle it as c_spec() would
01134         */
01135        if (mg_ehand[MG_E_CSPEC] == e_cspec)
01136               c_ccvt(c_ccolor, C_CSXY);
01137        else if (c_ccolor->flags & C_CDSPEC)
01138               return(put_cspec());
01139        if (mg_ehand[MG_E_CXY] != c_hcolor)
01140               return(put_cxy());
01141        return(MG_OK);
01142 }
01143 
01144 
01145 static int
01146 e_cct(               /* handle color temperature */
01147        int    ac,
01148        char   **av
01149 )
01150 {
01151        /*
01152         * Logic is similar to e_cmix here.  Support handler has already
01153         * converted temperature to spectral color.  Put it out as such
01154         * if they support it, otherwise convert to xy chromaticity and
01155         * put it out if they handle it.
01156         */
01157        if (mg_ehand[MG_E_CSPEC] != e_cspec)
01158               return(put_cspec());
01159        c_ccvt(c_ccolor, C_CSXY);
01160        if (mg_ehand[MG_E_CXY] != c_hcolor)
01161               return(put_cxy());
01162        return(MG_OK);
01163 }