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 (3 years, 11 months 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: readwfobj.c,v 2.3 2020/05/01 18:55:34 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 #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 /* add a new face to scene */
145 static int
146 add_face(Scene *sc, const VNDX ondx, int ac, char *av[])
147 {
148 VNDX vdef[4];
149 VNDX *varr = vdef;
150 Face *f = NULL;
151 int i;
152
153 if (ac < 3) /* legal polygon? */
154 return(0);
155 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 }
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 addVertex(sc, atof(argv[1]),
212 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 addTexture(sc, atof(argv[1]), atof(argv[2]));
221 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 if (addNormal(sc, atof(argv[1]),
230 atof(argv[2]),
231 atof(argv[3])) < 0) {
232 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 setMaterial(sc, argv[1]);
258 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 setGroup(sc, group_name(argc-1, argv+1));
266 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 }