--- ray/src/cv/obj2rad.c 1994/04/13 15:16:49 2.4 +++ ray/src/cv/obj2rad.c 1994/06/14 14:30:38 2.8 @@ -7,10 +7,10 @@ static char SCCSid[] = "$SunId$ LBL"; /* * Convert a Wavefront .obj file to Radiance format. * - * Currently, we support only polygonal geometry, and faces - * must be either quads or triangles for smoothing to work. + * Currently, we support only polygonal geometry. Non-planar + * faces are broken rather haphazardly into triangles. * Also, texture map indices only work for triangles, though - * I'm not sure they work correctly. + * I'm not sure they work correctly. (Taken out -- see TEXMAPS defines.) */ #include "standard.h" @@ -69,23 +69,25 @@ RULEHD *ourmapping = NULL; char *defmat = DEFMAT; /* default (starting) material name */ char *defobj = DEFOBJ; /* default (starting) object name */ -int donames = 0; /* only get qualifier names */ +int flatten = 0; /* discard surface normal information */ + char *getmtl(), *getonm(); char mapname[128]; /* current picture file */ char matname[64]; /* current material name */ char group[16][32]; /* current group names */ char objname[128]; /* current object name */ +char *inpfile; /* input file name */ int lineno; /* current line number */ -int faceno; /* number of faces read */ +int faceno; /* current face number */ main(argc, argv) /* read in .obj file and convert */ int argc; char *argv[]; { - char *fname; + int donames = 0; int i; for (i = 1; i < argc && argv[i][0] == '-'; i++) @@ -99,20 +101,23 @@ char *argv[]; case 'm': /* use custom mapfile */ ourmapping = getmapping(argv[++i], &qlist); break; + case 'f': /* flatten surfaces */ + flatten++; + break; default: goto userr; } if (i > argc | i < argc-1) goto userr; if (i == argc) - fname = ""; - else if (freopen(fname=argv[i], "r", stdin) == NULL) { - fprintf(stderr, "%s: cannot open\n", fname); + inpfile = ""; + else if (freopen(inpfile=argv[i], "r", stdin) == NULL) { + fprintf(stderr, "%s: cannot open\n", inpfile); exit(1); } if (donames) { /* scan for ids */ getnames(stdin); - printf("filename \"%s\"\n", fname); + printf("filename \"%s\"\n", inpfile); printf("filetype \"Wavefront\"\n"); write_quals(&qlist, qual, stdout); printf("qualifier %s begin\n", qlist.qual[Q_FAC]); @@ -121,7 +126,7 @@ char *argv[]; } else { /* translate file */ printf("# "); printargs(argc, argv, stdout); - convert(fname, stdin); + convert(stdin); } exit(0); userr: @@ -180,20 +185,14 @@ FILE *fp; } -convert(fname, fp) /* convert a T-mesh */ -char *fname; +convert(fp) /* convert a T-mesh */ FILE *fp; { char *argv[MAXARG]; int argc; int nstats, nunknown; register int i; - /* start fresh */ - freeverts(); - mapname[0] = '\0'; - strcpy(matname, defmat); - strcpy(objname, defobj); - lineno = 0; + nstats = nunknown = 0; /* scan until EOF */ while (argc = getstmt(argv, fp)) { @@ -202,7 +201,7 @@ FILE *fp; switch (argv[0][1]) { case '\0': /* point */ if (badarg(argc-1,argv+1,"fff")) - syntax(fname, lineno, "Bad vertex"); + syntax("Bad vertex"); newv(atof(argv[1]), atof(argv[2]), atof(argv[3])); break; @@ -210,10 +209,10 @@ FILE *fp; if (argv[0][2]) goto unknown; if (badarg(argc-1,argv+1,"fff")) - syntax(fname, lineno, "Bad normal"); + syntax("Bad normal"); if (!newvn(atof(argv[1]), atof(argv[2]), atof(argv[3]))) - syntax(fname, lineno, "Zero normal"); + syntax("Zero normal"); break; case 't': /* texture map */ if (argv[0][2]) @@ -232,20 +231,20 @@ FILE *fp; faceno++; switch (argc-1) { case 0: case 1: case 2: - syntax(fname, lineno, "Too few vertices"); + syntax("Too few vertices"); break; case 3: if (!puttri(argv[1], argv[2], argv[3])) - syntax(fname, lineno, "Bad triangle"); + syntax("Bad triangle"); break; case 4: if (!putquad(argv[1], argv[2], argv[3], argv[4])) - syntax(fname, lineno, "Bad quad"); + syntax("Bad quad"); break; default: if (!putface(argc-1, argv+1)) - syntax(fname, lineno, "Bad face"); + syntax("Bad face"); break; } break; @@ -260,7 +259,7 @@ FILE *fp; if (!strcmp(argv[1], "off")) mapname[0] = '\0'; else - strcpy(mapname, argv[1]); + sprintf(mapname, "%s.pic", argv[1]); } else goto unknown; break; @@ -279,6 +278,7 @@ FILE *fp; group[i-1][0] = '\0'; break; case '#': /* comment */ + printargs(argc, argv, stdout); break; default:; /* something we don't deal with */ unknown: @@ -287,7 +287,7 @@ FILE *fp; } nstats++; } - printf("\n# Done processing file: %s\n", fname); + printf("\n# Done processing file: %s\n", inpfile); printf("# %d lines, %d statements, %d unrecognized\n", lineno, nstats, nunknown); } @@ -332,8 +332,13 @@ getmtl() /* figure material for this face */ { register RULEHD *rp = ourmapping; - if (rp == NULL) /* no rule set */ - return(matname); + if (rp == NULL) { /* no rule set */ + if (matname[0]) + return(matname); + if (group[0][0]) + return(group[0]); + return(defmat); + } /* check for match */ do { if (matchrule(rp)) { @@ -354,10 +359,11 @@ getonm() /* invent a good name for object */ static char name[64]; register char *cp1, *cp2; register int i; - - if (!group[0][0] || strcmp(objname, DEFOBJ)) - return(objname); /* good enough for us */ - + /* check for preset */ + if (objname[0]) + return(objname); + if (!group[0][0]) + return(defobj); cp1 = name; /* else make name out of groups */ for (i = 0; group[i][0]; i++) { cp2 = group[i]; @@ -381,12 +387,16 @@ register RULEHD *rp; register int i; if (rp->qflg & FL(Q_MTL)) { + if (!matname[0]) + return(0); tmpid.number = 0; tmpid.name = matname; if (!matchid(&tmpid, &idm(rp)[Q_MTL])) return(0); } if (rp->qflg & FL(Q_MAP)) { + if (!mapname[0]) + return(0); tmpid.number = 0; tmpid.name = mapname; if (!matchid(&tmpid, &idm(rp)[Q_MAP])) @@ -403,6 +413,8 @@ register RULEHD *rp; return(0); } if (rp->qflg & FL(Q_OBJ)) { + if (!objname[0]) + return(0); tmpid.number = 0; tmpid.name = objname; if (!matchid(&tmpid, &idm(rp)[Q_OBJ])) @@ -465,19 +477,85 @@ register char *vs; } -putface(ac, av) /* put out an N-sided polygon */ +nonplanar(ac, av) /* are vertices are non-planar? */ register int ac; register char **av; { VNDX vi; - char *mod; + FLOAT *p0, *p1; + FVECT v1, v2, nsum, newn; + double d; + register int i; - if ((mod = getmtl()) == NULL) + if (!cvtndx(vi, av[0])) + return(0); + if (vi[2] >= 0) + return(1); /* has interpolated normals */ + if (ac < 4) + return(0); /* it's a triangle! */ + /* set up */ + p0 = vlist[vi[0]]; + if (!cvtndx(vi, av[1])) + return(0); /* error gets caught later */ + nsum[0] = nsum[1] = nsum[2] = 0.; + p1 = vlist[vi[0]]; + fvsum(v2, p1, p0, -1.0); + for (i = 2; i < ac; i++) { + VCOPY(v1, v2); + if (!cvtndx(vi, av[i])) + return(0); + p1 = vlist[vi[0]]; + fvsum(v2, p1, p0, -1.0); + fcross(newn, v1, v2); + if (normalize(newn) == 0.0) { + if (i < 3) + return(1); /* can't deal with this */ + fvsum(nsum, nsum, nsum, 1./(i-2)); + continue; + } + d = fdot(newn,nsum); + if (d >= 0) { + if (d < (1.0-FTINY)*(i-2)) + return(1); + fvsum(nsum, nsum, newn, 1.0); + } else { + if (d > -(1.0-FTINY)*(i-2)) + return(1); + fvsum(nsum, nsum, newn, -1.0); + } + } + return(0); +} + + +putface(ac, av) /* put out an N-sided polygon */ +int ac; +register char **av; +{ + VNDX vi; + char *cp; + register int i; + + if (nonplanar(ac, av)) { /* break into quads and triangles */ + while (ac > 3) { + if (!putquad(av[0], av[1], av[2], av[3])) + return(0); + ac -= 2; /* remove two vertices & rotate */ + cp = av[0]; + for (i = 0; i < ac-1; i++) + av[i] = av[i+3]; + av[i] = cp; + } + if (ac == 3 && !puttri(av[0], av[1], av[2])) + return(0); + return(1); + } + if ((cp = getmtl()) == NULL) return(-1); - printf("\n%s polygon %s.%d\n", mod, getonm(), faceno); + printf("\n%s polygon %s.%d\n", cp, getonm(), faceno); printf("0\n0\n%d\n", 3*ac); - while (ac--) { - if (!cvtndx(vi, *av++)) + for (i = 0; i < ac; i++) { + if (!cvtndx(vi, av[i])) return(0); pvect(vlist[vi[0]]); } @@ -499,8 +577,12 @@ char *v1, *v2, *v3; if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3)) return(0); /* compute barycentric coordinates */ - texOK = (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0); + texOK = !flatten && (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0); +#ifdef TEXMAPS patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0); +#else + patOK = 0; +#endif if (texOK | patOK) if (comp_baryc(bvecs, vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]]) < 0) @@ -522,6 +604,7 @@ char *v1, *v2, *v3; vnlist[v1i[2]][2], vnlist[v2i[2]][2], vnlist[v3i[2]][2]); } +#ifdef TEXMAPS /* put out pattern (if any) */ if (patOK) { printf("\n%s colorpict %s\n", mod, PATNAME); @@ -534,6 +617,7 @@ char *v1, *v2, *v3; printf("\t%f %f %f\n", vtlist[v1i[1]][1], vtlist[v2i[1]][1], vtlist[v3i[1]][1]); } +#endif /* put out triangle */ printf("\n%s polygon %s.%d\n", mod, getonm(), faceno); printf("0\n0\n9\n"); @@ -605,6 +689,11 @@ char *p0, *p1, *p3, *p2; /* names correspond to bina FVECT v1, v2, vc1, vc2; int ok1, ok2; +#ifdef TEXMAPS + /* also should output texture index coordinates, + * which will require new .cal file + */ +#endif if ((mod = getmtl()) == NULL) return(-1); name = getonm(); @@ -627,7 +716,7 @@ char *p0, *p1, *p3, *p2; /* names correspond to bina axis = norminterp(norm, p0i, p1i, p2i, p3i); /* put out quadrilateral? */ - if (ok1 & ok2 && fdot(vc1,vc2) >= 1.0-FTINY*FTINY) { + if (ok1 & ok2 && fabs(fdot(vc1,vc2)) >= 1.0-FTINY) { printf("\n%s ", mod); if (axis != -1) { printf("texfunc %s\n", TEXNAME); @@ -705,7 +794,10 @@ register VNDX p0i, p1i, p2i, p3i; FVECT v1; register int i, j; - if (!(p0i[2]>=0 && p1i[2]>=0 && p2i[2]>=0 && p3i[2]>=0)) +#ifdef TEXMAPS + /* also check for texture indices */ +#endif + if (flatten || !(p0i[2]>=0 && p1i[2]>=0 && p2i[2]>=0 && p3i[2]>=0)) return(-1); /* find dominant axis */ VCOPY(v1, vnlist[p0i[2]]); @@ -741,6 +833,9 @@ register VNDX p0i, p1i, p2i, p3i; eqnmat[j][1]*vnlist[p1i[2]][i] + eqnmat[j][2]*vnlist[p2i[2]][i] + eqnmat[j][3]*vnlist[p3i[2]][i]; +#ifdef TEXMAPS + /* compute result matrix for texture indices */ +#endif return(ax); #undef u @@ -839,12 +934,10 @@ double x, y; } -syntax(fn, ln, er) /* report syntax error and exit */ -char *fn; -int ln; +syntax(er) /* report syntax error and exit */ char *er; { fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n", - fn, ln, er); + inpfile, lineno, er); exit(1); }