1/* */ 2 3#define GL_GLEXT_PROTOTYPES 4 5#include <assert.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <string.h> 9#include <GL/glew.h> 10#include "glm.h" 11#include "readtex.h" 12#include "shaderutil.h" 13 14 15/* defines */ 16#define T(x) model->triangles[(x)] 17 18 19/* glmDraw: Renders the model to the current OpenGL context using the 20 * mode specified. 21 * 22 * model - initialized GLMmodel structure 23 * mode - a bitwise OR of values describing what is to be rendered. 24 * GLM_NONE - render with only vertices 25 * GLM_FLAT - render with facet normals 26 * GLM_SMOOTH - render with vertex normals 27 * GLM_TEXTURE - render with texture coords 28 * GLM_COLOR - render with colors (color material) 29 * GLM_MATERIAL - render with materials 30 * GLM_COLOR and GLM_MATERIAL should not both be specified. 31 * GLM_FLAT and GLM_SMOOTH should not both be specified. 32 */ 33GLvoid 34glmDraw(GLMmodel* model, GLuint mode) 35{ 36 GLuint i; 37 GLMgroup* group; 38 39 assert(model); 40 assert(model->vertices); 41 42 /* do a bit of warning */ 43 if (mode & GLM_FLAT && !model->facetnorms) { 44 printf("glmDraw() warning: flat render mode requested " 45 "with no facet normals defined.\n"); 46 mode &= ~GLM_FLAT; 47 } 48 if (mode & GLM_SMOOTH && !model->normals) { 49 printf("glmDraw() warning: smooth render mode requested " 50 "with no normals defined.\n"); 51 mode &= ~GLM_SMOOTH; 52 } 53 if (mode & GLM_TEXTURE && !model->texcoords) { 54 printf("glmDraw() warning: texture render mode requested " 55 "with no texture coordinates defined.\n"); 56 mode &= ~GLM_TEXTURE; 57 } 58 if (mode & GLM_FLAT && mode & GLM_SMOOTH) { 59 printf("glmDraw() warning: flat render mode requested " 60 "and smooth render mode requested (using smooth).\n"); 61 mode &= ~GLM_FLAT; 62 } 63 if (mode & GLM_COLOR && !model->materials) { 64 printf("glmDraw() warning: color render mode requested " 65 "with no materials defined.\n"); 66 mode &= ~GLM_COLOR; 67 } 68 if (mode & GLM_MATERIAL && !model->materials) { 69 printf("glmDraw() warning: material render mode requested " 70 "with no materials defined.\n"); 71 mode &= ~GLM_MATERIAL; 72 } 73 if (mode & GLM_COLOR && mode & GLM_MATERIAL) { 74 printf("glmDraw() warning: color and material render mode requested " 75 "using only material mode\n"); 76 mode &= ~GLM_COLOR; 77 } 78 if (mode & GLM_COLOR) 79 glEnable(GL_COLOR_MATERIAL); 80 if (mode & GLM_MATERIAL) 81 glDisable(GL_COLOR_MATERIAL); 82 83 glPushMatrix(); 84 glTranslatef(model->position[0], model->position[1], model->position[2]); 85 86 glBegin(GL_TRIANGLES); 87 group = model->groups; 88 while (group) { 89 if (mode & GLM_MATERIAL) { 90 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, 91 model->materials[group->material].ambient); 92 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 93 model->materials[group->material].diffuse); 94 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, 95 model->materials[group->material].specular); 96 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 97 model->materials[group->material].shininess); 98 } 99 100 if (mode & GLM_COLOR) { 101 glColor3fv(model->materials[group->material].diffuse); 102 } 103 104 for (i = 0; i < group->numtriangles; i++) { 105 if (mode & GLM_FLAT) 106 glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]); 107 108 if (mode & GLM_SMOOTH) 109 glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[0]]); 110 if (mode & GLM_TEXTURE) 111 glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]); 112 glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[0]]); 113#if 0 114 printf("%f %f %f\n", 115 model->vertices[3 * T(group->triangles[i]).vindices[0] + X], 116 model->vertices[3 * T(group->triangles[i]).vindices[0] + Y], 117 model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]); 118#endif 119 120 if (mode & GLM_SMOOTH) 121 glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[1]]); 122 if (mode & GLM_TEXTURE) 123 glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]); 124 glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[1]]); 125#if 0 126 printf("%f %f %f\n", 127 model->vertices[3 * T(group->triangles[i]).vindices[1] + X], 128 model->vertices[3 * T(group->triangles[i]).vindices[1] + Y], 129 model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]); 130#endif 131 132 if (mode & GLM_SMOOTH) 133 glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[2]]); 134 if (mode & GLM_TEXTURE) 135 glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]); 136 glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[2]]); 137#if 0 138 printf("%f %f %f\n", 139 model->vertices[3 * T(group->triangles[i]).vindices[2] + X], 140 model->vertices[3 * T(group->triangles[i]).vindices[2] + Y], 141 model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]); 142#endif 143 144 } 145 146 group = group->next; 147 } 148 glEnd(); 149 150 glPopMatrix(); 151} 152 153 154void 155glmMakeVBOs(GLMmodel *model) 156{ 157 uint bytes, vertexFloats, i; 158 float *buffer; 159 GLMgroup* group; 160 unsigned totalIndexes; 161 GLubyte *ibuffer, *ib; 162 163 /* 164 * Vertex data 165 */ 166 vertexFloats = 3; 167 model->posOffset = 0; 168 169 if (model->numnormals > 0) { 170 assert(model->numnormals == model->numvertices); 171 model->normOffset = vertexFloats * sizeof(GLfloat); 172 vertexFloats += 3; 173 } 174 175 if (model->numtexcoords > 0) { 176 assert(model->numtexcoords == model->numvertices); 177 model->texOffset = vertexFloats * sizeof(GLfloat); 178 vertexFloats += 2; 179 } 180 181 model->vertexSize = vertexFloats; 182 183 bytes = (model->numvertices + 1) * vertexFloats * sizeof(float); 184 185 buffer = (float *) malloc(bytes); 186 for (i = 0; i < model->numvertices; i++) { 187 /* copy vertex pos */ 188 uint j = 0; 189 buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 0]; 190 buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 1]; 191 buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 2]; 192 if (model->numnormals > 0) { 193 buffer[i * vertexFloats + j++] = model->normals[i * 3 + 0]; 194 buffer[i * vertexFloats + j++] = model->normals[i * 3 + 1]; 195 buffer[i * vertexFloats + j++] = model->normals[i * 3 + 2]; 196 } 197 if (model->numtexcoords > 0) { 198 buffer[i * vertexFloats + j++] = model->texcoords[i * 2 + 0]; 199 buffer[i * vertexFloats + j++] = model->texcoords[i * 2 + 1]; 200 } 201 } 202 203 glGenBuffersARB(1, &model->vbo); 204 glBindBufferARB(GL_ARRAY_BUFFER_ARB, model->vbo); 205 glBufferDataARB(GL_ARRAY_BUFFER_ARB, bytes, buffer, GL_STATIC_DRAW_ARB); 206 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 207 208 free(buffer); 209 210 /* 211 * Index data 212 */ 213 totalIndexes = 0; 214 for (group = model->groups; group; group = group->next) { 215 if (group->numtriangles > 0) { 216 totalIndexes += 3 * group->numtriangles; 217 } 218 } 219 220 glGenBuffersARB(1, &model->index_vbo); 221 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, model->index_vbo); 222 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, totalIndexes * sizeof(GLuint), 223 NULL, GL_STATIC_DRAW_ARB); 224 ibuffer = (GLubyte *) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 225 GL_WRITE_ONLY); 226 ib = ibuffer; 227 228 for (group = model->groups; group; group = group->next) { 229 if (group->numtriangles > 0) { 230 int bytes = 3 * group->numtriangles * sizeof(uint); 231 memcpy(ib, group->triIndexes, bytes); 232 totalIndexes += 3 * group->numtriangles; 233 group->indexVboOffset = ib - ibuffer; 234 ib += bytes; 235 } 236 } 237 238 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); 239 240 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 241} 242 243 244static void 245_glmLoadTexture(GLMmaterial *mat) 246{ 247 if (mat->map_kd) { 248 GLint imgWidth, imgHeight; 249 GLenum imgFormat; 250 GLubyte *image = NULL; 251 252 glGenTextures(1, &mat->texture_kd); 253 254 image = LoadRGBImage( mat->map_kd, &imgWidth, &imgHeight, &imgFormat ); 255 if (!image) { 256 /*fprintf(stderr, "Couldn't open texture %s\n", mat->map_kd);*/ 257 free(mat->map_kd); 258 mat->map_kd = NULL; 259 mat->texture_kd = 0; 260 return; 261 } 262 if (0) 263 printf("load texture %s %d x %d\n", mat->map_kd, imgWidth, imgHeight); 264 265 glBindTexture(GL_TEXTURE_2D, mat->texture_kd); 266 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imgWidth, imgHeight, 267 imgFormat, GL_UNSIGNED_BYTE, image); 268 free(image); 269 270 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); 271 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); 272 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); 273 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 274 } 275} 276 277void 278glmLoadTextures(GLMmodel *model) 279{ 280 uint i; 281 282 for (i = 0; i < model->nummaterials; i++) { 283 GLMmaterial *mat = &model->materials[i]; 284 _glmLoadTexture(mat); 285 } 286} 287 288 289void 290glmDrawVBO(GLMmodel *model) 291{ 292 GLMgroup* group; 293 uint prevMaterial = ~0; 294 295 assert(model->vbo); 296 297 glBindBufferARB(GL_ARRAY_BUFFER_ARB, model->vbo); 298 299 glVertexPointer(3, GL_FLOAT, model->vertexSize * sizeof(float), 300 (const void *) (size_t) model->posOffset); 301 glEnableClientState(GL_VERTEX_ARRAY); 302 303 if (model->numnormals > 0) { 304 glNormalPointer(GL_FLOAT, model->vertexSize * sizeof(float), 305 (const void *) (size_t) model->normOffset); 306 glEnableClientState(GL_NORMAL_ARRAY); 307 } 308 309 if (model->numtexcoords > 0) { 310 glTexCoordPointer(2, GL_FLOAT, model->vertexSize * sizeof(float), 311 (const void *) (size_t) model->texOffset); 312 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 313 } 314 315 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, model->index_vbo); 316 317 glPushMatrix(); 318 glTranslatef(model->position[0], model->position[1], model->position[2]); 319 glScalef(model->scale, model->scale, model->scale); 320 321 for (group = model->groups; group; group = group->next) { 322 if (group->numtriangles > 0) { 323 324 if (group->material != prevMaterial) { 325 glmShaderMaterial(&model->materials[group->material]); 326 prevMaterial = group->material; 327 } 328 329 glDrawRangeElements(GL_TRIANGLES, 330 group->minIndex, group->maxIndex, 331 3 * group->numtriangles, 332 GL_UNSIGNED_INT, 333 (void *) (GLintptr) group->indexVboOffset); 334 } 335 } 336 337 glPopMatrix(); 338 339 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 340 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 341 glDisableClientState(GL_VERTEX_ARRAY); 342 glDisableClientState(GL_NORMAL_ARRAY); 343 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 344} 345 346 347 348/* glmList: Generates and returns a display list for the model using 349 * the mode specified. 350 * 351 * model - initialized GLMmodel structure 352 * mode - a bitwise OR of values describing what is to be rendered. 353 * GLM_NONE - render with only vertices 354 * GLM_FLAT - render with facet normals 355 * GLM_SMOOTH - render with vertex normals 356 * GLM_TEXTURE - render with texture coords 357 * GLM_COLOR - render with colors (color material) 358 * GLM_MATERIAL - render with materials 359 * GLM_COLOR and GLM_MATERIAL should not both be specified. 360 * GLM_FLAT and GLM_SMOOTH should not both be specified. 361 */ 362GLuint 363glmList(GLMmodel* model, GLuint mode) 364{ 365 GLuint list; 366 367 list = glGenLists(1); 368 glNewList(list, GL_COMPILE); 369 glmDraw(model, mode); 370 glEndList(); 371 372 return list; 373} 374 375 376 377static const char *VertexShader = 378 "varying vec3 normal; \n" 379 "void main() { \n" 380 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" 381 " normal = gl_NormalMatrix * gl_Normal; \n" 382 " gl_TexCoord[0] = gl_MultiTexCoord0; \n" 383 "} \n"; 384 385/** 386 * Two %s substitutions: 387 * diffuse texture? true/false 388 * specular texture? true/false 389 */ 390static const char *TexFragmentShader = 391 "uniform vec4 ambient, diffuse, specular; \n" 392 "uniform vec4 ambientLight, diffuseLight, specularLight; \n" 393 "uniform float shininess; \n" 394 "uniform sampler2D diffTex; \n" 395 "uniform samplerCube specTex; \n" 396 "varying vec3 normal; \n" 397 "\n" 398 "void main() \n" 399 "{ \n" 400 " vec4 diffTerm, specTerm; \n" 401 " float dotProd = max(dot(gl_LightSource[0].position.xyz, \n" 402 " normalize(normal)), 0.0);\n" 403 " float dotProd2 = max(dot(-gl_LightSource[0].position.xyz, \n" 404 " normalize(normal)), 0.0);\n" 405 " dotProd += dotProd2; \n" 406 " \n" 407 " diffTerm = diffuse * diffuseLight * dotProd; \n" 408 " if (%s) \n" 409 " diffTerm *= texture2D(diffTex, gl_TexCoord[0].st); \n" 410 " \n" 411 " specTerm = specular * specularLight * pow(dotProd, shininess); \n" 412 " if (%s) \n" 413 " specTerm *= textureCube(specTex, normal); \n" 414 " \n" 415 " gl_FragColor = ambient * ambientLight + diffTerm + specTerm; \n" 416 "} \n"; 417 418 419void 420glmShaderMaterial(GLMmaterial *mat) 421{ 422 static const float ambientLight[4] = { 0.1, 0.1, 0.1, 0.0 }; 423 static const float diffuseLight[4] = { 0.75, 0.75, 0.75, 1.0 }; 424 static const float specularLight[4] = { 1.0, 1.0, 1.0, 0.0 }; 425 426 if (!mat->prog) { 427 /* make shader now */ 428 char newShader[10000]; 429 GLuint vs, fs; 430 const char *diffuseTex = mat->texture_kd ? "true" : "false"; 431 const char *specularTex = mat->texture_ks ? "true" : "false"; 432 GLint uAmbientLight, uDiffuseLight, uSpecularLight; 433 434 /* replace %d with 0 or 1 */ 435 sprintf(newShader, TexFragmentShader, diffuseTex, specularTex); 436 if (0) 437 printf("===== new shader =====\n%s\n============\n", newShader); 438 439 vs = CompileShaderText(GL_VERTEX_SHADER, VertexShader); 440 fs = CompileShaderText(GL_FRAGMENT_SHADER, newShader); 441 mat->prog = LinkShaders(vs, fs); 442 assert(mat->prog); 443 444 glUseProgram(mat->prog); 445 446 mat->uAmbient = glGetUniformLocation(mat->prog, "ambient"); 447 mat->uDiffuse = glGetUniformLocation(mat->prog, "diffuse"); 448 mat->uSpecular = glGetUniformLocation(mat->prog, "specular"); 449 mat->uShininess = glGetUniformLocation(mat->prog, "shininess"); 450 mat->uDiffTex = glGetUniformLocation(mat->prog, "diffTex"); 451 mat->uSpecTex = glGetUniformLocation(mat->prog, "specTex"); 452 453 uAmbientLight = glGetUniformLocation(mat->prog, "ambientLight"); 454 uDiffuseLight = glGetUniformLocation(mat->prog, "diffuseLight"); 455 uSpecularLight = glGetUniformLocation(mat->prog, "specularLight"); 456 457 glUniform4fv(mat->uAmbient, 1, mat->ambient); 458 glUniform4fv(mat->uDiffuse, 1, mat->diffuse); 459 glUniform4fv(mat->uSpecular, 1, mat->specular); 460 glUniform1f(mat->uShininess, mat->shininess); 461 glUniform1i(mat->uDiffTex, 0); 462 glUniform1i(mat->uSpecTex, 1); 463 464 glUniform4fv(uAmbientLight, 1, ambientLight); 465 glUniform4fv(uDiffuseLight, 1, diffuseLight); 466 glUniform4fv(uSpecularLight, 1, specularLight); 467 } 468 469 glActiveTexture(GL_TEXTURE1); 470 if (mat->texture_ks) 471 glBindTexture(GL_TEXTURE_CUBE_MAP, mat->texture_ks); 472 else 473 glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 474 475 glActiveTexture(GL_TEXTURE0); 476 if (mat->texture_kd) 477 glBindTexture(GL_TEXTURE_2D, mat->texture_kd); 478 else 479 glBindTexture(GL_TEXTURE_2D, 0); 480 481 if (mat->diffuse[3] < 1.0) { 482 glEnable(GL_BLEND); 483 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 484 } 485 else { 486 glDisable(GL_BLEND); 487 } 488 489 glUseProgram(mat->prog); 490} 491 492 493void 494glmSpecularTexture(GLMmodel *model, uint cubeTex) 495{ 496 uint i; 497 498 for (i = 0; i < model->nummaterials; i++) { 499 model->materials[i].texture_ks = cubeTex; 500 } 501} 502