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

OpenGLDisplayDevice.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: OpenGLDisplayDevice.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.189 $      $Date: 2011/02/11 22:10:04 $
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 <stdlib.h>
00026 #include <math.h>
00027 #include <GL/gl.h>
00028 #include <GL/glx.h>
00029 #include <X11/Xlib.h>
00030 #include <X11/cursorfont.h>
00031 #include <X11/keysym.h>
00032 
00033 #if defined(VMDXINERAMA)
00034 #include <X11/extensions/Xinerama.h>
00035 #endif
00036 
00037 #include "OpenGLDisplayDevice.h"
00038 #include "Inform.h"
00039 #include "utilities.h"
00040 #include "config.h"   // VMD version strings etc
00041 
00042 // static data for this object
00043 static const char *glStereoNameStr[OPENGL_STEREO_MODES] =
00044  { "Off",
00045    "QuadBuffered",
00046    "DTI SideBySide",
00047    "Checkerboard",
00048    "ColumnInterleaved",
00049    "RowInterleaved",
00050    "Anaglyph",
00051    "SideBySide",
00052    "AboveBelow",
00053    "Left",
00054    "Right" };
00055 
00056 static const char *glRenderNameStr[OPENGL_RENDER_MODES] = 
00057 { "Normal",
00058   "GLSL",
00059   "Acrobat3D" };
00060 
00061 static const char *glCacheNameStr[OPENGL_CACHE_MODES] = 
00062 { "Off",
00063   "On" };
00064 
00065 // determine if all of the ARB multisample extension routines are available
00066 #if defined(GL_ARB_multisample) && defined(GLX_SAMPLES_ARB) && defined(GLX_SAMPLE_BUFFERS_ARB)
00067 #define USEARBMULTISAMPLE 1
00068 #endif
00069 
00070 // colors for cursors
00071 static XColor cursorFG = { 0, 0xffff,      0,      0, 
00072                          DoRed | DoGreen | DoBlue, 0 };
00073 static XColor cursorBG = { 0, 0xffff, 0xffff, 0xffff, 
00074                          DoRed | DoGreen | DoBlue, 0 };
00075 
00077 
00078 #if defined(VMDXINPUT)
00079 
00080 #if defined(VMDXINPUT)
00081 #include <X11/extensions/XI.h>
00082 #include <X11/extensions/XInput.h>
00083 
00084 typedef struct {
00085   XDevice *dev;
00086   int motionevent;
00087   int motioneventclass;
00088   int buttonpressevent;
00089   int buttonpresseventclass;
00090   int buttonreleaseevent;
00091   int buttonreleaseeventclass;
00092   XEventClass evclasses[3];
00093 } xidevhandle;
00094 
00095 typedef struct {
00096   Display *dpy;
00097   Window win;
00098   xidevhandle *dev_spaceball;
00099   xidevhandle *dev_dialbox;
00100 } xinputhandle;
00101 
00102 #endif
00103 
00104 static xidevhandle * xinput_open_device(xinputhandle *handle, XID devinfo) {
00105   xidevhandle *xdhandle = (xidevhandle *) malloc(sizeof(xidevhandle));
00106   memset(xdhandle, 0, sizeof(xidevhandle));
00107   xdhandle->dev = XOpenDevice(handle->dpy, devinfo);
00108   if (xdhandle->dev == NULL) {
00109     free(xdhandle);
00110     return NULL;
00111   }
00112 
00113   DeviceMotionNotify(xdhandle->dev, xdhandle->motionevent, xdhandle->motioneventclass); 
00114   DeviceButtonPress(xdhandle->dev, xdhandle->buttonpressevent, xdhandle->buttonpresseventclass); 
00115   DeviceButtonRelease(xdhandle->dev, xdhandle->buttonreleaseevent, xdhandle->buttonreleaseeventclass); 
00116 
00117   xdhandle->evclasses[0] = xdhandle->motioneventclass;
00118   xdhandle->evclasses[1] = xdhandle->buttonpresseventclass;
00119   xdhandle->evclasses[2] = xdhandle->buttonreleaseeventclass;
00120 
00121   XSelectExtensionEvent(handle->dpy, handle->win, xdhandle->evclasses, 3);
00122 
00123   return xdhandle;
00124 }
00125 
00126 static void xinput_close_device(xinputhandle *handle, xidevhandle *xdhandle) {
00127   if (handle == NULL || xdhandle == NULL)
00128     return;
00129 
00130   if (xdhandle->dev != NULL) {
00131     XCloseDevice(handle->dpy, xdhandle->dev);
00132   }
00133   free(xdhandle);
00134 }
00135 
00136 static int xinput_device_decode_event(xinputhandle *handle, xidevhandle *dev,
00137                                       XEvent *xev, spaceballevent *sballevent) {
00138   if (xev->type == dev->motionevent) {
00139     XDeviceMotionEvent *mptr = (XDeviceMotionEvent *) xev;;
00140 
00141     // We assume that the axis mappings are in the order below,as this is
00142     // the axis ordering used by a few other applications as well.
00143     // We add the current control inputs to whatever we had previously,
00144     // so that we can process all queued events and not drop any inputs
00145     sballevent->tx     += mptr->axis_data[0]; // X translation
00146     sballevent->ty     += mptr->axis_data[1]; // Y translation
00147     sballevent->tz     += mptr->axis_data[2]; // Z translation
00148     sballevent->rx     += mptr->axis_data[3]; // A rotation
00149     sballevent->ry     += mptr->axis_data[4]; // B rotation
00150     sballevent->rz     += mptr->axis_data[5]; // C rotation
00151     sballevent->period += 50; // Period in milliseconds
00152     sballevent->event = 1;
00153     return 1;
00154   } else if (xev->type == dev->buttonpressevent) {
00155 //    XDeviceButtonEvent *bptr = (XDeviceButtonEvent *) xev;;
00156 //    sballevent->buttons |= (1 << xev->xclient.data.s[2]);
00157     sballevent->buttons |= 1;
00158     sballevent->event = 1;
00159     return 1;
00160   } else if (xev->type == dev->buttonreleaseevent) {
00161 //    XDeviceButtonEvent *bptr = (XDeviceButtonEvent *) xev;;
00162 //    sballevent->buttons &= ~(1 << xev->xclient.data.s[2]);
00163     sballevent->buttons &= ~1;
00164     sballevent->event = 1;
00165     return 1;
00166   }
00167  
00168   return 0;
00169 }
00170 
00171 static int xinput_decode_event(xinputhandle *handle, XEvent *xev,
00172                                spaceballevent *sballevent) {
00173   if (handle == NULL)
00174     return 0;
00175 
00176   if (handle->dev_spaceball != NULL) {
00177     return xinput_device_decode_event(handle, handle->dev_spaceball, xev, sballevent);
00178   }
00179 
00180   return 0;
00181 }
00182 
00183 // enable 6DOF input devices that use XInput 
00184 static xinputhandle * xinput_enable(Display *dpy, Window win) {
00185   xinputhandle *handle = NULL;
00186   int i, numdev, numextdev;
00187   XDeviceInfoPtr list;
00188   int ximajor, xiev, xierr;
00189   Atom sballdevtype;
00190 //  Atom dialboxdevtype; 
00191   xidevhandle *dev_spaceball = NULL;
00192 //  xidevhandle *dev_dialbox = NULL;
00193 
00194   /* check for availability of the XInput extension */
00195   if(!XQueryExtension(dpy,"XInputExtension", &ximajor, &xiev, &xierr)) {
00196     msgInfo << "X-Windows XInput extension unavailable." << sendmsg; 
00197     return NULL;
00198   }
00199 
00200   sballdevtype = XInternAtom(dpy, XI_SPACEBALL, True);
00201 //  dialboxdevtype = XInternAtom(dpy, XI_KNOB_BOX, True);
00202 
00203   /* Get the list of input devices attached to the display */
00204   list = (XDeviceInfoPtr) XListInputDevices(dpy, &numdev);
00205  
00206   numextdev = 0; 
00207   for (i = 0; i < numdev; i++) {
00208     if (list[i].use == IsXExtensionDevice) {
00209       // skip Xorg 'evdev brain' device
00210       if (!strupncmp(list[i].name, "evdev brain", strlen("evdev brain")))
00211         continue;
00212 
00213       numextdev++;
00214     }
00215   }
00216  
00217   if (numextdev > 0) {
00218     handle = (xinputhandle *) malloc(sizeof(xinputhandle));
00219     memset(handle, 0, sizeof(xinputhandle));
00220     handle->dpy = dpy;
00221     handle->win = win;
00222 
00223     msgInfo << "Detected " << numdev << " XInput devices, " 
00224             << numextdev << " usable device" 
00225             << ((numextdev > 1) ? "s:" : ":") << sendmsg;
00226 
00227     for (i = 0; i < numdev; i++) {
00228       if (list[i].use == IsXExtensionDevice) {
00229         // skip Xorg 'evdev brain' device
00230         if (!strupncmp(list[i].name, "evdev brain", strlen("evdev brain")))
00231           continue;
00232 
00233         /* list promising looking devices  */
00234         msgInfo << "  [" << list[i].id << "] " << list[i].name 
00235                 << ", type: " << (int) list[i].type 
00236                 << ", classes: " << (int) list[i].num_classes << sendmsg;
00237 
00238         /* Tag the first Spaceball device we find */
00239         if ((dev_spaceball == NULL) &&
00240             (((sballdevtype != None) && (list[i].type == sballdevtype)) ||
00241             !strupncmp(list[i].name, "SPACEBALL", strlen("SPACEBALL")) ||
00242             !strupncmp(list[i].name, "MAGELLAN", strlen("MAGELLAN")))) {
00243           dev_spaceball = xinput_open_device(handle, list[i].id);
00244         }
00245  
00246 #if 0 
00247         /* Tag the first dial box device we find */
00248         if ((dev_dialbox == NULL) &&
00249             ((dialboxdevtype != None) && (list[i].type == dialboxdevtype))) {
00250           dev_dialbox = xinput_open_device(handle, list[i].id);
00251         }
00252 #endif
00253       }
00254     }
00255     XFreeDeviceList(list);
00256   } else {
00257     // msgInfo << "No XInput devices found." << sendmsg; 
00258     XFreeDeviceList(list);
00259     return NULL;
00260   }
00261 
00262   if (dev_spaceball) {
00263     msgInfo << "Attached to XInput Spaceball" << sendmsg;
00264   }
00265 //  if (dev_dialbox) {
00266 //    msgInfo << "Attached to XInput Dial Box" << sendmsg;
00267 //  }
00268 
00269   if (dev_spaceball != NULL /* || dev_dialbox != NULL */) {
00270     handle->dev_spaceball = dev_spaceball;
00271 //    handle->dev_dialbox   = dev_dialbox;
00272   } else {
00273     free(handle);
00274     return NULL;
00275   }
00276 
00277   return handle;
00278 }
00279 
00280 void xinput_close(xinputhandle *handle) {
00281   if (handle != NULL) {
00282     xinput_close_device(handle, handle->dev_spaceball);
00283 //    xinput_close_device(handle, handle->dev_dialbox);
00284     free(handle);
00285   }
00286 }
00287 
00288 #endif
00289 
00290 
00291 // enable 3Dxware Spaceball / Magellan / SpaceNavigator events
00292 static spaceballhandle * spaceball_enable(Display *dpy, Window win) {
00293   // allocate and clear handle data structure
00294   spaceballhandle *handle = (spaceballhandle *) malloc(sizeof(spaceballhandle));
00295   memset(handle, 0, sizeof(spaceballhandle));  
00296 
00297   // find and store X atoms for the event types we care about
00298   handle->ev_motion         = XInternAtom(dpy, "MotionEvent", True);
00299   handle->ev_button_press   = XInternAtom(dpy, "ButtonPressEvent", True);
00300   handle->ev_button_release = XInternAtom(dpy, "ButtonReleaseEvent", True);
00301   handle->ev_command        = XInternAtom(dpy, "CommandEvent", True);
00302 
00303   if (!handle->ev_motion || !handle->ev_button_press || 
00304       !handle->ev_button_release || !handle->ev_command) {
00305     free(handle);
00306     return NULL; /* driver is not running */
00307   }
00308 
00309   // Find the root window of the driver
00310   Window root = RootWindow(dpy, DefaultScreen(dpy)); 
00311 
00312   // Find the driver's window
00313   Atom ActualType;
00314   int ActualFormat;
00315   unsigned long NItems, BytesReturn;
00316   unsigned char *PropReturn = NULL;
00317   XGetWindowProperty(dpy, root, handle->ev_command, 0, 1, FALSE,
00318                      AnyPropertyType, &ActualType, &ActualFormat, &NItems,
00319                      &BytesReturn, &PropReturn );
00320   if (PropReturn == NULL) {
00321     free(handle);
00322     return NULL;
00323   }
00324   handle->drv_win = *(Window *) PropReturn;
00325   XFree(PropReturn);
00326 
00327   XTextProperty sball_drv_winname;
00328   if (XGetWMName(dpy, handle->drv_win, &sball_drv_winname) != 0) {
00329     if (!strcmp("Magellan Window", (char *) sball_drv_winname.value)) {
00330       /* Send the application window to the Spaceball/Magellan driver */
00331       XEvent msg;
00332       msg.type = ClientMessage;
00333       msg.xclient.format = 16;
00334       msg.xclient.send_event = FALSE;
00335       msg.xclient.display = dpy;
00336       msg.xclient.window = handle->drv_win;
00337       msg.xclient.message_type = handle->ev_command;
00338 
00339       msg.xclient.data.s[0] = (short) (((win)>>16)&0x0000FFFF); // High 16
00340       msg.xclient.data.s[1] = (short) (((win))    &0x0000FFFF); // Low 16
00341       msg.xclient.data.s[2] = SBALL_COMMAND_APP_WINDOW; // 27695
00342 
00343       int rc = XSendEvent(dpy, handle->drv_win, FALSE, 0x0000, &msg);
00344       XFlush(dpy);
00345       if (rc == 0) {
00346         free(handle); 
00347         return NULL;
00348       }
00349     }
00350 
00351     XFree(sball_drv_winname.value);
00352   } 
00353 
00354   return handle;
00355 }
00356 
00357 static void spaceball_close(spaceballhandle *handle) {
00358   free(handle);
00359 }
00360 
00361 static int spaceball_decode_event(spaceballhandle *handle, const XEvent *xev, spaceballevent *sballevent) {
00362   unsigned int evtype;
00363 
00364   if (handle == NULL || xev == NULL || sballevent == NULL)
00365     return 0;
00366 
00367   if (xev->type != ClientMessage)
00368     return 0;
00369 
00370   evtype = xev->xclient.message_type;
00371 
00372   if (evtype == handle->ev_motion) {
00373     // We add the current control inputs to whatever we had previously,
00374     // so that we can process all queued events and not drop any inputs
00375     // xev->xclient.data.s[0] is Device Window High 16-bits 
00376     // xev->xclient.data.s[1] is Device Window Low 16-bits 
00377     sballevent->tx     += xev->xclient.data.s[2]; // X translation
00378     sballevent->ty     += xev->xclient.data.s[3]; // Y translation
00379     sballevent->tz     += xev->xclient.data.s[4]; // Z translation
00380     sballevent->rx     += xev->xclient.data.s[5]; // A rotation
00381     sballevent->ry     += xev->xclient.data.s[6]; // B rotation
00382     sballevent->rz     += xev->xclient.data.s[7]; // C rotation
00383     sballevent->period += xev->xclient.data.s[8]; // Period in milliseconds
00384     sballevent->event = 1;
00385     return 1;
00386   } else if (evtype == handle->ev_button_press) {
00387     // xev->xclient.data.s[0] is Device Window High 16-bits 
00388     // xev->xclient.data.s[1] is Device Window Low 16-bits 
00389     sballevent->buttons |= (1 << xev->xclient.data.s[2]);
00390     sballevent->event = 1;
00391     return 1;
00392   } else if (evtype == handle->ev_button_release) {
00393     // xev->xclient.data.s[0] is Device Window High 16-bits 
00394     // xev->xclient.data.s[1] is Device Window Low 16-bits 
00395     sballevent->buttons &= ~(1 << xev->xclient.data.s[2]);
00396     sballevent->event = 1;
00397     return 1;
00398   }
00399 
00400   return 0;
00401 }
00402 
00403 static void spaceball_init_event(spaceballevent *sballevent) {
00404   memset(sballevent, 0, sizeof(spaceballevent));
00405 }
00406 
00407 static void spaceball_clear_event(spaceballevent *sballevent) {
00408   sballevent->tx = 0;
00409   sballevent->ty = 0;
00410   sballevent->tz = 0;
00411   sballevent->rx = 0;
00412   sballevent->ry = 0;
00413   sballevent->rz = 0;
00414   sballevent->period = 0;
00415   sballevent->event = 0;
00416 }
00417 
00418 static XVisualInfo * vmd_get_visual(glxdata *glxsrv, int *stereo, int *msamp, int *numsamples) {
00419   // we want double-buffered RGB with a Z buffer (possibly with stereo)
00420   XVisualInfo *vi;
00421   int ns, dsize;
00422   int simplegraphics = 0;
00423   int disablestereo = 0;
00424   vi = NULL;
00425   *numsamples = 0;
00426   *msamp = FALSE; 
00427   *stereo = FALSE;
00428 
00429   if (getenv("VMDSIMPLEGRAPHICS")) {
00430     simplegraphics = 1;
00431   }
00432 
00433   if (getenv("VMDDISABLESTEREO")) {
00434     disablestereo = 1;
00435   } 
00436 
00437   // loop over a big range of depth buffer sizes, starting with biggest 
00438   // and working our way down from there.
00439   for (dsize=32; dsize >= 16; dsize-=4) { 
00440 
00441 // Try the OpenGL ARB multisample extension if available
00442 #if defined(USEARBMULTISAMPLE) 
00443     if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00444       // Stereo, multisample antialising, stencil buffer
00445       for (ns=16; ns>1; ns--) {
00446         int conf[]  = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, dsize, 
00447                        GLX_STEREO,
00448                        GLX_STENCIL_SIZE, 1, 
00449                        GLX_SAMPLE_BUFFERS_ARB, 1, GLX_SAMPLES_ARB, ns, None};
00450         vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00451   
00452         if (vi && (vi->c_class == TrueColor)) {
00453           *numsamples = ns;
00454           *msamp = TRUE;
00455           *stereo = TRUE;
00456           break; // exit loop if we got a good visual
00457         } 
00458       }
00459     }
00460 #endif
00461 
00462     if (getenv("VMDPREFERSTEREO") != NULL && !disablestereo) {
00463       // The preferred 24-bit color, quad buffered stereo mode.
00464       // This hack allows NVidia Quadro users to avoid the mutually-exclusive
00465       // antialiasing/stereo options on their cards with current drivers.
00466       // This forces VMD to skip looking for multisample antialiasing capable
00467       // X visuals and look for stereo instead.
00468       if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00469         int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, dsize, 
00470                       GLX_STEREO,
00471                       GLX_STENCIL_SIZE, 1, 
00472                       GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None};
00473         vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00474         ns = 0; // no multisample antialiasing
00475         *numsamples = ns;
00476         *msamp = FALSE; 
00477         *stereo = TRUE; 
00478       }
00479     } 
00480 #if defined(USEARBMULTISAMPLE) 
00481     else {
00482       // Try the OpenGL ARB multisample extension if available
00483       if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00484         // Non-Stereo, multisample antialising, stencil buffer
00485         for (ns=16; ns>1; ns--) {
00486           int conf[]  = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, dsize, 
00487                          GLX_STENCIL_SIZE, 1, 
00488                          GLX_SAMPLE_BUFFERS_ARB, 1, GLX_SAMPLES_ARB, ns, None};
00489           vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00490     
00491           if (vi && (vi->c_class == TrueColor)) {
00492             *numsamples = ns;
00493             *msamp = TRUE;
00494             *stereo = FALSE; 
00495             break; // exit loop if we got a good visual
00496           } 
00497         }
00498       }
00499     }
00500 #endif
00501 
00502   } // end of loop over a wide range of depth buffer sizes
00503 
00504   // Ideally we should fall back to accumulation buffer based antialiasing
00505   // here, but not currently implemented.  At this point no multisample
00506   // antialiasing mode is available.
00507 
00508   // The preferred 24-bit color, quad buffered stereo mode
00509   if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00510     int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STEREO,
00511                   GLX_STENCIL_SIZE, 1, 
00512                   GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None};
00513     vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00514     ns = 0; // no multisample antialiasing
00515     *numsamples = ns;
00516     *msamp = FALSE; 
00517     *stereo = TRUE; 
00518   }
00519 
00520   // Mode for machines that provide stereo only in modes with 16-bit color.
00521   if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00522     int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STEREO,
00523                   GLX_STENCIL_SIZE, 1, 
00524                   GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
00525     vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00526     ns = 0; // no multisample antialiasing
00527     *numsamples = ns;
00528     *msamp = FALSE; 
00529     *stereo = TRUE; 
00530   }
00531 
00532   // Mode for machines that provide stereo only without a stencil buffer, 
00533   // and with reduced color precision.  Examples of this are the SGI Octane2
00534   // machines with V6 graphics, with recent IRIX patch levels.
00535   // Without this configuration attempt, these machines won't get stereo.
00536   if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00537     int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STEREO,
00538                   GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
00539     vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00540     ns = 0; // no multisample antialiasing
00541     *numsamples = ns;
00542     *msamp = FALSE; 
00543     *stereo = TRUE; 
00544   }
00545 
00546   // This mode gives up on trying to get stereo, and goes back to trying
00547   // to get a high quality non-stereo visual.
00548   if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00549     int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, 
00550                   GLX_STENCIL_SIZE, 1, 
00551                   GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None};
00552     vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00553     ns = 0; // no multisample antialiasing
00554     *numsamples = ns;
00555     *msamp = FALSE; 
00556     *stereo = FALSE;
00557   }
00558   
00559   // check if we have a TrueColor visual.
00560   if(!vi || (vi->c_class != TrueColor) ) {
00561     // still no TrueColor.  Try again, with a very basic request ...
00562     // This is a catch all, we're desperate for any truecolor
00563     // visual by this point.  We've given up hoping for 24-bit
00564     // color or stereo by this time.
00565     int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, 
00566                   GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
00567     vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00568     ns = 0; // no multisample antialiasing
00569     *numsamples = ns;
00570     *msamp = FALSE; 
00571     *stereo = FALSE;
00572   }
00573 
00574   if (!vi || (vi->c_class != TrueColor)) {
00575     // complete failure
00576     ns = 0; // no multisample antialiasing
00577     *numsamples = ns;
00578     *msamp = FALSE; 
00579     *stereo = FALSE;
00580   }
00581 
00582   return vi;
00583 }
00584 
00585 
00586 // make an X11 window full-screen, or return it to normal state
00587 static void setfullscreen(int fson, Display *dpy, Window win, int xinescreen) {
00588   struct {
00589     unsigned long flags;
00590     unsigned long functions;
00591     unsigned long decorations;
00592     long inputMode;
00593     unsigned long status;
00594   } wmhints;
00595   
00596   memset(&wmhints, 0, sizeof(wmhints));
00597   wmhints.flags = 2;       // changing window decorations
00598   if (fson) {
00599     wmhints.decorations = 0; // 0 (false) no window decorations
00600   } else {
00601     wmhints.decorations = 1; // 1 (true) window decorations enabled
00602   }
00603 
00604   Atom wmproperty = XInternAtom(dpy, "_MOTIF_WM_HINTS", True);
00605   XChangeProperty(dpy, win, wmproperty, wmproperty, 32, 
00606                   PropModeReplace, (unsigned char *) &wmhints, 5);
00607 
00608   // resize window to size of either the whole X display screen,
00609   // or to the size of one of the Xinerama component displays
00610   // if Xinerama is enabled, and xinescreen is not -1.
00611   if (fson) {
00612     int dpyScreen = DefaultScreen(dpy);
00613   
00614     XSizeHints sizeHints;
00615     memset((void *) &(sizeHints), 0, sizeof(sizeHints));
00616     sizeHints.flags |= USSize;
00617     sizeHints.flags |= USPosition;
00618 
00619     sizeHints.width = DisplayWidth(dpy, dpyScreen);
00620     sizeHints.height = DisplayHeight(dpy, dpyScreen);
00621     sizeHints.x = 0;
00622     sizeHints.y = 0;
00623 
00624 #if defined(VMDXINERAMA)
00625     if (xinescreen != -1) {
00626       int xinerr, xinevent, xinenumscreens;
00627       if (XineramaQueryExtension(dpy, &xinevent, &xinerr) &&
00628           XineramaIsActive(dpy)) {
00629         XineramaScreenInfo *screens = 
00630           XineramaQueryScreens(dpy, &xinenumscreens);
00631         if (xinescreen >= 0 && xinescreen < xinenumscreens) {
00632           sizeHints.width = screens[xinescreen].width;
00633           sizeHints.height = screens[xinescreen].height;
00634           sizeHints.x = screens[xinescreen].x_org;
00635           sizeHints.y = screens[xinescreen].y_org;
00636         }
00637         XFree(screens);
00638       }
00639     }
00640 #endif
00641  
00642     XMoveWindow(dpy, win, sizeHints.x, sizeHints.y);
00643     XResizeWindow(dpy, win, sizeHints.width, sizeHints.height);
00644   }
00645 }
00646 
00647 
00649 
00650 OpenGLDisplayDevice::OpenGLDisplayDevice()
00651 : OpenGLRenderer((char *) "VMD " VMDVERSION " OpenGL Display") {
00652 
00653   // set up data possible before opening window
00654   stereoNames = glStereoNameStr;
00655   stereoModes = OPENGL_STEREO_MODES;
00656 
00657   renderNames = glRenderNameStr;
00658   renderModes = OPENGL_RENDER_MODES;
00659 
00660   cacheNames = glCacheNameStr;
00661   cacheModes = OPENGL_CACHE_MODES;
00662 
00663   memset(&glxsrv, 0, sizeof(glxsrv));
00664   glxsrv.dpy = NULL;
00665   glxsrv.dpyScreen = 0;
00666   glxsrv.xinp  = NULL;
00667   glxsrv.sball = NULL;
00668   glxsrv.havefocus = 0;
00669   have_window = FALSE;
00670   screenX = screenY = 0;
00671   vmdapp = NULL;
00672 }
00673 
00674 int OpenGLDisplayDevice::init(int argc, char **argv, VMDApp *app, int *size, int *loc) {
00675   vmdapp = app; // save VMDApp handle for use by drag-and-drop handlers
00676 
00677   // open the window
00678   glxsrv.windowID = open_window(name, size, loc, argc, argv);
00679   if (!have_window) return FALSE;
00680 
00681   // set flags for the capabilities of this display
00682   // whether we can do antialiasing or not.
00683   if (ext->hasmultisample) 
00684     aaAvailable = TRUE;  // we use multisampling over other methods
00685   else
00686     aaAvailable = FALSE; // no non-multisample implementation yet
00687 
00688   // set default settings
00689   if (ext->hasmultisample) {
00690     aa_on();  // enable fast multisample based antialiasing by default
00691               // other antialiasing techniques are slow, so only multisample
00692               // makes sense to enable by default.
00693   } 
00694 
00695   cueingAvailable = TRUE;
00696   cueing_on(); // leave depth cueing on by default, despite the speed hit.
00697 
00698   cullingAvailable = TRUE;
00699   culling_off();
00700 
00701   set_sphere_mode(sphereMode);
00702   set_sphere_res(sphereRes);
00703   set_line_width(lineWidth);
00704   set_line_style(lineStyle);
00705 
00706   // reshape and clear the display, which initializes some other variables
00707   reshape();
00708   normal();
00709   clear();
00710   update();
00711 
00712   // We have a window, return success.
00713   return TRUE;
00714 }
00715 
00716 // destructor ... close the window
00717 OpenGLDisplayDevice::~OpenGLDisplayDevice(void) {
00718   if (have_window) {
00719 #if defined(VMDXINPUT)
00720     // detach from XInput devices
00721     if (glxsrv.xinp != NULL) {
00722       xinput_close((xinputhandle *) glxsrv.xinp); 
00723     }
00724 #endif
00725     
00726     // detach from Xlib ClientMessage-based spaceball
00727     if (glxsrv.sball != NULL) {
00728       spaceball_close(glxsrv.sball); 
00729     }
00730 
00731     free_opengl_ctx(); // free display lists, textures, etc
00732  
00733     // close and delete windows, contexts, and display connections
00734     XUnmapWindow(glxsrv.dpy, glxsrv.windowID);
00735     glXDestroyContext(glxsrv.dpy, glxsrv.cx);
00736     XDestroyWindow(glxsrv.dpy, glxsrv.windowID);
00737     XCloseDisplay(glxsrv.dpy);
00738   }
00739 }
00740 
00741 
00743 
00744 
00745 // create a new window and set it's characteristics
00746 Window OpenGLDisplayDevice::open_window(char *nm, int *size, int *loc,
00747                                         int argc, char** argv
00748 ) {
00749   Window win;
00750   int i, SX = 100, SY = 100, W, H;
00751  
00752   char *dispname;
00753   if ((dispname = getenv("VMDGDISPLAY")) == NULL)
00754     dispname = getenv("DISPLAY");
00755 
00756   if(!(glxsrv.dpy = XOpenDisplay(dispname))) {
00757     msgErr << "Exiting due to X-Windows OpenGL window creation failure." << sendmsg;
00758     if (dispname != NULL) {
00759       msgErr << "Failed to open display: " << dispname << sendmsg;
00760     }
00761     return (Window)0; 
00762   }
00763 
00764 
00765   //
00766   // Check for "Composite" extension and any others that might cause
00767   // stability issues and warn the user about any potential problems...
00768   //
00769   char **xextensionlist;
00770   int nextensions, xtn;
00771   int warncompositeext=0;
00772   xextensionlist = XListExtensions(glxsrv.dpy, &nextensions);
00773   for (xtn=0; xtn<nextensions; xtn++) {
00774 //    printf("xtn[%d]: '%s'\n", xtn, xextensionlist[xtn]);
00775     if (xextensionlist[xtn] && !strcmp(xextensionlist[xtn], "Composite")) {
00776       warncompositeext=1;
00777     }
00778   }
00779   if (warncompositeext) {
00780     msgWarn << "Detected X11 'Composite' extension: if incorrect display occurs" << sendmsg;
00781     msgWarn << "try disabling this optional X server feature." << sendmsg;
00782   }
00783   XFreeExtensionList(xextensionlist);
00784 
00785 
00786   //
00787   // get info about root window
00788   //
00789   glxsrv.dpyScreen = DefaultScreen(glxsrv.dpy);
00790   glxsrv.rootWindowID = RootWindow(glxsrv.dpy, glxsrv.dpyScreen);
00791   screenX = DisplayWidth(glxsrv.dpy, glxsrv.dpyScreen);
00792   screenY = DisplayHeight(glxsrv.dpy, glxsrv.dpyScreen);
00793   W = size[0];
00794   H = size[1];
00795   if (loc) {
00796     SX = loc[0];
00797     // The X11 screen uses Y increasing from upper-left corner down; this is
00798     // opposite to what GL does, which is the way VMD was set up originally
00799     SY = (screenY - loc[1]) - H;
00800   }
00801 
00802   // (3) make sure the GLX extension is available
00803   if (!glXQueryExtension(glxsrv.dpy, NULL, NULL)) {
00804     msgErr << "The X server does not support the OpenGL GLX extension." 
00805            << "   Exiting ..." << sendmsg;
00806     XCloseDisplay(glxsrv.dpy);
00807     return (Window)0;
00808   }
00809 
00810   ext->hasstereo = TRUE;         // stereo on until we find out otherwise.
00811   ext->stereodrawforced = FALSE; // no need for force stereo draws initially
00812   ext->hasmultisample = TRUE;    // multisample on until we find out otherwise.
00813 
00814   // (4) find an appropriate X-Windows GLX-capable visual and colormap ...
00815   XVisualInfo *vi;
00816   vi =  vmd_get_visual(&glxsrv, &ext->hasstereo, &ext->hasmultisample, &ext->nummultisamples);
00817 
00818   // make sure we have what we want, darnit ...
00819   if (!vi) {
00820     msgErr << "A TrueColor visual is required, but not available." << sendmsg;
00821     msgErr << "The X server is not capable of displaying double-buffered," << sendmsg;
00822     msgErr << "RGB images with a Z buffer.   Exiting ..." << sendmsg;
00823     XCloseDisplay(glxsrv.dpy);
00824     return (Window)0;
00825   }
00826 
00827   Atom wmDeleteWindow = XInternAtom(glxsrv.dpy, "WM_DELETE_WINDOW", False);
00828 
00829   // (5) create an OpenGL rendering context
00830   if(!(glxsrv.cx = glXCreateContext(glxsrv.dpy, vi, None, GL_TRUE))) {
00831     msgErr << "Could not create OpenGL rendering context-> Exiting..." 
00832            << sendmsg;
00833     return (Window)0;
00834   }
00835 
00836   // (6) setup cursors, icons, iconized mode title, etc.
00837   glxsrv.cursor[0] = XCreateFontCursor(glxsrv.dpy, XC_left_ptr);
00838   glxsrv.cursor[1] = XCreateFontCursor(glxsrv.dpy, XC_fleur);
00839   glxsrv.cursor[2] = XCreateFontCursor(glxsrv.dpy, XC_sb_h_double_arrow);
00840   glxsrv.cursor[3] = XCreateFontCursor(glxsrv.dpy, XC_crosshair);
00841   glxsrv.cursor[4] = XCreateFontCursor(glxsrv.dpy, XC_watch);
00842   for(i=0; i < 5; i++)
00843     XRecolorCursor(glxsrv.dpy, glxsrv.cursor[i], &cursorFG, &cursorBG);
00844 
00845 
00846   //
00847   // Create the window
00848   //
00849   XSetWindowAttributes swa;
00850 
00851   //   For StaticGray , StaticColor, and TrueColor,
00852   //   alloc must be AllocNone , or a BadMatch error results
00853   swa.colormap = XCreateColormap(glxsrv.dpy, glxsrv.rootWindowID, 
00854                                  vi->visual, AllocNone);
00855 
00856   swa.background_pixmap = None;
00857   swa.border_pixel=0;
00858   swa.event_mask = ExposureMask;
00859   swa.cursor = glxsrv.cursor[0];
00860 
00861   win = XCreateWindow(glxsrv.dpy, glxsrv.rootWindowID, SX, SY, W, H, 0,
00862                       vi->depth, InputOutput, vi->visual,
00863                       CWBorderPixel | CWColormap | CWEventMask, &swa);
00864   XInstallColormap(glxsrv.dpy, swa.colormap);
00865 
00866   XFree(vi); // free visual info
00867 
00868   //
00869   // create size hints for new window
00870   //
00871   memset((void *) &(glxsrv.sizeHints), 0, sizeof(glxsrv.sizeHints));
00872   glxsrv.sizeHints.flags |= USSize;
00873   glxsrv.sizeHints.flags |= USPosition;
00874   glxsrv.sizeHints.width = W;
00875   glxsrv.sizeHints.height = H;
00876   glxsrv.sizeHints.x = SX;
00877   glxsrv.sizeHints.y = SY;
00878 
00879   XSetStandardProperties(glxsrv.dpy, win, nm, "VMD", None, argv, argc, &glxsrv.sizeHints);
00880   XWMHints *wmHints = XAllocWMHints();
00881   wmHints->initial_state = NormalState;
00882   wmHints->flags = StateHint;
00883   XSetWMHints(glxsrv.dpy, win, wmHints);
00884   XFree(wmHints);
00885   XSetWMProtocols(glxsrv.dpy, win, &wmDeleteWindow, 1);
00886 
00887 
00888   // (7) bind the rendering context to the window
00889   glXMakeCurrent(glxsrv.dpy, win, glxsrv.cx);
00890 
00891 
00892   // (8) actually request the window to be displayed
00893   XSelectInput(glxsrv.dpy, win, 
00894                KeyPressMask | ButtonPressMask | ButtonReleaseMask | 
00895                StructureNotifyMask | ExposureMask | 
00896                EnterWindowMask | LeaveWindowMask | FocusChangeMask);
00897   XMapRaised(glxsrv.dpy, win);
00898 
00899   // If we have acquired a multisample buffer with GLX, we
00900   // still need to test to see if we can actually use it.
00901   if (ext->hasmultisample) {
00902     int msampeext = 0;
00903 
00904     // check for ARB multisampling
00905     if (ext->vmdQueryExtension("GL_ARB_multisample")) {
00906       msampeext = 1;
00907     }
00908 
00909     if (!msampeext) {
00910       ext->hasmultisample = FALSE;
00911       ext->nummultisamples = 0;
00912     }
00913   }
00914 
00915   // (9) configure the rendering properly
00916   setup_initial_opengl_state();  // setup initial OpenGL state
00917 
00918 #if defined(VMDXINPUT)
00919   // (10) check for XInput based 6DOF controllers etc
00920   if (getenv("VMDDISABLEXINPUT") == NULL) {
00921     glxsrv.xinp = xinput_enable(glxsrv.dpy, win);
00922   }
00923 #endif
00924 
00925   // (11) Enable receiving Xlib ClientMessage-based Spaceball 
00926   //      events to this window
00927   if (getenv("VMDDISABLESPACEBALLXDRV") == NULL) {
00928     if (getenv("VMDSPACEBALLXDRVGLOBALFOCUS") == NULL) {
00929       // the driver will do focus processing for us
00930       glxsrv.sball = spaceball_enable(glxsrv.dpy, InputFocus);
00931     } else {
00932       // we'll do focus processing for ourselves
00933       glxsrv.sball = spaceball_enable(glxsrv.dpy, win);
00934     }
00935   }
00936   if (glxsrv.sball != NULL) {
00937     msgInfo << "X-Windows ClientMessage-based Spaceball device available." 
00938             << sendmsg;
00939   } 
00940 
00941 
00942   // initialize spaceball event structure to known state
00943   spaceball_init_event(&glxsrv.sballevent);
00944 
00945   // normal return: window was successfully created
00946   have_window = TRUE;
00947 
00948   // return window id
00949   return win;
00950 }
00951 
00952 void OpenGLDisplayDevice::do_resize_window(int w, int h) {
00953   if (getenv("VMDFULLSCREEN")) {
00954     int xinescreen=0;
00955     if (getenv("VMDXINESCREEN")) {
00956       xinescreen = atoi(getenv("VMDXINESCREEN"));
00957     }
00958     setfullscreen(1, glxsrv.dpy, glxsrv.windowID, xinescreen);
00959   } else {
00960     setfullscreen(0, glxsrv.dpy, glxsrv.windowID, -1);
00961     XResizeWindow(glxsrv.dpy, glxsrv.windowID, w, h);
00962   }
00963 }
00964 
00965 void OpenGLDisplayDevice::do_reposition_window(int xpos, int ypos) {
00966   XMoveWindow(glxsrv.dpy, glxsrv.windowID, xpos, ypos);
00967 }
00968 
00970 
00971 //
00972 // get the current state of the device's pointer (i.e. cursor if it has one)
00973 //
00974 
00975 // abs pos of cursor from lower-left corner of display
00976 int OpenGLDisplayDevice::x(void) {
00977   Window rw, cw;
00978   int rx, ry, wx, wy;
00979   unsigned int keymask;
00980 
00981   // get pointer info
00982   XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
00983 
00984   // return value
00985   return rx;
00986 }
00987 
00988 
00989 // same, for y direction
00990 int OpenGLDisplayDevice::y(void) {
00991   Window rw, cw;
00992   int rx, ry, wx, wy;
00993   unsigned int keymask;
00994 
00995   // get pointer info
00996   XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
00997 
00998   // return value
00999   // return value ... must subtract position from total size since
01000   // X is opposite to GL in sizing the screen
01001   return screenY - ry;
01002 }
01003 
01004 // return the current state of the shift, control, and alt keys
01005 int OpenGLDisplayDevice::shift_state(void) {
01006   int retval = 0;
01007 
01008   // get pointer info
01009   Window rw, cw;
01010   int rx, ry, wx, wy;
01011   unsigned int keymask;
01012   XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
01013 
01014   // determine state of keys, and OR results together
01015   if ((keymask & ShiftMask) != 0)
01016     retval |= SHIFT;
01017 
01018   if ((keymask & ControlMask) != 0)
01019     retval |= CONTROL;
01020 
01021   if ((keymask & Mod1Mask) != 0)
01022     retval |= ALT;
01023 
01024   // return the result
01025   return retval;
01026 }
01027 
01028 
01029 // return the spaceball state, if any
01030 int OpenGLDisplayDevice::spaceball(int *rx, int *ry, int *rz, int *tx, int *ty,
01031 int *tz, int *buttons) {
01032   // return event state we have from X11 windowing system events
01033   if ((glxsrv.sball != NULL || glxsrv.xinp != NULL)
01034        && glxsrv.sballevent.event == 1) {
01035     *rx = glxsrv.sballevent.rx;
01036     *ry = glxsrv.sballevent.ry;
01037     *rz = glxsrv.sballevent.rz;
01038     *tx = glxsrv.sballevent.tx;
01039     *ty = glxsrv.sballevent.ty;
01040     *tz = glxsrv.sballevent.tz;
01041     *buttons = glxsrv.sballevent.buttons;
01042     return 1;
01043   }
01044 
01045   return 0;
01046 }
01047 
01048 
01049 // set the Nth cursor shape as the current one.  If no arg given, the
01050 // default shape (n=0) is used.
01051 void OpenGLDisplayDevice::set_cursor(int n) {
01052   int cursorindex;
01053 
01054   switch (n) {
01055     default:
01056     case DisplayDevice::NORMAL_CURSOR: cursorindex = 0; break;
01057     case DisplayDevice::TRANS_CURSOR:  cursorindex = 1; break;
01058     case DisplayDevice::SCALE_CURSOR:  cursorindex = 2; break;
01059     case DisplayDevice::PICK_CURSOR:   cursorindex = 3; break;
01060     case DisplayDevice::WAIT_CURSOR:   cursorindex = 4; break;
01061   }
01062 
01063   XDefineCursor(glxsrv.dpy, glxsrv.windowID, glxsrv.cursor[cursorindex]);
01064 }
01065 
01066 
01067 //
01068 // event handling routines
01069 //
01070 
01071 // queue the standard events (need only be called once ... but this is
01072 // not done automatically by the window because it may not be necessary or
01073 // even wanted)
01074 void OpenGLDisplayDevice::queue_events(void) {
01075   XSelectInput(glxsrv.dpy, glxsrv.windowID, 
01076                KeyPressMask | ButtonPressMask | ButtonReleaseMask | 
01077                StructureNotifyMask | ExposureMask | 
01078                EnterWindowMask | LeaveWindowMask | FocusChangeMask);
01079 }
01080 
01081 
01082 // This version of read_event flushes the entire queue before returning the
01083 // last event to the caller.  It fixes buggy window resizing behavior on 
01084 // Linux when using the Nvidia OpenGL drivers.  
01085 int OpenGLDisplayDevice::read_event(long &retdev, long &retval) {
01086   XEvent xev;
01087   char keybuf[10];
01088   int keybuflen = 9;
01089   KeySym keysym;
01090   XComposeStatus comp;
01091 
01092   memset(keybuf, 0, sizeof(keybuf)); // clear keyboard input buffer
01093 
01094   // clear previous spaceball event state, except for button state which
01095   // must be left alone.
01096   spaceball_clear_event(&glxsrv.sballevent);
01097 
01098   retdev = WIN_NOEVENT;
01099   // read all events, handling the ones that need to be handled internally,
01100   // and returning the last one for processing.
01101   int need_reshape = FALSE;
01102   while (XPending(glxsrv.dpy)) {
01103     XNextEvent(glxsrv.dpy, &xev);
01104 
01105     // find what kind of event it was
01106     switch(xev.type) {
01107     case Expose:
01108     case ConfigureNotify:
01109     case ReparentNotify:
01110     case MapNotify:
01111       need_reshape = TRUE; // Probably not needed for Expose or Map
01112       _needRedraw = 1;
01113       // retdev not set; we handle this ourselves.
01114       break;
01115     case KeyPress:
01116       {
01117         int k = XLookupString(&(xev.xkey), keybuf, keybuflen,  &keysym, &comp);
01118         // handle all strictly alphanumeric keys here
01119         if (k > 0 && *keybuf != '\0') {
01120           retdev = WIN_KBD;
01121           retval = *keybuf;
01122         } else {
01123           switch (keysym) {
01124             case XK_Escape:      retdev = WIN_KBD_ESCAPE;    break;
01125             case XK_Up:          retdev = WIN_KBD_UP;        break;
01126             case XK_Down:        retdev = WIN_KBD_DOWN;      break;
01127             case XK_Left:        retdev = WIN_KBD_LEFT;      break;
01128             case XK_Right:       retdev = WIN_KBD_RIGHT;     break;
01129             case XK_Page_Up:     retdev = WIN_KBD_PAGE_UP;   break;
01130             case XK_Page_Down:   retdev = WIN_KBD_PAGE_UP;   break;
01131             case XK_Home:        retdev = WIN_KBD_HOME;      break;
01132             case XK_End:         retdev = WIN_KBD_END;       break;
01133             case XK_Insert:      retdev = WIN_KBD_INSERT;    break;
01134             case XK_Delete:      retdev = WIN_KBD_DELETE;    break;
01135             case XK_F1:          retdev = WIN_KBD_F1;        break;
01136             case XK_F2:          retdev = WIN_KBD_F2;        break;
01137             case XK_F3:          retdev = WIN_KBD_F3;        break;
01138             case XK_F4:          retdev = WIN_KBD_F4;        break;
01139             case XK_F5:          retdev = WIN_KBD_F5;        break;
01140             case XK_F6:          retdev = WIN_KBD_F6;        break;
01141             case XK_F7:          retdev = WIN_KBD_F7;        break;
01142             case XK_F8:          retdev = WIN_KBD_F8;        break;
01143             case XK_F9:          retdev = WIN_KBD_F9;        break;
01144             case XK_F10:         retdev = WIN_KBD_F10;       break;
01145             case XK_F11:         retdev = WIN_KBD_F11;       break;
01146             case XK_F12:         retdev = WIN_KBD_F12;       break;
01147           } 
01148         } 
01149         break;
01150       }
01151     case ButtonPress:
01152     case ButtonRelease:
01153       {
01154         unsigned int button = xev.xbutton.button;
01155         retval = (xev.type == ButtonPress);
01156         switch (button) {
01157           case Button1:
01158             retdev = WIN_LEFT;
01159             break;
01160           case Button2:
01161             retdev = WIN_MIDDLE;
01162             break;
01163           case Button3:
01164             retdev = WIN_RIGHT;
01165             break;
01166           case Button4:
01167             retdev = WIN_WHEELUP;
01168             break;
01169           case Button5:
01170             retdev = WIN_WHEELDOWN;
01171             break;
01172         }
01173         break;
01174       }
01175       break;
01176 
01177     case FocusIn:
01178     case EnterNotify:
01179       glxsrv.havefocus=1;
01180       break;
01181 
01182     case FocusOut:
01183     case LeaveNotify:
01184       glxsrv.havefocus=0;
01185       break;
01186 
01187     case ClientMessage:
01188 #if 1
01189       // let the spaceball driver take care of focus processing
01190       // if we have mouse/keyboard focus, then translate spaceball events
01191       spaceball_decode_event(glxsrv.sball, &xev, &glxsrv.sballevent);
01192 #else
01193       // do our own focus handling
01194       // if we have mouse/keyboard focus, then translate spaceball events
01195       if (glxsrv.havefocus) {
01196         spaceball_decode_event(glxsrv.sball, &xev, &glxsrv.sballevent);
01197       }
01198 #endif
01199       break;
01200 
01201     default:
01202 #if defined(VMDXINPUT)
01203       if (glxsrv.xinp != NULL) {
01204         if (xinput_decode_event((xinputhandle *) glxsrv.xinp, &xev, 
01205                                  &glxsrv.sballevent)) {
01206           break;
01207         }
01208       }
01209 #endif
01210 
01211 #if 0
01212       msgWarn << "Unrecognized X11 event" << xev.type << sendmsg;
01213 #endif      
01214       break;
01215 
01216     } 
01217   } 
01218 
01219   if (need_reshape) 
01220     reshape();
01221 
01222   return (retdev != WIN_NOEVENT);
01223 }
01224 
01225 //
01226 // virtual routines for preparing to draw, drawing, and finishing drawing
01227 //
01228 
01229 // reshape the display after a shape change
01230 void OpenGLDisplayDevice::reshape(void) {
01231 
01232   // get and store size of window
01233   XWindowAttributes xwa;
01234   Window childwin;                  // not used, just needed for X call
01235   int rx, ry;
01236 
01237   // 
01238   // XXX WireGL notes: 
01239   //   WireGL doesn't have a variable window size like normal 
01240   // OpenGL windows do.  Not only that, but the size values reported
01241   // by X11 will be widly different from those reported by 
01242   // the glGetIntegerv(GL_VIEWPORT) call, and cause schizophrenic
01243   // behavior.  For now, we don't do anything about this, but 
01244   // the default window that comes up on the tiled display is not
01245   // locked to the same size and aspect ratio as the host display,
01246   // so spheres can look rather egg shaped if the X window on the 
01247   // host display isn't adjusted. 
01248   //
01249 
01250   XGetWindowAttributes(glxsrv.dpy, glxsrv.windowID, &xwa);
01251   XTranslateCoordinates(glxsrv.dpy, glxsrv.windowID, glxsrv.rootWindowID, -xwa.border_width,
01252                         -xwa.border_width, &rx, &ry, &childwin);
01253 
01254   xSize = xwa.width;
01255   ySize = xwa.height;
01256   xOrig = rx;
01257   yOrig = screenY - ry - ySize;
01258   
01259   switch (inStereo) {
01260     case OPENGL_STEREO_SIDE:
01261       set_screen_pos(0.5f * (float)xSize / (float)ySize);
01262       break;
01263 
01264     case OPENGL_STEREO_ABOVEBELOW:
01265       set_screen_pos(2.0f * (float)xSize / (float)ySize);
01266       break;
01267 
01268     case OPENGL_STEREO_STENCIL_CHECKERBOARD:
01269     case OPENGL_STEREO_STENCIL_COLUMNS:
01270     case OPENGL_STEREO_STENCIL_ROWS:
01271       enable_stencil_stereo(inStereo);
01272       set_screen_pos((float)xSize / (float)ySize);
01273       break;
01274  
01275     default:
01276       set_screen_pos((float)xSize / (float)ySize);
01277       break;
01278   }
01279 }
01280 
01281 unsigned char * OpenGLDisplayDevice::readpixels(int &xs, int &ys) {
01282   unsigned char * img = NULL;
01283   xs = xSize;
01284   ys = ySize;
01285 
01286   // fall back to normal glReadPixels() if better methods fail
01287   if ((img = (unsigned char *) malloc(xs * ys * 3)) != NULL) {
01288     glPixelStorei(GL_PACK_ALIGNMENT, 1);
01289     glReadPixels(0, 0, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, img);
01290     return img; 
01291   }
01292 
01293   // else bail out
01294   xs = 0;
01295   ys = 0;
01296   return NULL;
01297 }
01298 
01299 
01300 // update after drawing
01301 void OpenGLDisplayDevice::update(int do_update) {
01302   if (wiregl) {
01303     glFinish(); // force cluster to synchronize before buffer swap, 
01304                 // this gives much better results than if the 
01305                 // synchronization is done implicitly by glXSwapBuffers.
01306   }
01307 
01308   if(do_update)
01309     glXSwapBuffers(glxsrv.dpy, glxsrv.windowID);
01310 
01311   glDrawBuffer(GL_BACK);
01312 }
01313 

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