// FILE: tex_spotlightdemo.cpp // Tylene S. Garrett // February 1, 2003 // // Demonstrates using a spotlight on a textured surface // Underlying surface material is bright white // Recursively subdivides texture as well as surface // // KEYS: // +/- : increases/decreases level of recursive subdivisions // PageUp/PageDown: increases/decreases cutoff angle // Arrow keys: move spotlight left, right, up, down // r: red spotlight // g: green spotlight // b: blue spotlight // w: white spotlight (default) // B: black spotlight #include #include #include //Info needed for the images: GLubyte myImage256[256][256][4]; GLuint texName[2]; long depth = 0; //used for level of recursion // The vertices of the square: float s1[3] = {-1.0, -1.0, 0.0}; float s2[3] = {1.0, -1.0, 0.0}; float s3[3] = {1.0, 1.0, 0.0}; float s4[3] = {-1.0, 1.0, 0.0}; // The vertices of the texture map: float t1[2] = {0.0, 0.0}; float t2[2] = {1.0, 0.0}; float t3[2] = {1.0, 1.0}; float t4[2] = {0.0, 1.0}; // The face normal: float norm[3] = {0.0, 0.0, 1.0}; float cutoff_angle = 15.0; //GLOBAL VARIABLES FOR LIGHT0: GLfloat diff_red, diff_green, diff_blue; //diffuse GLfloat x_dir = 0.0, y_dir = 0.0; void loadImages(); void init(); void display(); void scene(); void drawtriangle(float v1[3], float v2[3], float v3[3], float t1[2], float t2[2], float t3[2]); void subdivide(float v1[3], float v2[3], float v3[3], float t1[2], float t2[2], float t3[2], long depth); void drawsurface(); void definelight(); void reshape (int w, int h); void keyboard(unsigned char key, int x, int y); void mykeys(int key, int x, int y); int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize (600, 600); glutInitWindowPosition (10, 10); glutCreateWindow ("Demo Keys: +/- level recursion, PageUp/Down cutoff angle, arrow keys move spotlight"); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutSpecialFunc(mykeys); glutMainLoop(); return 0; } void init() { glClearColor (0.0, 0.0, 0.0, 0.0); //Define the material: GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat mat_shininess[] = { 100.0 }; glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); //light diff_red = 1.0; diff_green = 1.0; diff_blue = 1.0; //Global Ambient Light: GLfloat lmodel_ambient[] = { 1.0, 1.0, 1.0, 1.0}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); //override default loadImages(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //Generate the "name" for the texture maps (0): glGenTextures(1,texName); //Bind these parameters to texture 0, the image file: glBindTexture(GL_TEXTURE_2D, texName[0]); 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_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, myImage256); glShadeModel (GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void definelight() { //Define the light: GLfloat light0_ambient[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light0_diffuse[] = {diff_red, diff_green, diff_blue, 1.0}; GLfloat light0_specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat light0_position[] = {0.0, 0.0,2.0, 1.0}; //positional GLfloat spot_direction[] = {x_dir, y_dir, -1.0}; //down the neg. z-axis glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, cutoff_angle); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction); glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 5.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } void drawtriangle(float v1[3], float v2[3], float v3[3], float t1[2], float t2[2], float t3[2]) // Draws the triangle with assigned texture coordinates { glNormal3f(0.0, 0.0, 1.0); glBegin(GL_POLYGON); glTexCoord2fv(t1);glVertex3fv(v1); glTexCoord2fv(t2);glVertex3fv(v2); glTexCoord2fv(t3);glVertex3fv(v3); glEnd(); } void subdivide(float v1[3], float v2[3], float v3[3],float t1[2], float t2[2], float t3[2], long depth) // Recursively subdivides the triangle to given depth { GLfloat v12[3], v23[3], v31[3]; //vertex coordinates GLfloat t12[2], t23[2], t31[2]; //texture coordinates GLint i; if (depth == 0) { drawtriangle(v1, v2, v3, t1, t2, t3); return; } for (i=0; i<3; i++) { v12[i] = (v1[i]+v2[i])/2.0; v23[i] = (v2[i]+v3[i])/2.0; v31[i] = (v3[i]+v1[i])/2.0; } for(i=0; i<2; i++) { t12[i] = (t1[i] + t2[i])/2.0; t23[i] = (t2[i] + t3[i])/2.0; t31[i] = (t3[i] + t1[i])/2.0; } subdivide(v1, v12, v31, t1, t12, t31, depth-1); subdivide(v2, v23, v12, t2, t23, t12, depth-1); subdivide(v3, v31, v23, t3, t31, t23, depth-1); subdivide(v12,v23, v31, t12,t23, t31, depth-1); } void drawsurface() // Draws the square by subdividing into two triangular regions { subdivide(s1, s2, s3, t1, t2, t3, depth); subdivide(s1, s4, s3, t1, t4, t3, depth); } void scene() { glPushMatrix(); glRotated(-90, 0.0, 0.0, 1.0); //because image is not right side up when loaded drawsurface(); glPopMatrix(); } void display(void) { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); definelight(); scene(); glutSwapBuffers(); } void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity(); // Orthogonal projection: if (w <= h) glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'r': //red light diff_red = 1.0; diff_green = 0.0; diff_blue = 0.0; glutPostRedisplay(); break; case 'b': //blue light diff_red = 0.0; diff_green = 0.0; diff_blue = 1.0; glutPostRedisplay(); break; case 'g': //green light diff_red = 0.0; diff_green = 1.0; diff_blue = 0.0; glutPostRedisplay(); break; case 'w': //white light diff_red = 1.0; diff_green = 1.0; diff_blue = 1.0; glutPostRedisplay(); break; case 'B': //black light diff_red = 0.0; diff_green = 0.0; diff_blue = 0.0; glutPostRedisplay(); break; case 27: // ESC key exit(0); break; case 45: //- key depth = depth - 1; if (depth < 0) depth = 0; glutPostRedisplay(); break; case 43: //+ key depth = depth+ 1; if (depth > 8) depth = 8; glutPostRedisplay(); break; } } void mykeys(int key, int x, int y) { switch(key){ case GLUT_KEY_PAGE_DOWN: if (cutoff_angle >=45.0) cutoff_angle = cutoff_angle - 10; else cutoff_angle = cutoff_angle - 1.0; glutPostRedisplay(); break; case GLUT_KEY_PAGE_UP: if (cutoff_angle >=45.0) cutoff_angle = cutoff_angle + 10; else cutoff_angle = cutoff_angle + 1.0; glutPostRedisplay(); break; case GLUT_KEY_LEFT: //move spotlight left x_dir = x_dir - 0.1; glutPostRedisplay(); break; case GLUT_KEY_RIGHT: //move spotlight right x_dir = x_dir + 0.1; glutPostRedisplay(); break; case GLUT_KEY_DOWN: //move spotlight down y_dir = y_dir - 0.1; glutPostRedisplay(); break; case GLUT_KEY_UP: //move spotlight up y_dir = y_dir + 0.1; glutPostRedisplay(); break; } } void loadImages() { int i, j, c; ifstream infile; // infile.open("sunrise_256.ppm"); infile.open("wood_256x256.ppm"); // infile.open("brick1_256x256.ppm"); // infile.open("shingle_256x256.ppm"); for (j = 0; j < 256; j++) { for (i = 0; i < 256; i++) { infile>>c; myImage256[i][j][0] = (GLubyte) c; infile>>c; myImage256[i][j][1] = (GLubyte) c; infile>>c; myImage256[i][j][2] = (GLubyte) c; myImage256[i][j][3] = (GLubyte) 255; } } infile.close(); }