#include <stdio.h> /* fopen() */
#include <string.h> /* strtok() */
#include <stdlib.h> /* malloc(), free() */
#include <GL/glut.h>
struct vector { float x; float y; float z; } *v, *vn;
struct vlist { struct vector v; struct vlist *n; } *v_l, *vn_l;
struct flist { int v; int vn; struct flist *n; } *f_l;
int v_n, vn_n, f_n;
float diffuse[] = {1., 1., 1., 1.};
float reflect[] = {.3, .3, .3, 1.};
void error(char *err, int status)
{
fprintf(stderr, "%s\n", err);
exit(status);
}
/** Functions to parse the .obj file **/
struct vlist **appendv(struct vlist **l, struct vector v)
{
*l = malloc(sizeof(struct vlist));
(*l)->v = v;
(*l)->n = NULL;
return &((*l)->n);
}
struct flist **appendf(struct flist **l, int v, int vn)
{
*l = malloc(sizeof(struct flist));
(*l)->v = v;
(*l)->vn = vn;
(*l)->n = NULL;
return &((*l)->n);
}
void get2ints(char *s, int *a, int *b)
{
sscanf(s, "%d", a);
while(*s != '/') s++; /* first '/' */
s++;
while(*s != '/') s++; /* second '/' */
s++;
sscanf(s, "%d", b);
}
void readobj(FILE *obj)
{
char buffer[256], *tok;
int v_, vn_, i;
struct vector vec;
struct vlist **lv = &v_l, **lvn = &vn_l;
struct flist **lf = &f_l;
v_n = 0; vn_n = 0; f_n = 0;
while (fgets(buffer, 255, obj))
{
tok = strtok(buffer, " \t");
if(!strcmp(tok, "v"))
{
tok = strtok(NULL, " \t");
sscanf(tok, "%f", &(vec.x));
tok = strtok(NULL, " \t");
sscanf(tok, "%f", &(vec.y));
tok = strtok(NULL, " \t");
sscanf(tok, "%f", &(vec.z));
lv = appendv(lv, vec);
v_n++;
}
else if(!strcmp(tok, "vn"))
{
tok = strtok(NULL, " \t");
sscanf(tok, "%f", &(vec.x));
tok = strtok(NULL, " \t");
sscanf(tok, "%f", &(vec.y));
tok = strtok(NULL, " \t");
sscanf(tok, "%f", &(vec.z));
lvn = appendv(lvn, vec);
vn_n++;
}
else if(!strcmp(tok, "f"))
{
for(i=0; i<4; i++)
{
tok = strtok(NULL, " \t");
if(tok) get2ints(tok, &v_, &vn_); /* else: use previous */
lf = appendf(lf, v_ - 1, vn_ - 1);
}
f_n += 4;
}
}
}
struct vector *listtoarray(struct vlist *l, int n)
{
struct vlist *ll;
int i;
struct vector *vec = malloc(n * sizeof(struct vector));
for(i=0; i<n; i++)
{
ll = l;
vec[i] = l->v;
l = l->n;
free(ll);
}
return vec;
}
/** Functions to render it **/
void init_gl(char *name)
{
int c = 0;
float sun[] = {-1., -.5, 3., 0.}; /* x,y,z,s */
float sun_color[] = {1., 1., .9, 1.}; /* R,G,B,a */
glutInit(&c, NULL);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(100,50);
glutInitWindowSize(800,600);
glutCreateWindow(name);
gluLookAt( 2., -5., 3., /* camera */
0., 0., 0., /* center */
0., 0., 1.); /* up dir */
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST); /* Z-Buffer on */
glClearDepth(1.0);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, sun);
glLightfv(GL_LIGHT0, GL_DIFFUSE, sun_color);
glEnable(GL_LIGHT0);
}
void redraw(void)
{
struct flist *lf = f_l;
struct vector vec_v, vec_vn;
glClearColor(0., 0., 0., 0.);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, 1.333, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, reflect);
glBegin(GL_QUADS);
while(lf)
{
vec_v = v [lf->v ];
vec_vn = vn[lf->vn];
glNormal3f(vec_vn.x, vec_vn.y, vec_vn.z);
glVertex3f(vec_v.x, vec_v.y, vec_v.z);
lf = lf->n;
}
glEnd();
/**/fprintf(stderr, "List rendered\n");
glutSwapBuffers();
glFlush();
}
/** Main function **/
int main(int argc, char** argv)
{
FILE *obj;
if(argc < 2) error("Usage: ./obj2ogl file.obj", 1);
if(!( obj = fopen(argv[1], "r") )) error("Unable to open file", 1);
obj = fopen(argv[1], "r");
readobj(obj);
/**/fprintf(stderr, "Parsed successfully\n");
v = listtoarray(v_l, v_n);
vn = listtoarray(vn_l, vn_n);
/**/fprintf(stderr, "Converted successfully\n");
init_gl(argv[1]);
/**/fprintf(stderr, "OpenGL ready\n");
glutDisplayFunc(redraw);
glutMainLoop();
return 0;
}