src/Model.cpp

Go to the documentation of this file.
00001 /* Crown and Cutlass
00002  * Model Object Code
00003  */
00004 
00005 #include <string>
00006 #include "GLee.h"
00007 #include "Log.h"
00008 #include "Texture.h"
00009 #include "BoundBox.h"
00010 #include "Model.h"
00011 
00012 using namespace std;
00013 
00014 // Helpers for loadObj
00015 #define T(x) (model->triangles[(x)])
00016 
00017 struct ObjTriangle {
00018   GLuint vindices[3];           /* array of triangle vertex indices */
00019   GLuint nindices[3];           /* array of triangle normal indices */
00020   GLuint tindices[3];           /* array of triangle texcoord indices*/
00021   GLuint findex;                /* index of triangle facet normal */
00022 };
00023 
00024 struct ObjGroup {
00025   char*             name;           /* name of this group */
00026   GLuint            numtriangles;   /* number of triangles in this group */
00027   GLuint*           triangles;      /* array of triangle indices */
00028   //GLuint            material;       /* index to material for group */
00029   struct ObjGroup* next;           /* pointer to next group in model */
00030 };
00031 /*
00032 struct ObjMaterial
00033 {
00034   char* name;                   // name of material
00035   GLfloat diffuse[4];           // diffuse component
00036   GLfloat ambient[4];           // ambient component
00037   GLfloat specular[4];          // specular component
00038   GLfloat emmissive[4];         // emmissive component
00039   GLfloat shininess;            // specular exponent
00040 };
00041 */
00042 
00043 struct ObjModel {
00044   char*    pathname;            /* path to this model */
00045   char*    mtllibname;          /* name of the material library */
00046 
00047   GLuint   numvertices;         /* number of vertices in model */
00048   GLfloat* vertices;            /* array of vertices  */
00049 
00050   GLuint   numnormals;          /* number of normals in model */
00051   GLfloat* normals;             /* array of normals */
00052 
00053   GLuint   numtexcoords;        /* number of texcoords in model */
00054   GLfloat* texcoords;           /* array of texture coordinates */
00055 
00056   GLuint   numfacetnorms;       /* number of facetnorms in model */
00057   GLfloat* facetnorms;          /* array of facetnorms */
00058 
00059   GLuint       numtriangles;    /* number of triangles in model */
00060   ObjTriangle* triangles;       /* array of triangles */
00061 
00062   //GLuint       nummaterials;    /* number of materials in model */
00063   //ObjMaterial* materials;       /* array of materials */
00064 
00065   GLuint       numgroups;       /* number of groups in model */
00066   ObjGroup*    groups;          /* linked list of groups */
00067 
00068   GLfloat position[3];          /* position of the model */
00069 
00070 };
00071 
00072 Model::Model(string textureName) {
00073   loaded = false;
00074 
00075   texture = new Texture(textureName);
00076   texture->BindTexture();
00077 }
00078 
00079 Model::~Model() {
00080   if (loaded) {
00081     glDeleteLists(displayList, 1);
00082   }
00083 
00084   delete texture;
00085 
00086   delete modelBox;
00087 }
00088 
00089 void Model::draw() {
00090   if (loaded) {
00091     glCallList(displayList);
00092   }
00093 }
00094 
00095 void Model::startList() {
00096   GLfloat material[4];
00097 
00098   material[0] = 1.0;
00099   material[1] = 1.0;
00100   material[2] = 1.0;
00101   material[3] = 1.0;
00102 
00103   displayList = glGenLists(1);
00104   if (displayList == 0) {
00105     // Probably should throw and exception
00106     Log::s_log->Message("Could not generate model display list");
00107     return;
00108   }
00109 
00110   glNewList(displayList, GL_COMPILE);
00111 
00112   glMaterialfv(GL_FRONT, GL_AMBIENT, material);
00113   glMaterialfv(GL_FRONT, GL_DIFFUSE, material);
00114 
00115   texture->BindTexture();
00116 }
00117 
00118 void Model::loadObj(const char *filename, float scale) {
00119   ObjModel *model;
00120   ObjGroup* group;
00121   ObjGroup* oldGroup;
00122 
00123   model = objLoad(filename);
00124   if (!model) {
00125     return;
00126   }
00127 
00128   // Scale it properly
00129   objScale(model, scale);
00130 
00131   modelBox = objGenerateBox(model);
00132 
00133   startList();
00134   objDraw(model);
00135   glEndList();
00136 
00137   // Clean up the model
00138   group = model->groups;
00139   while(group) {
00140     free(group->triangles);
00141     free(group->name);
00142     oldGroup = group;
00143     group = group->next;
00144     free(oldGroup);
00145   }
00146   free(model->texcoords);
00147   free(model->normals);
00148   free(model->triangles);
00149   free(model->vertices);
00150   free(model->pathname);
00151   free(model);
00152 
00153   loaded = true;
00154 }
00155 
00156 ObjModel* Model::objLoad(const char *filename) {
00157   ObjModel* model;
00158   FILE*   file;
00159 
00160   /* open the file */
00161   file = fopen(filename, "r");
00162   if (!file) {
00163     // Probably should throw an exception
00164     Log::s_log->Message("Warning: Failed to open file %s", filename);
00165     return NULL;
00166   }
00167 
00168   /* allocate a new model */
00169   model = (ObjModel*)malloc(sizeof(ObjModel));
00170   model->pathname    = strdup(filename);
00171   model->mtllibname    = NULL;
00172   model->numvertices   = 0;
00173   model->vertices    = NULL;
00174   model->numnormals    = 0;
00175   model->normals     = NULL;
00176   model->numtexcoords  = 0;
00177   model->texcoords       = NULL;
00178   model->numfacetnorms = 0;
00179   model->facetnorms    = NULL;
00180   model->numtriangles  = 0;
00181   model->triangles       = NULL;
00182   //model->nummaterials  = 0;
00183   //model->materials       = NULL;
00184   model->numgroups       = 0;
00185   model->groups      = NULL;
00186   model->position[0]   = 0.0;
00187   model->position[1]   = 0.0;
00188   model->position[2]   = 0.0;
00189 
00190   /* make a first pass through the file to get a count of the number
00191      of vertices, normals, texcoords & triangles */
00192   objFirstPass(model, file);
00193 
00194   /* allocate memory */
00195   model->vertices = (GLfloat*)malloc(sizeof(GLfloat) *
00196              3 * (model->numvertices + 1));
00197   model->triangles = (ObjTriangle*)malloc(sizeof(ObjTriangle) *
00198             model->numtriangles);
00199   if (model->numnormals) {
00200     model->normals = (GLfloat*)malloc(sizeof(GLfloat) *
00201               3 * (model->numnormals + 1));
00202   }
00203   if (model->numtexcoords) {
00204     model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) *
00205           2 * (model->numtexcoords + 1));
00206   }
00207 
00208   /* rewind to beginning of file and read in the data this pass */
00209   rewind(file);
00210 
00211   objSecondPass(model, file);
00212 
00213   /* close the file */
00214   fclose(file);
00215 
00216   return model;
00217 }
00218 
00219 void Model::objDraw(ObjModel *model) {
00220   ObjGroup* group;
00221   ObjTriangle* triangle;
00222 
00223   glBegin(GL_TRIANGLES);
00224 
00225   group = model->groups;
00226   while (group) {
00227     for (unsigned int i = 0; i < group->numtriangles; i++) {
00228       triangle = &T(group->triangles[i]);
00229 
00230       glNormal3fv(&model->normals[3 * triangle->nindices[0]]);
00231       glTexCoord2fv(&model->texcoords[2 * triangle->tindices[0]]);
00232       glVertex3fv(&model->vertices[3 * triangle->vindices[0]]);
00233 
00234       glNormal3fv(&model->normals[3 * triangle->nindices[1]]);
00235       glTexCoord2fv(&model->texcoords[2 * triangle->tindices[1]]);
00236       glVertex3fv(&model->vertices[3 * triangle->vindices[1]]);
00237 
00238       glNormal3fv(&model->normals[3 * triangle->nindices[2]]);
00239       glTexCoord2fv(&model->texcoords[2 * triangle->tindices[2]]);
00240       glVertex3fv(&model->vertices[3 * triangle->vindices[2]]);
00241     }
00242 
00243     group = group->next;
00244   }
00245 
00246   glEnd();
00247 }
00248 
00249 void Model::objFirstPass(ObjModel *model, FILE* file) {
00250   GLuint  numvertices;        /* number of vertices in model */
00251   GLuint  numnormals;         /* number of normals in model */
00252   GLuint  numtexcoords;       /* number of texcoords in model */
00253   GLuint  numtriangles;       /* number of triangles in model */
00254   ObjGroup* group;            /* current group */
00255   unsigned    v, n, t;
00256   char        buf[128];
00257 
00258   /* make a default group */
00259   group = objAddGroup(model, "default");
00260 
00261   numvertices = numnormals = numtexcoords = numtriangles = 0;
00262   while(fscanf(file, "%s", buf) != EOF) {
00263     switch(buf[0]) {
00264     case '#':               /* comment */
00265       /* eat up rest of line */
00266       fgets(buf, sizeof(buf), file);
00267       break;
00268     case 'v':               /* v, vn, vt */
00269       switch(buf[1]) {
00270       case '\0':          /* vertex */
00271   /* eat up rest of line */
00272   fgets(buf, sizeof(buf), file);
00273   numvertices++;
00274   break;
00275       case 'n':           /* normal */
00276   /* eat up rest of line */
00277   fgets(buf, sizeof(buf), file);
00278   numnormals++;
00279   break;
00280       case 't':           /* texcoord */
00281   /* eat up rest of line */
00282   fgets(buf, sizeof(buf), file);
00283   numtexcoords++;
00284   break;
00285       default:
00286   printf("glmFirstPass(): Unknown token \"%s\".\n", buf);
00287   exit(1);
00288   break;
00289       }
00290       break;
00291     case 'm':
00292       /* eat up rest of line */
00293       fgets(buf, sizeof(buf), file);
00294       break;
00295     case 'u':
00296       /* eat up rest of line */
00297       fgets(buf, sizeof(buf), file);
00298       break;
00299     case 'g':               /* group */
00300       /* eat up rest of line */
00301       fgets(buf, sizeof(buf), file);
00302 #if SINGLE_STRING_GROUP_NAMES
00303       sscanf(buf, "%s", buf);
00304 #else
00305       buf[strlen(buf)-1] = '\0';  /* nuke '\n' */
00306 #endif
00307       group = objAddGroup(model, buf);
00308       break;
00309     case 'f':               /* face */
00310       v = n = t = 0;
00311       fscanf(file, "%s", buf);
00312       if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
00313   /* v/t/n */
00314   fscanf(file, "%d/%d/%d", &v, &t, &n);
00315   fscanf(file, "%d/%d/%d", &v, &t, &n);
00316   numtriangles++;
00317   group->numtriangles++;
00318   while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
00319     numtriangles++;
00320     group->numtriangles++;
00321   }
00322       } else {
00323   Log::s_log->Message("Warning: Invalid .obj file");
00324       }
00325       break;
00326 
00327     default:
00328       /* eat up rest of line */
00329       fgets(buf, sizeof(buf), file);
00330       break;
00331     }
00332   }
00333 
00334   /* set the stats in the model structure */
00335   model->numvertices  = numvertices;
00336   model->numnormals   = numnormals;
00337   model->numtexcoords = numtexcoords;
00338   model->numtriangles = numtriangles;
00339 
00340   /* allocate memory for the triangles in each group */
00341   group = model->groups;
00342   while(group) {
00343     group->triangles = (GLuint*)malloc(sizeof(GLuint) * group->numtriangles);
00344     group->numtriangles = 0;
00345     group = group->next;
00346   }
00347 }
00348 
00349 ObjGroup* Model::objAddGroup(ObjModel *model, char *name) {
00350   ObjGroup* group;
00351 
00352   group = objFindGroup(model, name);
00353   if (!group) {
00354     group = (ObjGroup*)malloc(sizeof(ObjGroup));
00355     group->name = strdup(name);
00356     //group->material = 0;
00357     group->numtriangles = 0;
00358     group->triangles = NULL;
00359     group->next = model->groups;
00360     model->groups = group;
00361     model->numgroups++;
00362   }
00363 
00364   return group;
00365 }
00366 
00367 ObjGroup* Model::objFindGroup(ObjModel* model, char* name) {
00368   ObjGroup* group;
00369 
00370   group = model->groups;
00371   while(group) {
00372     if (!strcmp(name, group->name))
00373       break;
00374     group = group->next;
00375   }
00376 
00377   return group;
00378 }
00379 
00380 void Model::objSecondPass(ObjModel* model, FILE* file) {
00381   GLuint  numvertices;        /* number of vertices in model */
00382   GLuint  numnormals;         /* number of normals in model */
00383   GLuint  numtexcoords;       /* number of texcoords in model */
00384   GLuint  numtriangles;       /* number of triangles in model */
00385   GLfloat*    vertices;           /* array of vertices  */
00386   GLfloat*    normals;            /* array of normals */
00387   GLfloat*    texcoords;          /* array of texture coordinates */
00388   ObjGroup* group;            /* current group pointer */
00389   //GLuint  material;           /* current material */
00390   GLuint  v, n, t;
00391   char        buf[128];
00392 
00393   /* set the pointer shortcuts */
00394   vertices       = model->vertices;
00395   normals    = model->normals;
00396   texcoords    = model->texcoords;
00397   group      = model->groups;
00398 
00399   /* on the second pass through the file, read all the data into the
00400      allocated arrays */
00401   numvertices = numnormals = numtexcoords = 1;
00402   numtriangles = 0;
00403   //material = 0;
00404   while(fscanf(file, "%s", buf) != EOF) {
00405     switch(buf[0]) {
00406     case '#':               /* comment */
00407       /* eat up rest of line */
00408       fgets(buf, sizeof(buf), file);
00409       break;
00410     case 'v':               /* v, vn, vt */
00411       switch(buf[1]) {
00412       case '\0':          /* vertex */
00413   fscanf(file, "%f %f %f",
00414          &vertices[3 * numvertices + 0],
00415          &vertices[3 * numvertices + 1],
00416          &vertices[3 * numvertices + 2]);
00417   numvertices++;
00418   break;
00419       case 'n':           /* normal */
00420   fscanf(file, "%f %f %f",
00421          &normals[3 * numnormals + 0],
00422          &normals[3 * numnormals + 1],
00423          &normals[3 * numnormals + 2]);
00424   numnormals++;
00425   break;
00426       case 't':           /* texcoord */
00427   fscanf(file, "%f %f",
00428          &texcoords[2 * numtexcoords + 0],
00429          &texcoords[2 * numtexcoords + 1]);
00430   numtexcoords++;
00431   break;
00432       }
00433       break;
00434     case 'u':
00435       fgets(buf, sizeof(buf), file);
00436       sscanf(buf, "%s %s", buf, buf);
00437       //group->material = material = glmFindMaterial(model, buf);
00438       break;
00439     case 'g':               /* group */
00440       /* eat up rest of line */
00441       fgets(buf, sizeof(buf), file);
00442 #if SINGLE_STRING_GROUP_NAMES
00443       sscanf(buf, "%s", buf);
00444 #else
00445       buf[strlen(buf)-1] = '\0';  /* nuke '\n' */
00446 #endif
00447       group = objFindGroup(model, buf);
00448       //group->material = material;
00449       break;
00450     case 'f':               /* face */
00451       v = n = t = 0;
00452       fscanf(file, "%s", buf);
00453       if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
00454   /* v/t/n */
00455   T(numtriangles).vindices[0] = v;
00456   T(numtriangles).tindices[0] = t;
00457   T(numtriangles).nindices[0] = n;
00458   fscanf(file, "%d/%d/%d", &v, &t, &n);
00459   T(numtriangles).vindices[1] = v;
00460   T(numtriangles).tindices[1] = t;
00461   T(numtriangles).nindices[1] = n;
00462   fscanf(file, "%d/%d/%d", &v, &t, &n);
00463   T(numtriangles).vindices[2] = v;
00464   T(numtriangles).tindices[2] = t;
00465   T(numtriangles).nindices[2] = n;
00466   group->triangles[group->numtriangles++] = numtriangles;
00467   numtriangles++;
00468   while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
00469     T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
00470     T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
00471     T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
00472     T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
00473     T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
00474     T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
00475     T(numtriangles).vindices[2] = v;
00476     T(numtriangles).tindices[2] = t;
00477     T(numtriangles).nindices[2] = n;
00478     group->triangles[group->numtriangles++] = numtriangles;
00479     numtriangles++;
00480   }
00481       } else {
00482   Log::s_log->Message("Warning: Invalid .obj file");
00483       }
00484       break;
00485 
00486     default:
00487       /* eat up rest of line */
00488       fgets(buf, sizeof(buf), file);
00489       break;
00490     }
00491   }
00492 }
00493 
00494 void Model::objScale(ObjModel* model, float scale) {
00495   GLuint i;
00496 
00497   for (i = 1; i <= model->numvertices; i++) {
00498     model->vertices[3 * i + 0] *= scale;
00499     model->vertices[3 * i + 1] *= scale;
00500     model->vertices[3 * i + 2] *= scale;
00501   }
00502 }
00503 
00504 BoundBox* Model::objGenerateBox(ObjModel* model) {
00505   float minX, maxX, minY, maxY, minZ, maxZ;
00506   float tempVertex;
00507 
00508   minX = 10000;
00509   maxX = -10000;
00510   minY = 10000;
00511   maxY = -10000;
00512   minZ = 10000;
00513   maxZ = -10000;
00514 
00515   for (unsigned int i = 1; i <= model->numvertices; i++) {
00516     tempVertex = model->vertices[3 * i + 0];
00517     if (tempVertex < minX) minX = tempVertex;
00518     if (tempVertex > maxX) maxX = tempVertex;
00519 
00520     tempVertex = model->vertices[3 * i + 1];
00521     if (tempVertex < minY) minY = tempVertex;
00522     if (tempVertex > maxY) maxY = tempVertex;
00523 
00524     tempVertex = model->vertices[3 * i + 2];
00525     if (tempVertex < minZ) minZ = tempVertex;
00526     if (tempVertex > maxZ) maxZ = tempVertex;
00527   }
00528 
00529   return new BoundBox(minX, maxX, minY, maxY, minZ, maxZ);
00530 }

Generated on Mon Jan 8 22:34:12 2007 for CrownandCutlass by  doxygen 1.4.7