Back to index

radiance  4R0+20100331
obj2rad.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: obj2rad.c,v 2.25 2008/11/10 19:08:18 greg Exp $";
00003 #endif
00004 /*
00005  * Convert a Wavefront .obj file to Radiance format.
00006  *
00007  * Currently, we support only polygonal geometry.  Non-planar
00008  * faces are broken rather haphazardly into triangles.
00009  * Also, texture map indices only work for triangles, though
00010  * I'm not sure they work correctly.  (Taken out -- see TEXMAPS defines.)
00011  */
00012 
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <ctype.h>
00016 
00017 #include "rtmath.h"
00018 #include "rtio.h"
00019 #include "resolu.h"
00020 #include "trans.h"
00021 #include "tmesh.h"
00022 
00023 
00024 #define PATNAME             "M-pat"              /* mesh pattern name (reused) */
00025 #define TEXNAME             "M-nor"              /* mesh texture name (reused) */
00026 #define DEFOBJ              "unnamed"     /* default object name */
00027 #define DEFMAT              "white"              /* default material name */
00028 
00029 #define pvect(v)     printf("%18.12g %18.12g %18.12g\n",(v)[0],(v)[1],(v)[2])
00030 
00031 FVECT  *vlist;                     /* our vertex list */
00032 int    nvs;                 /* number of vertices in our list */
00033 FVECT  *vnlist;             /* vertex normal list */
00034 int    nvns;
00035 RREAL  (*vtlist)[2];        /* map vertex list */
00036 int    nvts;
00037 
00038 int    ndegen = 0;          /* count of degenerate faces */
00039 
00040 typedef int   VNDX[3];      /* vertex index (point,map,normal) */
00041 
00042 #define CHUNKSIZ     1024   /* vertex allocation chunk size */
00043 
00044 #define MAXARG              512    /* maximum # arguments in a statement */
00045 
00046                             /* qualifiers */
00047 #define Q_MTL        0
00048 #define Q_MAP        1
00049 #define Q_GRP        2
00050 #define Q_OBJ        3
00051 #define Q_FAC        4
00052 #define NQUALS              5
00053 
00054 char   *qname[NQUALS] = {
00055        "Material",
00056        "Map",
00057        "Group",
00058        "Object",
00059        "Face",
00060 };
00061 
00062 QLIST  qlist = {NQUALS, qname};
00063                             /* valid qualifier ids */
00064 IDLIST qual[NQUALS];
00065                             /* mapping rules */
00066 RULEHD *ourmapping = NULL;
00067 
00068 char   *defmat = DEFMAT;    /* default (starting) material name */
00069 char   *defobj = DEFOBJ;    /* default (starting) object name */
00070 
00071 int    flatten = 0;         /* discard surface normal information */
00072 
00073 char   mapname[128];        /* current picture file */
00074 char   matname[64];         /* current material name */
00075 char   group[16][32];              /* current group names */
00076 char   objname[128];        /* current object name */
00077 char   *inpfile;            /* input file name */
00078 int    lineno;                     /* current line number */
00079 int    faceno;                     /* current face number */
00080 
00081 static void getnames(FILE *fp);
00082 static void convert(FILE *fp);
00083 static int getstmt(char *av[MAXARG], FILE *fp);
00084 static char * getmtl(void);
00085 static char * getonm(void);
00086 static int matchrule(RULEHD *rp);
00087 static int cvtndx(VNDX vi, char *vs);
00088 static int nonplanar(int ac, char **av);
00089 static int putface(int ac, char **av);
00090 static int puttri(char *v1, char *v2, char *v3);
00091 static void freeverts(void);
00092 static int newv(double x, double y, double z);
00093 static int newvn(double x, double y, double z);
00094 static int newvt(double x, double y);
00095 static void syntax(char *er);
00096 
00097 
00098 int
00099 main(         /* read in .obj file and convert */
00100        int    argc,
00101        char   *argv[]
00102 )
00103 {
00104        int    donames = 0;
00105        int    i;
00106 
00107        for (i = 1; i < argc && argv[i][0] == '-'; i++)
00108               switch (argv[i][1]) {
00109               case 'o':            /* object name */
00110                      defobj = argv[++i];
00111                      break;
00112               case 'n':            /* just produce name list */
00113                      donames++;
00114                      break;
00115               case 'm':            /* use custom mapfile */
00116                      ourmapping = getmapping(argv[++i], &qlist);
00117                      break;
00118               case 'f':            /* flatten surfaces */
00119                      flatten++;
00120                      break;
00121               default:
00122                      goto userr;
00123               }
00124        if ((i > argc) | (i < argc-1))
00125               goto userr;
00126        if (i == argc)
00127               inpfile = "<stdin>";
00128        else if (freopen(inpfile=argv[i], "r", stdin) == NULL) {
00129               fprintf(stderr, "%s: cannot open\n", inpfile);
00130               exit(1);
00131        }
00132        if (donames) {                            /* scan for ids */
00133               getnames(stdin);
00134               printf("filename \"%s\"\n", inpfile);
00135               printf("filetype \"Wavefront\"\n");
00136               write_quals(&qlist, qual, stdout);
00137               printf("qualifier %s begin\n", qlist.qual[Q_FAC]);
00138               printf("[%d:%d]\n", 1, faceno);
00139               printf("end\n");
00140        } else {                           /* translate file */
00141               printf("# ");
00142               printargs(argc, argv, stdout);
00143               convert(stdin);
00144        }
00145        if (ndegen)
00146               printf("# %d degenerate faces\n", ndegen);
00147        exit(0);
00148 userr:
00149        fprintf(stderr, "Usage: %s [-o obj][-m mapping][-n][-f] [file.obj]\n",
00150                      argv[0]);
00151        exit(1);
00152 }
00153 
00154 
00155 void
00156 getnames(                   /* get valid qualifier names */
00157        FILE   *fp
00158 )
00159 {
00160        char   *argv[MAXARG];
00161        int    argc;
00162        ID     tmpid;
00163        register int  i;
00164 
00165        while ( (argc = getstmt(argv, fp)) )
00166               switch (argv[0][0]) {
00167               case 'f':                          /* face */
00168                      if (!argv[0][1])
00169                             faceno++;
00170                      break;
00171               case 'u':
00172                      if (!strcmp(argv[0], "usemtl")) {  /* material */
00173                             if (argc < 2)
00174                                    break;        /* not fatal */
00175                             tmpid.number = 0;
00176                             tmpid.name = argv[1];
00177                             findid(&qual[Q_MTL], &tmpid, 1);
00178                      } else if (!strcmp(argv[0], "usemap")) {/* map */
00179                             if (argc < 2 || !strcmp(argv[1], "off"))
00180                                    break;        /* not fatal */
00181                             tmpid.number = 0;
00182                             tmpid.name = argv[1];
00183                             findid(&qual[Q_MAP], &tmpid, 1);
00184                      }
00185                      break;
00186               case 'o':            /* object name */
00187                      if (argv[0][1] || argc < 2)
00188                             break;
00189                      tmpid.number = 0;
00190                      tmpid.name = argv[1];
00191                      findid(&qual[Q_OBJ], &tmpid, 1);
00192                      break;
00193               case 'g':            /* group name(s) */
00194                      if (argv[0][1])
00195                             break;
00196                      tmpid.number = 0;
00197                      for (i = 1; i < argc; i++) {
00198                             tmpid.name = argv[i];
00199                             findid(&qual[Q_GRP], &tmpid, 1);
00200                      }
00201                      break;
00202               }
00203 }
00204 
00205 
00206 void
00207 convert(                    /* convert a T-mesh */
00208        FILE   *fp
00209 )
00210 {
00211        char   *argv[MAXARG];
00212        int    argc;
00213        int    nstats, nunknown;
00214        register int  i;
00215 
00216        nstats = nunknown = 0;
00217                                    /* scan until EOF */
00218        while ( (argc = getstmt(argv, fp)) ) {
00219               switch (argv[0][0]) {
00220               case 'v':            /* vertex */
00221                      switch (argv[0][1]) {
00222                      case '\0':                  /* point */
00223                             if (badarg(argc-1,argv+1,"fff"))
00224                                    syntax("Bad vertex");
00225                             newv(atof(argv[1]), atof(argv[2]),
00226                                           atof(argv[3]));
00227                             break;
00228                      case 'n':                   /* normal */
00229                             if (argv[0][2])
00230                                    goto unknown;
00231                             if (badarg(argc-1,argv+1,"fff"))
00232                                    syntax("Bad normal");
00233                             if (!newvn(atof(argv[1]), atof(argv[2]),
00234                                           atof(argv[3])))
00235                                    syntax("Zero normal");
00236                             break;
00237                      case 't':                   /* texture map */
00238                             if (argv[0][2])
00239                                    goto unknown;
00240                             if (badarg(argc-1,argv+1,"ff"))
00241                                    goto unknown;
00242                             newvt(atof(argv[1]), atof(argv[2]));
00243                             break;
00244                      default:
00245                             goto unknown;
00246                      }
00247                      break;
00248               case 'f':                          /* face */
00249                      if (argv[0][1])
00250                             goto unknown;
00251                      faceno++;
00252                      switch (argc-1) {
00253                      case 0: case 1: case 2:
00254                             syntax("Too few vertices");
00255                             break;
00256                      case 3:
00257                             if (!puttri(argv[1], argv[2], argv[3]))
00258                                    syntax("Bad triangle");
00259                             break;
00260                      default:
00261                             if (!putface(argc-1, argv+1))
00262                                    syntax("Bad face");
00263                             break;
00264                      }
00265                      break;
00266               case 'u':
00267                      if (!strcmp(argv[0], "usemtl")) {  /* material */
00268                             if (argc < 2)
00269                                    break;        /* not fatal */
00270                             strcpy(matname, argv[1]);
00271                      } else if (!strcmp(argv[0], "usemap")) {/* map */
00272                             if (argc < 2)
00273                                    break;        /* not fatal */
00274                             if (!strcmp(argv[1], "off"))
00275                                    mapname[0] = '\0';
00276                             else
00277                                    sprintf(mapname, "%s.hdr", argv[1]);
00278                      } else
00279                             goto unknown;
00280                      break;
00281               case 'o':            /* object name */
00282                      if (argv[0][1])
00283                             goto unknown;
00284                      if (argc < 2)
00285                             break;        /* not fatal */
00286                      strcpy(objname, argv[1]);
00287                      break;
00288               case 'g':            /* group name(s) */
00289                      if (argv[0][1])
00290                             goto unknown;
00291                      for (i = 1; i < argc; i++)
00292                             strcpy(group[i-1], argv[i]);
00293                      group[i-1][0] = '\0';
00294                      break;
00295               case '#':            /* comment */
00296                      printargs(argc, argv, stdout);
00297                      break;
00298               default:;            /* something we don't deal with */
00299               unknown:
00300                      nunknown++;
00301                      break;
00302               }
00303               nstats++;
00304        }
00305        printf("\n# Done processing file: %s\n", inpfile);
00306        printf("# %d lines, %d statements, %d unrecognized\n",
00307                      lineno, nstats, nunknown);
00308 }
00309 
00310 
00311 int
00312 getstmt(                           /* read the next statement from fp */
00313        register char *av[MAXARG],
00314        FILE   *fp
00315 )
00316 {
00317        static char   sbuf[MAXARG*16];
00318        register char *cp;
00319        register int  i;
00320 
00321        do {
00322               if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL)
00323                      return(0);
00324               i = 0;
00325               for ( ; ; ) {
00326                      while (isspace(*cp) || *cp == '\\') {
00327                             if (*cp == '\n')
00328                                    lineno++;
00329                             *cp++ = '\0';
00330                      }
00331                      if (!*cp)
00332                             break;
00333                      if (i >= MAXARG-1) {
00334                             fprintf(stderr,
00335                      "warning: line %d: too many arguments (limit %d)\n",
00336                                    lineno+1, MAXARG-1);
00337                             break;
00338                      }
00339                      av[i++] = cp;
00340                      while (*++cp && !isspace(*cp))
00341                             ;
00342               }
00343               av[i] = NULL;
00344               lineno++;
00345        } while (!i);
00346 
00347        return(i);
00348 }
00349 
00350 
00351 char *
00352 getmtl(void)                       /* figure material for this face */
00353 {
00354        register RULEHD      *rp = ourmapping;
00355 
00356        if (rp == NULL) {           /* no rule set */
00357               if (matname[0])
00358                      return(matname);
00359               if (group[0][0])
00360                      return(group[0]);
00361               return(defmat);
00362        }
00363                                    /* check for match */
00364        do {
00365               if (matchrule(rp)) {
00366                      if (!strcmp(rp->mnam, VOIDID))
00367                             return(NULL); /* match is null */
00368                      return(rp->mnam);
00369               }
00370               rp = rp->next;
00371        } while (rp != NULL);
00372                                    /* no match found */
00373        return(NULL);
00374 }
00375 
00376 
00377 char *
00378 getonm(void)                       /* invent a good name for object */
00379 {
00380        static char   name[64];
00381        register char *cp1, *cp2;
00382        register int  i;
00383                                    /* check for preset */
00384        if (objname[0])
00385               return(objname);
00386        if (!group[0][0])
00387               return(defobj);
00388        cp1 = name;                 /* else make name out of groups */
00389        for (i = 0; group[i][0]; i++) {
00390               cp2 = group[i];
00391               if (cp1 > name)
00392                      *cp1++ = '.';
00393               while ( (*cp1 = *cp2++) )
00394                      if (++cp1 >= name+sizeof(name)-2) {
00395                             *cp1 = '\0';
00396                             return(name);
00397                      }
00398        }
00399        return(name);
00400 }
00401 
00402 
00403 int
00404 matchrule(                         /* check for a match on this rule */
00405        register RULEHD      *rp
00406 )
00407 {
00408        ID     tmpid;
00409        int    gotmatch;
00410        register int  i;
00411 
00412        if (rp->qflg & FL(Q_MTL)) {
00413               if (!matname[0])
00414                      return(0);
00415               tmpid.number = 0;
00416               tmpid.name = matname;
00417               if (!matchid(&tmpid, &idm(rp)[Q_MTL]))
00418                      return(0);
00419        }
00420        if (rp->qflg & FL(Q_MAP)) {
00421               if (!mapname[0])
00422                      return(0);
00423               tmpid.number = 0;
00424               tmpid.name = mapname;
00425               if (!matchid(&tmpid, &idm(rp)[Q_MAP]))
00426                      return(0);
00427        }
00428        if (rp->qflg & FL(Q_GRP)) {
00429               tmpid.number = 0;
00430               gotmatch = 0;
00431               for (i = 0; group[i][0]; i++) {
00432                      tmpid.name = group[i];
00433                      gotmatch |= matchid(&tmpid, &idm(rp)[Q_GRP]);
00434               }
00435               if (!gotmatch)
00436                      return(0);
00437        }
00438        if (rp->qflg & FL(Q_OBJ)) {
00439               if (!objname[0])
00440                      return(0);
00441               tmpid.number = 0;
00442               tmpid.name = objname;
00443               if (!matchid(&tmpid, &idm(rp)[Q_OBJ]))
00444                      return(0);
00445        }
00446        if (rp->qflg & FL(Q_FAC)) {
00447               tmpid.name = NULL;
00448               tmpid.number = faceno;
00449               if (!matchid(&tmpid, &idm(rp)[Q_FAC]))
00450                      return(0);
00451        }
00452        return(1);
00453 }
00454 
00455 
00456 int
00457 cvtndx(                            /* convert vertex string to index */
00458        register VNDX vi,
00459        register char *vs
00460 )
00461 {
00462                                    /* get point */
00463        vi[0] = atoi(vs);
00464        if (vi[0] > 0) {
00465               if (vi[0]-- > nvs)
00466                      return(0);
00467        } else if (vi[0] < 0) {
00468               vi[0] += nvs;
00469               if (vi[0] < 0)
00470                      return(0);
00471        } else
00472               return(0);
00473                                    /* get map */
00474        while (*vs)
00475               if (*vs++ == '/')
00476                      break;
00477        vi[1] = atoi(vs);
00478        if (vi[1] > 0) {
00479               if (vi[1]-- > nvts)
00480                      return(0);
00481        } else if (vi[1] < 0) {
00482               vi[1] += nvts;
00483               if (vi[1] < 0)
00484                      return(0);
00485        } else
00486               vi[1] = -1;
00487                                    /* get normal */
00488        while (*vs)
00489               if (*vs++ == '/')
00490                      break;
00491        vi[2] = atoi(vs);
00492        if (vi[2] > 0) {
00493               if (vi[2]-- > nvns)
00494                      return(0);
00495        } else if (vi[2] < 0) {
00496               vi[2] += nvns;
00497               if (vi[2] < 0)
00498                      return(0);
00499        } else
00500               vi[2] = -1;
00501        return(1);
00502 }
00503 
00504 
00505 int
00506 nonplanar(                  /* are vertices non-planar? */
00507        register int  ac,
00508        register char **av
00509 )
00510 {
00511        VNDX   vi;
00512        RREAL  *p0, *p1;
00513        FVECT  v1, v2, nsum, newn;
00514        double d;
00515        register int  i;
00516 
00517        if (!cvtndx(vi, av[0]))
00518               return(0);
00519        if (!flatten && vi[2] >= 0)
00520               return(1);           /* has interpolated normals */
00521        if (ac < 4)
00522               return(0);           /* it's a triangle! */
00523                                    /* set up */
00524        p0 = vlist[vi[0]];
00525        if (!cvtndx(vi, av[1]))
00526               return(0);           /* error gets caught later */
00527        nsum[0] = nsum[1] = nsum[2] = 0.;
00528        p1 = vlist[vi[0]];
00529        fvsum(v2, p1, p0, -1.0);
00530        for (i = 2; i < ac; i++) {
00531               VCOPY(v1, v2);
00532               if (!cvtndx(vi, av[i]))
00533                      return(0);
00534               p1 = vlist[vi[0]];
00535               fvsum(v2, p1, p0, -1.0);
00536               fcross(newn, v1, v2);
00537               if (normalize(newn) == 0.0) {
00538                      if (i < 3)
00539                             return(1);    /* can't deal with this */
00540                      fvsum(nsum, nsum, nsum, 1./(i-2));
00541                      continue;
00542               }
00543               d = fdot(newn,nsum);
00544               if (d >= 0) {
00545                      if (d < (1.0-FTINY)*(i-2))
00546                             return(1);
00547                      fvsum(nsum, nsum, newn, 1.0);
00548               } else {
00549                      if (d > -(1.0-FTINY)*(i-2))
00550                             return(1);
00551                      fvsum(nsum, nsum, newn, -1.0);
00552               }
00553        }
00554        return(0);
00555 }
00556 
00557 
00558 int
00559 putface(                           /* put out an N-sided polygon */
00560        int    ac,
00561        register char **av
00562 )
00563 {
00564        VNDX   vi;
00565        char   *cp;
00566        register int  i;
00567 
00568        if (nonplanar(ac, av)) {    /* break into triangles */
00569               while (ac > 2) {
00570                      if (!puttri(av[0], av[1], av[2]))
00571                             return(0);
00572                      ac--;         /* remove vertex & rotate */
00573                      cp = av[0];
00574                      for (i = 0; i < ac-1; i++)
00575                             av[i] = av[i+2];
00576                      av[i] = cp;
00577               }
00578               return(1);
00579        }
00580        if ((cp = getmtl()) == NULL)
00581               return(0);
00582        printf("\n%s polygon %s.%d\n", cp, getonm(), faceno);
00583        printf("0\n0\n%d\n", 3*ac);
00584        for (i = 0; i < ac; i++) {
00585               if (!cvtndx(vi, av[i]))
00586                      return(0);
00587               pvect(vlist[vi[0]]);
00588        }
00589        return(1);
00590 }
00591 
00592 
00593 int
00594 puttri(                     /* put out a triangle */
00595        char *v1,
00596        char *v2,
00597        char *v3
00598 )
00599 {
00600        char   *mod;
00601        VNDX   v1i, v2i, v3i;
00602        BARYCCM       bvecs;
00603        RREAL  bcoor[3][3];
00604        int    texOK = 0, patOK;
00605        int    flatness;
00606        register int  i;
00607 
00608        if ((mod = getmtl()) == NULL)
00609               return(0);
00610 
00611        if (!cvtndx(v1i, v1) || !cvtndx(v2i, v2) || !cvtndx(v3i, v3))
00612               return(0);
00613                                    /* compute barycentric coordinates */
00614        if (v1i[2]>=0 && v2i[2]>=0 && v3i[2]>=0)
00615               flatness = flat_tri(vlist[v1i[0]], vlist[v2i[0]], vlist[v3i[0]],
00616                             vnlist[v1i[2]], vnlist[v2i[2]], vnlist[v3i[2]]);
00617        else
00618               flatness = ISFLAT;
00619 
00620        switch (flatness) {
00621        case DEGEN:                 /* zero area */
00622               ndegen++;
00623               return(-1);
00624        case RVFLAT:                /* reversed normals, but flat */
00625        case ISFLAT:                /* smoothing unnecessary */
00626               texOK = 0;
00627               break;
00628        case RVBENT:                /* reversed normals with smoothing */
00629        case ISBENT:                /* proper smoothing */
00630               texOK = 1;
00631               break;
00632        }
00633        if (flatten)
00634               texOK = 0;
00635 #ifdef TEXMAPS
00636        patOK = mapname[0] && (v1i[1]>=0 && v2i[1]>=0 && v3i[1]>=0);
00637 #else
00638        patOK = 0;
00639 #endif
00640        if (texOK | patOK)
00641               if (comp_baryc(&bvecs, vlist[v1i[0]], vlist[v2i[0]],
00642                             vlist[v3i[0]]) < 0)
00643                      texOK = patOK = 0;
00644                                    /* put out texture (if any) */
00645        if (texOK) {
00646               printf("\n%s texfunc %s\n", mod, TEXNAME);
00647               mod = TEXNAME;
00648               printf("4 dx dy dz %s\n", TCALNAME);
00649               printf("0\n");
00650               for (i = 0; i < 3; i++) {
00651                      bcoor[i][0] = vnlist[v1i[2]][i];
00652                      bcoor[i][1] = vnlist[v2i[2]][i];
00653                      bcoor[i][2] = vnlist[v3i[2]][i];
00654               }
00655               put_baryc(&bvecs, bcoor, 3);
00656        }
00657 #ifdef TEXMAPS
00658                                    /* put out pattern (if any) */
00659        if (patOK) {
00660               printf("\n%s colorpict %s\n", mod, PATNAME);
00661               mod = PATNAME;
00662               printf("7 noneg noneg noneg %s %s u v\n", mapname, TCALNAME);
00663               printf("0\n");
00664               for (i = 0; i < 2; i++) {
00665                      bcoor[i][0] = vtlist[v1i[1]][i];
00666                      bcoor[i][1] = vtlist[v2i[1]][i];
00667                      bcoor[i][2] = vtlist[v3i[1]][i];
00668               }
00669               put_baryc(&bvecs, bcoor, 2);
00670        }
00671 #endif
00672                                    /* put out (reversed) triangle */
00673        printf("\n%s polygon %s.%d\n", mod, getonm(), faceno);
00674        printf("0\n0\n9\n");
00675        if (flatness == RVFLAT || flatness == RVBENT) {
00676               pvect(vlist[v3i[0]]);
00677               pvect(vlist[v2i[0]]);
00678               pvect(vlist[v1i[0]]);
00679        } else {
00680               pvect(vlist[v1i[0]]);
00681               pvect(vlist[v2i[0]]);
00682               pvect(vlist[v3i[0]]);
00683        }
00684        return(1);
00685 }
00686 
00687 
00688 void
00689 freeverts(void)                    /* free all vertices */
00690 {
00691        if (nvs) {
00692               free((void *)vlist);
00693               nvs = 0;
00694        }
00695        if (nvts) {
00696               free((void *)vtlist);
00697               nvts = 0;
00698        }
00699        if (nvns) {
00700               free((void *)vnlist);
00701               nvns = 0;
00702        }
00703 }
00704 
00705 
00706 int
00707 newv(                /* create a new vertex */
00708        double x,
00709        double y,
00710        double z
00711 )
00712 {
00713        if (!(nvs%CHUNKSIZ)) {             /* allocate next block */
00714               if (nvs == 0)
00715                      vlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
00716               else
00717                      vlist = (FVECT *)realloc((void *)vlist,
00718                                    (nvs+CHUNKSIZ)*sizeof(FVECT));
00719               if (vlist == NULL) {
00720                      fprintf(stderr,
00721                      "Out of memory while allocating vertex %d\n", nvs);
00722                      exit(1);
00723               }
00724        }
00725                                    /* assign new vertex */
00726        vlist[nvs][0] = x;
00727        vlist[nvs][1] = y;
00728        vlist[nvs][2] = z;
00729        return(++nvs);
00730 }
00731 
00732 
00733 int
00734 newvn(               /* create a new vertex normal */
00735        double x,
00736        double y,
00737        double z
00738 )
00739 {
00740        if (!(nvns%CHUNKSIZ)) {            /* allocate next block */
00741               if (nvns == 0)
00742                      vnlist = (FVECT *)malloc(CHUNKSIZ*sizeof(FVECT));
00743               else
00744                      vnlist = (FVECT *)realloc((void *)vnlist,
00745                                    (nvns+CHUNKSIZ)*sizeof(FVECT));
00746               if (vnlist == NULL) {
00747                      fprintf(stderr,
00748                      "Out of memory while allocating normal %d\n", nvns);
00749                      exit(1);
00750               }
00751        }
00752                                    /* assign new normal */
00753        vnlist[nvns][0] = x;
00754        vnlist[nvns][1] = y;
00755        vnlist[nvns][2] = z;
00756        if (normalize(vnlist[nvns]) == 0.0)
00757               return(0);
00758        return(++nvns);
00759 }
00760 
00761 
00762 int
00763 newvt(               /* create a new texture map vertex */
00764        double x,
00765        double y
00766 )
00767 {
00768        if (!(nvts%CHUNKSIZ)) {            /* allocate next block */
00769               if (nvts == 0)
00770                      vtlist = (RREAL (*)[2])malloc(CHUNKSIZ*2*sizeof(RREAL));
00771               else
00772                      vtlist = (RREAL (*)[2])realloc((void *)vtlist,
00773                                    (nvts+CHUNKSIZ)*2*sizeof(RREAL));
00774               if (vtlist == NULL) {
00775                      fprintf(stderr,
00776                      "Out of memory while allocating texture vertex %d\n",
00777                                    nvts);
00778                      exit(1);
00779               }
00780        }
00781                                    /* assign new vertex */
00782        vtlist[nvts][0] = x;
00783        vtlist[nvts][1] = y;
00784        return(++nvts);
00785 }
00786 
00787 
00788 void
00789 syntax(                     /* report syntax error and exit */
00790        char   *er
00791 )
00792 {
00793        fprintf(stderr, "%s: Wavefront syntax error near line %d: %s\n",
00794                      inpfile, lineno, er);
00795        exit(1);
00796 }