From c608ee9a7df130c64f195fd1e9af1f145cad207d Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 18 Jun 2021 08:15:14 +0300 Subject: [PATCH] first pass at the obj loader --- src/level.c | 4 +- src/level.h | 2 +- src/main.c | 14 +++++- src/mesh.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- src/mesh.h | 1 + 5 files changed, 158 insertions(+), 25 deletions(-) diff --git a/src/level.c b/src/level.c index 4d1e30e..f13c486 100644 --- a/src/level.c +++ b/src/level.c @@ -4,8 +4,10 @@ int load_level(struct level *lvl, const char *fname) { + return -1; } -int ray_level(cgm_ray *ray, struct level *lvl, float maxt, struct hitpoint *hit) +int ray_level(cgm_ray *ray, struct level *lvl, float tmax, struct rayhit *hit) { + return 0; } diff --git a/src/level.h b/src/level.h index b5385a7..a2579b2 100644 --- a/src/level.h +++ b/src/level.h @@ -13,6 +13,6 @@ struct level { int load_level(struct level *lvl, const char *fname); -int ray_level(cgm_ray *ray, struct level *lvl, float maxt, struct hitpoint *hit); +int ray_level(cgm_ray *ray, struct level *lvl, float tmax, struct rayhit *hit); #endif /* LEVEL_H_ */ diff --git a/src/main.c b/src/main.c index 7ce59cb..28a9d3e 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include #include #include +#include "mesh.h" enum { KEY_F1 = GLUT_KEY_F1 | 0x100, @@ -46,7 +47,7 @@ static void motion(int x, int y); static long start_time; static float cam_theta, cam_phi; -static cgm_vec3 cam_pos; +static cgm_vec3 cam_pos = {0, -1.6, 0}; static float pxform[16]; static int mouse_x, mouse_y; @@ -62,6 +63,8 @@ static int keymap[NUM_INPUTS][2] = { {' ', 0} }; +static struct mesh mesh; + int main(int argc, char **argv) { glutInit(&argc, argv); @@ -97,15 +100,20 @@ static int init(void) glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + if(load_mesh(&mesh, "data/testlvl.obj") == -1) { + return -1; + } + start_time = glutGet(GLUT_ELAPSED_TIME); return 0; } static void cleanup(void) { + destroy_mesh(&mesh); } -#define WALK_SPEED 1.0f +#define WALK_SPEED 3.0f static void update(void) { static unsigned int prev_upd; @@ -153,6 +161,8 @@ static void display(void) glutSolidTeapot(1.0); glFrontFace(GL_CCW); + draw_mesh(&mesh); + glutSwapBuffers(); assert(glGetError() == GL_NO_ERROR); } diff --git a/src/mesh.c b/src/mesh.c index a84b347..0e2218f 100644 --- a/src/mesh.c +++ b/src/mesh.c @@ -1,7 +1,13 @@ #include #include +#include +#include #include "mesh.h" +struct facevertex { + int vidx, tidx, nidx; +}; + static char *cleanline(char *s) { char *ptr; @@ -15,6 +21,48 @@ static char *cleanline(char *s) return *s ? s : 0; } +static char *parse_idx(char *ptr, int *idx, int arrsz) +{ + char *endp; + int val = strtol(ptr, &endp, 10); + if(endp == ptr) return 0; + + if(val < 0) { /* convert negative indices */ + *idx = arrsz + val; + } else { + *idx = val - 1; /* indices in obj are 1-based */ + } + return endp; +} + +/* possible face-vertex definitions: + * 1. vertex + * 2. vertex/texcoord + * 3. vertex//normal + * 4. vertex/texcoord/normal + */ +static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn) +{ + if(!(ptr = parse_idx(ptr, &fv->vidx, numv))) + return 0; + if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0; + + if(*++ptr == '/') { /* no texcoord */ + fv->tidx = -1; + ++ptr; + } else { + if(!(ptr = parse_idx(ptr, &fv->tidx, numt))) + return 0; + if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0; + ++ptr; + } + + if(!(ptr = parse_idx(ptr, &fv->nidx, numn))) + return 0; + return (!*ptr || isspace(*ptr)) ? ptr : 0; +} + + #define APPEND(prefix) \ do { \ if(prefix##count >= prefix##max) { \ @@ -32,16 +80,24 @@ static char *cleanline(char *s) int load_mesh(struct mesh *m, const char *fname) { - int num, nline; + int i, num, nline, sidx, didx, res = -1; FILE *fp; - cgm_vec3 v; + cgm_vec3 v, va, vb, fnorm; cgm_vec3 *varr, *narr, *tarr; - int vcount, ncount, tcount, vmax, nmax, tmax; - char linebuf[256], *line; + int vcount, ncount, tcount, vmax, nmax, tmax, max_faces, newsz; + char linebuf[256], *line, *ptr; + struct facevertex fv[4]; + struct triangle *tri; + void *tmpptr; + static const int quadidx[] = { 0, 1, 2, 0, 1, 3 }; varr = narr = tarr = 0; vcount = ncount = tcount = vmax = nmax = tmax = 0; + m->faces = 0; + m->num_faces = 0; + max_faces = 0; + if(!(fp = fopen(fname, "rb"))) { fprintf(stderr, "load_mesh: failed to open: %s\n", fname); return -1; @@ -57,47 +113,111 @@ int load_mesh(struct mesh *m, const char *fname) switch(line[0]) { case 'v': v.y = v.z = 0; - if((num = sscanf(line + 1, "%f %f %f", &v.x, &v.y, &v.z)) < 2) { + if((num = sscanf(line + 2, "%f %f %f", &v.x, &v.y, &v.z)) < 2) { verr: fprintf(stderr, "load_mesh: ignoring malformed attribute at %d: %s\n", nline, line); continue; } if(isspace(line[1])) { APPEND(v); varr[vcount++] = v; - } else if(line[1] == 'n') { + } else if(line[1] == 'n' && isspace(line[2])) { APPEND(n); narr[ncount++] = v; - } else if(line[1] == 't') { + } else if(line[1] == 't' && isspace(line[2])) { APPEND(t); - tarr[ncount].x = v.x; - tarr[ncount++].y = v.y; + tarr[tcount].x = v.x; + tarr[tcount++].y = v.y; } else { goto verr; } break; - /* TODO cont */ + case 'f': + if(!isspace(line[1])) { + break; + } + ptr = line + 2; + for(i=0; i<4; i++) { + fv[i].nidx = fv[i].tidx = -1; + if(!(ptr = parse_face_vert(ptr, fv + i, vcount, tcount, ncount))) { + break; + } + } + + if(i < 2) { + fprintf(stderr, "load_mesh: invalid face definition at %d: %s\n", nline, line); + break; + } + + va = varr[fv[1].vidx]; + cgm_vsub(&va, varr + fv[0].vidx); + vb = varr[fv[2].vidx]; + cgm_vsub(&vb, varr + fv[0].vidx); + cgm_vcross(&fnorm, &va, &vb); + cgm_vnormalize(&fnorm); + + if(m->num_faces >= max_faces - 1) { + newsz = max_faces ? max_faces * 2 : 16; + if(!(tmpptr = realloc(m->faces, newsz * sizeof *m->faces))) { + fprintf(stderr, "load_mesh: failed to resize faces array to %d\n", newsz); + goto end; + } + m->faces = tmpptr; + max_faces = newsz; + } + + num = i > 3 ? 6 : 3; + for(i=0; ifaces + m->num_faces++; + tri->norm = fnorm; + tri->mtl = &m->mtl; + } + sidx = quadidx[i]; + didx = i >= 3 ? i - 3 : i; + tri->v[didx].pos = varr[fv[sidx].vidx]; + tri->v[didx].norm = fv[sidx].nidx >= 0 ? varr[fv[sidx].nidx] : fnorm; + if(fv[sidx].tidx >= 0) { + tri->v[didx].tex.x = tarr[fv[sidx].tidx].x; + tri->v[didx].tex.y = tarr[fv[sidx].tidx].y; + } else { + tri->v[didx].tex.x = tri->v[sidx].tex.y = 0; + } + } + break; } } + res = 0; +end: + free(varr); + free(narr); + free(tarr); fclose(fp); - return 0; + return res; +} + +void destroy_mesh(struct mesh *m) +{ + free(m->faces); + m->faces = 0; } void draw_mesh(struct mesh *m) { - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + int i; - glVertexPointer(3, GL_FLOAT, sizeof *m->faces, &m->faces->v[0].pos.x); - glNormalPointer(GL_FLOAT, sizeof *m->faces, &m->faces->v[0].norm.x); - glTexCoordPointer(2, GL_FLOAT, sizeof *m->faces, &m->faces->v[0].tex.x); + glBegin(GL_TRIANGLES); + for(i=0; inum_faces; i++) { + glNormal3fv(&m->faces[i].v[0].norm); + glVertex3fv(&m->faces[i].v[0].pos); - glDrawArrays(GL_TRIANGLES, 0, m->num_faces * 3); + glNormal3fv(&m->faces[i].v[1].norm); + glVertex3fv(&m->faces[i].v[1].pos); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glNormal3fv(&m->faces[i].v[2].norm); + glVertex3fv(&m->faces[i].v[2].pos); + } + glEnd(); } diff --git a/src/mesh.h b/src/mesh.h index b97f9cd..4a51837 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -15,6 +15,7 @@ struct mesh { }; int load_mesh(struct mesh *m, const char *fname); +void destroy_mesh(struct mesh *m); void draw_mesh(struct mesh *m); #endif /* MESH_H_ */ -- 1.7.10.4