// WhichPot.cpp // NKU CSC 480/580 - Kirby // ------------------------------------------------------------------------------------------ // Demonstrating: // - Picking. // Slightly revised 4/28/06: Replaced orthographic with perspective projection (lines 49-50). // ------------------------------------------------------------------------------------------ #include #include using namespace std ; bool gTopView= false ; // front/top view: toggled by space bar. void lighting() // Set up some simple lighting and materials for our teapots. { const float YELLOW[]={1,1,0,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 ) ; glPolygonMode( GL_FRONT, GL_FILL ) ; glEnable( GL_NORMALIZE ) ; glEnable( GL_LIGHTING ) ; // 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, YELLOW ); } void drawTeapots( GLenum mode ) // Draw a scene of three teapots at three depths, overlapping from viewpoint, in given mode. { // Projection (common to both rendering and selection modes) glMatrixMode( GL_PROJECTION ) ; double s= 2 ; gluPerspective( 30., 1., 6, 10 ) ; gluLookAt( 0,0,8, 0,0,0, 0,1,0 ) ; // Switch to model view for manipulation of scene glMatrixMode( GL_MODELVIEW ) ; glPushMatrix() ; { if ( gTopView ) glRotated( 90, 1,0,0 ) ; // "view" part of modelview // Set up lighting (subject to modelview) lighting() ; // Teapot 1 (name 100) forward, top right glPushMatrix() ; glTranslated( 0.5, 0.5 ,1.3 ) ; if ( mode == GL_SELECT ) glLoadName( 100 ) ; glutSolidTeapot( 0.5 ) ; glPopMatrix() ; // Teapot 2 (name 200) middle, center glPushMatrix() ; if ( mode == GL_SELECT ) glLoadName( 200 ) ; glutSolidTeapot( 0.5 ) ; glPopMatrix() ; // Teapot 3 (name 300) behind, bottom left glPushMatrix() ; glTranslated( -0.5, -0.5, -1.3 ) ; if ( mode == GL_SELECT ) glLoadName( 300 ) ; glutSolidTeapot( 0.5 ) ; glPopMatrix() ; } glPopMatrix() ; } void display() { // In rendering mode, we start with identity projection. glMatrixMode( GL_PROJECTION ) ; glLoadIdentity() ; // Draw scene. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; drawTeapots( GL_RENDER ) ; glutSwapBuffers() ; } void reportHits( int nHits, unsigned int nameBuffer[] ) // Print out information about hits on console. // Reference: OpenGL Red Book p.536. { cout << "This click triggered " << nHits << " hits." << endl ; unsigned int* pi= nameBuffer ; for ( int i=0 ; i < nHits ; ++i ) { int nNames= (int) *pi++ ; float minDepth= (float) (*pi++)/0xFFFFFFFF ; float maxDepth= (float) (*pi++)/0xFFFFFFFF ; cout << " Hit " << (i+1) << " [depth " << minDepth << " ... " << maxDepth << "]. Names: " ; for ( int j=0 ; j < nNames ; ++j ) cout << " " << *pi++ ; cout << endl ; } } void pickAt( int ix, int iy, double r ) // Mouse click at (ix,iy): draw in selection mode and report hits in box // of size r around click location. { cout << "\nClick at " << ix << ", " << iy << endl ; // Initialize name buffer. const int BUFSIZE= 512 ; static unsigned int nameBuffer[ BUFSIZE ] ; glSelectBuffer( BUFSIZE, nameBuffer ) ; glRenderMode( GL_SELECT ) ; glInitNames() ; glPushName( 0 ) ; // Grab viewport. int vport[4] ; glGetIntegerv( GL_VIEWPORT, vport ) ; int iyMax= vport[3] ; // Define special projection matrix for picking, then draw. glMatrixMode( GL_PROJECTION ) ; glPushMatrix() ; { glLoadIdentity() ; gluPickMatrix( (double) ix, (double)( iyMax-iy ), r, r, vport ) ; drawTeapots( GL_SELECT ) ; } glMatrixMode( GL_PROJECTION ) ; glPopMatrix() ; // Process hits int nHits= glRenderMode( GL_RENDER ) ; reportHits( nHits, nameBuffer ) ; glutPostRedisplay() ; glPopName() ; } void mouseClick( int button, int state, int ix, int iy ) // Event handler for mouse click event. { if ( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) pickAt( ix, iy, 4 ) ; } void kbDispatch( unsigned char ch, int x, int y ) // Adjust view: front/top. { if ( ch == ' ' ) gTopView= ! gTopView ; glutPostRedisplay() ; } 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( "Which Pot?" ) ; // Register callbacks. glutMouseFunc( mouseClick ) ; glutKeyboardFunc( kbDispatch ) ; glutDisplayFunc( display ) ; // Go. glutMainLoop() ; return 0 ; }