/************************************************************ * file: pan.cc * Visualization Course, Fall 2001 * Author: Chee Yap * * A basic demo of panning an image. * This program reads from several bmp files, each stored in * an instance of "RGBpixmap" class. * * Technical details of panning: * -- need double buffering * -- new implementation of "RGBpixmap::draw(int x, int y)" * to draw image at new position (x,y) instead of (0,0). * -- use of glPixelStorei(GL_UNPACK_SKIP_ROWS, r) * to skip r initial rows of image * -- use of glPixelStorei(GL_UNPACK_SKIP_PIXELS, c); * to skip c initial pixels of each row of image * -- use of glPixelStorei(GL_UNPACK_ROW_LENGTH, C); * to specify that the FULL image rows has C column * * Keyboard commands: * q = quit * s = switch to the next pixmap for display * w = write the current buffer out to a file "out.bmp" * o = read from out.bmp file into current pixmap * f = re-read input file of current pixmap * x/X = pan right/left * y/Y = pan up/down * (ALTERNATIVELY, USE vi's Keystrokes: * l = left, h = right, j = down, k = up) * g = reads into pixmap a 200x200 portion of screen at * current raster position (set with Left-mouse click, * see below) * * Mouse actions: * Mouse drag = current image is dragged along * Right-click = clears the screen. * * Adapted from pixmap.cc ************************************************************/ #include // needed for use of cout #include // needed for math functions exp(x), etc #include "RGBpixmap.h" #ifdef _WINDOZ #include #include #else #include #endif // #include "app3.cc" // grab bag of routines from Appendix 3 of book, // but many functions omitted (do not compile) ///////////////////////////////////////////////////////////// // Constants ///////////////////////////////////////////////////////////// const double ZOOMSCALE = 2; const int defaultWidth = 600; const int defaultHeight = 480; int screenWidth = defaultWidth; int screenHeight = defaultHeight; int show_loc = 0; char out_buffer[30], buffer[80]; // names of bmp files to read: const int numPics = 3; // number of pictures to show char * fname[numPics+1] = { "/home/yap/public_html/data/edges/MVC-001F.bmp", "/home/yap/public_html/data/edges/MVC-002F.bmp", "/home/yap/public_html/data/edges/MVC-004F.bmp", "out.bmp"}; // out.bmp is for output, not for reading! RGBpixmap pic[numPics]; // create numPics global pixmaps int whichPic = 0; // current pixmap to display // position for panning IntPoint rasterPos(0,0); // rasterPos for drawing image IntPoint lastMousePos(0,0); // differential position for mouse motion int speed = 1; // speed for keyboard panning // scaling float sx = 1.0; float sy = 1.0; //<<<<<<<<<<<<<<<<<<<<<<<<< myMouse >>>>>>>>>>>>>>>>>>>>>>>> void myMouse(int button, int state, int mx, int my) { // set raster position with a left click if(button == GLUT_LEFT_BUTTON) { lastMousePos.x = mx; lastMousePos.y = my; } else { glutPostRedisplay(); } } //<<<<<<<<<<<<<<<<<<<<<<<<< myMouse >>>>>>>>>>>>>>>>>>>>>>>> void paMove(int mx, int my) { // mouse movement, without any button pressed. sprintf(out_buffer, "(%3d,%3d)", mx, my); glutPostRedisplay(); } //<<<<<<<<<<<<<<<<<<<<<<<<< mouseMove >>>>>>>>>>>>>>>>> void mouseMove(int mx, int my) { // set raster position with mouse motion rasterPos.x -= mx - lastMousePos.x; rasterPos.y -= lastMousePos.y - my; lastMousePos.x = mx; lastMousePos.y = my; sprintf(out_buffer, "(%3d,%3d)", mx, my); glutPostRedisplay(); }// mouseMove //<<<<<<<<<<<<<<<<<<<<<<<<<< myReshape >>>>>>>>>>>>>>>>>>> void myReshape(int w, int h) { screenWidth = w; screenHeight = h; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, w, 0.0,h); glMatrixMode(GL_MODELVIEW); }// myReshape //<<<<<<<<<<<<<<<<<<<<<<< myDisplay >>>>>>>>>>>>>>>>>>>>>>>>>> void myDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); RGBpixmap pm = pic[whichPic]; pm.draw(rasterPos.x, rasterPos.y); if (show_loc) { char *p; glPushMatrix(); glScalef(.08, .08, 1.); glTranslatef(20., screenHeight - 50., 0.); sprintf(buffer, "%s scale: %7.3f pan: (%d, %d) ", out_buffer, sx, rasterPos.x, rasterPos.y); for (p = buffer; *p; p ++) glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, *p); glPopMatrix(); } glFlush(); glutSwapBuffers(); } //<<<<<<<<<<<<<<<<<<<<<<<< mySpclKeys >>>>>>>>>>>>>>>>>>>>>> void mySpclKeys(int key, int , int ) { int ctrl = (glutGetModifiers() & GLUT_ACTIVE_SHIFT); switch (key) { case GLUT_KEY_UP: rasterPos.y += ctrl ? (int)(screenHeight/sy):speed; break; case GLUT_KEY_DOWN: rasterPos.y -= ctrl ? (int)(screenHeight/sy):speed; break; case GLUT_KEY_LEFT: rasterPos.x -= ctrl ? (int)(screenWidth/sx):speed; break; case GLUT_KEY_RIGHT: rasterPos.x += ctrl ? (int)(screenWidth/sx):speed; break; case GLUT_KEY_PAGE_DOWN: rasterPos.y -= (int)(screenHeight / sy); break; case GLUT_KEY_PAGE_UP: rasterPos.y += (int)(screenHeight / sy); break; case GLUT_KEY_HOME: // reset rasterPos.x = 0; rasterPos.y = 0; sx = 1.0; sy = 1.0; speed = 1; glPixelZoom(sx, sy); glutPostRedisplay(); break; } glutPostRedisplay(); } //<<<<<<<<<<<<<<<<<<<<<<<< myKeys >>>>>>>>>>>>>>>>>>>>>> void myKeys(unsigned char key, int x, int y) { RGBpixmap pm; RGBpixmap * outpm; GLint value[4]; int v[5]; switch(key) { int read_w, read_h; case 27: case 'q': exit(0); break; case 's': // switch image whichPic++; if (whichPic >= numPics) whichPic=0; glPixelStorei(GL_UNPACK_ROW_LENGTH, pic[whichPic].nCols); rasterPos.x = 0; rasterPos.y = 0; sx = 1.0; sy = 1.0; glPixelZoom(sx, sy); glutPostRedisplay(); break; case 'g': // grab a piece y = screenHeight - y - 1 - 200; // read_w = (screenWidth - x > 200) ? 200: screenWidth - x; read_h = (screenHeight - y > 200) ? 200: screenHeight - y; if (y < 0) { read_h += y; y = 0; } pic[whichPic].read(x, y, read_w, read_h); // pic[whichPic].read(rasterPos.x, rasterPos.y, // rasterPos.x+200, rasterPos.y+200); break; case 'w': // write current buffer to out.bmp file outpm = new RGBpixmap(screenHeight, screenWidth); glPixelStorei(GL_PACK_ALIGNMENT,1); glReadPixels(0,0, screenWidth, screenHeight, GL_RGB, GL_UNSIGNED_BYTE, outpm->pixel); outpm->writeBMPFile("out.bmp"); break; case 'R': // read file again pic[whichPic].readBMPFile(fname[numPics]); //fname[numPics]="out.bmp" glPixelStorei(GL_UNPACK_ROW_LENGTH, pic[whichPic].nCols); break; case 'f': // read current file again pic[whichPic].readBMPFile(fname[whichPic]); //re-read file glPixelStorei(GL_UNPACK_ROW_LENGTH, pic[whichPic].nCols); break; case 'r': // reset rasterPos.x = 0; rasterPos.y = 0; sx = 1.0; sy = 1.0; speed = 1; glPixelZoom(sx, sy); glutPostRedisplay(); break; case 'l': case 'x': // translate x rasterPos.x += speed; break; case 'k': case 'y': // translate y rasterPos.y += speed; break; case 'h': case 'X': // translate -x rasterPos.x -= speed; break; case 'j': case 'Y': // translate -y rasterPos.y -= speed; break; case 'a': // accelerate speed += 1; break; case 'A': // accelerate speed -= 1; if (speed == 0) speed = 1; break; case '0': glGetIntegerv(GL_RED_BITS, value); v[0] = value[0]; glGetIntegerv(GL_GREEN_BITS, value); v[1] = value[0]; glGetIntegerv(GL_BLUE_BITS, value); v[2] = value[0]; glGetIntegerv(GL_INDEX_BITS, value); v[3] = value[0]; cout << "Red (bit per pixel): " << v[0] << endl << "Green (bit per pixel): " << v[1] << endl << "Blue (bit per pixel): "<< v[2] << endl; break; case 'i': sx *= ZOOMSCALE; sy *= ZOOMSCALE; glPixelZoom(sx, sy); break; // zoom in case 'o': sx /= ZOOMSCALE; sy /= ZOOMSCALE; glPixelZoom(sx, sy); break; // zoom in case '1': show_loc = 1 - show_loc; if (!show_loc) for (int i = 0; i < 30 ; i ++) buffer[i] = ' '; buffer[31] = 0; break; } glutPostRedisplay(); } //<<<<<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>>>>>> int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(screenWidth, screenHeight); glutInitWindowPosition(30, 30); glutCreateWindow("Panning Images"); // the next three lines are essential for the // glRasterPos2i(x,y) to work properly! glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0, (GLdouble)screenWidth, 0.0, (GLdouble)screenHeight); glMatrixMode(GL_MODELVIEW); glutKeyboardFunc(myKeys); glutSpecialFunc(mySpclKeys); glutMouseFunc(myMouse); // mouse button down or up glutMotionFunc(mouseMove); // mouse motion with any button down glutPassiveMotionFunc(paMove);// mouse motion without any button down glutDisplayFunc(myDisplay); glutReshapeFunc(myReshape); glClearColor(0.9f, 0.9f, 0.9f, 0.0); //background color glClear(GL_COLOR_BUFFER_BIT); // initialize images for (int i=0; i< numPics; i++) pic[i].readBMPFile(fname[i]); //make a pixmap // Need to control the pixel-storage mode in a per image basis! // See the key board commands for panning // glPixelStorei(GL_UNPACK_ALIGNMENT,1); glPixelStorei(GL_UNPACK_ROW_LENGTH, pic[whichPic].nCols); glutMainLoop(); }