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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: readwfobj.c,v 2.2 2020/04/23 03:19:48 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 /* 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 addVertex(sc, atof(argv[1]),
234 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 addTexture(sc, atof(argv[1]), atof(argv[2]));
243 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 if (addNormal(sc, atof(argv[1]),
252 atof(argv[2]),
253 atof(argv[3])) < 0) {
254 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 setMaterial(sc, argv[1]);
280 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 setGroup(sc, group_name(argc-1, argv+1));
288 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 }