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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: readwfobj.c,v 2.1 2020/03/30 18:28:35 greg Exp $";
3 #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 #include "paths.h"
16 #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 }