ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/readwfobj.c
Revision: 2.4
Committed: Sat May 2 00:12:45 2020 UTC (4 years ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.3: +16 -38 lines
Log Message:
Made addFace() into a public routine as well, so tools can add geometry

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.4 static const char RCSid[] = "$Id: readwfobj.c,v 2.3 2020/05/01 18:55:34 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     #define MAXARG 512 /* maximum # arguments in a statement */
20    
21     static int lineno; /* current line number */
22    
23     /* read the next statement from fp */
24     static int
25     get_stmt(char *av[MAXARG], FILE *fp)
26     {
27     static char sbuf[MAXARG*16];
28     register char *cp;
29     register int i;
30    
31     do {
32     if (fgetline(cp=sbuf, sizeof(sbuf), fp) == NULL)
33     return(0);
34     i = 0;
35     for ( ; ; ) {
36     while (isspace(*cp) || *cp == '\\') {
37     if (*cp == '\n')
38     lineno++;
39     *cp++ = '\0';
40     }
41     if (!*cp)
42     break;
43     if (i >= MAXARG-1) {
44     sprintf(errmsg,
45     "Too many arguments near line %d (limit %d)",
46     lineno+1, MAXARG-1);
47     error(WARNING, errmsg);
48     break;
49     }
50     av[i++] = cp;
51     while (*++cp && !isspace(*cp))
52     ;
53     }
54     av[i] = NULL;
55     lineno++;
56     } while (!i);
57    
58     return(i);
59     }
60    
61     /* convert vertex string to index */
62     static int
63     cvtndx(VNDX vi, const Scene *sc, const VNDX ondx, const char *vs)
64     {
65     /* get point */
66     vi[0] = atoi(vs);
67     if (vi[0] > 0) {
68     if ((vi[0] += ondx[0] - 1) >= sc->nverts)
69     return(0);
70     } else if (vi[0] < 0) {
71     vi[0] += sc->nverts;
72     if (vi[0] < 0)
73     return(0);
74     } else
75     return(0);
76     /* get map coord. */
77     while (*vs)
78     if (*vs++ == '/')
79     break;
80     vi[1] = atoi(vs);
81     if (vi[1] > 0) {
82     if ((vi[1] += ondx[1] - 1) >= sc->ntex)
83     return(0);
84     } else if (vi[1] < 0) {
85     vi[1] += sc->ntex;
86     if (vi[1] < 0)
87     return(0);
88     } else
89     vi[1] = -1;
90     /* get normal */
91     while (*vs)
92     if (*vs++ == '/')
93     break;
94     vi[2] = atoi(vs);
95     if (vi[2] > 0) {
96     if ((vi[2] += ondx[2] - 1) >= sc->nnorms)
97     return(0);
98     } else if (vi[2] < 0) {
99     vi[2] += sc->nnorms;
100     if (vi[2] < 0)
101     return(0);
102     } else
103     vi[2] = -1;
104     return(1);
105     }
106    
107     /* report syntax error */
108     static void
109     syntax(const char *fn, const char *er)
110     {
111     sprintf(errmsg, "%s: Wavefront syntax error near line %d: %s",
112     fn, lineno, er);
113     error(USER, errmsg);
114     }
115    
116     /* combine multi-group name into single identifier w/o spaces */
117     static char *
118     group_name(int ac, char **av)
119     {
120     static char nambuf[256];
121     char *cp;
122     if (ac < 1)
123     return("NO_NAME");
124     if (ac == 1)
125     return(av[0]);
126     for (cp = nambuf; ac--; av++) {
127     strcpy(cp, *av);
128     while (*cp) {
129     /* XXX white space disallowed by current get_stmt()
130     if (isspace(*cp))
131     *cp = '_';
132     else
133     */
134     if (*cp == '.')
135     *cp = '_';
136     ++cp;
137     }
138     *cp++ = '.';
139     }
140     *--cp = '\0';
141     return(nambuf);
142     }
143    
144 greg 2.4 /* add a new face to scene */
145 greg 2.1 static int
146     add_face(Scene *sc, const VNDX ondx, int ac, char *av[])
147     {
148 greg 2.4 VNDX vdef[4];
149     VNDX *varr = vdef;
150     Face *f = NULL;
151 greg 2.1 int i;
152    
153 greg 2.4 if (ac < 3) /* legal polygon? */
154 greg 2.1 return(0);
155 greg 2.4 if (ac > 4) /* need to allocate array? */
156     varr = (VNDX *)emalloc(ac*sizeof(VNDX));
157     for (i = ac; i--; ) /* index each vertex */
158     if (!cvtndx(varr[i], sc, ondx, av[i]))
159     break;
160     if (i < 0) /* create face if indices OK */
161     f = addFace(sc, varr, ac);
162     if (varr != vdef)
163     efree((char *)varr);
164     return(f != NULL);
165 greg 2.1 }
166    
167     /* Load a .OBJ file */
168     Scene *
169     loadOBJ(Scene *sc, const char *fspec)
170     {
171     FILE *fp;
172     char *argv[MAXARG];
173     int argc;
174     char buf[256];
175     int nstats=0, nunknown=0;
176     int onfaces;
177     VNDX ondx;
178    
179     if (fspec == NULL) {
180     fp = stdin;
181     fspec = "<stdin>";
182     #if POPEN_SUPPORT
183     } else if (fspec[0] == '!') {
184     if ((fp = popen(fspec+1, "r")) == NULL) {
185     sprintf(errmsg, "%s: cannot execute", fspec);
186     error(SYSTEM, errmsg);
187     return(NULL);
188     }
189     #endif
190     } else if ((fp = fopen(fspec, "r")) == NULL) {
191     sprintf(errmsg, "%s: cannot open for reading", fspec);
192     error(SYSTEM, errmsg);
193     return(NULL);
194     }
195     if (sc == NULL)
196     sc = newScene();
197     lineno = 0;
198     onfaces = sc->nfaces;
199     ondx[0] = sc->nverts;
200     ondx[1] = sc->ntex;
201     ondx[2] = sc->nnorms;
202     while ((argc = get_stmt(argv, fp)) > 0) {
203     switch (argv[0][0]) {
204     case 'v': /* vertex */
205     switch (argv[0][1]) {
206     case '\0': /* point */
207     if (badarg(argc-1,argv+1,"fff")) {
208     syntax(fspec, "bad vertex");
209     goto failure;
210     }
211 greg 2.3 addVertex(sc, atof(argv[1]),
212 greg 2.1 atof(argv[2]),
213     atof(argv[3]));
214     break;
215     case 't': /* texture coord. */
216     if (argv[0][2])
217     goto unknown;
218     if (badarg(argc-1,argv+1,"ff"))
219     goto unknown;
220 greg 2.3 addTexture(sc, atof(argv[1]), atof(argv[2]));
221 greg 2.1 break;
222     case 'n': /* normal */
223     if (argv[0][2])
224     goto unknown;
225     if (badarg(argc-1,argv+1,"fff")) {
226     syntax(fspec, "bad normal");
227     goto failure;
228     }
229 greg 2.3 if (addNormal(sc, atof(argv[1]),
230 greg 2.1 atof(argv[2]),
231 greg 2.3 atof(argv[3])) < 0) {
232 greg 2.1 syntax(fspec, "zero normal");
233     goto failure;
234     }
235     break;
236     default:
237     goto unknown;
238     }
239     break;
240     case 'f': /* face */
241     if (argv[0][1])
242     goto unknown;
243     if (!add_face(sc, ondx, argc-1, argv+1)) {
244     syntax(fspec, "bad face");
245     goto failure;
246     }
247     break;
248     case 'u': /* usemtl/usemap */
249     if (!strcmp(argv[0], "usemap"))
250     break;
251     if (strcmp(argv[0], "usemtl"))
252     goto unknown;
253     if (argc != 2) {
254     syntax(fspec, "bad # arguments");
255     goto failure;
256     }
257 greg 2.3 setMaterial(sc, argv[1]);
258 greg 2.1 break;
259     case 'o': /* object name */
260     case 'g': /* group name */
261     if (argc < 2) {
262     syntax(fspec, "missing argument");
263     goto failure;
264     }
265 greg 2.3 setGroup(sc, group_name(argc-1, argv+1));
266 greg 2.1 break;
267     case '#': /* comment */
268     continue;
269     default:; /* something we don't deal with */
270     unknown:
271     nunknown++;
272     break;
273     }
274     nstats++;
275     if (verbose && !(nstats & 0x3fff))
276     fprintf(stderr, " %8d statements\r", nstats);
277     }
278     #if POPEN_SUPPORT
279     if (fspec[0] == '!')
280     pclose(fp);
281     else
282     #endif
283     if (fp != stdin)
284     fclose(fp);
285     sprintf(buf, "%d statements read from \"%s\"", nstats, fspec);
286     addComment(sc, buf);
287     if (nunknown) {
288     sprintf(buf, "\t%d unrecognized", nunknown);
289     addComment(sc, buf);
290     }
291     sprintf(buf, "%d faces", sc->nfaces - onfaces);
292     addComment(sc, buf);
293     sprintf(buf, "\t%d vertices, %d texture coordinates, %d surface normals",
294     sc->nverts - ondx[0],
295     sc->ntex - ondx[1],
296     sc->nnorms - ondx[2]);
297     addComment(sc, buf);
298     return(sc);
299     failure:
300     #if POPEN_SUPPORT
301     if (fspec[0] == '!')
302     pclose(fp);
303     else
304     #endif
305     if (fp != stdin)
306     fclose(fp);
307     freeScene(sc);
308     return(NULL);
309     }