/* * GLUT demonstration of texturing with specular highlights. * * When drawing a lit, textured surface one usually wants the specular * highlight to override the texture colors. However, OpenGL applies * texturing after lighting so the specular highlight is modulated by * the texture. * * The solution here shown here is a two-pass algorithm: * 1. Draw the textured surface without specular lighting. * 2. Enable blending to add the next pass: * 3. Redraw the surface with a matte white material and only the * specular components of light sources enabled. * * Brian Paul February 1997 */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <GL/glut.h> static GLUquadricObj *Quadric; static GLuint Sphere; static GLfloat LightPos[4] = {10.0, 10.0, 10.0, 1.0}; static GLfloat Delta = 20.0; static GLint Mode = 4; /*static GLfloat Blue[4] = {0.0, 0.0, 1.0, 1.0};*/ /*static GLfloat Gray[4] = {0.5, 0.5, 0.5, 1.0};*/ static GLfloat Black[4] = {0.0, 0.0, 0.0, 1.0}; static GLfloat White[4] = {1.0, 1.0, 1.0, 1.0}; static GLboolean smooth = 1; static void Idle(void) { static double t0 = -1.; double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;; if (t0 < 0.0) t0 = t; dt = t - t0; t0 = t; LightPos[0] += Delta * dt; if (LightPos[0]>15.0 || LightPos[0]<-15.0) Delta = -Delta; glutPostRedisplay(); } static void Display( void ) { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glLightfv(GL_LIGHT0, GL_POSITION, LightPos); glPushMatrix(); glRotatef(90.0, 1.0, 0.0, 0.0); if (Mode==0) { /* Typical method: diffuse + specular + texture */ glEnable(GL_TEXTURE_2D); glLightfv(GL_LIGHT0, GL_DIFFUSE, White); /* enable diffuse */ glLightfv(GL_LIGHT0, GL_SPECULAR, White); /* enable specular */ #ifdef GL_VERSION_1_2 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); #endif glCallList(Sphere); } else if (Mode==1) { /* just specular highlight */ glDisable(GL_TEXTURE_2D); glLightfv(GL_LIGHT0, GL_DIFFUSE, Black); /* disable diffuse */ glLightfv(GL_LIGHT0, GL_SPECULAR, White); /* enable specular */ #ifdef GL_VERSION_1_2 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); #endif glCallList(Sphere); } else if (Mode==2) { /* diffuse textured */ glEnable(GL_TEXTURE_2D); glLightfv(GL_LIGHT0, GL_DIFFUSE, White); /* enable diffuse */ glLightfv(GL_LIGHT0, GL_SPECULAR, Black); /* disable specular */ #ifdef GL_VERSION_1_2 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); #endif glCallList(Sphere); } else if (Mode==3) { /* 2-pass: diffuse textured then add specular highlight*/ glEnable(GL_TEXTURE_2D); glLightfv(GL_LIGHT0, GL_DIFFUSE, White); /* enable diffuse */ glLightfv(GL_LIGHT0, GL_SPECULAR, Black); /* disable specular */ #ifdef GL_VERSION_1_2 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); #endif glCallList(Sphere); /* specular highlight */ glDepthFunc(GL_EQUAL); /* redraw same pixels */ glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); /* add */ glLightfv(GL_LIGHT0, GL_DIFFUSE, Black); /* disable diffuse */ glLightfv(GL_LIGHT0, GL_SPECULAR, White); /* enable specular */ glCallList(Sphere); glDepthFunc(GL_LESS); glDisable(GL_BLEND); } else if (Mode==4) { /* OpenGL 1.2's separate diffuse and specular color */ glEnable(GL_TEXTURE_2D); glLightfv(GL_LIGHT0, GL_DIFFUSE, White); /* enable diffuse */ glLightfv(GL_LIGHT0, GL_SPECULAR, White); /* enable specular */ #ifdef GL_VERSION_1_2 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); #endif glCallList(Sphere); } glPopMatrix(); glutSwapBuffers(); } static void Reshape( int width, int height ) { glViewport( 0, 0, width, height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, -12.0 ); } static void Key( unsigned char key, int x, int y ) { (void) x; (void) y; switch (key) { case 27: exit(0); break; case 's': smooth = !smooth; if (smooth) glShadeModel(GL_SMOOTH); else glShadeModel(GL_FLAT); break; } glutPostRedisplay(); } static void SpecialKey( int key, int x, int y ) { (void) x; (void) y; switch (key) { case GLUT_KEY_UP: break; case GLUT_KEY_DOWN: break; } glutPostRedisplay(); } static void Init( void ) { int i, j; GLubyte texImage[64][64][3]; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Black); glShadeModel(GL_SMOOTH); glMaterialfv(GL_FRONT, GL_DIFFUSE, White); glMaterialfv(GL_FRONT, GL_SPECULAR, White); glMaterialf(GL_FRONT, GL_SHININESS, 20.0); /* Actually, these are set again later */ glLightfv(GL_LIGHT0, GL_DIFFUSE, White); glLightfv(GL_LIGHT0, GL_SPECULAR, White); Quadric = gluNewQuadric(); gluQuadricTexture( Quadric, GL_TRUE ); Sphere= glGenLists(1); glNewList( Sphere, GL_COMPILE ); gluSphere( Quadric, 1.0, 24, 24 ); glEndList(); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); for (i=0;i<64;i++) { for (j=0;j<64;j++) { int k = ((i>>3)&1) ^ ((j>>3)&1); texImage[i][j][0] = 255*k; texImage[i][j][1] = 255*(1-k); texImage[i][j][2] = 0; } } glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D( GL_TEXTURE_2D, 0, 3, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, texImage ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnable(GL_TEXTURE_2D); glBlendFunc(GL_ONE, GL_ONE); } static void ModeMenu(int entry) { if (entry==99) exit(0); Mode = entry; } int main( int argc, char *argv[] ) { glutInitWindowSize( 300, 300 ); glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); glutCreateWindow( "spectex" ); Init(); glutReshapeFunc( Reshape ); glutKeyboardFunc( Key ); glutSpecialFunc( SpecialKey ); glutDisplayFunc( Display ); glutIdleFunc( Idle ); glutCreateMenu( ModeMenu ); glutAddMenuEntry("1-pass lighting + texturing", 0); glutAddMenuEntry("specular lighting", 1); glutAddMenuEntry("diffuse lighting + texturing", 2); glutAddMenuEntry("2-pass lighting + texturing", 3); #ifdef GL_VERSION_1_2 glutAddMenuEntry("OpenGL 1.2 separate specular", 4); #endif glutAddMenuEntry("Quit", 99); glutAttachMenu(GLUT_RIGHT_BUTTON); glutMainLoop(); return 0; }