ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.15
Committed: Wed Jun 22 12:35:59 1994 UTC (29 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.14: +2 -75 lines
Log Message:
moved barycentric routines into tmesh.c

File Contents

# User Rev Content
1 greg 2.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     * Convert a Wavefront .obj file to Radiance format.
9     *
10 greg 2.5 * Currently, we support only polygonal geometry. Non-planar
11     * faces are broken rather haphazardly into triangles.
12 greg 2.3 * Also, texture map indices only work for triangles, though
13 greg 2.7 * I'm not sure they work correctly. (Taken out -- see TEXMAPS defines.)
14 greg 2.1 */
15    
16     #include "standard.h"
17    
18 greg 2.3 #include "trans.h"
19    
20 greg 2.15 #include "tmesh.h"
21    
22 greg 2.1 #include <ctype.h>
23    
24     #define PATNAME "M-pat" /* mesh pattern name (reused) */
25     #define TEXNAME "M-nor" /* mesh texture name (reused) */
26 greg 2.3 #define DEFOBJ "unnamed" /* default object name */
27     #define DEFMAT "white" /* default material name */
28 greg 2.1
29     #define pvect(v) printf("%18.12g %18.12g %18.12g\n",(v)[0],(v)[1],(v)[2])
30    
31     FVECT *vlist; /* our vertex list */
32     int nvs; /* number of vertices in our list */
33     FVECT *vnlist; /* vertex normal list */
34     int nvns;
35 greg 2.3 FLOAT (*vtlist)[2]; /* map vertex list */
36 greg 2.1 int nvts;
37    
38 greg 2.3 typedef int VNDX[3]; /* vertex index (point,map,normal) */
39 greg 2.1
40 greg 2.3 #define CHUNKSIZ 256 /* vertex allocation chunk size */
41 greg 2.1
42     #define MAXARG 64 /* maximum # arguments in a statement */
43    
44 greg 2.3 /* qualifiers */
45     #define Q_MTL 0
46     #define Q_MAP 1
47     #define Q_GRP 2
48     #define Q_OBJ 3
49     #define Q_FAC 4
50     #define NQUALS 5
51 greg 2.1
52 greg 2.3 char *qname[NQUALS] = {
53     "Material",
54     "Map",
55     "Group",
56     "Object",
57     "Face",
58     };
59    
60     QLIST qlist = {NQUALS, qname};
61     /* valid qualifier ids */
62     IDLIST qual[NQUALS];
63     /* mapping rules */
64     RULEHD *ourmapping = NULL;
65    
66     char *defmat = DEFMAT; /* default (starting) material name */
67     char *defobj = DEFOBJ; /* default (starting) object name */
68    
69 greg 2.8 int flatten = 0; /* discard surface normal information */
70    
71 greg 2.3 char *getmtl(), *getonm();
72    
73     char mapname[128]; /* current picture file */
74 greg 2.1 char matname[64]; /* current material name */
75 greg 2.3 char group[16][32]; /* current group names */
76 greg 2.1 char objname[128]; /* current object name */
77 greg 2.6 char *inpfile; /* input file name */
78 greg 2.1 int lineno; /* current line number */
79 greg 2.6 int faceno; /* current face number */
80 greg 2.1
81    
82 greg 2.3 main(argc, argv) /* read in .obj file and convert */
83 greg 2.1 int argc;
84     char *argv[];
85     {
86 greg 2.6 int donames = 0;
87 greg 2.1 int i;
88    
89     for (i = 1; i < argc && argv[i][0] == '-'; i++)
90     switch (argv[i][1]) {
91     case 'o': /* object name */
92     defobj = argv[++i];
93     break;
94 greg 2.3 case 'n': /* just produce name list */
95     donames++;
96 greg 2.1 break;
97 greg 2.3 case 'm': /* use custom mapfile */
98     ourmapping = getmapping(argv[++i], &qlist);
99 greg 2.1 break;
100 greg 2.8 case 'f': /* flatten surfaces */
101     flatten++;
102     break;
103 greg 2.1 default:
104 greg 2.3 goto userr;
105 greg 2.1 }
106 greg 2.3 if (i > argc | i < argc-1)
107     goto userr;
108     if (i == argc)
109 greg 2.6 inpfile = "<stdin>";
110     else if (freopen(inpfile=argv[i], "r", stdin) == NULL) {
111     fprintf(stderr, "%s: cannot open\n", inpfile);
112 greg 2.3 exit(1);
113     }
114     if (donames) { /* scan for ids */
115     getnames(stdin);
116 greg 2.6 printf("filename \"%s\"\n", inpfile);
117 greg 2.3 printf("filetype \"Wavefront\"\n");
118     write_quals(&qlist, qual, stdout);
119     printf("qualifier %s begin\n", qlist.qual[Q_FAC]);
120     printf("[%d:%d]\n", 1, faceno);
121     printf("end\n");
122     } else { /* translate file */
123     printf("# ");
124     printargs(argc, argv, stdout);
125 greg 2.6 convert(stdin);
126 greg 2.3 }
127     exit(0);
128     userr:
129 greg 2.9 fprintf(stderr, "Usage: %s [-o obj][-m mapping][-n][-f] [file.obj]\n",
130 greg 2.3 argv[0]);
131     exit(1);
132     }
133    
134    
135     getnames(fp) /* get valid qualifier names */
136     FILE *fp;
137     {
138     char *argv[MAXARG];
139     int argc;
140     ID tmpid;
141     register int i;
142    
143     while (argc = getstmt(argv, fp))
144     switch (argv[0][0]) {
145     case 'f': /* face */
146     if (!argv[0][1])
147     faceno++;
148     break;
149     case 'u':
150     if (!strcmp(argv[0], "usemtl")) { /* material */
151     if (argc < 2)
152     break; /* not fatal */
153     tmpid.number = 0;
154     tmpid.name = argv[1];
155     findid(&qual[Q_MTL], &tmpid, 1);
156     } else if (!strcmp(argv[0], "usemap")) {/* map */
157     if (argc < 2 || !strcmp(argv[1], "off"))
158     break; /* not fatal */
159     tmpid.number = 0;
160     tmpid.name = argv[1];
161     findid(&qual[Q_MAP], &tmpid, 1);
162 greg 2.1 }
163 greg 2.3 break;
164     case 'o': /* object name */
165     if (argv[0][1] || argc < 2)
166     break;
167     tmpid.number = 0;
168     tmpid.name = argv[1];
169     findid(&qual[Q_OBJ], &tmpid, 1);
170     break;
171     case 'g': /* group name(s) */
172     if (argv[0][1])
173     break;
174     tmpid.number = 0;
175     for (i = 1; i < argc; i++) {
176     tmpid.name = argv[i];
177     findid(&qual[Q_GRP], &tmpid, 1);
178     }
179     break;
180 greg 2.1 }
181     }
182    
183    
184 greg 2.6 convert(fp) /* convert a T-mesh */
185 greg 2.1 FILE *fp;
186     {
187     char *argv[MAXARG];
188     int argc;
189     int nstats, nunknown;
190     register int i;
191 greg 2.6
192 greg 2.1 nstats = nunknown = 0;
193     /* scan until EOF */
194     while (argc = getstmt(argv, fp)) {
195     switch (argv[0][0]) {
196     case 'v': /* vertex */
197     switch (argv[0][1]) {
198     case '\0': /* point */
199     if (badarg(argc-1,argv+1,"fff"))
200 greg 2.6 syntax("Bad vertex");
201 greg 2.1 newv(atof(argv[1]), atof(argv[2]),
202     atof(argv[3]));
203     break;
204     case 'n': /* normal */
205     if (argv[0][2])
206     goto unknown;
207     if (badarg(argc-1,argv+1,"fff"))
208 greg 2.6 syntax("Bad normal");
209 greg 2.1 if (!newvn(atof(argv[1]), atof(argv[2]),
210     atof(argv[3])))
211 greg 2.6 syntax("Zero normal");
212 greg 2.1 break;
213 greg 2.3 case 't': /* texture map */
214 greg 2.1 if (argv[0][2])
215     goto unknown;
216     if (badarg(argc-1,argv+1,"ff"))
217     goto unknown;
218     newvt(atof(argv[1]), atof(argv[2]));
219     break;
220     default:
221     goto unknown;
222     }
223     break;
224     case 'f': /* face */
225     if (argv[0][1])
226     goto unknown;
227 greg 2.3 faceno++;
228 greg 2.1 switch (argc-1) {
229     case 0: case 1: case 2:
230 greg 2.6 syntax("Too few vertices");
231 greg 2.1 break;
232     case 3:
233     if (!puttri(argv[1], argv[2], argv[3]))
234 greg 2.6 syntax("Bad triangle");
235 greg 2.1 break;
236     default:
237     if (!putface(argc-1, argv+1))
238 greg 2.6 syntax("Bad face");
239 greg 2.1 break;
240     }
241     break;
242     case 'u':
243     if (!strcmp(argv[0], "usemtl")) { /* material */
244     if (argc < 2)
245     break; /* not fatal */
246     strcpy(matname, argv[1]);
247     } else if (!strcmp(argv[0], "usemap")) {/* map */
248     if (argc < 2)
249     break; /* not fatal */
250     if (!strcmp(argv[1], "off"))
251 greg 2.3 mapname[0] = '\0';
252 greg 2.1 else
253 greg 2.7 sprintf(mapname, "%s.pic", argv[1]);
254 greg 2.1 } else
255     goto unknown;
256     break;
257     case 'o': /* object name */
258     if (argv[0][1])
259     goto unknown;
260     if (argc < 2)
261     break; /* not fatal */
262     strcpy(objname, argv[1]);
263     break;
264     case 'g': /* group name(s) */
265     if (argv[0][1])
266     goto unknown;
267     for (i = 1; i < argc; i++)
268 greg 2.3 strcpy(group[i-1], argv[i]);
269     group[i-1][0] = '\0';
270 greg 2.1 break;
271     case '#': /* comment */
272 greg 2.7 printargs(argc, argv, stdout);
273 greg 2.1 break;
274     default:; /* something we don't deal with */
275     unknown:
276     nunknown++;
277     break;
278     }
279     nstats++;
280     }
281 greg 2.6 printf("\n# Done processing file: %s\n", inpfile);
282 greg 2.1 printf("# %d lines, %d statements, %d unrecognized\n",
283     lineno, nstats, nunknown);
284     }
285    
286    
287     int
288     getstmt(av, fp) /* read the next statement from fp */
289     register char *av[MAXARG];
290     FILE *fp;
291     {
292     extern char *fgetline();
293     static char sbuf[MAXARG*10];
294     register char *cp;
295     register int i;
296    
297     do {
298     if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL)
299     return(0);
300     i = 0;
301     for ( ; ; ) {
302     while (isspace(*cp) || *cp == '\\') {
303     if (*cp == '\n')
304     lineno++;
305     *cp++ = '\0';
306     }
307     if (!*cp || i >= MAXARG-1)
308     break;
309     av[i++] = cp;
310     while (*++cp && !isspace(*cp))
311     ;
312     }
313     av[i] = NULL;
314     lineno++;
315     } while (!i);
316    
317     return(i);
318     }
319    
320 greg 2.3
321     char *
322     getmtl() /* figure material for this face */
323     {
324     register RULEHD *rp = ourmapping;
325    
326 greg 2.6 if (rp == NULL) { /* no rule set */
327     if (matname[0])
328     return(matname);
329     if (group[0][0])
330     return(group[0]);
331     return(defmat);
332     }
333 greg 2.3 /* check for match */
334     do {
335     if (matchrule(rp)) {
336     if (!strcmp(rp->mnam, VOIDID))
337     return(NULL); /* match is null */
338     return(rp->mnam);
339     }
340     rp = rp->next;
341     } while (rp != NULL);
342     /* no match found */
343     return(NULL);
344     }
345    
346    
347     char *
348     getonm() /* invent a good name for object */
349     {
350     static char name[64];
351     register char *cp1, *cp2;
352     register int i;
353 greg 2.6 /* check for preset */
354     if (objname[0])
355     return(objname);
356     if (!group[0][0])
357     return(defobj);
358 greg 2.3 cp1 = name; /* else make name out of groups */
359     for (i = 0; group[i][0]; i++) {
360     cp2 = group[i];
361     if (cp1 > name)
362     *cp1++ = '.';
363     while (*cp1 = *cp2++)
364     if (++cp1 >= name+sizeof(name)-2) {
365     *cp1 = '\0';
366     return(name);
367     }
368     }
369     return(name);
370     }
371    
372    
373     matchrule(rp) /* check for a match on this rule */
374     register RULEHD *rp;
375     {
376     ID tmpid;
377     int gotmatch;
378     register int i;
379    
380     if (rp->qflg & FL(Q_MTL)) {
381 greg 2.6 if (!matname[0])
382     return(0);
383 greg 2.3 tmpid.number = 0;
384     tmpid.name = matname;
385     if (!matchid(&tmpid, &idm(rp)[Q_MTL]))
386     return(0);
387     }
388     if (rp->qflg & FL(Q_MAP)) {
389 greg 2.6 if (!mapname[0])
390     return(0);
391 greg 2.3 tmpid.number = 0;
392     tmpid.name = mapname;
393     if (!matchid(&tmpid, &idm(rp)[Q_MAP]))
394     return(0);
395     }
396     if (rp->qflg & FL(Q_GRP)) {
397     tmpid.number = 0;
398     gotmatch = 0;
399     for (i = 0; group[i][0]; i++) {
400     tmpid.name = group[i];
401     gotmatch |= matchid(&tmpid, &idm(rp)[Q_GRP]);
402     }
403     if (!gotmatch)
404     return(0);
405     }
406     if (rp->qflg & FL(Q_OBJ)) {
407 greg 2.6 if (!objname[0])
408     return(0);
409 greg 2.3 tmpid.number = 0;
410     tmpid.name = objname;
411     if (!matchid(&tmpid, &idm(rp)[Q_OBJ]))
412     return(0);
413     }
414     if (rp->qflg & FL(Q_FAC)) {
415     tmpid.name = NULL;
416     tmpid.number = faceno;
417     if (!matchid(&tmpid, &idm(rp)[Q_FAC]))
418     return(0);
419     }
420     return(1);
421     }
422    
423    
424 greg 2.1 cvtndx(vi, vs) /* convert vertex string to index */
425     register VNDX vi;
426     register char *vs;
427     {
428     /* get point */
429     vi[0] = atoi(vs);
430     if (vi[0] > 0) {
431     if (vi[0]-- > nvs)
432     return(0);
433     } else if (vi[0] < 0) {
434 greg 2.9 vi[0] += nvs;
435 greg 2.1 if (vi[0] < 0)
436     return(0);
437     } else
438     return(0);
439 greg 2.3 /* get map */
440 greg 2.1 while (*vs)
441     if (*vs++ == '/')
442     break;
443     vi[1] = atoi(vs);
444     if (vi[1] > 0) {
445     if (vi[1]-- > nvts)
446     return(0);
447     } else if (vi[1] < 0) {
448 greg 2.9 vi[1] += nvts;
449 greg 2.1 if (vi[1] < 0)
450     return(0);
451     } else
452     vi[1] = -1;
453     /* get normal */
454     while (*vs)
455     if (*vs++ == '/')
456     break;
457     vi[2] = atoi(vs);
458     if (vi[2] > 0) {
459     if (vi[2]-- > nvns)
460     return(0);
461     } else if (vi[2] < 0) {
462 greg 2.9 vi[2] += nvns;
463 greg 2.1 if (vi[2] < 0)
464     return(0);
465     } else
466     vi[2] = -1;
467     return(1);
468     }
469    
470    
471 greg 2.9 nonplanar(ac, av) /* are vertices non-planar? */
472 greg 2.1 register int ac;
473     register char **av;
474     {
475     VNDX vi;
476 greg 2.5 FLOAT *p0, *p1;
477     FVECT v1, v2, nsum, newn;
478     double d;
479     register int i;
480    
481     if (!cvtndx(vi, av[0]))
482     return(0);
483 greg 2.12 if (!flatten && vi[2] >= 0)
484 greg 2.5 return(1); /* has interpolated normals */
485     if (ac < 4)
486     return(0); /* it's a triangle! */
487     /* set up */
488     p0 = vlist[vi[0]];
489     if (!cvtndx(vi, av[1]))
490     return(0); /* error gets caught later */
491     nsum[0] = nsum[1] = nsum[2] = 0.;
492     p1 = vlist[vi[0]];
493     fvsum(v2, p1, p0, -1.0);
494     for (i = 2; i < ac; i++) {
495     VCOPY(v1, v2);
496     if (!cvtndx(vi, av[i]))
497     return(0);
498     p1 = vlist[vi[0]];
499     fvsum(v2, p1, p0, -1.0);
500     fcross(newn, v1, v2);
501     if (normalize(newn) == 0.0) {
502     if (i < 3)
503     return(1); /* can't deal with this */
504     fvsum(nsum, nsum, nsum, 1./(i-2));
505     continue;
506     }
507     d = fdot(newn,nsum);
508     if (d >= 0) {
509     if (d < (1.0-FTINY)*(i-2))
510     return(1);
511     fvsum(nsum, nsum, newn, 1.0);
512     } else {
513     if (d > -(1.0-FTINY)*(i-2))
514     return(1);
515     fvsum(nsum, nsum, newn, -1.0);
516     }
517     }
518     return(0);
519     }
520    
521    
522     putface(ac, av) /* put out an N-sided polygon */
523     int ac;
524     register char **av;
525     {
526     VNDX vi;
527 greg 2.7 char *cp;
528 greg 2.5 register int i;
529 greg 2.1
530 greg 2.11 if (nonplanar(ac, av)) { /* break into triangles */
531     while (ac > 2) {
532     if (!puttri(av[0], av[1], av[2]))
533 greg 2.5 return(0);
534 greg 2.11 ac--; /* remove vertex & rotate */
535 greg 2.7 cp = av[0];
536     for (i = 0; i < ac-1; i++)
537 greg 2.11 av[i] = av[i+2];
538 greg 2.7 av[i] = cp;
539 greg 2.5 }
540     return(1);
541     }
542 greg 2.7 if ((cp = getmtl()) == NULL)
543 greg 2.3 return(-1);
544 greg 2.7 printf("\n%s polygon %s.%d\n", cp, getonm(), faceno);
545 greg 2.1 printf("0\n0\n%d\n", 3*ac);
546 greg 2.5 for (i = 0; i < ac; i++) {
547     if (!cvtndx(vi, av[i]))
548 greg 2.1 return(0);
549     pvect(vlist[vi[0]]);
550     }
551     return(1);
552     }
553    
554    
555     puttri(v1, v2, v3) /* put out a triangle */
556     char *v1, *v2, *v3;
557     {
558 greg 2.3 char *mod;
559 greg 2.1 VNDX v1i, v2i, v3i;
560     BARYCCM bvecs;
561 greg 2.14 FLOAT bcoor[3][3];
562 greg 2.2 int texOK, patOK;
563 greg 2.13 register int i;
564 greg 2.1
565 greg 2.3 if ((mod = getmtl()) == NULL)
566     return(-1);
567    
568 greg 2.1 if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3))
569     return(0);
570     /* compute barycentric coordinates */
571 greg 2.8 texOK = !flatten && (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0);
572 greg 2.7 #ifdef TEXMAPS
573 greg 2.3 patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0);
574 greg 2.7 #else
575     patOK = 0;
576     #endif
577 greg 2.2 if (texOK | patOK)
578 greg 2.10 if (comp_baryc(&bvecs, vlist[v1i[0]], vlist[v2i[0]],
579 greg 2.1 vlist[v3i[0]]) < 0)
580 greg 2.2 return(-1);
581 greg 2.1 /* put out texture (if any) */
582 greg 2.2 if (texOK) {
583 greg 2.1 printf("\n%s texfunc %s\n", mod, TEXNAME);
584     mod = TEXNAME;
585     printf("4 dx dy dz %s\n", TCALNAME);
586 greg 2.13 printf("0\n");
587     for (i = 0; i < 3; i++) {
588     bcoor[i][0] = vnlist[v1i[2]][i];
589     bcoor[i][1] = vnlist[v2i[2]][i];
590     bcoor[i][2] = vnlist[v3i[2]][i];
591     }
592     put_baryc(&bvecs, bcoor, 3);
593 greg 2.1 }
594 greg 2.7 #ifdef TEXMAPS
595 greg 2.1 /* put out pattern (if any) */
596 greg 2.2 if (patOK) {
597 greg 2.1 printf("\n%s colorpict %s\n", mod, PATNAME);
598     mod = PATNAME;
599 greg 2.3 printf("7 noneg noneg noneg %s %s u v\n", mapname, TCALNAME);
600 greg 2.13 printf("0\n");
601     for (i = 0; i < 2; i++) {
602     bcoor[i][0] = vtlist[v1i[1]][i];
603     bcoor[i][1] = vtlist[v2i[1]][i];
604     bcoor[i][2] = vtlist[v3i[1]][i];
605     }
606     put_baryc(&bvecs, bcoor, 2);
607 greg 2.1 }
608 greg 2.7 #endif
609 greg 2.1 /* put out triangle */
610 greg 2.3 printf("\n%s polygon %s.%d\n", mod, getonm(), faceno);
611 greg 2.1 printf("0\n0\n9\n");
612     pvect(vlist[v1i[0]]);
613     pvect(vlist[v2i[0]]);
614     pvect(vlist[v3i[0]]);
615    
616     return(1);
617     }
618    
619    
620     freeverts() /* free all vertices */
621     {
622     if (nvs) {
623     free((char *)vlist);
624     nvs = 0;
625     }
626     if (nvts) {
627     free((char *)vtlist);
628     nvts = 0;
629     }
630     if (nvns) {
631     free((char *)vnlist);
632     nvns = 0;
633     }
634     }
635    
636    
637     int
638     newv(x, y, z) /* create a new vertex */
639     double x, y, z;
640     {
641     if (!(nvs%CHUNKSIZ)) { /* allocate next block */
642     if (nvs == 0)
643     vlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
644     else
645     vlist = (FVECT *)realloc((char *)vlist,
646     (nvs+CHUNKSIZ)*sizeof(FVECT));
647     if (vlist == NULL) {
648     fprintf(stderr,
649     "Out of memory while allocating vertex %d\n", nvs);
650     exit(1);
651     }
652     }
653     /* assign new vertex */
654     vlist[nvs][0] = x;
655     vlist[nvs][1] = y;
656     vlist[nvs][2] = z;
657     return(++nvs);
658     }
659    
660    
661     int
662     newvn(x, y, z) /* create a new vertex normal */
663     double x, y, z;
664     {
665     if (!(nvns%CHUNKSIZ)) { /* allocate next block */
666     if (nvns == 0)
667     vnlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
668     else
669     vnlist = (FVECT *)realloc((char *)vnlist,
670     (nvns+CHUNKSIZ)*sizeof(FVECT));
671     if (vnlist == NULL) {
672     fprintf(stderr,
673     "Out of memory while allocating normal %d\n", nvns);
674     exit(1);
675     }
676     }
677     /* assign new normal */
678     vnlist[nvns][0] = x;
679     vnlist[nvns][1] = y;
680     vnlist[nvns][2] = z;
681     if (normalize(vnlist[nvns]) == 0.0)
682     return(0);
683     return(++nvns);
684     }
685    
686    
687     int
688 greg 2.3 newvt(x, y) /* create a new texture map vertex */
689 greg 2.1 double x, y;
690     {
691     if (!(nvts%CHUNKSIZ)) { /* allocate next block */
692     if (nvts == 0)
693     vtlist = (FLOAT (*)[2])malloc(CHUNKSIZ*2*sizeof(FLOAT));
694     else
695     vtlist = (FLOAT (*)[2])realloc((char *)vtlist,
696     (nvts+CHUNKSIZ)*2*sizeof(FLOAT));
697     if (vtlist == NULL) {
698     fprintf(stderr,
699     "Out of memory while allocating texture vertex %d\n",
700     nvts);
701     exit(1);
702     }
703     }
704 greg 2.3 /* assign new vertex */
705 greg 2.1 vtlist[nvts][0] = x;
706     vtlist[nvts][1] = y;
707     return(++nvts);
708     }
709    
710    
711 greg 2.6 syntax(er) /* report syntax error and exit */
712 greg 2.1 char *er;
713     {
714     fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n",
715 greg 2.6 inpfile, lineno, er);
716 greg 2.1 exit(1);
717     }