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 (30 years 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

# 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
73 char *getmtl(), *getonm();
74
75 char mapname[128]; /* current picture file */
76 char matname[64]; /* current material name */
77 char group[16][32]; /* current group names */
78 char objname[128]; /* current object name */
79 char *inpfile; /* input file name */
80 int lineno; /* current line number */
81 int faceno; /* current face number */
82
83
84 main(argc, argv) /* read in .obj file and convert */
85 int argc;
86 char *argv[];
87 {
88 int donames = 0;
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 inpfile = "<stdin>";
109 else if (freopen(inpfile=argv[i], "r", stdin) == NULL) {
110 fprintf(stderr, "%s: cannot open\n", inpfile);
111 exit(1);
112 }
113 if (donames) { /* scan for ids */
114 getnames(stdin);
115 printf("filename \"%s\"\n", inpfile);
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(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(fp) /* convert a T-mesh */
184 FILE *fp;
185 {
186 char *argv[MAXARG];
187 int argc;
188 int nstats, nunknown;
189 register int i;
190
191 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 syntax("Bad vertex");
200 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 syntax("Bad normal");
208 if (!newvn(atof(argv[1]), atof(argv[2]),
209 atof(argv[3])))
210 syntax("Zero normal");
211 break;
212 case 't': /* texture map */
213 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 faceno++;
227 switch (argc-1) {
228 case 0: case 1: case 2:
229 syntax("Too few vertices");
230 break;
231 case 3:
232 if (!puttri(argv[1], argv[2], argv[3]))
233 syntax("Bad triangle");
234 break;
235 case 4:
236 if (!putquad(argv[1], argv[2],
237 argv[3], argv[4]))
238 syntax("Bad quad");
239 break;
240 default:
241 if (!putface(argc-1, argv+1))
242 syntax("Bad face");
243 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 mapname[0] = '\0';
256 else
257 strcpy(mapname, argv[1]);
258 } 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 strcpy(group[i-1], argv[i]);
273 group[i-1][0] = '\0';
274 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 printf("\n# Done processing file: %s\n", inpfile);
285 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
324 char *
325 getmtl() /* figure material for this face */
326 {
327 register RULEHD *rp = ourmapping;
328
329 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 /* 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 /* check for preset */
357 if (objname[0])
358 return(objname);
359 if (!group[0][0])
360 return(defobj);
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 if (!matname[0])
385 return(0);
386 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 if (!mapname[0])
393 return(0);
394 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 if (!objname[0])
411 return(0);
412 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 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 /* get map */
443 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 nonplanar(ac, av) /* are vertices are non-planar? */
475 register int ac;
476 register char **av;
477 {
478 VNDX vi;
479 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 char *mod;
531 register int i;
532
533 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 /* remove two vertices & rotate */
538 av[ac -= 2] = av[0];
539 for (i = 0; i <= ac; i++)
540 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 if ((mod = getmtl()) == NULL)
547 return(-1);
548 printf("\n%s polygon %s.%d\n", mod, getonm(), faceno);
549 printf("0\n0\n%d\n", 3*ac);
550 for (i = 0; i < ac; i++) {
551 if (!cvtndx(vi, av[i]))
552 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 char *mod;
563 VNDX v1i, v2i, v3i;
564 BARYCCM bvecs;
565 int texOK, patOK;
566
567 if ((mod = getmtl()) == NULL)
568 return(-1);
569
570 if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3))
571 return(0);
572 /* compute barycentric coordinates */
573 texOK = (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0);
574 patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0);
575 if (texOK | patOK)
576 if (comp_baryc(bvecs, vlist[v1i[0]], vlist[v2i[0]],
577 vlist[v3i[0]]) < 0)
578 return(-1);
579 /* put out texture (if any) */
580 if (texOK) {
581 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 if (patOK) {
598 printf("\n%s colorpict %s\n", mod, PATNAME);
599 mod = PATNAME;
600 printf("7 noneg noneg noneg %s %s u v\n", mapname, TCALNAME);
601 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 printf("\n%s polygon %s.%d\n", mod, getonm(), faceno);
610 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 putquad(p0, p1, p3, p2) /* put out a quadrilateral */
670 char *p0, *p1, *p3, *p2; /* names correspond to binary pos. */
671 {
672 VNDX p0i, p1i, p2i, p3i;
673 FVECT norm[4];
674 char *mod, *name;
675 int axis;
676 FVECT v1, v2, vc1, vc2;
677 int ok1, ok2;
678
679 if ((mod = getmtl()) == NULL)
680 return(-1);
681 name = getonm();
682 /* 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 return(-1);
697 /* compute normal interpolation */
698 axis = norminterp(norm, p0i, p1i, p2i, p3i);
699
700 /* put out quadrilateral? */
701 if (ok1 & ok2 && fabs(fdot(vc1,vc2)) >= 1.0-FTINY) {
702 printf("\n%s ", mod);
703 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 printf("polygon %s.%d\n", name, faceno);
716 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 printf("\n%s ", mod);
726 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 printf("polygon %s.%da\n", name, faceno);
738 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 printf("\n%s ", mod);
745 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 printf("polygon %s.%db\n", name, faceno);
757 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 newvt(x, y) /* create a new texture map vertex */
891 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 /* assign new vertex */
907 vtlist[nvts][0] = x;
908 vtlist[nvts][1] = y;
909 return(++nvts);
910 }
911
912
913 syntax(er) /* report syntax error and exit */
914 char *er;
915 {
916 fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n",
917 inpfile, lineno, er);
918 exit(1);
919 }