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

Generated on Wed Oct 8 01:26:37 2008 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002