ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.8
Committed: Tue Jun 14 14:30:38 1994 UTC (29 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.7: +7 -2 lines
Log Message:
added -f option to flatten faces

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