00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdlib.h>
00026 #include <math.h>
00027 #include <GL/gl.h>
00028 #include <GL/glx.h>
00029 #include <X11/Xlib.h>
00030 #include <X11/cursorfont.h>
00031 #include <X11/keysym.h>
00032
00033 #if defined(VMDXINERAMA)
00034 #include <X11/extensions/Xinerama.h>
00035 #endif
00036
00037 #include "OpenGLDisplayDevice.h"
00038 #include "Inform.h"
00039 #include "utilities.h"
00040 #include "config.h"
00041
00042
00043 static const char *glStereoNameStr[OPENGL_STEREO_MODES] =
00044 { "Off",
00045 "QuadBuffered",
00046 "DTI SideBySide",
00047 "Checkerboard",
00048 "ColumnInterleaved",
00049 "RowInterleaved",
00050 "Anaglyph",
00051 "SideBySide",
00052 "AboveBelow",
00053 "Left",
00054 "Right" };
00055
00056 static const char *glRenderNameStr[OPENGL_RENDER_MODES] =
00057 { "Normal",
00058 "GLSL",
00059 "Acrobat3D" };
00060
00061 static const char *glCacheNameStr[OPENGL_CACHE_MODES] =
00062 { "Off",
00063 "On" };
00064
00065
00066 #if defined(GL_ARB_multisample) && defined(GLX_SAMPLES_ARB) && defined(GLX_SAMPLE_BUFFERS_ARB)
00067 #define USEARBMULTISAMPLE 1
00068 #endif
00069
00070
00071 static XColor cursorFG = { 0, 0xffff, 0, 0,
00072 DoRed | DoGreen | DoBlue, 0 };
00073 static XColor cursorBG = { 0, 0xffff, 0xffff, 0xffff,
00074 DoRed | DoGreen | DoBlue, 0 };
00075
00077
00078 #if defined(VMDXINPUT)
00079
00080 #if defined(VMDXINPUT)
00081 #include <X11/extensions/XI.h>
00082 #include <X11/extensions/XInput.h>
00083
00084 typedef struct {
00085 XDevice *dev;
00086 int motionevent;
00087 int motioneventclass;
00088 int buttonpressevent;
00089 int buttonpresseventclass;
00090 int buttonreleaseevent;
00091 int buttonreleaseeventclass;
00092 XEventClass evclasses[3];
00093 } xidevhandle;
00094
00095 typedef struct {
00096 Display *dpy;
00097 Window win;
00098 xidevhandle *dev_spaceball;
00099 xidevhandle *dev_dialbox;
00100 } xinputhandle;
00101
00102 #endif
00103
00104 static xidevhandle * xinput_open_device(xinputhandle *handle, XID devinfo) {
00105 xidevhandle *xdhandle = (xidevhandle *) malloc(sizeof(xidevhandle));
00106 memset(xdhandle, 0, sizeof(xidevhandle));
00107 xdhandle->dev = XOpenDevice(handle->dpy, devinfo);
00108 if (xdhandle->dev == NULL) {
00109 free(xdhandle);
00110 return NULL;
00111 }
00112
00113 DeviceMotionNotify(xdhandle->dev, xdhandle->motionevent, xdhandle->motioneventclass);
00114 DeviceButtonPress(xdhandle->dev, xdhandle->buttonpressevent, xdhandle->buttonpresseventclass);
00115 DeviceButtonRelease(xdhandle->dev, xdhandle->buttonreleaseevent, xdhandle->buttonreleaseeventclass);
00116
00117 xdhandle->evclasses[0] = xdhandle->motioneventclass;
00118 xdhandle->evclasses[1] = xdhandle->buttonpresseventclass;
00119 xdhandle->evclasses[2] = xdhandle->buttonreleaseeventclass;
00120
00121 XSelectExtensionEvent(handle->dpy, handle->win, xdhandle->evclasses, 3);
00122
00123 return xdhandle;
00124 }
00125
00126 static void xinput_close_device(xinputhandle *handle, xidevhandle *xdhandle) {
00127 if (handle == NULL || xdhandle == NULL)
00128 return;
00129
00130 if (xdhandle->dev != NULL) {
00131 XCloseDevice(handle->dpy, xdhandle->dev);
00132 }
00133 free(xdhandle);
00134 }
00135
00136 static int xinput_device_decode_event(xinputhandle *handle, xidevhandle *dev,
00137 XEvent *xev, spaceballevent *sballevent) {
00138 if (xev->type == dev->motionevent) {
00139 XDeviceMotionEvent *mptr = (XDeviceMotionEvent *) xev;;
00140
00141
00142
00143
00144
00145 sballevent->tx += mptr->axis_data[0];
00146 sballevent->ty += mptr->axis_data[1];
00147 sballevent->tz += mptr->axis_data[2];
00148 sballevent->rx += mptr->axis_data[3];
00149 sballevent->ry += mptr->axis_data[4];
00150 sballevent->rz += mptr->axis_data[5];
00151 sballevent->period += 50;
00152 sballevent->event = 1;
00153 return 1;
00154 } else if (xev->type == dev->buttonpressevent) {
00155
00156
00157 sballevent->buttons |= 1;
00158 sballevent->event = 1;
00159 return 1;
00160 } else if (xev->type == dev->buttonreleaseevent) {
00161
00162
00163 sballevent->buttons &= ~1;
00164 sballevent->event = 1;
00165 return 1;
00166 }
00167
00168 return 0;
00169 }
00170
00171 static int xinput_decode_event(xinputhandle *handle, XEvent *xev,
00172 spaceballevent *sballevent) {
00173 if (handle == NULL)
00174 return 0;
00175
00176 if (handle->dev_spaceball != NULL) {
00177 return xinput_device_decode_event(handle, handle->dev_spaceball, xev, sballevent);
00178 }
00179
00180 return 0;
00181 }
00182
00183
00184 static xinputhandle * xinput_enable(Display *dpy, Window win) {
00185 xinputhandle *handle = NULL;
00186 int i, numdev, numextdev;
00187 XDeviceInfoPtr list;
00188 int ximajor, xiev, xierr;
00189 Atom sballdevtype;
00190
00191 xidevhandle *dev_spaceball = NULL;
00192
00193
00194
00195 if(!XQueryExtension(dpy,"XInputExtension", &ximajor, &xiev, &xierr)) {
00196 msgInfo << "X-Windows XInput extension unavailable." << sendmsg;
00197 return NULL;
00198 }
00199
00200 sballdevtype = XInternAtom(dpy, XI_SPACEBALL, True);
00201
00202
00203
00204 list = (XDeviceInfoPtr) XListInputDevices(dpy, &numdev);
00205
00206 numextdev = 0;
00207 for (i = 0; i < numdev; i++) {
00208 if (list[i].use == IsXExtensionDevice) {
00209
00210 if (!strupncmp(list[i].name, "evdev brain", strlen("evdev brain")))
00211 continue;
00212
00213 numextdev++;
00214 }
00215 }
00216
00217 if (numextdev > 0) {
00218 handle = (xinputhandle *) malloc(sizeof(xinputhandle));
00219 memset(handle, 0, sizeof(xinputhandle));
00220 handle->dpy = dpy;
00221 handle->win = win;
00222
00223 msgInfo << "Detected " << numdev << " XInput devices, "
00224 << numextdev << " usable device"
00225 << ((numextdev > 1) ? "s:" : ":") << sendmsg;
00226
00227 for (i = 0; i < numdev; i++) {
00228 if (list[i].use == IsXExtensionDevice) {
00229
00230 if (!strupncmp(list[i].name, "evdev brain", strlen("evdev brain")))
00231 continue;
00232
00233
00234 msgInfo << " [" << list[i].id << "] " << list[i].name
00235 << ", type: " << (int) list[i].type
00236 << ", classes: " << (int) list[i].num_classes << sendmsg;
00237
00238
00239 if ((dev_spaceball == NULL) &&
00240 (((sballdevtype != None) && (list[i].type == sballdevtype)) ||
00241 !strupncmp(list[i].name, "SPACEBALL", strlen("SPACEBALL")) ||
00242 !strupncmp(list[i].name, "MAGELLAN", strlen("MAGELLAN")))) {
00243 dev_spaceball = xinput_open_device(handle, list[i].id);
00244 }
00245
00246 #if 0
00247
00248 if ((dev_dialbox == NULL) &&
00249 ((dialboxdevtype != None) && (list[i].type == dialboxdevtype))) {
00250 dev_dialbox = xinput_open_device(handle, list[i].id);
00251 }
00252 #endif
00253 }
00254 }
00255 XFreeDeviceList(list);
00256 } else {
00257
00258 XFreeDeviceList(list);
00259 return NULL;
00260 }
00261
00262 if (dev_spaceball) {
00263 msgInfo << "Attached to XInput Spaceball" << sendmsg;
00264 }
00265
00266
00267
00268
00269 if (dev_spaceball != NULL ) {
00270 handle->dev_spaceball = dev_spaceball;
00271
00272 } else {
00273 free(handle);
00274 return NULL;
00275 }
00276
00277 return handle;
00278 }
00279
00280 void xinput_close(xinputhandle *handle) {
00281 if (handle != NULL) {
00282 xinput_close_device(handle, handle->dev_spaceball);
00283
00284 free(handle);
00285 }
00286 }
00287
00288 #endif
00289
00290
00291
00292 static spaceballhandle * spaceball_enable(Display *dpy, Window win) {
00293
00294 spaceballhandle *handle = (spaceballhandle *) malloc(sizeof(spaceballhandle));
00295 memset(handle, 0, sizeof(spaceballhandle));
00296
00297
00298 handle->ev_motion = XInternAtom(dpy, "MotionEvent", True);
00299 handle->ev_button_press = XInternAtom(dpy, "ButtonPressEvent", True);
00300 handle->ev_button_release = XInternAtom(dpy, "ButtonReleaseEvent", True);
00301 handle->ev_command = XInternAtom(dpy, "CommandEvent", True);
00302
00303 if (!handle->ev_motion || !handle->ev_button_press ||
00304 !handle->ev_button_release || !handle->ev_command) {
00305 free(handle);
00306 return NULL;
00307 }
00308
00309
00310 Window root = RootWindow(dpy, DefaultScreen(dpy));
00311
00312
00313 Atom ActualType;
00314 int ActualFormat;
00315 unsigned long NItems, BytesReturn;
00316 unsigned char *PropReturn = NULL;
00317 XGetWindowProperty(dpy, root, handle->ev_command, 0, 1, FALSE,
00318 AnyPropertyType, &ActualType, &ActualFormat, &NItems,
00319 &BytesReturn, &PropReturn );
00320 if (PropReturn == NULL) {
00321 free(handle);
00322 return NULL;
00323 }
00324 handle->drv_win = *(Window *) PropReturn;
00325 XFree(PropReturn);
00326
00327 XTextProperty sball_drv_winname;
00328 if (XGetWMName(dpy, handle->drv_win, &sball_drv_winname) != 0) {
00329 if (!strcmp("Magellan Window", (char *) sball_drv_winname.value)) {
00330
00331 XEvent msg;
00332 msg.type = ClientMessage;
00333 msg.xclient.format = 16;
00334 msg.xclient.send_event = FALSE;
00335 msg.xclient.display = dpy;
00336 msg.xclient.window = handle->drv_win;
00337 msg.xclient.message_type = handle->ev_command;
00338
00339 msg.xclient.data.s[0] = (short) (((win)>>16)&0x0000FFFF);
00340 msg.xclient.data.s[1] = (short) (((win)) &0x0000FFFF);
00341 msg.xclient.data.s[2] = SBALL_COMMAND_APP_WINDOW;
00342
00343 int rc = XSendEvent(dpy, handle->drv_win, FALSE, 0x0000, &msg);
00344 XFlush(dpy);
00345 if (rc == 0) {
00346 free(handle);
00347 return NULL;
00348 }
00349 }
00350
00351 XFree(sball_drv_winname.value);
00352 }
00353
00354 return handle;
00355 }
00356
00357 static void spaceball_close(spaceballhandle *handle) {
00358 free(handle);
00359 }
00360
00361 static int spaceball_decode_event(spaceballhandle *handle, const XEvent *xev, spaceballevent *sballevent) {
00362 unsigned int evtype;
00363
00364 if (handle == NULL || xev == NULL || sballevent == NULL)
00365 return 0;
00366
00367 if (xev->type != ClientMessage)
00368 return 0;
00369
00370 evtype = xev->xclient.message_type;
00371
00372 if (evtype == handle->ev_motion) {
00373
00374
00375
00376
00377 sballevent->tx += xev->xclient.data.s[2];
00378 sballevent->ty += xev->xclient.data.s[3];
00379 sballevent->tz += xev->xclient.data.s[4];
00380 sballevent->rx += xev->xclient.data.s[5];
00381 sballevent->ry += xev->xclient.data.s[6];
00382 sballevent->rz += xev->xclient.data.s[7];
00383 sballevent->period += xev->xclient.data.s[8];
00384 sballevent->event = 1;
00385 return 1;
00386 } else if (evtype == handle->ev_button_press) {
00387
00388
00389 sballevent->buttons |= (1 << xev->xclient.data.s[2]);
00390 sballevent->event = 1;
00391 return 1;
00392 } else if (evtype == handle->ev_button_release) {
00393
00394
00395 sballevent->buttons &= ~(1 << xev->xclient.data.s[2]);
00396 sballevent->event = 1;
00397 return 1;
00398 }
00399
00400 return 0;
00401 }
00402
00403 static void spaceball_init_event(spaceballevent *sballevent) {
00404 memset(sballevent, 0, sizeof(spaceballevent));
00405 }
00406
00407 static void spaceball_clear_event(spaceballevent *sballevent) {
00408 sballevent->tx = 0;
00409 sballevent->ty = 0;
00410 sballevent->tz = 0;
00411 sballevent->rx = 0;
00412 sballevent->ry = 0;
00413 sballevent->rz = 0;
00414 sballevent->period = 0;
00415 sballevent->event = 0;
00416 }
00417
00418 static XVisualInfo * vmd_get_visual(glxdata *glxsrv, int *stereo, int *msamp, int *numsamples) {
00419
00420 XVisualInfo *vi;
00421 int ns, dsize;
00422 int simplegraphics = 0;
00423 int disablestereo = 0;
00424 vi = NULL;
00425 *numsamples = 0;
00426 *msamp = FALSE;
00427 *stereo = FALSE;
00428
00429 if (getenv("VMDSIMPLEGRAPHICS")) {
00430 simplegraphics = 1;
00431 }
00432
00433 if (getenv("VMDDISABLESTEREO")) {
00434 disablestereo = 1;
00435 }
00436
00437
00438
00439 for (dsize=32; dsize >= 16; dsize-=4) {
00440
00441
00442 #if defined(USEARBMULTISAMPLE)
00443 if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00444
00445 for (ns=16; ns>1; ns--) {
00446 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, dsize,
00447 GLX_STEREO,
00448 GLX_STENCIL_SIZE, 1,
00449 GLX_SAMPLE_BUFFERS_ARB, 1, GLX_SAMPLES_ARB, ns, None};
00450 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00451
00452 if (vi && (vi->c_class == TrueColor)) {
00453 *numsamples = ns;
00454 *msamp = TRUE;
00455 *stereo = TRUE;
00456 break;
00457 }
00458 }
00459 }
00460 #endif
00461
00462 if (getenv("VMDPREFERSTEREO") != NULL && !disablestereo) {
00463
00464
00465
00466
00467
00468 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00469 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, dsize,
00470 GLX_STEREO,
00471 GLX_STENCIL_SIZE, 1,
00472 GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None};
00473 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00474 ns = 0;
00475 *numsamples = ns;
00476 *msamp = FALSE;
00477 *stereo = TRUE;
00478 }
00479 }
00480 #if defined(USEARBMULTISAMPLE)
00481 else {
00482
00483 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00484
00485 for (ns=16; ns>1; ns--) {
00486 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, dsize,
00487 GLX_STENCIL_SIZE, 1,
00488 GLX_SAMPLE_BUFFERS_ARB, 1, GLX_SAMPLES_ARB, ns, None};
00489 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00490
00491 if (vi && (vi->c_class == TrueColor)) {
00492 *numsamples = ns;
00493 *msamp = TRUE;
00494 *stereo = FALSE;
00495 break;
00496 }
00497 }
00498 }
00499 }
00500 #endif
00501
00502 }
00503
00504
00505
00506
00507
00508
00509 if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00510 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STEREO,
00511 GLX_STENCIL_SIZE, 1,
00512 GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None};
00513 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00514 ns = 0;
00515 *numsamples = ns;
00516 *msamp = FALSE;
00517 *stereo = TRUE;
00518 }
00519
00520
00521 if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00522 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STEREO,
00523 GLX_STENCIL_SIZE, 1,
00524 GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
00525 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00526 ns = 0;
00527 *numsamples = ns;
00528 *msamp = FALSE;
00529 *stereo = TRUE;
00530 }
00531
00532
00533
00534
00535
00536 if (!simplegraphics && !disablestereo && (!vi || (vi->c_class != TrueColor))) {
00537 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STEREO,
00538 GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
00539 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00540 ns = 0;
00541 *numsamples = ns;
00542 *msamp = FALSE;
00543 *stereo = TRUE;
00544 }
00545
00546
00547
00548 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00549 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16,
00550 GLX_STENCIL_SIZE, 1,
00551 GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None};
00552 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00553 ns = 0;
00554 *numsamples = ns;
00555 *msamp = FALSE;
00556 *stereo = FALSE;
00557 }
00558
00559
00560 if(!vi || (vi->c_class != TrueColor) ) {
00561
00562
00563
00564
00565 int conf[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 16,
00566 GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
00567 vi = glXChooseVisual(glxsrv->dpy, glxsrv->dpyScreen, conf);
00568 ns = 0;
00569 *numsamples = ns;
00570 *msamp = FALSE;
00571 *stereo = FALSE;
00572 }
00573
00574 if (!vi || (vi->c_class != TrueColor)) {
00575
00576 ns = 0;
00577 *numsamples = ns;
00578 *msamp = FALSE;
00579 *stereo = FALSE;
00580 }
00581
00582 return vi;
00583 }
00584
00585
00586
00587 static void setfullscreen(int fson, Display *dpy, Window win, int xinescreen) {
00588 struct {
00589 unsigned long flags;
00590 unsigned long functions;
00591 unsigned long decorations;
00592 long inputMode;
00593 unsigned long status;
00594 } wmhints;
00595
00596 memset(&wmhints, 0, sizeof(wmhints));
00597 wmhints.flags = 2;
00598 if (fson) {
00599 wmhints.decorations = 0;
00600 } else {
00601 wmhints.decorations = 1;
00602 }
00603
00604 Atom wmproperty = XInternAtom(dpy, "_MOTIF_WM_HINTS", True);
00605 XChangeProperty(dpy, win, wmproperty, wmproperty, 32,
00606 PropModeReplace, (unsigned char *) &wmhints, 5);
00607
00608
00609
00610
00611 if (fson) {
00612 int dpyScreen = DefaultScreen(dpy);
00613
00614 XSizeHints sizeHints;
00615 memset((void *) &(sizeHints), 0, sizeof(sizeHints));
00616 sizeHints.flags |= USSize;
00617 sizeHints.flags |= USPosition;
00618
00619 sizeHints.width = DisplayWidth(dpy, dpyScreen);
00620 sizeHints.height = DisplayHeight(dpy, dpyScreen);
00621 sizeHints.x = 0;
00622 sizeHints.y = 0;
00623
00624 #if defined(VMDXINERAMA)
00625 if (xinescreen != -1) {
00626 int xinerr, xinevent, xinenumscreens;
00627 if (XineramaQueryExtension(dpy, &xinevent, &xinerr) &&
00628 XineramaIsActive(dpy)) {
00629 XineramaScreenInfo *screens =
00630 XineramaQueryScreens(dpy, &xinenumscreens);
00631 if (xinescreen >= 0 && xinescreen < xinenumscreens) {
00632 sizeHints.width = screens[xinescreen].width;
00633 sizeHints.height = screens[xinescreen].height;
00634 sizeHints.x = screens[xinescreen].x_org;
00635 sizeHints.y = screens[xinescreen].y_org;
00636 }
00637 XFree(screens);
00638 }
00639 }
00640 #endif
00641
00642 XMoveWindow(dpy, win, sizeHints.x, sizeHints.y);
00643 XResizeWindow(dpy, win, sizeHints.width, sizeHints.height);
00644 }
00645 }
00646
00647
00649
00650 OpenGLDisplayDevice::OpenGLDisplayDevice()
00651 : OpenGLRenderer((char *) "VMD " VMDVERSION " OpenGL Display") {
00652
00653
00654 stereoNames = glStereoNameStr;
00655 stereoModes = OPENGL_STEREO_MODES;
00656
00657 renderNames = glRenderNameStr;
00658 renderModes = OPENGL_RENDER_MODES;
00659
00660 cacheNames = glCacheNameStr;
00661 cacheModes = OPENGL_CACHE_MODES;
00662
00663 memset(&glxsrv, 0, sizeof(glxsrv));
00664 glxsrv.dpy = NULL;
00665 glxsrv.dpyScreen = 0;
00666 glxsrv.xinp = NULL;
00667 glxsrv.sball = NULL;
00668 glxsrv.havefocus = 0;
00669 have_window = FALSE;
00670 screenX = screenY = 0;
00671 vmdapp = NULL;
00672 }
00673
00674 int OpenGLDisplayDevice::init(int argc, char **argv, VMDApp *app, int *size, int *loc) {
00675 vmdapp = app;
00676
00677
00678 glxsrv.windowID = open_window(name, size, loc, argc, argv);
00679 if (!have_window) return FALSE;
00680
00681
00682
00683 if (ext->hasmultisample)
00684 aaAvailable = TRUE;
00685 else
00686 aaAvailable = FALSE;
00687
00688
00689 if (ext->hasmultisample) {
00690 aa_on();
00691
00692
00693 }
00694
00695 cueingAvailable = TRUE;
00696 cueing_on();
00697
00698 cullingAvailable = TRUE;
00699 culling_off();
00700
00701 set_sphere_mode(sphereMode);
00702 set_sphere_res(sphereRes);
00703 set_line_width(lineWidth);
00704 set_line_style(lineStyle);
00705
00706
00707 reshape();
00708 normal();
00709 clear();
00710 update();
00711
00712
00713 return TRUE;
00714 }
00715
00716
00717 OpenGLDisplayDevice::~OpenGLDisplayDevice(void) {
00718 if (have_window) {
00719 #if defined(VMDXINPUT)
00720
00721 if (glxsrv.xinp != NULL) {
00722 xinput_close((xinputhandle *) glxsrv.xinp);
00723 }
00724 #endif
00725
00726
00727 if (glxsrv.sball != NULL) {
00728 spaceball_close(glxsrv.sball);
00729 }
00730
00731 free_opengl_ctx();
00732
00733
00734 XUnmapWindow(glxsrv.dpy, glxsrv.windowID);
00735 glXDestroyContext(glxsrv.dpy, glxsrv.cx);
00736 XDestroyWindow(glxsrv.dpy, glxsrv.windowID);
00737 XCloseDisplay(glxsrv.dpy);
00738 }
00739 }
00740
00741
00743
00744
00745
00746 Window OpenGLDisplayDevice::open_window(char *nm, int *size, int *loc,
00747 int argc, char** argv
00748 ) {
00749 Window win;
00750 int i, SX = 100, SY = 100, W, H;
00751
00752 char *dispname;
00753 if ((dispname = getenv("VMDGDISPLAY")) == NULL)
00754 dispname = getenv("DISPLAY");
00755
00756 if(!(glxsrv.dpy = XOpenDisplay(dispname))) {
00757 msgErr << "Exiting due to X-Windows OpenGL window creation failure." << sendmsg;
00758 if (dispname != NULL) {
00759 msgErr << "Failed to open display: " << dispname << sendmsg;
00760 }
00761 return (Window)0;
00762 }
00763
00764
00765
00766
00767
00768
00769 char **xextensionlist;
00770 int nextensions, xtn;
00771 int warncompositeext=0;
00772 xextensionlist = XListExtensions(glxsrv.dpy, &nextensions);
00773 for (xtn=0; xtn<nextensions; xtn++) {
00774
00775 if (xextensionlist[xtn] && !strcmp(xextensionlist[xtn], "Composite")) {
00776 warncompositeext=1;
00777 }
00778 }
00779 if (warncompositeext) {
00780 msgWarn << "Detected X11 'Composite' extension: if incorrect display occurs" << sendmsg;
00781 msgWarn << "try disabling this optional X server feature." << sendmsg;
00782 }
00783 XFreeExtensionList(xextensionlist);
00784
00785
00786
00787
00788
00789 glxsrv.dpyScreen = DefaultScreen(glxsrv.dpy);
00790 glxsrv.rootWindowID = RootWindow(glxsrv.dpy, glxsrv.dpyScreen);
00791 screenX = DisplayWidth(glxsrv.dpy, glxsrv.dpyScreen);
00792 screenY = DisplayHeight(glxsrv.dpy, glxsrv.dpyScreen);
00793 W = size[0];
00794 H = size[1];
00795 if (loc) {
00796 SX = loc[0];
00797
00798
00799 SY = (screenY - loc[1]) - H;
00800 }
00801
00802
00803 if (!glXQueryExtension(glxsrv.dpy, NULL, NULL)) {
00804 msgErr << "The X server does not support the OpenGL GLX extension."
00805 << " Exiting ..." << sendmsg;
00806 XCloseDisplay(glxsrv.dpy);
00807 return (Window)0;
00808 }
00809
00810 ext->hasstereo = TRUE;
00811 ext->stereodrawforced = FALSE;
00812 ext->hasmultisample = TRUE;
00813
00814
00815 XVisualInfo *vi;
00816 vi = vmd_get_visual(&glxsrv, &ext->hasstereo, &ext->hasmultisample, &ext->nummultisamples);
00817
00818
00819 if (!vi) {
00820 msgErr << "A TrueColor visual is required, but not available." << sendmsg;
00821 msgErr << "The X server is not capable of displaying double-buffered," << sendmsg;
00822 msgErr << "RGB images with a Z buffer. Exiting ..." << sendmsg;
00823 XCloseDisplay(glxsrv.dpy);
00824 return (Window)0;
00825 }
00826
00827 Atom wmDeleteWindow = XInternAtom(glxsrv.dpy, "WM_DELETE_WINDOW", False);
00828
00829
00830 if(!(glxsrv.cx = glXCreateContext(glxsrv.dpy, vi, None, GL_TRUE))) {
00831 msgErr << "Could not create OpenGL rendering context-> Exiting..."
00832 << sendmsg;
00833 return (Window)0;
00834 }
00835
00836
00837 glxsrv.cursor[0] = XCreateFontCursor(glxsrv.dpy, XC_left_ptr);
00838 glxsrv.cursor[1] = XCreateFontCursor(glxsrv.dpy, XC_fleur);
00839 glxsrv.cursor[2] = XCreateFontCursor(glxsrv.dpy, XC_sb_h_double_arrow);
00840 glxsrv.cursor[3] = XCreateFontCursor(glxsrv.dpy, XC_crosshair);
00841 glxsrv.cursor[4] = XCreateFontCursor(glxsrv.dpy, XC_watch);
00842 for(i=0; i < 5; i++)
00843 XRecolorCursor(glxsrv.dpy, glxsrv.cursor[i], &cursorFG, &cursorBG);
00844
00845
00846
00847
00848
00849 XSetWindowAttributes swa;
00850
00851
00852
00853 swa.colormap = XCreateColormap(glxsrv.dpy, glxsrv.rootWindowID,
00854 vi->visual, AllocNone);
00855
00856 swa.background_pixmap = None;
00857 swa.border_pixel=0;
00858 swa.event_mask = ExposureMask;
00859 swa.cursor = glxsrv.cursor[0];
00860
00861 win = XCreateWindow(glxsrv.dpy, glxsrv.rootWindowID, SX, SY, W, H, 0,
00862 vi->depth, InputOutput, vi->visual,
00863 CWBorderPixel | CWColormap | CWEventMask, &swa);
00864 XInstallColormap(glxsrv.dpy, swa.colormap);
00865
00866 XFree(vi);
00867
00868
00869
00870
00871 memset((void *) &(glxsrv.sizeHints), 0, sizeof(glxsrv.sizeHints));
00872 glxsrv.sizeHints.flags |= USSize;
00873 glxsrv.sizeHints.flags |= USPosition;
00874 glxsrv.sizeHints.width = W;
00875 glxsrv.sizeHints.height = H;
00876 glxsrv.sizeHints.x = SX;
00877 glxsrv.sizeHints.y = SY;
00878
00879 XSetStandardProperties(glxsrv.dpy, win, nm, "VMD", None, argv, argc, &glxsrv.sizeHints);
00880 XWMHints *wmHints = XAllocWMHints();
00881 wmHints->initial_state = NormalState;
00882 wmHints->flags = StateHint;
00883 XSetWMHints(glxsrv.dpy, win, wmHints);
00884 XFree(wmHints);
00885 XSetWMProtocols(glxsrv.dpy, win, &wmDeleteWindow, 1);
00886
00887
00888
00889 glXMakeCurrent(glxsrv.dpy, win, glxsrv.cx);
00890
00891
00892
00893 XSelectInput(glxsrv.dpy, win,
00894 KeyPressMask | ButtonPressMask | ButtonReleaseMask |
00895 StructureNotifyMask | ExposureMask |
00896 EnterWindowMask | LeaveWindowMask | FocusChangeMask);
00897 XMapRaised(glxsrv.dpy, win);
00898
00899
00900
00901 if (ext->hasmultisample) {
00902 int msampeext = 0;
00903
00904
00905 if (ext->vmdQueryExtension("GL_ARB_multisample")) {
00906 msampeext = 1;
00907 }
00908
00909 if (!msampeext) {
00910 ext->hasmultisample = FALSE;
00911 ext->nummultisamples = 0;
00912 }
00913 }
00914
00915
00916 setup_initial_opengl_state();
00917
00918 #if defined(VMDXINPUT)
00919
00920 if (getenv("VMDDISABLEXINPUT") == NULL) {
00921 glxsrv.xinp = xinput_enable(glxsrv.dpy, win);
00922 }
00923 #endif
00924
00925
00926
00927 if (getenv("VMDDISABLESPACEBALLXDRV") == NULL) {
00928 if (getenv("VMDSPACEBALLXDRVGLOBALFOCUS") == NULL) {
00929
00930 glxsrv.sball = spaceball_enable(glxsrv.dpy, InputFocus);
00931 } else {
00932
00933 glxsrv.sball = spaceball_enable(glxsrv.dpy, win);
00934 }
00935 }
00936 if (glxsrv.sball != NULL) {
00937 msgInfo << "X-Windows ClientMessage-based Spaceball device available."
00938 << sendmsg;
00939 }
00940
00941
00942
00943 spaceball_init_event(&glxsrv.sballevent);
00944
00945
00946 have_window = TRUE;
00947
00948
00949 return win;
00950 }
00951
00952 void OpenGLDisplayDevice::do_resize_window(int w, int h) {
00953 if (getenv("VMDFULLSCREEN")) {
00954 int xinescreen=0;
00955 if (getenv("VMDXINESCREEN")) {
00956 xinescreen = atoi(getenv("VMDXINESCREEN"));
00957 }
00958 setfullscreen(1, glxsrv.dpy, glxsrv.windowID, xinescreen);
00959 } else {
00960 setfullscreen(0, glxsrv.dpy, glxsrv.windowID, -1);
00961 XResizeWindow(glxsrv.dpy, glxsrv.windowID, w, h);
00962 }
00963 }
00964
00965 void OpenGLDisplayDevice::do_reposition_window(int xpos, int ypos) {
00966 XMoveWindow(glxsrv.dpy, glxsrv.windowID, xpos, ypos);
00967 }
00968
00970
00971
00972
00973
00974
00975
00976 int OpenGLDisplayDevice::x(void) {
00977 Window rw, cw;
00978 int rx, ry, wx, wy;
00979 unsigned int keymask;
00980
00981
00982 XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
00983
00984
00985 return rx;
00986 }
00987
00988
00989
00990 int OpenGLDisplayDevice::y(void) {
00991 Window rw, cw;
00992 int rx, ry, wx, wy;
00993 unsigned int keymask;
00994
00995
00996 XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
00997
00998
00999
01000
01001 return screenY - ry;
01002 }
01003
01004
01005 int OpenGLDisplayDevice::shift_state(void) {
01006 int retval = 0;
01007
01008
01009 Window rw, cw;
01010 int rx, ry, wx, wy;
01011 unsigned int keymask;
01012 XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
01013
01014
01015 if ((keymask & ShiftMask) != 0)
01016 retval |= SHIFT;
01017
01018 if ((keymask & ControlMask) != 0)
01019 retval |= CONTROL;
01020
01021 if ((keymask & Mod1Mask) != 0)
01022 retval |= ALT;
01023
01024
01025 return retval;
01026 }
01027
01028
01029
01030 int OpenGLDisplayDevice::spaceball(int *rx, int *ry, int *rz, int *tx, int *ty,
01031 int *tz, int *buttons) {
01032
01033 if ((glxsrv.sball != NULL || glxsrv.xinp != NULL)
01034 && glxsrv.sballevent.event == 1) {
01035 *rx = glxsrv.sballevent.rx;
01036 *ry = glxsrv.sballevent.ry;
01037 *rz = glxsrv.sballevent.rz;
01038 *tx = glxsrv.sballevent.tx;
01039 *ty = glxsrv.sballevent.ty;
01040 *tz = glxsrv.sballevent.tz;
01041 *buttons = glxsrv.sballevent.buttons;
01042 return 1;
01043 }
01044
01045 return 0;
01046 }
01047
01048
01049
01050
01051 void OpenGLDisplayDevice::set_cursor(int n) {
01052 int cursorindex;
01053
01054 switch (n) {
01055 default:
01056 case DisplayDevice::NORMAL_CURSOR: cursorindex = 0; break;
01057 case DisplayDevice::TRANS_CURSOR: cursorindex = 1; break;
01058 case DisplayDevice::SCALE_CURSOR: cursorindex = 2; break;
01059 case DisplayDevice::PICK_CURSOR: cursorindex = 3; break;
01060 case DisplayDevice::WAIT_CURSOR: cursorindex = 4; break;
01061 }
01062
01063 XDefineCursor(glxsrv.dpy, glxsrv.windowID, glxsrv.cursor[cursorindex]);
01064 }
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074 void OpenGLDisplayDevice::queue_events(void) {
01075 XSelectInput(glxsrv.dpy, glxsrv.windowID,
01076 KeyPressMask | ButtonPressMask | ButtonReleaseMask |
01077 StructureNotifyMask | ExposureMask |
01078 EnterWindowMask | LeaveWindowMask | FocusChangeMask);
01079 }
01080
01081
01082
01083
01084
01085 int OpenGLDisplayDevice::read_event(long &retdev, long &retval) {
01086 XEvent xev;
01087 char keybuf[10];
01088 int keybuflen = 9;
01089 KeySym keysym;
01090 XComposeStatus comp;
01091
01092 memset(keybuf, 0, sizeof(keybuf));
01093
01094
01095
01096 spaceball_clear_event(&glxsrv.sballevent);
01097
01098 retdev = WIN_NOEVENT;
01099
01100
01101 int need_reshape = FALSE;
01102 while (XPending(glxsrv.dpy)) {
01103 XNextEvent(glxsrv.dpy, &xev);
01104
01105
01106 switch(xev.type) {
01107 case Expose:
01108 case ConfigureNotify:
01109 case ReparentNotify:
01110 case MapNotify:
01111 need_reshape = TRUE;
01112 _needRedraw = 1;
01113
01114 break;
01115 case KeyPress:
01116 {
01117 int k = XLookupString(&(xev.xkey), keybuf, keybuflen, &keysym, &comp);
01118
01119 if (k > 0 && *keybuf != '\0') {
01120 retdev = WIN_KBD;
01121 retval = *keybuf;
01122 } else {
01123 switch (keysym) {
01124 case XK_Escape: retdev = WIN_KBD_ESCAPE; break;
01125 case XK_Up: retdev = WIN_KBD_UP; break;
01126 case XK_Down: retdev = WIN_KBD_DOWN; break;
01127 case XK_Left: retdev = WIN_KBD_LEFT; break;
01128 case XK_Right: retdev = WIN_KBD_RIGHT; break;
01129 case XK_Page_Up: retdev = WIN_KBD_PAGE_UP; break;
01130 case XK_Page_Down: retdev = WIN_KBD_PAGE_UP; break;
01131 case XK_Home: retdev = WIN_KBD_HOME; break;
01132 case XK_End: retdev = WIN_KBD_END; break;
01133 case XK_Insert: retdev = WIN_KBD_INSERT; break;
01134 case XK_Delete: retdev = WIN_KBD_DELETE; break;
01135 case XK_F1: retdev = WIN_KBD_F1; break;
01136 case XK_F2: retdev = WIN_KBD_F2; break;
01137 case XK_F3: retdev = WIN_KBD_F3; break;
01138 case XK_F4: retdev = WIN_KBD_F4; break;
01139 case XK_F5: retdev = WIN_KBD_F5; break;
01140 case XK_F6: retdev = WIN_KBD_F6; break;
01141 case XK_F7: retdev = WIN_KBD_F7; break;
01142 case XK_F8: retdev = WIN_KBD_F8; break;
01143 case XK_F9: retdev = WIN_KBD_F9; break;
01144 case XK_F10: retdev = WIN_KBD_F10; break;
01145 case XK_F11: retdev = WIN_KBD_F11; break;
01146 case XK_F12: retdev = WIN_KBD_F12; break;
01147 }
01148 }
01149 break;
01150 }
01151 case ButtonPress:
01152 case ButtonRelease:
01153 {
01154 unsigned int button = xev.xbutton.button;
01155 retval = (xev.type == ButtonPress);
01156 switch (button) {
01157 case Button1:
01158 retdev = WIN_LEFT;
01159 break;
01160 case Button2:
01161 retdev = WIN_MIDDLE;
01162 break;
01163 case Button3:
01164 retdev = WIN_RIGHT;
01165 break;
01166 case Button4:
01167 retdev = WIN_WHEELUP;
01168 break;
01169 case Button5:
01170 retdev = WIN_WHEELDOWN;
01171 break;
01172 }
01173 break;
01174 }
01175 break;
01176
01177 case FocusIn:
01178 case EnterNotify:
01179 glxsrv.havefocus=1;
01180 break;
01181
01182 case FocusOut:
01183 case LeaveNotify:
01184 glxsrv.havefocus=0;
01185 break;
01186
01187 case ClientMessage:
01188 #if 1
01189
01190
01191 spaceball_decode_event(glxsrv.sball, &xev, &glxsrv.sballevent);
01192 #else
01193
01194
01195 if (glxsrv.havefocus) {
01196 spaceball_decode_event(glxsrv.sball, &xev, &glxsrv.sballevent);
01197 }
01198 #endif
01199 break;
01200
01201 default:
01202 #if defined(VMDXINPUT)
01203 if (glxsrv.xinp != NULL) {
01204 if (xinput_decode_event((xinputhandle *) glxsrv.xinp, &xev,
01205 &glxsrv.sballevent)) {
01206 break;
01207 }
01208 }
01209 #endif
01210
01211 #if 0
01212 msgWarn << "Unrecognized X11 event" << xev.type << sendmsg;
01213 #endif
01214 break;
01215
01216 }
01217 }
01218
01219 if (need_reshape)
01220 reshape();
01221
01222 return (retdev != WIN_NOEVENT);
01223 }
01224
01225
01226
01227
01228
01229
01230 void OpenGLDisplayDevice::reshape(void) {
01231
01232
01233 XWindowAttributes xwa;
01234 Window childwin;
01235 int rx, ry;
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250 XGetWindowAttributes(glxsrv.dpy, glxsrv.windowID, &xwa);
01251 XTranslateCoordinates(glxsrv.dpy, glxsrv.windowID, glxsrv.rootWindowID, -xwa.border_width,
01252 -xwa.border_width, &rx, &ry, &childwin);
01253
01254 xSize = xwa.width;
01255 ySize = xwa.height;
01256 xOrig = rx;
01257 yOrig = screenY - ry - ySize;
01258
01259 switch (inStereo) {
01260 case OPENGL_STEREO_SIDE:
01261 set_screen_pos(0.5f * (float)xSize / (float)ySize);
01262 break;
01263
01264 case OPENGL_STEREO_ABOVEBELOW:
01265 set_screen_pos(2.0f * (float)xSize / (float)ySize);
01266 break;
01267
01268 case OPENGL_STEREO_STENCIL_CHECKERBOARD:
01269 case OPENGL_STEREO_STENCIL_COLUMNS:
01270 case OPENGL_STEREO_STENCIL_ROWS:
01271 enable_stencil_stereo(inStereo);
01272 set_screen_pos((float)xSize / (float)ySize);
01273 break;
01274
01275 default:
01276 set_screen_pos((float)xSize / (float)ySize);
01277 break;
01278 }
01279 }
01280
01281 unsigned char * OpenGLDisplayDevice::readpixels(int &xs, int &ys) {
01282 unsigned char * img = NULL;
01283 xs = xSize;
01284 ys = ySize;
01285
01286
01287 if ((img = (unsigned char *) malloc(xs * ys * 3)) != NULL) {
01288 glPixelStorei(GL_PACK_ALIGNMENT, 1);
01289 glReadPixels(0, 0, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, img);
01290 return img;
01291 }
01292
01293
01294 xs = 0;
01295 ys = 0;
01296 return NULL;
01297 }
01298
01299
01300
01301 void OpenGLDisplayDevice::update(int do_update) {
01302 if (wiregl) {
01303 glFinish();
01304
01305
01306 }
01307
01308 if(do_update)
01309 glXSwapBuffers(glxsrv.dpy, glxsrv.windowID);
01310
01311 glDrawBuffer(GL_BACK);
01312 }
01313