// ---------------------- // OpenGL cube demo. // // Written by Chris Halsall (chalsall@chalsall.com) for the // O'Reilly Network on Linux.com (oreilly.linux.com). // May 2000. // // Released into the Public Domain; do with it as you wish. // We would like to hear about interesting uses. // // Coded to the groovy tunes of Yello: Pocket Universe. #define PROGRAM_TITLE "O'Reilly Net: OpenGL Demo -- C.Halsall" #include // Always a good idea. #include // For our FPS stats. #include // OpenGL itself. #include // GLU support library. #include // GLUT support library. // Some global variables. // Window and texture IDs, window width and height. int Texture_ID; int Window_ID; int Window_Width = 300; int Window_Height = 300; // Our display mode settings. int Light_On = 0; int Blend_On = 0; int Texture_On = 0; int Filtering_On = 0; int Alpha_Add = 0; int Curr_TexMode = 0; char *TexModesStr[] = {"GL_DECAL","GL_MODULATE","GL_BLEND","GL_REPLACE"}; GLint TexModes[] = {GL_DECAL,GL_MODULATE,GL_BLEND,GL_REPLACE}; // Object and scene global variables. // Cube position and rotation speed variables. float X_Rot = 0.9f; float Y_Rot = 0.0f; float X_Speed = 0.0f; float Y_Speed = 0.5f; float Z_Off =-5.0f; // Settings for our light. Try playing with these (or add more lights). float Light_Ambient[]= { 0.1f, 0.1f, 0.1f, 1.0f }; float Light_Diffuse[]= { 1.2f, 1.2f, 1.2f, 1.0f }; float Light_Position[]= { 2.0f, 2.0f, 0.0f, 1.0f }; // ------ // Frames per second (FPS) statistic variables and routine. #define FRAME_RATE_SAMPLES 50 int FrameCount=0; float FrameRate=0; static void ourDoFPS( ) { static clock_t last=0; clock_t now; float delta; if (++FrameCount >= FRAME_RATE_SAMPLES) { now = clock(); delta= (now - last) / (float) CLOCKS_PER_SEC; last = now; FrameRate = FRAME_RATE_SAMPLES / delta; FrameCount = 0; } } // ------ // String rendering routine; leverages on GLUT routine. static void ourPrintString( void *font, char *str ) { int i,l=strlen(str); for(i=0;i 3 ) Curr_TexMode=0; glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,TexModes[Curr_TexMode]); break; case 116: case 84: // T - Texturing. Texture_On = Texture_On ? 0 : 1; break; case 97: case 65: // A - Alpha-blending hack. Alpha_Add = Alpha_Add ? 0 : 1; break; case 102: case 70: // F - Filtering. Filtering_On = Filtering_On ? 0 : 1; break; case 115: case 83: case 32: // F (Space) - Freeze! X_Speed=Y_Speed=0; break; case 114: case 82: // R - Reverse. X_Speed=-X_Speed; Y_Speed=-Y_Speed; break; default: printf ("KP: No action for %d.\n", key); break; } } // ------ // Callback Function called when a special key is pressed. void cbSpecialKeyPressed( int key, int x, int y ) { switch (key) { case GLUT_KEY_PAGE_UP: // move the cube into the distance. Z_Off -= 0.05f; break; case GLUT_KEY_PAGE_DOWN: // move the cube closer. Z_Off += 0.05f; break; case GLUT_KEY_UP: // decrease x rotation speed; X_Speed -= 0.01f; break; case GLUT_KEY_DOWN: // increase x rotation speed; X_Speed += 0.01f; break; case GLUT_KEY_LEFT: // decrease y rotation speed; Y_Speed -= 0.01f; break; case GLUT_KEY_RIGHT: // increase y rotation speed; Y_Speed += 0.01f; break; default: printf ("SKP: No action for %d.\n", key); break; } } // ------ // Function to build a simple full-color texture with alpha channel, // and then create mipmaps. This could instead load textures from // graphics files from disk, or render textures based on external // input. void ourBuildTextures( void ) { GLenum gluerr; GLubyte tex[128][128][4]; int x,y,t; int hole_size = 3300; // ~ == 57.45 ^ 2. // Generate a texture index, then bind it for future operations. glGenTextures(1,&Texture_ID); glBindTexture(GL_TEXTURE_2D,Texture_ID); // Iterate across the texture array. for(y=0;y<128;y++) { for(x=0;x<128;x++) { // A simple repeating squares pattern. // Dark blue on white. if ( ( (x+4)%32 < 8 ) && ( (y+4)%32 < 8)) { tex[x][y][0]=tex[x][y][1]=0; tex[x][y][2]=120; } else { tex[x][y][0]=tex[x][y][1]=tex[x][y][2]=240; } // Make a round dot in the texture's alpha-channel. // Calculate distance to center (squared). t = (x-64)*(x-64) + (y-64)*(y-64) ; if ( t < hole_size) // Don't take square root; compare squared. tex[x][y][3]=255; // The dot itself is opaque. else if (t < hole_size + 100) tex[x][y][3]=128; // Give our dot an anti-aliased edge. else tex[x][y][3]=0; // Outside of the dot, it's transparent. } } // The GLU library helps us build MipMaps for our texture. if ((gluerr=gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, (void *)tex))) { fprintf(stderr,"GLULib%s\n",gluErrorString(gluerr)); exit(-1); } // Some pretty standard settings for wrapping and filtering. glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); // We start with GL_DECAL mode. glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); } // ------ // Callback routine executed whenever our window is resized. Lets us // request the newly appropriate perspective projection matrix for // our needs. Try removing the gluPerspective() call to see what happens. void cbResizeScene( int Width, int Height ) { // Let's not core dump, no matter what. if (Height == 0) Height = 1; glViewport(0, 0, Width, Height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); Window_Width = Width; Window_Height = Height; } // ------ // Does everything needed before losing control to the main // OpenGL event loop. void ourInit( int Width, int Height ) { ourBuildTextures(); // Color to clear color buffer to. glClearColor(0.1f, 0.1f, 0.1f, 0.0f); // Depth to clear depth buffer to; type of test. glClearDepth(1.0); glDepthFunc(GL_LESS); // Enables Smooth Color Shading; try GL_FLAT for (lack of) fun. glShadeModel(GL_SMOOTH); // Load up the correct perspective matrix; using a callback directly. cbResizeScene(Width,Height); // Set up a light, turn it on. glLightfv(GL_LIGHT1, GL_POSITION, Light_Position); glLightfv(GL_LIGHT1, GL_AMBIENT, Light_Ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, Light_Diffuse); glEnable (GL_LIGHT1); // A handy trick -- have surface material mirror the color. glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); } // ------ // The main() function. Inits OpenGL. Calls our own init function, // then passes control onto OpenGL. int main( int argc, char **argv ) { glutInit(&argc, argv); // To see OpenGL drawing, take out the GLUT_DOUBLE request. glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(Window_Width, Window_Height); // Open a window Window_ID = glutCreateWindow( PROGRAM_TITLE ); // Register the callback function to do the drawing. glutDisplayFunc(&cbRenderScene); // If there's nothing to do, draw. glutIdleFunc(&cbRenderScene); // It's a good idea to know when our window's resized. glutReshapeFunc(&cbResizeScene); // And let's get some keyboard input. glutKeyboardFunc(&cbKeyPressed); glutSpecialFunc(&cbSpecialKeyPressed); // OK, OpenGL's ready to go. Let's call our own init function. ourInit(Window_Width, Window_Height); // Print out a bit of help dialog. printf("\n" PROGRAM_TITLE "\n\n\ Use arrow keys to rotate, 'R' to reverse, 'S' to stop.\n\ Page up/down will move cube away from/towards camera.\n\n\ Use first letter of shown display mode settings to alter.\n\n\ Q or [Esc] to quit; OpenGL window must have focus for input.\n"); // Pass off control to OpenGL. // Above functions are called as appropriate. glutMainLoop(); return 1; }