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

File Contents

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