// MouseTrack3DX.cpp // NKU CSC 480 Kirby // ---------------------------------------------------------------------------------- // Allows the user to rotate and translate a lit mesh by dragging the mouse. // Illustrates composition of rotation matrices and use of the mouse callbacks. // // Revised 3/29/06 to use new Mesh::getBoundingRadius() to draw meshes of // arbitrary scale. // ---------------------------------------------------------------------------------- #include #include #include #include #include #include #include #include "Mesh.h" struct Mouse // Mouse state. { bool leftButtonDown ; // which button bool ctrl, alt, shift ; // key modifiers int ix, iy ; // last recorded pixel coordinates in a mouse event } ; // Global state. Mouse G_mouse ; int G_dispListMesh ; double G_rotMatrix[]= {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 } ; Vector3 G_transVector ; double G_scale = 1 ; void textLabel( const char* szLabel, double x, double y ) // Write a string at given x,y position in [-1,1]x[-1,1]. { // Save and reset matrices glMatrixMode( GL_MODELVIEW ) ; glPushMatrix() ; glLoadIdentity() ; glMatrixMode( GL_PROJECTION ) ; glPushMatrix() ; glLoadIdentity() ; // Issue command in canonical coordinates. glRasterPos2f( x, y ) ; while ( *szLabel ) glutBitmapCharacter( GLUT_BITMAP_8_BY_13, *szLabel++ ) ; // Restore matrices glMatrixMode( GL_PROJECTION ) ; glPopMatrix() ; glMatrixMode( GL_MODELVIEW ) ; glPopMatrix() ; } void showMatrices() // Write the modelview and projection matrices on the display. { double m[ 16 ] ; // Write modelview matrix at lower left of viewport. glGetDoublev( GL_MODELVIEW_MATRIX, m ) ; for ( int j=0 ; j < 4 ; ++j ) { ostringstream os ; for ( int i=0 ; i < 4 ; ++i ) os << setprecision(3) << setw(8) << m[ 4*i + j ] << " " ; textLabel( os.str().c_str(), -0.95, -0.80 - 0.05*j ) ; } // Write projection matrix at lower right of viewport. glGetDoublev( GL_PROJECTION_MATRIX, m ) ; for ( int j=0 ; j < 4 ; ++j ) { ostringstream os ; for ( int i=0 ; i < 4 ; ++i ) os << setprecision(3) << setw(8) << m[ 4*i + j ] << " " ; textLabel( os.str().c_str(), 0.05, -0.80 - 0.05*j ) ; } } void lightsAndMaterials() // Set up some simple lighting and materials for the teapot. { const float CYAN[]={0,1,1,0}, WHITE[]={1,1,1,0}, GREY[]={0.3, 0.3, 0.3, 0 } ; // Set up the appropriate processing steps for lighting. glEnable( GL_DEPTH_TEST ) ; glEnable( GL_NORMALIZE ) ; // One Phong light source. float lightPos[]= {1,1,1,0} ; glLightfv( GL_LIGHT0, GL_POSITION, lightPos ) ; glLightfv( GL_LIGHT0, GL_DIFFUSE, WHITE ) ; glLightfv( GL_LIGHT0, GL_AMBIENT, GREY ) ; glEnable( GL_LIGHT0 ) ; // The material for all the solids drawn will be default yellow. glMaterialfv( GL_FRONT, GL_DIFFUSE, CYAN ); } void lightsOn( bool on ) // Enable/disable lighting/filling. { if ( on ) { glPolygonMode( GL_FRONT, GL_FILL ) ; glEnable( GL_LIGHTING ) ; } else { glPolygonMode( GL_FRONT, GL_LINE ) ; glDisable( GL_LIGHTING ) ; } } void display() // Display the scene. { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; // View: position camera out on z looking at origin glMatrixMode( GL_MODELVIEW ) ; glLoadIdentity() ; gluLookAt( 0,0,10, 0,0,0, 0,1,0 ) ; // Model: apply rotation and translation matrices as generated by mouse motion. glTranslated( G_transVector.dx, G_transVector.dy, G_transVector.dz ) ; glMultMatrixd( G_rotMatrix ) ; // Mesh lightsOn( true ) ; glScaled( G_scale, G_scale, G_scale ) ; glCallList( G_dispListMesh ) ; // Show M and P matrices in window. lightsOn( false ) ; glColor3f( 1, 1, 1 ) ; showMatrices() ; glutSwapBuffers() ; } void xglAccumRotationGlobal( double degrees, double x, double y, double z ) // Multiply the current rotation matrix on the LEFT by a rotation matrix. // Hijack the MV matrix stack to do the calculation. { glMatrixMode( GL_MODELVIEW ) ; glPushMatrix() ; glLoadIdentity() ; glRotated( degrees, x, y, z) ; glMultMatrixd( G_rotMatrix ) ; glGetDoublev( GL_MODELVIEW_MATRIX, G_rotMatrix ) ; glPopMatrix() ; } void mouseMotion( int ix, int iy ) // Respond to micro movement of mouse, updating transformations. { if ( G_mouse.leftButtonDown ) { Vector3 drag( ix - G_mouse.ix, G_mouse.iy - iy, 0 ) ; if ( G_mouse.ctrl ) { // Add in some more translation. static const double TRANS_SENSITIVITY = 0.003 ; G_transVector += TRANS_SENSITIVITY * drag ; } else { // Factor in some more rotation. static const double ROT_SENSITIVITY = 0.2 ; // degrees of rot per unit mouse drag pixel Vector3 axis= Vector3(0,0,1) ^ drag ; // rot axis is perpendicular to drag double degrees= ROT_SENSITIVITY * drag.norm() ; // angle proportional to drag length xglAccumRotationGlobal( degrees, axis.dx, axis.dy, axis.dz ) ; } G_mouse.ix= ix ; G_mouse.iy= iy ; glutPostRedisplay() ; } } void mousePress( int button, int state, int ix, int iy ) // Mouse button press event handler. Extract and store current mouse state. { G_mouse.leftButtonDown= ( button == GLUT_LEFT_BUTTON ) && ( state == GLUT_DOWN ) ; int mods= glutGetModifiers() ; G_mouse.ctrl= (mods & GLUT_ACTIVE_CTRL) !=0 ; G_mouse.alt= (mods & GLUT_ACTIVE_ALT) !=0 ; G_mouse.shift= (mods & GLUT_ACTIVE_SHIFT) !=0; G_mouse.ix= ix ; G_mouse.iy= iy ; } int main( int argc, char** argv ) { // Initialize OpenGL. glutInit( &argc, argv ) ; glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH ) ; // Window attributes. glutInitWindowSize( 700, 700 ) ; glutInitWindowPosition( 100, 100 ) ; glutCreateWindow( "NKU CSC 480" ) ; // Set up simple perspective viewing. glMatrixMode( GL_PROJECTION ) ; glLoadIdentity() ; gluPerspective( 20, 1, 8, 12 ) ; glMatrixMode( GL_MODELVIEW ) ; glLoadIdentity() ; // Lighting lightsAndMaterials() ; // Register callbacks. glutMouseFunc( mousePress ) ; glutMotionFunc( mouseMotion ) ; glutDisplayFunc( display ) ; // Load mesh. string filename ; cout << "Enter mesh file name: " ; cin >> filename ; ifstream meshfile( filename.c_str() ) ; if ( ! meshfile ) { cerr << "Mesh file " << filename << " not found." << endl ; exit( 1 ) ; } Mesh mesh( meshfile ) ; G_dispListMesh= mesh.makeDisplayList() ; G_scale = 1 / mesh.getBoundingRadius() ; // Go. glutMainLoop() ; return 0 ; }