ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.7
Committed: Thu Apr 14 13:36:18 1994 UTC (30 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +28 -9 lines
Log Message:
took out use of Wavefront texture maps and indices
fixed bug introduced last time in conversion of non-planar polygons

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     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.7 sprintf(mapname, "%s.pic", 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 greg 2.7 printargs(argc, argv, stdout);
277 greg 2.1 break;
278     default:; /* something we don't deal with */
279     unknown:
280     nunknown++;
281     break;
282     }
283     nstats++;
284     }
285 greg 2.6 printf("\n# Done processing file: %s\n", inpfile);
286 greg 2.1 printf("# %d lines, %d statements, %d unrecognized\n",
287     lineno, nstats, nunknown);
288     }
289    
290    
291     int
292     getstmt(av, fp) /* read the next statement from fp */
293     register char *av[MAXARG];
294     FILE *fp;
295     {
296     extern char *fgetline();
297     static char sbuf[MAXARG*10];
298     register char *cp;
299     register int i;
300    
301     do {
302     if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL)
303     return(0);
304     i = 0;
305     for ( ; ; ) {
306     while (isspace(*cp) || *cp == '\\') {
307     if (*cp == '\n')
308     lineno++;
309     *cp++ = '\0';
310     }
311     if (!*cp || i >= MAXARG-1)
312     break;
313     av[i++] = cp;
314     while (*++cp && !isspace(*cp))
315     ;
316     }
317     av[i] = NULL;
318     lineno++;
319     } while (!i);
320    
321     return(i);
322     }
323    
324 greg 2.3
325     char *
326     getmtl() /* figure material for this face */
327     {
328     register RULEHD *rp = ourmapping;
329    
330 greg 2.6 if (rp == NULL) { /* no rule set */
331     if (matname[0])
332     return(matname);
333     if (group[0][0])
334     return(group[0]);
335     return(defmat);
336     }
337 greg 2.3 /* 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 greg 2.6 /* check for preset */
358     if (objname[0])
359     return(objname);
360     if (!group[0][0])
361     return(defobj);
362 greg 2.3 cp1 = name; /* else make name out of groups */
363     for (i = 0; group[i][0]; i++) {
364     cp2 = group[i];
365     if (cp1 > name)
366     *cp1++ = '.';
367     while (*cp1 = *cp2++)
368     if (++cp1 >= name+sizeof(name)-2) {
369     *cp1 = '\0';
370     return(name);
371     }
372     }
373     return(name);
374     }
375    
376    
377     matchrule(rp) /* check for a match on this rule */
378     register RULEHD *rp;
379     {
380     ID tmpid;
381     int gotmatch;
382     register int i;
383    
384     if (rp->qflg & FL(Q_MTL)) {
385 greg 2.6 if (!matname[0])
386     return(0);
387 greg 2.3 tmpid.number = 0;
388     tmpid.name = matname;
389     if (!matchid(&tmpid, &idm(rp)[Q_MTL]))
390     return(0);
391     }
392     if (rp->qflg & FL(Q_MAP)) {
393 greg 2.6 if (!mapname[0])
394     return(0);
395 greg 2.3 tmpid.number = 0;
396     tmpid.name = mapname;
397     if (!matchid(&tmpid, &idm(rp)[Q_MAP]))
398     return(0);
399     }
400     if (rp->qflg & FL(Q_GRP)) {
401     tmpid.number = 0;
402     gotmatch = 0;
403     for (i = 0; group[i][0]; i++) {
404     tmpid.name = group[i];
405     gotmatch |= matchid(&tmpid, &idm(rp)[Q_GRP]);
406     }
407     if (!gotmatch)
408     return(0);
409     }
410     if (rp->qflg & FL(Q_OBJ)) {
411 greg 2.6 if (!objname[0])
412     return(0);
413 greg 2.3 tmpid.number = 0;
414     tmpid.name = objname;
415     if (!matchid(&tmpid, &idm(rp)[Q_OBJ]))
416     return(0);
417     }
418     if (rp->qflg & FL(Q_FAC)) {
419     tmpid.name = NULL;
420     tmpid.number = faceno;
421     if (!matchid(&tmpid, &idm(rp)[Q_FAC]))
422     return(0);
423     }
424     return(1);
425     }
426    
427    
428 greg 2.1 cvtndx(vi, vs) /* convert vertex string to index */
429     register VNDX vi;
430     register char *vs;
431     {
432     /* get point */
433     vi[0] = atoi(vs);
434     if (vi[0] > 0) {
435     if (vi[0]-- > nvs)
436     return(0);
437     } else if (vi[0] < 0) {
438     vi[0] = nvs + vi[0];
439     if (vi[0] < 0)
440     return(0);
441     } else
442     return(0);
443 greg 2.3 /* get map */
444 greg 2.1 while (*vs)
445     if (*vs++ == '/')
446     break;
447     vi[1] = atoi(vs);
448     if (vi[1] > 0) {
449     if (vi[1]-- > nvts)
450     return(0);
451     } else if (vi[1] < 0) {
452     vi[1] = nvts + vi[1];
453     if (vi[1] < 0)
454     return(0);
455     } else
456     vi[1] = -1;
457     /* get normal */
458     while (*vs)
459     if (*vs++ == '/')
460     break;
461     vi[2] = atoi(vs);
462     if (vi[2] > 0) {
463     if (vi[2]-- > nvns)
464     return(0);
465     } else if (vi[2] < 0) {
466     vi[2] = nvns + vi[2];
467     if (vi[2] < 0)
468     return(0);
469     } else
470     vi[2] = -1;
471     return(1);
472     }
473    
474    
475 greg 2.5 nonplanar(ac, av) /* are vertices are non-planar? */
476 greg 2.1 register int ac;
477     register char **av;
478     {
479     VNDX vi;
480 greg 2.5 FLOAT *p0, *p1;
481     FVECT v1, v2, nsum, newn;
482     double d;
483     register int i;
484    
485     if (!cvtndx(vi, av[0]))
486     return(0);
487     if (vi[2] >= 0)
488     return(1); /* has interpolated normals */
489     if (ac < 4)
490     return(0); /* it's a triangle! */
491     /* set up */
492     p0 = vlist[vi[0]];
493     if (!cvtndx(vi, av[1]))
494     return(0); /* error gets caught later */
495     nsum[0] = nsum[1] = nsum[2] = 0.;
496     p1 = vlist[vi[0]];
497     fvsum(v2, p1, p0, -1.0);
498     for (i = 2; i < ac; i++) {
499     VCOPY(v1, v2);
500     if (!cvtndx(vi, av[i]))
501     return(0);
502     p1 = vlist[vi[0]];
503     fvsum(v2, p1, p0, -1.0);
504     fcross(newn, v1, v2);
505     if (normalize(newn) == 0.0) {
506     if (i < 3)
507     return(1); /* can't deal with this */
508     fvsum(nsum, nsum, nsum, 1./(i-2));
509     continue;
510     }
511     d = fdot(newn,nsum);
512     if (d >= 0) {
513     if (d < (1.0-FTINY)*(i-2))
514     return(1);
515     fvsum(nsum, nsum, newn, 1.0);
516     } else {
517     if (d > -(1.0-FTINY)*(i-2))
518     return(1);
519     fvsum(nsum, nsum, newn, -1.0);
520     }
521     }
522     return(0);
523     }
524    
525    
526     putface(ac, av) /* put out an N-sided polygon */
527     int ac;
528     register char **av;
529     {
530     VNDX vi;
531 greg 2.7 char *cp;
532 greg 2.5 register int i;
533 greg 2.1
534 greg 2.5 if (nonplanar(ac, av)) { /* break into quads and triangles */
535     while (ac > 3) {
536     if (!putquad(av[0], av[1], av[2], av[3]))
537     return(0);
538 greg 2.7 ac -= 2; /* remove two vertices & rotate */
539     cp = av[0];
540     for (i = 0; i < ac-1; i++)
541     av[i] = av[i+3];
542     av[i] = cp;
543 greg 2.5 }
544     if (ac == 3 && !puttri(av[0], av[1], av[2]))
545     return(0);
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.2 int texOK, patOK;
568 greg 2.1
569 greg 2.3 if ((mod = getmtl()) == NULL)
570     return(-1);
571    
572 greg 2.1 if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3))
573     return(0);
574     /* compute barycentric coordinates */
575 greg 2.2 texOK = (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0);
576 greg 2.7 #ifdef TEXMAPS
577 greg 2.3 patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0);
578 greg 2.7 #else
579     patOK = 0;
580     #endif
581 greg 2.2 if (texOK | patOK)
582 greg 2.1 if (comp_baryc(bvecs, vlist[v1i[0]], vlist[v2i[0]],
583     vlist[v3i[0]]) < 0)
584 greg 2.2 return(-1);
585 greg 2.1 /* put out texture (if any) */
586 greg 2.2 if (texOK) {
587 greg 2.1 printf("\n%s texfunc %s\n", mod, TEXNAME);
588     mod = TEXNAME;
589     printf("4 dx dy dz %s\n", TCALNAME);
590     printf("0\n21\n");
591     put_baryc(bvecs);
592     printf("\t%14.12g %14.12g %14.12g\n",
593     vnlist[v1i[2]][0], vnlist[v2i[2]][0],
594     vnlist[v3i[2]][0]);
595     printf("\t%14.12g %14.12g %14.12g\n",
596     vnlist[v1i[2]][1], vnlist[v2i[2]][1],
597     vnlist[v3i[2]][1]);
598     printf("\t%14.12g %14.12g %14.12g\n",
599     vnlist[v1i[2]][2], vnlist[v2i[2]][2],
600     vnlist[v3i[2]][2]);
601     }
602 greg 2.7 #ifdef TEXMAPS
603 greg 2.1 /* put out pattern (if any) */
604 greg 2.2 if (patOK) {
605 greg 2.1 printf("\n%s colorpict %s\n", mod, PATNAME);
606     mod = PATNAME;
607 greg 2.3 printf("7 noneg noneg noneg %s %s u v\n", mapname, TCALNAME);
608 greg 2.1 printf("0\n18\n");
609     put_baryc(bvecs);
610     printf("\t%f %f %f\n", vtlist[v1i[1]][0],
611     vtlist[v2i[1]][0], vtlist[v3i[1]][0]);
612     printf("\t%f %f %f\n", vtlist[v1i[1]][1],
613     vtlist[v2i[1]][1], vtlist[v3i[1]][1]);
614     }
615 greg 2.7 #endif
616 greg 2.1 /* put out triangle */
617 greg 2.3 printf("\n%s polygon %s.%d\n", mod, getonm(), faceno);
618 greg 2.1 printf("0\n0\n9\n");
619     pvect(vlist[v1i[0]]);
620     pvect(vlist[v2i[0]]);
621     pvect(vlist[v3i[0]]);
622    
623     return(1);
624     }
625    
626    
627     int
628     comp_baryc(bcm, v1, v2, v3) /* compute barycentric vectors */
629     register BARYCCM bcm;
630     FLOAT *v1, *v2, *v3;
631     {
632     FLOAT *vt;
633     FVECT va, vab, vcb;
634     double d;
635     register int i, j;
636    
637     for (j = 0; j < 3; j++) {
638     for (i = 0; i < 3; i++) {
639     vab[i] = v1[i] - v2[i];
640     vcb[i] = v3[i] - v2[i];
641     }
642     d = DOT(vcb,vcb);
643     if (d <= FTINY)
644     return(-1);
645     d = DOT(vcb,vab)/d;
646     for (i = 0; i < 3; i++)
647     va[i] = vab[i] - vcb[i]*d;
648     d = DOT(va,va);
649     if (d <= FTINY)
650     return(-1);
651     for (i = 0; i < 3; i++) {
652     va[i] /= d;
653     bcm[j][i] = va[i];
654     }
655     bcm[j][3] = -DOT(v2,va);
656     /* rotate vertices */
657     vt = v1;
658     v1 = v2;
659     v2 = v3;
660     v3 = vt;
661     }
662     return(0);
663     }
664    
665    
666     put_baryc(bcm) /* put barycentric coord. vectors */
667     register BARYCCM bcm;
668     {
669     register int i;
670    
671     for (i = 0; i < 3; i++)
672     printf("%14.8f %14.8f %14.8f %14.8f\n",
673     bcm[i][0], bcm[i][1], bcm[i][2], bcm[i][3]);
674     }
675    
676    
677 greg 2.4 putquad(p0, p1, p3, p2) /* put out a quadrilateral */
678     char *p0, *p1, *p3, *p2; /* names correspond to binary pos. */
679 greg 2.1 {
680     VNDX p0i, p1i, p2i, p3i;
681     FVECT norm[4];
682 greg 2.3 char *mod, *name;
683 greg 2.1 int axis;
684     FVECT v1, v2, vc1, vc2;
685     int ok1, ok2;
686 greg 2.3
687 greg 2.7 #ifdef TEXMAPS
688     /* also should output texture index coordinates,
689     * which will require new .cal file
690     */
691     #endif
692 greg 2.3 if ((mod = getmtl()) == NULL)
693     return(-1);
694     name = getonm();
695 greg 2.1 /* get actual indices */
696     if (!cvtndx(p0i,p0) || !cvtndx(p1i,p1) ||
697     !cvtndx(p2i,p2) || !cvtndx(p3i,p3))
698     return(0);
699     /* compute exact normals */
700     fvsum(v1, vlist[p1i[0]], vlist[p0i[0]], -1.0);
701     fvsum(v2, vlist[p2i[0]], vlist[p0i[0]], -1.0);
702     fcross(vc1, v1, v2);
703     ok1 = normalize(vc1) != 0.0;
704     fvsum(v1, vlist[p2i[0]], vlist[p3i[0]], -1.0);
705     fvsum(v2, vlist[p1i[0]], vlist[p3i[0]], -1.0);
706     fcross(vc2, v1, v2);
707     ok2 = normalize(vc2) != 0.0;
708     if (!(ok1 | ok2))
709 greg 2.2 return(-1);
710 greg 2.1 /* compute normal interpolation */
711     axis = norminterp(norm, p0i, p1i, p2i, p3i);
712    
713     /* put out quadrilateral? */
714 greg 2.5 if (ok1 & ok2 && fabs(fdot(vc1,vc2)) >= 1.0-FTINY) {
715 greg 2.3 printf("\n%s ", mod);
716 greg 2.1 if (axis != -1) {
717     printf("texfunc %s\n", TEXNAME);
718     printf("4 surf_dx surf_dy surf_dz %s\n", QCALNAME);
719     printf("0\n13\t%d\n", axis);
720     pvect(norm[0]);
721     pvect(norm[1]);
722     pvect(norm[2]);
723     fvsum(v1, norm[3], vc1, -0.5);
724     fvsum(v1, v1, vc2, -0.5);
725     pvect(v1);
726     printf("\n%s ", TEXNAME);
727     }
728 greg 2.3 printf("polygon %s.%d\n", name, faceno);
729 greg 2.1 printf("0\n0\n12\n");
730     pvect(vlist[p0i[0]]);
731     pvect(vlist[p1i[0]]);
732     pvect(vlist[p3i[0]]);
733     pvect(vlist[p2i[0]]);
734     return(1);
735     }
736     /* put out triangles? */
737     if (ok1) {
738 greg 2.3 printf("\n%s ", mod);
739 greg 2.1 if (axis != -1) {
740     printf("texfunc %s\n", TEXNAME);
741     printf("4 surf_dx surf_dy surf_dz %s\n", QCALNAME);
742     printf("0\n13\t%d\n", axis);
743     pvect(norm[0]);
744     pvect(norm[1]);
745     pvect(norm[2]);
746     fvsum(v1, norm[3], vc1, -1.0);
747     pvect(v1);
748     printf("\n%s ", TEXNAME);
749     }
750 greg 2.3 printf("polygon %s.%da\n", name, faceno);
751 greg 2.1 printf("0\n0\n9\n");
752     pvect(vlist[p0i[0]]);
753     pvect(vlist[p1i[0]]);
754     pvect(vlist[p2i[0]]);
755     }
756     if (ok2) {
757 greg 2.3 printf("\n%s ", mod);
758 greg 2.1 if (axis != -1) {
759     printf("texfunc %s\n", TEXNAME);
760     printf("4 surf_dx surf_dy surf_dz %s\n", QCALNAME);
761     printf("0\n13\t%d\n", axis);
762     pvect(norm[0]);
763     pvect(norm[1]);
764     pvect(norm[2]);
765     fvsum(v2, norm[3], vc2, -1.0);
766     pvect(v2);
767     printf("\n%s ", TEXNAME);
768     }
769 greg 2.3 printf("polygon %s.%db\n", name, faceno);
770 greg 2.1 printf("0\n0\n9\n");
771     pvect(vlist[p2i[0]]);
772     pvect(vlist[p1i[0]]);
773     pvect(vlist[p3i[0]]);
774     }
775     return(1);
776     }
777    
778    
779     int
780     norminterp(resmat, p0i, p1i, p2i, p3i) /* compute normal interpolation */
781     register FVECT resmat[4];
782     register VNDX p0i, p1i, p2i, p3i;
783     {
784     #define u ((ax+1)%3)
785     #define v ((ax+2)%3)
786    
787     register int ax;
788     MAT4 eqnmat;
789     FVECT v1;
790     register int i, j;
791    
792 greg 2.7 #ifdef TEXMAPS
793     /* also check for texture indices */
794     #endif
795 greg 2.1 if (!(p0i[2]>=0 && p1i[2]>=0 && p2i[2]>=0 && p3i[2]>=0))
796     return(-1);
797     /* find dominant axis */
798     VCOPY(v1, vnlist[p0i[2]]);
799     fvsum(v1, v1, vnlist[p1i[2]], 1.0);
800     fvsum(v1, v1, vnlist[p2i[2]], 1.0);
801     fvsum(v1, v1, vnlist[p3i[2]], 1.0);
802     ax = ABS(v1[0]) > ABS(v1[1]) ? 0 : 1;
803     ax = ABS(v1[ax]) > ABS(v1[2]) ? ax : 2;
804     /* assign equation matrix */
805     eqnmat[0][0] = vlist[p0i[0]][u]*vlist[p0i[0]][v];
806     eqnmat[0][1] = vlist[p0i[0]][u];
807     eqnmat[0][2] = vlist[p0i[0]][v];
808     eqnmat[0][3] = 1.0;
809     eqnmat[1][0] = vlist[p1i[0]][u]*vlist[p1i[0]][v];
810     eqnmat[1][1] = vlist[p1i[0]][u];
811     eqnmat[1][2] = vlist[p1i[0]][v];
812     eqnmat[1][3] = 1.0;
813     eqnmat[2][0] = vlist[p2i[0]][u]*vlist[p2i[0]][v];
814     eqnmat[2][1] = vlist[p2i[0]][u];
815     eqnmat[2][2] = vlist[p2i[0]][v];
816     eqnmat[2][3] = 1.0;
817     eqnmat[3][0] = vlist[p3i[0]][u]*vlist[p3i[0]][v];
818     eqnmat[3][1] = vlist[p3i[0]][u];
819     eqnmat[3][2] = vlist[p3i[0]][v];
820     eqnmat[3][3] = 1.0;
821     /* invert matrix (solve system) */
822     if (!invmat4(eqnmat, eqnmat))
823     return(-1); /* no solution */
824     /* compute result matrix */
825     for (j = 0; j < 4; j++)
826     for (i = 0; i < 3; i++)
827     resmat[j][i] = eqnmat[j][0]*vnlist[p0i[2]][i] +
828     eqnmat[j][1]*vnlist[p1i[2]][i] +
829     eqnmat[j][2]*vnlist[p2i[2]][i] +
830     eqnmat[j][3]*vnlist[p3i[2]][i];
831 greg 2.7 #ifdef TEXMAPS
832     /* compute result matrix for texture indices */
833     #endif
834 greg 2.1 return(ax);
835    
836     #undef u
837     #undef v
838     }
839    
840    
841     freeverts() /* free all vertices */
842     {
843     if (nvs) {
844     free((char *)vlist);
845     nvs = 0;
846     }
847     if (nvts) {
848     free((char *)vtlist);
849     nvts = 0;
850     }
851     if (nvns) {
852     free((char *)vnlist);
853     nvns = 0;
854     }
855     }
856    
857    
858     int
859     newv(x, y, z) /* create a new vertex */
860     double x, y, z;
861     {
862     if (!(nvs%CHUNKSIZ)) { /* allocate next block */
863     if (nvs == 0)
864     vlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
865     else
866     vlist = (FVECT *)realloc((char *)vlist,
867     (nvs+CHUNKSIZ)*sizeof(FVECT));
868     if (vlist == NULL) {
869     fprintf(stderr,
870     "Out of memory while allocating vertex %d\n", nvs);
871     exit(1);
872     }
873     }
874     /* assign new vertex */
875     vlist[nvs][0] = x;
876     vlist[nvs][1] = y;
877     vlist[nvs][2] = z;
878     return(++nvs);
879     }
880    
881    
882     int
883     newvn(x, y, z) /* create a new vertex normal */
884     double x, y, z;
885     {
886     if (!(nvns%CHUNKSIZ)) { /* allocate next block */
887     if (nvns == 0)
888     vnlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
889     else
890     vnlist = (FVECT *)realloc((char *)vnlist,
891     (nvns+CHUNKSIZ)*sizeof(FVECT));
892     if (vnlist == NULL) {
893     fprintf(stderr,
894     "Out of memory while allocating normal %d\n", nvns);
895     exit(1);
896     }
897     }
898     /* assign new normal */
899     vnlist[nvns][0] = x;
900     vnlist[nvns][1] = y;
901     vnlist[nvns][2] = z;
902     if (normalize(vnlist[nvns]) == 0.0)
903     return(0);
904     return(++nvns);
905     }
906    
907    
908     int
909 greg 2.3 newvt(x, y) /* create a new texture map vertex */
910 greg 2.1 double x, y;
911     {
912     if (!(nvts%CHUNKSIZ)) { /* allocate next block */
913     if (nvts == 0)
914     vtlist = (FLOAT (*)[2])malloc(CHUNKSIZ*2*sizeof(FLOAT));
915     else
916     vtlist = (FLOAT (*)[2])realloc((char *)vtlist,
917     (nvts+CHUNKSIZ)*2*sizeof(FLOAT));
918     if (vtlist == NULL) {
919     fprintf(stderr,
920     "Out of memory while allocating texture vertex %d\n",
921     nvts);
922     exit(1);
923     }
924     }
925 greg 2.3 /* assign new vertex */
926 greg 2.1 vtlist[nvts][0] = x;
927     vtlist[nvts][1] = y;
928     return(++nvts);
929     }
930    
931    
932 greg 2.6 syntax(er) /* report syntax error and exit */
933 greg 2.1 char *er;
934     {
935     fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n",
936 greg 2.6 inpfile, lineno, er);
937 greg 2.1 exit(1);
938     }