--- ray/src/ot/wfconv.c 2003/03/11 17:08:55 2.1 +++ ray/src/ot/wfconv.c 2021/03/11 17:00:58 2.17 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: wfconv.c,v 2.1 2003/03/11 17:08:55 greg Exp $"; +static const char RCSid[] = "$Id: wfconv.c,v 2.17 2021/03/11 17:00:58 greg Exp $"; #endif /* * Load Wavefront .OBJ file and convert to triangles with mesh info. @@ -9,34 +9,50 @@ static const char RCSid[] = "$Id: wfconv.c,v 2.1 2003/ #include "copyright.h" #include "standard.h" #include "cvmesh.h" +#include "triangulate.h" #include -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 */ -int nvts; - typedef int VNDX[3]; /* vertex index (point,map,normal) */ #define CHUNKSIZ 1024 /* vertex allocation chunk size */ -#define MAXARG 64 /* maximum # arguments in a statement */ +#define MAXARG 512 /* maximum # arguments in a statement */ -char *inpfile; /* input file name */ -int lineno; /* current line number */ -int faceno; /* current face number */ +static FVECT *vlist; /* our vertex list */ +static int nvs; /* number of vertices in our list */ +static FVECT *vnlist; /* vertex normal list */ +static int nvns; +static RREAL (*vtlist)[2]; /* map vertex list */ +static int nvts; +static char *inpfile; /* input file name */ +static int havemats; /* materials available? */ +static char material[256]; /* current material name */ +static char group[256]; /* current group name */ +static int lineno; /* current line number */ +static int faceno; /* current face number */ -wfreadobj(objfn) /* read in .OBJ file and convert */ -char *objfn; +static int getstmt(char *av[MAXARG], FILE *fp); +static int cvtndx(VNDX vi, char *vs); +static int putface(int ac, char **av); +static OBJECT getmod(void); +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); + + +void +wfreadobj( /* read in .OBJ file and convert */ + char *objfn +) { FILE *fp; char *argv[MAXARG]; int argc; int nstats, nunknown; - int i; if (objfn == NULL) { inpfile = ""; @@ -45,16 +61,19 @@ char *objfn; sprintf(errmsg, "cannot open \"%s\"", inpfile); error(USER, errmsg); } + havemats = (nobjects > 0); nstats = nunknown = 0; + material[0] = '\0'; + group[0] = '\0'; lineno = 0; faceno = 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]) { case '\0': /* point */ if (badarg(argc-1,argv+1,"fff")) - syntax("Bad vertex"); + syntax("bad vertex"); newv(atof(argv[1]), atof(argv[2]), atof(argv[3])); break; @@ -62,12 +81,12 @@ char *objfn; if (argv[0][2]) goto unknown; if (badarg(argc-1,argv+1,"fff")) - syntax("Bad normal"); + syntax("bad normal"); if (!newvn(atof(argv[1]), atof(argv[2]), atof(argv[3]))) - syntax("Zero normal"); + syntax("zero normal"); break; - case 't': /* texture map */ + case 't': /* coordinate */ if (argv[0][2]) goto unknown; if (badarg(argc-1,argv+1,"ff")) @@ -84,30 +103,39 @@ char *objfn; faceno++; switch (argc-1) { case 0: case 1: case 2: - syntax("Too few vertices"); + syntax("too few vertices"); break; case 3: if (!puttri(argv[1], argv[2], argv[3])) - syntax("Bad triangle"); + syntax("bad triangle"); break; default: if (!putface(argc-1, argv+1)) - syntax("Bad face"); + syntax("bad face"); break; } break; - case 'u': - if (strcmp(argv[0], "usemtl") && - strcmp(argv[0], "usemap")) + case 'u': /* usemtl/usemap */ + if (!strcmp(argv[0], "usemap")) + break; + if (strcmp(argv[0], "usemtl")) goto unknown; + if (argc > 1) + strcpy(material, argv[1]); + else + material[0] = '\0'; break; case 'o': /* object name */ if (argv[0][1]) goto unknown; break; - case 'g': /* group name(s) */ + case 'g': /* group name */ if (argv[0][1]) goto unknown; + if (argc > 1) + strcpy(group, argv[1]); + else + group[0] = '\0'; break; case '#': /* comment */ break; @@ -129,14 +157,15 @@ char *objfn; } -int -getstmt(av, fp) /* read the next statement from fp */ -register char *av[MAXARG]; -FILE *fp; +static int +getstmt( /* read the next statement from fp */ + char *av[MAXARG], + FILE *fp +) { - 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) @@ -148,8 +177,14 @@ FILE *fp; lineno++; *cp++ = '\0'; } - if (!*cp || i >= MAXARG-1) + if (!*cp) break; + if (i >= MAXARG-1) { + sprintf(errmsg, + "%s: too many arguments near line %d (limit %d)\n", + inpfile, lineno+1, MAXARG-1); + break; + } av[i++] = cp; while (*++cp && !isspace(*cp)) ; @@ -162,9 +197,11 @@ FILE *fp; } -cvtndx(vi, vs) /* convert vertex string to index */ -register VNDX vi; -register char *vs; +static int +cvtndx( /* convert vertex string to index */ + VNDX vi, + char *vs +) { /* get point */ vi[0] = atoi(vs); @@ -208,41 +245,116 @@ register char *vs; return(1); } +/* determine dominant axis for triangle */ +static int +dominant_axis(char *v1, char *v2, char *v3) +{ + VNDX v1i, v2i, v3i; + FVECT e1, e2, vn; + int i, imax; -putface(ac, av) /* put out an N-sided polygon */ -int ac; -register char **av; + if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3)) + return(-1); + VSUB(e1, vlist[v2i[0]], vlist[v1i[0]]); + VSUB(e2, vlist[v3i[0]], vlist[v2i[0]]); + VCROSS(vn, e1, e2); + for (i = imax = 2; i--; ) + if (vn[i]*vn[i] > vn[imax]*vn[imax]) + imax = i; + return(vn[imax]*vn[imax] > FTINY*FTINY*FTINY*FTINY ? imax : -1); +} + +/* callback for triangle output from polygon */ +static int +tri_out(const Vert2_list *tp, int a, int b, int c) { - VNDX vi; - char *cp; - register int i; + return( puttri( ((char **)tp->p)[a], + ((char **)tp->p)[b], + ((char **)tp->p)[c] ) ); +} - while (ac > 3) { /* break into triangles */ - if (!puttri(av[0], av[1], av[2])) - { - fprintf(stderr, "f %s %s %s\n", av[0], av[1], av[2]); +static int +putface( /* put out an N-sided polygon */ + int ac, + char **av +) +{ + Vert2_list *poly; + int i, ax, ay; + + for (i = ac-3; i >= 0; i--) /* identify dominant axis */ + if ((ax = dominant_axis(av[i], av[i+1], av[i+2])) >= 0) + break; + if (ax < 0) + return(1); /* ignore degenerate face */ + poly = polyAlloc(ac); + if (poly == NULL) + return(0); + poly->p = (void *)av; + if (++ax >= 3) ax = 0; + ay = ax; + if (++ay >= 3) ay = 0; + for (i = 0; i < ac; i++) { /* convert to 2-D polygon */ + VNDX vi; + if (!cvtndx(vi, av[i])) { + error(WARNING, "bad vertex reference"); + polyFree(poly); return(0); - } - ac--; /* remove vertex & rotate */ - cp = av[0]; - for (i = 0; i < ac-1; i++) - av[i] = av[i+2]; - av[i] = cp; + } + poly->v[i].mX = vlist[vi[0]][ax]; + poly->v[i].mY = vlist[vi[0]][ay]; } - return(puttri(av[0], av[1], av[2])); + /* break into triangles & output */ + if (!polyTriangulate(poly, &tri_out)) { + sprintf(errmsg, "self-intersecting face with %d vertices", ac); + error(WARNING, errmsg); + } + polyFree(poly); + return(1); } -puttri(v1, v2, v3) /* convert a triangle */ -char *v1, *v2, *v3; +static OBJECT +getmod(void) /* get current modifier ID */ { - VNDX v1i, v2i, v3i; - FLOAT *v1c, *v2c, *v3c; - FLOAT *v1n, *v2n, *v3n; + char *mnam; + OBJECT mod; - if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3)) - return(0); + if (!havemats) + return(OVOID); + if (!strcmp(material, VOIDID)) + return(OVOID); + if (material[0]) /* prefer usemtl statements */ + mnam = material; + else if (group[0]) /* else use group name */ + mnam = group; + else + return(OVOID); + mod = modifier(mnam); + if (mod == OVOID) { + sprintf(errmsg, "%s: undefined modifier \"%s\"", + inpfile, mnam); + error(USER, errmsg); + } + return(mod); +} + +static int +puttri( /* convert a triangle */ + char *v1, + char *v2, + char *v3 +) +{ + VNDX v1i, v2i, v3i; + RREAL *v1c, *v2c, *v3c; + RREAL *v1n, *v2n, *v3n; + + if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3)) { + error(WARNING, "bad vertex reference"); + return(0); + } if (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0) { v1c = vtlist[v1i[1]]; v2c = vtlist[v2i[1]]; @@ -257,12 +369,13 @@ char *v1, *v2, *v3; } else v1n = v2n = v3n = NULL; - return(cvtri(vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]], + return(cvtri(getmod(), vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]], v1n, v2n, v3n, v1c, v2c, v3c) >= 0); } -freeverts() /* free all vertices */ +static void +freeverts(void) /* free all vertices */ { if (nvs) { free((void *)vlist); @@ -279,21 +392,21 @@ freeverts() /* free all vertices */ } -int -newv(x, y, z) /* create a new vertex */ -double x, y, z; +static int +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, - "Out of memory while allocating vertex %d\n", nvs); - exit(1); - } + if (vlist == NULL) + error(SYSTEM, "out of memory in newv"); } /* assign new vertex */ vlist[nvs][0] = x; @@ -303,21 +416,21 @@ double x, y, z; } -int -newvn(x, y, z) /* create a new vertex normal */ -double x, y, z; +static int +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, - "Out of memory while allocating normal %d\n", nvns); - exit(1); - } + if (vnlist == NULL) + error(SYSTEM, "out of memory in newvn"); } /* assign new normal */ vnlist[nvns][0] = x; @@ -329,22 +442,20 @@ double x, y, z; } -int -newvt(x, y) /* create a new texture map vertex */ -double x, y; +static int +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)); - if (vtlist == NULL) { - fprintf(stderr, - "Out of memory while allocating texture vertex %d\n", - nvts); - exit(1); - } + vtlist = (RREAL (*)[2])realloc((void *)vtlist, + (nvts+CHUNKSIZ)*2*sizeof(RREAL)); + if (vtlist == NULL) + error(SYSTEM, "out of memory in newvt"); } /* assign new vertex */ vtlist[nvts][0] = x; @@ -353,10 +464,12 @@ double x, y; } -syntax(er) /* report syntax error and exit */ -char *er; +static void +syntax( /* report syntax error and exit */ + char *er +) { - fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n", + sprintf(errmsg, "%s: Wavefront syntax error near line %d: %s", inpfile, lineno, er); - exit(1); + error(USER, errmsg); }