/* The code below is based on the 2D equilateral triangle code from the last question of Exam 01. Notice that the vertices of the triangle are hardcoded (it's on purpose...). 1. First, describe in this comment, what modifications you would make to cause the the triangle to spin. Note, you do NOT need to program this yet. Just assume that you would do this by modifying the vertex definitions. Try to be specific, and in addition to updating the vertices, what would you do with buffering and animation. THE VERTICES WOULD DEPEND ON SOME ANGLE THETA, SO AS THETA IS INCREASED, THE VERTICES WOULD CHANGE ACCORDINGLY. THIS GEOMETRIC DERIVATION WOULD BE A LOT OF WORK, SO LUCKILY THERE IS AN EASIER WAY (SEE GLROTATEF() BELOW). IN ADDITION, DOUBLE BUFFEREING WOULD NEED TO BE TURNED ON (ENABLED IN MAIN, GLUTSWAPBUFFERS USED, ALONG WITH AN IDLE FUNCTION). THE IDLE FUNCTION WOULD NEED SOME MECHANISM, PROBABLY VIA MOUSECLICK, TO BE TOGGLED ON AND OFF. 2. Now, we'll consider an easier way to make the triangle spin, by using one of OpenGL's modelview transforms. In particular, we can use the glRotatef() call. Take a moment and look up the glRotatef() call, either in your text, the OpenGL web-site, or via Google. Don't peek... Ok, now that you're back, you probably read that there are several versions of glRotate. The one we will use is glRotatef. In it, we need to specify an angle and an axis to rotate around. Since we're in 2D, the axis we rotate around is pretty easy to determine. Our triangle is in the x-y plane, and we're looking down at it along the z-axis. So we want to rotate along the z-axis. You'll want to think about how to "ask" for the z-axis in the call to glRotatef(). The other thing to consider is what angle to use. In this case, glRotatef() requires the angles in radians, so if you think in degrees, you'll need to scale your angle with 2.0*PI/360.0. So in the line below this one, in the comments, type what you think your glRotatef() call will look like. Oh, note that a global variable, theta, is provided. You can define your angle there. theta will then be used in #5, so the speed of rotation can be controlled. theta = 5.0 * 2*PI/360; glRotatef( theta , 0 , 0 , 1 ); 3. In order to modify your code to incorporate the rotate, you need to create an idle routine, as well as some mechanisim to toggle this idle function on and off. In this case, create an idle routine, as well as a menu, which has three options intially: (1)quit (2)spin (3)stop spinning. Don't forget "smooth" animation with double buffering too. 4. Once your rotate is working, create a reshape function which will preserve the aspect ratio of the triangle, and show all of it, when the window is resized. 5. And for your last improvement, modify your menu, so the spin menu has a submenu with options: (1)fast (2)slow You can simply set different theta angles. */ #include #include #include #define WINDOW 300 // we will define PI to help calculate an angle for rotation GLdouble PI=4.0*atan(1.0); // // #3 // // the angle of rotation, theta, can be global variable, which // will allow us to change the rate of rotation. Initial value // will be 5 degrees, or 5*2*PI/360. GLdouble theta = 10.0*PI/360.0; // set up background color and clipping window here void myInit() { glClearColor( 0, 0, 0, 0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D( -WINDOW/2.0, WINDOW/2.0, -WINDOW/2.0, WINDOW/2.0); glMatrixMode(GL_MODELVIEW); } // // #3 // void spinDisplay() { // rotate the triangle theta radians (degrees *PI/360), along which z-axis glRotatef( theta , 0 ,0 , 1 ); glutPostRedisplay(); } // // #3 // void menu (GLint id) { switch (id) { case 1: exit(0); break; case 2: glutIdleFunc(spinDisplay); break; case 3: glutIdleFunc(NULL); break; } } // // #5 // void menu01 (GLint id) { switch (id) { case 3: //theta += 2*2.0*PI/360.0; theta = 20*2.0*PI/360.0; break; case 4: //theta -= 2*2.0*PI/360.0; theta = 2.0*PI/360.0; break; case 2: break; } glutIdleFunc(spinDisplay); } // // #5 // void menu02 (GLint id) { switch (id) { case 1: exit(0); break; case 5: glutIdleFunc(NULL); break; } } void display() { glClear( GL_COLOR_BUFFER_BIT ); // the definition of the triangle can be hardcoded glBegin( GL_POLYGON ); glColor3f(1,0,0); glVertex2f( 87 , -50 ); glColor3f(0,1,0); glVertex2f( 0 , 100 ); glColor3f(0,0,1); glVertex2f( -87 , -50 ); glEnd(); // // #3 // glutSwapBuffers(); // glFlush(); } // // #4 // void reshape (GLint w, GLint h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w<=h) { gluOrtho2D( -WINDOW/2.0, WINDOW/2.0, (-WINDOW/2.0)*(double) h/ (double) w, (WINDOW/2.0)*(double) h/ (double) w); } else { gluOrtho2D( (-WINDOW/2.0)*(double) w/ (double) h, (WINDOW/2.0)*(double) w/ (double) h, -WINDOW/2.0, WINDOW/2.0); } glMatrixMode(GL_MODELVIEW); } // set up the keyboard callback void keyboard (unsigned char key , int x, int y) { if ( key=='q' || key=='Q' ) { exit( 0 ); } } void main(int argc , char ** argv) { glutInit(&argc,argv); // // #3 // glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB ); //glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB ); glutInitWindowSize( WINDOW, WINDOW); glutInitWindowPosition(50,50); glutCreateWindow("Rotating Triangle"); glutKeyboardFunc( keyboard ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); /* // // #3 // glutCreateMenu(menu); glutAddMenuEntry("quit",1); glutAddMenuEntry("spin",2); glutAddMenuEntry("stop",3); glutAttachMenu(GLUT_LEFT_BUTTON); */ // // #5 // GLint spinMenu = glutCreateMenu(menu01); glutAddMenuEntry("spin",2); glutAddMenuEntry("speed up",3); glutAddMenuEntry("slow down",4); glutCreateMenu(menu02); glutAddMenuEntry("quit",1); glutAddSubMenu("spin options",spinMenu); glutAddMenuEntry("stop",5); glutAttachMenu(GLUT_LEFT_BUTTON); myInit(); glutMainLoop(); }