Back to index

radiance  4R0+20100331
wfconv.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: wfconv.c,v 2.9 2004/04/23 16:20:56 greg Exp $";
00003 #endif
00004 /*
00005  *  Load Wavefront .OBJ file and convert to triangles with mesh info.
00006  *  Code borrowed largely from obj2rad.c
00007  */
00008 
00009 #include "copyright.h"
00010 #include "standard.h"
00011 #include "cvmesh.h"
00012 #include <ctype.h>
00013 
00014 typedef int   VNDX[3];      /* vertex index (point,map,normal) */
00015 
00016 #define CHUNKSIZ     1024   /* vertex allocation chunk size */
00017 
00018 #define MAXARG              512    /* maximum # arguments in a statement */
00019 
00020 static FVECT  *vlist;              /* our vertex list */
00021 static int    nvs;          /* number of vertices in our list */
00022 static FVECT  *vnlist;      /* vertex normal list */
00023 static int    nvns;
00024 static RREAL  (*vtlist)[2]; /* map vertex list */
00025 static int    nvts;
00026 
00027 static char   *inpfile;     /* input file name */
00028 static int    havemats;     /* materials available? */
00029 static char   material[64]; /* current material name */
00030 static char   group[64];    /* current group name */
00031 static int    lineno;              /* current line number */
00032 static int    faceno;              /* current face number */
00033 
00034 static int getstmt(char     *av[MAXARG], FILE    *fp);
00035 static int cvtndx(VNDX      vi, char      *vs);
00036 static int putface(int      ac, char      **av);
00037 static OBJECT getmod(void);
00038 static int puttri(char      *v1, char     *v2, char     *v3);
00039 static void freeverts(void);
00040 static int newv(double      x, double     y, double     z);
00041 static int newvn(double     x, double     y, double     z);
00042 static int newvt(double     x, double     y);
00043 static void syntax(char     *er);
00044 
00045 
00046 void
00047 wfreadobj(           /* read in .OBJ file and convert */
00048        char   *objfn
00049 )
00050 {
00051        FILE   *fp;
00052        char   *argv[MAXARG];
00053        int    argc;
00054        int    nstats, nunknown;
00055 
00056        if (objfn == NULL) {
00057               inpfile = "<stdin>";
00058               fp = stdin;
00059        } else if ((fp = fopen(inpfile=objfn, "r")) == NULL) {
00060               sprintf(errmsg, "cannot open \"%s\"", inpfile);
00061               error(USER, errmsg);
00062        }
00063        havemats = (nobjects > 0);
00064        nstats = nunknown = 0;
00065        material[0] = '\0';
00066        group[0] = '\0';
00067        lineno = 0; faceno = 0;
00068                                    /* scan until EOF */
00069        while ( (argc = getstmt(argv, fp)) ) {
00070               switch (argv[0][0]) {
00071               case 'v':            /* vertex */
00072                      switch (argv[0][1]) {
00073                      case '\0':                  /* point */
00074                             if (badarg(argc-1,argv+1,"fff"))
00075                                    syntax("bad vertex");
00076                             newv(atof(argv[1]), atof(argv[2]),
00077                                           atof(argv[3]));
00078                             break;
00079                      case 'n':                   /* normal */
00080                             if (argv[0][2])
00081                                    goto unknown;
00082                             if (badarg(argc-1,argv+1,"fff"))
00083                                    syntax("bad normal");
00084                             if (!newvn(atof(argv[1]), atof(argv[2]),
00085                                           atof(argv[3])))
00086                                    syntax("zero normal");
00087                             break;
00088                      case 't':                   /* coordinate */
00089                             if (argv[0][2])
00090                                    goto unknown;
00091                             if (badarg(argc-1,argv+1,"ff"))
00092                                    goto unknown;
00093                             newvt(atof(argv[1]), atof(argv[2]));
00094                             break;
00095                      default:
00096                             goto unknown;
00097                      }
00098                      break;
00099               case 'f':                          /* face */
00100                      if (argv[0][1])
00101                             goto unknown;
00102                      faceno++;
00103                      switch (argc-1) {
00104                      case 0: case 1: case 2:
00105                             syntax("too few vertices");
00106                             break;
00107                      case 3:
00108                             if (!puttri(argv[1], argv[2], argv[3]))
00109                                    syntax("bad triangle");
00110                             break;
00111                      default:
00112                             if (!putface(argc-1, argv+1))
00113                                    syntax("bad face");
00114                             break;
00115                      }
00116                      break;
00117               case 'u':                          /* usemtl/usemap */
00118                      if (!strcmp(argv[0], "usemap"))
00119                             break;
00120                      if (strcmp(argv[0], "usemtl"))
00121                             goto unknown;
00122                      if (argc > 1)
00123                             strcpy(material, argv[1]);
00124                      else
00125                             material[0] = '\0';
00126                      break;
00127               case 'o':            /* object name */
00128                      if (argv[0][1])
00129                             goto unknown;
00130                      break;
00131               case 'g':            /* group name */
00132                      if (argv[0][1])
00133                             goto unknown;
00134                      if (argc > 1)
00135                             strcpy(group, argv[1]);
00136                      else
00137                             group[0] = '\0';
00138                      break;
00139               case '#':            /* comment */
00140                      break;
00141               default:;            /* something we don't deal with */
00142               unknown:
00143                      nunknown++;
00144                      break;
00145               }
00146               nstats++;
00147        }
00148                             /* clean up */
00149        freeverts();
00150        fclose(fp);
00151        if (nunknown > 0) {
00152               sprintf(errmsg, "%d of %d statements unrecognized",
00153                             nunknown, nstats);
00154               error(WARNING, errmsg);
00155        }
00156 }
00157 
00158 
00159 static int
00160 getstmt(                           /* read the next statement from fp */
00161        register char *av[MAXARG],
00162        FILE   *fp
00163 )
00164 {
00165        static char   sbuf[MAXARG*16];
00166        register char *cp;
00167        register int  i;
00168 
00169        do {
00170               if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL)
00171                      return(0);
00172               i = 0;
00173               for ( ; ; ) {
00174                      while (isspace(*cp) || *cp == '\\') {
00175                             if (*cp == '\n')
00176                                    lineno++;
00177                             *cp++ = '\0';
00178                      }
00179                      if (!*cp)
00180                             break;
00181                      if (i >= MAXARG-1) {
00182                             sprintf(errmsg,
00183                      "%s: too many arguments near line %d (limit %d)\n",
00184                                    inpfile, lineno+1, MAXARG-1);
00185                             break;
00186                      }
00187                      av[i++] = cp;
00188                      while (*++cp && !isspace(*cp))
00189                             ;
00190               }
00191               av[i] = NULL;
00192               lineno++;
00193        } while (!i);
00194 
00195        return(i);
00196 }
00197 
00198 
00199 static int
00200 cvtndx(                            /* convert vertex string to index */
00201        register VNDX vi,
00202        register char *vs
00203 )
00204 {
00205                                    /* get point */
00206        vi[0] = atoi(vs);
00207        if (vi[0] > 0) {
00208               if (vi[0]-- > nvs)
00209                      return(0);
00210        } else if (vi[0] < 0) {
00211               vi[0] += nvs;
00212               if (vi[0] < 0)
00213                      return(0);
00214        } else
00215               return(0);
00216                                    /* get map coord. */
00217        while (*vs)
00218               if (*vs++ == '/')
00219                      break;
00220        vi[1] = atoi(vs);
00221        if (vi[1] > 0) {
00222               if (vi[1]-- > nvts)
00223                      return(0);
00224        } else if (vi[1] < 0) {
00225               vi[1] += nvts;
00226               if (vi[1] < 0)
00227                      return(0);
00228        } else
00229               vi[1] = -1;
00230                                    /* get normal */
00231        while (*vs)
00232               if (*vs++ == '/')
00233                      break;
00234        vi[2] = atoi(vs);
00235        if (vi[2] > 0) {
00236               if (vi[2]-- > nvns)
00237                      return(0);
00238        } else if (vi[2] < 0) {
00239               vi[2] += nvns;
00240               if (vi[2] < 0)
00241                      return(0);
00242        } else
00243               vi[2] = -1;
00244        return(1);
00245 }
00246 
00247 
00248 static int
00249 putface(                           /* put out an N-sided polygon */
00250        int    ac,
00251        register char **av
00252 )
00253 {
00254        char          *cp;
00255        register int  i;
00256 
00257        while (ac > 3) {            /* break into triangles */
00258               if (!puttri(av[0], av[1], av[2]))
00259                      return(0);
00260               ac--;                /* remove vertex & rotate */
00261               cp = av[0];
00262               for (i = 0; i < ac-1; i++)
00263                      av[i] = av[i+2];
00264               av[i] = cp;
00265        }
00266        return(puttri(av[0], av[1], av[2]));
00267 }
00268 
00269 
00270 static OBJECT
00271 getmod(void)                       /* get current modifier ID */
00272 {
00273        char   *mnam;
00274        OBJECT mod;
00275 
00276        if (!havemats)
00277               return(OVOID);
00278        if (!strcmp(material, VOIDID))
00279               return(OVOID);
00280        if (material[0])            /* prefer usemtl statements */
00281               mnam = material;
00282        else if (group[0])          /* else use group name */
00283               mnam = group;
00284        else
00285               return(OVOID);
00286        mod = modifier(mnam);
00287        if (mod == OVOID) {
00288               sprintf(errmsg, "%s: undefined modifier \"%s\"",
00289                             inpfile, mnam);
00290               error(USER, errmsg);
00291        }
00292        return(mod);
00293 }
00294 
00295 
00296 static int
00297 puttri(                     /* convert a triangle */
00298        char   *v1,
00299        char   *v2,
00300        char   *v3
00301 )
00302 {
00303        VNDX   v1i, v2i, v3i;
00304        RREAL  *v1c, *v2c, *v3c;
00305        RREAL  *v1n, *v2n, *v3n;
00306        
00307        if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3)) {
00308               error(WARNING, "bad vertex reference");
00309               return(0);
00310        }
00311        if (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0) {
00312               v1c = vtlist[v1i[1]];
00313               v2c = vtlist[v2i[1]];
00314               v3c = vtlist[v3i[1]];
00315        } else
00316               v1c = v2c = v3c = NULL;
00317 
00318        if (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0) {
00319               v1n = vnlist[v1i[2]];
00320               v2n = vnlist[v2i[2]];
00321               v3n = vnlist[v3i[2]];
00322        } else
00323               v1n = v2n = v3n = NULL;
00324        
00325        return(cvtri(getmod(), vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]],
00326                      v1n, v2n, v3n, v1c, v2c, v3c) >= 0);
00327 }
00328 
00329 
00330 static void
00331 freeverts(void)                    /* free all vertices */
00332 {
00333        if (nvs) {
00334               free((void *)vlist);
00335               nvs = 0;
00336        }
00337        if (nvts) {
00338               free((void *)vtlist);
00339               nvts = 0;
00340        }
00341        if (nvns) {
00342               free((void *)vnlist);
00343               nvns = 0;
00344        }
00345 }
00346 
00347 
00348 static int
00349 newv(                /* create a new vertex */
00350        double x,
00351        double y,
00352        double z
00353 )
00354 {
00355        if (!(nvs%CHUNKSIZ)) {             /* allocate next block */
00356               if (nvs == 0)
00357                      vlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
00358               else
00359                      vlist = (FVECT *)realloc((void *)vlist,
00360                                    (nvs+CHUNKSIZ)*sizeof(FVECT));
00361               if (vlist == NULL)
00362                      error(SYSTEM, "out of memory in newv");
00363        }
00364                                    /* assign new vertex */
00365        vlist[nvs][0] = x;
00366        vlist[nvs][1] = y;
00367        vlist[nvs][2] = z;
00368        return(++nvs);
00369 }
00370 
00371 
00372 static int
00373 newvn(               /* create a new vertex normal */
00374        double x,
00375        double y,
00376        double z
00377 )
00378 {
00379        if (!(nvns%CHUNKSIZ)) {            /* allocate next block */
00380               if (nvns == 0)
00381                      vnlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
00382               else
00383                      vnlist = (FVECT *)realloc((void *)vnlist,
00384                                    (nvns+CHUNKSIZ)*sizeof(FVECT));
00385               if (vnlist == NULL)
00386                      error(SYSTEM, "out of memory in newvn");
00387        }
00388                                    /* assign new normal */
00389        vnlist[nvns][0] = x;
00390        vnlist[nvns][1] = y;
00391        vnlist[nvns][2] = z;
00392        if (normalize(vnlist[nvns]) == 0.0)
00393               return(0);
00394        return(++nvns);
00395 }
00396 
00397 
00398 static int
00399 newvt(               /* create a new texture map vertex */
00400        double x,
00401        double y
00402 )
00403 {
00404        if (!(nvts%CHUNKSIZ)) {            /* allocate next block */
00405               if (nvts == 0)
00406                      vtlist = (RREAL (*)[2])malloc(CHUNKSIZ*2*sizeof(RREAL));
00407               else
00408                      vtlist = (RREAL (*)[2])realloc((void *)vtlist,
00409                                    (nvts+CHUNKSIZ)*2*sizeof(RREAL));
00410               if (vtlist == NULL)
00411                      error(SYSTEM, "out of memory in newvt");
00412        }
00413                                    /* assign new vertex */
00414        vtlist[nvts][0] = x;
00415        vtlist[nvts][1] = y;
00416        return(++nvts);
00417 }
00418 
00419 
00420 static void
00421 syntax(                     /* report syntax error and exit */
00422        char   *er
00423 )
00424 {
00425        sprintf(errmsg, "%s: Wavefront syntax error near line %d: %s\n",
00426                      inpfile, lineno, er);
00427        error(USER, errmsg);
00428 }