ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/obj2rad.c
Revision: 2.19
Committed: Wed Apr 23 00:52:33 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.18: +3 -3 lines
Log Message:
Added (void *) cast to realloc calls

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Convert a Wavefront .obj file to Radiance format.
6 *
7 * Currently, we support only polygonal geometry. Non-planar
8 * faces are broken rather haphazardly into triangles.
9 * Also, texture map indices only work for triangles, though
10 * I'm not sure they work correctly. (Taken out -- see TEXMAPS defines.)
11 */
12
13 #include "standard.h"
14
15 #include "trans.h"
16
17 #include "tmesh.h"
18
19 #include <ctype.h>
20
21 #define PATNAME "M-pat" /* mesh pattern name (reused) */
22 #define TEXNAME "M-nor" /* mesh texture name (reused) */
23 #define DEFOBJ "unnamed" /* default object name */
24 #define DEFMAT "white" /* default material name */
25
26 #define pvect(v) printf("%18.12g %18.12g %18.12g\n",(v)[0],(v)[1],(v)[2])
27
28 FVECT *vlist; /* our vertex list */
29 int nvs; /* number of vertices in our list */
30 FVECT *vnlist; /* vertex normal list */
31 int nvns;
32 FLOAT (*vtlist)[2]; /* map vertex list */
33 int nvts;
34
35 typedef int VNDX[3]; /* vertex index (point,map,normal) */
36
37 #define CHUNKSIZ 256 /* vertex allocation chunk size */
38
39 #define MAXARG 64 /* maximum # arguments in a statement */
40
41 /* qualifiers */
42 #define Q_MTL 0
43 #define Q_MAP 1
44 #define Q_GRP 2
45 #define Q_OBJ 3
46 #define Q_FAC 4
47 #define NQUALS 5
48
49 char *qname[NQUALS] = {
50 "Material",
51 "Map",
52 "Group",
53 "Object",
54 "Face",
55 };
56
57 QLIST qlist = {NQUALS, qname};
58 /* valid qualifier ids */
59 IDLIST qual[NQUALS];
60 /* mapping rules */
61 RULEHD *ourmapping = NULL;
62
63 char *defmat = DEFMAT; /* default (starting) material name */
64 char *defobj = DEFOBJ; /* default (starting) object name */
65
66 int flatten = 0; /* discard surface normal information */
67
68 char *getmtl(), *getonm();
69
70 char mapname[128]; /* current picture file */
71 char matname[64]; /* current material name */
72 char group[16][32]; /* current group names */
73 char objname[128]; /* current object name */
74 char *inpfile; /* input file name */
75 int lineno; /* current line number */
76 int faceno; /* current face number */
77
78
79 main(argc, argv) /* read in .obj file and convert */
80 int argc;
81 char *argv[];
82 {
83 int donames = 0;
84 int i;
85
86 for (i = 1; i < argc && argv[i][0] == '-'; i++)
87 switch (argv[i][1]) {
88 case 'o': /* object name */
89 defobj = argv[++i];
90 break;
91 case 'n': /* just produce name list */
92 donames++;
93 break;
94 case 'm': /* use custom mapfile */
95 ourmapping = getmapping(argv[++i], &qlist);
96 break;
97 case 'f': /* flatten surfaces */
98 flatten++;
99 break;
100 default:
101 goto userr;
102 }
103 if (i > argc | i < argc-1)
104 goto userr;
105 if (i == argc)
106 inpfile = "<stdin>";
107 else if (freopen(inpfile=argv[i], "r", stdin) == NULL) {
108 fprintf(stderr, "%s: cannot open\n", inpfile);
109 exit(1);
110 }
111 if (donames) { /* scan for ids */
112 getnames(stdin);
113 printf("filename \"%s\"\n", inpfile);
114 printf("filetype \"Wavefront\"\n");
115 write_quals(&qlist, qual, stdout);
116 printf("qualifier %s begin\n", qlist.qual[Q_FAC]);
117 printf("[%d:%d]\n", 1, faceno);
118 printf("end\n");
119 } else { /* translate file */
120 printf("# ");
121 printargs(argc, argv, stdout);
122 convert(stdin);
123 }
124 exit(0);
125 userr:
126 fprintf(stderr, "Usage: %s [-o obj][-m mapping][-n][-f] [file.obj]\n",
127 argv[0]);
128 exit(1);
129 }
130
131
132 getnames(fp) /* get valid qualifier names */
133 FILE *fp;
134 {
135 char *argv[MAXARG];
136 int argc;
137 ID tmpid;
138 register int i;
139
140 while (argc = getstmt(argv, fp))
141 switch (argv[0][0]) {
142 case 'f': /* face */
143 if (!argv[0][1])
144 faceno++;
145 break;
146 case 'u':
147 if (!strcmp(argv[0], "usemtl")) { /* material */
148 if (argc < 2)
149 break; /* not fatal */
150 tmpid.number = 0;
151 tmpid.name = argv[1];
152 findid(&qual[Q_MTL], &tmpid, 1);
153 } else if (!strcmp(argv[0], "usemap")) {/* map */
154 if (argc < 2 || !strcmp(argv[1], "off"))
155 break; /* not fatal */
156 tmpid.number = 0;
157 tmpid.name = argv[1];
158 findid(&qual[Q_MAP], &tmpid, 1);
159 }
160 break;
161 case 'o': /* object name */
162 if (argv[0][1] || argc < 2)
163 break;
164 tmpid.number = 0;
165 tmpid.name = argv[1];
166 findid(&qual[Q_OBJ], &tmpid, 1);
167 break;
168 case 'g': /* group name(s) */
169 if (argv[0][1])
170 break;
171 tmpid.number = 0;
172 for (i = 1; i < argc; i++) {
173 tmpid.name = argv[i];
174 findid(&qual[Q_GRP], &tmpid, 1);
175 }
176 break;
177 }
178 }
179
180
181 convert(fp) /* convert a T-mesh */
182 FILE *fp;
183 {
184 char *argv[MAXARG];
185 int argc;
186 int nstats, nunknown;
187 register int i;
188
189 nstats = nunknown = 0;
190 /* scan until EOF */
191 while (argc = getstmt(argv, fp)) {
192 switch (argv[0][0]) {
193 case 'v': /* vertex */
194 switch (argv[0][1]) {
195 case '\0': /* point */
196 if (badarg(argc-1,argv+1,"fff"))
197 syntax("Bad vertex");
198 newv(atof(argv[1]), atof(argv[2]),
199 atof(argv[3]));
200 break;
201 case 'n': /* normal */
202 if (argv[0][2])
203 goto unknown;
204 if (badarg(argc-1,argv+1,"fff"))
205 syntax("Bad normal");
206 if (!newvn(atof(argv[1]), atof(argv[2]),
207 atof(argv[3])))
208 syntax("Zero normal");
209 break;
210 case 't': /* texture map */
211 if (argv[0][2])
212 goto unknown;
213 if (badarg(argc-1,argv+1,"ff"))
214 goto unknown;
215 newvt(atof(argv[1]), atof(argv[2]));
216 break;
217 default:
218 goto unknown;
219 }
220 break;
221 case 'f': /* face */
222 if (argv[0][1])
223 goto unknown;
224 faceno++;
225 switch (argc-1) {
226 case 0: case 1: case 2:
227 syntax("Too few vertices");
228 break;
229 case 3:
230 if (!puttri(argv[1], argv[2], argv[3]))
231 syntax("Bad triangle");
232 break;
233 default:
234 if (!putface(argc-1, argv+1))
235 syntax("Bad face");
236 break;
237 }
238 break;
239 case 'u':
240 if (!strcmp(argv[0], "usemtl")) { /* material */
241 if (argc < 2)
242 break; /* not fatal */
243 strcpy(matname, argv[1]);
244 } else if (!strcmp(argv[0], "usemap")) {/* map */
245 if (argc < 2)
246 break; /* not fatal */
247 if (!strcmp(argv[1], "off"))
248 mapname[0] = '\0';
249 else
250 sprintf(mapname, "%s.pic", argv[1]);
251 } else
252 goto unknown;
253 break;
254 case 'o': /* object name */
255 if (argv[0][1])
256 goto unknown;
257 if (argc < 2)
258 break; /* not fatal */
259 strcpy(objname, argv[1]);
260 break;
261 case 'g': /* group name(s) */
262 if (argv[0][1])
263 goto unknown;
264 for (i = 1; i < argc; i++)
265 strcpy(group[i-1], argv[i]);
266 group[i-1][0] = '\0';
267 break;
268 case '#': /* comment */
269 printargs(argc, argv, stdout);
270 break;
271 default:; /* something we don't deal with */
272 unknown:
273 nunknown++;
274 break;
275 }
276 nstats++;
277 }
278 printf("\n# Done processing file: %s\n", inpfile);
279 printf("# %d lines, %d statements, %d unrecognized\n",
280 lineno, nstats, nunknown);
281 }
282
283
284 int
285 getstmt(av, fp) /* read the next statement from fp */
286 register char *av[MAXARG];
287 FILE *fp;
288 {
289 extern char *fgetline();
290 static char sbuf[MAXARG*10];
291 register char *cp;
292 register int i;
293
294 do {
295 if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL)
296 return(0);
297 i = 0;
298 for ( ; ; ) {
299 while (isspace(*cp) || *cp == '\\') {
300 if (*cp == '\n')
301 lineno++;
302 *cp++ = '\0';
303 }
304 if (!*cp || i >= MAXARG-1)
305 break;
306 av[i++] = cp;
307 while (*++cp && !isspace(*cp))
308 ;
309 }
310 av[i] = NULL;
311 lineno++;
312 } while (!i);
313
314 return(i);
315 }
316
317
318 char *
319 getmtl() /* figure material for this face */
320 {
321 register RULEHD *rp = ourmapping;
322
323 if (rp == NULL) { /* no rule set */
324 if (matname[0])
325 return(matname);
326 if (group[0][0])
327 return(group[0]);
328 return(defmat);
329 }
330 /* check for match */
331 do {
332 if (matchrule(rp)) {
333 if (!strcmp(rp->mnam, VOIDID))
334 return(NULL); /* match is null */
335 return(rp->mnam);
336 }
337 rp = rp->next;
338 } while (rp != NULL);
339 /* no match found */
340 return(NULL);
341 }
342
343
344 char *
345 getonm() /* invent a good name for object */
346 {
347 static char name[64];
348 register char *cp1, *cp2;
349 register int i;
350 /* check for preset */
351 if (objname[0])
352 return(objname);
353 if (!group[0][0])
354 return(defobj);
355 cp1 = name; /* else make name out of groups */
356 for (i = 0; group[i][0]; i++) {
357 cp2 = group[i];
358 if (cp1 > name)
359 *cp1++ = '.';
360 while (*cp1 = *cp2++)
361 if (++cp1 >= name+sizeof(name)-2) {
362 *cp1 = '\0';
363 return(name);
364 }
365 }
366 return(name);
367 }
368
369
370 matchrule(rp) /* check for a match on this rule */
371 register RULEHD *rp;
372 {
373 ID tmpid;
374 int gotmatch;
375 register int i;
376
377 if (rp->qflg & FL(Q_MTL)) {
378 if (!matname[0])
379 return(0);
380 tmpid.number = 0;
381 tmpid.name = matname;
382 if (!matchid(&tmpid, &idm(rp)[Q_MTL]))
383 return(0);
384 }
385 if (rp->qflg & FL(Q_MAP)) {
386 if (!mapname[0])
387 return(0);
388 tmpid.number = 0;
389 tmpid.name = mapname;
390 if (!matchid(&tmpid, &idm(rp)[Q_MAP]))
391 return(0);
392 }
393 if (rp->qflg & FL(Q_GRP)) {
394 tmpid.number = 0;
395 gotmatch = 0;
396 for (i = 0; group[i][0]; i++) {
397 tmpid.name = group[i];
398 gotmatch |= matchid(&tmpid, &idm(rp)[Q_GRP]);
399 }
400 if (!gotmatch)
401 return(0);
402 }
403 if (rp->qflg & FL(Q_OBJ)) {
404 if (!objname[0])
405 return(0);
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;
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;
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;
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 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 (!flatten && 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 *cp;
525 register int i;
526
527 if (nonplanar(ac, av)) { /* break into triangles */
528 while (ac > 2) {
529 if (!puttri(av[0], av[1], av[2]))
530 return(0);
531 ac--; /* remove vertex & rotate */
532 cp = av[0];
533 for (i = 0; i < ac-1; i++)
534 av[i] = av[i+2];
535 av[i] = cp;
536 }
537 return(1);
538 }
539 if ((cp = getmtl()) == NULL)
540 return(-1);
541 printf("\n%s polygon %s.%d\n", cp, 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 FLOAT bcoor[3][3];
559 int texOK, patOK;
560 int flatness;
561 register int i;
562
563 if ((mod = getmtl()) == NULL)
564 return(-1);
565
566 if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3))
567 return(0);
568 /* compute barycentric coordinates */
569 if (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0)
570 flatness = flat_tri(vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]],
571 vnlist[v1i[2]], vnlist[v2i[2]], vnlist[v3i[2]]);
572 else
573 flatness = ISFLAT;
574
575 switch (flatness) {
576 case DEGEN: /* zero area */
577 return(-1);
578 case RVFLAT: /* reversed normals, but flat */
579 case ISFLAT: /* smoothing unnecessary */
580 texOK = 0;
581 break;
582 case RVBENT: /* reversed normals with smoothing */
583 case ISBENT: /* proper smoothing */
584 texOK = 1;
585 break;
586 }
587 if (flatten)
588 texOK = 0;
589 #ifdef TEXMAPS
590 patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0);
591 #else
592 patOK = 0;
593 #endif
594 if (texOK | patOK)
595 if (comp_baryc(&bvecs, vlist[v1i[0]], vlist[v2i[0]],
596 vlist[v3i[0]]) < 0)
597 return(-1);
598 /* put out texture (if any) */
599 if (texOK) {
600 printf("\n%s texfunc %s\n", mod, TEXNAME);
601 mod = TEXNAME;
602 printf("4 dx dy dz %s\n", TCALNAME);
603 printf("0\n");
604 for (i = 0; i < 3; i++) {
605 bcoor[i][0] = vnlist[v1i[2]][i];
606 bcoor[i][1] = vnlist[v2i[2]][i];
607 bcoor[i][2] = vnlist[v3i[2]][i];
608 }
609 put_baryc(&bvecs, bcoor, 3);
610 }
611 #ifdef TEXMAPS
612 /* put out pattern (if any) */
613 if (patOK) {
614 printf("\n%s colorpict %s\n", mod, PATNAME);
615 mod = PATNAME;
616 printf("7 noneg noneg noneg %s %s u v\n", mapname, TCALNAME);
617 printf("0\n");
618 for (i = 0; i < 2; i++) {
619 bcoor[i][0] = vtlist[v1i[1]][i];
620 bcoor[i][1] = vtlist[v2i[1]][i];
621 bcoor[i][2] = vtlist[v3i[1]][i];
622 }
623 put_baryc(&bvecs, bcoor, 2);
624 }
625 #endif
626 /* put out (reversed) triangle */
627 printf("\n%s polygon %s.%d\n", mod, getonm(), faceno);
628 printf("0\n0\n9\n");
629 if (flatness == RVFLAT || flatness == RVBENT) {
630 pvect(vlist[v3i[0]]);
631 pvect(vlist[v2i[0]]);
632 pvect(vlist[v1i[0]]);
633 } else {
634 pvect(vlist[v1i[0]]);
635 pvect(vlist[v2i[0]]);
636 pvect(vlist[v3i[0]]);
637 }
638 return(1);
639 }
640
641
642 freeverts() /* free all vertices */
643 {
644 if (nvs) {
645 free((void *)vlist);
646 nvs = 0;
647 }
648 if (nvts) {
649 free((void *)vtlist);
650 nvts = 0;
651 }
652 if (nvns) {
653 free((void *)vnlist);
654 nvns = 0;
655 }
656 }
657
658
659 int
660 newv(x, y, z) /* create a new vertex */
661 double x, y, z;
662 {
663 if (!(nvs%CHUNKSIZ)) { /* allocate next block */
664 if (nvs == 0)
665 vlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
666 else
667 vlist = (FVECT *)realloc((void *)vlist,
668 (nvs+CHUNKSIZ)*sizeof(FVECT));
669 if (vlist == NULL) {
670 fprintf(stderr,
671 "Out of memory while allocating vertex %d\n", nvs);
672 exit(1);
673 }
674 }
675 /* assign new vertex */
676 vlist[nvs][0] = x;
677 vlist[nvs][1] = y;
678 vlist[nvs][2] = z;
679 return(++nvs);
680 }
681
682
683 int
684 newvn(x, y, z) /* create a new vertex normal */
685 double x, y, z;
686 {
687 if (!(nvns%CHUNKSIZ)) { /* allocate next block */
688 if (nvns == 0)
689 vnlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
690 else
691 vnlist = (FVECT *)realloc((void *)vnlist,
692 (nvns+CHUNKSIZ)*sizeof(FVECT));
693 if (vnlist == NULL) {
694 fprintf(stderr,
695 "Out of memory while allocating normal %d\n", nvns);
696 exit(1);
697 }
698 }
699 /* assign new normal */
700 vnlist[nvns][0] = x;
701 vnlist[nvns][1] = y;
702 vnlist[nvns][2] = z;
703 if (normalize(vnlist[nvns]) == 0.0)
704 return(0);
705 return(++nvns);
706 }
707
708
709 int
710 newvt(x, y) /* create a new texture map vertex */
711 double x, y;
712 {
713 if (!(nvts%CHUNKSIZ)) { /* allocate next block */
714 if (nvts == 0)
715 vtlist = (FLOAT (*)[2])malloc(CHUNKSIZ*2*sizeof(FLOAT));
716 else
717 vtlist = (FLOAT (*)[2])realloc((void *)vtlist,
718 (nvts+CHUNKSIZ)*2*sizeof(FLOAT));
719 if (vtlist == NULL) {
720 fprintf(stderr,
721 "Out of memory while allocating texture vertex %d\n",
722 nvts);
723 exit(1);
724 }
725 }
726 /* assign new vertex */
727 vtlist[nvts][0] = x;
728 vtlist[nvts][1] = y;
729 return(++nvts);
730 }
731
732
733 syntax(er) /* report syntax error and exit */
734 char *er;
735 {
736 fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n",
737 inpfile, lineno, er);
738 exit(1);
739 }