ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/readwfobj.c
Revision: 2.10
Committed: Tue Feb 7 20:28:16 2023 UTC (15 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, HEAD
Changes since 2.9: +8 -1 lines
Log Message:
perf: added calls to flockfile()/funlockfile() for more efficient reading

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.10 static const char RCSid[] = "$Id: readwfobj.c,v 2.9 2022/01/15 02:00:21 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 greg 2.9 efree(varr);
164 greg 2.4 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 greg 2.8 char buf[1024];
175 greg 2.1 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 greg 2.10 #ifdef getc_unlocked /* avoid stupid semaphores */
196     flockfile(fp);
197     #endif
198 greg 2.1 if (sc == NULL)
199     sc = newScene();
200     lineno = 0;
201     onfaces = sc->nfaces;
202     ondx[0] = sc->nverts;
203     ondx[1] = sc->ntex;
204     ondx[2] = sc->nnorms;
205     while ((argc = get_stmt(argv, fp)) > 0) {
206     switch (argv[0][0]) {
207     case 'v': /* vertex */
208     switch (argv[0][1]) {
209     case '\0': /* point */
210     if (badarg(argc-1,argv+1,"fff")) {
211     syntax(fspec, "bad vertex");
212     goto failure;
213     }
214 greg 2.3 addVertex(sc, atof(argv[1]),
215 greg 2.1 atof(argv[2]),
216     atof(argv[3]));
217     break;
218     case 't': /* texture coord. */
219     if (argv[0][2])
220     goto unknown;
221     if (badarg(argc-1,argv+1,"ff"))
222     goto unknown;
223 greg 2.3 addTexture(sc, atof(argv[1]), atof(argv[2]));
224 greg 2.1 break;
225     case 'n': /* normal */
226     if (argv[0][2])
227     goto unknown;
228     if (badarg(argc-1,argv+1,"fff")) {
229     syntax(fspec, "bad normal");
230     goto failure;
231     }
232 greg 2.3 if (addNormal(sc, atof(argv[1]),
233 greg 2.1 atof(argv[2]),
234 greg 2.3 atof(argv[3])) < 0) {
235 greg 2.1 syntax(fspec, "zero normal");
236     goto failure;
237     }
238     break;
239     default:
240     goto unknown;
241     }
242     break;
243     case 'f': /* face */
244     if (argv[0][1])
245     goto unknown;
246     if (!add_face(sc, ondx, argc-1, argv+1)) {
247     syntax(fspec, "bad face");
248     goto failure;
249     }
250     break;
251     case 'u': /* usemtl/usemap */
252     if (!strcmp(argv[0], "usemap"))
253     break;
254     if (strcmp(argv[0], "usemtl"))
255     goto unknown;
256     if (argc != 2) {
257     syntax(fspec, "bad # arguments");
258     goto failure;
259     }
260 greg 2.3 setMaterial(sc, argv[1]);
261 greg 2.1 break;
262     case 'o': /* object name */
263     case 'g': /* group name */
264     if (argc < 2) {
265     syntax(fspec, "missing argument");
266     goto failure;
267     }
268 greg 2.3 setGroup(sc, group_name(argc-1, argv+1));
269 greg 2.1 break;
270     case '#': /* comment */
271     continue;
272     default:; /* something we don't deal with */
273     unknown:
274     nunknown++;
275     break;
276     }
277     nstats++;
278     if (verbose && !(nstats & 0x3fff))
279     fprintf(stderr, " %8d statements\r", nstats);
280     }
281     #if POPEN_SUPPORT
282 greg 2.6 if (fspec[0] == '!') {
283     if (pclose(fp) != 0) {
284     sprintf(errmsg, "Bad return status from: %s", fspec+1);
285     error(USER, errmsg);
286     freeScene(sc);
287     return(NULL);
288     }
289 greg 2.5 } else
290 greg 2.1 #endif
291     if (fp != stdin)
292     fclose(fp);
293 greg 2.10 #ifdef getc_unlocked
294     else
295     funlockfile(fp);
296     #endif
297 greg 2.7 if (verbose)
298     fprintf(stderr, "Read %d statements\n", nstats);
299 greg 2.8 if (strlen(fspec) < sizeof(buf)-32)
300     sprintf(buf, "%d statements read from \"%s\"", nstats, fspec);
301     else
302     sprintf(buf, "%d statements read from (TOO LONG TO SHOW)", nstats);
303 greg 2.1 addComment(sc, buf);
304     if (nunknown) {
305     sprintf(buf, "\t%d unrecognized", nunknown);
306     addComment(sc, buf);
307     }
308     sprintf(buf, "%d faces", sc->nfaces - onfaces);
309     addComment(sc, buf);
310     sprintf(buf, "\t%d vertices, %d texture coordinates, %d surface normals",
311     sc->nverts - ondx[0],
312     sc->ntex - ondx[1],
313     sc->nnorms - ondx[2]);
314     addComment(sc, buf);
315     return(sc);
316     failure:
317     #if POPEN_SUPPORT
318     if (fspec[0] == '!')
319     pclose(fp);
320     else
321     #endif
322     if (fp != stdin)
323     fclose(fp);
324     freeScene(sc);
325     return(NULL);
326     }