/***************************************************************************/ /* This is a simple demo program written for CS 184 by Ravi Ramamoorthi */ /* This program corresponds to the third OpenGL lecture. */ /* It builds on the program written in the first and second lectures. */ /* */ /* This version adds lighting to the teapot, much as in homework 1 */ /* The intent is to just show you how to add lighting effects... */ /* Much of the subtleties of how they work is covered in class and in */ /* Nate Robbins' OpenGL tutorials, also shown in class */ /***************************************************************************/ /**************************************************************************/ /* INCREMENTAL STEPS FROM SECOND DEMO RELATIVE TO THE FIRST DEMO */ /* 0. Add global for pillar display list, change floor to white */ /* 1. Init includes a Display list for the pillars with GLu */ /* 2. Draw 4 pillars by using matrix stacks */ /* - See if order matters by moving floor to the end. */ /* 3. Add depth test with Z-buffering */ /* 4. Add animation routines for teapot (add double buffering) */ /* 5. Texture map the floor */ /**************************************************************************/ #include #include // ** NEW ** for loading the texture #include #include // ** NEW ** for errors int mouseoldx, mouseoldy ; // For mouse motion GLdouble eyeloc = 2.0 ; // Where to look from; initially 0 -2, 2 GLuint pillar ; // ** NEW ** For the display list for the pillars GLint animate = 0 ; // ** NEW ** whether to animate or not GLdouble teapotloc = -0.5 ; // ** NEW ** where the teapot is located GLubyte woodtexture[256][256][3] ; // ** NEW ** texture (from grsites.com) GLuint texName ; // ** NEW ** for texture GLenum err ; // ** NEW ** for errors GLint smooth = 1 ; // ** NEW DEMO 3, toggle smooth/flat shading void display(void) { /* clear all pixels */ /* ** New for demo 2, to handle depth ** */ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw white polygon (square) of unit length centered at the origin // Note that vertices must generally go counterclockwise /* ** Change from demo 1 **, in that I just made it white */ /* Does the order of drawing matter? What happens if I draw the ground after the pillars? I will show this in class */ /* glColor3f(1.0,1.0,1.0) ; glBegin(GL_POLYGON); glVertex3f (0.5, 0.5, 0.0); glVertex3f (-0.5, 0.5, 0.0); glVertex3f (-0.5, -0.5, 0.0); glVertex3f (0.5, -0.5, 0.0); glEnd(); */ /* ** New for OpenGL2 **, Add some more geometry */ /* Note the use of matrix stacks and push and pop */ glMatrixMode(GL_MODELVIEW) ; /* Draw first pillar by Translating */ glPushMatrix() ; glTranslatef(0.4, 0.4, 0.0) ; glColor3f(1.0, 1.0, 0.0) ; glCallList(pillar) ; glPopMatrix() ; /* Draw second pillar by Translating */ glPushMatrix() ; glTranslatef(-0.4, 0.4, 0.0) ; glColor3f(1.0, 0.0, 0.0) ; glCallList(pillar) ; glPopMatrix() ; /* Draw third pillar by Translating */ glPushMatrix() ; glTranslatef(-0.4, -0.4, 0.0) ; glColor3f(0.0, 1.0, 0.0) ; glCallList(pillar) ; glPopMatrix() ; /* Draw fourth pillar by Translating */ glPushMatrix() ; glTranslatef(0.4, -0.4, 0.0) ; glColor3f(0.0, 0.0, 1.0) ; glCallList(pillar) ; glPopMatrix() ; // draw white polygon (square) of unit length centered at the origin // Note that vertices must generally go counterclockwise /* ** Change from opengl1 **, in that I just made it white */ /* Does the order of drawing matter? What happens if I draw the ground after the pillars? I will show this in class */ /* glColor3f(1.0,1.0,1.0) ; glBegin(GL_POLYGON); glVertex3f (0.5, 0.5, 0.0); glVertex3f (-0.5, 0.5, 0.0); glVertex3f (-0.5, -0.5, 0.0); glVertex3f (0.5, -0.5, 0.0); glEnd(); */ /* As a final step, I modify this for texture mapping * NEW * */ /* Consult chapter 9 for the explanation of the various options */ /* Note addition of texture coordinates, and the glue to add texturing */ /* Also note some effort to find the error if any */ glEnable(GL_TEXTURE_2D) ; glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) ; glBindTexture(GL_TEXTURE_2D, texName) ; glColor3f(1.0,1.0,1.0) ; err = glGetError() ; assert(err == GL_NO_ERROR) ; glBegin(GL_POLYGON) ; glTexCoord2f(1.0, 1.0) ; glVertex3f (0.5, 0.5, 0.0); glTexCoord2f(0.0,1.0) ; glVertex3f (-0.5, 0.5, 0.0); glTexCoord2f(0.0,0.0); glVertex3f (-0.5, -0.5, 0.0); glTexCoord2f(1.0,0.0) ; glVertex3f (0.5, -0.5, 0.0); glEnd() ; err = glGetError() ; assert(err == GL_NO_ERROR) ; glDisable(GL_TEXTURE_2D) ; /* New for Demo 3; add lighting effects */ /* See hw1 and the red book (chapter 5) for details */ { GLfloat one[] = {1, 1, 1, 1}; // GLfloat small[] = {0.2, 0.2, 0.2, 1}; GLfloat medium[] = {0.5, 0.5, 0.5, 1}; GLfloat small[] = {0.2, 0.2, 0.2, 1}; GLfloat high[] = {100}; GLfloat light_specular[] = {1, 0.5, 0, 1}; GLfloat light_specular1[] = {0, 0.5, 1, 1}; GLfloat light_position[] = {0.5, 0, 0, 1}; GLfloat light_position1[] = {0, -0.5, 0, 1}; /* Set Material properties for the teapot */ glMaterialfv(GL_FRONT, GL_AMBIENT, one); glMaterialfv(GL_FRONT, GL_SPECULAR, one); glMaterialfv(GL_FRONT, GL_DIFFUSE, medium); glMaterialfv(GL_FRONT, GL_SHININESS, high); /* Set up point lights, Light 0 and Light 1 */ /* Note that the other parameters are default values */ glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT0, GL_DIFFUSE, small); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular1); glLightfv(GL_LIGHT1, GL_DIFFUSE, medium); glLightfv(GL_LIGHT1, GL_POSITION, light_position1); /* Enable and Disable everything around the teapot */ /* Generally, we would also need to define normals etc. */ /* But glut already does this for us */ glEnable(GL_LIGHTING) ; glEnable(GL_LIGHT0) ; glEnable(GL_LIGHT1) ; if (smooth) glShadeModel(GL_SMOOTH) ; else glShadeModel(GL_FLAT) ; } /* ** NEW ** Put a teapot in the middle that animates */ glColor3f(0.0,1.0,1.0) ; glPushMatrix() ; /* I now transform by the teapot translation for animation */ glTranslatef(teapotloc, 0.0, 0.0) ; /* The following two transforms set up and center the teapot */ /* Remember that transforms right-multiply the stack */ glTranslatef(0.0,0.0,0.1) ; glRotatef(90.0,1.0,0.0,0.0) ; glutSolidTeapot(0.15) ; glDisable(GL_LIGHTING) ; // ** NEW for Demo 3 ** only light teapot glPopMatrix() ; /* don't wait! * start processing buffered OpenGL routines */ glutSwapBuffers() ; glFlush (); } /* ** NEW ** in this assignment, is an animation of a teapot */ /* Hitting p will pause this animation; see keyboard callback */ void animation(void) { teapotloc = teapotloc + 0.005 ; if (teapotloc > 0.5) teapotloc = -0.5 ; glutPostRedisplay() ; } /* Defines a Mouse callback to zoom in and out */ /* This is done by modifying gluLookAt */ /* The actual motion is in mousedrag */ /* mouse simply sets state for mousedrag */ void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON) { if (state == GLUT_UP) { // Do Nothing ; } else if (state == GLUT_DOWN) { mouseoldx = x ; mouseoldy = y ; // so we can move wrt x , y } } else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { // Reset gluLookAt eyeloc = 2.0 ; glMatrixMode(GL_MODELVIEW) ; glLoadIdentity() ; gluLookAt(0,-eyeloc,eyeloc,0,0,0,0,1,1) ; glutPostRedisplay() ; } } void mousedrag(int x, int y) { int yloc = y - mouseoldy ; // We will use the y coord to zoom in/out eyeloc += 0.005*yloc ; // Where do we look from if (eyeloc < 0) eyeloc = 0.0 ; mouseoldy = y ; /* Set the eye location */ glMatrixMode(GL_MODELVIEW) ; glLoadIdentity() ; gluLookAt(0,-eyeloc,eyeloc,0,0,0,0,1,1) ; glutPostRedisplay() ; } /* Defines what to do when various keys are pressed */ void keyboard (unsigned char key, int x, int y) { switch (key) { case 27: // Escape to quit exit(0) ; break ; case 'p': // ** NEW ** to pause/restart animation animate = !animate ; if (animate) glutIdleFunc(animation) ; else glutIdleFunc(NULL) ; break ; case 's': // ** NEW DEMO 3 ** Toggle flat/smooth shading smooth = !smooth ; glutPostRedisplay() ; break ; default: break ; } } /* Reshapes the window appropriately */ void reshape(int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Think about the rationale for this choice for gluPerspective // What would happen if you changed near and far planes? gluPerspective(30.0, (GLdouble)w/(GLdouble)h, 1.0, 10.0) ; } void init (void) { FILE *fp ; int i,j,k ; // For the texture ** NEW ** GLUquadricObj * cyl ; // For the cylinder new quadric ** NEW ** /* select clearing color */ glClearColor (0.0, 0.0, 0.0, 0.0); /* initialize viewing values */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Think about this. Why is the up vector not normalized? glMatrixMode(GL_MODELVIEW) ; glLoadIdentity() ; gluLookAt(0,-eyeloc,eyeloc,0,0,0,0,1,1) ; /* ** NEW for demo 2 ** Some new primitives that I added */ /* This uses gluCylinder. The glu primitives are sometimes useful */ /* The GLU library is described in chapter 11. We need only a small */ /* part of it. */ cyl = gluNewQuadric() ; /* This part sets up a display list for the pillars. Refer to chapter 7 for more details */ pillar = glGenLists(1) ; glNewList(pillar, GL_COMPILE) ; gluCylinder (cyl, 0.1, 0.1, .5, 10, 10) ; glEndList() ; /* ** New for demo 2 ** enable depth test */ glEnable(GL_DEPTH_TEST) ; glDepthFunc(GL_LESS) ; // The default option /* ** New for demo 2 ** setup for textures */ /* First, read this simple ppm file in */ assert(fp = fopen("wood.ppm","rb")) ; fscanf(fp,"%*s %*d %*d %*d%*c") ; for (i = 0 ; i < 256 ; i++) for (j = 0 ; j < 256 ; j++) for (k = 0 ; k < 3 ; k++) fscanf(fp,"%c",&(woodtexture[i][j][k])) ; fclose(fp) ; /* Now, set up all the stuff for texturing, per page 368 */ glGenTextures(1, &texName) ; glBindTexture(GL_TEXTURE_2D, texName) ; 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,GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, woodtexture) ; } int main(int argc, char** argv) { glutInit(&argc, argv); // Requests the type of buffers (Single, RGB). // Think about what buffers you would need... /* ** NEW for demo 2, request depth, later switch to double buffer ** */ glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow ("Simple Demo"); init (); // Always initialize first // Now, we define callbacks and functions for various tasks. glutDisplayFunc(display); glutReshapeFunc(reshape) ; glutKeyboardFunc(keyboard); glutMouseFunc(mouse) ; glutMotionFunc(mousedrag) ; glutMainLoop(); // Start the main code return 0; /* ANSI C requires main to return int. */ }