4 #include <cgmath/cgmath.h>
11 static char *cleanline(char *s)
15 if((ptr = strchr(s, '#'))) *ptr = 0;
17 while(*s && isspace(*s)) s++;
18 ptr = s + strlen(s) - 1;
19 while(ptr >= s && isspace(*s)) *ptr-- = 0;
24 static char *parse_idx(char *ptr, int *idx, int arrsz)
27 int val = strtol(ptr, &endp, 10);
28 if(endp == ptr) return 0;
30 if(val < 0) { /* convert negative indices */
33 *idx = val - 1; /* indices in obj are 1-based */
38 /* possible face-vertex definitions:
42 * 4. vertex/texcoord/normal
44 static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn)
46 if(!(ptr = parse_idx(ptr, &fv->vidx, numv)))
48 if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
50 if(*++ptr == '/') { /* no texcoord */
54 if(!(ptr = parse_idx(ptr, &fv->tidx, numt)))
56 if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
60 if(!(ptr = parse_idx(ptr, &fv->nidx, numn)))
62 return (!*ptr || isspace(*ptr)) ? ptr : 0;
66 #define APPEND(prefix) \
68 if(prefix##count >= prefix##max) { \
69 int newsz = prefix##max ? prefix##max * 2 : 8; \
70 void *ptr = realloc(prefix##arr, newsz * sizeof(cgm_vec3)); \
72 fprintf(stderr, "load_mesh: failed to resize array to %d elements\n", newsz); \
76 prefix##max = newsz; \
81 int load_mesh(struct mesh *m, const char *fname)
83 int i, num, nline, sidx, didx, res = -1;
85 cgm_vec3 v, va, vb, fnorm;
86 cgm_vec3 *varr, *narr, *tarr;
87 int vcount, ncount, tcount, vmax, nmax, tmax, max_faces, newsz;
88 char linebuf[256], *line, *ptr;
89 struct facevertex fv[4];
92 static const int quadidx[] = { 0, 1, 2, 0, 1, 3 };
94 varr = narr = tarr = 0;
95 vcount = ncount = tcount = vmax = nmax = tmax = 0;
101 if(!(fp = fopen(fname, "rb"))) {
102 fprintf(stderr, "load_mesh: failed to open: %s\n", fname);
107 while(fgets(linebuf, sizeof linebuf, fp)) {
109 if(!(line = cleanline(linebuf))) {
116 if((num = sscanf(line + 2, "%f %f %f", &v.x, &v.y, &v.z)) < 2) {
117 verr: fprintf(stderr, "load_mesh: ignoring malformed attribute at %d: %s\n", nline, line);
120 if(isspace(line[1])) {
123 } else if(line[1] == 'n' && isspace(line[2])) {
126 } else if(line[1] == 't' && isspace(line[2])) {
128 tarr[tcount].x = v.x;
129 tarr[tcount++].y = v.y;
136 if(!isspace(line[1])) {
141 fv[i].nidx = fv[i].tidx = -1;
142 if(!(ptr = parse_face_vert(ptr, fv + i, vcount, tcount, ncount))) {
148 fprintf(stderr, "load_mesh: invalid face definition at %d: %s\n", nline, line);
152 va = varr[fv[1].vidx];
153 cgm_vsub(&va, varr + fv[0].vidx);
154 vb = varr[fv[2].vidx];
155 cgm_vsub(&vb, varr + fv[0].vidx);
156 cgm_vcross(&fnorm, &va, &vb);
157 cgm_vnormalize(&fnorm);
159 if(m->num_faces >= max_faces - 1) {
160 newsz = max_faces ? max_faces * 2 : 16;
161 if(!(tmpptr = realloc(m->faces, newsz * sizeof *m->faces))) {
162 fprintf(stderr, "load_mesh: failed to resize faces array to %d\n", newsz);
170 for(i=0; i<num; i++) {
172 tri = m->faces + m->num_faces++;
177 didx = i >= 3 ? i - 3 : i;
178 tri->v[didx].pos = varr[fv[sidx].vidx];
179 tri->v[didx].norm = fv[sidx].nidx >= 0 ? varr[fv[sidx].nidx] : fnorm;
180 if(fv[sidx].tidx >= 0) {
181 tri->v[didx].tex.x = tarr[fv[sidx].tidx].x;
182 tri->v[didx].tex.y = tarr[fv[sidx].tidx].y;
184 tri->v[didx].tex.x = tri->v[sidx].tex.y = 0;
201 void destroy_mesh(struct mesh *m)
207 void draw_mesh(struct mesh *m)
211 glBegin(GL_TRIANGLES);
212 for(i=0; i<m->num_faces; i++) {
213 glNormal3fv(&m->faces[i].v[0].norm);
214 glVertex3fv(&m->faces[i].v[0].pos);
216 glNormal3fv(&m->faces[i].v[1].norm);
217 glVertex3fv(&m->faces[i].v[1].pos);
219 glNormal3fv(&m->faces[i].v[2].norm);
220 glVertex3fv(&m->faces[i].v[2].pos);