ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.13
Committed: Wed Jun 15 15:07:08 1994 UTC (29 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.12: +31 -23 lines
Log Message:
further reduced complexity and size of barycentric calculation

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