ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.14
Committed: Wed Jun 15 19:06:04 1994 UTC (29 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.13: +2 -2 lines
Log Message:
cosmetic fix to parameters of put_baryc

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.1 #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 greg 2.3 #define DEFOBJ "unnamed" /* default object name */
26     #define DEFMAT "white" /* default material name */
27 greg 2.1
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 greg 2.3 FLOAT (*vtlist)[2]; /* map vertex list */
37 greg 2.1 int nvts;
38    
39 greg 2.10 typedef struct {
40     int ax; /* major axis */
41     FLOAT tm[2][3]; /* transformation */
42     } BARYCCM;
43 greg 2.1
44 greg 2.3 typedef int VNDX[3]; /* vertex index (point,map,normal) */
45 greg 2.1
46 greg 2.3 #define CHUNKSIZ 256 /* vertex allocation chunk size */
47 greg 2.1
48     #define MAXARG 64 /* maximum # arguments in a statement */
49    
50 greg 2.3 /* 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 greg 2.1
58 greg 2.3 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 greg 2.8 int flatten = 0; /* discard surface normal information */
76    
77 greg 2.3 char *getmtl(), *getonm();
78    
79     char mapname[128]; /* current picture file */
80 greg 2.1 char matname[64]; /* current material name */
81 greg 2.3 char group[16][32]; /* current group names */
82 greg 2.1 char objname[128]; /* current object name */
83 greg 2.6 char *inpfile; /* input file name */
84 greg 2.1 int lineno; /* current line number */
85 greg 2.6 int faceno; /* current face number */
86 greg 2.1
87    
88 greg 2.3 main(argc, argv) /* read in .obj file and convert */
89 greg 2.1 int argc;
90     char *argv[];
91     {
92 greg 2.6 int donames = 0;
93 greg 2.1 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 greg 2.3 case 'n': /* just produce name list */
101     donames++;
102 greg 2.1 break;
103 greg 2.3 case 'm': /* use custom mapfile */
104     ourmapping = getmapping(argv[++i], &qlist);
105 greg 2.1 break;
106 greg 2.8 case 'f': /* flatten surfaces */
107     flatten++;
108     break;
109 greg 2.1 default:
110 greg 2.3 goto userr;
111 greg 2.1 }
112 greg 2.3 if (i > argc | i < argc-1)
113     goto userr;
114     if (i == argc)
115 greg 2.6 inpfile = "<stdin>";
116     else if (freopen(inpfile=argv[i], "r", stdin) == NULL) {
117     fprintf(stderr, "%s: cannot open\n", inpfile);
118 greg 2.3 exit(1);
119     }
120     if (donames) { /* scan for ids */
121     getnames(stdin);
122 greg 2.6 printf("filename \"%s\"\n", inpfile);
123 greg 2.3 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 greg 2.6 convert(stdin);
132 greg 2.3 }
133     exit(0);
134     userr:
135 greg 2.9 fprintf(stderr, "Usage: %s [-o obj][-m mapping][-n][-f] [file.obj]\n",
136 greg 2.3 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 greg 2.1 }
169 greg 2.3 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 greg 2.1 }
187     }
188    
189    
190 greg 2.6 convert(fp) /* convert a T-mesh */
191 greg 2.1 FILE *fp;
192     {
193     char *argv[MAXARG];
194     int argc;
195     int nstats, nunknown;
196     register int i;
197 greg 2.6
198 greg 2.1 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 greg 2.6 syntax("Bad vertex");
207 greg 2.1 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 greg 2.6 syntax("Bad normal");
215 greg 2.1 if (!newvn(atof(argv[1]), atof(argv[2]),
216     atof(argv[3])))
217 greg 2.6 syntax("Zero normal");
218 greg 2.1 break;
219 greg 2.3 case 't': /* texture map */
220 greg 2.1 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 greg 2.3 faceno++;
234 greg 2.1 switch (argc-1) {
235     case 0: case 1: case 2:
236 greg 2.6 syntax("Too few vertices");
237 greg 2.1 break;
238     case 3:
239     if (!puttri(argv[1], argv[2], argv[3]))
240 greg 2.6 syntax("Bad triangle");
241 greg 2.1 break;
242     default:
243     if (!putface(argc-1, argv+1))
244 greg 2.6 syntax("Bad face");
245 greg 2.1 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 greg 2.3 mapname[0] = '\0';
258 greg 2.1 else
259 greg 2.7 sprintf(mapname, "%s.pic", argv[1]);
260 greg 2.1 } 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 greg 2.3 strcpy(group[i-1], argv[i]);
275     group[i-1][0] = '\0';
276 greg 2.1 break;
277     case '#': /* comment */
278 greg 2.7 printargs(argc, argv, stdout);
279 greg 2.1 break;
280     default:; /* something we don't deal with */
281     unknown:
282     nunknown++;
283     break;
284     }
285     nstats++;
286     }
287 greg 2.6 printf("\n# Done processing file: %s\n", inpfile);
288 greg 2.1 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 greg 2.3
327     char *
328     getmtl() /* figure material for this face */
329     {
330     register RULEHD *rp = ourmapping;
331    
332 greg 2.6 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 greg 2.3 /* 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 greg 2.6 /* check for preset */
360     if (objname[0])
361     return(objname);
362     if (!group[0][0])
363     return(defobj);
364 greg 2.3 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 greg 2.6 if (!matname[0])
388     return(0);
389 greg 2.3 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 greg 2.6 if (!mapname[0])
396     return(0);
397 greg 2.3 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 greg 2.6 if (!objname[0])
414     return(0);
415 greg 2.3 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 greg 2.1 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 greg 2.9 vi[0] += nvs;
441 greg 2.1 if (vi[0] < 0)
442     return(0);
443     } else
444     return(0);
445 greg 2.3 /* get map */
446 greg 2.1 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 greg 2.9 vi[1] += nvts;
455 greg 2.1 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 greg 2.9 vi[2] += nvns;
469 greg 2.1 if (vi[2] < 0)
470     return(0);
471     } else
472     vi[2] = -1;
473     return(1);
474     }
475    
476    
477 greg 2.9 nonplanar(ac, av) /* are vertices non-planar? */
478 greg 2.1 register int ac;
479     register char **av;
480     {
481     VNDX vi;
482 greg 2.5 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 greg 2.12 if (!flatten && vi[2] >= 0)
490 greg 2.5 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 greg 2.7 char *cp;
534 greg 2.5 register int i;
535 greg 2.1
536 greg 2.11 if (nonplanar(ac, av)) { /* break into triangles */
537     while (ac > 2) {
538     if (!puttri(av[0], av[1], av[2]))
539 greg 2.5 return(0);
540 greg 2.11 ac--; /* remove vertex & rotate */
541 greg 2.7 cp = av[0];
542     for (i = 0; i < ac-1; i++)
543 greg 2.11 av[i] = av[i+2];
544 greg 2.7 av[i] = cp;
545 greg 2.5 }
546     return(1);
547     }
548 greg 2.7 if ((cp = getmtl()) == NULL)
549 greg 2.3 return(-1);
550 greg 2.7 printf("\n%s polygon %s.%d\n", cp, getonm(), faceno);
551 greg 2.1 printf("0\n0\n%d\n", 3*ac);
552 greg 2.5 for (i = 0; i < ac; i++) {
553     if (!cvtndx(vi, av[i]))
554 greg 2.1 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 greg 2.3 char *mod;
565 greg 2.1 VNDX v1i, v2i, v3i;
566     BARYCCM bvecs;
567 greg 2.14 FLOAT bcoor[3][3];
568 greg 2.2 int texOK, patOK;
569 greg 2.13 register int i;
570 greg 2.1
571 greg 2.3 if ((mod = getmtl()) == NULL)
572     return(-1);
573    
574 greg 2.1 if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3))
575     return(0);
576     /* compute barycentric coordinates */
577 greg 2.8 texOK = !flatten && (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0);
578 greg 2.7 #ifdef TEXMAPS
579 greg 2.3 patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0);
580 greg 2.7 #else
581     patOK = 0;
582     #endif
583 greg 2.2 if (texOK | patOK)
584 greg 2.10 if (comp_baryc(&bvecs, vlist[v1i[0]], vlist[v2i[0]],
585 greg 2.1 vlist[v3i[0]]) < 0)
586 greg 2.2 return(-1);
587 greg 2.1 /* put out texture (if any) */
588 greg 2.2 if (texOK) {
589 greg 2.1 printf("\n%s texfunc %s\n", mod, TEXNAME);
590     mod = TEXNAME;
591     printf("4 dx dy dz %s\n", TCALNAME);
592 greg 2.13 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 greg 2.1 }
600 greg 2.7 #ifdef TEXMAPS
601 greg 2.1 /* put out pattern (if any) */
602 greg 2.2 if (patOK) {
603 greg 2.1 printf("\n%s colorpict %s\n", mod, PATNAME);
604     mod = PATNAME;
605 greg 2.3 printf("7 noneg noneg noneg %s %s u v\n", mapname, TCALNAME);
606 greg 2.13 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 greg 2.1 }
614 greg 2.7 #endif
615 greg 2.1 /* put out triangle */
616 greg 2.3 printf("\n%s polygon %s.%d\n", mod, getonm(), faceno);
617 greg 2.1 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 greg 2.10 register BARYCCM *bcm;
629 greg 2.1 FLOAT *v1, *v2, *v3;
630     {
631     FLOAT *vt;
632     FVECT va, vab, vcb;
633     double d;
634 greg 2.10 int ax0, ax1;
635 greg 2.1 register int i, j;
636 greg 2.10 /* 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 greg 2.1 if (d <= FTINY)
653     return(-1);
654 greg 2.10 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 greg 2.1 if (d <= FTINY)
659     return(-1);
660 greg 2.10 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 greg 2.1 /* rotate vertices */
664     vt = v1;
665     v1 = v2;
666     v2 = v3;
667     v3 = vt;
668     }
669     return(0);
670     }
671    
672    
673 greg 2.13 put_baryc(bcm, com, n) /* put barycentric coord. vectors */
674 greg 2.10 register BARYCCM *bcm;
675 greg 2.14 register FLOAT com[][3];
676 greg 2.13 int n;
677 greg 2.1 {
678 greg 2.13 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 greg 2.1 }
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 greg 2.3 newvt(x, y) /* create a new texture map vertex */
762 greg 2.1 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 greg 2.3 /* assign new vertex */
778 greg 2.1 vtlist[nvts][0] = x;
779     vtlist[nvts][1] = y;
780     return(++nvts);
781     }
782    
783    
784 greg 2.6 syntax(er) /* report syntax error and exit */
785 greg 2.1 char *er;
786     {
787     fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n",
788 greg 2.6 inpfile, lineno, er);
789 greg 2.1 exit(1);
790     }