--- ray/src/cv/obj2rad.c 1996/07/24 13:07:41 2.16 +++ ray/src/cv/obj2rad.c 2021/04/15 23:51:04 2.32 @@ -1,11 +1,8 @@ -/* Copyright (c) 1994 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: obj2rad.c,v 2.32 2021/04/15 23:51:04 greg Exp $"; #endif - /* - * Convert a Wavefront .obj file to Radiance format. + * Convert a Wavefront .OBJ file to Radiance format. * * Currently, we support only polygonal geometry. Non-planar * faces are broken rather haphazardly into triangles. @@ -13,33 +10,38 @@ static char SCCSid[] = "$SunId$ LBL"; * I'm not sure they work correctly. (Taken out -- see TEXMAPS defines.) */ -#include "standard.h" +#include +#include +#include "rtmath.h" +#include "rtio.h" +#include "resolu.h" #include "trans.h" - #include "tmesh.h" -#include #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 pvect(v) printf("%18.12g %18.12g %18.12g\n",(v)[0],(v)[1],(v)[2]) +#define pvect(v) printf(" %18.12g %18.12g %18.12g\n",(v)[0],(v)[1],(v)[2]) FVECT *vlist; /* our vertex list */ int nvs; /* number of vertices in our list */ FVECT *vnlist; /* vertex normal list */ int nvns; -FLOAT (*vtlist)[2]; /* map vertex list */ +RREAL (*vtlist)[2]; /* map vertex list */ int nvts; +int ndegen = 0; /* count of degenerate faces */ +int n0norm = 0; /* count of zero normals */ + typedef int VNDX[3]; /* vertex index (point,map,normal) */ -#define CHUNKSIZ 256 /* vertex allocation chunk size */ +#define CHUNKSIZ 1024 /* vertex allocation chunk size */ -#define MAXARG 64 /* maximum # arguments in a statement */ +#define MAXARG 512 /* maximum # arguments in a statement */ /* qualifiers */ #define Q_MTL 0 @@ -68,20 +70,36 @@ char *defobj = DEFOBJ; /* default (starting) object na 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 mapname[256]; /* current picture file */ +char matname[256]; /* current material name */ +char group[8][256]; /* current group name(s) */ +char objname[256]; /* current object name */ char *inpfile; /* input file name */ int lineno; /* current line number */ int faceno; /* current face number */ +static void getnames(FILE *fp); +static void convert(FILE *fp); +static int getstmt(char *av[MAXARG], FILE *fp); +static char * getmtl(void); +static char * getonm(void); +static int matchrule(RULEHD *rp); +static int cvtndx(VNDX vi, char *vs); +static int nonplanar(int ac, char **av); +static int putface(int ac, char **av); +static int puttri(char *v1, char *v2, char *v3); +static void freeverts(void); +static int newv(double x, double y, double z); +static int newvn(double x, double y, double z); +static int newvt(double x, double y); +static void syntax(char *er); -main(argc, argv) /* read in .obj file and convert */ -int argc; -char *argv[]; + +int +main( /* read in .OBJ file and convert */ + int argc, + char *argv[] +) { int donames = 0; int i; @@ -103,7 +121,7 @@ char *argv[]; default: goto userr; } - if (i > argc | i < argc-1) + if ((i > argc) | (i < argc-1)) goto userr; if (i == argc) inpfile = ""; @@ -124,6 +142,10 @@ char *argv[]; printargs(argc, argv, stdout); convert(stdin); } + if (ndegen) + printf("# %d degenerate faces\n", ndegen); + if (n0norm) + printf("# %d invalid (zero) normals\n", n0norm); exit(0); userr: fprintf(stderr, "Usage: %s [-o obj][-m mapping][-n][-f] [file.obj]\n", @@ -132,15 +154,17 @@ userr: } -getnames(fp) /* get valid qualifier names */ -FILE *fp; +void +getnames( /* get valid qualifier names */ + FILE *fp +) { char *argv[MAXARG]; int argc; ID tmpid; - register int i; + int i; - while (argc = getstmt(argv, fp)) + while ( (argc = getstmt(argv, fp)) ) switch (argv[0][0]) { case 'f': /* face */ if (!argv[0][1]) @@ -181,17 +205,19 @@ FILE *fp; } -convert(fp) /* convert a T-mesh */ -FILE *fp; +void +convert( /* convert an OBJ stream */ + FILE *fp +) { char *argv[MAXARG]; int argc; int nstats, nunknown; - register int i; + int i; nstats = nunknown = 0; /* scan until EOF */ - while (argc = getstmt(argv, fp)) { + while ( (argc = getstmt(argv, fp)) ) { switch (argv[0][0]) { case 'v': /* vertex */ switch (argv[0][1]) { @@ -250,7 +276,7 @@ FILE *fp; if (!strcmp(argv[1], "off")) mapname[0] = '\0'; else - sprintf(mapname, "%s.pic", argv[1]); + sprintf(mapname, "%s.hdr", argv[1]); } else goto unknown; break; @@ -266,7 +292,7 @@ FILE *fp; goto unknown; for (i = 1; i < argc; i++) strcpy(group[i-1], argv[i]); - group[i-1][0] = '\0'; + group[argc-1][0] = '\0'; break; case '#': /* comment */ printargs(argc, argv, stdout); @@ -285,14 +311,14 @@ FILE *fp; int -getstmt(av, fp) /* read the next statement from fp */ -register char *av[MAXARG]; -FILE *fp; +getstmt( /* read the next statement from fp */ + char *av[MAXARG], + FILE *fp +) { - extern char *fgetline(); - static char sbuf[MAXARG*10]; - register char *cp; - register int i; + static char sbuf[MAXARG*16]; + char *cp; + int i; do { if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL) @@ -304,8 +330,14 @@ FILE *fp; lineno++; *cp++ = '\0'; } - if (!*cp || i >= MAXARG-1) + if (!*cp) break; + if (i >= MAXARG-1) { + fprintf(stderr, + "warning: line %d: too many arguments (limit %d)\n", + lineno+1, MAXARG-1); + break; + } av[i++] = cp; while (*++cp && !isspace(*cp)) ; @@ -319,9 +351,9 @@ FILE *fp; char * -getmtl() /* figure material for this face */ +getmtl(void) /* figure material for this face */ { - register RULEHD *rp = ourmapping; + RULEHD *rp = ourmapping; if (rp == NULL) { /* no rule set */ if (matname[0]) @@ -345,11 +377,11 @@ getmtl() /* figure material for this face */ char * -getonm() /* invent a good name for object */ +getonm(void) /* invent a good name for object */ { static char name[64]; - register char *cp1, *cp2; - register int i; + char *cp1, *cp2; + int i; /* check for preset */ if (objname[0]) return(objname); @@ -360,7 +392,7 @@ getonm() /* invent a good name for object */ cp2 = group[i]; if (cp1 > name) *cp1++ = '.'; - while (*cp1 = *cp2++) + while ( (*cp1 = *cp2++) ) if (++cp1 >= name+sizeof(name)-2) { *cp1 = '\0'; return(name); @@ -370,12 +402,14 @@ getonm() /* invent a good name for object */ } -matchrule(rp) /* check for a match on this rule */ -register RULEHD *rp; +int +matchrule( /* check for a match on this rule */ + RULEHD *rp +) { ID tmpid; int gotmatch; - register int i; + int i; if (rp->qflg & FL(Q_MTL)) { if (!matname[0]) @@ -421,9 +455,11 @@ register RULEHD *rp; } -cvtndx(vi, vs) /* convert vertex string to index */ -register VNDX vi; -register char *vs; +int +cvtndx( /* convert vertex string to index */ + VNDX vi, + char *vs +) { /* get point */ vi[0] = atoi(vs); @@ -464,19 +500,24 @@ register char *vs; return(0); } else vi[2] = -1; + /* zero normal is not normal */ + if (vi[2] >= 0 && DOT(vnlist[vi[2]],vnlist[vi[2]]) <= FTINY) + vi[2] = -1; return(1); } -nonplanar(ac, av) /* are vertices non-planar? */ -register int ac; -register char **av; +int +nonplanar( /* are vertices non-planar? */ + int ac, + char **av +) { VNDX vi; - FLOAT *p0, *p1; + RREAL *p0, *p1; FVECT v1, v2, nsum, newn; double d; - register int i; + int i; if (!cvtndx(vi, av[0])) return(0); @@ -519,13 +560,15 @@ register char **av; } -putface(ac, av) /* put out an N-sided polygon */ -int ac; -register char **av; +int +putface( /* put out an N-sided polygon */ + int ac, + char **av +) { VNDX vi; char *cp; - register int i; + int i; if (nonplanar(ac, av)) { /* break into triangles */ while (ac > 2) { @@ -552,15 +595,20 @@ register char **av; } -puttri(v1, v2, v3) /* put out a triangle */ -char *v1, *v2, *v3; +int +puttri( /* put out a triangle */ + char *v1, + char *v2, + char *v3 +) { char *mod; VNDX v1i, v2i, v3i; BARYCCM bvecs; - FLOAT bcoor[3][3]; - int texOK, patOK; - register int i; + RREAL bcoor[3][3]; + int texOK = 0, patOK; + int flatness; + int i; if ((mod = getmtl()) == NULL) return(-1); @@ -568,22 +616,27 @@ char *v1, *v2, *v3; if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3)) return(0); /* compute barycentric coordinates */ - if (!flatten && v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0) - switch (flat_tri(vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]], - vnlist[v1i[2]], vnlist[v2i[2]], vnlist[v3i[2]])) { - case DEGEN: /* zero area */ - return(-1); - case RVFLAT: /* reversed normals, but flat */ - case ISFLAT: /* smoothing unnecessary */ - texOK = 0; - break; - case RVBENT: /* reversed normals with smoothing */ - case ISBENT: /* proper smoothing */ - texOK = 1; - break; - } + if (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0) + flatness = flat_tri(vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]], + vnlist[v1i[2]], vnlist[v2i[2]], vnlist[v3i[2]]); else + flatness = ISFLAT; + + switch (flatness) { + case DEGEN: /* zero area */ + ndegen++; + return(-1); + case RVFLAT: /* reversed normals, but flat */ + case ISFLAT: /* smoothing unnecessary */ texOK = 0; + break; + case RVBENT: /* reversed normals with smoothing */ + case ISBENT: /* proper smoothing */ + texOK = 1; + break; + } + if (flatten) + texOK = 0; #ifdef TEXMAPS patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0); #else @@ -592,7 +645,7 @@ char *v1, *v2, *v3; if (texOK | patOK) if (comp_baryc(&bvecs, vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]]) < 0) - return(-1); + texOK = patOK = 0; /* put out texture (if any) */ if (texOK) { printf("\n%s texfunc %s\n", mod, TEXNAME); @@ -604,7 +657,7 @@ char *v1, *v2, *v3; bcoor[i][1] = vnlist[v2i[2]][i]; bcoor[i][2] = vnlist[v3i[2]][i]; } - put_baryc(&bvecs, bcoor, 3); + fput_baryc(&bvecs, bcoor, 3, stdout); } #ifdef TEXMAPS /* put out pattern (if any) */ @@ -618,46 +671,55 @@ char *v1, *v2, *v3; bcoor[i][1] = vtlist[v2i[1]][i]; bcoor[i][2] = vtlist[v3i[1]][i]; } - put_baryc(&bvecs, bcoor, 2); + fput_baryc(&bvecs, bcoor, 2, stdout); } #endif - /* put out triangle */ + /* put out (reversed) triangle */ printf("\n%s polygon %s.%d\n", mod, getonm(), faceno); printf("0\n0\n9\n"); - pvect(vlist[v1i[0]]); - pvect(vlist[v2i[0]]); - pvect(vlist[v3i[0]]); - + if (flatness == RVFLAT || flatness == RVBENT) { + pvect(vlist[v3i[0]]); + pvect(vlist[v2i[0]]); + pvect(vlist[v1i[0]]); + } else { + pvect(vlist[v1i[0]]); + pvect(vlist[v2i[0]]); + pvect(vlist[v3i[0]]); + } return(1); } -freeverts() /* free all vertices */ +void +freeverts(void) /* free all vertices */ { if (nvs) { - free((char *)vlist); + free((void *)vlist); nvs = 0; } if (nvts) { - free((char *)vtlist); + free((void *)vtlist); nvts = 0; } if (nvns) { - free((char *)vnlist); + free((void *)vnlist); nvns = 0; } } int -newv(x, y, z) /* create a new vertex */ -double x, y, z; +newv( /* create a new vertex */ + double x, + double y, + double z +) { if (!(nvs%CHUNKSIZ)) { /* allocate next block */ if (nvs == 0) vlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT)); else - vlist = (FVECT *)realloc((char *)vlist, + vlist = (FVECT *)realloc((void *)vlist, (nvs+CHUNKSIZ)*sizeof(FVECT)); if (vlist == NULL) { fprintf(stderr, @@ -674,14 +736,17 @@ double x, y, z; int -newvn(x, y, z) /* create a new vertex normal */ -double x, y, z; +newvn( /* create a new vertex normal */ + double x, + double y, + double z +) { if (!(nvns%CHUNKSIZ)) { /* allocate next block */ if (nvns == 0) vnlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT)); else - vnlist = (FVECT *)realloc((char *)vnlist, + vnlist = (FVECT *)realloc((void *)vnlist, (nvns+CHUNKSIZ)*sizeof(FVECT)); if (vnlist == NULL) { fprintf(stderr, @@ -693,22 +758,23 @@ double x, y, z; vnlist[nvns][0] = x; vnlist[nvns][1] = y; vnlist[nvns][2] = z; - if (normalize(vnlist[nvns]) == 0.0) - return(0); + n0norm += (normalize(vnlist[nvns]) == 0.0); return(++nvns); } int -newvt(x, y) /* create a new texture map vertex */ -double x, y; +newvt( /* create a new texture map vertex */ + double x, + double y +) { if (!(nvts%CHUNKSIZ)) { /* allocate next block */ if (nvts == 0) - vtlist = (FLOAT (*)[2])malloc(CHUNKSIZ*2*sizeof(FLOAT)); + vtlist = (RREAL (*)[2])malloc(CHUNKSIZ*2*sizeof(RREAL)); else - vtlist = (FLOAT (*)[2])realloc((char *)vtlist, - (nvts+CHUNKSIZ)*2*sizeof(FLOAT)); + vtlist = (RREAL (*)[2])realloc((void *)vtlist, + (nvts+CHUNKSIZ)*2*sizeof(RREAL)); if (vtlist == NULL) { fprintf(stderr, "Out of memory while allocating texture vertex %d\n", @@ -723,8 +789,10 @@ double x, y; } -syntax(er) /* report syntax error and exit */ -char *er; +void +syntax( /* report syntax error and exit */ + char *er +) { fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n", inpfile, lineno, er);