diff options
author | Brian Paul <[email protected]> | 2009-10-01 12:58:36 -0600 |
---|---|---|
committer | Brian Paul <[email protected]> | 2009-10-01 13:14:48 -0600 |
commit | ca1bda552d1cd1a6ddc911e535681a10b9c2d846 (patch) | |
tree | e781dc211d35fe3756a7e6cb90bfa9c4c919e242 /progs/objviewer/glmdraw.c | |
parent | e32a341be66391e0ea1cc6ce19bbd57997f46b6b (diff) |
progs/objviewer: Wavefront .obj file loader/viewer demo
Adapted from code written by Nate Robins. See README.txt.
Diffstat (limited to 'progs/objviewer/glmdraw.c')
-rw-r--r-- | progs/objviewer/glmdraw.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/progs/objviewer/glmdraw.c b/progs/objviewer/glmdraw.c new file mode 100644 index 00000000000..cc986d9d1e3 --- /dev/null +++ b/progs/objviewer/glmdraw.c @@ -0,0 +1,480 @@ +/* */ + +#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; + int mode = GLM_MATERIAL; + + 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 (0&&strcmp(group->name, "Fuselage") != 0) + continue; + + if (group->numtriangles > 0) { + + if (model->materials && (mode & GLM_MATERIAL)) { +#if 0 + 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); +#else + glmShaderMaterial(&model->materials[group->material]); +#endif + } + + +#if 0 + glDrawElements(GL_TRIANGLES, 3 * group->numtriangles, + GL_UNSIGNED_INT, group->triIndexes); +#else + glDrawRangeElements(GL_TRIANGLES, + group->minIndex, group->maxIndex, + 3 * group->numtriangles, + GL_UNSIGNED_INT, group->triIndexes); +#endif + + glDisable(GL_BLEND); + } + } + + 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; + } +} |