ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.10
Committed: Wed Jun 15 12:29:55 1994 UTC (29 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.9: +40 -29 lines
Log Message:
changed to more compact barycentric coordinate calculation

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