00001
00002
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
00015 #define T(x) (model->triangles[(x)])
00016
00017 struct ObjTriangle {
00018 GLuint vindices[3];
00019 GLuint nindices[3];
00020 GLuint tindices[3];
00021 GLuint findex;
00022 };
00023
00024 struct ObjGroup {
00025 char* name;
00026 GLuint numtriangles;
00027 GLuint* triangles;
00028
00029 struct ObjGroup* next;
00030 };
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 struct ObjModel {
00044 char* pathname;
00045 char* mtllibname;
00046
00047 GLuint numvertices;
00048 GLfloat* vertices;
00049
00050 GLuint numnormals;
00051 GLfloat* normals;
00052
00053 GLuint numtexcoords;
00054 GLfloat* texcoords;
00055
00056 GLuint numfacetnorms;
00057 GLfloat* facetnorms;
00058
00059 GLuint numtriangles;
00060 ObjTriangle* triangles;
00061
00062
00063
00064
00065 GLuint numgroups;
00066 ObjGroup* groups;
00067
00068 GLfloat position[3];
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
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
00129 objScale(model, scale);
00130
00131 modelBox = objGenerateBox(model);
00132
00133 startList();
00134 objDraw(model);
00135 glEndList();
00136
00137
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
00161 file = fopen(filename, "r");
00162 if (!file) {
00163
00164 Log::s_log->Message("Warning: Failed to open file %s", filename);
00165 return NULL;
00166 }
00167
00168
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
00183
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
00191
00192 objFirstPass(model, file);
00193
00194
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
00209 rewind(file);
00210
00211 objSecondPass(model, file);
00212
00213
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;
00251 GLuint numnormals;
00252 GLuint numtexcoords;
00253 GLuint numtriangles;
00254 ObjGroup* group;
00255 unsigned v, n, t;
00256 char buf[128];
00257
00258
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 '#':
00265
00266 fgets(buf, sizeof(buf), file);
00267 break;
00268 case 'v':
00269 switch(buf[1]) {
00270 case '\0':
00271
00272 fgets(buf, sizeof(buf), file);
00273 numvertices++;
00274 break;
00275 case 'n':
00276
00277 fgets(buf, sizeof(buf), file);
00278 numnormals++;
00279 break;
00280 case 't':
00281
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
00293 fgets(buf, sizeof(buf), file);
00294 break;
00295 case 'u':
00296
00297 fgets(buf, sizeof(buf), file);
00298 break;
00299 case 'g':
00300
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';
00306 #endif
00307 group = objAddGroup(model, buf);
00308 break;
00309 case 'f':
00310 v = n = t = 0;
00311 fscanf(file, "%s", buf);
00312 if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
00313
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
00329 fgets(buf, sizeof(buf), file);
00330 break;
00331 }
00332 }
00333
00334
00335 model->numvertices = numvertices;
00336 model->numnormals = numnormals;
00337 model->numtexcoords = numtexcoords;
00338 model->numtriangles = numtriangles;
00339
00340
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
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;
00382 GLuint numnormals;
00383 GLuint numtexcoords;
00384 GLuint numtriangles;
00385 GLfloat* vertices;
00386 GLfloat* normals;
00387 GLfloat* texcoords;
00388 ObjGroup* group;
00389
00390 GLuint v, n, t;
00391 char buf[128];
00392
00393
00394 vertices = model->vertices;
00395 normals = model->normals;
00396 texcoords = model->texcoords;
00397 group = model->groups;
00398
00399
00400
00401 numvertices = numnormals = numtexcoords = 1;
00402 numtriangles = 0;
00403
00404 while(fscanf(file, "%s", buf) != EOF) {
00405 switch(buf[0]) {
00406 case '#':
00407
00408 fgets(buf, sizeof(buf), file);
00409 break;
00410 case 'v':
00411 switch(buf[1]) {
00412 case '\0':
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':
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':
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
00438 break;
00439 case 'g':
00440
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';
00446 #endif
00447 group = objFindGroup(model, buf);
00448
00449 break;
00450 case 'f':
00451 v = n = t = 0;
00452 fscanf(file, "%s", buf);
00453 if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
00454
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
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 }