first pass at the obj loader
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 18 Jun 2021 05:15:14 +0000 (08:15 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 18 Jun 2021 05:15:14 +0000 (08:15 +0300)
src/level.c
src/level.h
src/main.c
src/mesh.c
src/mesh.h

index 4d1e30e..f13c486 100644 (file)
@@ -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;
 }
index b5385a7..a2579b2 100644 (file)
@@ -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_ */
index 7ce59cb..28a9d3e 100644 (file)
@@ -3,6 +3,7 @@
 #include <assert.h>
 #include <GL/glut.h>
 #include <cgmath/cgmath.h>
+#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);
 }
index a84b347..0e2218f 100644 (file)
@@ -1,7 +1,13 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <ctype.h>
+#include <cgmath/cgmath.h>
 #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; i<num; i++) {
+                               if(i % 3 == 0) {
+                                       tri = m->faces + 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; i<m->num_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();
 }
index b97f9cd..4a51837 100644 (file)
@@ -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_ */