ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/parser.c
Revision: 1.17
Committed: Tue May 9 14:38:22 1995 UTC (28 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.16: +27 -27 lines
Log Message:
precautions against 16-bit architectures

File Contents

# Content
1 /* Copyright (c) 1995 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * Parse an MGF file, converting or discarding unsupported entities
9 */
10
11 #include <stdio.h>
12 #include <math.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include "parser.h"
16 #include "lookup.h"
17 #include "messages.h"
18
19 /*
20 * Global definitions of variables declared in parser.h
21 */
22 /* entity names */
23
24 char mg_ename[MG_NENTITIES][MG_MAXELEN] = MG_NAMELIST;
25
26 /* Handler routines for each entity */
27
28 int (*mg_ehand[MG_NENTITIES])();
29
30 /* error messages */
31
32 char *mg_err[MG_NERRS] = MG_ERRLIST;
33
34 MG_FCTXT *mg_file; /* current file context pointer */
35
36 int mg_nqcdivs = MG_NQCD; /* number of divisions per quarter circle */
37
38 /*
39 * The idea with this parser is to compensate for any missing entries in
40 * mg_ehand with alternate handlers that express these entities in terms
41 * of others that the calling program can handle.
42 *
43 * In some cases, no alternate handler is possible because the entity
44 * has no approximate equivalent. These entities are simply discarded.
45 *
46 * Certain entities are dependent on others, and mg_init() will fail
47 * if the supported entities are not consistent.
48 *
49 * Some alternate entity handlers require that earlier entities be
50 * noted in some fashion, and we therefore keep another array of
51 * parallel support handlers to assist in this effort.
52 */
53
54 /* temporary settings for testing */
55 #define e_ies e_any_toss
56 /* alternate handler routines */
57
58 static int e_any_toss(), /* discard unneeded entity */
59 e_ies(), /* IES luminaire file */
60 e_include(), /* include file */
61 e_sph(), /* sphere */
62 e_cct(), /* color temperature */
63 e_cmix(), /* color mixtures */
64 e_cspec(), /* color spectra */
65 e_cyl(), /* cylinder */
66 e_cone(), /* cone */
67 e_prism(), /* prism */
68 e_ring(), /* ring */
69 e_torus(); /* torus */
70
71 /* alternate handler support functions */
72
73 static int (*e_supp[MG_NENTITIES])();
74
75 static char FLTFMT[] = "%.12g";
76
77 static int warpconends; /* hack for generating good normals */
78
79
80 void
81 mg_init() /* initialize alternate entity handlers */
82 {
83 unsigned long ineed = 0, uneed = 0;
84 register int i;
85 /* pick up slack */
86 if (mg_ehand[MG_E_IES] == NULL)
87 mg_ehand[MG_E_IES] = e_ies;
88 if (mg_ehand[MG_E_INCLUDE] == NULL)
89 mg_ehand[MG_E_INCLUDE] = e_include;
90 if (mg_ehand[MG_E_SPH] == NULL) {
91 mg_ehand[MG_E_SPH] = e_sph;
92 ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
93 } else
94 uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
95 if (mg_ehand[MG_E_CYL] == NULL) {
96 mg_ehand[MG_E_CYL] = e_cyl;
97 ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
98 } else
99 uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
100 if (mg_ehand[MG_E_CONE] == NULL) {
101 mg_ehand[MG_E_CONE] = e_cone;
102 ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
103 } else
104 uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
105 if (mg_ehand[MG_E_RING] == NULL) {
106 mg_ehand[MG_E_RING] = e_ring;
107 ineed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX;
108 } else
109 uneed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX|1L<<MG_E_XF;
110 if (mg_ehand[MG_E_PRISM] == NULL) {
111 mg_ehand[MG_E_PRISM] = e_prism;
112 ineed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX;
113 } else
114 uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
115 if (mg_ehand[MG_E_TORUS] == NULL) {
116 mg_ehand[MG_E_TORUS] = e_torus;
117 ineed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX;
118 } else
119 uneed |= 1L<<MG_E_POINT|1L<<MG_E_NORMAL|1L<<MG_E_VERTEX|1L<<MG_E_XF;
120 if (mg_ehand[MG_E_COLOR] != NULL) {
121 if (mg_ehand[MG_E_CMIX] == NULL) {
122 mg_ehand[MG_E_CMIX] = e_cmix;
123 ineed |= 1L<<MG_E_COLOR|1L<<MG_E_CXY|1L<<MG_E_CSPEC|1L<<MG_E_CMIX|1L<<MG_E_CCT;
124 }
125 if (mg_ehand[MG_E_CSPEC] == NULL) {
126 mg_ehand[MG_E_CSPEC] = e_cspec;
127 ineed |= 1L<<MG_E_COLOR|1L<<MG_E_CXY|1L<<MG_E_CSPEC|1L<<MG_E_CMIX|1L<<MG_E_CCT;
128 }
129 if (mg_ehand[MG_E_CCT] == NULL) {
130 mg_ehand[MG_E_CCT] = e_cct;
131 ineed |= 1L<<MG_E_COLOR|1L<<MG_E_CXY|1L<<MG_E_CSPEC|1L<<MG_E_CMIX|1L<<MG_E_CCT;
132 }
133 }
134 /* check for consistency */
135 if (mg_ehand[MG_E_FACE] != NULL)
136 uneed |= 1L<<MG_E_POINT|1L<<MG_E_VERTEX|1L<<MG_E_XF;
137 if (mg_ehand[MG_E_CXY] != NULL || mg_ehand[MG_E_CSPEC] != NULL ||
138 mg_ehand[MG_E_CMIX] != NULL)
139 uneed |= 1L<<MG_E_COLOR;
140 if (mg_ehand[MG_E_RD] != NULL || mg_ehand[MG_E_TD] != NULL ||
141 mg_ehand[MG_E_IR] != NULL ||
142 mg_ehand[MG_E_ED] != NULL ||
143 mg_ehand[MG_E_RS] != NULL ||
144 mg_ehand[MG_E_TS] != NULL ||
145 mg_ehand[MG_E_SIDES] != NULL)
146 uneed |= 1L<<MG_E_MATERIAL;
147 for (i = 0; i < MG_NENTITIES; i++)
148 if (uneed & 1L<<i && mg_ehand[i] == NULL) {
149 fprintf(stderr, "Missing support for \"%s\" entity\n",
150 mg_ename[i]);
151 exit(1);
152 }
153 /* add support as needed */
154 if (ineed & 1L<<MG_E_VERTEX && mg_ehand[MG_E_VERTEX] != c_hvertex)
155 e_supp[MG_E_VERTEX] = c_hvertex;
156 if (ineed & 1L<<MG_E_POINT && mg_ehand[MG_E_POINT] != c_hvertex)
157 e_supp[MG_E_POINT] = c_hvertex;
158 if (ineed & 1L<<MG_E_NORMAL && mg_ehand[MG_E_NORMAL] != c_hvertex)
159 e_supp[MG_E_NORMAL] = c_hvertex;
160 if (ineed & 1L<<MG_E_COLOR && mg_ehand[MG_E_COLOR] != c_hcolor)
161 e_supp[MG_E_COLOR] = c_hcolor;
162 if (ineed & 1L<<MG_E_CXY && mg_ehand[MG_E_CXY] != c_hcolor)
163 e_supp[MG_E_CXY] = c_hcolor;
164 if (ineed & 1L<<MG_E_CSPEC && mg_ehand[MG_E_CSPEC] != c_hcolor)
165 e_supp[MG_E_CSPEC] = c_hcolor;
166 if (ineed & 1L<<MG_E_CMIX && mg_ehand[MG_E_CMIX] != c_hcolor)
167 e_supp[MG_E_CMIX] = c_hcolor;
168 if (ineed & 1L<<MG_E_CCT && mg_ehand[MG_E_CCT] != c_hcolor)
169 e_supp[MG_E_CCT] = c_hcolor;
170 /* discard remaining entities */
171 for (i = 0; i < MG_NENTITIES; i++)
172 if (mg_ehand[i] == NULL)
173 mg_ehand[i] = e_any_toss;
174 }
175
176
177 int
178 mg_entity(name) /* get entity number from its name */
179 char *name;
180 {
181 static LUTAB ent_tab = LU_SINIT(NULL,NULL); /* lookup table */
182 register char *cp;
183
184 if (!ent_tab.tsiz) { /* initialize hash table */
185 if (!lu_init(&ent_tab, MG_NENTITIES))
186 return(-1); /* what to do? */
187 for (cp = mg_ename[MG_NENTITIES-1]; cp >= mg_ename[0];
188 cp -= sizeof(mg_ename[0]))
189 lu_find(&ent_tab, cp)->key = cp;
190 }
191 cp = lu_find(&ent_tab, name)->key;
192 if (cp == NULL)
193 return(-1);
194 return((cp - mg_ename[0])/sizeof(mg_ename[0]));
195 }
196
197
198 int
199 mg_handle(en, ac, av) /* pass entity to appropriate handler */
200 register int en;
201 int ac;
202 char **av;
203 {
204 int rv;
205
206 if (en < 0 && (en = mg_entity(av[0])) < 0)
207 return(MG_EUNK);
208 if (e_supp[en] != NULL) {
209 if ((rv = (*e_supp[en])(ac, av)) != MG_OK)
210 return(rv);
211 }
212 return((*mg_ehand[en])(ac, av));
213 }
214
215
216 int
217 mg_open(ctx, fn) /* open new input file */
218 register MG_FCTXT *ctx;
219 char *fn;
220 {
221 static int nfids;
222 register char *cp;
223
224 ctx->fid = ++nfids;
225 ctx->lineno = 0;
226 if (fn == NULL) {
227 strcpy(ctx->fname, "<stdin>");
228 ctx->fp = stdin;
229 ctx->prev = mg_file;
230 mg_file = ctx;
231 return(MG_OK);
232 }
233 /* get name relative to this context */
234 if (mg_file != NULL && (cp = strrchr(mg_file->fname, '/')) != NULL) {
235 strcpy(ctx->fname, mg_file->fname);
236 strcpy(ctx->fname+(cp-mg_file->fname+1), fn);
237 } else
238 strcpy(ctx->fname, fn);
239 ctx->fp = fopen(ctx->fname, "r");
240 if (ctx->fp == NULL)
241 return(MG_ENOFILE);
242 ctx->prev = mg_file; /* establish new context */
243 mg_file = ctx;
244 return(MG_OK);
245 }
246
247
248 void
249 mg_close() /* close input file */
250 {
251 register MG_FCTXT *ctx = mg_file;
252
253 mg_file = ctx->prev; /* restore enclosing context */
254 if (ctx->fp == stdin)
255 return; /* don't close standard input */
256 fclose(ctx->fp);
257 }
258
259
260 void
261 mg_fgetpos(pos) /* get current position in input file */
262 register MG_FPOS *pos;
263 {
264 extern long ftell();
265
266 pos->fid = mg_file->fid;
267 pos->lineno = mg_file->lineno;
268 pos->offset = ftell(mg_file->fp);
269 }
270
271
272 int
273 mg_fgoto(pos) /* reposition input file pointer */
274 register MG_FPOS *pos;
275 {
276 if (pos->fid != mg_file->fid)
277 return(MG_ESEEK);
278 if (pos->lineno == mg_file->lineno)
279 return(MG_OK);
280 if (mg_file->fp == stdin)
281 return(MG_ESEEK); /* cannot seek on standard input */
282 if (fseek(mg_file->fp, pos->offset, 0) == EOF)
283 return(MG_ESEEK);
284 mg_file->lineno = pos->lineno;
285 return(MG_OK);
286 }
287
288
289 int
290 mg_read() /* read next line from file */
291 {
292 register int len = 0;
293
294 do {
295 if (fgets(mg_file->inpline+len,
296 MG_MAXLINE-len, mg_file->fp) == NULL)
297 return(len);
298 mg_file->lineno++;
299 len += strlen(mg_file->inpline+len);
300 if (len > 1 && mg_file->inpline[len-2] == '\\')
301 mg_file->inpline[--len-1] = ' ';
302 } while (mg_file->inpline[len]);
303
304 return(len);
305 }
306
307
308 int
309 mg_parse() /* parse current input line */
310 {
311 char abuf[MG_MAXLINE];
312 char *argv[MG_MAXARGC];
313 int en;
314 register char *cp, **ap;
315
316 strcpy(cp=abuf, mg_file->inpline);
317 ap = argv; /* break into words */
318 for ( ; ; ) {
319 while (isspace(*cp))
320 *cp++ = '\0';
321 if (!*cp)
322 break;
323 if (ap - argv >= MG_MAXARGC-1)
324 return(MG_EARGC);
325 *ap++ = cp;
326 while (*++cp && !isspace(*cp))
327 ;
328 }
329 if (ap == argv)
330 return(MG_OK); /* no words in line */
331 *ap = NULL;
332 /* else handle it */
333 return(mg_handle(-1, ap-argv, argv));
334 }
335
336
337 int
338 mg_load(fn) /* load an MGF file */
339 char *fn;
340 {
341 MG_FCTXT cntxt;
342 int rval;
343
344 if ((rval = mg_open(&cntxt, fn)) != MG_OK) {
345 fprintf(stderr, "%s: %s\n", fn, mg_err[rval]);
346 return(rval);
347 }
348 while (mg_read()) /* parse each line */
349 if ((rval = mg_parse()) != MG_OK) {
350 fprintf(stderr, "%s: %d: %s:\n%s", cntxt.fname,
351 cntxt.lineno, mg_err[rval],
352 cntxt.inpline);
353 break;
354 }
355 mg_close();
356 return(rval);
357 }
358
359
360 void
361 mg_clear() /* clear parser history */
362 {
363 c_clearall(); /* clear context tables */
364 mg_file = NULL; /* reset our context */
365 }
366
367
368 /****************************************************************************
369 * The following routines handle unsupported entities
370 */
371
372
373 static int
374 e_any_toss(ac, av) /* discard an unwanted entity */
375 int ac;
376 char **av;
377 {
378 return(MG_OK);
379 }
380
381
382 static int
383 e_include(ac, av) /* include file */
384 int ac;
385 char **av;
386 {
387 char *xfarg[MG_MAXARGC];
388 MG_FCTXT ictx;
389 XF_SPEC *xf_orig = xf_context;
390 int rv;
391
392 if (ac < 2)
393 return(MG_EARGC);
394 if ((rv = mg_open(&ictx, av[1])) != MG_OK)
395 return(rv);
396 if (ac > 2) {
397 register int i;
398
399 xfarg[0] = mg_ename[MG_E_XF];
400 for (i = 1; i < ac-1; i++)
401 xfarg[i] = av[i+1];
402 xfarg[ac-1] = NULL;
403 if ((rv = mg_handle(MG_E_XF, ac-1, xfarg)) != MG_OK)
404 return(rv);
405 }
406 do {
407 while (mg_read())
408 if ((rv = mg_parse()) != MG_OK) {
409 fprintf(stderr, "%s: %d: %s:\n%s", ictx.fname,
410 ictx.lineno, mg_err[rv],
411 ictx.inpline);
412 mg_close();
413 return(MG_EINCL);
414 }
415 if (ac > 2)
416 if ((rv = mg_handle(MG_E_XF, 1, xfarg)) != MG_OK)
417 return(rv);
418 } while (xf_context != xf_orig);
419 mg_close();
420 return(MG_OK);
421 }
422
423
424 static void
425 make_axes(u, v, w) /* compute u and v given w (normalized) */
426 FVECT u, v, w;
427 {
428 register int i;
429
430 v[0] = v[1] = v[2] = 0.;
431 for (i = 0; i < 3; i++)
432 if (w[i] < .6 && w[i] > -.6)
433 break;
434 v[i] = 1.;
435 fcross(u, v, w);
436 normalize(u);
437 fcross(v, w, u);
438 }
439
440
441 static int
442 e_sph(ac, av) /* expand a sphere into cones */
443 int ac;
444 char **av;
445 {
446 static char p2x[24], p2y[24], p2z[24], r1[24], r2[24];
447 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_sv1","=","_sv2"};
448 static char *v2ent[4] = {mg_ename[MG_E_VERTEX],"_sv2","="};
449 static char *p2ent[5] = {mg_ename[MG_E_POINT],p2x,p2y,p2z};
450 static char *conent[6] = {mg_ename[MG_E_CONE],"_sv1",r1,"_sv2",r2};
451 register C_VERTEX *cv;
452 register int i;
453 int rval;
454 double rad;
455 double theta;
456
457 if (ac != 3)
458 return(MG_EARGC);
459 if ((cv = c_getvert(av[1])) == NULL)
460 return(MG_EUNDEF);
461 if (!isflt(av[2]))
462 return(MG_ETYPE);
463 rad = atof(av[2]);
464 /* initialize */
465 warpconends = 1;
466 if ((rval = mg_handle(MG_E_VERTEX, 3, v2ent)) != MG_OK)
467 return(rval);
468 sprintf(p2x, FLTFMT, cv->p[0]);
469 sprintf(p2y, FLTFMT, cv->p[1]);
470 sprintf(p2z, FLTFMT, cv->p[2]+rad);
471 if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
472 return(rval);
473 r2[0] = '0'; r2[1] = '\0';
474 for (i = 1; i <= 2*mg_nqcdivs; i++) {
475 theta = i*(PI/2)/mg_nqcdivs;
476 if ((rval = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
477 return(rval);
478 sprintf(p2z, FLTFMT, cv->p[2]+rad*cos(theta));
479 if ((rval = mg_handle(MG_E_VERTEX, 2, v2ent)) != MG_OK)
480 return(rval);
481 if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
482 return(rval);
483 strcpy(r1, r2);
484 sprintf(r2, FLTFMT, rad*sin(theta));
485 if ((rval = mg_handle(MG_E_CONE, 5, conent)) != MG_OK)
486 return(rval);
487 }
488 warpconends = 0;
489 return(MG_OK);
490 }
491
492
493 static int
494 e_torus(ac, av) /* expand a torus into cones */
495 int ac;
496 char **av;
497 {
498 static char p2[3][24], r1[24], r2[24];
499 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_tv1","=","_tv2"};
500 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_tv2","="};
501 static char *p2ent[5] = {mg_ename[MG_E_POINT],p2[0],p2[1],p2[2]};
502 static char *conent[6] = {mg_ename[MG_E_CONE],"_tv1",r1,"_tv2",r2};
503 register C_VERTEX *cv;
504 register int i, j;
505 int rval;
506 int sgn;
507 double minrad, maxrad, avgrad;
508 double theta;
509
510 if (ac != 4)
511 return(MG_EARGC);
512 if ((cv = c_getvert(av[1])) == NULL)
513 return(MG_EUNDEF);
514 if (is0vect(cv->n))
515 return(MG_EILL);
516 if (!isflt(av[2]) || !isflt(av[3]))
517 return(MG_ETYPE);
518 minrad = atof(av[2]);
519 round0(minrad);
520 maxrad = atof(av[3]);
521 /* check orientation */
522 if (minrad > 0.)
523 sgn = 1;
524 else if (minrad < 0.)
525 sgn = -1;
526 else if (maxrad > 0.)
527 sgn = 1;
528 else if (maxrad < 0.)
529 sgn = -1;
530 else
531 return(MG_EILL);
532 if (sgn*(maxrad-minrad) <= 0.)
533 return(MG_EILL);
534 /* initialize */
535 warpconends = 1;
536 v2ent[3] = av[1];
537 for (j = 0; j < 3; j++)
538 sprintf(p2[j], FLTFMT, cv->p[j] +
539 .5*sgn*(maxrad-minrad)*cv->n[j]);
540 if ((rval = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
541 return(rval);
542 if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
543 return(rval);
544 sprintf(r2, FLTFMT, avgrad=.5*(minrad+maxrad));
545 /* run outer section */
546 for (i = 1; i <= 2*mg_nqcdivs; i++) {
547 theta = i*(PI/2)/mg_nqcdivs;
548 if ((rval = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
549 return(rval);
550 for (j = 0; j < 3; j++)
551 sprintf(p2[j], FLTFMT, cv->p[j] +
552 .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
553 if ((rval = mg_handle(MG_E_VERTEX, 2, v2ent)) != MG_OK)
554 return(rval);
555 if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
556 return(rval);
557 strcpy(r1, r2);
558 sprintf(r2, FLTFMT, avgrad + .5*(maxrad-minrad)*sin(theta));
559 if ((rval = mg_handle(MG_E_CONE, 5, conent)) != MG_OK)
560 return(rval);
561 }
562 /* run inner section */
563 sprintf(r2, FLTFMT, -.5*(minrad+maxrad));
564 for ( ; i <= 4*mg_nqcdivs; i++) {
565 theta = i*(PI/2)/mg_nqcdivs;
566 for (j = 0; j < 3; j++)
567 sprintf(p2[j], FLTFMT, cv->p[j] +
568 .5*sgn*(maxrad-minrad)*cos(theta)*cv->n[j]);
569 if ((rval = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
570 return(rval);
571 if ((rval = mg_handle(MG_E_VERTEX, 2, v2ent)) != MG_OK)
572 return(rval);
573 if ((rval = mg_handle(MG_E_POINT, 4, p2ent)) != MG_OK)
574 return(rval);
575 strcpy(r1, r2);
576 sprintf(r2, FLTFMT, -avgrad - .5*(maxrad-minrad)*sin(theta));
577 if ((rval = mg_handle(MG_E_CONE, 5, conent)) != MG_OK)
578 return(rval);
579 }
580 warpconends = 0;
581 return(MG_OK);
582 }
583
584
585 static int
586 e_cyl(ac, av) /* replace a cylinder with equivalent cone */
587 int ac;
588 char **av;
589 {
590 static char *avnew[6] = {mg_ename[MG_E_CONE]};
591
592 if (ac != 4)
593 return(MG_EARGC);
594 avnew[1] = av[1];
595 avnew[2] = av[2];
596 avnew[3] = av[3];
597 avnew[4] = av[2];
598 return(mg_handle(MG_E_CONE, 5, avnew));
599 }
600
601
602 static int
603 e_ring(ac, av) /* turn a ring into polygons */
604 int ac;
605 char **av;
606 {
607 static char p3[3][24], p4[3][24];
608 static char *nzent[5] = {mg_ename[MG_E_NORMAL],"0","0","0"};
609 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_rv1","="};
610 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_rv2","=","_rv3"};
611 static char *v3ent[4] = {mg_ename[MG_E_VERTEX],"_rv3","="};
612 static char *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
613 static char *v4ent[4] = {mg_ename[MG_E_VERTEX],"_rv4","="};
614 static char *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
615 static char *fent[6] = {mg_ename[MG_E_FACE],"_rv1","_rv2","_rv3","_rv4"};
616 register C_VERTEX *cv;
617 register int i, j;
618 FVECT u, v;
619 double minrad, maxrad;
620 int rv;
621 double theta, d;
622
623 if (ac != 4)
624 return(MG_EARGC);
625 if ((cv = c_getvert(av[1])) == NULL)
626 return(MG_EUNDEF);
627 if (is0vect(cv->n))
628 return(MG_EILL);
629 if (!isflt(av[2]) || !isflt(av[3]))
630 return(MG_ETYPE);
631 minrad = atof(av[2]);
632 round0(minrad);
633 maxrad = atof(av[3]);
634 if (minrad < 0. || maxrad <= minrad)
635 return(MG_EILL);
636 /* initialize */
637 make_axes(u, v, cv->n);
638 for (j = 0; j < 3; j++)
639 sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*u[j]);
640 if ((rv = mg_handle(MG_E_VERTEX, 3, v3ent)) != MG_OK)
641 return(rv);
642 if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
643 return(rv);
644 if (minrad == 0.) { /* closed */
645 v1ent[3] = av[1];
646 if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
647 return(rv);
648 if ((rv = mg_handle(MG_E_NORMAL, 4, nzent)) != MG_OK)
649 return(rv);
650 for (i = 1; i <= 4*mg_nqcdivs; i++) {
651 theta = i*(PI/2)/mg_nqcdivs;
652 if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
653 return(rv);
654 for (j = 0; j < 3; j++)
655 sprintf(p3[j], FLTFMT, cv->p[j] +
656 maxrad*u[j]*cos(theta) +
657 maxrad*v[j]*sin(theta));
658 if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
659 return(rv);
660 if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
661 return(rv);
662 if ((rv = mg_handle(MG_E_FACE, 4, fent)) != MG_OK)
663 return(rv);
664 }
665 } else { /* open */
666 if ((rv = mg_handle(MG_E_VERTEX, 3, v4ent)) != MG_OK)
667 return(rv);
668 for (j = 0; j < 3; j++)
669 sprintf(p4[j], FLTFMT, cv->p[j] + minrad*u[j]);
670 if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
671 return(rv);
672 v1ent[3] = "_rv4";
673 for (i = 1; i <= 4*mg_nqcdivs; i++) {
674 theta = i*(PI/2)/mg_nqcdivs;
675 if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
676 return(rv);
677 if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
678 return(rv);
679 for (j = 0; j < 3; j++) {
680 d = u[j]*cos(theta) + v[j]*sin(theta);
681 sprintf(p3[j], FLTFMT, cv->p[j] + maxrad*d);
682 sprintf(p4[j], FLTFMT, cv->p[j] + minrad*d);
683 }
684 if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
685 return(rv);
686 if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
687 return(rv);
688 if ((rv = mg_handle(MG_E_VERTEX, 2, v4ent)) != MG_OK)
689 return(rv);
690 if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
691 return(rv);
692 if ((rv = mg_handle(MG_E_FACE, 5, fent)) != MG_OK)
693 return(rv);
694 }
695 }
696 return(MG_OK);
697 }
698
699
700 static int
701 e_cone(ac, av) /* turn a cone into polygons */
702 int ac;
703 char **av;
704 {
705 static char p3[3][24], p4[3][24], n3[3][24], n4[3][24];
706 static char *v1ent[5] = {mg_ename[MG_E_VERTEX],"_cv1","="};
707 static char *v2ent[5] = {mg_ename[MG_E_VERTEX],"_cv2","=","_cv3"};
708 static char *v3ent[4] = {mg_ename[MG_E_VERTEX],"_cv3","="};
709 static char *p3ent[5] = {mg_ename[MG_E_POINT],p3[0],p3[1],p3[2]};
710 static char *n3ent[5] = {mg_ename[MG_E_NORMAL],n3[0],n3[1],n3[2]};
711 static char *v4ent[4] = {mg_ename[MG_E_VERTEX],"_cv4","="};
712 static char *p4ent[5] = {mg_ename[MG_E_POINT],p4[0],p4[1],p4[2]};
713 static char *n4ent[5] = {mg_ename[MG_E_NORMAL],n4[0],n4[1],n4[2]};
714 static char *fent[6] = {mg_ename[MG_E_FACE],"_cv1","_cv2","_cv3","_cv4"};
715 register C_VERTEX *cv1, *cv2;
716 register int i, j;
717 FVECT u, v, w;
718 double rad1, rad2;
719 int sgn;
720 double n1off, n2off;
721 double d;
722 int rv;
723 double theta;
724
725 if (ac != 5)
726 return(MG_EARGC);
727 if ((cv1 = c_getvert(av[1])) == NULL ||
728 (cv2 = c_getvert(av[3])) == NULL)
729 return(MG_EUNDEF);
730 if (!isflt(av[2]) || !isflt(av[4]))
731 return(MG_ETYPE);
732 rad1 = atof(av[2]);
733 round0(rad1);
734 rad2 = atof(av[4]);
735 round0(rad2);
736 if (rad1 == 0.) {
737 if (rad2 == 0.)
738 return(MG_EILL);
739 } else if (rad2 != 0.) {
740 if (rad1 < 0. ^ rad2 < 0.)
741 return(MG_EILL);
742 } else { /* swap */
743 C_VERTEX *cv;
744
745 cv = cv1;
746 cv1 = cv2;
747 cv2 = cv;
748 d = rad1;
749 rad1 = rad2;
750 rad2 = d;
751 }
752 sgn = rad2 < 0. ? -1 : 1;
753 /* initialize */
754 for (j = 0; j < 3; j++)
755 w[j] = cv1->p[j] - cv2->p[j];
756 if ((d = normalize(w)) == 0.)
757 return(MG_EILL);
758 n1off = n2off = (rad2 - rad1)/d;
759 if (warpconends) { /* hack for e_sph and e_torus */
760 d = atan(n2off) - (PI/4)/mg_nqcdivs;
761 if (d <= -PI/2+FTINY)
762 n2off = -FHUGE;
763 else
764 n2off = tan(d);
765 }
766 make_axes(u, v, w);
767 for (j = 0; j < 3; j++) {
768 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*u[j]);
769 if (n2off <= -FHUGE)
770 sprintf(n3[j], FLTFMT, -w[j]);
771 else
772 sprintf(n3[j], FLTFMT, u[j] + w[j]*n2off);
773 }
774 if ((rv = mg_handle(MG_E_VERTEX, 3, v3ent)) != MG_OK)
775 return(rv);
776 if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
777 return(rv);
778 if ((rv = mg_handle(MG_E_NORMAL, 4, n3ent)) != MG_OK)
779 return(rv);
780 if (rad1 == 0.) { /* triangles */
781 v1ent[3] = av[1];
782 if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
783 return(rv);
784 for (j = 0; j < 3; j++)
785 sprintf(n4[j], FLTFMT, w[j]);
786 if ((rv = mg_handle(MG_E_NORMAL, 4, n4ent)) != MG_OK)
787 return(rv);
788 for (i = 1; i <= 4*mg_nqcdivs; i++) {
789 theta = sgn*i*(PI/2)/mg_nqcdivs;
790 if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
791 return(rv);
792 for (j = 0; j < 3; j++) {
793 d = u[j]*cos(theta) + v[j]*sin(theta);
794 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
795 if (n2off > -FHUGE)
796 sprintf(n3[j], FLTFMT, d + w[j]*n2off);
797 }
798 if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
799 return(rv);
800 if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
801 return(rv);
802 if (n2off > -FHUGE &&
803 (rv = mg_handle(MG_E_NORMAL, 4, n3ent)) != MG_OK)
804 return(rv);
805 if ((rv = mg_handle(MG_E_FACE, 4, fent)) != MG_OK)
806 return(rv);
807 }
808 } else { /* quads */
809 v1ent[3] = "_cv4";
810 if (warpconends) { /* hack for e_sph and e_torus */
811 d = atan(n1off) + (PI/4)/mg_nqcdivs;
812 if (d >= PI/2-FTINY)
813 n1off = FHUGE;
814 else
815 n1off = tan(atan(n1off)+(PI/4)/mg_nqcdivs);
816 }
817 for (j = 0; j < 3; j++) {
818 sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*u[j]);
819 if (n1off >= FHUGE)
820 sprintf(n4[j], FLTFMT, w[j]);
821 else
822 sprintf(n4[j], FLTFMT, u[j] + w[j]*n1off);
823 }
824 if ((rv = mg_handle(MG_E_VERTEX, 3, v4ent)) != MG_OK)
825 return(rv);
826 if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
827 return(rv);
828 if ((rv = mg_handle(MG_E_NORMAL, 4, n4ent)) != MG_OK)
829 return(rv);
830 for (i = 1; i <= 4*mg_nqcdivs; i++) {
831 theta = sgn*i*(PI/2)/mg_nqcdivs;
832 if ((rv = mg_handle(MG_E_VERTEX, 4, v1ent)) != MG_OK)
833 return(rv);
834 if ((rv = mg_handle(MG_E_VERTEX, 4, v2ent)) != MG_OK)
835 return(rv);
836 for (j = 0; j < 3; j++) {
837 d = u[j]*cos(theta) + v[j]*sin(theta);
838 sprintf(p3[j], FLTFMT, cv2->p[j] + rad2*d);
839 if (n2off > -FHUGE)
840 sprintf(n3[j], FLTFMT, d + w[j]*n2off);
841 sprintf(p4[j], FLTFMT, cv1->p[j] + rad1*d);
842 if (n1off < FHUGE)
843 sprintf(n4[j], FLTFMT, d + w[j]*n1off);
844 }
845 if ((rv = mg_handle(MG_E_VERTEX, 2, v3ent)) != MG_OK)
846 return(rv);
847 if ((rv = mg_handle(MG_E_POINT, 4, p3ent)) != MG_OK)
848 return(rv);
849 if (n2off > -FHUGE &&
850 (rv = mg_handle(MG_E_NORMAL, 4, n3ent)) != MG_OK)
851 return(rv);
852 if ((rv = mg_handle(MG_E_VERTEX, 2, v4ent)) != MG_OK)
853 return(rv);
854 if ((rv = mg_handle(MG_E_POINT, 4, p4ent)) != MG_OK)
855 return(rv);
856 if (n1off < FHUGE &&
857 (rv = mg_handle(MG_E_NORMAL, 4, n4ent)) != MG_OK)
858 return(rv);
859 if ((rv = mg_handle(MG_E_FACE, 5, fent)) != MG_OK)
860 return(rv);
861 }
862 }
863 return(MG_OK);
864 }
865
866
867 static int
868 e_prism(ac, av) /* turn a prism into polygons */
869 int ac;
870 char **av;
871 {
872 static char p[3][24];
873 static char *vent[5] = {mg_ename[MG_E_VERTEX],NULL,"="};
874 static char *pent[5] = {mg_ename[MG_E_POINT],p[0],p[1],p[2]};
875 static char *znorm[5] = {mg_ename[MG_E_NORMAL],"0","0","0"};
876 char *newav[MG_MAXARGC], nvn[MG_MAXARGC-1][8];
877 double length;
878 int hasnorm;
879 FVECT v1, v2, v3, norm;
880 register C_VERTEX *cv;
881 C_VERTEX *cv0;
882 int rv;
883 register int i, j;
884 /* check arguments */
885 if (ac < 5)
886 return(MG_EARGC);
887 if (!isflt(av[ac-1]))
888 return(MG_ETYPE);
889 length = atof(av[ac-1]);
890 if (length <= FTINY && length >= -FTINY)
891 return(MG_EILL);
892 /* compute face normal */
893 if ((cv0 = c_getvert(av[1])) == NULL)
894 return(MG_EUNDEF);
895 hasnorm = 0;
896 norm[0] = norm[1] = norm[2] = 0.;
897 v1[0] = v1[1] = v1[2] = 0.;
898 for (i = 2; i < ac-1; i++) {
899 if ((cv = c_getvert(av[i])) == NULL)
900 return(MG_EUNDEF);
901 hasnorm += !is0vect(cv->n);
902 v2[0] = cv->p[0] - cv0->p[0];
903 v2[1] = cv->p[1] - cv0->p[1];
904 v2[2] = cv->p[2] - cv0->p[2];
905 fcross(v3, v1, v2);
906 norm[0] += v3[0];
907 norm[1] += v3[1];
908 norm[2] += v3[2];
909 VCOPY(v1, v2);
910 }
911 if (normalize(norm) == 0.)
912 return(MG_EILL);
913 /* create moved vertices */
914 for (i = 1; i < ac-1; i++) {
915 sprintf(nvn[i-1], "_pv%d", i);
916 vent[1] = nvn[i-1];
917 vent[3] = av[i];
918 if ((rv = mg_handle(MG_E_VERTEX, 4, vent)) != MG_OK)
919 return(rv);
920 cv = c_getvert(av[i]); /* checked above */
921 for (j = 0; j < 3; j++)
922 sprintf(p[j], FLTFMT, cv->p[j] - length*norm[j]);
923 if ((rv = mg_handle(MG_E_POINT, 4, pent)) != MG_OK)
924 return(rv);
925 }
926 /* make faces */
927 newav[0] = mg_ename[MG_E_FACE];
928 /* do the side faces */
929 newav[5] = NULL;
930 newav[3] = av[ac-2];
931 newav[4] = nvn[ac-3];
932 for (i = 1; i < ac-1; i++) {
933 newav[1] = nvn[i-1];
934 newav[2] = av[i];
935 if ((rv = mg_handle(MG_E_FACE, 5, newav)) != MG_OK)
936 return(rv);
937 newav[3] = newav[2];
938 newav[4] = newav[1];
939 }
940 /* do top face */
941 for (i = 1; i < ac-1; i++) {
942 if (hasnorm) { /* zero normals */
943 vent[1] = nvn[i-1];
944 if ((rv = mg_handle(MG_E_VERTEX, 2, vent)) != MG_OK)
945 return(rv);
946 if ((rv = mg_handle(MG_E_NORMAL, 4, znorm)) != MG_OK)
947 return(rv);
948 }
949 newav[ac-1-i] = nvn[i-1]; /* reverse */
950 }
951 if ((rv = mg_handle(MG_E_FACE, ac-1, newav)) != MG_OK)
952 return(rv);
953 /* do bottom face */
954 if (hasnorm)
955 for (i = 1; i < ac-1; i++) {
956 vent[1] = nvn[i-1];
957 vent[3] = av[i];
958 if ((rv = mg_handle(MG_E_VERTEX, 4, vent)) != MG_OK)
959 return(rv);
960 if ((rv = mg_handle(MG_E_NORMAL, 4, znorm)) != MG_OK)
961 return(rv);
962 newav[i] = nvn[i-1];
963 }
964 else
965 for (i = 1; i < ac-1; i++)
966 newav[i] = av[i];
967 newav[i] = NULL;
968 if ((rv = mg_handle(MG_E_FACE, i, newav)) != MG_OK)
969 return(rv);
970 return(MG_OK);
971 }
972
973
974 static int
975 put_cxy() /* put out current xy chromaticities */
976 {
977 static char xbuf[24], ybuf[24];
978 static char *ccom[4] = {mg_ename[MG_E_CXY], xbuf, ybuf};
979 int rv;
980
981 sprintf(xbuf, "%.4f", c_ccolor->cx);
982 sprintf(ybuf, "%.4f", c_ccolor->cy);
983 if ((rv = mg_handle(MG_E_CXY, 3, ccom)) != MG_OK)
984 return(rv);
985 return(MG_OK);
986 }
987
988
989 static int
990 put_cspec() /* put out current color spectrum */
991 {
992 char wl[2][6], vbuf[C_CNSS][24];
993 char *newav[C_CNSS+4];
994 double sf;
995 register int i;
996
997 if (mg_ehand[MG_E_CSPEC] != c_hcolor) {
998 sprintf(wl[0], "%d", C_CMINWL);
999 sprintf(wl[1], "%d", C_CMAXWL);
1000 newav[0] = mg_ename[MG_E_CSPEC];
1001 newav[1] = wl[0];
1002 newav[2] = wl[1];
1003 sf = (double)C_CNSS / c_ccolor->ssum;
1004 for (i = 0; i < C_CNSS; i++) {
1005 sprintf(vbuf[i], "%.4f", sf*c_ccolor->ssamp[i]);
1006 newav[i+3] = vbuf[i];
1007 }
1008 newav[C_CNSS+3] = NULL;
1009 if ((i = mg_handle(MG_E_CSPEC, C_CNSS+3, newav)) != MG_OK)
1010 return(i);
1011 }
1012 return(MG_OK);
1013 }
1014
1015
1016 static int
1017 e_cspec(ac, av) /* handle spectral color */
1018 int ac;
1019 char **av;
1020 {
1021 /* convert to xy chromaticity */
1022 c_ccvt(c_ccolor, C_CSXY);
1023 /* if it's really their handler, use it */
1024 if (mg_ehand[MG_E_CXY] != c_hcolor)
1025 return(put_cxy());
1026 return(MG_OK);
1027 }
1028
1029
1030 static int
1031 e_cmix(ac, av) /* handle mixing of colors */
1032 int ac;
1033 char **av;
1034 {
1035 /*
1036 * Contorted logic works as follows:
1037 * 1. the colors are already mixed in c_hcolor() support function
1038 * 2. if we would handle a spectral result, make sure it's not
1039 * 3. if c_hcolor() would handle a spectral result, don't bother
1040 * 4. otherwise, make cspec entity and pass it to their handler
1041 * 5. if we have only xy results, handle it as c_spec() would
1042 */
1043 if (mg_ehand[MG_E_CSPEC] == e_cspec)
1044 c_ccvt(c_ccolor, C_CSXY);
1045 else if (c_ccolor->flags & C_CDSPEC)
1046 return(put_cspec());
1047 if (mg_ehand[MG_E_CXY] != c_hcolor)
1048 return(put_cxy());
1049 return(MG_OK);
1050 }
1051
1052
1053 static int
1054 e_cct(ac, av) /* handle color temperature */
1055 int ac;
1056 char **av;
1057 {
1058 /*
1059 * Logic is similar to e_cmix here. Support handler has already
1060 * converted temperature to spectral color. Put it out as such
1061 * if they support it, otherwise convert to xy chromaticity and
1062 * put it out if they handle it.
1063 */
1064 if (mg_ehand[MG_E_CSPEC] != e_cspec)
1065 return(put_cspec());
1066 c_ccvt(c_ccolor, C_CSXY);
1067 if (mg_ehand[MG_E_CXY] != c_hcolor)
1068 return(put_cxy());
1069 return(MG_OK);
1070 }