//<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> // <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> // Basic FLTK/OpenGL Template // main.cpp // // Written by Kristi Potter // Feb 4, 2006 // <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> //<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> // System Includes #include #include #include // FLTK Includes (also includes GL) #include #include #include #include #include #include using namespace std; //~~~~~~~~~~~~~~~~~~~~ Typedef Structs ~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Color Pixel Struct typedef struct { unsigned char r, g, b; /* use 256 colors */ } rgb_pixel; // 2D Point Struct typedef struct { float x, y; // x and y coordinates } point; // 2D Line Struct typedef struct { float x0, y0; // The 1st endpoint float x1, y1; // The 2nd endpoint } line; //~~~~~~~~~~~~~~~~~~~~~ Class Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~// //-------------- MyWindow Class -----------------------------------// // Subclass of the fltk gl window. We must define draw and handle // // functions. The draw function contains ALL openGL calls. The // // handle function handles mouse and keyboard I/O. // //-----------------------------------------------------------------// class glWindow : public Fl_Gl_Window { public: glWindow(int X, int Y, int W, int H, const char *L) : Fl_Gl_Window(X, Y, W, H, L) {mouse_counter = 0;} // Class Functions void draw(); int handle(int); // Private Variables point p1, p2; int mouse_counter; }; //~~~~~~~~~~~~~~~~~~~~~~ Global Variables ~~~~~~~~~~~~~~~~~~~~~~~~~~// // Keyboard/mouse interaction variables int last_x; int last_y; int last_z; // Dimensions of the openGL window const int screenWidth = 512; const int screenHeight = 512; // A value slider Fl_Value_Slider * slide; // openGL drawing window glWindow * gl_window; // A point collection rgb_pixel points_color; vector points; // A line collection rgb_pixel lines_color; vector lines; // The coordinate axes rgb_pixel axes_color; vector axes(2); //~~~~~~~~~~~~~~~~~~~~ Function Prototypes ~~~~~~~~~~~~~~~~~~~~~~~~// // User Interface Callback Functions void saveCallback(Fl_Widget *w, void *data); void idleCallback(void * data); void buttonCallback(Fl_Widget *w, void *data); void sliderCallback(Fl_Widget *w, void *data); void quitCallback(Fl_Widget *w, void *data); // Add a point to a point collection vector addPointToCollection(point p, vector collection); // Add a line to a line collection vector addLineToCollection(line l, vector collection); // Draw a single point onto the screen void drawPoint(int x0, int y0); // Draw a single line onto the screen void drawLine(float x0, float y0, float x1, float y1); // Draw a line collection onto the screen void drawLineCollection(vector collection, rgb_pixel color); // Draw a point collection onto the screen void drawPointCollection(vector collection, rgb_pixel color); // Saves the display window to a ppm image int save_raw_ppm_image(char*); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //+%+%+%+%+%+%+%+%+ Function Definitions %+%+%+%+%+%+%+%+%+%+%+// //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ // Main //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ int main(int argc, char **argv) { // Create the main fltk UI window Fl_Window *main_window = new Fl_Window(532, 650, "OpenGL with FLTK Template"); // Create the menu for the main FL window Fl_Menu_Bar * menu_bar = new Fl_Menu_Bar(0, 0, 1054, 30); Fl_Menu_Item menu_items[] ={ {"File", 0, 0, 0, FL_SUBMENU}, {"Save Image", FL_ALT+'s', saveCallback}, {"&Quit", FL_ALT+'q', quitCallback}, {0}, {0}}; menu_bar->menu(menu_items); // Create the openGL window gl_window = new glWindow(10, 50, 512, 512, "OpenGL Window"); gl_window->end(); // Add a button Fl_Button * button = new Fl_Button(gl_window->x() + 10, gl_window->y() + gl_window->h() + 20, 100, 50, "Button"); button->callback(buttonCallback); // Add a horizontal slider slide = new Fl_Value_Slider(gl_window->x() + gl_window->w()/2 + 10, gl_window->y() + gl_window->h() + 30, 200, 25,"Slider"); slide->type(FL_HOR_NICE_SLIDER); slide->callback(sliderCallback); slide->when(FL_WHEN_RELEASE); slide->bounds(0, 10); slide->step(1); slide->value(5); // End the main window, show & run main_window->end(); main_window->show(argc, argv); // Make the idle redraw the glWindow Fl::add_idle(idleCallback); return Fl::run(); } //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ // Save Button Callback function // Action for save button. //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ void saveCallback(Fl_Widget *w, void *data) { save_raw_ppm_image("image.ppm"); } //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ // idleCallback // What to do when the fltk window is idle. //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ void idleCallback(void * data) { gl_window->redraw(); } //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ // Call back for the button //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ void buttonCallback(Fl_Widget *w, void *data) { cout << "Button Pushed!" << endl; } //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ // Call back for the value slider //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ void sliderCallback(Fl_Widget *w, void *data) { cout << "Slider Value: " << slide->value() << endl; } //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ // Quit Button Callback function // Action for quit button. //+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+ void quitCallback(Fl_Widget *w, void *data) { exit(0); } //--------------------------------------------------------------------// // glWindow Class // //--------------------------------------------------------------------// //--------------------------------------------------------------------// // draw // Place all openGL calls here. If there are GL calls that should be // called only once put them inside the if(!valid()) branch. //--------------------------------------------------------------------// void glWindow::draw() { // Valid is set to true after the draw function is called ONCE if(!valid()) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Put calls here that should only be called ONCE. // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Set the background color to black glClearColor(0.0, 0.0, 0.0, 1.0); // Enable the depth test glEnable(GL_DEPTH_TEST); // Set the coordinate axes color axes_color.r = 255; axes_color.g = 0; axes_color.b = 0; // Initialize the coordinate axes line l1; l1.x0 = 0.0; l1.y0 = screenHeight/2; l1.x1 = screenWidth; l1.y1 = screenHeight/2; axes = addLineToCollection(l1, axes); line l2; l2.x0 = screenWidth/2; l2.y0 = 0.0; l2.x1 = screenWidth/2; l2.y1 = screenHeight; axes = addLineToCollection(l2, axes); // Initialize the points collection color points_color.r = 0; points_color.g = 255; points_color.b = 255; // Intialize the lines collection color lines_color.r = 255; lines_color.g = 255; lines_color.b = 255; } // Clear the buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Load the projection matrix glMatrixMode( GL_PROJECTION ); // Set the projection matrix to the identity matrix glLoadIdentity(); // Set an orthographic projection gluOrtho2D(0.0f,(float)screenWidth,(float)screenHeight,0.0f); //Load the modelview matrix glMatrixMode(GL_MODELVIEW); // Set the modelview matrix to the identity glLoadIdentity(); // Push a new matrix on the stack for translations glPushMatrix(); { glPushMatrix(); { //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$// // Put all drawing stuff here. // // For the first and second assignments, you will not need to // // change this section at all. // //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$// // Draw the coordinate axis drawLineCollection(axes, axes_color); // Draw the line collection drawLineCollection(lines, lines_color); // Draw the point collection drawPointCollection(points, points_color); } glPopMatrix(); } // Pop the translations off the matrix stack glPopMatrix(); // Flush all drawing to the screen glFlush(); } //--------------------------------------------------------------------// // glWindow:handle // Deal with all mouse and keyboard i/o. //--------------------------------------------------------------------// int glWindow::handle(int event) { switch(event) { //+$+$+$+$+$ Mouse Down Event $+$+$+$+// case FL_PUSH: // Left Mouse Button if(Fl::event_button() == 1) { point p; p.x = Fl::event_x(); p.y = Fl::event_y(); cout <<"The mouse position is ("< addPointToCollection(point p, vector collection) { collection.push_back(p); return collection; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // addLineToCollection // // Add a line to a line collection // //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// vector addLineToCollection(line l, vector collection) { collection.push_back(l); return collection; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // drawPoint // // Draw a single point onto the screen. // //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// void drawPoint(int x, int y) { glBegin(GL_POINTS); { glVertex2f(x, y); } glEnd(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // drawLine // // Draw a single line onto the screen. // //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// void drawLine(float x0, float y0, float x1, float y1) { glBegin(GL_LINES); { glVertex2f(x0, y0); glVertex2f(x1, y1); } glEnd(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // drawLineCollection // // Draw a line collection onto the screen // //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// void drawLineCollection(vector collection, rgb_pixel color) { glBegin(GL_LINES); { glColor3ub(color.r, color.g, color.b); for(int i = 0; i < collection.size(); i++) { glVertex2f(collection[i].x0, collection[i].y0); glVertex2f(collection[i].x1, collection[i].y1); } } glEnd(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // drawPointCollection // // Draw a point collection onto the screen // //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// void drawPointCollection(vector collection, rgb_pixel color) { glBegin(GL_POINTS); { glColor3ub(color.r, color.g, color.b); for(int i = 0; i < collection.size(); i++) { glVertex2f(collection[i].x, collection[i].y); } } glEnd(); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// // save_raw_ppm_image // // Saves the display window to the image called filename. //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// int save_raw_ppm_image(char *filename) { // Read in pixels from the framebuffer rgb_pixel canvas[screenWidth * screenHeight]; glReadPixels(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight, GL_RGB, GL_UNSIGNED_BYTE, canvas); /* see http://www.swin.edu.au/astronomy/pbourke/dataformats/ppm/ */ /* or a detailed description of PPM and related formats */ FILE *fp; int total_size, count, row_count, column_count; fp = fopen(filename, "w"); if(!fp) { fprintf(stderr, "Unable to open %s for writing\n", filename); return(0); } /* create the raw PPM header */ fprintf(fp,"P6\n"); /* print the type identifier */ fprintf(fp,"# template image\n"); /*comment */ fprintf(fp,"%d %d\n255\n", screenWidth, screenHeight); /* header complete - now write the image */ /* due to the format of PPM, we need to write out rows in reverse order, * but columns in standard order. */ total_size = screenWidth * screenHeight; row_count = 1; column_count = 1; count = total_size - (row_count * screenWidth); while(row_count <= screenHeight) { /* fill in each row */ fprintf(fp,"%c%c%c", canvas[count].r, canvas[count].g, canvas[count].b); count++; column_count++; if(column_count > screenWidth) { /* we have reached the end of a row - start the next one */ row_count++; count = total_size - (row_count * screenWidth); column_count = 1; } } fclose(fp); return(1); }