Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

FltkOpenGLDisplayDevice.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: FltkOpenGLDisplayDevice.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.63 $       $Date: 2011/04/12 14:34:39 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * Subclass of DisplayDevice, this object has routines used by all the
00020  * different display devices that are OpenGL-specific.  Will render drawing
00021  * commands into a single X window.
00022  *
00023  ***************************************************************************/
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <math.h>
00028 #include "FltkOpenGLDisplayDevice.h"
00029 #include "Inform.h"
00030 #include "utilities.h"
00031 #include "config.h"   // VMD version strings etc
00032 #include "VMDApp.h"  
00033 #include "FL/Fl.H"
00034 #include "FL/Fl_Gl_Window.H"
00035 #include "FL/forms.H"
00036 
00039 class myglwindow : public Fl_Gl_Window {
00040   FltkOpenGLDisplayDevice *dispdev;
00041   VMDApp *app;     // cached VMDApp handle for use in drag-and-drop
00042   int dragpending; // flag indicating incoming PASTE event is drag-and-drop
00043 
00044 public:
00045   myglwindow(int wx, int wy, int width, int height, const char *nm, 
00046     FltkOpenGLDisplayDevice *d, VMDApp *vmdapp) 
00047   : Fl_Gl_Window(wx, wy, width, height, nm), dispdev(d), app(vmdapp), dragpending(0) {
00048     // XXX this may not be reliable on MacOS X with recent revs of FLTK
00049     size_range(1,1,0,0); // resizable to full screen
00050  }
00051 
00052   int handle(int event) {
00053 #if 1
00054     // handle paste operations
00055     if (event == FL_PASTE) {
00056       // ignore paste operations that weren't due to drag-and-drop
00057       // since they could be any arbitrary data/text, and not just filenames.
00058       if (dragpending) {
00059         int len = Fl::event_length();
00060 
00061         // ignore zero-length paste events (why do these occur???)
00062         if (len > 0) {
00063           int numfiles, i;
00064           const char *lastc;
00065           int lasti;
00066           FileSpec spec;
00067           const char *ctext = Fl::event_text();
00068           char *filename = (char *) malloc((1 + len) * sizeof(char));
00069 
00070           for (lasti=0,lastc=ctext,numfiles=0,i=0; i<len; i++) {
00071             // parse out all but last filename, which doesn't have a CR
00072             if (ctext[i] == '\n') {
00073               memcpy(filename, lastc, (i-lasti)*sizeof(char));
00074               filename[i-lasti] = '\0';
00075   
00076               // attempt to load the file into a new molecule
00077               app->molecule_load(-1, filename, NULL, &spec);
00078   
00079               lasti=i+1;
00080               lastc=&ctext[lasti];
00081               numfiles++;
00082             }
00083   
00084             // special-case last filename, since there's no CR
00085             if (i == (len-1)) {
00086               memcpy(filename, lastc, (1+i-lasti)*sizeof(char));
00087               filename[1+i-lasti] = '\0';
00088   
00089               // attempt to load the file into a new molecule
00090               app->molecule_load(-1, filename, NULL, &spec);
00091               numfiles++;
00092             }
00093           }
00094   
00095           free(filename);
00096         }
00097   
00098         dragpending = 0; // no longer waiting for drag-and-drop paste
00099       }
00100   
00101       return 1; // indicate that we handled the paste operation
00102     }
00103 
00104     // handle drag-and-drop operations
00105     if (event == FL_DND_ENTER || event == FL_DND_DRAG) {
00106       return 1; // indicate that we want the drag-and-drop operation
00107     }
00108     if (event == FL_DND_RELEASE) {
00109       Fl::paste(*this);
00110       dragpending = 1; // flag to expect incoming paste due to DND operation
00111       return 1;
00112     }
00113 #endif
00114 
00115     switch (event) {
00116       case FL_MOUSEWHEEL:
00117         dispdev->lastevent = event;
00118         dispdev->lastzdelta = Fl::event_dy();
00119         break;
00120       case FL_PUSH:
00121         dispdev->lastevent = event;
00122         dispdev->lastbtn = Fl::event_button();
00123         if (dispdev->lastbtn == FL_LEFT_MOUSE && Fl::event_state(FL_META)) {
00124           dispdev->lastbtn = FL_MIDDLE_MOUSE; 
00125         }
00126         break;
00127       case FL_DRAG:
00128         dispdev->lastevent = event;
00129         break;
00130       case FL_RELEASE:
00131         dispdev->lastevent = event;
00132         break;
00133 #if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 1)
00134       case FL_KEYDOWN:
00135 #else
00136       // This event code is superceded by FL_KEYDOWN in newer revs of FLTK
00137       case FL_KEYBOARD:
00138 #endif
00139         dispdev->lastevent = event;
00140         dispdev->lastkeycode = Fl::event_key();
00141         dispdev->lastbtn = *Fl::event_text();
00142         break; 
00143       default:
00144         return Fl_Gl_Window::handle(event);
00145     }
00146     return 1;
00147   }
00148   void draw() {
00149     dispdev->reshape();
00150     dispdev->_needRedraw = 1;
00151     app->VMDupdate(VMD_IGNORE_EVENTS);
00152   }    
00153   // override the hide() method since we have no way of getting it back
00154   void hide() {
00155     if (fl_show_question("Really Quit?", 0))
00156       app->VMDexit("",0,0);
00157   }
00158 };
00159  
00160 
00161 // static data for this object
00162 static const char *glStereoNameStr[OPENGL_STEREO_MODES] = 
00163  { "Off", 
00164    "QuadBuffered", 
00165    "DTI SideBySide",
00166    "Checkerboard",
00167    "ColumnInterleaved",
00168    "RowInterleaved",
00169    "Anaglyph", 
00170    "SideBySide", 
00171    "AboveBelow",
00172    "Left", 
00173    "Right" };
00174 
00175 static const char *glRenderNameStr[OPENGL_RENDER_MODES] =
00176 { "Normal",
00177   "GLSL",
00178   "Acrobat3D" }; 
00179 
00180 static const char *glCacheNameStr[OPENGL_CACHE_MODES] =
00181 { "Off",
00182   "On" };
00183 
00185 
00186 // constructor ... open a window and set initial default values
00187 FltkOpenGLDisplayDevice::FltkOpenGLDisplayDevice(int argc, char **argv, 
00188   VMDApp *vmdapp, int *size, int *loc)
00189     : OpenGLRenderer((char *) "VMD " VMDVERSION " OpenGL Display") {
00190 
00191   // set up data possible before opening window
00192   stereoNames = glStereoNameStr;
00193   stereoModes = OPENGL_STEREO_MODES;
00194 
00195   // GLSL is only available on MacOS X 10.4 and later.
00196   renderNames = glRenderNameStr;
00197   renderModes = OPENGL_RENDER_MODES;
00198 
00199   cacheNames = glCacheNameStr;
00200   cacheModes = OPENGL_CACHE_MODES;
00201 
00202   // open the window
00203   int SX = 100, SY = 100, W, H;
00204 
00205   W = size[0];
00206   H = size[1];
00207   if (loc) {
00208     SX = loc[0];
00209     SY = loc[1];
00210   }
00211   window = new myglwindow(SX, SY, W, H, name, this, vmdapp);
00212 
00213   ext->hasstereo = FALSE;         // stereo is off initially
00214   ext->stereodrawforced = FALSE;  // stereo not forced initially
00215   ext->hasmultisample = FALSE;    // multisample is off initially
00216 
00217   int rc=0;
00218 // FLTK stereo support only started working for MacOS X at around version 1.1.7
00219 #if (FL_MAJOR_VERSION >= 1) && (((FL_MINOR_VERSION >= 1) && (FL_PATCH_VERSION >= 7)) || ((FL_MINOR_VERSION >= 1) && (FL_PATCH_VERSION >= 7)))
00220   // find an appropriate visual and colormap ...
00221   if (getenv("VMDPREFERSTEREO") != NULL) {
00222     // Stereo limps along with FLTK 1.1.7 on MacOS X
00223     rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL | FL_STEREO);
00224     ext->hasstereo = TRUE;
00225 #if defined(__APPLE__)
00226     ext->stereodrawforced = TRUE; // forced draw in stereo all the time when on
00227 #endif
00228   // FLTK multisample antialiasing still doesn't actually work in 
00229   // MacOS X as of FLTK 1.1.10...
00230 #if !defined(__APPLE__)
00231   //  } else if (getenv("VMDPREFERMULTISAMPLE") != NULL) {
00232   } else if (rc != 0) {
00233     rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL | FL_MULTISAMPLE);
00234     ext->hasmultisample = TRUE; // FLTK only does SGI multisample, no ARB yet
00235 #endif
00236   } else {
00237     rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL);
00238   }
00239 #else
00240   // find an appropriate visual and colormap ...
00241   rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL);
00242 #endif
00243 
00244   window->show();
00245   // (7) bind the rendering context to the window
00246   window->make_current();
00247 
00248   // (8) actually request the window to be displayed
00249   screenX = Fl::w();
00250   screenY = Fl::h();  
00251 
00252   // (9) configure the rendering properly
00253   setup_initial_opengl_state();  // setup initial OpenGL state
00254   
00255   // set flags for the capabilities of this display
00256   // whether we can do antialiasing or not.
00257   if (ext->hasmultisample) 
00258     aaAvailable = TRUE;  // we use multisampling over other methods
00259   else
00260     aaAvailable = FALSE; // no non-multisample implementation yet
00261 
00262   // set default settings
00263   if (ext->hasmultisample) {
00264     aa_on();  // enable fast multisample based antialiasing by default
00265               // other antialiasing techniques are slow, so only multisample
00266               // makes sense to enable by default.
00267   } 
00268 
00269   cueingAvailable = TRUE;
00270   cueing_on(); // leave depth cueing on by default, despite the speed hit.
00271 
00272   cullingAvailable = TRUE;
00273   culling_off();
00274 
00275   set_sphere_mode(sphereMode);
00276   set_sphere_res(sphereRes);
00277   set_line_width(lineWidth);
00278   set_line_style(lineStyle);
00279 
00280   // reshape and clear the display, which initializes some other variables
00281   reshape();
00282   normal();
00283   clear();
00284   update();
00285 }
00286 
00287 // destructor ... close the window
00288 FltkOpenGLDisplayDevice::~FltkOpenGLDisplayDevice(void) {
00289   free_opengl_ctx(); // free display lists, textures, etc
00290   delete window;
00291 }
00292 
00294 
00295 //
00296 // get the current state of the device's pointer (i.e. cursor if it has one)
00297 //
00298 
00299 // abs pos of cursor from lower-left corner of display
00300 int FltkOpenGLDisplayDevice::x(void) {
00301   //Fl::check();
00302 #if 1
00303   return Fl::event_x_root();  
00304 #else
00305   int x, y;
00306   Fl::get_mouse(x, y);
00307   return x;  
00308 #endif
00309 }
00310 
00311 
00312 // same, for y direction
00313 int FltkOpenGLDisplayDevice::y(void) {
00314   //Fl::check();
00315 #if 1
00316   return screenY - Fl::event_y_root();
00317 #else
00318   int x, y;
00319   Fl::get_mouse(x, y);
00320   return screenY - y;  
00321 #endif
00322 }
00323 
00324 // return the current state of the shift, control, and alt keys
00325 int FltkOpenGLDisplayDevice::shift_state(void) {
00326   Fl::check();
00327    
00328   int retval = 0;
00329   int keymask = (int) Fl::event_state();
00330   if (keymask & FL_SHIFT)
00331     retval |= SHIFT;
00332   if (keymask & FL_CTRL)
00333     retval |= CONTROL;
00334   if (keymask & FL_ALT)
00335     retval |= ALT;
00336   return retval;
00337 }
00338 
00339 // return the spaceball state, if any
00340 int FltkOpenGLDisplayDevice::spaceball(int *rx, int *ry, int *rz, int *tx, int *ty,
00341 int *tz, int *buttons) {
00342   // not implemented yet
00343   return 0;
00344 }
00345 
00346 
00347 // set the Nth cursor shape as the current one.  If no arg given, the
00348 // default shape (n=0) is used.
00349 void FltkOpenGLDisplayDevice::set_cursor(int n) {
00350   switch (n) {
00351     default:
00352     case DisplayDevice::NORMAL_CURSOR: window->cursor(FL_CURSOR_ARROW); break;
00353     case DisplayDevice::TRANS_CURSOR: window->cursor(FL_CURSOR_MOVE); break;
00354     case DisplayDevice::SCALE_CURSOR: window->cursor(FL_CURSOR_WE); break;
00355     case DisplayDevice::PICK_CURSOR: window->cursor(FL_CURSOR_CROSS); break;
00356     case DisplayDevice::WAIT_CURSOR: window->cursor(FL_CURSOR_WAIT); break;
00357   }
00358 }
00359 
00360 
00361 //
00362 // event handling routines
00363 //
00364 
00365 // read the next event ... returns an event type (one of the above ones),
00366 // and a value.  Returns success, and sets arguments.
00367 int FltkOpenGLDisplayDevice::read_event(long &retdev, long &retval) {
00368 #if !defined(__APPLE__)
00369     // disabled on OSX to avoid problems with Tcl/Tk mishandling events.
00370     // XXX this code was previously being used on MacOS X for Intel, but
00371     //     it seems that it should match what we do on PowerPC so we 
00372     //     do the same in all MacOS X cases now.
00373     Fl::check();
00374 #endif
00375   
00376   switch (lastevent) {
00377     case FL_MOUSEWHEEL:
00378       // XXX tests on the Mac show that FLTK is using a coordinate system 
00379       // backwards from what is used on Windows' zDelta value.
00380       if (lastzdelta < 0) {
00381         retdev = WIN_WHEELUP;
00382       } else {
00383         retdev = WIN_WHEELDOWN;
00384       }
00385       break;
00386     case FL_PUSH:
00387     case FL_DRAG:
00388     case FL_RELEASE:
00389       if (lastbtn == FL_LEFT_MOUSE) retdev = WIN_LEFT;
00390       else if (lastbtn == FL_MIDDLE_MOUSE) retdev = WIN_MIDDLE;
00391       else if (lastbtn == FL_RIGHT_MOUSE) retdev = WIN_RIGHT;
00392       else {
00393         //printf("unknown button: %d\n", lastbtn);
00394       }
00395       retval = (lastevent == FL_PUSH || lastevent == FL_DRAG);
00396       break;
00397   
00398 #if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 1)
00399     case FL_KEYDOWN:
00400 #else
00401     // This event code is superceded by FL_KEYDOWN in newer revs of FLTK
00402     case FL_KEYBOARD:
00403 #endif
00404       // check function keys first
00405       if (lastkeycode >= FL_F && lastkeycode <= FL_F_Last) {
00406         retdev = (lastkeycode - FL_F) + ((int) WIN_KBD_F1);
00407       } else {
00408         switch(lastkeycode) {
00409           case FL_Escape:      retdev = WIN_KBD_ESCAPE;    break;
00410           case FL_Up:          retdev = WIN_KBD_UP;        break;
00411           case FL_Down:        retdev = WIN_KBD_DOWN;      break;
00412           case FL_Left:        retdev = WIN_KBD_LEFT;      break;
00413           case FL_Right:       retdev = WIN_KBD_RIGHT;     break;
00414           case FL_Page_Up:     retdev = WIN_KBD_PAGE_UP;   break;
00415           case FL_Page_Down:   retdev = WIN_KBD_PAGE_UP;   break;
00416           case FL_Home:        retdev = WIN_KBD_HOME;      break;
00417           case FL_End:         retdev = WIN_KBD_END;       break;
00418           case FL_Insert:      retdev = WIN_KBD_INSERT;    break;
00419           case FL_Delete:      retdev = WIN_KBD_DELETE;    break;
00420 
00421           default:
00422             retdev = WIN_KBD;
00423             break;
00424         }
00425       }
00426       retval = lastbtn;
00427       break;
00428 
00429     default:
00430       return 0;
00431   }
00432   lastevent = 0;
00433   return 1;
00434 }
00435 
00436 //
00437 // virtual routines for preparing to draw, drawing, and finishing drawing
00438 //
00439 
00440 // reshape the display after a shape change
00441 void FltkOpenGLDisplayDevice::reshape(void) {
00442 
00443   xSize = window->w();
00444   ySize = window->h();
00445   xOrig = window->x();
00446   yOrig = screenY - window->y() - ySize;
00447 
00448   switch (inStereo) {
00449     case OPENGL_STEREO_SIDE:
00450       set_screen_pos(0.5f * (float)xSize / (float)ySize);
00451       break;
00452 
00453     case OPENGL_STEREO_ABOVEBELOW:
00454       set_screen_pos(2.0f * (float)xSize / (float)ySize);
00455       break;
00456 
00457     case OPENGL_STEREO_STENCIL_CHECKERBOARD:
00458     case OPENGL_STEREO_STENCIL_COLUMNS:
00459     case OPENGL_STEREO_STENCIL_ROWS:
00460       enable_stencil_stereo(inStereo);
00461       set_screen_pos((float)xSize / (float)ySize);
00462       break;
00463 
00464     default:
00465       set_screen_pos((float)xSize / (float)ySize);
00466       break;
00467   }
00468 }
00469 
00470 unsigned char * FltkOpenGLDisplayDevice::readpixels(int &x, int &y) {
00471   unsigned char * img;
00472 
00473   x = xSize;
00474   y = ySize;
00475 
00476   if ((img = (unsigned char *) malloc(x * y * 3)) != NULL) {
00477 #if !defined(WIREGL) 
00478     glPixelStorei(GL_PACK_ALIGNMENT, 1);
00479     glReadPixels(0, 0, x, y, GL_RGB, GL_UNSIGNED_BYTE, img);
00480 #endif
00481   } else {
00482     x = 0;
00483     y = 0;
00484   } 
00485 
00486   return img; 
00487 }
00488 
00489 
00490 // update after drawing
00491 void FltkOpenGLDisplayDevice::update(int do_update) {
00492   if(do_update)
00493     window->swap_buffers();
00494 
00495   glDrawBuffer(GL_BACK);
00496 }
00497 
00498 void FltkOpenGLDisplayDevice::do_resize_window(int w, int h) {
00499   window->size(w, h);
00500   // XXX this may not be reliable on MacOS X with recent revs of FLTK
00501   window->size_range(1,1,0,0); // resizable to full screen
00502 }
00503 
00504 void FltkOpenGLDisplayDevice::do_reposition_window(int xpos, int ypos) {
00505   window->position(xpos, ypos);
00506   // XXX this may not be reliable on MacOS X with recent revs of FLTK
00507   window->size_range(1,1,0,0); // resizable to full screen
00508 }
00509 
00510 

Generated on Sat May 26 01:47:59 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002