//----------------------------------------------------------------------------- // nile: xform.cpp // desc: sample shows how usage of modelview transformations in OpenGL // // to compile (OS X): // g++ -o xform xform.cpp -framework OpenGL -framework GLUT // // to run: // ./xform // // Music 256a | Stanford University | Ge Wang // http://ccrma.stanford.edu/courses/256a/ //----------------------------------------------------------------------------- #include #include #include #include // mac os x #include // other platforms // #include //----------------------------------------------------------------------------- // function prototypes //----------------------------------------------------------------------------- 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 ); void initialize( ); void buildVerts( int num_sides ); void buildGrid( int x, int z, GLfloat space ); void cleanUp( ); void render_wheel( ); void render_frame( ); void render_obj( ); void render_grid( ); //----------------------------------------------------------------------------- // global variables and #defines //----------------------------------------------------------------------------- #define __PI 3.1415926 #define ABS(x) (float) (x < 0 ? -x : x) #define COS(x) (float) cos( (double) (x) * __PI / 180.0 ) #define SIN(x) (float) sin( (double) (x) * __PI / 180.0 ) #define RADIUS .4f // width and height of the window GLsizei g_width = 800; GLsizei g_height = 600; // whether to animate GLboolean g_rotate = GL_TRUE; // data points for wheel GLfloat ** g_vArray = NULL; GLsizei g_numVerts = 0; // the grid GLfloat ** g_grid = NULL; GLsizei g_numGrid = 0; // x position of object GLfloat g_pos_x = 0.0f; // y position of object GLfloat g_pos_y = 0.0f; // z postion of object GLfloat g_pos_z = 0.0f; // increment for x on each cycle GLfloat g_inc = 0.0f; // the speed and direction of the wheels GLfloat g_factor = 1.0f; // the y for the pos of viewer GLfloat g_y = 50.0f; // target positions GLfloat g_target_x = 0.0; GLfloat g_target_y = 0.0; GLfloat g_target_z = 0.0; // target view GLfloat g_target_view_y = 0.0; //----------------------------------------------------------------------------- // Name: main( ) // Desc: starting point //----------------------------------------------------------------------------- int main( int argc, char ** argv ) { // initialize GLUT glutInit( &argc, argv ); // double buffer, use rgb color, enable depth buffer 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( "xform" ); // set the idle function - called when idle glutIdleFunc( g_rotate ? idleFunc : NULL ); // 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 ); // set the mouse function - called on mouse stuff 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.0f, 0.0f, 0.0f, 1.0f ); // set the shading model to 'smooth' glShadeModel( GL_SMOOTH ); // enable depth glEnable( GL_DEPTH_TEST ); // set the front faces of polygons glFrontFace( GL_CCW ); // draw in wireframe glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); // build data points for wheels buildVerts( 16 ); // build data points for grid buildGrid( 11, 11, 1.0f); printf( "hold left mouse button - move car left\n" ); printf( "hold right mouse button - move car right\n" ); printf( "center mouse button - resets position\n" ); printf( "'[' - move car left\n" ); printf( "'-' - move car near\n" ); printf( "'=' - move car far\n" ); printf( "'u' - move camera up\n" ); printf( "'d' - move camera down\n" ); } //----------------------------------------------------------------------------- // Name: buildVerts( ) // Desc: function to build the vertex and color arrays for a N-sided polygon //----------------------------------------------------------------------------- void buildVerts( GLsizei numVerts ) { // this is the degrees between two vertices adjacent GLfloat inc = 360.0 / (float) numVerts; // starting offsets for the r, g, b components GLfloat r = 90.0f, g = 45.0f, b = 0.0f; // the radios of the vertice GLfloat radius = RADIUS; // make sure we have at least 3 vertices if ( numVerts < 3 ) return; // clean up any memory cleanUp( ); // allocate the vert and color arrays g_vArray = new GLfloat *[ numVerts ]; g_numVerts = numVerts; for( GLsizei i = 0; i < numVerts; i++ ) { g_vArray[i] = new GLfloat[3]; // calculate the next vertex g_vArray[i][0] = COS( inc * i ) * radius; g_vArray[i][1] = SIN( inc * i ) * radius; g_vArray[i][2] = 0.0f; } } //----------------------------------------------------------------------------- // Name: buildGrid( ) // Desc: function to build grid //----------------------------------------------------------------------------- void buildGrid( int x, int z, GLfloat space ) { GLsizei i; // allocate the grid g_numGrid = ( x + z ) * 2; g_grid = new GLfloat *[ g_numGrid ]; memset( g_grid, 0, sizeof( GLfloat ) * g_numGrid ); GLfloat width = ( x - 1 ) * space * 2; GLfloat height = ( z - 1 ) * space * 2; // generate the points for the grid for( i = 0; i < x * 2; i += 2 ) { g_grid[i] = new GLfloat[3]; g_grid[i+1] = new GLfloat[3]; g_grid[i][0] = i * space; g_grid[i][1] = 0; g_grid[i][2] = 0; g_grid[i+1][0] = i * space; g_grid[i+1][1] = 0; g_grid[i+1][2] = -height; } for( i = 0; i < z * 2; i += 2 ) { g_grid[i + x * 2] = new GLfloat[3]; g_grid[i + x * 2 + 1] = new GLfloat[3]; g_grid[i + x * 2][0] = 0; g_grid[i + x * 2][1] = 0; g_grid[i + x * 2][2] = -i * space; g_grid[i + x * 2 + 1][0] = width; g_grid[i + x * 2 + 1][1] = 0; g_grid[i + x * 2 + 1][2] = -i * space; } } //----------------------------------------------------------------------------- // Name: cleanUp( ) // Desc: cleans up dynamic memory for vArray //----------------------------------------------------------------------------- void cleanUp( ) { int i; if( g_vArray ) { for( i = 0; i < g_numVerts; i++ ) delete [] g_vArray[i]; delete [] g_vArray; g_vArray = NULL; } g_numVerts = 0; } //----------------------------------------------------------------------------- // Name: reshapeFunc( ) // Desc: called when window size changes //----------------------------------------------------------------------------- void reshapeFunc( GLsizei w, GLsizei h ) { // save the new window size g_width = w; g_height = h; // map the view port to the client area glViewport( 0, 0, w, h ); // set the matrix mode to project glMatrixMode( GL_PROJECTION ); // load the identity matrix glLoadIdentity( ); // create the viewing frustum gluPerspective( 90.0, (GLfloat) w / (GLfloat) h, 1.0, 300.0 ); // set the matrix mode to modelview glMatrixMode( GL_MODELVIEW ); // load the identity matrix glLoadIdentity( ); // position the view point gluLookAt( 0.0f, g_y, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f ); } //----------------------------------------------------------------------------- // name: rand2f() // desc: generate a random float //----------------------------------------------------------------------------- GLfloat rand2f( float a, float b ) { return a + (b-a)*(rand() / (GLfloat)RAND_MAX); } //----------------------------------------------------------------------------- // Name: keyboardFunc( ) // Desc: key event //----------------------------------------------------------------------------- void keyboardFunc( unsigned char key, int x, int y ) { switch( key ) { case 'Q': case 'q': exit(1); break; case '[': g_target_x -= 1; g_factor = 1.0f; break; case ']': g_target_x += 1; g_factor = -1.0f; break; case '=': // move further g_target_z -= 1.0f; break; case '-': // move closer g_target_z += 1.0f; break; case '0': // reset the location of object g_target_x = 0.0f; g_target_y = 0.0f; g_target_z = 0.0f; g_inc = 0.0f; break; case 'u': // move view up g_target_view_y -= 2; break; case 'd': // move view down g_target_view_y += 2; break; case 't': // teleport! g_target_x = rand2f(-2,2); g_target_y = rand2f(-2,2); g_target_z = rand2f(-20,2); break; } glutPostRedisplay( ); } //----------------------------------------------------------------------------- // 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, move left if( state == GLUT_DOWN ) { g_inc -= 0.01f; g_factor = 1.0f; } else g_inc += 0.01f; } else if ( button == GLUT_RIGHT_BUTTON ) { // when right mouse button down, move right if( state == GLUT_DOWN ) { g_inc += .01f; g_factor = -1.0f; } else g_inc -= .01f; } else { // reset the location of object g_pos_x = 0.0f; g_inc = 0.0f; } glutPostRedisplay( ); } //----------------------------------------------------------------------------- // name: interp() // desc: ... //----------------------------------------------------------------------------- void interp() { static GLfloat slew = .001f; // move towards the x target g_pos_x = (g_target_x-g_pos_x)*slew + g_pos_x; g_pos_y = (g_target_y-g_pos_y)*slew + g_pos_y; g_pos_z = (g_target_z-g_pos_z)*slew + g_pos_z; g_y = (g_target_view_y-g_y)*slew + g_y; } //----------------------------------------------------------------------------- // Name: idleFunc( ) // Desc: callback from GLUT //----------------------------------------------------------------------------- void idleFunc( ) { // render the scene glutPostRedisplay( ); // interp interp(); // reshape reshapeFunc( g_width, g_height ); } //----------------------------------------------------------------------------- // Name: displayFunc( ) // Desc: callback function invoked to draw the client area //----------------------------------------------------------------------------- void displayFunc( ) { static GLfloat x = 0.0f; // clear the color and depth buffers glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // draw the world grid glPushMatrix( ); // position the grid glTranslatef( -10.0f, 0.0f, 10.0f); // draw the grid glLineWidth( 1.0f ); glColor3f( .2f, 1.0f, .2f ); render_grid( ); glPopMatrix( ); // draw the car glPushMatrix( ); // translate to ( x, y, z ) world coordinate glTranslatef( g_pos_x, g_pos_y, g_pos_z ); glLineWidth( 2.0f ); // draw the object render_obj( ); glPopMatrix( ); glFlush( ); glutSwapBuffers( ); } //----------------------------------------------------------------------------- // Name: render_grid( ) // Desc: draws grid in object coordinate //----------------------------------------------------------------------------- void render_grid( ) { glBegin( GL_LINES ); for( int i = 0; i < g_numGrid; i += 2 ) { glVertex3fv( g_grid[i] ); glVertex3fv( g_grid[i+1] ); } glEnd( ); } //----------------------------------------------------------------------------- // Name: render_obj( ) // Desc: draws object in object coordinate //----------------------------------------------------------------------------- void render_obj( ) { static GLfloat rot_z = 0.0f; // left near wheel glColor3f( 1.0f, 0.8f, .2f ); glPushMatrix( ); glTranslatef( -1.0f, RADIUS, .5f ); glRotatef( rot_z, 0.0f, 0.0f, 1.0f ); render_wheel( ); glPopMatrix( ); // left far wheel glPushMatrix( ); glTranslatef( -1.0f, RADIUS, -.5f ); glRotatef( rot_z, 0.0f, 0.0f, 1.0f ); render_wheel( ); glPopMatrix( ); // right near wheel glPushMatrix( ); glTranslatef( 1.0f, RADIUS, .5f ); glRotatef( rot_z, 0.0f, 0.0f, 1.0f ); render_wheel( ); glPopMatrix( ); // right far wheel glPushMatrix( ); glTranslatef( 1.0f, RADIUS, -.5f ); glRotatef( rot_z, 0.0f, 0.0f, 1.0f ); render_wheel( ); glPopMatrix( ); // rotate the wheel for next time rot_z += 0.1f * g_factor; // draw the frame of the object glColor3f( .6f, 0.6f, 1.0f ); glPushMatrix( ); glTranslatef( 0.0f, RADIUS, 0.0f ); render_frame( ); glPopMatrix( ); } //----------------------------------------------------------------------------- // Name: render_frame( ) // Desc: draw the frame of the car //----------------------------------------------------------------------------- void render_frame( ) { GLfloat y1 = RADIUS/2, y2 = y1 * 1.2f; GLfloat x1 = -1.04f, x2 = 1.04f; GLfloat z1 = .5f, z2 = -.5f; // draw the frame glBegin( GL_QUAD_STRIP ); glVertex3f( x1, 0.0f, z1 ); glVertex3f( x1, y1, z1 ); glVertex3f( x2, 0.0f, z1 ); glVertex3f( x2, y2, z1 ); glVertex3f( x2, 0.0f, z2 ); glVertex3f( x2, y2, z2 ); glVertex3f( x1, 0.0f, z2 ); glVertex3f( x1, y1, z2 ); glVertex3f( x1, 0.0f, z1 ); glVertex3f( x1, y1, z1 ); glEnd( ); } //----------------------------------------------------------------------------- // Name: render_wheel( ) // Desc: draw a wheel in local coordinate //----------------------------------------------------------------------------- void render_wheel( ) { GLsizei i; // draw one wheel glBegin( GL_TRIANGLE_FAN ); glVertex3f( 0.0f, 0.0f, 0.0f ); for( i = 0; i < g_numVerts; i++ ) glVertex3fv( g_vArray[i] ); glVertex3fv( g_vArray[0] ); glEnd( ); }