ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/readwfobj.c
Revision: 2.3
Committed: Fri May 1 18:55:34 2020 UTC (4 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.2: +7 -65 lines
Log Message:
Made some useful routines public from readwfobj.c

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.3 static const char RCSid[] = "$Id: readwfobj.c,v 2.2 2020/04/23 03:19:48 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     /* combine multi-group name into single identifier w/o spaces */
119     static char *
120     group_name(int ac, char **av)
121     {
122     static char nambuf[256];
123     char *cp;
124     if (ac < 1)
125     return("NO_NAME");
126     if (ac == 1)
127     return(av[0]);
128     for (cp = nambuf; ac--; av++) {
129     strcpy(cp, *av);
130     while (*cp) {
131     /* XXX white space disallowed by current get_stmt()
132     if (isspace(*cp))
133     *cp = '_';
134     else
135     */
136     if (*cp == '.')
137     *cp = '_';
138     ++cp;
139     }
140     *cp++ = '.';
141     }
142     *--cp = '\0';
143     return(nambuf);
144     }
145    
146     /* Add a new face to scene */
147     static int
148     add_face(Scene *sc, const VNDX ondx, int ac, char *av[])
149     {
150     Face *f;
151     int i;
152    
153     if (ac < 3)
154     return(0);
155     f = (Face *)emalloc(sizeof(Face)+sizeof(VertEnt)*(ac-3));
156     f->flags = 0;
157     f->nv = ac;
158     f->grp = sc->lastgrp;
159     f->mat = sc->lastmat;
160     for (i = 0; i < ac; i++) { /* add each vertex */
161     VNDX vin;
162     int j;
163     if (!cvtndx(vin, sc, ondx, av[i])) {
164     efree((char *)f);
165     return(0);
166     }
167     f->v[i].vid = vin[0];
168     f->v[i].tid = vin[1];
169     f->v[i].nid = vin[2];
170     f->v[i].fnext = NULL;
171     for (j = i; j-- > 0; )
172     if (f->v[j].vid == vin[0])
173     break;
174     if (j < 0) { /* first occurrence? */
175     f->v[i].fnext = sc->vert[vin[0]].vflist;
176     sc->vert[vin[0]].vflist = f;
177     } else if (ac == 3) /* degenerate triangle? */
178     f->flags |= FACE_DEGENERATE;
179     }
180     f->next = sc->flist; /* push onto face list */
181     sc->flist = f;
182     sc->nfaces++;
183     /* check face area */
184     if (!(f->flags & FACE_DEGENERATE) && faceArea(sc, f, NULL) <= FTINY)
185     f->flags |= FACE_DEGENERATE;
186     return(1);
187     }
188    
189     /* Load a .OBJ file */
190     Scene *
191     loadOBJ(Scene *sc, const char *fspec)
192     {
193     FILE *fp;
194     char *argv[MAXARG];
195     int argc;
196     char buf[256];
197     int nstats=0, nunknown=0;
198     int onfaces;
199     VNDX ondx;
200    
201     if (fspec == NULL) {
202     fp = stdin;
203     fspec = "<stdin>";
204     #if POPEN_SUPPORT
205     } else if (fspec[0] == '!') {
206     if ((fp = popen(fspec+1, "r")) == NULL) {
207     sprintf(errmsg, "%s: cannot execute", fspec);
208     error(SYSTEM, errmsg);
209     return(NULL);
210     }
211     #endif
212     } else if ((fp = fopen(fspec, "r")) == NULL) {
213     sprintf(errmsg, "%s: cannot open for reading", fspec);
214     error(SYSTEM, errmsg);
215     return(NULL);
216     }
217     if (sc == NULL)
218     sc = newScene();
219     lineno = 0;
220     onfaces = sc->nfaces;
221     ondx[0] = sc->nverts;
222     ondx[1] = sc->ntex;
223     ondx[2] = sc->nnorms;
224     while ((argc = get_stmt(argv, fp)) > 0) {
225     switch (argv[0][0]) {
226     case 'v': /* vertex */
227     switch (argv[0][1]) {
228     case '\0': /* point */
229     if (badarg(argc-1,argv+1,"fff")) {
230     syntax(fspec, "bad vertex");
231     goto failure;
232     }
233 greg 2.3 addVertex(sc, atof(argv[1]),
234 greg 2.1 atof(argv[2]),
235     atof(argv[3]));
236     break;
237     case 't': /* texture coord. */
238     if (argv[0][2])
239     goto unknown;
240     if (badarg(argc-1,argv+1,"ff"))
241     goto unknown;
242 greg 2.3 addTexture(sc, atof(argv[1]), atof(argv[2]));
243 greg 2.1 break;
244     case 'n': /* normal */
245     if (argv[0][2])
246     goto unknown;
247     if (badarg(argc-1,argv+1,"fff")) {
248     syntax(fspec, "bad normal");
249     goto failure;
250     }
251 greg 2.3 if (addNormal(sc, atof(argv[1]),
252 greg 2.1 atof(argv[2]),
253 greg 2.3 atof(argv[3])) < 0) {
254 greg 2.1 syntax(fspec, "zero normal");
255     goto failure;
256     }
257     break;
258     default:
259     goto unknown;
260     }
261     break;
262     case 'f': /* face */
263     if (argv[0][1])
264     goto unknown;
265     if (!add_face(sc, ondx, argc-1, argv+1)) {
266     syntax(fspec, "bad face");
267     goto failure;
268     }
269     break;
270     case 'u': /* usemtl/usemap */
271     if (!strcmp(argv[0], "usemap"))
272     break;
273     if (strcmp(argv[0], "usemtl"))
274     goto unknown;
275     if (argc != 2) {
276     syntax(fspec, "bad # arguments");
277     goto failure;
278     }
279 greg 2.3 setMaterial(sc, argv[1]);
280 greg 2.1 break;
281     case 'o': /* object name */
282     case 'g': /* group name */
283     if (argc < 2) {
284     syntax(fspec, "missing argument");
285     goto failure;
286     }
287 greg 2.3 setGroup(sc, group_name(argc-1, argv+1));
288 greg 2.1 break;
289     case '#': /* comment */
290     continue;
291     default:; /* something we don't deal with */
292     unknown:
293     nunknown++;
294     break;
295     }
296     nstats++;
297     if (verbose && !(nstats & 0x3fff))
298     fprintf(stderr, " %8d statements\r", nstats);
299     }
300     #if POPEN_SUPPORT
301     if (fspec[0] == '!')
302     pclose(fp);
303     else
304     #endif
305     if (fp != stdin)
306     fclose(fp);
307     sprintf(buf, "%d statements read from \"%s\"", nstats, fspec);
308     addComment(sc, buf);
309     if (nunknown) {
310     sprintf(buf, "\t%d unrecognized", nunknown);
311     addComment(sc, buf);
312     }
313     sprintf(buf, "%d faces", sc->nfaces - onfaces);
314     addComment(sc, buf);
315     sprintf(buf, "\t%d vertices, %d texture coordinates, %d surface normals",
316     sc->nverts - ondx[0],
317     sc->ntex - ondx[1],
318     sc->nnorms - ondx[2]);
319     addComment(sc, buf);
320     return(sc);
321     failure:
322     #if POPEN_SUPPORT
323     if (fspec[0] == '!')
324     pclose(fp);
325     else
326     #endif
327     if (fp != stdin)
328     fclose(fp);
329     freeScene(sc);
330     return(NULL);
331     }