ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/readwfobj.c
Revision: 2.2
Committed: Thu Apr 23 03:19:48 2020 UTC (4 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.1: +2 -2 lines
Log Message:
Fix for missing popen() in Windows

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.2 static const char RCSid[] = "$Id: readwfobj.c,v 2.1 2020/03/30 18:28:35 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * readobj.c
6     *
7     * Routines for reading a Wavefront .OBJ file
8     *
9     * Created by Greg Ward on Wed Feb 11 2004.
10     */
11    
12     #include "rtio.h"
13     #include "rterror.h"
14     #include "fvect.h"
15 greg 2.2 #include "paths.h"
16 greg 2.1 #include <ctype.h>
17     #include "objutil.h"
18    
19     typedef int VNDX[3]; /* vertex index (point,map,normal) */
20    
21     #define MAXARG 512 /* maximum # arguments in a statement */
22    
23     static int lineno; /* current line number */
24    
25     /* read the next statement from fp */
26     static int
27     get_stmt(char *av[MAXARG], FILE *fp)
28     {
29     static char sbuf[MAXARG*16];
30     register char *cp;
31     register int i;
32    
33     do {
34     if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL)
35     return(0);
36     i = 0;
37     for ( ; ; ) {
38     while (isspace(*cp) || *cp == '\\') {
39     if (*cp == '\n')
40     lineno++;
41     *cp++ = '\0';
42     }
43     if (!*cp)
44     break;
45     if (i >= MAXARG-1) {
46     sprintf(errmsg,
47     "Too many arguments near line %d (limit %d)",
48     lineno+1, MAXARG-1);
49     error(WARNING, errmsg);
50     break;
51     }
52     av[i++] = cp;
53     while (*++cp && !isspace(*cp))
54     ;
55     }
56     av[i] = NULL;
57     lineno++;
58     } while (!i);
59    
60     return(i);
61     }
62    
63     /* convert vertex string to index */
64     static int
65     cvtndx(VNDX vi, const Scene *sc, const VNDX ondx, const char *vs)
66     {
67     /* get point */
68     vi[0] = atoi(vs);
69     if (vi[0] > 0) {
70     if ((vi[0] += ondx[0] - 1) >= sc->nverts)
71     return(0);
72     } else if (vi[0] < 0) {
73     vi[0] += sc->nverts;
74     if (vi[0] < 0)
75     return(0);
76     } else
77     return(0);
78     /* get map coord. */
79     while (*vs)
80     if (*vs++ == '/')
81     break;
82     vi[1] = atoi(vs);
83     if (vi[1] > 0) {
84     if ((vi[1] += ondx[1] - 1) >= sc->ntex)
85     return(0);
86     } else if (vi[1] < 0) {
87     vi[1] += sc->ntex;
88     if (vi[1] < 0)
89     return(0);
90     } else
91     vi[1] = -1;
92     /* get normal */
93     while (*vs)
94     if (*vs++ == '/')
95     break;
96     vi[2] = atoi(vs);
97     if (vi[2] > 0) {
98     if ((vi[2] += ondx[2] - 1) >= sc->nnorms)
99     return(0);
100     } else if (vi[2] < 0) {
101     vi[2] += sc->nnorms;
102     if (vi[2] < 0)
103     return(0);
104     } else
105     vi[2] = -1;
106     return(1);
107     }
108    
109     /* report syntax error */
110     static void
111     syntax(const char *fn, const char *er)
112     {
113     sprintf(errmsg, "%s: Wavefront syntax error near line %d: %s",
114     fn, lineno, er);
115     error(USER, errmsg);
116     }
117    
118     /* Add a vertex to our scene */
119     static void
120     add_vertex(Scene *sc, double x, double y, double z)
121     {
122     sc->vert = chunk_alloc(Vertex, sc->vert, sc->nverts);
123     sc->vert[sc->nverts].p[0] = x;
124     sc->vert[sc->nverts].p[1] = y;
125     sc->vert[sc->nverts].p[2] = z;
126     sc->vert[sc->nverts++].vflist = NULL;
127     }
128    
129     /* Add a texture coordinate to our scene */
130     static void
131     add_texture(Scene *sc, double u, double v)
132     {
133     sc->tex = chunk_alloc(TexCoord, sc->tex, sc->ntex);
134     sc->tex[sc->ntex].u = u;
135     sc->tex[sc->ntex].v = v;
136     sc->ntex++;
137     }
138    
139     /* Add a surface normal to our scene */
140     static int
141     add_normal(Scene *sc, double xn, double yn, double zn)
142     {
143     FVECT nrm;
144    
145     nrm[0] = xn; nrm[1] = yn; nrm[2] = zn;
146     if (normalize(nrm) == .0)
147     return(0);
148     sc->norm = chunk_alloc(Normal, sc->norm, sc->nnorms);
149     VCOPY(sc->norm[sc->nnorms], nrm);
150     sc->nnorms++;
151     return(1);
152     }
153    
154     /* combine multi-group name into single identifier w/o spaces */
155     static char *
156     group_name(int ac, char **av)
157     {
158     static char nambuf[256];
159     char *cp;
160     if (ac < 1)
161     return("NO_NAME");
162     if (ac == 1)
163     return(av[0]);
164     for (cp = nambuf; ac--; av++) {
165     strcpy(cp, *av);
166     while (*cp) {
167     /* XXX white space disallowed by current get_stmt()
168     if (isspace(*cp))
169     *cp = '_';
170     else
171     */
172     if (*cp == '.')
173     *cp = '_';
174     ++cp;
175     }
176     *cp++ = '.';
177     }
178     *--cp = '\0';
179     return(nambuf);
180     }
181    
182     /* set current group */
183     static void
184     set_group(Scene *sc, const char *nm)
185     {
186     sc->lastgrp = findName(nm, (const char **)sc->grpname, sc->ngrps);
187     if (sc->lastgrp >= 0)
188     return;
189     sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps);
190     sc->grpname[sc->lastgrp=sc->ngrps++] = savqstr((char *)nm);
191     }
192    
193     /* set current material */
194     static void
195     set_material(Scene *sc, const char *nm)
196     {
197     sc->lastmat = findName(nm, (const char **)sc->matname, sc->nmats);
198     if (sc->lastmat >= 0)
199     return;
200     sc->matname = chunk_alloc(char *, sc->matname, sc->nmats);
201     sc->matname[sc->lastmat=sc->nmats++] = savqstr((char *)nm);
202     }
203    
204     /* Add a new face to scene */
205     static int
206     add_face(Scene *sc, const VNDX ondx, int ac, char *av[])
207     {
208     Face *f;
209     int i;
210    
211     if (ac < 3)
212     return(0);
213     f = (Face *)emalloc(sizeof(Face)+sizeof(VertEnt)*(ac-3));
214     f->flags = 0;
215     f->nv = ac;
216     f->grp = sc->lastgrp;
217     f->mat = sc->lastmat;
218     for (i = 0; i < ac; i++) { /* add each vertex */
219     VNDX vin;
220     int j;
221     if (!cvtndx(vin, sc, ondx, av[i])) {
222     efree((char *)f);
223     return(0);
224     }
225     f->v[i].vid = vin[0];
226     f->v[i].tid = vin[1];
227     f->v[i].nid = vin[2];
228     f->v[i].fnext = NULL;
229     for (j = i; j-- > 0; )
230     if (f->v[j].vid == vin[0])
231     break;
232     if (j < 0) { /* first occurrence? */
233     f->v[i].fnext = sc->vert[vin[0]].vflist;
234     sc->vert[vin[0]].vflist = f;
235     } else if (ac == 3) /* degenerate triangle? */
236     f->flags |= FACE_DEGENERATE;
237     }
238     f->next = sc->flist; /* push onto face list */
239     sc->flist = f;
240     sc->nfaces++;
241     /* check face area */
242     if (!(f->flags & FACE_DEGENERATE) && faceArea(sc, f, NULL) <= FTINY)
243     f->flags |= FACE_DEGENERATE;
244     return(1);
245     }
246    
247     /* Load a .OBJ file */
248     Scene *
249     loadOBJ(Scene *sc, const char *fspec)
250     {
251     FILE *fp;
252     char *argv[MAXARG];
253     int argc;
254     char buf[256];
255     int nstats=0, nunknown=0;
256     int onfaces;
257     VNDX ondx;
258    
259     if (fspec == NULL) {
260     fp = stdin;
261     fspec = "<stdin>";
262     #if POPEN_SUPPORT
263     } else if (fspec[0] == '!') {
264     if ((fp = popen(fspec+1, "r")) == NULL) {
265     sprintf(errmsg, "%s: cannot execute", fspec);
266     error(SYSTEM, errmsg);
267     return(NULL);
268     }
269     #endif
270     } else if ((fp = fopen(fspec, "r")) == NULL) {
271     sprintf(errmsg, "%s: cannot open for reading", fspec);
272     error(SYSTEM, errmsg);
273     return(NULL);
274     }
275     if (sc == NULL)
276     sc = newScene();
277     lineno = 0;
278     onfaces = sc->nfaces;
279     ondx[0] = sc->nverts;
280     ondx[1] = sc->ntex;
281     ondx[2] = sc->nnorms;
282     while ((argc = get_stmt(argv, fp)) > 0) {
283     switch (argv[0][0]) {
284     case 'v': /* vertex */
285     switch (argv[0][1]) {
286     case '\0': /* point */
287     if (badarg(argc-1,argv+1,"fff")) {
288     syntax(fspec, "bad vertex");
289     goto failure;
290     }
291     add_vertex(sc, atof(argv[1]),
292     atof(argv[2]),
293     atof(argv[3]));
294     break;
295     case 't': /* texture coord. */
296     if (argv[0][2])
297     goto unknown;
298     if (badarg(argc-1,argv+1,"ff"))
299     goto unknown;
300     add_texture(sc, atof(argv[1]), atof(argv[2]));
301     break;
302     case 'n': /* normal */
303     if (argv[0][2])
304     goto unknown;
305     if (badarg(argc-1,argv+1,"fff")) {
306     syntax(fspec, "bad normal");
307     goto failure;
308     }
309     if (!add_normal(sc, atof(argv[1]),
310     atof(argv[2]),
311     atof(argv[3]))) {
312     syntax(fspec, "zero normal");
313     goto failure;
314     }
315     break;
316     default:
317     goto unknown;
318     }
319     break;
320     case 'f': /* face */
321     if (argv[0][1])
322     goto unknown;
323     if (!add_face(sc, ondx, argc-1, argv+1)) {
324     syntax(fspec, "bad face");
325     goto failure;
326     }
327     break;
328     case 'u': /* usemtl/usemap */
329     if (!strcmp(argv[0], "usemap"))
330     break;
331     if (strcmp(argv[0], "usemtl"))
332     goto unknown;
333     if (argc != 2) {
334     syntax(fspec, "bad # arguments");
335     goto failure;
336     }
337     set_material(sc, argv[1]);
338     break;
339     case 'o': /* object name */
340     case 'g': /* group name */
341     if (argc < 2) {
342     syntax(fspec, "missing argument");
343     goto failure;
344     }
345     set_group(sc, group_name(argc-1, argv+1));
346     break;
347     case '#': /* comment */
348     continue;
349     default:; /* something we don't deal with */
350     unknown:
351     nunknown++;
352     break;
353     }
354     nstats++;
355     if (verbose && !(nstats & 0x3fff))
356     fprintf(stderr, " %8d statements\r", nstats);
357     }
358     #if POPEN_SUPPORT
359     if (fspec[0] == '!')
360     pclose(fp);
361     else
362     #endif
363     if (fp != stdin)
364     fclose(fp);
365     sprintf(buf, "%d statements read from \"%s\"", nstats, fspec);
366     addComment(sc, buf);
367     if (nunknown) {
368     sprintf(buf, "\t%d unrecognized", nunknown);
369     addComment(sc, buf);
370     }
371     sprintf(buf, "%d faces", sc->nfaces - onfaces);
372     addComment(sc, buf);
373     sprintf(buf, "\t%d vertices, %d texture coordinates, %d surface normals",
374     sc->nverts - ondx[0],
375     sc->ntex - ondx[1],
376     sc->nnorms - ondx[2]);
377     addComment(sc, buf);
378     return(sc);
379     failure:
380     #if POPEN_SUPPORT
381     if (fspec[0] == '!')
382     pclose(fp);
383     else
384     #endif
385     if (fp != stdin)
386     fclose(fp);
387     freeScene(sc);
388     return(NULL);
389     }