//----------------------------------------------------------------------------- // File: starfield.cpp // Desc: 3d opengl/glut starfield // // summer 2001 - Ge Wang & Adrenaline University c++ class //----------------------------------------------------------------------------- #include #include #include #include #include //----------------------------------------------------------------------------- // function prototypes //----------------------------------------------------------------------------- // glut callback functions void idleFunc( ); void displayFunc( ); void reshapeFunc( GLsizei width, GLsizei height ); void keyboardFunc( unsigned char, int, int ); void mouseFunc( int button, int state, int x, int y ); // app specific functions void initialize( ); void cleanUp( ); void render( ); //----------------------------------------------------------------------------- // global variables and #define //----------------------------------------------------------------------------- #define NUM_STARS 400 #define FAR_PLANE -40.0f #define NEAR_PLANE 3.0f #define GAP 0.0f #define FIELD_WIDTH ( 30.0f ) #define FIELD_HEIGHT ( 25.0f ) #define RADIUS 1.0f #define DEFAULT_SPEED .02f; // width and height of the window GLsizei g_width = 640; GLsizei g_height = 480; // light position GLfloat g_light_position[4] = { 0.0f, 0.0f, 3.0f, 1.0f }; // the location float * g_xyz[NUM_STARS]; // the colors float * g_colors[NUM_STARS]; // the alpha and red components of polygon to blend float g_alpha = 0.3f; float g_red = 0.0f; float g_speed = DEFAULT_SPEED; float g_speed_inc = 0.0f; //----------------------------------------------------------------------------- // Name: main( ) // Desc: entry point for GLUT OpenGL application //----------------------------------------------------------------------------- int main( int argc, char ** argv ) { // initialize GLUT glutInit( &argc, argv ); // double buffer, use rgb color glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); // initialize the window size glutInitWindowSize( g_width, g_height ); // set the window postion glutInitWindowPosition( 100,100 ); // create the window glutCreateWindow( "Starfield OpenGL" ); // set the idle function - called when idle glutIdleFunc( idleFunc ); // set the display function - called when redrawing glutDisplayFunc( displayFunc ); // set the reshape function - called when client area changes glutReshapeFunc( reshapeFunc ); // set the keyboard function - called on keyboard events glutKeyboardFunc( keyboardFunc ); // mouse function - called on mouse events glutMouseFunc( mouseFunc ); // do our own initialization initialize(); // let GLUT handle the current thread from here glutMainLoop(); return 0; } //----------------------------------------------------------------------------- // Name: initialize( ) // Desc: sets initial OpenGL states // also initializes any application data //----------------------------------------------------------------------------- void initialize() { // set the GL clear color - use when the color buffer is cleared glClearColor( 0, 0, 0, 0 ); // set the shading model to 'smooth' glShadeModel( GL_SMOOTH ); // set GL to render front of polygons glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); // enable depth test glEnable( GL_DEPTH_TEST ); // set the initial line width glLineWidth( 1.0f ); // enable lighting glEnable( GL_LIGHTING ); // enable lighting for front glLightModeli( GL_FRONT, GL_TRUE ); // material have diffuse and ambient lighting glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); // enable color glEnable( GL_COLOR_MATERIAL ); // enable light 0 glEnable( GL_LIGHT0 ); // set light attenuation glLightf( GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.01f ); glLightf( GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.2f ); glLightf( GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.001f ); // clear the color buffer once glClear( GL_COLOR_BUFFER_BIT ); // randomly generate srand( time( NULL ) ); for( int i = 0; i < NUM_STARS; i++ ) { g_xyz[i] = new float[3]; g_xyz[i][0] = ( (float) rand() / RAND_MAX - .5f ) * FIELD_WIDTH; g_xyz[i][1] = ( (float) rand() / RAND_MAX - .5f ) * FIELD_HEIGHT; g_xyz[i][2] = ( (float) rand() / RAND_MAX ) * ( NEAR_PLANE - FAR_PLANE + GAP ) + FAR_PLANE; g_colors[i] = new float[3]; g_colors[i][0] = (float) rand() / RAND_MAX; g_colors[i][1] = (float) rand() / RAND_MAX; g_colors[i][2] = (float) rand() / RAND_MAX; } printf( "--------------------------------------------------\n" ); printf( "OpenGL flying simulation\n" ); printf( "--------------------------------------------------\n" ); printf( "[L/R] mouse button - accelerate forward/backwards\n" ); printf( " (try going backwards)\n" ); printf( "middle mouse button - reset to default speed\n" ); printf( "'=' or '+' - increase tail\n" ); printf( "'-' - decrease tail\n" ); printf( "'q' - quit progrqam\n" ); printf( "--------------------------------------------------\n" ); printf( "http://www.gewang.com/projects/\n" ); printf( "summer 2001, adrenaline univ.\n" ); printf( "--------------------------------------------------\n" ); printf( "\n" ); } //----------------------------------------------------------------------------- // Name: cleanUp( ) // Desc: cleans up dynamic memory //----------------------------------------------------------------------------- void cleanUp( ) { } //----------------------------------------------------------------------------- // Name: idleFunc( ) // Desc: callback function invoked when idle, used for animation //----------------------------------------------------------------------------- void idleFunc( ) { // invalidates the current window, so GLUT will call display function glutPostRedisplay( ); } //----------------------------------------------------------------------------- // Name: displayFunc( ) // Desc: callback function invoked to draw the client area //----------------------------------------------------------------------------- void displayFunc( ) { // clear the depth buffer glClear( GL_DEPTH_BUFFER_BIT ); // enable blending glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // disable lighting glDisable( GL_LIGHTING ); // disable depth test glDisable( GL_DEPTH_TEST ); // blend in a polygon glColor4f( g_red, g_red, g_red, g_alpha ); // reduce the red component g_red -= .02f; if( g_red < 0.0f ) g_red = 0.0f; // draw the polyg glBegin( GL_QUADS ); glVertex3f( -1.0f, -1.0f, 2.0f ); glVertex3f( -1.0f, 1.0f, 2.0f ); glVertex3f( 1.0f, 1.0f, 2.0f ); glVertex3f( 1.0f, -1.0f, 2.0f ); glEnd(); // enable lighting glEnable( GL_LIGHTING ); // enable depth test glEnable( GL_DEPTH_TEST ); // disable blending glDisable( GL_BLEND ); // save the current matrix state, so transformation will // not persist across displayFunc calls, since we // will do a glPopMatrix() at the end of this function glPushMatrix( ); // render the scene render( ); // restore the matrix state glPopMatrix( ); // flush the buffer glFlush( ); // swap the double buffer glutSwapBuffers( ); } void render() { static float inc = 0.0f; inc += 0.001f; glRotatef( 50 * cos( inc ), 0.0f, 0.0f, 1.0f ); g_speed += g_speed_inc; for( int i = 0; i < NUM_STARS; i++ ) { glPushMatrix(); glTranslatef( g_xyz[i][0], g_xyz[i][1], g_xyz[i][2] ); glColor3fv( g_colors[i] ); glutSolidSphere( .1f, 5, 5 ); glPopMatrix(); // increment z g_xyz[i][2] += g_speed; // check to see if passed view if( g_xyz[i][2] > NEAR_PLANE + GAP ) { float d; if( ( d = sqrt( g_xyz[i][0] * g_xyz[i][0] + g_xyz[i][1] * g_xyz[i][1] ) ) < RADIUS ) { g_red += ( RADIUS - d ) / RADIUS; if( g_red > 2.5f ) g_red = 2.5f; } g_xyz[i][0] = ( (float) rand() / RAND_MAX - .5f ) * FIELD_WIDTH; g_xyz[i][1] = ( (float) rand() / RAND_MAX - .5f ) * FIELD_HEIGHT; g_xyz[i][2] = FAR_PLANE; } else if( g_xyz[i][2] < FAR_PLANE ) { g_xyz[i][0] = ( (float) rand() / RAND_MAX - .5f ) * FIELD_WIDTH; g_xyz[i][1] = ( (float) rand() / RAND_MAX - .5f ) * FIELD_HEIGHT; g_xyz[i][2] = NEAR_PLANE; } } } //----------------------------------------------------------------------------- // Name: reshapeFunc( ) // Desc: callback function handle client area resizes //----------------------------------------------------------------------------- void reshapeFunc( GLsizei w, GLsizei h ) { // save the new width and height g_width = w; g_height = h; // map the view port to the entire client area glViewport(0, 0, w, h); // set the matrix mode to projection matrix glMatrixMode(GL_PROJECTION); // load the identity matrix glLoadIdentity(); // set the perspective matrix gluPerspective( 64.0, (GLdouble) w / h, .1, 300.0 ); // set the matrix mode to the modelview matrix glMatrixMode(GL_MODELVIEW); // load the identity matrix into the modelview matrix glLoadIdentity(); // set the 'camera' gluLookAt( 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 2.0, 3.0 ); // set the position of the light glLightfv( GL_LIGHT0, GL_POSITION, g_light_position ); } //----------------------------------------------------------------------------- // Name: keyboardFunc( ) // Desc: callback function to handle keyboard events //----------------------------------------------------------------------------- void keyboardFunc( unsigned char key, int x, int y ) { switch( key ) { case '+': case '=': g_alpha -= .02f; if( g_alpha < .05f ) g_alpha = 0.05f; break; case '-': g_alpha += .02f; if( g_alpha > 1.0f ) g_alpha = 1.0f; break; case 'Q': case 'q': cleanUp( ); exit( 1 ); break; }; } //----------------------------------------------------------------------------- // Name: mouseFunc( ) // Desc: handles mouse stuff //----------------------------------------------------------------------------- void mouseFunc( int button, int state, int x, int y ) { if( button == GLUT_LEFT_BUTTON ) { // when left mouse button is down, go forward faster if( state == GLUT_DOWN ) { g_speed_inc += .02f; } else if( state == GLUT_UP ) { g_speed_inc -= .02f; } } else if ( button == GLUT_RIGHT_BUTTON ) { // when right mouse button down, go backwards faster if( state == GLUT_DOWN ) { g_speed_inc -= .02f; } else if( state == GLUT_UP ) { g_speed_inc += .02f; } } else if( button == GLUT_MIDDLE_BUTTON ) { if( state == GLUT_DOWN ) { g_speed = DEFAULT_SPEED; g_speed_inc = 0; } } }