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/cursorfont.h>
00030
00031 #include "OpenGLDisplayDevice.h"
00032 #include "Inform.h"
00033 #include "utilities.h"
00034 #include "config.h"
00035
00036
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
00061 #if defined(GL_ARB_multisample) && defined(GLX_SAMPLES_ARB) && defined(GLX_SAMPLE_BUFFERS_ARB)
00062 #define USEARBMULTISAMPLE 1
00063 #endif
00064
00065
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
00137
00138
00139
00140 sballevent->tx += mptr->axis_data[0];
00141 sballevent->ty += mptr->axis_data[1];
00142 sballevent->tz += mptr->axis_data[2];
00143 sballevent->rx += mptr->axis_data[3];
00144 sballevent->ry += mptr->axis_data[4];
00145 sballevent->rz += mptr->axis_data[5];
00146 sballevent->period += 50;
00147 sballevent->event = 1;
00148 return 1;
00149 } else if (xev->type == dev->buttonpressevent) {
00150
00151
00152 sballevent->buttons |= 1;
00153 sballevent->event = 1;
00154 return 1;
00155 } else if (xev->type == dev->buttonreleaseevent) {
00156
00157
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
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
00186 xidevhandle *dev_spaceball = NULL;
00187
00188
00189
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
00197
00198
00199 list = (XDeviceInfoPtr) XListInputDevices(dpy, &numdev);
00200
00201 numextdev = 0;
00202 for (i = 0; i < numdev; i++) {
00203 if (list[i].use == IsXExtensionDevice) {
00204
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
00225 if (!strupncmp(list[i].name, "evdev brain", strlen("evdev brain")))
00226 continue;
00227
00228
00229 msgInfo << " [" << list[i].id << "] " << list[i].name
00230 << ", type: " << (int) list[i].type
00231 << ", classes: " << (int) list[i].num_classes << sendmsg;
00232
00233
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
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
00253 return NULL;
00254 }
00255
00256 if (dev_spaceball) {
00257 msgInfo << "Attached to XInput Spaceball" << sendmsg;
00258 }
00259
00260
00261
00262
00263 if (dev_spaceball != NULL ) {
00264 handle->dev_spaceball = dev_spaceball;
00265
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
00278 free(handle);
00279 }
00280 }
00281
00282 #endif
00283
00284
00285
00286 static spaceballhandle * spaceball_enable(Display *dpy, Window win) {
00287
00288 spaceballhandle *handle = (spaceballhandle *) malloc(sizeof(spaceballhandle));
00289 memset(handle, 0, sizeof(spaceballhandle));
00290
00291
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;
00301 }
00302
00303
00304 Window root = RootWindow(dpy, DefaultScreen(dpy));
00305
00306
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
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);
00334 msg.xclient.data.s[1] = (short) (((win)) &0x0000FFFF);
00335 msg.xclient.data.s[2] = SBALL_COMMAND_APP_WINDOW;
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
00366
00367
00368
00369 sballevent->tx += xev->xclient.data.s[2];
00370 sballevent->ty += xev->xclient.data.s[3];
00371 sballevent->tz += xev->xclient.data.s[4];
00372 sballevent->rx += xev->xclient.data.s[5];
00373 sballevent->ry += xev->xclient.data.s[6];
00374 sballevent->rz += xev->xclient.data.s[7];
00375 sballevent->period += xev->xclient.data.s[8];
00376 sballevent->event = 1;
00377 return 1;
00378 } else if (evtype == handle->ev_button_press) {
00379
00380
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
00386
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
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
00426
00427 for (dsize=32; dsize >= 16; dsize-=4) {
00428
00429
00430 #if defined(GLX_VIDEO_RESIZE_SUN) && defined(USEARBMULTISAMPLE)
00431 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00432
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;
00446 }
00447 }
00448 }
00449 #endif
00450
00451
00452 #if defined(USEARBMULTISAMPLE)
00453 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00454
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;
00468 }
00469 }
00470 }
00471 #endif
00472
00473
00474
00475 #if defined(GLX_SGIS_multisample)
00476 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00477
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;
00491 }
00492 }
00493 }
00494 #endif
00495
00496
00497 #if defined(GLX_VIDEO_RESIZE_SUN) && defined(USEARBMULTISAMPLE)
00498 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00499
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;
00512 }
00513 }
00514 }
00515 #endif
00516
00517 if (getenv("VMDPREFERSTEREO") != NULL) {
00518
00519
00520
00521
00522
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;
00530 *numsamples = ns;
00531 *msamp = FALSE;
00532 *stereo = TRUE;
00533 *hasdvr = FALSE;
00534 }
00535 } else {
00536 #if defined(USEARBMULTISAMPLE)
00537
00538 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00539
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;
00552 }
00553 }
00554 }
00555 #endif
00556
00557 #if defined(GLX_SGIS_multisample)
00558
00559 if (!simplegraphics && (!vi || (vi->c_class != TrueColor))) {
00560
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;
00573 }
00574 }
00575 }
00576 #endif
00577 }
00578
00579 }
00580
00581
00582
00583
00584
00585
00586
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;
00593 *numsamples = ns;
00594 *msamp = FALSE;
00595 *stereo = TRUE;
00596 *hasdvr = FALSE;
00597 }
00598
00599
00600
00601
00602
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;
00609 *numsamples = ns;
00610 *msamp = FALSE;
00611 *stereo = TRUE;
00612 *hasdvr = FALSE;
00613 }
00614
00615
00616
00617
00618
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;
00624 *numsamples = ns;
00625 *msamp = FALSE;
00626 *stereo = TRUE;
00627 *hasdvr = FALSE;
00628 }
00629
00630
00631
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;
00638 *numsamples = ns;
00639 *msamp = FALSE;
00640 *stereo = FALSE;
00641 }
00642
00643
00644 if(!vi || (vi->c_class != TrueColor) ) {
00645
00646
00647
00648
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;
00653 *numsamples = ns;
00654 *msamp = FALSE;
00655 *stereo = FALSE;
00656 *hasdvr = FALSE;
00657 }
00658
00659 if (!vi || (vi->c_class != TrueColor)) {
00660
00661 ns = 0;
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
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;
00700
00701
00702 glxsrv.windowID = open_window(name, size, loc, argc, argv);
00703 if (!have_window) return FALSE;
00704
00705
00706
00707 if (ext->hasmultisample)
00708 aaAvailable = TRUE;
00709 else
00710 aaAvailable = FALSE;
00711
00712 cueingAvailable = TRUE;
00713 cullingAvailable = TRUE;
00714 cullingEnabled = FALSE;
00715
00716
00717 if (ext->hasmultisample) {
00718 aa_on();
00719
00720
00721 }
00722 cueing_off();
00723
00724 set_sphere_mode(sphereMode);
00725 set_sphere_res(sphereRes);
00726 set_line_width(lineWidth);
00727 set_line_style(lineStyle);
00728
00729
00730 reshape();
00731 normal();
00732 clear();
00733 update();
00734
00735
00736 return TRUE;
00737 }
00738
00739
00740 OpenGLDisplayDevice::~OpenGLDisplayDevice(void) {
00741 if (have_window) {
00742 #if defined(VMDXINPUT)
00743
00744 if (glxsrv.xinp != NULL) {
00745 xinput_close((xinputhandle *) glxsrv.xinp);
00746 }
00747 #endif
00748
00749
00750 if (glxsrv.sball != NULL) {
00751 spaceball_close(glxsrv.sball);
00752 }
00753
00754 free_opengl_ctx();
00755
00756
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
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
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
00796
00797 SY = (screenY - loc[1]) - H;
00798 }
00799
00800
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;
00809 ext->stereodrawforced = FALSE;
00810 ext->hasmultisample = TRUE;
00811
00812
00813 XVisualInfo *vi;
00814 vi = vmd_get_visual(&glxsrv, &ext->hasstereo, &ext->hasmultisample, &ext->nummultisamples, &ext->hasglvideoresizesun);
00815
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
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
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
00845
00846 XSetWindowAttributes swa;
00847
00848
00849
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);
00864
00865
00866
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
00886 glXMakeCurrent(glxsrv.dpy, win, glxsrv.cx);
00887
00888
00889
00890 XSelectInput(glxsrv.dpy, win,
00891 KeyPressMask | ButtonPressMask | ButtonReleaseMask |
00892 StructureNotifyMask | ExposureMask |
00893 EnterWindowMask | LeaveWindowMask | FocusChangeMask);
00894 XMapRaised(glxsrv.dpy, win);
00895
00896
00897
00898 if (ext->hasmultisample) {
00899 int msampeext = 0;
00900
00901
00902 if (ext->vmdQueryExtension("GL_ARB_multisample")) {
00903 msampeext = 1;
00904 }
00905
00906
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
00918 setup_initial_opengl_state();
00919
00920 #if defined(VMDXINPUT)
00921
00922 if (getenv("VMDDISABLEXINPUT") == NULL) {
00923 glxsrv.xinp = xinput_enable(glxsrv.dpy, win);
00924 }
00925 #endif
00926
00927
00928
00929 if (getenv("VMDDISABLESPACEBALLXDRV") == NULL) {
00930 if (getenv("VMDSPACEBALLXDRVGLOBALFOCUS") == NULL) {
00931
00932 glxsrv.sball = spaceball_enable(glxsrv.dpy, InputFocus);
00933 } else {
00934
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
00945 spaceball_init_event(&glxsrv.sballevent);
00946
00947
00948 have_window = TRUE;
00949
00950
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
00965
00966
00967
00968 int OpenGLDisplayDevice::x(void) {
00969 Window rw, cw;
00970 int rx, ry, wx, wy;
00971 unsigned int keymask;
00972
00973
00974 XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
00975
00976
00977 return rx;
00978 }
00979
00980
00981
00982 int OpenGLDisplayDevice::y(void) {
00983 Window rw, cw;
00984 int rx, ry, wx, wy;
00985 unsigned int keymask;
00986
00987
00988 XQueryPointer(glxsrv.dpy, glxsrv.windowID, &rw, &cw, &rx, &ry, &wx, &wy, &keymask);
00989
00990
00991
00992
00993 return screenY - ry;
00994 }
00995
00996
00997 int OpenGLDisplayDevice::shift_state(void) {
00998 int retval = 0;
00999
01000
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
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
01017 return retval;
01018 }
01019
01020
01021
01022 int OpenGLDisplayDevice::spaceball(int *rx, int *ry, int *rz, int *tx, int *ty,
01023 int *tz, int *buttons) {
01024
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
01042
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
01061
01062
01063
01064
01065
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
01075
01076
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
01085
01086 spaceball_clear_event(&glxsrv.sballevent);
01087
01088 retdev = WIN_NOEVENT;
01089
01090
01091 int need_reshape = FALSE;
01092 while (XPending(glxsrv.dpy)) {
01093 XNextEvent(glxsrv.dpy, &xev);
01094
01095
01096 switch(xev.type) {
01097 case Expose:
01098 case ConfigureNotify:
01099 case ReparentNotify:
01100 case MapNotify:
01101 need_reshape = TRUE;
01102 _needRedraw = 1;
01103
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
01153
01154 spaceball_decode_event(glxsrv.sball, &xev, &glxsrv.sballevent);
01155 #else
01156
01157
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
01190
01191
01192
01193 void OpenGLDisplayDevice::reshape(void) {
01194
01195
01196 XWindowAttributes xwa;
01197 Window childwin;
01198 int rx, ry;
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
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
01250
01251
01252 if (ext->hasglreadvideopixelssun) {
01253 if ((img = (unsigned char *) malloc(xs * ys * 3)) != NULL) {
01254 GLenum err;
01255 GLint buffer;
01256
01257
01258
01259 err = glGetError();
01260 glGetIntegerv(GL_READ_BUFFER, &buffer);
01261 glReadBuffer(GL_FRONT);
01262 glXSwapBuffers(glxsrv.dpy, glxsrv.windowID);
01263
01264
01265
01266 #if 0
01267
01268 glReadVideoPixelsSUN(0, 0, xs, ys, GL_RGB, GL_UNSIGNED_BYTE, img);
01269 #else
01270
01271
01272
01273
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);
01279
01280
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
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
01302 xs = 0;
01303 ys = 0;
01304 return NULL;
01305 }
01306
01307
01308
01309 void OpenGLDisplayDevice::update(int do_update) {
01310 if (wiregl) {
01311 glFinish();
01312
01313
01314 }
01315
01316 if(do_update)
01317 glXSwapBuffers(glxsrv.dpy, glxsrv.windowID);
01318
01319 glDrawBuffer(GL_BACK);
01320 }
01321