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

Win32OpenGLDisplayDevice.C

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

Generated on Wed Apr 17 02:46:55 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002