glmdraw.c revision 32001f49
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