ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.6
Committed: Thu Apr 14 04:29:10 1994 UTC (29 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.5: +41 -36 lines
Log Message:
slight enhancement in conversion of non-planar polygons
now uses group name as default material if no usemtl and no -m option

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