--- ray/src/cv/obj2rad.c 1994/04/12 17:12:42 2.1 +++ ray/src/cv/obj2rad.c 1994/04/13 17:24:24 2.5 @@ -7,22 +7,24 @@ 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. - * Also, texture indices only work for triangles, though + * 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. */ #include "standard.h" +#include "trans.h" + #include -#define VOIDID "void" /* this is defined in object.h */ - #define TCALNAME "tmesh.cal" /* triangle interp. file */ #define QCALNAME "surf.cal" /* quad interp. file */ #define PATNAME "M-pat" /* mesh pattern name (reused) */ #define TEXNAME "M-nor" /* mesh texture name (reused) */ +#define DEFOBJ "unnamed" /* default object name */ +#define DEFMAT "white" /* default material name */ #define ABS(x) ((x)>=0 ? (x) : -(x)) @@ -32,34 +34,58 @@ FVECT *vlist; /* our vertex list */ int nvs; /* number of vertices in our list */ FVECT *vnlist; /* vertex normal list */ int nvns; -FLOAT (*vtlist)[2]; /* texture vertex list */ +FLOAT (*vtlist)[2]; /* map vertex list */ int nvts; typedef FLOAT BARYCCM[3][4]; /* barycentric coordinate system */ -typedef int VNDX[3]; /* vertex index (point,texture,normal) */ +typedef int VNDX[3]; /* vertex index (point,map,normal) */ -#define CHUNKSIZ 128 /* vertex allocation chunk size */ +#define CHUNKSIZ 256 /* vertex allocation chunk size */ #define MAXARG 64 /* maximum # arguments in a statement */ -char *defmat = VOIDID; /* default (starting) material name */ -char *defpat = ""; /* default (starting) picture name */ -char *defobj = "F"; /* default (starting) object name */ + /* qualifiers */ +#define Q_MTL 0 +#define Q_MAP 1 +#define Q_GRP 2 +#define Q_OBJ 3 +#define Q_FAC 4 +#define NQUALS 5 -char picfile[128]; /* current picture file */ +char *qname[NQUALS] = { + "Material", + "Map", + "Group", + "Object", + "Face", +}; + +QLIST qlist = {NQUALS, qname}; + /* valid qualifier ids */ +IDLIST qual[NQUALS]; + /* mapping rules */ +RULEHD *ourmapping = NULL; + +char *defmat = DEFMAT; /* default (starting) material name */ +char *defobj = DEFOBJ; /* default (starting) object name */ +int donames = 0; /* only get qualifier names */ + +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 */ int lineno; /* current line number */ +int faceno; /* number of faces read */ -int nfaces; /* total number of faces output */ - -main(argc, argv) /* read in T-mesh files and convert */ +main(argc, argv) /* read in .obj file and convert */ int argc; char *argv[]; { - FILE *fp; + char *fname; int i; for (i = 1; i < argc && argv[i][0] == '-'; i++) @@ -67,30 +93,90 @@ char *argv[]; case 'o': /* object name */ defobj = argv[++i]; break; - case 'm': /* default material */ - defmat = argv[++i]; + case 'n': /* just produce name list */ + donames++; break; - case 'p': /* default picture */ - defpat = argv[++i]; + case 'm': /* use custom mapfile */ + ourmapping = getmapping(argv[++i], &qlist); break; default: - fprintf(stderr, - "Usage: %s [-o obj][-m mat][-p pic] [file ..]\n", - argv[0]); - exit(1); + goto userr; } - if (i >= argc) - convert("", stdin); - else - for ( ; i < argc; i++) { - if ((fp = fopen(argv[i], "r")) == NULL) { - perror(argv[i]); - exit(1); + 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); + exit(1); + } + if (donames) { /* scan for ids */ + getnames(stdin); + printf("filename \"%s\"\n", fname); + printf("filetype \"Wavefront\"\n"); + write_quals(&qlist, qual, stdout); + printf("qualifier %s begin\n", qlist.qual[Q_FAC]); + printf("[%d:%d]\n", 1, faceno); + printf("end\n"); + } else { /* translate file */ + printf("# "); + printargs(argc, argv, stdout); + convert(fname, stdin); + } + exit(0); +userr: + fprintf(stderr, "Usage: %s [-o obj][-m mapping][-n] [file.obj]\n", + argv[0]); + exit(1); +} + + +getnames(fp) /* get valid qualifier names */ +FILE *fp; +{ + char *argv[MAXARG]; + int argc; + ID tmpid; + register int i; + + while (argc = getstmt(argv, fp)) + switch (argv[0][0]) { + case 'f': /* face */ + if (!argv[0][1]) + faceno++; + break; + case 'u': + if (!strcmp(argv[0], "usemtl")) { /* material */ + if (argc < 2) + break; /* not fatal */ + tmpid.number = 0; + tmpid.name = argv[1]; + findid(&qual[Q_MTL], &tmpid, 1); + } else if (!strcmp(argv[0], "usemap")) {/* map */ + if (argc < 2 || !strcmp(argv[1], "off")) + break; /* not fatal */ + tmpid.number = 0; + tmpid.name = argv[1]; + findid(&qual[Q_MAP], &tmpid, 1); } - convert(argv[i], fp); - fclose(fp); + break; + case 'o': /* object name */ + if (argv[0][1] || argc < 2) + break; + tmpid.number = 0; + tmpid.name = argv[1]; + findid(&qual[Q_OBJ], &tmpid, 1); + break; + case 'g': /* group name(s) */ + if (argv[0][1]) + break; + tmpid.number = 0; + for (i = 1; i < argc; i++) { + tmpid.name = argv[i]; + findid(&qual[Q_GRP], &tmpid, 1); + } + break; } - exit(0); } @@ -104,13 +190,11 @@ FILE *fp; register int i; /* start fresh */ freeverts(); - strcpy(picfile, defpat); + mapname[0] = '\0'; strcpy(matname, defmat); strcpy(objname, defobj); lineno = 0; nstats = nunknown = 0; - - printf("\n# Wavefront file read from: %s\n", fname); /* scan until EOF */ while (argc = getstmt(argv, fp)) { switch (argv[0][0]) { @@ -131,7 +215,7 @@ FILE *fp; atof(argv[3]))) syntax(fname, lineno, "Zero normal"); break; - case 't': /* texture */ + case 't': /* texture map */ if (argv[0][2]) goto unknown; if (badarg(argc-1,argv+1,"ff")) @@ -145,6 +229,7 @@ FILE *fp; case 'f': /* face */ if (argv[0][1]) goto unknown; + faceno++; switch (argc-1) { case 0: case 1: case 2: syntax(fname, lineno, "Too few vertices"); @@ -173,9 +258,9 @@ FILE *fp; if (argc < 2) break; /* not fatal */ if (!strcmp(argv[1], "off")) - picfile[0] = '\0'; + mapname[0] = '\0'; else - strcpy(picfile, argv[1]); + strcpy(mapname, argv[1]); } else goto unknown; break; @@ -189,15 +274,9 @@ FILE *fp; case 'g': /* group name(s) */ if (argv[0][1]) goto unknown; - if (argc < 2) - break; /* not fatal */ - objname[0] = '\0'; for (i = 1; i < argc; i++) - if (objname[0]) - sprintf(objname+strlen(objname), - ".%s", argv[i]); - else - strcpy(objname, argv[i]); + strcpy(group[i-1], argv[i]); + group[i-1][0] = '\0'; break; case '#': /* comment */ break; @@ -208,7 +287,7 @@ FILE *fp; } nstats++; } - printf("# Done processing file: %s\n", fname); + printf("\n# Done processing file: %s\n", fname); printf("# %d lines, %d statements, %d unrecognized\n", lineno, nstats, nunknown); } @@ -246,8 +325,99 @@ FILE *fp; return(i); } - + +char * +getmtl() /* figure material for this face */ +{ + register RULEHD *rp = ourmapping; + + if (rp == NULL) /* no rule set */ + return(matname); + /* check for match */ + do { + if (matchrule(rp)) { + if (!strcmp(rp->mnam, VOIDID)) + return(NULL); /* match is null */ + return(rp->mnam); + } + rp = rp->next; + } while (rp != NULL); + /* no match found */ + return(NULL); +} + + +char * +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 */ + + cp1 = name; /* else make name out of groups */ + for (i = 0; group[i][0]; i++) { + cp2 = group[i]; + if (cp1 > name) + *cp1++ = '.'; + while (*cp1 = *cp2++) + if (++cp1 >= name+sizeof(name)-2) { + *cp1 = '\0'; + return(name); + } + } + return(name); +} + + +matchrule(rp) /* check for a match on this rule */ +register RULEHD *rp; +{ + ID tmpid; + int gotmatch; + register int i; + + if (rp->qflg & FL(Q_MTL)) { + tmpid.number = 0; + tmpid.name = matname; + if (!matchid(&tmpid, &idm(rp)[Q_MTL])) + return(0); + } + if (rp->qflg & FL(Q_MAP)) { + tmpid.number = 0; + tmpid.name = mapname; + if (!matchid(&tmpid, &idm(rp)[Q_MAP])) + return(0); + } + if (rp->qflg & FL(Q_GRP)) { + tmpid.number = 0; + gotmatch = 0; + for (i = 0; group[i][0]; i++) { + tmpid.name = group[i]; + gotmatch |= matchid(&tmpid, &idm(rp)[Q_GRP]); + } + if (!gotmatch) + return(0); + } + if (rp->qflg & FL(Q_OBJ)) { + tmpid.number = 0; + tmpid.name = objname; + if (!matchid(&tmpid, &idm(rp)[Q_OBJ])) + return(0); + } + if (rp->qflg & FL(Q_FAC)) { + tmpid.name = NULL; + tmpid.number = faceno; + if (!matchid(&tmpid, &idm(rp)[Q_FAC])) + return(0); + } + return(1); +} + + cvtndx(vi, vs) /* convert vertex string to index */ register VNDX vi; register char *vs; @@ -263,7 +433,7 @@ register char *vs; return(0); } else return(0); - /* get texture */ + /* get map */ while (*vs) if (*vs++ == '/') break; @@ -295,16 +465,83 @@ 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; + FLOAT *p0, *p1; + FVECT v1, v2, nsum, newn; + double d; + register int i; - printf("\n%s polygon %s.%d\n", matname, objname, ++nfaces); + 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 *mod; + 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 */ + for (i = 1; i < ac; i++) + av[i] = av[i+2]; + } + if (ac == 3 && !puttri(av[0], av[1], av[2])) + return(0); + return(1); + } + if ((mod = getmtl()) == NULL) + return(-1); + printf("\n%s polygon %s.%d\n", mod, 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]]); } @@ -315,20 +552,25 @@ register char **av; puttri(v1, v2, v3) /* put out a triangle */ char *v1, *v2, *v3; { - char *mod = matname; + char *mod; VNDX v1i, v2i, v3i; BARYCCM bvecs; + int texOK, patOK; + if ((mod = getmtl()) == NULL) + return(-1); + if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3)) return(0); /* compute barycentric coordinates */ - if ((v1i[2]>=0&&v2i[2]>=0&&v3i[2]>=0) || - (v1i[1]>=0&&v2i[1]>=0&&v3i[1]>=0)) + texOK = (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0); + patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0); + if (texOK | patOK) if (comp_baryc(bvecs, vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]]) < 0) - return(0); + return(-1); /* put out texture (if any) */ - if (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0) { + if (texOK) { printf("\n%s texfunc %s\n", mod, TEXNAME); mod = TEXNAME; printf("4 dx dy dz %s\n", TCALNAME); @@ -345,10 +587,10 @@ char *v1, *v2, *v3; vnlist[v3i[2]][2]); } /* put out pattern (if any) */ - if (picfile[0] && v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0) { + if (patOK) { printf("\n%s colorpict %s\n", mod, PATNAME); mod = PATNAME; - printf("7 noneg noneg noneg %s %s u v\n", picfile, TCALNAME); + printf("7 noneg noneg noneg %s %s u v\n", mapname, TCALNAME); printf("0\n18\n"); put_baryc(bvecs); printf("\t%f %f %f\n", vtlist[v1i[1]][0], @@ -357,7 +599,7 @@ char *v1, *v2, *v3; vtlist[v2i[1]][1], vtlist[v3i[1]][1]); } /* put out triangle */ - printf("\n%s polygon %s.%d\n", matname, objname, ++nfaces); + printf("\n%s polygon %s.%d\n", mod, getonm(), faceno); printf("0\n0\n9\n"); pvect(vlist[v1i[0]]); pvect(vlist[v2i[0]]); @@ -417,14 +659,19 @@ register BARYCCM bcm; } -putquad(p0, p1, p2, p3) /* put out a quadrilateral */ -char *p0, *p1, *p2, *p3; +putquad(p0, p1, p3, p2) /* put out a quadrilateral */ +char *p0, *p1, *p3, *p2; /* names correspond to binary pos. */ { VNDX p0i, p1i, p2i, p3i; FVECT norm[4]; + char *mod, *name; int axis; FVECT v1, v2, vc1, vc2; int ok1, ok2; + + if ((mod = getmtl()) == NULL) + return(-1); + name = getonm(); /* get actual indices */ if (!cvtndx(p0i,p0) || !cvtndx(p1i,p1) || !cvtndx(p2i,p2) || !cvtndx(p3i,p3)) @@ -439,13 +686,13 @@ char *p0, *p1, *p2, *p3; fcross(vc2, v1, v2); ok2 = normalize(vc2) != 0.0; if (!(ok1 | ok2)) - return(0); + return(-1); /* compute normal interpolation */ axis = norminterp(norm, p0i, p1i, p2i, p3i); /* put out quadrilateral? */ - if (ok1 & ok2 && fdot(vc1,vc2) >= 1.0-FTINY*FTINY) { - printf("\n%s ", matname); + if (ok1 & ok2 && fabs(fdot(vc1,vc2)) >= 1.0-FTINY) { + printf("\n%s ", mod); if (axis != -1) { printf("texfunc %s\n", TEXNAME); printf("4 surf_dx surf_dy surf_dz %s\n", QCALNAME); @@ -458,7 +705,7 @@ char *p0, *p1, *p2, *p3; pvect(v1); printf("\n%s ", TEXNAME); } - printf("polygon %s.%d\n", objname, ++nfaces); + printf("polygon %s.%d\n", name, faceno); printf("0\n0\n12\n"); pvect(vlist[p0i[0]]); pvect(vlist[p1i[0]]); @@ -468,7 +715,7 @@ char *p0, *p1, *p2, *p3; } /* put out triangles? */ if (ok1) { - printf("\n%s ", matname); + printf("\n%s ", mod); if (axis != -1) { printf("texfunc %s\n", TEXNAME); printf("4 surf_dx surf_dy surf_dz %s\n", QCALNAME); @@ -480,14 +727,14 @@ char *p0, *p1, *p2, *p3; pvect(v1); printf("\n%s ", TEXNAME); } - printf("polygon %s.%d\n", objname, ++nfaces); + printf("polygon %s.%da\n", name, faceno); printf("0\n0\n9\n"); pvect(vlist[p0i[0]]); pvect(vlist[p1i[0]]); pvect(vlist[p2i[0]]); } if (ok2) { - printf("\n%s ", matname); + printf("\n%s ", mod); if (axis != -1) { printf("texfunc %s\n", TEXNAME); printf("4 surf_dx surf_dy surf_dz %s\n", QCALNAME); @@ -499,7 +746,7 @@ char *p0, *p1, *p2, *p3; pvect(v2); printf("\n%s ", TEXNAME); } - printf("polygon %s.%d\n", objname, ++nfaces); + printf("polygon %s.%db\n", name, faceno); printf("0\n0\n9\n"); pvect(vlist[p2i[0]]); pvect(vlist[p1i[0]]); @@ -633,7 +880,7 @@ double x, y, z; int -newvt(x, y) /* create a new texture vertex */ +newvt(x, y) /* create a new texture map vertex */ double x, y; { if (!(nvts%CHUNKSIZ)) { /* allocate next block */ @@ -649,7 +896,7 @@ double x, y; exit(1); } } - /* assign new texture vertex */ + /* assign new vertex */ vtlist[nvts][0] = x; vtlist[nvts][1] = y; return(++nvts);