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

Win32OpenGLDisplayDevice.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: Win32OpenGLDisplayDevice.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.118 $      $Date: 2011/02/25 18:15:15 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   Subclass of DisplayDevice, this object has routines used by all the
00019  *   different display devices that are OpenGL-specific.  Will render drawing
00020  *   commands into a single window.
00021  ***************************************************************************/
00022 
00023 #if 1
00024 #ifndef _WIN32_WINNT
00025 #define _WIN32_WINNT 0x0400 // hack to allow access to mouse wheel events
00026 #endif
00027 #endif
00028 #include <windows.h>        // Mouse wheel events and related macros
00029 #include <winuser.h>        // Mouse wheel events and related macros
00030 
00031 #include "VMDApp.h"
00032 #include "OpenGLDisplayDevice.h"
00033 #include "Inform.h"
00034 #include "utilities.h"
00035 #include "config.h"   // VMD version strings etc
00036 
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <math.h>
00040 #include <GL/gl.h>
00041 
00042 #include "../msvc/winvmd/res/resource.h" // VMD icon resource
00043 
00044 // NOTE: you may have to get copies of the latest OpenGL extension headers
00045 // from the OpenGL web site if your Linux or Win32 machine lacks them:
00046 //   http://oss.sgi.com/projects/ogl-sample/registry/
00047 #include <GL/glext.h>   // include OpenGL extension headers
00048 #include <GL/wglext.h>  // include OpenGL extension headers
00049 
00050 // static data for this object
00051 static const char *glStereoNameStr[OPENGL_STEREO_MODES] = 
00052  { "Off", 
00053    "QuadBuffered", 
00054    "DTI SideBySide",
00055    "Checkerboard",
00056    "ColumnInterleaved",
00057    "RowInterleaved",
00058    "Anaglyph",
00059    "SideBySide", 
00060    "AboveBelow",
00061    "Left", 
00062    "Right" };
00063 
00064 static const char *glRenderNameStr[OPENGL_RENDER_MODES] =
00065 { "Normal",
00066   "GLSL",
00067   "Acrobat3D" };
00068 
00069 static const char *glCacheNameStr[OPENGL_CACHE_MODES] = 
00070 { "Off",
00071   "On" };
00072 
00073 static char szAppName[] = "VMD";
00074 static char szAppTitle[]="VMD " VMDVERSION " OpenGL Display";
00075 
00076 LRESULT WINAPI vmdWindowProc( HWND, UINT, WPARAM, LPARAM );
00077 
00078 static int OpenWin32Connection(wgldata * glwsrv) {
00079   WNDCLASS  wc;
00080   HINSTANCE hInstance = GetModuleHandle(NULL);
00081 
00082   /* Clear (important!) and then fill in the window class structure. */
00083   memset(&wc, 0, sizeof(WNDCLASS));
00084   wc.style         = CS_OWNDC;
00085   wc.lpfnWndProc   = (WNDPROC) vmdWindowProc;
00086   wc.hInstance     = hInstance;
00087 #if 1
00088   // use our VMD icon
00089   wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
00090 #else
00091   wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
00092 #endif
00093   wc.hCursor       = LoadCursor(hInstance, IDC_ARROW);
00094   wc.hbrBackground = NULL; /* Default color */
00095   wc.lpszMenuName  = NULL;
00096   wc.lpszClassName = szAppName;
00097 
00098   if(!RegisterClass(&wc)) {
00099     printf("Cannot register window class.\n");
00100     return -1;
00101   }
00102 
00103   // get screen size 
00104   // XXX There's no Win32 API to get the full multi-monitor desktop,
00105   //     so this code doesn't correctly handle multi-monitor systems yet.
00106   //     To correctly handle multiple monitors, we'd have to 
00107   //     walk the device tree, take into account monitor layout/positioning, 
00108   //     and compute the desktop dimensions from that.  Since these values
00109   //     are currently only used by do_reposition_window() method, we can
00110   //     live with primary-monitor values for the time being.
00111   glwsrv->scrwidth  = GetSystemMetrics(SM_CXSCREEN);
00112   glwsrv->scrheight = GetSystemMetrics(SM_CYSCREEN);
00113 
00114   return 0;
00115 }
00116 
00117 static int PFDHasStereo(int ID, HDC hDC) {
00118   PIXELFORMATDESCRIPTOR pfd;
00119   DescribePixelFormat(hDC, ID, sizeof(PIXELFORMATDESCRIPTOR), &pfd); 
00120 
00121 #if 0
00122   // print a message if we find out we've got an accelerated mode
00123   if ((pfd.dwFlags & PFD_GENERIC_ACCELERATED) ||
00124       !(pfd.dwFlags & PFD_GENERIC_FORMAT))  
00125     msgInfo << "Hardware 3D Acceleration enabled." << sendmsg;
00126   else
00127     msgInfo << "No hardware 3D Acceleration found." << sendmsg;
00128 #endif
00129 
00130   if (pfd.dwFlags & PFD_STEREO) 
00131     return 1;
00132   
00133   return 0;
00134 } 
00135 
00136 #if 0
00137 static void PrintPFD(int ID, HDC hDC) {
00138   PIXELFORMATDESCRIPTOR pfd;
00139   FILE * ofp;
00140 
00141   if (ID == 0) {
00142     int i, num;
00143     num = DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfd); 
00144     for (i=1; i<num; i++) 
00145       PrintPFD(i, hDC);
00146 
00147     return;
00148   }
00149 
00150   DescribePixelFormat(hDC, ID, sizeof(PIXELFORMATDESCRIPTOR), &pfd); 
00151 
00152   ofp=fopen("c:/video.txt", "a+");
00153   if (ofp == NULL) 
00154     ofp=stdout;
00155 
00156   if (pfd.cColorBits < 15) {
00157     fprintf(ofp, "Windows Pixel Format ID: %d -- not enough color bits\n", ID);
00158   }
00159   else {
00160     fprintf(ofp, "\nWindows Pixel Format ID: %d\n", ID);
00161     fprintf(ofp, "  Color Buffer Depth: %d bits\n", pfd.cColorBits);
00162     fprintf(ofp, "      Z Buffer Depth: %d bits\n", pfd.cDepthBits);
00163     if (pfd.dwFlags & PFD_DOUBLEBUFFER)
00164       fprintf(ofp, "    PFD_DOUBLEBUFFER\n"); 
00165     if (pfd.dwFlags & PFD_STEREO)
00166       fprintf(ofp, "    PFD_STEREO\n"); 
00167     if (pfd.dwFlags & PFD_DRAW_TO_WINDOW)
00168       fprintf(ofp, "    PFD_DRAW_TO_WINDOW\n"); 
00169     if (pfd.dwFlags & PFD_SUPPORT_GDI)
00170       fprintf(ofp, "    PFD_SUPPORT_GDI\n"); 
00171     if (pfd.dwFlags & PFD_SUPPORT_OPENGL)
00172       fprintf(ofp, "    PFD_SUPPORT_OPENGL\n"); 
00173     if (pfd.dwFlags & PFD_SWAP_EXCHANGE) 
00174       fprintf(ofp, "    PFD_SWAP_EXCHANGE\n"); 
00175     if (pfd.dwFlags & PFD_SWAP_COPY) 
00176       fprintf(ofp, "    PFD_SWAP_COPY\n"); 
00177     if (pfd.dwFlags & PFD_SWAP_LAYER_BUFFERS) 
00178       fprintf(ofp, "    PFD_SWAP_LAYER_BUFFERS\n"); 
00179     if (pfd.dwFlags & PFD_GENERIC_ACCELERATED)
00180       fprintf(ofp, "    PFD_GENERIC_ACCELERATED\n"); 
00181     if (pfd.dwFlags & PFD_GENERIC_FORMAT)
00182       fprintf(ofp, "    PFD_GENERIC_FORMAT\n"); 
00183   } 
00184   if (ofp != NULL && ofp != stdout) 
00185     fclose(ofp);
00186 }
00187 #endif
00188 
00189 static HGLRC SetupOpenGL(wgldata *glwsrv) {
00190   int ID;
00191   HDC hDC;
00192   HGLRC hRC;
00193 
00194   PIXELFORMATDESCRIPTOR pfd = {
00195     sizeof (PIXELFORMATDESCRIPTOR), /* struct size      */
00196     1,                              /* Version number   */
00197     PFD_DRAW_TO_WINDOW      /* Flags, draw to a window, */
00198       | PFD_DOUBLEBUFFER    /* Requires Doublebuffer hw */
00199       | PFD_STEREO          /* we want stereo if possible */ 
00200       | PFD_SUPPORT_OPENGL, /* use OpenGL               */
00201     PFD_TYPE_RGBA,          /* RGBA pixel values        */
00202     16,                     /* 24-bit color             */
00203     0, 0, 0,                /* RGB bits & shift sizes.  */
00204     0, 0, 0,                /* Don't care about them    */
00205     0, 0,                   /* No alpha buffer info     */
00206     0, 0, 0, 0, 0,          /* No accumulation buffer   */
00207     16,                     /* depth buffer             */
00208     1,                      /* stencil buffer           */
00209     0,                      /* No auxiliary buffers     */
00210     PFD_MAIN_PLANE,         /* Layer type               */
00211     0,                      /* Reserved (must be 0)     */
00212     0,                      /* No layer mask            */
00213     0,                      /* No visible mask          */
00214     0                       /* No damage mask           */
00215   };
00216 
00217   hDC = GetDC(glwsrv->hWnd);
00218   ID = ChoosePixelFormat(hDC, &pfd);
00219 
00220   /*
00221    * catch errors here.
00222    * If ID is zero, then there's
00223    * something wrong... most likely the window's
00224    * style bits are incorrect (in CreateWindow() )
00225    * or OpenGL isn't installed on this machine
00226    */
00227 
00228   if (ID == 0) {
00229     printf("Error selecting OpenGL Pixel Format!!\n");
00230     return NULL;
00231   }
00232 
00233   glwsrv->PFDisStereo = PFDHasStereo(ID, hDC);
00234   //PrintPFD(ID, hDC);
00235   //printf("*** Setting Windows OpenGL Pixel Format to ID %d ***\n", ID); 
00236   SetPixelFormat( hDC, ID, &pfd );
00237 
00238   hRC = wglCreateContext(hDC);
00239   ReleaseDC(glwsrv->hWnd, hDC);
00240 
00241   return hRC;
00242 }
00243 
00244 static int myCreateWindow(OpenGLDisplayDevice *ogldispdev,
00245                           int xpos, int ypos, int xs, int ys) {
00246   /* Create a main window for this application instance. */
00247   ogldispdev->glwsrv.hWnd =
00248         CreateWindow(
00249               szAppName,          /* app name */
00250               szAppTitle,         /* Text for window title bar */
00251               WS_OVERLAPPEDWINDOW /* Window style */
00252                | WS_CLIPCHILDREN
00253                | WS_CLIPSIBLINGS, /* NEED THESE for OpenGL calls to work! */
00254               xpos, ypos,
00255               xs, ys,
00256               NULL,                  /* no parent window                */
00257               NULL,                  /* Use the window class menu.      */
00258               GetModuleHandle(NULL), /* This instance owns this window  */
00259               ogldispdev             /* We pass in the caller class ptr */
00260         );
00261 
00262   if (!ogldispdev->glwsrv.hWnd) {
00263     printf("Couldn't Open Window!!\n");
00264     return -1;
00265   }
00266 
00267   ogldispdev->glwsrv.hDC = GetDC(ogldispdev->glwsrv.hWnd);
00268   wglMakeCurrent(ogldispdev->glwsrv.hDC, ogldispdev->glwsrv.hRC);
00269 
00270   /* Make the window visible & update its client area */
00271   ShowWindow(ogldispdev->glwsrv.hWnd, SW_SHOW);   /* Show the window    */
00272   UpdateWindow(ogldispdev->glwsrv.hWnd );         /* Sends WM_PAINT msg */
00273   DragAcceptFiles(ogldispdev->glwsrv.hWnd, TRUE); /* Enable Drag & Drop */
00274 
00275   return 0;
00276 }
00277 
00278 static void vmd_transwin32mouse(OpenGLDisplayDevice * d, LPARAM l) {
00279   int x, y;
00280   x = LOWORD(l);
00281   y = HIWORD(l);
00282   if(x & 1 << 15) x -= (1 << 16); // handle mouse capture in negative range
00283   if(y & 1 << 15) y -= (1 << 16); // handle mouse capture in negative range
00284   d->glwsrv.MouseX = x;
00285   d->glwsrv.MouseY = (d->ySize) - y; // translate to coords VMD likes (GL-like)
00286 }
00287 
00288 
00289 #ifdef VMDSPACEWARE
00290 // Windows code to talk to Spaceball device
00291 static void vmd_setupwin32spaceball(wgldata *glwsrv) {
00292   SiOpenData oData;
00293   enum SpwRetVal res;
00294 
00295   // init the sball pointer to NULL by default, used to determine if we
00296   // had a healthy init later on.
00297   glwsrv->sball = NULL;
00298 
00299   switch (SiInitialize()) {
00300     case SPW_NO_ERROR:
00301       break;
00302 
00303     case SPW_DLL_LOAD_ERROR:
00304       msgInfo << "Spaceball driver not installed.  Spaceball interface disabled." << sendmsg;
00305       return;
00306 
00307     default:
00308       msgInfo << "Spaceball did not initialize properly.  Spaceball interface disabled." << sendmsg;
00309       return;
00310   }
00311 
00312   SiOpenWinInit(&oData, glwsrv->hWnd);            // init win platform data
00313   SiSetUiMode(glwsrv->sball, SI_UI_ALL_CONTROLS); // config softbutton display
00314 
00315   // actually start a connection to the device now that the UI mode
00316   // and window system data are setup.
00317   glwsrv->sball = SiOpen("VMD", SI_ANY_DEVICE, SI_NO_MASK, SI_EVENT, &oData);
00318   if ((glwsrv->sball == NULL) || (glwsrv->sball == SI_NO_HANDLE)) {
00319     SiTerminate(); // shutdown spaceware input library
00320     msgInfo << "Spaceball is unresponsive.  Spaceball interface disabled." << sendmsg;
00321     glwsrv->sball = NULL; // NULL out the handle for sure.
00322     return;
00323   }
00324 
00325   res = SiBeep(glwsrv->sball, "CcCc"); // beep the spaceball
00326   if ((glwsrv->sball != NULL) && (glwsrv->sball != SI_NO_HANDLE))
00327     msgInfo << "Spaceball found, software interface initialized." << sendmsg;
00328 }
00329 
00330 static void vmd_closewin32spaceball(wgldata *glwsrv) {
00331   enum SpwRetVal res;
00332 
00333   if (glwsrv->sball != NULL) {
00334     res = SiClose(glwsrv->sball); // close spaceball device
00335     if (res != SPW_NO_ERROR) 
00336       msgInfo << "An error occured while shutting down the Spaceball device." << sendmsg;
00337 
00338     SiTerminate();          // shutdown spaceware input library
00339   }
00340 
00341   glwsrv->sball = NULL;   // NULL out the handle.
00342 }
00343 
00344 static int vmd_processwin32spaceballevent(wgldata *glwsrv, UINT msg, WPARAM wParam, LPARAM lParam) {
00345 
00346   if (glwsrv == NULL)
00347     return 0;
00348 
00349   if (glwsrv->sball == NULL) 
00350     return 0;  // no spaceball attached/running
00351  
00352   // Check to see if this message is a spaceball message
00353   SiGetEventWinInit(&glwsrv->spwedata, msg, wParam, lParam);
00354 
00355   if (SiGetEvent(glwsrv->sball, 0, &glwsrv->spwedata, &glwsrv->spwevent) == SI_IS_EVENT) {
00356     return 1;
00357   }
00358 
00359   return 0;
00360 }
00361 #endif
00362 
00363 
00364 LRESULT WINAPI vmdWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
00365   PAINTSTRUCT   ps; /* Paint structure. */
00366 
00367   // XXX this enum has to be replicated here since its otherwise 
00368   //     private to the DisplayDevice class and children.
00369   enum EventCodes { WIN_REDRAW, WIN_LEFT, WIN_MIDDLE, WIN_RIGHT,
00370                     WIN_WHEELUP, WIN_WHEELDOWN, WIN_MOUSEX, WIN_MOUSEY, 
00371                     WIN_KBD, 
00372                     WIN_KBD_ESCAPE,
00373                     WIN_KBD_UP,
00374                     WIN_KBD_DOWN,
00375                     WIN_KBD_LEFT,
00376                     WIN_KBD_RIGHT,
00377                     WIN_KBD_PAGE_UP,
00378                     WIN_KBD_PAGE_DOWN,
00379                     WIN_KBD_HOME,
00380                     WIN_KBD_END,
00381                     WIN_KBD_INSERT,
00382                     WIN_KBD_DELETE,
00383                     WIN_KBD_F1,  WIN_KBD_F2,  WIN_KBD_F3,  WIN_KBD_F4,
00384                     WIN_KBD_F5,  WIN_KBD_F6,  WIN_KBD_F7,  WIN_KBD_F8,
00385                     WIN_KBD_F9,  WIN_KBD_F10, WIN_KBD_F11, WIN_KBD_F12,
00386                     WIN_NOEVENT };
00387   wgldata *glwsrv;
00388   OpenGLDisplayDevice * ogldispdev;
00389 
00390   // Upon first window creation, immediately set our user-data field
00391   // to store caller-provided handles for this window instance
00392   if (msg == WM_NCCREATE) {
00393 #if defined(_M_X64) || defined(_WIN64) || defined(_Wp64)
00394     SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) (((CREATESTRUCT *) lParam)->lpCreateParams));
00395 #else
00396     SetWindowLong(hwnd, GWL_USERDATA, (LONG) (((CREATESTRUCT *) lParam)->lpCreateParams));
00397 #endif
00398   }
00399 
00400   // check to make sure we have a valid window data structure in case
00401   // it is destroyed while there are still pending messages...
00402 #if defined(_M_X64) || defined(_WIN64) || defined(_Wp64)
00403   ogldispdev = (OpenGLDisplayDevice *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
00404 #else
00405   ogldispdev = (OpenGLDisplayDevice *) GetWindowLong(hwnd, GWL_USERDATA);
00406 #endif
00407 
00408   // when VMD destroys its window data structures it is possible that
00409   // the window could still get messages briefly thereafter, this prevents
00410   // us from attempting to handle any messages when the VMD state that goes
00411   // with the window has already been destructed. (most notably when using
00412   // the spaceball..)  If we have a NULL pointer, let windows handle the
00413   // event for us using the default window proc.
00414   if (ogldispdev == NULL)
00415     return DefWindowProc(hwnd, msg, wParam, lParam);
00416  
00417   glwsrv = &ogldispdev->glwsrv;
00418 
00419 #ifdef VMDSPACEWARE
00420   // see if it is a spaceball event, if so do something about it.
00421   if (vmd_processwin32spaceballevent(glwsrv, msg, wParam, lParam))
00422     return 0; //
00423 #endif
00424 
00425   switch(msg) {
00426     case WM_CREATE:
00427       glwsrv->hWnd = hwnd;
00428       glwsrv->hRC = SetupOpenGL(glwsrv);
00429       glwsrv->WEvents = WIN_REDRAW;
00430       return 0;
00431 
00432     case WM_SIZE:
00433       wglMakeCurrent(glwsrv->hDC, glwsrv->hRC);
00434       ogldispdev->xSize = LOWORD(lParam);
00435       ogldispdev->ySize = HIWORD(lParam);
00436       ogldispdev->reshape();
00437       glViewport(0, 0, (GLsizei) ogldispdev->xSize, (GLsizei) ogldispdev->ySize);
00438       glwsrv->WEvents = WIN_REDRAW;
00439       return 0;
00440 
00441     case WM_SIZING:
00442       wglMakeCurrent(glwsrv->hDC, glwsrv->hRC);
00443       glClear(GL_COLOR_BUFFER_BIT);
00444       SwapBuffers(glwsrv->hDC);
00445       glDrawBuffer(GL_BACK);
00446       return 0;
00447 
00448     case WM_CLOSE:
00449       PostQuitMessage(0);
00450       return 0;
00451 
00452     case WM_PAINT:
00453       BeginPaint(hwnd, &ps);
00454       EndPaint(hwnd, &ps);
00455       glwsrv->WEvents = WIN_REDRAW;
00456       return 0;
00457 
00458     case WM_KEYDOWN:
00459       glwsrv->KeyFlag = MapVirtualKey((UINT) wParam, 2); // map to ASCII
00460       glwsrv->WEvents = WIN_KBD;
00461       if (glwsrv->KeyFlag == 0) {
00462         unsigned int keysym = wParam;
00463         switch (keysym) {
00464           case VK_ESCAPE:    glwsrv->WEvents = WIN_KBD_ESCAPE;    break;
00465           case VK_UP:        glwsrv->WEvents = WIN_KBD_UP;        break;
00466           case VK_DOWN:      glwsrv->WEvents = WIN_KBD_DOWN;      break;
00467           case VK_LEFT:      glwsrv->WEvents = WIN_KBD_LEFT;      break;
00468           case VK_RIGHT:     glwsrv->WEvents = WIN_KBD_RIGHT;     break;
00469           case VK_PRIOR:     glwsrv->WEvents = WIN_KBD_PAGE_UP;   break;
00470           case VK_NEXT:      glwsrv->WEvents = WIN_KBD_PAGE_DOWN; break;
00471           case VK_HOME:      glwsrv->WEvents = WIN_KBD_HOME;      break;
00472           case VK_END:       glwsrv->WEvents = WIN_KBD_END;       break;
00473           case VK_INSERT:    glwsrv->WEvents = WIN_KBD_INSERT;    break;
00474           case VK_DELETE:    glwsrv->WEvents = WIN_KBD_DELETE;    break;
00475           case VK_F1:        glwsrv->WEvents = WIN_KBD_F1;        break;
00476           case VK_F2:        glwsrv->WEvents = WIN_KBD_F2;        break;
00477           case VK_F3:        glwsrv->WEvents = WIN_KBD_F3;        break;
00478           case VK_F4:        glwsrv->WEvents = WIN_KBD_F4;        break;
00479           case VK_F5:        glwsrv->WEvents = WIN_KBD_F5;        break;
00480           case VK_F6:        glwsrv->WEvents = WIN_KBD_F6;        break;
00481           case VK_F7:        glwsrv->WEvents = WIN_KBD_F7;        break;
00482           case VK_F8:        glwsrv->WEvents = WIN_KBD_F8;        break;
00483           case VK_F9:        glwsrv->WEvents = WIN_KBD_F9;        break;
00484           case VK_F10:       glwsrv->WEvents = WIN_KBD_F10;       break;
00485           case VK_F11:       glwsrv->WEvents = WIN_KBD_F11;       break;
00486           case VK_F12:       glwsrv->WEvents = WIN_KBD_F12;       break;
00487           default:
00488             glwsrv->WEvents = WIN_NOEVENT;
00489             break;
00490         }
00491       }
00492       return 0;
00493 
00494     case WM_MOUSEMOVE:
00495       vmd_transwin32mouse(ogldispdev, lParam);
00496       glwsrv->MouseFlags = (long) wParam;
00497       return 0;
00498 
00499     case WM_MOUSEWHEEL:
00500       {
00501         int zDelta = ((short) HIWORD(wParam));
00502         // XXX
00503         // zDelta is in positive or negative multiples of WHEEL_DELTA for
00504         // clicky type scroll wheels on existing mice, may need to
00505         // recode this for continuous wheels at some future point in time.
00506         // WHEEL_DELTA is 120 in current versions of Windows.
00507         // We only activate an event if the user moves the mouse wheel at
00508         // least half of WHEEL_DELTA, so that they don't do it by accident
00509         // all the time.
00510         if (zDelta > (WHEEL_DELTA / 2)) {
00511           glwsrv->WEvents = WIN_WHEELUP;
00512         } else if (zDelta < -(WHEEL_DELTA / 2)) {
00513           glwsrv->WEvents = WIN_WHEELDOWN;
00514         }
00515       }
00516       return 0;
00517 
00518     case WM_LBUTTONDOWN:
00519       SetCapture(hwnd);
00520       vmd_transwin32mouse(ogldispdev, lParam);
00521       glwsrv->MouseFlags = (long) wParam;
00522       glwsrv->WEvents = WIN_LEFT;
00523       return 0;
00524 
00525     case WM_LBUTTONUP:
00526       vmd_transwin32mouse(ogldispdev, lParam);
00527       glwsrv->MouseFlags = (long) wParam;
00528       glwsrv->WEvents = WIN_LEFT;
00529       if (!(glwsrv->MouseFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))) 
00530         ReleaseCapture();
00531       return 0;
00532 
00533     case WM_MBUTTONDOWN:
00534       SetCapture(hwnd);
00535       vmd_transwin32mouse(ogldispdev, lParam);
00536       glwsrv->MouseFlags = (long) wParam;
00537       glwsrv->WEvents = WIN_MIDDLE;
00538       return 0;
00539 
00540     case WM_MBUTTONUP:
00541       vmd_transwin32mouse(ogldispdev, lParam);
00542       glwsrv->MouseFlags = (long) wParam;
00543       glwsrv->WEvents = WIN_MIDDLE;
00544       if (!(glwsrv->MouseFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))) 
00545         ReleaseCapture();
00546       return 0;
00547 
00548     case WM_RBUTTONDOWN:
00549       SetCapture(hwnd);
00550       vmd_transwin32mouse(ogldispdev, lParam);
00551       glwsrv->MouseFlags = (long) wParam;
00552       glwsrv->WEvents = WIN_RIGHT;
00553       return 0;
00554 
00555     case WM_RBUTTONUP:
00556       vmd_transwin32mouse(ogldispdev, lParam);
00557       glwsrv->MouseFlags = (long) wParam;
00558       glwsrv->WEvents = WIN_RIGHT;
00559       if (!(glwsrv->MouseFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))) 
00560         ReleaseCapture();
00561       return 0;
00562 
00563     case WM_SETCURSOR:
00564       // We process the mouse cursor hit test codes here, they tell us
00565       // what part of the window we're over, which helps us set the cursor
00566       // to the correct style for sizing borders, moves, etc.
00567       switch (LOWORD(lParam)) {
00568         case HTBOTTOM:
00569         case HTTOP:
00570           SetCursor(LoadCursor(NULL, IDC_SIZENS));
00571           break;
00572 
00573         case HTLEFT:
00574         case HTRIGHT:
00575           SetCursor(LoadCursor(NULL, IDC_SIZEWE));
00576           break;
00577 
00578         case HTTOPRIGHT:
00579         case HTBOTTOMLEFT:
00580           SetCursor(LoadCursor(NULL, IDC_SIZENESW));
00581           break;
00582 
00583         case HTTOPLEFT:
00584         case HTBOTTOMRIGHT:
00585           SetCursor(LoadCursor(NULL, IDC_SIZENWSE));
00586           break;
00587 
00588         case HTCAPTION:
00589           SetCursor(LoadCursor(NULL, IDC_ARROW));
00590           break;
00591           
00592         case HTCLIENT:
00593         default:
00594           ogldispdev->set_cursor(glwsrv->cursornum);
00595       }
00596       return 0;
00597 
00598     // 
00599     // Handle Windows File Drag and Drop Operations  
00600     // This code needs to be linked against SHELL32.DLL
00601     // 
00602     case WM_DROPFILES: 
00603       {
00604         char lpszFile[4096];
00605         UINT numfiles, fileindex, numc;
00606         HDROP hDropInfo = (HDROP)wParam;
00607         
00608         // Get the number of simultaneous dragged/dropped files.
00609         numfiles = DragQueryFile(hDropInfo, (DWORD)(-1), (LPSTR)NULL, 0);
00610   
00611         msgInfo << "Ignoring Drag and Drop operation, received " 
00612                 << ((int) numfiles) << " files:" << sendmsg;
00613 
00614         FileSpec spec;       
00615         for (fileindex=0; fileindex<numfiles; fileindex++) {
00616           // lpszFile: complete pathname with device, colon and backslashes
00617           numc = DragQueryFile(hDropInfo, fileindex, (char *) &lpszFile, 4096);
00618   
00619           // VMD loads the file(s) here, or queues them up in its own
00620           // list to decide how to cope with them.  Deciding how to deal
00621           // with these files is definitely the tricky part.
00622           msgInfo << "  File(" << ((int) fileindex) << "): " << lpszFile 
00623                   << " (numc=" << ((int) numc) << ")" << sendmsg;
00624 
00625           // attempt to load the file into a new molecule
00626           ogldispdev->vmdapp->molecule_load(-1, lpszFile, NULL, &spec);
00627         }  
00628         DragFinish(hDropInfo); // finish drop operation and release memory
00629       }
00630       return 0;
00631 
00632     default:
00633       return DefWindowProc(hwnd, msg, wParam, lParam);
00634   }
00635 
00636   return 0;
00637 }
00638 
00639 
00641 
00642 OpenGLDisplayDevice::OpenGLDisplayDevice() 
00643 : OpenGLRenderer("VMD " VMDVERSION " OpenGL Display") {
00644   // set up data possible before opening window
00645   stereoNames = glStereoNameStr;
00646   stereoModes = OPENGL_STEREO_MODES;
00647 
00648   renderNames = glRenderNameStr;
00649   renderModes = OPENGL_RENDER_MODES;
00650 
00651   cacheNames = glCacheNameStr;
00652   cacheModes = OPENGL_CACHE_MODES;
00653 
00654   memset(&glwsrv, 0, sizeof(glwsrv));
00655   have_window = FALSE;
00656   screenX = screenY = 0;
00657   vmdapp = NULL;
00658 }
00659 
00660 // init ... open a window and set initial default values
00661 int OpenGLDisplayDevice::init(int argc, char **argv, VMDApp *app, int *size, int *loc) {
00662   vmdapp = app; // save VMDApp handle for use by drag-and-drop handlers
00663 
00664   // open the window
00665   if (open_window(name, size, loc, argc, argv) != 0) return FALSE;
00666   if (!have_window) return FALSE;
00667 
00668   // get screen size 
00669   // XXX There's no Win32 API to get the full multi-monitor desktop,
00670   //     so this code doesn't correctly handle multi-monitor systems yet.
00671   //     To correctly handle multiple monitors, we'd have to 
00672   //     walk the device tree, take into account monitor layout/positioning, 
00673   //     and compute the desktop dimensions from that.  Since these values
00674   //     are currently only used by do_reposition_window() method, we can
00675   //     live with primary-monitor values for the time being.
00676   screenX = GetSystemMetrics(SM_CXSCREEN);
00677   screenY = GetSystemMetrics(SM_CYSCREEN);
00678 
00679   // set flags for the capabilities of this display
00680   ext->hasmultisample = FALSE;      // no code for this extension yet
00681   ext->nummultisamples = 0;
00682   aaAvailable = FALSE;
00683 
00684   // set default settings
00685   if (ext->hasmultisample) {
00686     aa_on();  // enable fast multisample based antialiasing by default
00687               // other antialiasing techniques are slow, so only multisample
00688               // makes sense to enable by default.
00689   }
00690 
00691   cueingAvailable = TRUE;
00692   cueing_on(); // leave depth cueing on by default, despite the speed hit.
00693 
00694   cullingAvailable = TRUE;
00695   culling_off();
00696 
00697   set_sphere_mode(sphereMode);
00698   set_sphere_res(sphereRes);
00699   set_line_width(lineWidth);
00700   set_line_style(lineStyle);
00701 
00702   // reshape and clear the display, which initializes some other variables
00703   reshape();
00704   normal();
00705   clear();
00706   update();
00707 
00708   // successfully created window
00709   return TRUE;
00710 }
00711 
00712 // destructor ... close the window
00713 OpenGLDisplayDevice::~OpenGLDisplayDevice(void) {
00714   if (have_window) {
00715     // close and delete windows, contexts, and display connections
00716     free_opengl_ctx(); // free display lists, textures, etc
00717 
00718 #if VMDSPACEWARE
00719     vmd_closewin32spaceball(&glwsrv);
00720 #endif
00721   }
00722 }
00723 
00724 
00726 
00727 // create a new window and set it's characteristics
00728 int OpenGLDisplayDevice::open_window(char *nm, int *size, int *loc,
00729                                      int argc, char** argv) {
00730   int SX = 596, SY = 190;
00731   if (loc) {
00732     SX = loc[0];
00733     // X screen uses Y increasing from upper-left corner down; this is
00734     // opposite to what GL does, which is the way VMD was set up originally
00735     SY = screenY - loc[1] - size[1];
00736   }
00737   glwsrv.cursornum = 0; // initialize cursor number
00738   
00739   // window opening stuff goes here
00740   int rc = OpenWin32Connection(&glwsrv);
00741   if (rc != 0) {
00742     return -1;
00743   }
00744 
00745   xOrig = 0;
00746   yOrig = 0;
00747   xSize = size[0]; 
00748   ySize = size[1]; 
00749   glwsrv.width = xSize; 
00750   glwsrv.height = ySize; 
00751   rc = myCreateWindow(this, 0, 0, glwsrv.width, glwsrv.height);
00752   if (rc != 0) {
00753     return -1;
00754   }
00755 
00756   // Determine if stereo is available
00757   if (glwsrv.PFDisStereo == 0) {
00758     ext->hasstereo = FALSE;
00759   } else {
00760     ext->hasstereo = TRUE;
00761   }
00762   ext->stereodrawforced = FALSE; // don't force stereo draws initially
00763   
00764   setup_initial_opengl_state();
00765 
00766 #ifdef VMDSPACEWARE
00767   vmd_setupwin32spaceball(&glwsrv); 
00768 #endif
00769 
00770   // normal return: window was successfully created
00771   have_window = TRUE;
00772   // return window id
00773   return 0;
00774 }
00775 
00776 void OpenGLDisplayDevice::do_resize_window(int width, int height) {
00777   RECT rcClient, rcWindow;
00778   POINT ptDiff;
00779   GetClientRect(glwsrv.hWnd, &rcClient);
00780   GetWindowRect(glwsrv.hWnd, &rcWindow);
00781   ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
00782   ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
00783   MoveWindow(glwsrv.hWnd, rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, TRUE);
00784 }
00785 
00786 void OpenGLDisplayDevice::do_reposition_window(int xpos, int ypos) {
00787   RECT rcClient, rcWindow;
00788   GetClientRect(glwsrv.hWnd, &rcClient);
00789   GetWindowRect(glwsrv.hWnd, &rcWindow);
00790   MoveWindow(glwsrv.hWnd, xpos, ypos, rcWindow.right-rcWindow.left, rcWindow.bottom-rcWindow.top, TRUE);
00791 }
00792 
00793 
00795 
00796 //
00797 // get the current state of the device's pointer (i.e. cursor if it has one)
00798 //
00799 
00800 // abs X pos of cursor from lower-left corner of display
00801 int OpenGLDisplayDevice::x(void) {
00802   return glwsrv.MouseX;
00803 }
00804 
00805 // same, for Y direction
00806 int OpenGLDisplayDevice::y(void) {
00807   return glwsrv.MouseY;
00808 }
00809 
00810 // return the current state of the shift, control, and alt keys
00811 int OpenGLDisplayDevice::shift_state(void) {
00812   int retval = 0;
00813 
00814   if ((glwsrv.MouseFlags & MK_SHIFT) != 0)
00815     retval |= SHIFT;
00816   
00817   if ((glwsrv.MouseFlags & MK_CONTROL) != 0)
00818     retval |= CONTROL;
00819 
00820   return retval; 
00821 }
00822 
00823 // return the spaceball state, if any
00824 int OpenGLDisplayDevice::spaceball(int *rx, int *ry, int *rz, int *tx, int *ty, int *tz, int *buttons) {
00825 
00826 #ifdef VMDSPACEWARE
00827   if (glwsrv.sball != NULL) {
00828     *rx = glwsrv.spwevent.u.spwData.mData[SI_RX];
00829     *ry = glwsrv.spwevent.u.spwData.mData[SI_RY];
00830     *rz = glwsrv.spwevent.u.spwData.mData[SI_RZ];
00831     *tx = glwsrv.spwevent.u.spwData.mData[SI_TX];
00832     *ty = glwsrv.spwevent.u.spwData.mData[SI_TY];
00833     *tz = glwsrv.spwevent.u.spwData.mData[SI_TZ];
00834     *buttons = glwsrv.spwevent.u.spwData.bData.current;
00835     return 1;
00836   }
00837 #endif
00838 
00839   return 0;
00840 }
00841 
00842 
00843 // set the Nth cursor shape as the current one.
00844 void OpenGLDisplayDevice::set_cursor(int n) {
00845   glwsrv.cursornum = n; // hack to save cursor state when mouse enters/leaves
00846 
00847   switch (n) {
00848     default:
00849     case DisplayDevice::NORMAL_CURSOR:
00850       SetCursor(LoadCursor(NULL, IDC_ARROW));
00851       break;
00852 
00853     case DisplayDevice::TRANS_CURSOR:
00854       SetCursor(LoadCursor(NULL, IDC_SIZEALL));
00855       break;
00856  
00857     case DisplayDevice::SCALE_CURSOR:
00858       SetCursor(LoadCursor(NULL, IDC_SIZEWE));
00859       break;
00860 
00861     case DisplayDevice::PICK_CURSOR:
00862       SetCursor(LoadCursor(NULL, IDC_CROSS));
00863       break;
00864 
00865     case DisplayDevice::WAIT_CURSOR:
00866       SetCursor(LoadCursor(NULL, IDC_WAIT));
00867       break;
00868   }
00869 }
00870 
00871 
00872 //
00873 // event handling routines
00874 //
00875 
00876 // queue the standard events (need only be called once ... but this is
00877 // not done automatically by the window because it may not be necessary or
00878 // even wanted)
00879 void OpenGLDisplayDevice::queue_events(void) {
00880 }
00881 
00882 // read the next event ... returns an event type (one of the above ones),
00883 // and a value.  Returns success, and sets arguments.
00884 int OpenGLDisplayDevice::read_event(long &retdev, long &retval) {
00885   MSG msg;
00886 
00887   // This pumps the Windows message queue, forcing WEvents to be updated
00888   // by the time we return from DispatchMessage.
00889   if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
00890     TranslateMessage(&msg); // translate the message
00891     DispatchMessage(&msg);  // fire it off to the window proc
00892   } 
00893 
00894   retdev = glwsrv.WEvents;
00895 
00896   switch (glwsrv.WEvents) {
00897     case WIN_REDRAW:
00898       glwsrv.WEvents = WIN_NOEVENT;
00899       // reshape() is already called from within the window proc.
00900       _needRedraw = 1;
00901       return FALSE;
00902 
00903     case WIN_KBD:
00904       if (glwsrv.KeyFlag != '\0') {
00905         retval = glwsrv.KeyFlag;
00906         glwsrv.WEvents = WIN_NOEVENT;
00907         return TRUE;
00908       }
00909       break; 
00910 
00911     case WIN_KBD_ESCAPE:
00912     case WIN_KBD_UP:
00913     case WIN_KBD_DOWN:
00914     case WIN_KBD_LEFT:
00915     case WIN_KBD_RIGHT:
00916     case WIN_KBD_PAGE_UP:
00917     case WIN_KBD_PAGE_DOWN:
00918     case WIN_KBD_HOME:
00919     case WIN_KBD_END:
00920     case WIN_KBD_INSERT:
00921     case WIN_KBD_DELETE:
00922     case WIN_KBD_F1:
00923     case WIN_KBD_F2:
00924     case WIN_KBD_F3:
00925     case WIN_KBD_F4:
00926     case WIN_KBD_F5:
00927     case WIN_KBD_F6:
00928     case WIN_KBD_F7:
00929     case WIN_KBD_F8:
00930     case WIN_KBD_F9:
00931     case WIN_KBD_F10:
00932     case WIN_KBD_F11:
00933     case WIN_KBD_F12:
00934       retval = glwsrv.KeyFlag;
00935       glwsrv.WEvents = WIN_NOEVENT;
00936       return TRUE;
00937 
00938     case WIN_WHEELUP:
00939       retval = 1;
00940       glwsrv.WEvents = WIN_NOEVENT;
00941       return TRUE;
00942 
00943     case WIN_WHEELDOWN:
00944       retval = 1;
00945       glwsrv.WEvents = WIN_NOEVENT;
00946       return TRUE;
00947   
00948     case WIN_LEFT:
00949       // retval _must_ be either 1 or 0, nothing else...
00950       retval = (glwsrv.MouseFlags & MK_LBUTTON) != 0; 
00951       glwsrv.WEvents = WIN_NOEVENT;
00952       return TRUE;
00953 
00954     case WIN_MIDDLE:
00955       // retval _must_ be either 1 or 0, nothing else...
00956       retval = (glwsrv.MouseFlags & MK_MBUTTON) != 0; 
00957       glwsrv.WEvents = WIN_NOEVENT;
00958       return TRUE;
00959 
00960     case WIN_RIGHT:
00961       // retval _must_ be either 1 or 0, nothing else...
00962       retval = (glwsrv.MouseFlags & MK_RBUTTON) != 0; 
00963       glwsrv.WEvents = WIN_NOEVENT;
00964       return TRUE;
00965   }
00966 
00967   retval = 0; 
00968   glwsrv.WEvents = WIN_NOEVENT;
00969   return FALSE;
00970 }
00971 
00972 
00973 //
00974 // virtual routines for preparing to draw, drawing, and finishing drawing
00975 //
00976 
00977 // reshape the display after a shape change
00978 void OpenGLDisplayDevice::reshape(void) {
00979   // this code assumes that the xSize and ySize variables have
00980   // been updated (magically) already by the time this gets called.
00981 
00982   switch (inStereo) {
00983     case OPENGL_STEREO_SIDE:
00984       set_screen_pos(0.5f * (float)xSize / (float)ySize);
00985       break;
00986 
00987     case OPENGL_STEREO_ABOVEBELOW:
00988       set_screen_pos(2.0f * (float)xSize / (float)ySize);
00989       break;
00990 
00991     case OPENGL_STEREO_STENCIL_CHECKERBOARD:
00992     case OPENGL_STEREO_STENCIL_COLUMNS:
00993     case OPENGL_STEREO_STENCIL_ROWS:
00994       enable_stencil_stereo(inStereo);
00995       set_screen_pos((float)xSize / (float)ySize);
00996       break;
00997  
00998     default:
00999       set_screen_pos((float)xSize / (float)ySize);
01000       break;
01001   }
01002 }
01003 
01004 unsigned char * OpenGLDisplayDevice::readpixels(int &x, int &y) {
01005   unsigned char * img;
01006 
01007   x = xSize;
01008   y = ySize;
01009 
01010   if ((img = (unsigned char *) malloc(x * y * 3)) != NULL) {
01011     glPixelStorei(GL_PACK_ALIGNMENT, 1);
01012     glReadPixels(0, 0, x, y, GL_RGB, GL_UNSIGNED_BYTE, img);
01013   } else {
01014     x = 0;
01015     y = 0;
01016   } 
01017 
01018   return img; 
01019 }
01020 
01021 
01022 // update after drawing
01023 void OpenGLDisplayDevice::update(int do_update) {
01024   glFlush();
01025 
01026   if(do_update) 
01027     SwapBuffers(glwsrv.hDC);
01028 
01029   glDrawBuffer(GL_BACK);
01030 }
01031 
01032 

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