diff options
-rw-r--r-- | math3d.c | 3 | ||||
-rw-r--r-- | math3d.h | 6 | ||||
-rw-r--r-- | obj.c | 206 | ||||
-rw-r--r-- | obj.h | 47 | ||||
-rw-r--r-- | objloader.c | 73 |
5 files changed, 211 insertions, 124 deletions
@@ -1,3 +1,6 @@ +#include <GL/glew.h> +#include <stdio.h> +#include <stdlib.h> #include "math3d.h" void m3dFindNormal(M3DVector3f result, const M3DVector3f point1, @@ -1,12 +1,8 @@ #ifndef _MATH3D_H_ #define _MATH3D_H_ -#include <GL/glew.h> -#include <GL/freeglut.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <math.h> +#include <string.h> #define M3D_PI (3.14159265358979323846) #define M3D_PI_DIV_180 (0.017453292519943296) @@ -12,6 +12,7 @@ * */ +#include <GL/glew.h> #include <stdlib.h> #include <stdio.h> #include <memory.h> @@ -19,18 +20,24 @@ ObjModel* ObjLoadModel(char *memory, size_t size) { - char *p = NULL, *e = NULL; - ObjModel *ret = (ObjModel *) calloc(1, sizeof(ObjModel)); - /* initialize to zero */ - memset(ret, 0, sizeof(ObjModel)); - /* if size is 0, meaning file was not loaded correctly, return null */ if (!size) - return ret; + return NULL; + char *p = NULL, *e = NULL; + ObjModel *ret = (ObjModel *) malloc(sizeof(ObjModel)); + if (!ret) + { + fprintf(stderr, "ObjLoadModel() failed, %s:%d\n", __FILE__, __LINE__); + perror("malloc"); + exit(-1); + } + + /* initialize to zero */ + memset(ret, 0, sizeof(ObjModel)); p = memory; e = memory + size; - + /* count the number of normals, texcoords, vertices, and faces, line by line */ while (p != e) { @@ -39,87 +46,114 @@ ObjModel* ObjLoadModel(char *memory, size_t size) else if (memcmp(p, "v", 1) == 0) ret->nVertex++; else if (memcmp(p, "f", 1) == 0) ret->nFace++; - while (*p++ != (char) 0x0a); + /* seek to new line */ + while (*p++ != (char) 0x0a) + ; } /* allocate memory for arrays */ ret->VertexArray = (ObjVertex *) malloc(sizeof(ObjVertex) * ret->nVertex); ret->NormalArray = (ObjNormal *) malloc(sizeof(ObjNormal) * ret->nNormal); ret->TexCoordArray = (ObjTexCoord *) malloc(sizeof(ObjTexCoord) * ret->nTexCoord); - ret->FaceArray = (ObjFace *) malloc(sizeof(ObjFace) * ret->nFace); - ret->mtllib = (char *) malloc(sizeof(char) * 21); - ret->objectName = (char *) malloc(sizeof(char) * 21); - ret->usemtl = (char *) malloc(sizeof(char) * 21); + ret->FaceArray = (ObjFace *) malloc(sizeof(ObjFace) * ret->nFace); + ret->mtllib = (char *) malloc(sizeof(char) * 21); + ret->objectName = (char *) malloc(sizeof(char) * 21); + ret->usemtl = (char *) malloc(sizeof(char) * 21); + + *ret->mtllib = '\0'; + *ret->objectName = '\0'; + *ret->usemtl = '\0'; + + if (!ret->VertexArray || !ret->NormalArray || !ret->TexCoordArray || + !ret->FaceArray || !ret->mtllib || !ret->objectName || !ret->usemtl) + { + fprintf(stderr, "ObjLoadModel() failed, %s:%d\n", __FILE__, __LINE__); + perror("malloc"); + exit(-1); + } + +#if 0 /* already done by memset */ memset(ret->mtllib, 0, 21); memset(ret->objectName, 0, 21); memset(ret->usemtl, 0, 21); +#endif p = memory; - - int nV = 0, nN = 0, nT = 0, nF = 0; - int nread = 0; - + + unsigned int nV = 0, nN = 0, nT = 0, nF = 0; + unsigned int nread = 0; + while (p != e) { /* check for mtl file */ if (memcmp(p, "mtllib", 6) == 0) sscanf(p, "mtllib %s", ret->mtllib); - /* check if mtl file will be used*/ + /* check if mtl file will be used */ if (memcmp(p, "usemtl", 6) == 0) sscanf(p, "usemtl %s", ret->usemtl); if (memcmp(p, "g", 1) == 0) sscanf(p, "g %s", ret->objectName); - + + /* parse a normal */ if (memcmp(p, "vn", 2) == 0) { nread = sscanf(p, "vn %f %f %f", &ret->NormalArray[nN].x, - &ret->NormalArray[nN].y, - &ret->NormalArray[nN].z); + &ret->NormalArray[nN].y, + &ret->NormalArray[nN].z); if (nread != 3) printf("vn: read only %d instead of 3\n", nread); + nN++; } + /* parse a texture coordinates */ else if (memcmp(p, "vt", 2) == 0) { nread = sscanf(p, "vt %f %f", &ret->TexCoordArray[nT].u, - &ret->TexCoordArray[nT].v); + &ret->TexCoordArray[nT].v); if (nread != 2) - printf("vt: read only %d instead of 2\n", nread); + printf("vt: read only %d instead of 2\n", nread); + nT++; } + /* parse a vertex */ else if (memcmp(p, "v", 1) == 0) /* or *p == 'v' */ { nread = sscanf(p, "v %f %f %f", &ret->VertexArray[nV].x, - &ret->VertexArray[nV].y, - &ret->VertexArray[nV].z); + &ret->VertexArray[nV].y, + &ret->VertexArray[nV].z); if (nread != 3) printf("v: read only %d instead of 3\n", nread); + nV++; } /* quad */ else if (memcmp(p, "f", 1) == 0) /* or *p == 'f' */ { nread = sscanf(p, "f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", - &ret->FaceArray[nF].Vertex[0], - &ret->FaceArray[nF].TexCoord[0], - &ret->FaceArray[nF].Normal[0], - &ret->FaceArray[nF].Vertex[1], - &ret->FaceArray[nF].TexCoord[1], - &ret->FaceArray[nF].Normal[1], - &ret->FaceArray[nF].Vertex[2], - &ret->FaceArray[nF].TexCoord[2], - &ret->FaceArray[nF].Normal[2], - &ret->FaceArray[nF].Vertex[3], - &ret->FaceArray[nF].TexCoord[3], - &ret->FaceArray[nF].Normal[3]); + &ret->FaceArray[nF].Vertex[0], + &ret->FaceArray[nF].TexCoord[0], + &ret->FaceArray[nF].Normal[0], + &ret->FaceArray[nF].Vertex[1], + &ret->FaceArray[nF].TexCoord[1], + &ret->FaceArray[nF].Normal[1], + &ret->FaceArray[nF].Vertex[2], + &ret->FaceArray[nF].TexCoord[2], + &ret->FaceArray[nF].Normal[2], + &ret->FaceArray[nF].Vertex[3], + &ret->FaceArray[nF].TexCoord[3], + &ret->FaceArray[nF].Normal[3]); + if (nread != 12) - printf("f: read only %d instead of 12\n", nread); + printf("f: read only %d instead of 12\n", nread); + nF++; } + /* seek to a newline */ - while (*p++ != (char) 0x0a); + while (*p++ != (char) 0x0a) + ; } /* sanity check */ @@ -136,7 +170,7 @@ ObjModel* ObjLoadModel(char *memory, size_t size) if (ret->nFace != nF) fprintf(stdout, "faces: scanned %d, read %d\n", ret->nFace, nF); } - + /* load the mtl file */ if (ret->mtllib != NULL && ret->usemtl) { @@ -149,13 +183,27 @@ ObjModel* ObjLoadModel(char *memory, size_t size) if (mtl_bytes) { - ObjMtl *mtl = (ObjMtl *) calloc(1, sizeof(ObjMtl)); + ObjMtl *mtl = (ObjMtl *) malloc(sizeof(ObjMtl)); + if (!mtl) + { + fprintf(stderr, "ObjLoadModel() failed, %s:%d\n", __FILE__, __LINE__); + perror("malloc"); + exit(-1); + } + /* initialize to zero */ memset(mtl, 0, sizeof(ObjMtl)); /* allocate space for dynamic members */ mtl->map_Ka = (char *) malloc(sizeof(char) * 21); mtl->map_Kd = (char *) malloc(sizeof(char) * 21); + if (!mtl->map_Ka || !mtl->map_Kd) + { + fprintf(stderr, "ObjLoadModel() failed, %s:%d\n", __FILE__, __LINE__); + perror("malloc"); + exit(-1); + } + *mtl->map_Ka = '\0'; *mtl->map_Kd = '\0'; @@ -165,7 +213,8 @@ ObjModel* ObjLoadModel(char *memory, size_t size) while (st != ed) { /* skip spaces */ - while (*st++ == (char) 0x20); + while (*st++ == (char) 0x20) + ; if (memcmp(st, "Ns", 2) == 0) sscanf(st, "Ns %f", &mtl->Ns); @@ -204,16 +253,18 @@ ObjModel* ObjLoadModel(char *memory, size_t size) sscanf(st, "map_Kd %s", mtl->map_Kd); /* go to next line */ - while (*st++ != (char) 0x0a); + while (*st++ != (char) 0x0a) + ; } /* set the mtl */ ret->mtl = mtl; } else - ret->mtl = NULL; + ret->mtl = NULL; /* should already be NULL but what the hell */ - free(fname); - } + if (fname) + free(fname); + } return ret; } @@ -230,13 +281,16 @@ size_t ObjLoadFile(char *szFileName, char **memory) size_t end = ftell(file); fseek(file, 0, SEEK_SET); - *memory = (char *) malloc(end); + *memory = (char *) malloc(sizeof(char) * end); bytes = fread(*memory, sizeof(char), end, file); fclose(file); } else - perror("fopen"); + { + fprintf(stderr, "ObjLoadModel() failed, %s:%d\n", __FILE__, __LINE__); + perror("fopen"); + } return bytes; } @@ -259,7 +313,7 @@ void ObjList(ObjModel *model) for (i = 0; i < model->nTexCoord; i++) printf("v %f %f\n", model->TexCoordArray[i].u, model->TexCoordArray[i].v); - printf("%d faces\n", model->nFace); + printf("%d faces\n", model->nFace); for (i = 0; i < model->nFace; i++) { printf("f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d\n", @@ -283,7 +337,7 @@ char *ObjGetPath(char *fname) if (obj_last_fname == NULL) return NULL; - char *path = (char *) malloc(sizeof(char) * 31); + char *path = (char *) malloc(sizeof(char) * 101); char *delimeter = strrchr(obj_last_fname, '/'); unsigned int offset = delimeter - obj_last_fname; strncpy(path, obj_last_fname, offset + 1); @@ -292,8 +346,53 @@ char *ObjGetPath(char *fname) return path; } +void ObjPutFaceGLCmd(const ObjModel *model, const unsigned i) +{ + if (!model) + return; + + glNormal3f(model->NormalArray[model->FaceArray[i].Normal[0] - 1].x, + model->NormalArray[model->FaceArray[i].Normal[0] - 1].y, + model->NormalArray[model->FaceArray[i].Normal[0] - 1].z ); + glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[0] - 1].u, + model->TexCoordArray[model->FaceArray[i].TexCoord[0] - 1].v); + glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[0] - 1].x, + model->VertexArray[model->FaceArray[i].Vertex[0] - 1].y, + model->VertexArray[model->FaceArray[i].Vertex[0] - 1].z ); + + glNormal3f(model->NormalArray[model->FaceArray[i].Normal[1] - 1].x, + model->NormalArray[model->FaceArray[i].Normal[1] - 1].y, + model->NormalArray[model->FaceArray[i].Normal[1] - 1].z ); + glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[1] - 1].u, + model->TexCoordArray[model->FaceArray[i].TexCoord[1] - 1].v); + glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[1] - 1].x, + model->VertexArray[model->FaceArray[i].Vertex[1] - 1].y, + model->VertexArray[model->FaceArray[i].Vertex[1] - 1].z ); + + glNormal3f(model->NormalArray[model->FaceArray[i].Normal[2] - 1].x, + model->NormalArray[model->FaceArray[i].Normal[2] - 1].y, + model->NormalArray[model->FaceArray[i].Normal[2] - 1].z ); + glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[2] - 1].u, + model->TexCoordArray[model->FaceArray[i].TexCoord[2] - 1].v); + glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[2] - 1].x, + model->VertexArray[model->FaceArray[i].Vertex[2] - 1].y, + model->VertexArray[model->FaceArray[i].Vertex[2] - 1].z ); + + glNormal3f(model->NormalArray[model->FaceArray[i].Normal[3] - 1].x, + model->NormalArray[model->FaceArray[i].Normal[3] - 1].y, + model->NormalArray[model->FaceArray[i].Normal[3] - 1].z ); + glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[3] - 1].u, + model->TexCoordArray[model->FaceArray[i].TexCoord[3] - 1].v); + glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[3] - 1].x, + model->VertexArray[model->FaceArray[i].Vertex[3] - 1].y, + model->VertexArray[model->FaceArray[i].Vertex[3] - 1].z ); +} + void ObjFree(ObjModel *model) { + if (model == NULL) + return; + free(model->NormalArray); free(model->TexCoordArray); free(model->FaceArray); @@ -302,9 +401,12 @@ void ObjFree(ObjModel *model) free(model->objectName); free(model->usemtl); - free(model->mtl->map_Ka); - free(model->mtl->map_Kd); - free(model->mtl); + if (model->mtl) + { + free(model->mtl->map_Ka); + free(model->mtl->map_Kd); + free(model->mtl); + } free(model); } @@ -1,8 +1,7 @@ -#ifndef OBJ_H -#define OBJ_H +#ifndef _OBJLOADER_H_ +#define _OBJLOADER_H_ -/* external variables */ -char obj_last_fname[31]; +extern char obj_last_fname[101]; typedef struct { @@ -17,9 +16,9 @@ typedef struct typedef struct { - int Vertex[4]; - int Normal[4]; - int TexCoord[4]; + unsigned int Vertex[4]; + unsigned int Normal[4]; + unsigned int TexCoord[4]; } ObjFace; typedef struct @@ -28,8 +27,8 @@ typedef struct float Ni; float d; float Tr; - ObjVertex Tf; int illum; + ObjVertex Tf; ObjVertex Ka; ObjVertex Kd; ObjVertex Ks; @@ -44,13 +43,13 @@ typedef struct char *objectName; char *groupName; char *usemtl; - - ObjMtl *mtl; - int nVertex, nNormal, nTexCoord, nFace; - ObjVertex *VertexArray; - ObjNormal *NormalArray; + + ObjMtl *mtl; + ObjVertex *VertexArray; + ObjNormal *NormalArray; ObjTexCoord *TexCoordArray; - ObjFace *FaceArray; + ObjFace *FaceArray; + unsigned nVertex, nNormal, nTexCoord, nFace; } ObjModel; /* function prototypes */ @@ -58,14 +57,32 @@ ObjModel *ObjLoadModel(char *, size_t); /* read a file into argument 2, and return amount of bytes read */ size_t ObjLoadFile(char *, char **); - void ObjList(ObjModel *); /* once we load an .obj file, we can extract path up to last '/' to load a * mtl or texture that resides in the same folder */ char *ObjGetPath(char *); +void ObjPutFaceGLCmd(const ObjModel *, const unsigned); void ObjFree(ObjModel *); +static inline ObjNormal *ObjGetNormal(const ObjModel *model, const unsigned i, + const unsigned j) +{ + return &(model->NormalArray[model->FaceArray[i].Normal[j] - 1]); +} + +static inline ObjTexCoord *ObjGetTexCoord(const ObjModel *model, const unsigned i, + const unsigned j) +{ + return &(model->TexCoordArray[model->FaceArray[i].TexCoord[j] - 1]); +} + +static inline ObjVertex *ObjGetVertex(const ObjModel *model, const unsigned i, + const unsigned j) +{ + return &(model->VertexArray[model->FaceArray[i].Vertex[j] - 1]); +} + #endif diff --git a/objloader.c b/objloader.c index 63cf273..0e6aba9 100644 --- a/objloader.c +++ b/objloader.c @@ -15,6 +15,8 @@ #include <SDL/SDL.h> #include <SDL/SDL_image.h> +#include <GL/glew.h> +#include <GL/freeglut.h> #include "math3d.h" #include "obj.h" @@ -27,6 +29,7 @@ static void render(ObjModel *); /* global */ int program_running = 1; +char obj_last_fname[101]; static void resize(int w, int h) { @@ -45,7 +48,7 @@ static void resize(int w, int h) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - + /* this needs to be ran again, glut does it for you I suppose */ SDL_SetVideoMode(w, h, 32, SDL_OPENGL | SDL_RESIZABLE); } @@ -73,13 +76,13 @@ static void setup_opengl(ObjModel *model) /* enable color tracking */ glEnable(GL_COLOR_MATERIAL); - + /* set Material properties to follow glColor values */ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); /* gray background */ glClearColor(0.5f, 0.5f, 0.5f, 1.0f); - + /* example of loading a targa file, note: RLE compression is not supported */ GLbyte *pBytes; GLint iWidth, iHeight, iComponents; @@ -90,7 +93,7 @@ static void setup_opengl(ObjModel *model) if (model->mtl != NULL) { printf("ambient texture map: %s\n", model->mtl->map_Ka); - + /* load texture */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); pBytes = gltLoadTGA(fname, &iWidth, &iHeight, &iComponents, &eFormat); @@ -117,7 +120,7 @@ static void process_events(void) { SDL_Event event; SDLKey sym; - + while (SDL_PollEvent(&event)) { sym = event.key.keysym.sym; @@ -158,53 +161,19 @@ static void render(ObjModel *model) /* clear the window with current clearing color */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_ground(); - + glPushMatrix(); glScalef(0.1f, 0.1f, 0.1f); glTranslatef(5.0f, 0.0f, -150.0f); + glBegin(GL_QUADS); - int i; - for (i = 0; i < model->nFace; i++) - { - glNormal3f(model->NormalArray[model->FaceArray[i].Normal[0] - 1].x, - model->NormalArray[model->FaceArray[i].Normal[0] - 1].y, - model->NormalArray[model->FaceArray[i].Normal[0] - 1].z ); - glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[0] - 1].u, - model->TexCoordArray[model->FaceArray[i].TexCoord[0] - 1].v); - glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[0] - 1].x, - model->VertexArray[model->FaceArray[i].Vertex[0] - 1].y, - model->VertexArray[model->FaceArray[i].Vertex[0] - 1].z ); - - glNormal3f(model->NormalArray[model->FaceArray[i].Normal[1] - 1].x, - model->NormalArray[model->FaceArray[i].Normal[1] - 1].y, - model->NormalArray[model->FaceArray[i].Normal[1] - 1].z ); - glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[1] - 1].u, - model->TexCoordArray[model->FaceArray[i].TexCoord[1] - 1].v); - glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[1] - 1].x, - model->VertexArray[model->FaceArray[i].Vertex[1] - 1].y, - model->VertexArray[model->FaceArray[i].Vertex[1] - 1].z ); - - glNormal3f(model->NormalArray[model->FaceArray[i].Normal[2] - 1].x, - model->NormalArray[model->FaceArray[i].Normal[2] - 1].y, - model->NormalArray[model->FaceArray[i].Normal[2] - 1].z ); - glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[2] - 1].u, - model->TexCoordArray[model->FaceArray[i].TexCoord[2] - 1].v); - glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[2] - 1].x, - model->VertexArray[model->FaceArray[i].Vertex[2] - 1].y, - model->VertexArray[model->FaceArray[i].Vertex[2] - 1].z ); - - glNormal3f(model->NormalArray[model->FaceArray[i].Normal[3] - 1].x, - model->NormalArray[model->FaceArray[i].Normal[3] - 1].y, - model->NormalArray[model->FaceArray[i].Normal[3] - 1].z ); - glTexCoord2f(model->TexCoordArray[model->FaceArray[i].TexCoord[3] - 1].u, - model->TexCoordArray[model->FaceArray[i].TexCoord[3] - 1].v); - glVertex3f(model->VertexArray[model->FaceArray[i].Vertex[3] - 1].x, - model->VertexArray[model->FaceArray[i].Vertex[3] - 1].y, - model->VertexArray[model->FaceArray[i].Vertex[3] - 1].z ); - } + int i; + for (i = 0; i < model->nFace; i++) + ObjPutFaceGLCmd(model, i); glEnd(); + glPopMatrix(); - + /* buffer swap */ SDL_GL_SwapBuffers(); } @@ -227,13 +196,13 @@ int main(int argc, char **argv) SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - + if ((screen = SDL_SetVideoMode(640, 480, 32, SDL_OPENGL | SDL_RESIZABLE)) == NULL) { fprintf(stderr, "unable to set video mode: %s\n", SDL_GetError()); exit(-1); } - + SDL_EnableUNICODE(1); /* SDL doesn't trigger off a ResizeEvent at startup, but as we need this * for OpenGL, we do this ourselves */ @@ -242,7 +211,7 @@ int main(int argc, char **argv) resizeEvent.resize.w = 640; resizeEvent.resize.h = 480; SDL_PushEvent(&resizeEvent); - + /* initalize glew */ GLenum glewerr = glewInit(); if (GLEW_OK != glewerr) @@ -263,7 +232,7 @@ int main(int argc, char **argv) exit(-1); } - /* setup few stuff before rendring */ + /* setup few stuff before rendering */ setup_opengl(model); /* main loop */ @@ -272,11 +241,11 @@ int main(int argc, char **argv) process_events(); render(model); } - + /* free up the resources */ ObjFree(model); puts("bye!"); - + return 0; } |