diff options
Diffstat (limited to 'progs/objviewer/glmdraw.c')
| -rw-r--r-- | progs/objviewer/glmdraw.c | 455 | 
1 files changed, 455 insertions, 0 deletions
| diff --git a/progs/objviewer/glmdraw.c b/progs/objviewer/glmdraw.c new file mode 100644 index 0000000000..8b214cdb55 --- /dev/null +++ b/progs/objviewer/glmdraw.c @@ -0,0 +1,455 @@ +/* */ + +#define GL_GLEXT_PROTOTYPES + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <GL/gl.h> +#include <GL/glu.h> +#include "glm.h" +#include "readtex.h" +#include "shaderutil.h" + + +/* defines */ +#define T(x) model->triangles[(x)] + + +/* glmDraw: Renders the model to the current OpenGL context using the + * mode specified. + * + * model    - initialized GLMmodel structure + * mode     - a bitwise OR of values describing what is to be rendered. + *            GLM_NONE     -  render with only vertices + *            GLM_FLAT     -  render with facet normals + *            GLM_SMOOTH   -  render with vertex normals + *            GLM_TEXTURE  -  render with texture coords + *            GLM_COLOR    -  render with colors (color material) + *            GLM_MATERIAL -  render with materials + *            GLM_COLOR and GLM_MATERIAL should not both be specified.   + *            GLM_FLAT and GLM_SMOOTH should not both be specified.   + */ +GLvoid +glmDraw(GLMmodel* model, GLuint mode) +{ +  GLuint i; +  GLMgroup* group; + +  assert(model); +  assert(model->vertices); + +  /* do a bit of warning */ +  if (mode & GLM_FLAT && !model->facetnorms) { +    printf("glmDraw() warning: flat render mode requested " +	   "with no facet normals defined.\n"); +    mode &= ~GLM_FLAT; +  } +  if (mode & GLM_SMOOTH && !model->normals) { +    printf("glmDraw() warning: smooth render mode requested " +	   "with no normals defined.\n"); +    mode &= ~GLM_SMOOTH; +  } +  if (mode & GLM_TEXTURE && !model->texcoords) { +    printf("glmDraw() warning: texture render mode requested " +	   "with no texture coordinates defined.\n"); +    mode &= ~GLM_TEXTURE; +  } +  if (mode & GLM_FLAT && mode & GLM_SMOOTH) { +    printf("glmDraw() warning: flat render mode requested " +	   "and smooth render mode requested (using smooth).\n"); +    mode &= ~GLM_FLAT; +  } +  if (mode & GLM_COLOR && !model->materials) { +    printf("glmDraw() warning: color render mode requested " +	   "with no materials defined.\n"); +    mode &= ~GLM_COLOR; +  } +  if (mode & GLM_MATERIAL && !model->materials) { +    printf("glmDraw() warning: material render mode requested " +	   "with no materials defined.\n"); +    mode &= ~GLM_MATERIAL; +  } +  if (mode & GLM_COLOR && mode & GLM_MATERIAL) { +    printf("glmDraw() warning: color and material render mode requested " +	   "using only material mode\n"); +    mode &= ~GLM_COLOR; +  } +  if (mode & GLM_COLOR) +    glEnable(GL_COLOR_MATERIAL); +  if (mode & GLM_MATERIAL) +    glDisable(GL_COLOR_MATERIAL); + +  glPushMatrix(); +  glTranslatef(model->position[0], model->position[1], model->position[2]); + +  glBegin(GL_TRIANGLES); +  group = model->groups; +  while (group) { +    if (mode & GLM_MATERIAL) { +      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  +		   model->materials[group->material].ambient); +      glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  +		   model->materials[group->material].diffuse); +      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  +		   model->materials[group->material].specular); +       glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS,  +  		  model->materials[group->material].shininess); +    } + +    if (mode & GLM_COLOR) { +      glColor3fv(model->materials[group->material].diffuse); +    } + +    for (i = 0; i < group->numtriangles; i++) { +      if (mode & GLM_FLAT) +	glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]); +       +      if (mode & GLM_SMOOTH) +	glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[0]]); +      if (mode & GLM_TEXTURE) +	glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]); +      glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[0]]); +#if 0 +      printf("%f %f %f\n",  +	     model->vertices[3 * T(group->triangles[i]).vindices[0] + X], +	     model->vertices[3 * T(group->triangles[i]).vindices[0] + Y], +	     model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]); +#endif +       +      if (mode & GLM_SMOOTH) +	glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[1]]); +      if (mode & GLM_TEXTURE) +	glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]); +      glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[1]]); +#if 0 +      printf("%f %f %f\n",  +	     model->vertices[3 * T(group->triangles[i]).vindices[1] + X], +	     model->vertices[3 * T(group->triangles[i]).vindices[1] + Y], +	     model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]); +#endif +       +      if (mode & GLM_SMOOTH) +	glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[2]]); +      if (mode & GLM_TEXTURE) +	glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]); +      glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[2]]); +#if 0 +      printf("%f %f %f\n",  +	     model->vertices[3 * T(group->triangles[i]).vindices[2] + X], +	     model->vertices[3 * T(group->triangles[i]).vindices[2] + Y], +	     model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]); +#endif +       +    } +     +    group = group->next; +  } +  glEnd(); + +  glPopMatrix(); +} + + +void +glmMakeVBOs(GLMmodel *model) +{ +   uint bytes, vertexFloats, i; +   float *buffer; + +   vertexFloats = 3; +   model->posOffset = 0; + +   if (model->numnormals > 0) { +      assert(model->numnormals == model->numvertices); +      model->normOffset = vertexFloats * sizeof(GLfloat); +      vertexFloats += 3; +   }       + +   if (model->numtexcoords > 0) { +      assert(model->numtexcoords == model->numvertices); +      model->texOffset = vertexFloats * sizeof(GLfloat); +      vertexFloats += 2; +   } + +   model->vertexSize = vertexFloats; + +   bytes = (model->numvertices + 1) * vertexFloats * sizeof(float); + +   buffer = (float *) malloc(bytes); +   for (i = 0; i < model->numvertices; i++) { +      /* copy vertex pos */ +      uint j = 0; +      buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 0]; +      buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 1]; +      buffer[i * vertexFloats + j++] = model->vertices[i * 3 + 2]; +      if (model->numnormals > 0) { +         buffer[i * vertexFloats + j++] = model->normals[i * 3 + 0]; +         buffer[i * vertexFloats + j++] = model->normals[i * 3 + 1]; +         buffer[i * vertexFloats + j++] = model->normals[i * 3 + 2]; +      } +      if (model->numtexcoords > 0) { +         buffer[i * vertexFloats + j++] = model->texcoords[i * 2 + 0]; +         buffer[i * vertexFloats + j++] = model->texcoords[i * 2 + 1]; +      } +   } + +   glGenBuffersARB(1, &model->vbo); +   glBindBufferARB(GL_ARRAY_BUFFER_ARB, model->vbo); +   glBufferDataARB(GL_ARRAY_BUFFER_ARB, bytes, buffer, GL_STATIC_DRAW_ARB); +   glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + +   free(buffer); +} + + +static void +_glmLoadTexture(GLMmaterial *mat) +{ +  if (mat->map_kd) { +     GLint imgWidth, imgHeight; +     GLenum imgFormat; +     GLubyte *image = NULL; +      +     glGenTextures(1, &mat->texture_kd); + +     image = LoadRGBImage( mat->map_kd, &imgWidth, &imgHeight, &imgFormat ); +     if (!image) { +        /*fprintf(stderr, "Couldn't open texture %s\n", mat->map_kd);*/ +        free(mat->map_kd); +        mat->map_kd = NULL; +        mat->texture_kd = 0; +        return; +     } +     if (0) +        printf("load texture %s %d x %d\n", mat->map_kd, imgWidth, imgHeight); + +     glBindTexture(GL_TEXTURE_2D, mat->texture_kd); +     gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imgWidth, imgHeight, +                       imgFormat, GL_UNSIGNED_BYTE, image); +     free(image); + +     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); +     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); +     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); +     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); +  } +} + +void +glmLoadTextures(GLMmodel *model) +{ +   uint i; + +   for (i = 0; i < model->nummaterials; i++) { +      GLMmaterial *mat = &model->materials[i]; +      _glmLoadTexture(mat); +   } +} + + +void +glmDrawVBO(GLMmodel *model) +{ +   GLMgroup* group; + +   assert(model->vbo); + +   glBindBufferARB(GL_ARRAY_BUFFER_ARB, model->vbo); + +   glVertexPointer(3, GL_FLOAT, model->vertexSize * sizeof(float), +                   (void *) model->posOffset); +   glEnableClientState(GL_VERTEX_ARRAY); + +   if (model->numnormals > 0) { +      glNormalPointer(GL_FLOAT, model->vertexSize * sizeof(float), +                      (void *) model->normOffset); +      glEnableClientState(GL_NORMAL_ARRAY); +   } + +   if (model->numtexcoords > 0) { +      glTexCoordPointer(2, GL_FLOAT, model->vertexSize * sizeof(float), +                        (void *) model->texOffset); +      glEnableClientState(GL_TEXTURE_COORD_ARRAY); +   } + +   glPushMatrix(); +   glTranslatef(model->position[0], model->position[1], model->position[2]); +   glScalef(model->scale, model->scale, model->scale); + +   for (group = model->groups; group; group = group->next) { +      if (group->numtriangles > 0) { + +         glmShaderMaterial(&model->materials[group->material]); + +         glDrawRangeElements(GL_TRIANGLES, +                             group->minIndex, group->maxIndex, +                             3 * group->numtriangles, +                             GL_UNSIGNED_INT, group->triIndexes); +      } +   } + +   glPopMatrix(); + +   glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); +   glDisableClientState(GL_VERTEX_ARRAY); +   glDisableClientState(GL_NORMAL_ARRAY); +   glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + + + +/* glmList: Generates and returns a display list for the model using + * the mode specified. + * + * model    - initialized GLMmodel structure + * mode     - a bitwise OR of values describing what is to be rendered. + *            GLM_NONE     -  render with only vertices + *            GLM_FLAT     -  render with facet normals + *            GLM_SMOOTH   -  render with vertex normals + *            GLM_TEXTURE  -  render with texture coords + *            GLM_COLOR    -  render with colors (color material) + *            GLM_MATERIAL -  render with materials + *            GLM_COLOR and GLM_MATERIAL should not both be specified.   + *            GLM_FLAT and GLM_SMOOTH should not both be specified.   + */ +GLuint +glmList(GLMmodel* model, GLuint mode) +{ +  GLuint list; + +  list = glGenLists(1); +  glNewList(list, GL_COMPILE); +  glmDraw(model, mode); +  glEndList(); + +  return list; +} + + + +static const char *VertexShader = +   "varying vec3 normal; \n" +   "void main() { \n" +   "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" +   "   normal = gl_NormalMatrix * gl_Normal; \n" +   "   gl_TexCoord[0] = gl_MultiTexCoord0; \n" +   "} \n"; + +/** + * Two %s substitutions: + *   diffuse texture? true/false + *   specular texture? true/false + */ +static const char *TexFragmentShader = +   "uniform vec4 ambient, diffuse, specular; \n" +   "uniform vec4 ambientLight, diffuseLight, specularLight; \n" +   "uniform float shininess; \n" +   "uniform sampler2D diffTex; \n" +   "uniform samplerCube specTex; \n" +   "varying vec3 normal; \n" +   "\n" +   "void main() \n" +   "{ \n" +   "   vec4 diffTerm, specTerm; \n" +   "   float dotProd = max(dot(gl_LightSource[0].position.xyz, \n" +   "                           normalize(normal)), 0.0);\n" +   "   float dotProd2 = max(dot(-gl_LightSource[0].position.xyz, \n" +   "                           normalize(normal)), 0.0);\n" +   "   dotProd += dotProd2; \n" +   " \n" +   "   diffTerm = diffuse * diffuseLight * dotProd; \n" +   "   if (%s) \n" +   "      diffTerm *= texture2D(diffTex, gl_TexCoord[0].st); \n" +   " \n" +   "   specTerm = specular * specularLight * pow(dotProd, shininess); \n" +   "   if (%s) \n" +   "      specTerm *= textureCube(specTex, normal); \n" +   " \n" +   "   gl_FragColor = ambient * ambientLight + diffTerm + specTerm; \n" +   "} \n"; + + +void +glmShaderMaterial(GLMmaterial *mat) +{ +   static const float ambientLight[4] = { 0.1, 0.1, 0.1, 0.0 }; +   static const float diffuseLight[4] = { 0.75, 0.75, 0.75, 1.0 }; +   static const float specularLight[4] = { 1.0, 1.0, 1.0, 0.0 }; + +   if (!mat->prog) { +      /* make shader now */ +      char newShader[10000]; +      GLuint vs, fs; +      const char *diffuseTex = mat->texture_kd ? "true" : "false"; +      const char *specularTex = mat->texture_ks ? "true" : "false"; +      GLint uAmbientLight, uDiffuseLight, uSpecularLight; + +      /* replace %d with 0 or 1 */ +      sprintf(newShader, TexFragmentShader, diffuseTex, specularTex); +      if (0) +         printf("===== new shader =====\n%s\n============\n", newShader); + +      vs = CompileShaderText(GL_VERTEX_SHADER, VertexShader); +      fs = CompileShaderText(GL_FRAGMENT_SHADER, newShader); +      mat->prog = LinkShaders(vs, fs); +      assert(mat->prog); + +      glUseProgram(mat->prog); + +      mat->uAmbient = glGetUniformLocation(mat->prog, "ambient"); +      mat->uDiffuse = glGetUniformLocation(mat->prog, "diffuse"); +      mat->uSpecular = glGetUniformLocation(mat->prog, "specular"); +      mat->uShininess = glGetUniformLocation(mat->prog, "shininess"); +      mat->uDiffTex = glGetUniformLocation(mat->prog, "diffTex"); +      mat->uSpecTex = glGetUniformLocation(mat->prog, "specTex"); + +      uAmbientLight = glGetUniformLocation(mat->prog, "ambientLight"); +      uDiffuseLight = glGetUniformLocation(mat->prog, "diffuseLight"); +      uSpecularLight = glGetUniformLocation(mat->prog, "specularLight"); + +      glUniform4fv(mat->uAmbient, 1, mat->ambient); +      glUniform4fv(mat->uDiffuse, 1, mat->diffuse); +      glUniform4fv(mat->uSpecular, 1, mat->specular); +      glUniform1f(mat->uShininess, mat->shininess); +      glUniform1i(mat->uDiffTex, 0); +      glUniform1i(mat->uSpecTex, 1); + +      glUniform4fv(uAmbientLight, 1, ambientLight); +      glUniform4fv(uDiffuseLight, 1, diffuseLight); +      glUniform4fv(uSpecularLight, 1, specularLight); +   } + +   glActiveTexture(GL_TEXTURE1); +   if (mat->texture_ks) +      glBindTexture(GL_TEXTURE_CUBE_MAP, mat->texture_ks); +   else +      glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + +   glActiveTexture(GL_TEXTURE0); +   if (mat->texture_kd) +      glBindTexture(GL_TEXTURE_2D, mat->texture_kd); +   else +      glBindTexture(GL_TEXTURE_2D, 0); + +   if (mat->diffuse[3] < 1.0) { +      glEnable(GL_BLEND); +      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +   } +   else { +      glDisable(GL_BLEND); +   } + +   glUseProgram(mat->prog); +} + + +void +glmSpecularTexture(GLMmodel *model, uint cubeTex) +{ +   uint i; + +   for (i = 0; i < model->nummaterials; i++) { +      model->materials[i].texture_ks = cubeTex; +   } +} | 
