ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.5
Committed: Wed Apr 13 17:24:24 1994 UTC (29 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +70 -6 lines
Log Message:
added sloppy division of non-planar faces into triangles

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