#include #include #include #include #include "texture.h" /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #if !defined(GL_VERSION_1_1) && !defined(GL_VERSION_1_2) #define glBindTexture glBindTextureEXT #endif #define CHECK_ERROR(str) \ { \ GLenum error; \ if(error = glGetError()) \ printf("GL Error: %s (%s)\n", gluErrorString(error), str); \ } #ifndef FALSE enum {FALSE, TRUE}; #endif enum {X, Y, Z, W}; enum {OBJ_ANGLE, LIGHT_ANGLE, OBJ_TRANSLATE}; enum {SURF_TEX, HIGHLIGHT_TEX}; /* window dimensions */ int winWidth = 512; int winHeight = 512; int active; int dblbuf = TRUE; int highlight = TRUE; int gouraud = FALSE; int texmap = FALSE; int notex = FALSE; /* don't texture gouraud */ int object = 2; int maxobject = 2; GLfloat lightangle[2] = {0.f, 0.f}; GLfloat objangle[2] = {0.f, 0.f}; GLfloat objpos[2] = {0.f, 0.f}; GLfloat color[4] = {1.f, 1.f, 1.f, 1.f}; GLfloat zero[4] = {0.f, 0.f, 0.f, 1.f}; GLfloat one[4] = {1.f, 1.f, 1.f, 1.f}; int texdim = 128; GLfloat *lighttex = 0; GLfloat lightpos[4] = {0.f, 0.f, 1.f, 0.f}; GLboolean lightchanged[2] = {GL_TRUE, GL_TRUE}; enum {UPDATE_OGL, UPDATE_TEX}; /* draw a highly tesselated sphere with a specular highlight */ void makeHighlight(int shinyness) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); /* starts as modelview */ glLoadIdentity(); glTranslatef(0.f, 0.f, -texdim/2.f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-texdim/2., texdim/2., -texdim/2., texdim/2., 0., texdim/2.); glPushAttrib(GL_LIGHTING_BIT|GL_VIEWPORT_BIT); glViewport(0, 0, texdim, texdim); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_DIFFUSE, zero); glLightfv(GL_LIGHT0, GL_POSITION, lightpos); /* light direction */ /* XXX TODO, range check an report errors */ glMateriali(GL_FRONT, GL_SHININESS, shinyness); /* cosine power */ glMaterialfv(GL_FRONT, GL_AMBIENT, zero); glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); glMaterialfv(GL_FRONT, GL_SPECULAR, color); glDisable(GL_TEXTURE_2D); glCallList(1); glEnable(GL_TEXTURE_2D); glPopAttrib(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glReadPixels(0, 0, texdim, texdim, GL_RGB, GL_FLOAT, lighttex); glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texdim, texdim, 0, GL_RGB, GL_FLOAT, lighttex); } void reshape(int wid, int ht) { winWidth = wid; winHeight = ht; glViewport(0, 0, wid, ht); } void motion(int x, int y) { switch(active) { case OBJ_ANGLE: objangle[X] = (x - winWidth/2) * 360./winWidth; objangle[Y] = (y - winHeight/2) * 360./winHeight; glutPostRedisplay(); break; case LIGHT_ANGLE: lightangle[X] = (x - winWidth/2) * 2 * M_PI/winWidth; lightangle[Y] = (winHeight/2 - y) * 2 * M_PI/winHeight; lightpos[Y] = sin(lightangle[Y]); lightpos[X] = cos(lightangle[Y]) * sin(lightangle[X]); lightpos[Z] = cos(lightangle[Y]) * cos(lightangle[X]); lightpos[W] = 0.; lightchanged[UPDATE_OGL] = GL_TRUE; lightchanged[UPDATE_TEX] = GL_TRUE; glutPostRedisplay(); break; case OBJ_TRANSLATE: objpos[X] = (x - winWidth/2) * 100./winWidth; objpos[Y] = (winHeight/2 - y) * 100./winHeight; glutPostRedisplay(); break; } } void mouse(int button, int state, int x, int y) { if(state == GLUT_DOWN) switch(button) { case GLUT_LEFT_BUTTON: /* move the light */ active = OBJ_ANGLE; motion(x, y); break; case GLUT_MIDDLE_BUTTON: active = LIGHT_ANGLE; motion(x, y); break; case GLUT_RIGHT_BUTTON: /* move the polygon */ active = OBJ_TRANSLATE; motion(x, y); break; } } /* draw the object unlit without surface texture */ void redraw_white(void) { glPushMatrix(); /* assuming modelview */ glTranslatef(objpos[X], objpos[Y], 0.f); /* translate object */ glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */ glRotatef(objangle[Y], 1.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); /* draw the specular highlight */ glCallList(object); glEnable(GL_TEXTURE_2D); glPopMatrix(); /* assuming modelview */ CHECK_ERROR("OpenGL Error in redraw_tex()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* just draw textured highlight */ void redraw_tex_highlight(void) { if(lightchanged[UPDATE_TEX]) { makeHighlight(128); lightchanged[UPDATE_TEX] = GL_FALSE; } glPushMatrix(); /* assuming modelview */ glTranslatef(objpos[X], objpos[Y], 0.f); /* translate object */ glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */ glRotatef(objangle[Y], 1.f, 0.f, 0.f); glClearColor(.1f, .1f, .1f, 1.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glClearColor(0.f, 0.f, 0.f, 1.f); /* draw the specular highlight */ glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glCallList(object); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glPopMatrix(); /* assuming modelview */ CHECK_ERROR("OpenGL Error in redraw_tex()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* just draw opengl highlight */ void redraw_gouraud_highlight(void) { if(lightchanged[UPDATE_OGL]) { glLightfv(GL_LIGHT0, GL_POSITION, lightpos); lightchanged[UPDATE_OGL] = GL_FALSE; } glPushAttrib(GL_LIGHTING); glPushMatrix(); /* assuming modelview */ glTranslatef(objpos[X], objpos[Y], 0.f); /* translate object */ glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */ glRotatef(objangle[Y], 1.f, 0.f, 0.f); glClearColor(.1f, .1f, .1f, 1.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glClearColor(0.f, 0.f, 0.f, 1.f); /* draw the specular highlight */ glEnable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glMaterialfv(GL_FRONT, GL_SPECULAR, color); /* turn on ogl highlights */ glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); /* turn off ogl diffuse */ glMaterialfv(GL_FRONT, GL_AMBIENT, zero); /* turn off ogl diffuse */ /* draw the specular highlight */ glCallList(object); glEnable(GL_TEXTURE_2D); glPopMatrix(); /* assuming modelview */ glPopAttrib(); CHECK_ERROR("OpenGL Error in redraw_tex()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* show highlight texture map */ void redraw_map(void) { if(lightchanged[UPDATE_TEX]) { makeHighlight(128); lightchanged[UPDATE_TEX] = GL_FALSE; } glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX); glDisable(GL_LIGHTING); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, -1); glTexCoord2i(1, 0); glVertex2i(1, -1); glTexCoord2i(1, 1); glVertex2i(1, 1); glTexCoord2i(0, 1); glVertex2i(-1, 1); glEnd(); glEnable(GL_LIGHTING); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); CHECK_ERROR("OpenGL Error in redraw_map()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* multipass, use texture to make highlight */ void redraw_tex(void) { if(lightchanged[UPDATE_TEX]) { makeHighlight(128); lightchanged[UPDATE_TEX] = GL_FALSE; } if(lightchanged[UPDATE_OGL]) { glLightfv(GL_LIGHT0, GL_POSITION, lightpos); lightchanged[UPDATE_OGL] = GL_FALSE; } glPushMatrix(); /* assuming modelview */ glTranslatef(objpos[X], objpos[Y], 0.f); /* translate object */ glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */ glRotatef(objangle[Y], 1.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /* draw the diffuse portion of the light */ glEnable(GL_LIGHTING); glBindTexture(GL_TEXTURE_2D, SURF_TEX); if(notex) glDisable(GL_TEXTURE_2D); glCallList(object); if(notex) glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); /* draw the specular highlight */ glEnable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, HIGHLIGHT_TEX); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glDepthFunc(GL_LEQUAL); glCallList(object); glDepthFunc(GL_LESS); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_BLEND); glPopMatrix(); /* assuming modelview */ CHECK_ERROR("OpenGL Error in redraw_tex()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* multipass; use opengl to make highlight */ void redraw_phong(void) { if(lightchanged[UPDATE_OGL]) { glLightfv(GL_LIGHT0, GL_POSITION, lightpos); lightchanged[UPDATE_OGL] = GL_FALSE; } glPushAttrib(GL_LIGHTING); glPushMatrix(); /* assuming modelview */ glTranslatef(objpos[X], objpos[Y], 0.f); /* translate object */ glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */ glRotatef(objangle[Y], 1.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /* draw the diffuse portion of the light */ glEnable(GL_LIGHTING); glBindTexture(GL_TEXTURE_2D, SURF_TEX); if(notex) glDisable(GL_TEXTURE_2D); glCallList(object); if(notex) glEnable(GL_TEXTURE_2D); /* turn off texturing so phong highlight color is pure */ glDisable(GL_TEXTURE_2D); glMaterialfv(GL_FRONT, GL_SPECULAR, color); /* turn on ogl highlights */ glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); /* turn off ogl diffuse */ glMaterialfv(GL_FRONT, GL_AMBIENT, zero); /* turn off ogl diffuse */ /* draw the specular highlight */ glEnable(GL_BLEND); glDepthFunc(GL_LEQUAL); glCallList(object); glEnable(GL_TEXTURE_2D); glDepthFunc(GL_LESS); glDisable(GL_BLEND); glPopMatrix(); /* assuming modelview */ glPopAttrib(); CHECK_ERROR("OpenGL Error in redraw_tex()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* Use OpenGL lighting to get highlight */ void redraw_original(void) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); /* assuming modelview */ glTranslatef(objpos[X], objpos[Y], 0.f); /* translate object */ glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */ glRotatef(objangle[Y], 1.f, 0.f, 0.f); if(lightchanged[UPDATE_OGL]) { glLightfv(GL_LIGHT0, GL_POSITION, lightpos); lightchanged[UPDATE_OGL] = GL_FALSE; } glEnable(GL_LIGHTING); glBindTexture(GL_TEXTURE_2D, SURF_TEX); glMaterialfv(GL_FRONT, GL_SPECULAR, color); /* turn on ogl highlights */ if(notex) glDisable(GL_TEXTURE_2D); glCallList(object); if(notex) glEnable(GL_TEXTURE_2D); glMaterialfv(GL_FRONT, GL_SPECULAR, zero); glDisable(GL_LIGHTING); glPopMatrix(); /* assuming modelview */ CHECK_ERROR("OpenGL Error in redraw()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* Draw with no highlight */ void redraw_diffuse(void) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); /* assuming modelview */ glTranslatef(objpos[X], objpos[Y], 0.f); /* translate object */ glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */ glRotatef(objangle[Y], 1.f, 0.f, 0.f); if(lightchanged[UPDATE_OGL]) { glLightfv(GL_LIGHT0, GL_POSITION, lightpos); lightchanged[UPDATE_OGL] = GL_FALSE; } /* draw the diffuse portion of the light */ glEnable(GL_LIGHTING); glBindTexture(GL_TEXTURE_2D, SURF_TEX); glCallList(object); glDisable(GL_LIGHTING); glPopMatrix(); /* assuming modelview */ CHECK_ERROR("OpenGL Error in redraw()"); if(dblbuf) glutSwapBuffers(); else glFlush(); } /* ARGSUSED1 */ void key(unsigned char key, int x, int y) { switch(key) { case 'u': /* unmodified highlight */ printf("Use unmodified gouraud highlight\n"); glutDisplayFunc(redraw_original); glutPostRedisplay(); break; case 'd': printf("Draw diffuse only\n"); glutDisplayFunc(redraw_diffuse); glutPostRedisplay(); break; case 'g': /* separate gouraud shaded highlight */ printf("Use separate gouraud shaded highlight\n"); glutDisplayFunc(redraw_phong); glutPostRedisplay(); break; case 't': /* separate textured highlight */ printf("Use separate texture highlight\n"); glutDisplayFunc(redraw_tex); glutPostRedisplay(); break; case 'o': /* toggle object type */ object++; if(object > maxobject) object = 2; glutPostRedisplay(); break; case 'm': /* show highlight texture map */ printf("Show highlight texture map\n"); glutDisplayFunc(redraw_map); glutPostRedisplay(); break; case 'n': if(notex) notex = FALSE; else notex = TRUE; glutPostRedisplay(); break; case 'h': printf("Show textured phong highlight\n"); glutDisplayFunc(redraw_tex_highlight); glutPostRedisplay(); break; case 'p': printf("Show gouraud-shaded phong highlight\n"); glutDisplayFunc(redraw_gouraud_highlight); glutPostRedisplay(); break; case 'w': printf("Show white object\n"); glutDisplayFunc(redraw_white); glutPostRedisplay(); break; case '\033': exit(0); break; default: fprintf(stderr, "Keyboard commands:\n\n" "u - (unmodified opengl lighting)\n" "d - diffuse only\n" "g - multipass gouraud highlight\n" "t - multipass texture highlight\n" "o - toggle object\n" "m - show highlight texture map\n" "n - toggle surface texturing\n" "h - show textured phong highlight\n" "p - show gouraud-shaded phong highlight\n" "w - show unlit white object\n"); break; } } main(int argc, char *argv[]) { GLuint *tex; int texwid, texht, texcomps; GLUquadricObj *quadric; glutInitWindowSize(winWidth, winHeight); glutInit(&argc, argv); if(argc > 1) { char *args = argv[1]; int done = FALSE; while(!done) { switch(*args) { case 's': /* single buffer */ printf("Single Buffered\n"); dblbuf = FALSE; break; case '-': /* do nothing */ break; case 0: done = TRUE; break; } args++; } } if(dblbuf) glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE); else glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH); (void)glutCreateWindow("example program"); glutDisplayFunc(redraw_original); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMotionFunc(motion); glutKeyboardFunc(key); /* draw a perspective scene */ glMatrixMode(GL_PROJECTION); glFrustum(-100., 100., -100., 100., 300., 600.); glMatrixMode(GL_MODELVIEW); /* look at scene from (0, 0, 450) */ gluLookAt(0., 0., 450., 0., 0., 0., 0., 1., 0.); /* turn on features */ glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glMateriali(GL_FRONT, GL_SHININESS, 128); /* cosine power */ /* remove back faces to speed things up */ glCullFace(GL_BACK); glBlendFunc(GL_ONE, GL_ONE); lightchanged[UPDATE_TEX] = GL_TRUE; lightchanged[UPDATE_OGL] = GL_TRUE; /* load pattern for current 2d texture */ tex = read_texture("data/wood0.rgb", &texwid, &texht, &texcomps); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, texwid, texht, GL_RGBA, GL_UNSIGNED_BYTE, tex); free(tex); CHECK_ERROR("end of main"); lighttex = (GLfloat *)malloc(texdim * texdim * sizeof(GL_FLOAT) * 3); /* XXX TODO use display list to avoid retesselating */ glNewList(1, GL_COMPILE); glutSolidSphere((GLdouble)texdim/2., 50, 50); glEndList(); glNewList(2, GL_COMPILE); glutSolidTeapot(70.); glEndList(); quadric = gluNewQuadric(); gluQuadricTexture(quadric, GL_TRUE); glNewList(3, GL_COMPILE); gluSphere(quadric, 70., 20, 20); glEndList(); gluDeleteQuadric(quadric); maxobject = 3; glutMainLoop(); return 0; }