ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/parser.c
Revision: 1.15
Committed: Thu Apr 13 12:11:30 1995 UTC (29 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.14: +1 -0 lines
Log Message:
added material index of refraction

File Contents

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