//-------------------------------------------------- // GLWidget.cpp -- implementation of GLWidget class //-------------------------------------------------- #include #include #ifdef WIN32 #include #endif #include #include "glWidget.h" #include #include using namespace std; static bool idle_flag = false; //====================================================================== // call back function used usually for animation; here the new position // of the raster image is set, based on a straightline path. // void IdleCallback(void* pData) { if (pData != NULL) { GLWidget* glw = reinterpret_cast(pData); if (glw->t_param < 0.95) { glw->posx = glw->pt1[0] + glw->t_param*(glw->pt2[0] - glw->pt1[0]); glw->posy = glw->pt1[1] + glw->t_param*(glw->pt2[1] - glw->pt1[1]); glw->t_param += 0.01; glw->redraw(); } } } //====================================================================== GLWidget::GLWidget( int x, int y, int w, int h, const char *l ) : Fl_Gl_Window( x, y, w, h, l ) { num_points = 0; t_param = 0.; setWindowExtents(); // load raster image (ppm ascii format) loadPPMImage(); // some GL initializations mode( FL_DOUBLE | FL_RGB ); // Set the clear color to black glClearColor( 0.0, 0.0, 0.0, 1.0 ); changeMode( CLEAR_SCREEN ); } int GLWidget::handle( int event ) { // The handle() function, reimplemented from // Fl_Gl_Window, notifies us of any user input // in our OpenGL drawing area. There are various // Fl::event_ functions to get event parameters like // which button or key pressed, mouse x and y // position, etc. switch( event ) { // Mouse button pressed case FL_PUSH: // If it was the right button, clear the screen if( Fl::event_button3() ) { changeMode( CLEAR_SCREEN ); } else if( drawmode == DRAW_LINE ) { if( !num_points ) { // Get the first point on the line x0 = Fl::event_x(); y0 = Fl::event_y(); num_points++; } else { // Get the second point on the line // and draw it x1 = Fl::event_x(); y1 = Fl::event_y(); num_points++; redraw(); } } else if( drawmode == DRAW_FREE ) { // Get the first point for freehand drawing x0 = x1 = Fl::event_x(); y0 = y1 = Fl::event_y(); } // Must return 1 to let FLTK know we handled the // event. Otherwise, it may get sent to another // widget. return 1; // Called repeatedly while there is mouse movement // with a button down case FL_DRAG: if( drawmode == DRAW_FREE ) { // Move current point to previous and get // a new point. Draw a line between these two. x0 = x1; y0 = y1; x1 = Fl::event_x(); y1 = Fl::event_y(); num_points++; redraw(); } return 1; } // Send any event we didn't use to the default handler return Fl_Gl_Window::handle( event ); } void GLWidget::setWindowExtents() { // Fl::event_x() and Fl::event_y() return mouse position // in pixels from top-left of drawing area. So we'll set // GL's window extents to match: // x = 0 (left) to 700 (right), y = 500 (bottom) to 0 (top) gluOrtho2D( 0, 700, 500, 0 ); } void GLWidget::changeMode( DrawMode newmode ) { drawmode = (DrawMode)newmode; num_points = 0; // If Clear Screen was selected we want to // go ahead and redraw. if ( drawmode == CLEAR_SCREEN ) redraw(); if (newmode == DRAW_IMAGE) { // initialize line parameters t_param = 0.; pt1[0] = 0.; pt1[1] = 300.; pt2[0] = 400.; pt2[1] = 0.; // add idle callback function if this // mode is selected if (!idle_flag) { Fl::add_idle(IdleCallback, this); idle_flag = true; } else redraw(); } else if (idle_flag) // changing modes - remove idle // callback, else it will tie up the CPU! { Fl::remove_idle(IdleCallback); idle_flag = false; } } void GLWidget::draw() { // All drawing code goes in the draw() function, which is // reimplemented from Fl_Gl_Window. // // NOTE: draw() should only be called by the system. To // explicitly redraw the screen in your code, call // redraw(). This doesn't swap buffers. if( !valid() ) { // If our window has been invalidated (for example // minimized then restored), we'll have to reset // the window parameters. setWindowExtents(); } switch( drawmode ) { case CLEAR_SCREEN: // This clears the drawing area to // our preset glClearColor. glClear( GL_COLOR_BUFFER_BIT ); break; case DRAW_LINE: // Don't do anything if not explicitly called if( num_points != 2 ) break; // Draw a "tan" line from (x0,y0) to (x1,y1) glBegin( GL_LINES ); glColor3f( 1.0, 0.5, 0.0 ); glVertex2i( x0, y0 ); glVertex2i( x1, y1 ); glEnd(); num_points = 0; break; case DRAW_FREE: // Don't do anything if not explicitly called if( num_points == 0 ) break; // Draw a "mint" line from (x0,y0) to (x1,y1) glBegin( GL_LINES ); glColor3f( 0.0, 1.0, 0.5 ); glVertex2i( x0, y0 ); glVertex2i( x1, y1 ); glEnd(); break; case DRAW_IMAGE: glClear(GL_COLOR_BUFFER_BIT); glColor3f (1., 0.5, 0.); glRasterPos2f(posx, posy); glDrawPixels (image_w,image_h,GL_RGB,GL_UNSIGNED_BYTE,(GLvoid*)image); break; } } ////////////////////////////////////////////////////////////////// void GLWidget::loadPPMImage() { // ppm ascii read module ifstream infile("./mona4.bw"); // if (!infile) // { // cout << "File mona2.bw doesnt exist!" << endl; // exit (-1); // } char str[2000]; // quick and dirty load - not enough error checking! // skip the first 3 lines infile.getline(str, 2000); infile.getline(str, 2000); infile.getline(str, 2000); // allocate image array (RGB) int width, height, col_val; infile >> image_w >> image_h; image = new GLubyte[image_w*image_h*3]; // note that the each row of the image array must start // on a word boundary, else the image drawn by // glDrawPixels will be distorted - messed up int k = 0; for (int i = 0; i < image_h; i++) { k = (image_h -i -1)*image_w*3; for (int j = 0; j < image_w; j++) { infile >> col_val >> col_val >> col_val; image[k] = (GLubyte) col_val; image[k+1] = (GLubyte) col_val; image[k+2] = (GLubyte) col_val; k += 3; } } } //////////////////////////////////////////////////////////////////