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

OpenGLDisplayDevice.C

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

Generated on Mon Nov 17 02:46:33 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /