////////////////////////////////////////////////////////////////// // Concept: John Tran // Modified by Robert C. Duvall // Fall 2001 // // Display a spinning "DNA spiral". // #include // also includes glu and gl correctly #include // for atoi #include // for sprintf ////////////////////////////////////////////////////////////////// // Globals // // Constants // const int WINDOW_WIDTH = 800; // size of glut window const int WINDOW_HEIGHT = 600; // // Variables // int theNumPairs = 10; // number of rows to draw int theShouldAnimate = 0; // allow user to pause animation // keep track of the number of frames per second int theFrameCount = 0; int theLastFrameTime = 0; ////////////////////////////////////////////////////////////////// // Utility functions // float min (float a, float b) { return ((a < b) ? a : b); } void computeFPS () // post: compute frames per second and display in window's title bar { theFrameCount++; int currentTime = glutGet(GLUT_ELAPSED_TIME); if (currentTime - theLastFrameTime > 1000) { char s[16]; sprintf(s, "FPS: %4.2f", theFrameCount * 1000.0 / (currentTime - theLastFrameTime)); glutSetWindowTitle(s); theLastFrameTime = currentTime; theFrameCount = 0; } } ////////////////////////////////////////////////////////////////// // User Functions // These are the functions you will mostly be changing. // void initModel (int numPairs) { theNumPairs = numPairs; } void animateModel () { // animate model by spinning it glRotatef(2.5, 0.0, 1.0, 0.0); } void drawModel () { // start centered below origin in y direction glTranslatef(0.0, -(theNumPairs - 1.0) / theNumPairs, 0.0); // build pairs going up increments and rotating 45 degrees for (int k = 0; k < theNumPairs; k++) { // draw connecting line glLineWidth(min(12.0, 100.0 / theNumPairs)); glColor3f(1.0, 0.0, 0.0); glBegin(GL_LINES); glVertex3f(-0.25, 0, 0); glVertex3f(0.25, 0, 0); glEnd(); // draw first sphere glColor3f(0.0, 0.0, 0.9); glTranslatef(-0.25, 0.0, 0.0); glutSolidSphere(min(0.2, 1.0 / theNumPairs), 16, 16); // draw second sphere glColor3f(1.0, 1.0, 0.0); glTranslatef(0.5, 0.0, 0.0); glutSolidSphere(min(0.2, 1.0 / theNumPairs), 16, 16); // translate back to zero in the x-direction glTranslatef(-0.25, 0.0, 0.0); // rotate by 45 degrees around y-axis glRotatef(45, 0.0, 1.0, 0.0); // translate up in y-direction glTranslatef(0.0, 2.0 / theNumPairs, 0.0); } // translate and rotate back to origin glTranslatef(0.0, -(theNumPairs + 1.0) / theNumPairs, 0.0); glRotatef(-45 * theNumPairs, 0.0, 1.0, 0.0); } ////////////////////////////////////////////////////////////////// // Callback Functions // These functions are registered with the glut window and called // when certain events occur. // void onInit (int numPairs) // pre: glut window has been initialized // post: model has been initialized { initModel(numPairs); // set color used to clear window to black (i.e., background color) glClearColor(0.0, 0.0, 0.0, 0.0); // set to draw in window based on depth glEnable(GL_DEPTH_TEST); } void onRedraw () // pre: glut window needs to be refreshed // post: model is drawn { // erases requested bits (color and depth) in glut window glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawModel(); // double-buffering - swap the back and front buffers glutSwapBuffers(); } void onIdle () // pre: glut window is not doing anything else // post: model is spun a little more { if (theShouldAnimate) { computeFPS(); animateModel(); // mark that glut window should be refreshed glutPostRedisplay(); } } void onKeyPressed (unsigned char key, int mouseX, int mouseY) // pre: key has been pressed while mouse is within glut window // post: animation may be paused or started, program may be exited { switch (key) { case 'p': theShouldAnimate = ! theShouldAnimate; break; case 'q': case 27: // ESCAPE key exit(1); break; } } void onResize (int width, int height) // pre: glut window has been resized // post: resets cameras location and aspect to match window { // set viewable area to entire window glViewport(0, 0, GLint(width), GLint(height)); } void onVisible (int state) // pre: glut window has just been iconified or restored // post: if window is visible, animate model, otherwise don't bother { if (state == GLUT_VISIBLE) { // tell glut to animate model using onIdle function glutIdleFunc(onIdle); } else { glutIdleFunc(NULL); } } ////////////////////////////////////////////////////////////////// // Main Function // int main (int argc, char *argv[]) { // initialize glut glutInit(&argc, argv); // request initial window size glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); // request glut window with double buffering and drawing based on depth glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA); // create window and make its title the name of the executable glutCreateWindow(argv[0]); // initialize model onInit(argc > 1 ? atoi(argv[1]) : 10); // tell glut how to display model glutDisplayFunc(onRedraw); // tell glut how to handle normal key presses glutKeyboardFunc(onKeyPressed); // tell glut how to respond to changes in window size glutReshapeFunc(onResize); // tell glut how to handle changes in windows visibility glutVisibilityFunc(onVisible); // give control over to glut glutMainLoop(); // program should never get here return 0; }