--- ray/src/cv/mgflib/parser.c 1994/06/29 16:15:20 1.10 +++ ray/src/cv/mgflib/parser.c 2003/11/15 17:54:06 1.28 @@ -1,14 +1,12 @@ -/* Copyright (c) 1994 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: parser.c,v 1.28 2003/11/15 17:54:06 schorsch Exp $"; #endif - /* * Parse an MGF file, converting or discarding unsupported entities */ #include +#include #include #include #include @@ -27,6 +25,12 @@ char mg_ename[MG_NENTITIES][MG_MAXELEN] = MG_NAMELIST; int (*mg_ehand[MG_NENTITIES])(); + /* Handler routine for unknown entities */ + +int (*mg_uhand)() = mg_defuhand; + +unsigned mg_nunknown; /* count of unknown entities */ + /* error messages */ char *mg_err[MG_NERRS] = MG_ERRLIST; @@ -55,21 +59,19 @@ int mg_nqcdivs = MG_NQCD; /* number of divisions per q #define e_ies e_any_toss /* alternate handler routines */ -static int e_any_toss(), /* discard unneeded entity */ - e_ies(), /* IES luminaire file */ - e_include(), /* include file */ - e_sph(), /* sphere */ - e_cmix(), /* color mixtures */ - e_cspec(), /* color spectra */ - e_cyl(), /* cylinder */ - e_cone(), /* cone */ - e_prism(), /* prism */ - e_ring(), /* ring */ - e_torus(); /* torus */ +static void make_axes(FVECT u, FVECT v, FVECT w); +static int put_cxy(void); +static int put_cspec(void); +static int e_any_toss(int ac, char **av); /* discard an unwanted entity */ +static int e_cspec(int ac, char **av); /* handle spectral color */ +static int e_cmix(int ac, char **av); /* handle mixing of colors */ +static int e_cct(int ac, char **av); /* handle color temperature */ + + /* alternate handler support functions */ -static int (*e_supp[MG_NENTITIES])(); +static int (*e_supp[MG_NENTITIES])(int ac, char **av); static char FLTFMT[] = "%.12g"; @@ -77,7 +79,7 @@ static int warpconends; /* hack for generating good n void -mg_init() /* initialize alternate entity handlers */ +mg_init(void) /* initialize alternate entity handlers */ { unsigned long ineed = 0, uneed = 0; register int i; @@ -88,76 +90,88 @@ mg_init() /* initialize alternate entity handlers */ mg_ehand[MG_E_INCLUDE] = e_include; if (mg_ehand[MG_E_SPH] == NULL) { mg_ehand[MG_E_SPH] = e_sph; - ineed |= 1<fid = ++nfids; @@ -224,14 +242,12 @@ char *fn; return(MG_OK); } /* get name relative to this context */ - if (mg_file != NULL && - (cp = strrchr(mg_file->fname, '/')) != NULL) - olen = cp - mg_file->fname + 1; - else - olen = 0; - if (olen) + if (fn[0] != '/' && mg_file != NULL && + (cp = strrchr(mg_file->fname, '/')) != NULL) { strcpy(ctx->fname, mg_file->fname); - strcpy(ctx->fname+olen, fn); + strcpy(ctx->fname+(cp-mg_file->fname+1), fn); + } else + strcpy(ctx->fname, fn); ctx->fp = fopen(ctx->fname, "r"); if (ctx->fp == NULL) return(MG_ENOFILE); @@ -242,23 +258,21 @@ char *fn; void -mg_close() /* close input file */ +mg_close(void) /* close input file */ { register MG_FCTXT *ctx = mg_file; mg_file = ctx->prev; /* restore enclosing context */ - if (ctx->fp == stdin) - return; /* don't close standard input */ - fclose(ctx->fp); + if (ctx->fp != stdin) /* close file if it's a file */ + fclose(ctx->fp); } void -mg_fgetpos(pos) /* get current position in input file */ -register MG_FPOS *pos; +mg_fgetpos( /* get current position in input file */ + register MG_FPOS *pos +) { - extern long ftell(); - pos->fid = mg_file->fid; pos->lineno = mg_file->lineno; pos->offset = ftell(mg_file->fp); @@ -266,8 +280,9 @@ register MG_FPOS *pos; int -mg_fgoto(pos) /* reposition input file pointer */ -register MG_FPOS *pos; +mg_fgoto( /* reposition input file pointer */ + register MG_FPOS *pos +) { if (pos->fid != mg_file->fid) return(MG_ESEEK); @@ -283,7 +298,7 @@ register MG_FPOS *pos; int -mg_read() /* read next line from file */ +mg_read(void) /* read next line from file */ { register int len = 0; @@ -291,26 +306,28 @@ mg_read() /* read next line from file */ if (fgets(mg_file->inpline+len, MG_MAXLINE-len, mg_file->fp) == NULL) return(len); - mg_file->lineno++; len += strlen(mg_file->inpline+len); - if (len > 1 && mg_file->inpline[len-2] == '\\') - mg_file->inpline[--len-1] = ' '; - } while (mg_file->inpline[len]); + if (len >= MG_MAXLINE-1) + return(len); + mg_file->lineno++; + } while (len > 1 && mg_file->inpline[len-2] == '\\'); return(len); } int -mg_parse() /* parse current input line */ +mg_parse(void) /* parse current input line */ { char abuf[MG_MAXLINE]; char *argv[MG_MAXARGC]; - int en; - register char *cp, **ap; - - strcpy(cp=abuf, mg_file->inpline); - ap = argv; /* break into words */ + register char *cp, *cp2, **ap; + /* copy line, removing escape chars */ + cp = abuf; cp2 = mg_file->inpline; + while ((*cp++ = *cp2++)) + if (cp2[0] == '\n' && cp2[-1] == '\\') + cp--; + cp = abuf; ap = argv; /* break into words */ for ( ; ; ) { while (isspace(*cp)) *cp++ = '\0'; @@ -331,33 +348,55 @@ mg_parse() /* parse current input line */ int -mg_load(fn) /* load an MGF file */ -char *fn; +mg_load( /* load an MGF file */ + char *fn +) { MG_FCTXT cntxt; int rval; + register int nbr; if ((rval = mg_open(&cntxt, fn)) != MG_OK) { fprintf(stderr, "%s: %s\n", fn, mg_err[rval]); return(rval); } - while (mg_read()) /* parse each line */ + while ((nbr = mg_read()) > 0) { /* parse each line */ + if (nbr >= MG_MAXLINE-1) { + fprintf(stderr, "%s: %d: %s\n", cntxt.fname, + cntxt.lineno, mg_err[rval=MG_ELINE]); + break; + } if ((rval = mg_parse()) != MG_OK) { fprintf(stderr, "%s: %d: %s:\n%s", cntxt.fname, cntxt.lineno, mg_err[rval], cntxt.inpline); break; } + } mg_close(); return(rval); } +int +mg_defuhand( /* default handler for unknown entities */ + int ac, + char **av +) +{ + if (mg_nunknown++ == 0) /* report first incident */ + fprintf(stderr, "%s: %d: %s: %s\n", mg_file->fname, + mg_file->lineno, mg_err[MG_EUNK], av[0]); + return(MG_OK); +} + + void -mg_clear() /* clear parser history */ +mg_clear(void) /* clear parser history */ { c_clearall(); /* clear context tables */ - mg_file = NULL; /* reset our context */ + while (mg_file != NULL) /* reset our file context */ + mg_close(); } @@ -367,22 +406,25 @@ mg_clear() /* clear parser history */ static int -e_any_toss(ac, av) /* discard an unwanted entity */ -int ac; -char **av; +e_any_toss( /* discard an unwanted entity */ + int ac, + char **av +) { return(MG_OK); } -static int -e_include(ac, av) /* include file */ -int ac; -char **av; +int +e_include( /* include file */ + int ac, + char **av +) { char *xfarg[MG_MAXARGC]; MG_FCTXT ictx; - int rv; + XF_SPEC *xf_orig = xf_context; + register int rv; if (ac < 2) return(MG_EARGC); @@ -395,11 +437,19 @@ char **av; for (i = 1; i < ac-1; i++) xfarg[i] = av[i+1]; xfarg[ac-1] = NULL; - if ((rv = mg_handle(MG_E_XF, ac-1, xfarg)) != MG_OK) + if ((rv = mg_handle(MG_E_XF, ac-1, xfarg)) != MG_OK) { + mg_close(); return(rv); + } } - while (!feof(mg_file->fp)) { - while (mg_read()) + do { + while ((rv = mg_read()) > 0) { + if (rv >= MG_MAXLINE-1) { + fprintf(stderr, "%s: %d: %s\n", ictx.fname, + ictx.lineno, mg_err[MG_ELINE]); + mg_close(); + return(MG_EINCL); + } if ((rv = mg_parse()) != MG_OK) { fprintf(stderr, "%s: %d: %s:\n%s", ictx.fname, ictx.lineno, mg_err[rv], @@ -407,18 +457,57 @@ char **av; mg_close(); return(MG_EINCL); } + } if (ac > 2) - if ((rv = mg_handle(MG_E_XF, 1, xfarg)) != MG_OK) + if ((rv = mg_handle(MG_E_XF, 1, xfarg)) != MG_OK) { + mg_close(); return(rv); - } + } + } while (xf_context != xf_orig); mg_close(); return(MG_OK); } +int +e_faceh( /* replace face+holes with single contour */ + int ac, + char **av +) +{ + char *newav[MG_MAXARGC]; + int lastp = 0; + register int i, j; + + newav[0] = mg_ename[MG_E_FACE]; + for (i = 1; i < ac; i++) + if (av[i][0] == '-') { + if (i < 4) + return(MG_EARGC); + if (i >= ac-1) + break; + if (!lastp) + lastp = i-1; + for (j = i+1; j < ac-1 && av[j+1][0] != '-'; j++) + ; + if (j - i < 3) + return(MG_EARGC); + newav[i] = av[j]; /* connect hole loop */ + } else + newav[i] = av[i]; /* hole or perimeter vertex */ + if (lastp) + newav[i++] = av[lastp]; /* finish seam to outside */ + newav[i] = NULL; + return(mg_handle(MG_E_FACE, i, newav)); +} + + static void -make_axes(u, v, w) /* compute u and v given w (normalized) */ -FVECT u, v, w; +make_axes( /* compute u and v given w (normalized) */ + FVECT u, + FVECT v, + FVECT w +) { register int i; @@ -433,10 +522,11 @@ FVECT u, v, w; } -static int -e_sph(ac, av) /* expand a sphere into cones */ -int ac; -char **av; +int +e_sph( /* expand a sphere into cones */ + int ac, + char **av +) { static char p2x[24], p2y[24], p2z[24], r1[24], r2[24]; static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_sv1","=","_sv2"}; @@ -485,10 +575,11 @@ char **av; } -static int -e_torus(ac, av) /* expand a torus into cones */ -int ac; -char **av; +int +e_torus( /* expand a torus into cones */ + int ac, + char **av +) { static char p2[3][24], r1[24], r2[24]; static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_tv1","=","_tv2"}; @@ -577,10 +668,11 @@ char **av; } -static int -e_cyl(ac, av) /* replace a cylinder with equivalent cone */ -int ac; -char **av; +int +e_cyl( /* replace a cylinder with equivalent cone */ + int ac, + char **av +) { static char *avnew[6] = {mg_ename[MG_E_CONE]}; @@ -594,10 +686,11 @@ char **av; } -static int -e_ring(ac, av) /* turn a ring into polygons */ -int ac; -char **av; +int +e_ring( /* turn a ring into polygons */ + int ac, + char **av +) { static char p3[3][24], p4[3][24]; static char *nzent[5] = {mg_ename[MG_E_NORMAL],"0","0","0"}; @@ -692,10 +785,11 @@ char **av; } -static int -e_cone(ac, av) /* turn a cone into polygons */ -int ac; -char **av; +int +e_cone( /* turn a cone into polygons */ + int ac, + char **av +) { static char p3[3][24], p4[3][24], n3[3][24], n4[3][24]; static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_cv1","="}; @@ -707,6 +801,7 @@ char **av; static char *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]}; static char *n4ent[5] = {mg_ename[MG_E_NORMAL],n4[0],n4[1],n4[2]}; static char *fent[6] = {mg_ename[MG_E_FACE],"_cv1","_cv2","_cv3","_cv4"}; + char *v1n; register C_VERTEX *cv1, *cv2; register int i, j; FVECT u, v, w; @@ -722,6 +817,7 @@ char **av; if ((cv1 = c_getvert(av[1])) == NULL || (cv2 = c_getvert(av[3])) == NULL) return(MG_EUNDEF); + v1n = av[1]; if (!isflt(av[2]) || !isflt(av[4])) return(MG_ETYPE); rad1 = atof(av[2]); @@ -732,7 +828,7 @@ char **av; if (rad2 == 0.) return(MG_EILL); } else if (rad2 != 0.) { - if (rad1 < 0. ^ rad2 < 0.) + if ((rad1 < 0.) ^ (rad2 < 0.)) return(MG_EILL); } else { /* swap */ C_VERTEX *cv; @@ -740,6 +836,7 @@ char **av; cv = cv1; cv1 = cv2; cv2 = cv; + v1n = av[3]; d = rad1; rad1 = rad2; rad2 = d; @@ -773,7 +870,7 @@ char **av; if ((rv = mg_handle(MG_E_NORMAL, 4, n3ent)) != MG_OK) return(rv); if (rad1 == 0.) { /* triangles */ - v1ent[3] = av[1]; + v1ent[3] = v1n; if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK) return(rv); for (j = 0; j < 3; j++) @@ -859,22 +956,25 @@ char **av; } -static int -e_prism(ac, av) /* turn a prism into polygons */ -int ac; -char **av; +int +e_prism( /* turn a prism into polygons */ + int ac, + char **av +) { static char p[3][24]; - static char *vent[4] = {mg_ename[MG_E_VERTEX],NULL,"="}; + static char *vent[5] = {mg_ename[MG_E_VERTEX],NULL,"="}; static char *pent[5] = {mg_ename[MG_E_POINT],p[0],p[1],p[2]}; + static char *znorm[5] = {mg_ename[MG_E_NORMAL],"0","0","0"}; char *newav[MG_MAXARGC], nvn[MG_MAXARGC-1][8]; double length; + int hasnorm; FVECT v1, v2, v3, norm; register C_VERTEX *cv; C_VERTEX *cv0; int rv; register int i, j; - + /* check arguments */ if (ac < 5) return(MG_EARGC); if (!isflt(av[ac-1])) @@ -882,21 +982,16 @@ char **av; length = atof(av[ac-1]); if (length <= FTINY && length >= -FTINY) return(MG_EILL); - /* do bottom face */ - newav[0] = mg_ename[MG_E_FACE]; - for (i = 1; i < ac-1; i++) - newav[i] = av[i]; - newav[i] = NULL; - if ((rv = mg_handle(MG_E_FACE, i, newav)) != MG_OK) - return(rv); - /* compute face normal */ + /* compute face normal */ if ((cv0 = c_getvert(av[1])) == NULL) return(MG_EUNDEF); + hasnorm = 0; norm[0] = norm[1] = norm[2] = 0.; v1[0] = v1[1] = v1[2] = 0.; for (i = 2; i < ac-1; i++) { if ((cv = c_getvert(av[i])) == NULL) return(MG_EUNDEF); + hasnorm += !is0vect(cv->n); v2[0] = cv->p[0] - cv0->p[0]; v2[1] = cv->p[1] - cv0->p[1]; v2[2] = cv->p[2] - cv0->p[2]; @@ -908,22 +1003,21 @@ char **av; } if (normalize(norm) == 0.) return(MG_EILL); - /* create moved vertices */ + /* create moved vertices */ for (i = 1; i < ac-1; i++) { sprintf(nvn[i-1], "_pv%d", i); vent[1] = nvn[i-1]; - if ((rv = mg_handle(MG_E_VERTEX, 3, vent)) != MG_OK) + vent[3] = av[i]; + if ((rv = mg_handle(MG_E_VERTEX, 4, vent)) != MG_OK) return(rv); cv = c_getvert(av[i]); /* checked above */ for (j = 0; j < 3; j++) sprintf(p[j], FLTFMT, cv->p[j] - length*norm[j]); if ((rv = mg_handle(MG_E_POINT, 4, pent)) != MG_OK) return(rv); - newav[ac-1-i] = nvn[i-1]; /* reverse */ } - /* do top face */ - if ((rv = mg_handle(MG_E_FACE, ac-1, newav)) != MG_OK) - return(rv); + /* make faces */ + newav[0] = mg_ename[MG_E_FACE]; /* do the side faces */ newav[5] = NULL; newav[3] = av[ac-2]; @@ -936,40 +1030,100 @@ char **av; newav[3] = newav[2]; newav[4] = newav[1]; } + /* do top face */ + for (i = 1; i < ac-1; i++) { + if (hasnorm) { /* zero normals */ + vent[1] = nvn[i-1]; + if ((rv = mg_handle(MG_E_VERTEX, 2, vent)) != MG_OK) + return(rv); + if ((rv = mg_handle(MG_E_NORMAL, 4, znorm)) != MG_OK) + return(rv); + } + newav[ac-1-i] = nvn[i-1]; /* reverse */ + } + if ((rv = mg_handle(MG_E_FACE, ac-1, newav)) != MG_OK) + return(rv); + /* do bottom face */ + if (hasnorm) + for (i = 1; i < ac-1; i++) { + vent[1] = nvn[i-1]; + vent[3] = av[i]; + if ((rv = mg_handle(MG_E_VERTEX, 4, vent)) != MG_OK) + return(rv); + if ((rv = mg_handle(MG_E_NORMAL, 4, znorm)) != MG_OK) + return(rv); + newav[i] = nvn[i-1]; + } + else + for (i = 1; i < ac-1; i++) + newav[i] = av[i]; + newav[i] = NULL; + if ((rv = mg_handle(MG_E_FACE, i, newav)) != MG_OK) + return(rv); return(MG_OK); } static int -e_cspec(ac, av) /* handle spectral color */ -int ac; -char **av; +put_cxy(void) /* put out current xy chromaticities */ { static char xbuf[24], ybuf[24]; static char *ccom[4] = {mg_ename[MG_E_CXY], xbuf, ybuf}; - int rv; - c_ccvt(c_ccolor, C_CSXY); - /* if it's really their handler, use it */ - if (mg_ehand[MG_E_CXY] != c_hcolor) { - sprintf(xbuf, "%.4f", c_ccolor->cx); - sprintf(ybuf, "%.4f", c_ccolor->cy); - if ((rv = mg_handle(MG_E_CXY, 3, ccom)) != MG_OK) - return(rv); - } - return(MG_OK); + sprintf(xbuf, "%.4f", c_ccolor->cx); + sprintf(ybuf, "%.4f", c_ccolor->cy); + return(mg_handle(MG_E_CXY, 3, ccom)); } static int -e_cmix(ac, av) /* handle mixing of colors */ -int ac; -char **av; +put_cspec(void) /* put out current color spectrum */ { char wl[2][6], vbuf[C_CNSS][24]; char *newav[C_CNSS+4]; - int rv; + double sf; register int i; + + if (mg_ehand[MG_E_CSPEC] != c_hcolor) { + sprintf(wl[0], "%d", C_CMINWL); + sprintf(wl[1], "%d", C_CMAXWL); + newav[0] = mg_ename[MG_E_CSPEC]; + newav[1] = wl[0]; + newav[2] = wl[1]; + sf = (double)C_CNSS / c_ccolor->ssum; + for (i = 0; i < C_CNSS; i++) { + sprintf(vbuf[i], "%.4f", sf*c_ccolor->ssamp[i]); + newav[i+3] = vbuf[i]; + } + newav[C_CNSS+3] = NULL; + if ((i = mg_handle(MG_E_CSPEC, C_CNSS+3, newav)) != MG_OK) + return(i); + } + return(MG_OK); +} + + +static int +e_cspec( /* handle spectral color */ + int ac, + char **av +) +{ + /* convert to xy chromaticity */ + c_ccvt(c_ccolor, C_CSXY); + /* if it's really their handler, use it */ + if (mg_ehand[MG_E_CXY] != c_hcolor) + return(put_cxy()); + return(MG_OK); +} + + +static int +e_cmix( /* handle mixing of colors */ + int ac, + char **av +) +{ /* * Contorted logic works as follows: * 1. the colors are already mixed in c_hcolor() support function @@ -980,34 +1134,30 @@ char **av; */ if (mg_ehand[MG_E_CSPEC] == e_cspec) c_ccvt(c_ccolor, C_CSXY); - else if (c_ccolor->flags & C_CDSPEC) { - if (mg_ehand[MG_E_CSPEC] != c_hcolor) { - sprintf(wl[0], "%d", C_CMINWL); - sprintf(wl[1], "%d", C_CMAXWL); - newav[0] = mg_ename[MG_E_CSPEC]; - newav[1] = wl[0]; - newav[2] = wl[1]; - for (i = 0; i < C_CNSS; i++) { - sprintf(vbuf[i], "%.6f", - (double)c_ccolor->ssamp[i] / - c_ccolor->ssum); - newav[i+3] = vbuf[i]; - } - newav[C_CNSS+3] = NULL; - if ((rv = mg_handle(MG_E_CSPEC, C_CNSS+3, newav)) != MG_OK) - return(rv); - } - return(MG_OK); - } - if (mg_ehand[MG_E_CXY] != c_hcolor) { - sprintf(vbuf[0], "%.4f", c_ccolor->cx); - sprintf(vbuf[1], "%.4f", c_ccolor->cy); - newav[0] = mg_ename[MG_E_CXY]; - newav[1] = vbuf[0]; - newav[2] = vbuf[1]; - newav[3] = NULL; - if ((rv = mg_handle(MG_E_CXY, 3, newav)) != MG_OK) - return(rv); - } + else if (c_ccolor->flags & C_CDSPEC) + return(put_cspec()); + if (mg_ehand[MG_E_CXY] != c_hcolor) + return(put_cxy()); + return(MG_OK); +} + + +static int +e_cct( /* handle color temperature */ + int ac, + char **av +) +{ + /* + * Logic is similar to e_cmix here. Support handler has already + * converted temperature to spectral color. Put it out as such + * if they support it, otherwise convert to xy chromaticity and + * put it out if they handle it. + */ + if (mg_ehand[MG_E_CSPEC] != e_cspec) + return(put_cspec()); + c_ccvt(c_ccolor, C_CSXY); + if (mg_ehand[MG_E_CXY] != c_hcolor) + return(put_cxy()); return(MG_OK); }