Blender V2.61 - r43446

GHOST_WindowWin32.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00040 #include <string.h>
00041 #include "GHOST_WindowWin32.h"
00042 #include "GHOST_SystemWin32.h"
00043 #include "GHOST_DropTargetWin32.h"
00044 
00045 // Need glew for some defines
00046 #include <GL/glew.h>
00047 #include <GL/wglew.h>
00048 #include <math.h>
00049 
00050 // MSVC6 still doesn't define M_PI
00051 #ifndef M_PI
00052 #define M_PI 3.1415926536
00053 #endif
00054 
00055 // Some more multisample defines
00056 #define WGL_SAMPLE_BUFERS_ARB   0x2041
00057 #define WGL_SAMPLES_ARB         0x2042
00058 
00059 // win64 doesn't define GWL_USERDATA
00060 #ifdef WIN32
00061 #ifndef GWL_USERDATA
00062 #define GWL_USERDATA GWLP_USERDATA
00063 #define GWL_WNDPROC GWLP_WNDPROC
00064 #endif
00065 #endif
00066 
00067 LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass";
00068 const int GHOST_WindowWin32::s_maxTitleLength = 128;
00069 HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL;
00070 HDC GHOST_WindowWin32::s_firstHDC = NULL;
00071 
00072 static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd);
00073 static int EnumPixelFormats(HDC hdc);
00074 
00075 /*
00076  * Color and depth bit values are not to be trusted.
00077  * For instance, on TNT2:
00078  * When the screen color depth is set to 16 bit, we get 5 color bits
00079  * and 16 depth bits.
00080  * When the screen color depth is set to 32 bit, we get 8 color bits
00081  * and 24 depth bits.
00082  * Just to be safe, we request high waulity settings.
00083  */
00084 static PIXELFORMATDESCRIPTOR sPreferredFormat = {
00085     sizeof(PIXELFORMATDESCRIPTOR),  /* size */
00086     1,                              /* version */
00087     PFD_SUPPORT_OPENGL |
00088     PFD_DRAW_TO_WINDOW |
00089     PFD_SWAP_COPY |                 /* support swap copy */
00090     PFD_DOUBLEBUFFER,               /* support double-buffering */
00091     PFD_TYPE_RGBA,                  /* color type */
00092     32,                             /* prefered color depth */
00093     0, 0, 0, 0, 0, 0,               /* color bits (ignored) */
00094     0,                              /* no alpha buffer */
00095     0,                              /* alpha bits (ignored) */
00096     0,                              /* no accumulation buffer */
00097     0, 0, 0, 0,                     /* accum bits (ignored) */
00098     32,                             /* depth buffer */
00099     0,                              /* no stencil buffer */
00100     0,                              /* no auxiliary buffers */
00101     PFD_MAIN_PLANE,                 /* main layer */
00102     0,                              /* reserved */
00103     0, 0, 0                         /* no layer, visible, damage masks */
00104 };
00105 
00106 /* Intel videocards don't work fine with multiple contexts and
00107    have to share the same context for all windows.
00108    But if we just share context for all windows it could work incorrect
00109    with multiple videocards configuration. Suppose, that Intel videocards
00110    can't be in multiple-devices configuration. */
00111 static int is_crappy_intel_card(void)
00112 {
00113     int crappy = 0;
00114     const char *vendor = (const char*)glGetString(GL_VENDOR);
00115 
00116     if (strstr(vendor, "Intel"))
00117         crappy = 1;
00118 
00119     return crappy;
00120 }
00121 
00122 GHOST_WindowWin32::GHOST_WindowWin32(
00123     GHOST_SystemWin32 * system,
00124     const STR_String& title,
00125     GHOST_TInt32 left,
00126     GHOST_TInt32 top,
00127     GHOST_TUns32 width,
00128     GHOST_TUns32 height,
00129     GHOST_TWindowState state,
00130     GHOST_TDrawingContextType type,
00131     const bool stereoVisual,
00132     const GHOST_TUns16 numOfAASamples,
00133     GHOST_TEmbedderWindowID parentwindowhwnd,
00134     GHOST_TSuccess msEnabled,
00135     int msPixelFormat)
00136 :
00137     GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone,
00138     stereoVisual,numOfAASamples),
00139     m_system(system),
00140     m_hDC(0),
00141     m_hGlRc(0),
00142     m_hasMouseCaptured(false),
00143     m_hasGrabMouse(false),
00144     m_nPressedButtons(0),
00145     m_customCursor(0),
00146     m_wintab(NULL),
00147     m_tabletData(NULL),
00148     m_tablet(0),
00149     m_maxPressure(0),
00150     m_multisample(numOfAASamples),
00151     m_parentWindowHwnd(parentwindowhwnd),
00152     m_multisampleEnabled(msEnabled),
00153     m_msPixelFormat(msPixelFormat),
00154     //For recreation
00155     m_title(title),
00156     m_left(left),
00157     m_top(top),
00158     m_width(width),
00159     m_height(height),
00160     m_normal_state(GHOST_kWindowStateNormal),
00161     m_stereo(stereoVisual),
00162     m_nextWindow(NULL)
00163 {
00164     OSVERSIONINFOEX versionInfo;
00165     bool hasMinVersionForTaskbar = false;
00166     
00167     ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
00168     
00169     versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
00170     
00171     if(!GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
00172         versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
00173         if(GetVersionEx((OSVERSIONINFO*)&versionInfo)) {
00174             if((versionInfo.dwMajorVersion==6 && versionInfo.dwMinorVersion>=1) || versionInfo.dwMajorVersion >= 7) {
00175                 hasMinVersionForTaskbar = true;
00176             }
00177         }
00178     } else {
00179         if((versionInfo.dwMajorVersion==6 && versionInfo.dwMinorVersion>=1) || versionInfo.dwMajorVersion >= 7) {
00180             hasMinVersionForTaskbar = true;
00181         }
00182     }
00183 
00184     if (state != GHOST_kWindowStateFullScreen) {
00185         RECT rect;
00186         MONITORINFO monitor;
00187         GHOST_TUns32 tw, th; 
00188 
00189         width += GetSystemMetrics(SM_CXSIZEFRAME)*2;
00190         height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION);
00191 
00192         rect.left = left;
00193         rect.right = left + width;
00194         rect.top = top;
00195         rect.bottom = top + height;
00196 
00197         monitor.cbSize=sizeof(monitor);
00198         monitor.dwFlags=0;
00199 
00200         // take taskbar into account
00201         GetMonitorInfo(MonitorFromRect(&rect,MONITOR_DEFAULTTONEAREST),&monitor);
00202 
00203         th = monitor.rcWork.bottom - monitor.rcWork.top;
00204         tw = monitor.rcWork.right - monitor.rcWork.left;
00205 
00206         if(tw < width)
00207         {
00208             width = tw;
00209             left = monitor.rcWork.left;
00210         }
00211         else if(monitor.rcWork.right < left + (int)width)
00212             left = monitor.rcWork.right - width;
00213         else if(left < monitor.rcWork.left)
00214             left = monitor.rcWork.left;
00215 
00216         if(th < height)
00217         {
00218             height = th;
00219             top = monitor.rcWork.top;
00220         }
00221         else if(monitor.rcWork.bottom < top + (int)height)
00222             top = monitor.rcWork.bottom - height;
00223         else if(top < monitor.rcWork.top)
00224             top = monitor.rcWork.top;
00225 
00226         int wintype = WS_OVERLAPPEDWINDOW;
00227         if (m_parentWindowHwnd != 0)
00228         {
00229             wintype = WS_CHILD;
00230             GetWindowRect((HWND)m_parentWindowHwnd, &rect);
00231             left = 0;
00232             top = 0;
00233             width = rect.right - rect.left;
00234             height = rect.bottom - rect.top;
00235         }
00236         
00237         m_hWnd = ::CreateWindow(
00238             s_windowClassName,          // pointer to registered class name
00239             title,                      // pointer to window name
00240             wintype,                    // window style
00241             left,                   // horizontal position of window
00242             top,                    // vertical position of window
00243             width,                      // window width
00244             height,                     // window height
00245             (HWND) m_parentWindowHwnd,  // handle to parent or owner window
00246             0,                          // handle to menu or child-window identifier
00247             ::GetModuleHandle(0),       // handle to application instance
00248             0);                         // pointer to window-creation data
00249     }
00250     else {
00251         m_hWnd = ::CreateWindow(
00252             s_windowClassName,          // pointer to registered class name
00253             title,                      // pointer to window name
00254             WS_POPUP | WS_MAXIMIZE,     // window style
00255             left,                       // horizontal position of window
00256             top,                        // vertical position of window
00257             width,                      // window width
00258             height,                     // window height
00259             HWND_DESKTOP,               // handle to parent or owner window
00260             0,                          // handle to menu or child-window identifier
00261             ::GetModuleHandle(0),       // handle to application instance
00262             0);                         // pointer to window-creation data
00263     }
00264     if (m_hWnd) {
00265         // Register this window as a droptarget. Requires m_hWnd to be valid.
00266         // Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32.
00267         m_dropTarget = new GHOST_DropTargetWin32(this, m_system);
00268         // Store a pointer to this class in the window structure
00269         ::SetWindowLongPtr(m_hWnd, GWL_USERDATA, (LONG_PTR)this);
00270 
00271         // Store the device context
00272         m_hDC = ::GetDC(m_hWnd);
00273 
00274         if(!s_firstHDC) {
00275             s_firstHDC = m_hDC;
00276         }
00277 
00278         // Show the window
00279         int nCmdShow;
00280         switch (state) {
00281             case GHOST_kWindowStateMaximized:
00282                 nCmdShow = SW_SHOWMAXIMIZED;
00283                 break;
00284             case GHOST_kWindowStateMinimized:
00285                 nCmdShow = SW_SHOWMINIMIZED;
00286                 break;
00287             case GHOST_kWindowStateNormal:
00288             default:
00289                 nCmdShow = SW_SHOWNORMAL;
00290                 break;
00291         }
00292         GHOST_TSuccess success;
00293         success = setDrawingContextType(type);
00294 
00295         if (success)
00296         {
00297             ::ShowWindow(m_hWnd, nCmdShow);
00298             // Force an initial paint of the window
00299             ::UpdateWindow(m_hWnd);
00300         }
00301         else
00302         {
00303             //invalidate the window
00304             m_hWnd = 0;
00305         }
00306     }
00307 
00308     if (parentwindowhwnd != 0) {
00309         RAWINPUTDEVICE device = {0};
00310         device.usUsagePage  = 0x01; /* usUsagePage & usUsage for keyboard*/
00311         device.usUsage      = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
00312         device.dwFlags |= RIDEV_INPUTSINK; // makes WM_INPUT is visible for ghost when has parent window
00313         device.hwndTarget = m_hWnd;
00314         RegisterRawInputDevices(&device, 1, sizeof(device));
00315     }
00316 
00317     m_wintab = ::LoadLibrary("Wintab32.dll");
00318     if (m_wintab) {
00319         GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
00320         GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" );
00321 
00322         // let's see if we can initialize tablet here
00323         /* check if WinTab available. */
00324         if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
00325             // Now init the tablet
00326             LOGCONTEXT lc;
00327             AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */
00328 
00329             // Open a Wintab context
00330 
00331             // Get default context information
00332             fpWTInfo( WTI_DEFCONTEXT, 0, &lc );
00333 
00334             // Open the context
00335             lc.lcPktData = PACKETDATA;
00336             lc.lcPktMode = PACKETMODE;
00337             lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
00338 
00339             /* Set the entire tablet as active */
00340             fpWTInfo(WTI_DEVICES,DVC_X,&TabletX);
00341             fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY);
00342 
00343             /* get the max pressure, to divide into a float */
00344             BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
00345             if (pressureSupport)
00346                 m_maxPressure = Pressure.axMax;
00347             else
00348                 m_maxPressure = 0;
00349 
00350             /* get the max tilt axes, to divide into floats */
00351             BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
00352             if (tiltSupport) {
00353                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
00354                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
00355                     /* all this assumes the minimum is 0 */
00356                     m_maxAzimuth = Orientation[0].axMax;
00357                     m_maxAltitude = Orientation[1].axMax;
00358                 }
00359                 else {  /* no so dont do tilt stuff */
00360                     m_maxAzimuth = m_maxAltitude = 0;
00361                 }
00362             }
00363 
00364             if (fpWTOpen) {
00365                 m_tablet = fpWTOpen( m_hWnd, &lc, TRUE );
00366                 if (m_tablet) {
00367                     m_tabletData = new GHOST_TabletData();
00368                     m_tabletData->Active = GHOST_kTabletModeNone;
00369                 }
00370             }
00371         }
00372     }
00373 
00374     if(hasMinVersionForTaskbar)
00375         CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList ,(LPVOID*)&m_Bar);
00376     else
00377         m_Bar=NULL;
00378 }
00379 
00380 
00381 GHOST_WindowWin32::~GHOST_WindowWin32()
00382 {
00383     if(m_Bar)
00384     {
00385         m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
00386         m_Bar->Release();
00387     };
00388 
00389     if (m_wintab) {
00390         GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" );
00391         if (fpWTClose) {
00392             if (m_tablet)
00393                 fpWTClose(m_tablet);
00394             if (m_tabletData)
00395                 delete m_tabletData;
00396                 m_tabletData = NULL;
00397         }
00398     }
00399     if (m_customCursor) {
00400         DestroyCursor(m_customCursor);
00401         m_customCursor = NULL;
00402     }
00403 
00404     ::wglMakeCurrent(NULL, NULL);
00405     m_multisampleEnabled = GHOST_kFailure;
00406     m_multisample = 0;
00407     setDrawingContextType(GHOST_kDrawingContextTypeNone);
00408     if (m_hDC && m_hDC != s_firstHDC) {
00409         ::ReleaseDC(m_hWnd, m_hDC);
00410         m_hDC = 0;
00411     }
00412     if (m_hWnd) {
00413         m_dropTarget->Release(); // frees itself.
00414         ::DestroyWindow(m_hWnd);
00415         m_hWnd = 0;
00416     }
00417 }
00418 
00419 GHOST_Window *GHOST_WindowWin32::getNextWindow()
00420 {
00421     return m_nextWindow;
00422 }
00423 
00424 bool GHOST_WindowWin32::getValid() const
00425 {
00426     return m_hWnd != 0;
00427 }
00428 
00429 HWND GHOST_WindowWin32::getHWND() const
00430 {
00431     return m_hWnd;
00432 }
00433 
00434 void GHOST_WindowWin32::setTitle(const STR_String& title)
00435 {
00436     ::SetWindowText(m_hWnd, title);
00437 }
00438 
00439 
00440 void GHOST_WindowWin32::getTitle(STR_String& title) const
00441 {
00442     char buf[s_maxTitleLength];
00443     ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
00444     STR_String temp (buf);
00445     title = buf;
00446 }
00447 
00448 
00449 void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const
00450 {
00451     RECT rect;
00452     ::GetWindowRect(m_hWnd, &rect);
00453     bounds.m_b = rect.bottom;
00454     bounds.m_l = rect.left;
00455     bounds.m_r = rect.right;
00456     bounds.m_t = rect.top;
00457 }
00458 
00459 
00460 void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
00461 {
00462     RECT rect;
00463     GHOST_TWindowState state= this->getState();
00464     LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
00465     int sm_cysizeframe = GetSystemMetrics(SM_CYSIZEFRAME);
00466     ::GetWindowRect(m_hWnd, &rect);
00467 
00468     if((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE)) {
00469         if(state==GHOST_kWindowStateMaximized) {
00470             // in maximized state we don't have borders on the window
00471             bounds.m_b = rect.bottom-GetSystemMetrics(SM_CYCAPTION)- sm_cysizeframe*2;
00472             bounds.m_l = rect.left + sm_cysizeframe;
00473             bounds.m_r = rect.right - sm_cysizeframe;
00474             bounds.m_t = rect.top;
00475         } else if (state == GHOST_kWindowStateEmbedded) {
00476             bounds.m_b = rect.bottom;
00477             bounds.m_l = rect.left;
00478             bounds.m_r = rect.right;
00479             bounds.m_t = rect.top;
00480         } else {
00481             bounds.m_b = rect.bottom-GetSystemMetrics(SM_CYCAPTION)-sm_cysizeframe*2;
00482             bounds.m_l = rect.left;
00483             bounds.m_r = rect.right-sm_cysizeframe*2;
00484             bounds.m_t = rect.top;
00485         }
00486     } else {
00487         bounds.m_b = rect.bottom;
00488         bounds.m_l = rect.left;
00489         bounds.m_r = rect.right;
00490         bounds.m_t = rect.top;
00491     }
00492 }
00493 
00494 
00495 GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
00496 {
00497     GHOST_TSuccess success;
00498     GHOST_Rect cBnds, wBnds;
00499     getClientBounds(cBnds);
00500     if (cBnds.getWidth() != (GHOST_TInt32)width) {
00501         getWindowBounds(wBnds);
00502         int cx = wBnds.getWidth() + width - cBnds.getWidth();
00503         int cy = wBnds.getHeight();
00504         success =  ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
00505             GHOST_kSuccess : GHOST_kFailure;
00506     }
00507     else {
00508         success = GHOST_kSuccess;
00509     }
00510     return success;
00511 }
00512 
00513 
00514 GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
00515 {
00516     GHOST_TSuccess success;
00517     GHOST_Rect cBnds, wBnds;
00518     getClientBounds(cBnds);
00519     if (cBnds.getHeight() != (GHOST_TInt32)height) {
00520         getWindowBounds(wBnds);
00521         int cx = wBnds.getWidth();
00522         int cy = wBnds.getHeight() + height - cBnds.getHeight();
00523         success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
00524             GHOST_kSuccess : GHOST_kFailure;
00525     }
00526     else {
00527         success = GHOST_kSuccess;
00528     }
00529     return success;
00530 }
00531 
00532 
00533 GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
00534 {
00535     GHOST_TSuccess success;
00536     GHOST_Rect cBnds, wBnds;
00537     getClientBounds(cBnds);
00538     if ((cBnds.getWidth() != (GHOST_TInt32)width) || (cBnds.getHeight() != (GHOST_TInt32)height)) {
00539         getWindowBounds(wBnds);
00540         int cx = wBnds.getWidth() + width - cBnds.getWidth();
00541         int cy = wBnds.getHeight() + height - cBnds.getHeight();
00542         success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
00543             GHOST_kSuccess : GHOST_kFailure;
00544     }
00545     else {
00546         success = GHOST_kSuccess;
00547     }
00548     return success;
00549 }
00550 
00551 
00552 GHOST_TWindowState GHOST_WindowWin32::getState() const
00553 {
00554     GHOST_TWindowState state;
00555 
00556     // XXX 27.04.2011
00557     // we need to find a way to combine parented windows + resizing if we simply set the
00558     // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else.
00559     // It's also strange that in Windows is the only platform we need to make this separation.
00560     if (m_parentWindowHwnd != 0) {
00561         state = GHOST_kWindowStateEmbedded;
00562         return state;
00563     }
00564     if (::IsIconic(m_hWnd)) {
00565         state = GHOST_kWindowStateMinimized;
00566     }
00567     else if (::IsZoomed(m_hWnd)) {
00568         LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
00569         if((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE))
00570             state = GHOST_kWindowStateMaximized;
00571         else
00572             state = GHOST_kWindowStateFullScreen;
00573     }
00574     else {
00575         state = GHOST_kWindowStateNormal;
00576     }
00577     return state;
00578 }
00579 
00580 
00581 void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
00582 {
00583     POINT point = { inX, inY };
00584     ::ScreenToClient(m_hWnd, &point);
00585     outX = point.x;
00586     outY = point.y;
00587 }
00588 
00589 
00590 void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
00591 {
00592     POINT point = { inX, inY };
00593     ::ClientToScreen(m_hWnd, &point);
00594     outX = point.x;
00595     outY = point.y;
00596 }
00597 
00598 
00599 GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
00600 {
00601     GHOST_TWindowState curstate = getState();
00602     WINDOWPLACEMENT wp;
00603     wp.length = sizeof(WINDOWPLACEMENT);
00604     ::GetWindowPlacement(m_hWnd, &wp);
00605 
00606     if (state == GHOST_kWindowStateNormal)
00607         state = m_normal_state;
00608     switch (state) {
00609     case GHOST_kWindowStateMinimized:
00610         wp.showCmd = SW_SHOWMINIMIZED;
00611         break;
00612     case GHOST_kWindowStateMaximized:
00613         wp.showCmd = SW_SHOWMAXIMIZED;
00614         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
00615         break;
00616     case GHOST_kWindowStateFullScreen:
00617         if (curstate != state && curstate != GHOST_kWindowStateMinimized)
00618             m_normal_state = curstate;
00619         wp.showCmd = SW_SHOWMAXIMIZED;
00620         wp.ptMaxPosition.x = 0;
00621         wp.ptMaxPosition.y = 0;
00622         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
00623         break;
00624     case GHOST_kWindowStateEmbedded:
00625         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD);
00626         break;
00627     case GHOST_kWindowStateNormal:
00628     default:
00629         wp.showCmd = SW_SHOWNORMAL;
00630         SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
00631         break;
00632     }
00633     SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); /*Clears window cache for SetWindowLongPtr */
00634     return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00635 }
00636 
00637 
00638 GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
00639 {
00640     HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM;
00641     return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00642 }
00643 
00644 
00645 GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
00646 {
00647     HDC hDC = m_hDC;
00648 
00649     if (is_crappy_intel_card())
00650         hDC = ::wglGetCurrentDC();
00651 
00652     return ::SwapBuffers(hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00653 }
00654 
00655 
00656 GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext()
00657 {
00658     GHOST_TSuccess success;
00659     if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
00660         if (m_hDC && m_hGlRc) {
00661             success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00662         }
00663         else {
00664             success = GHOST_kFailure;
00665         }
00666     }
00667     else {
00668         success = GHOST_kSuccess;
00669     }
00670     return success;
00671 }
00672 
00673 
00674 GHOST_TSuccess GHOST_WindowWin32::invalidate()
00675 {
00676     GHOST_TSuccess success;
00677     if (m_hWnd) {
00678         success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
00679     }
00680     else {
00681         success = GHOST_kFailure;
00682     }
00683     return success;
00684 }
00685 
00686 GHOST_TSuccess GHOST_WindowWin32::initMultisample(PIXELFORMATDESCRIPTOR pfd)
00687 {
00688     int pixelFormat;
00689     bool success = FALSE;
00690     UINT numFormats;
00691     HDC hDC = GetDC(getHWND());
00692     float fAttributes[] = {0, 0};
00693     UINT nMaxFormats = 1;
00694 
00695     // The attributes to look for
00696     int iAttributes[] = {
00697         WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
00698         WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
00699         WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
00700         WGL_COLOR_BITS_ARB, pfd.cColorBits,
00701         WGL_DEPTH_BITS_ARB, pfd.cDepthBits,
00702         WGL_STENCIL_BITS_ARB, pfd.cStencilBits,
00703         WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
00704         WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
00705         WGL_SAMPLES_ARB, m_multisample,
00706         0, 0
00707     };
00708 
00709     // Get the function
00710     PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");  
00711 
00712     if (!wglChoosePixelFormatARB)
00713     {
00714         m_multisampleEnabled = GHOST_kFailure;
00715         return GHOST_kFailure;
00716     }
00717 
00718     // iAttributes[17] is the initial multisample. If not valid try to use the closest valid value under it.
00719     while (iAttributes[17] > 0) {
00720         // See if the format is valid
00721         success = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, nMaxFormats, &pixelFormat, &numFormats);
00722         GHOST_PRINTF("WGL_SAMPLES_ARB = %i --> success = %i, %i formats\n", iAttributes[17], success, numFormats);
00723 
00724         if (success && numFormats >= 1 && m_multisampleEnabled == GHOST_kFailure) {
00725             GHOST_PRINTF("valid pixel format with %i multisamples\n", iAttributes[17]);
00726             m_multisampleEnabled = GHOST_kSuccess;
00727             m_msPixelFormat = pixelFormat;
00728         }
00729         iAttributes[17] -= 1;
00730         success = GHOST_kFailure;
00731     }
00732     if (m_multisampleEnabled == GHOST_kSuccess) {
00733         return GHOST_kSuccess;
00734     }
00735     GHOST_PRINT("no available pixel format\n");
00736     return GHOST_kFailure;
00737 }
00738 
00739 GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type)
00740 {
00741     GHOST_TSuccess success;
00742     switch (type) {
00743     case GHOST_kDrawingContextTypeOpenGL:
00744         {
00745         // If this window has multisample enabled, use the supplied format
00746         if (m_multisampleEnabled)
00747         {
00748             if (SetPixelFormat(m_hDC, m_msPixelFormat, &sPreferredFormat)==FALSE)
00749             {
00750                 success = GHOST_kFailure;
00751                 break;
00752             }
00753 
00754             // Create the context
00755             m_hGlRc = ::wglCreateContext(m_hDC);
00756             if (m_hGlRc) {
00757                 if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) {
00758                     if (s_firsthGLRc) {
00759                         if (is_crappy_intel_card()) {
00760                             if (::wglMakeCurrent(NULL, NULL) == TRUE) {
00761                                 ::wglDeleteContext(m_hGlRc);
00762                                 m_hGlRc = s_firsthGLRc;
00763                             }
00764                             else {
00765                                 ::wglDeleteContext(m_hGlRc);
00766                                 m_hGlRc = NULL;
00767                             }
00768                         }
00769                         else {
00770                             ::wglCopyContext(s_firsthGLRc, m_hGlRc, GL_ALL_ATTRIB_BITS);
00771                             ::wglShareLists(s_firsthGLRc, m_hGlRc);
00772                         }
00773                     }
00774                     else {
00775                         s_firsthGLRc = m_hGlRc;
00776                     }
00777 
00778                     if (m_hGlRc) {
00779                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00780                     }
00781                     else {
00782                         success = GHOST_kFailure;
00783                     }
00784                 }
00785                 else {
00786                     success = GHOST_kFailure;
00787                 }
00788             }
00789             else {
00790                 success = GHOST_kFailure;
00791             }
00792 
00793             if (success == GHOST_kFailure) {
00794                 printf("Failed to get a context....\n");
00795             }
00796         }
00797         else
00798         {
00799             if(m_stereoVisual)
00800                 sPreferredFormat.dwFlags |= PFD_STEREO;
00801 
00802             // Attempt to match device context pixel format to the preferred format
00803             int iPixelFormat = EnumPixelFormats(m_hDC);
00804             if (iPixelFormat == 0) {
00805                 success = GHOST_kFailure;
00806                 break;
00807             }
00808             if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) {
00809                 success = GHOST_kFailure;
00810                 break;
00811             }
00812             // For debugging only: retrieve the pixel format chosen
00813             PIXELFORMATDESCRIPTOR preferredFormat;
00814             ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat);
00815 
00816             // Create the context
00817             m_hGlRc = ::wglCreateContext(m_hDC);
00818             if (m_hGlRc) {
00819                 if (::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE) {
00820                     if (s_firsthGLRc) {
00821                         if (is_crappy_intel_card()) {
00822                             if (::wglMakeCurrent(NULL, NULL) == TRUE) {
00823                                 ::wglDeleteContext(m_hGlRc);
00824                                 m_hGlRc = s_firsthGLRc;
00825                             }
00826                             else {
00827                                 ::wglDeleteContext(m_hGlRc);
00828                                 m_hGlRc = NULL;
00829                             }
00830                         }
00831                         else {
00832                             ::wglShareLists(s_firsthGLRc, m_hGlRc);
00833                         }
00834                     }
00835                     else {
00836                         s_firsthGLRc = m_hGlRc;
00837                     }
00838 
00839                     if (m_hGlRc) {
00840                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00841                     }
00842                     else {
00843                         success = GHOST_kFailure;
00844                     }
00845                 }
00846                 else {
00847                     success = GHOST_kFailure;
00848                 }
00849             }
00850             else {
00851                 success = GHOST_kFailure;
00852             }
00853 
00854             if (success == GHOST_kFailure) {
00855                 printf("Failed to get a context....\n");
00856             }
00857                     
00858             // Attempt to enable multisample
00859             if (m_multisample && WGL_ARB_multisample && !m_multisampleEnabled)
00860             {
00861                 success = initMultisample(preferredFormat);
00862 
00863                 if (success)
00864                 {
00865 
00866                     // Make sure we don't screw up the context
00867                     if (m_hGlRc == s_firsthGLRc)
00868                         s_firsthGLRc = NULL;
00869                     m_drawingContextType = GHOST_kDrawingContextTypeOpenGL;
00870                     removeDrawingContext();
00871 
00872                     // Create a new window
00873                     GHOST_TWindowState new_state = getState();
00874 
00875                     m_nextWindow = new GHOST_WindowWin32((GHOST_SystemWin32*)GHOST_ISystem::getSystem(),
00876                                                     m_title,
00877                                                     m_left,
00878                                                     m_top,
00879                                                     m_width,
00880                                                     m_height,
00881                                                     new_state,
00882                                                     type,
00883                                                     m_stereo,
00884                                                     m_multisample,
00885                                                     m_parentWindowHwnd,
00886                                                     m_multisampleEnabled,
00887                                                     m_msPixelFormat);
00888 
00889                     // Return failure so we can trash this window.
00890                     success = GHOST_kFailure;
00891                     break;
00892                 } else {
00893                     m_multisampleEnabled = GHOST_kSuccess;
00894                     printf("Multisample failed to initialized\n");
00895                     success = GHOST_kSuccess;
00896                 }
00897             }
00898         }
00899 
00900         }
00901         break;
00902 
00903     case GHOST_kDrawingContextTypeNone:
00904         success = GHOST_kSuccess;
00905         break;
00906 
00907     default:
00908         success = GHOST_kFailure;
00909     }
00910     return success;
00911 }
00912 
00913 GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext()
00914 {
00915     GHOST_TSuccess success;
00916     switch (m_drawingContextType) {
00917     case GHOST_kDrawingContextTypeOpenGL:
00918         // we shouldn't remove the drawing context if it's the first OpenGL context
00919         // If we do, we get corrupted drawing. See #19997
00920         if (m_hGlRc && m_hGlRc!=s_firsthGLRc) {
00921             success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00922             m_hGlRc = 0;
00923         }
00924         else {
00925             success = GHOST_kFailure;
00926         }
00927         break;
00928     case GHOST_kDrawingContextTypeNone:
00929         success = GHOST_kSuccess;
00930         break;
00931     default:
00932         success = GHOST_kFailure;
00933     }
00934     return success;
00935 }
00936 
00937 void GHOST_WindowWin32::lostMouseCapture()
00938 {
00939     if(m_hasMouseCaptured)
00940         {   m_hasGrabMouse = false;
00941             m_nPressedButtons = 0;
00942             m_hasMouseCaptured = false;
00943         };
00944 }
00945 
00946 void GHOST_WindowWin32::registerMouseClickEvent(int press)
00947 {
00948 
00949     switch(press)
00950     {
00951         case 0: m_nPressedButtons++;    break;
00952         case 1: if(m_nPressedButtons)   m_nPressedButtons--; break;
00953         case 2: m_hasGrabMouse=true;    break;
00954         case 3: m_hasGrabMouse=false;   break;
00955     }
00956 
00957     if(!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured)
00958     {
00959             ::ReleaseCapture();
00960             m_hasMouseCaptured = false;
00961     }
00962     else if((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured)
00963     {
00964             ::SetCapture(m_hWnd);
00965             m_hasMouseCaptured = true;
00966 
00967     }
00968 }
00969 
00970 
00971 void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
00972 {
00973     if (!visible) {
00974         while (::ShowCursor(FALSE) >= 0);
00975     }
00976     else {
00977         while (::ShowCursor(TRUE) < 0);
00978     }
00979 
00980     if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
00981         ::SetCursor( m_customCursor );
00982     } else {
00983         // Convert GHOST cursor to Windows OEM cursor
00984         bool success = true;
00985         LPCSTR id;
00986         switch (cursor) {
00987             case GHOST_kStandardCursorDefault:      id = IDC_ARROW;     break;
00988             case GHOST_kStandardCursorRightArrow:       id = IDC_ARROW;     break;
00989             case GHOST_kStandardCursorLeftArrow:        id = IDC_ARROW;     break;
00990             case GHOST_kStandardCursorInfo:         id = IDC_SIZEALL;   break;  // Four-pointed arrow pointing north, south, east, and west
00991             case GHOST_kStandardCursorDestroy:      id = IDC_NO;        break;  // Slashed circle
00992             case GHOST_kStandardCursorHelp:         id = IDC_HELP;      break;  // Arrow and question mark
00993             case GHOST_kStandardCursorCycle:        id = IDC_NO;        break;  // Slashed circle
00994             case GHOST_kStandardCursorSpray:        id = IDC_SIZEALL;   break;  // Four-pointed arrow pointing north, south, east, and west
00995             case GHOST_kStandardCursorWait:         id = IDC_WAIT;      break;  // Hourglass
00996             case GHOST_kStandardCursorText:         id = IDC_IBEAM;     break;  // I-beam
00997             case GHOST_kStandardCursorCrosshair:        id = IDC_CROSS;     break;  // Crosshair
00998             case GHOST_kStandardCursorUpDown:       id = IDC_SIZENS;    break;  // Double-pointed arrow pointing north and south
00999             case GHOST_kStandardCursorLeftRight:        id = IDC_SIZEWE;    break;  // Double-pointed arrow pointing west and east
01000             case GHOST_kStandardCursorTopSide:      id = IDC_UPARROW;   break;  // Vertical arrow
01001             case GHOST_kStandardCursorBottomSide:       id = IDC_SIZENS;    break;
01002             case GHOST_kStandardCursorLeftSide:     id = IDC_SIZEWE;    break;
01003             case GHOST_kStandardCursorTopLeftCorner:    id = IDC_SIZENWSE;  break;
01004             case GHOST_kStandardCursorTopRightCorner:   id = IDC_SIZENESW;  break;
01005             case GHOST_kStandardCursorBottomRightCorner:    id = IDC_SIZENWSE;  break;
01006             case GHOST_kStandardCursorBottomLeftCorner: id = IDC_SIZENESW;  break;
01007             case GHOST_kStandardCursorPencil:       id = IDC_ARROW;     break;
01008             case GHOST_kStandardCursorCopy:         id = IDC_ARROW;     break;
01009             default:
01010             success = false;
01011         }
01012 
01013         if (success) {
01014             ::SetCursor(::LoadCursor(0, id));
01015         }
01016     }
01017 }
01018 
01019 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
01020 {
01021     if (::GetForegroundWindow() == m_hWnd) {
01022         loadCursor(visible, getCursorShape());
01023     }
01024 
01025     return GHOST_kSuccess;
01026 }
01027 
01028 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
01029 {
01030     if(mode != GHOST_kGrabDisable) {
01031         if(mode != GHOST_kGrabNormal) {
01032             m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
01033             setCursorGrabAccum(0, 0);
01034 
01035             if(mode == GHOST_kGrabHide)
01036                 setWindowCursorVisibility(false);
01037         }
01038         registerMouseClickEvent(2);
01039     }
01040     else {
01041         if (m_cursorGrab==GHOST_kGrabHide) {
01042             m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
01043             setWindowCursorVisibility(true);
01044         }
01045         if(m_cursorGrab != GHOST_kGrabNormal) {
01046             /* use to generate a mouse move event, otherwise the last event
01047              * blender gets can be outside the screen causing menus not to show
01048              * properly unless the user moves the mouse */
01049             GHOST_TInt32 pos[2];
01050             m_system->getCursorPosition(pos[0], pos[1]);
01051             m_system->setCursorPosition(pos[0], pos[1]);
01052         }
01053 
01054         /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
01055         setCursorGrabAccum(0, 0);
01056         m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */
01057         registerMouseClickEvent(3);
01058     }
01059     
01060     return GHOST_kSuccess;
01061 }
01062 
01063 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
01064 {
01065     if (m_customCursor) {
01066         DestroyCursor(m_customCursor);
01067         m_customCursor = NULL;
01068     }
01069 
01070     if (::GetForegroundWindow() == m_hWnd) {
01071         loadCursor(getCursorVisibility(), cursorShape);
01072     }
01073 
01074     return GHOST_kSuccess;
01075 }
01076 
01077 void GHOST_WindowWin32::processWin32TabletInitEvent()
01078 {
01079     if (m_wintab) {
01080         GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
01081 
01082         // let's see if we can initialize tablet here
01083         /* check if WinTab available. */
01084         if (fpWTInfo) {
01085             AXIS Pressure, Orientation[3]; /* The maximum tablet size */
01086 
01087             BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
01088             if (pressureSupport)
01089                 m_maxPressure = Pressure.axMax;
01090             else
01091                 m_maxPressure = 0;
01092 
01093             BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
01094             if (tiltSupport) {
01095                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
01096                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
01097                     m_maxAzimuth = Orientation[0].axMax;
01098                     m_maxAltitude = Orientation[1].axMax;
01099                 }
01100                 else {  /* no so dont do tilt stuff */
01101                     m_maxAzimuth = m_maxAltitude = 0;
01102                 }
01103             }
01104 
01105             m_tabletData->Active = GHOST_kTabletModeNone;
01106         }
01107     }
01108 }
01109 
01110 void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
01111 {
01112     PACKET pkt;
01113     if (m_wintab) {
01114         GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" );
01115         if (fpWTPacket) {
01116             if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
01117                 if (m_tabletData) {
01118                     switch (pkt.pkCursor) {
01119                         case 0: /* first device */
01120                         case 3: /* second device */
01121                             m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */
01122                             break;
01123                         case 1:
01124                         case 4:
01125                             m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */
01126                             break;
01127                         case 2:
01128                         case 5:
01129                             m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */
01130                             break;
01131                     }
01132                     if (m_maxPressure > 0) {
01133                         m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
01134                     } else {
01135                         m_tabletData->Pressure = 1.0f;
01136                     }
01137 
01138                     if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
01139                         ORIENTATION ort = pkt.pkOrientation;
01140                         float vecLen;
01141                         float altRad, azmRad;   /* in radians */
01142 
01143                         /*
01144                         from the wintab spec:
01145                         orAzimuth   Specifies the clockwise rotation of the
01146                         cursor about the z axis through a full circular range.
01147 
01148                         orAltitude  Specifies the angle with the x-y plane
01149                         through a signed, semicircular range.  Positive values
01150                         specify an angle upward toward the positive z axis;
01151                         negative values specify an angle downward toward the negative z axis.
01152 
01153                         wintab.h defines .orAltitude as a UINT but documents .orAltitude
01154                         as positive for upward angles and negative for downward angles.
01155                         WACOM uses negative altitude values to show that the pen is inverted;
01156                         therefore we cast .orAltitude as an (int) and then use the absolute value.
01157                         */
01158 
01159                         /* convert raw fixed point data to radians */
01160                         altRad = (float)((fabs((float)ort.orAltitude)/(float)m_maxAltitude) * M_PI/2.0);
01161                         azmRad = (float)(((float)ort.orAzimuth/(float)m_maxAzimuth) * M_PI*2.0);
01162 
01163                         /* find length of the stylus' projected vector on the XY plane */
01164                         vecLen = cos(altRad);
01165 
01166                         /* from there calculate X and Y components based on azimuth */
01167                         m_tabletData->Xtilt = sin(azmRad) * vecLen;
01168                         m_tabletData->Ytilt = (float)(sin(M_PI/2.0 - azmRad) * vecLen);
01169 
01170                     } else {
01171                         m_tabletData->Xtilt = 0.0f;
01172                         m_tabletData->Ytilt = 0.0f;
01173                     }
01174                 }
01175             }
01176         }
01177     }
01178 }
01179 
01181 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
01182 {
01183     ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
01184     ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
01185     ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
01186     return ch;
01187 }
01188 
01190 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
01191 {
01192     shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
01193     shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
01194     shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
01195     shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
01196     return shrt;
01197 }
01198 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
01199                                                              GHOST_TUns8 mask[16][2],
01200                                                              int hotX, int hotY)
01201 {
01202     return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask,
01203                                       16, 16, hotX, hotY, 0, 1);
01204 }
01205 
01206 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
01207                     GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY,
01208                     int fg_color, int bg_color)
01209 {
01210     GHOST_TUns32 andData[32];
01211     GHOST_TUns32 xorData[32];
01212     GHOST_TUns32 fullBitRow, fullMaskRow;
01213     int x, y, cols;
01214 
01215     cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */
01216     if (sizeX%8) cols++;
01217 
01218     if (m_customCursor) {
01219         DestroyCursor(m_customCursor);
01220         m_customCursor = NULL;
01221     }
01222 
01223     memset(&andData, 0xFF, sizeof(andData));
01224     memset(&xorData, 0, sizeof(xorData));
01225 
01226     for (y=0; y<sizeY; y++) {
01227         fullBitRow=0;
01228         fullMaskRow=0;
01229         for (x=cols-1; x>=0; x--){
01230             fullBitRow<<=8;
01231             fullMaskRow<<=8;
01232             fullBitRow  |= uns8ReverseBits(bitmap[cols*y + x]);
01233             fullMaskRow |= uns8ReverseBits(  mask[cols*y + x]);
01234         }
01235         xorData[y]= fullBitRow & fullMaskRow;
01236         andData[y]= ~fullMaskRow;
01237     }
01238 
01239     m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
01240     if (!m_customCursor) {
01241         return GHOST_kFailure;
01242     }
01243 
01244     if (::GetForegroundWindow() == m_hWnd) {
01245         loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
01246     }
01247 
01248     return GHOST_kSuccess;
01249 }
01250 
01251 
01252 GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress)
01253 {   
01254     /*SetProgressValue sets state to TBPF_NORMAL automaticly*/
01255     if(m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd,10000*progress,10000))
01256         return GHOST_kSuccess;
01257 
01258     return GHOST_kFailure;
01259 }
01260 
01261 GHOST_TSuccess GHOST_WindowWin32::endProgressBar()
01262 {
01263     if(m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd,TBPF_NOPROGRESS))
01264         return GHOST_kSuccess;
01265 
01266     return GHOST_kFailure;
01267 }
01268 
01269 /*  Ron Fosner's code for weighting pixel formats and forcing software.
01270     See http://www.opengl.org/resources/faq/technical/weight.cpp */
01271 
01272 static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd)
01273 {
01274     int weight = 0;
01275 
01276     /* assume desktop color depth is 32 bits per pixel */
01277 
01278     /* cull unusable pixel formats */
01279     /* if no formats can be found, can we determine why it was rejected? */
01280     if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
01281         !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
01282         !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
01283         ( pfd.cDepthBits <= 8 ) ||
01284         !(pfd.iPixelType == PFD_TYPE_RGBA))
01285         return 0;
01286 
01287     weight = 1;  /* it's usable */
01288 
01289     /* the bigger the depth buffer the better */
01290     /* give no weight to a 16-bit depth buffer, because those are crap */
01291     weight += pfd.cDepthBits - 16;
01292 
01293     weight += pfd.cColorBits - 8;
01294 
01295     /* want swap copy capability -- it matters a lot */
01296     if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16;
01297 
01298     /* but if it's a generic (not accelerated) view, it's really bad */
01299     if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10;
01300 
01301     return weight;
01302 }
01303 
01304 /* A modification of Ron Fosner's replacement for ChoosePixelFormat */
01305 /* returns 0 on error, else returns the pixel format number to be used */
01306 static int EnumPixelFormats(HDC hdc)
01307 {
01308     int iPixelFormat;
01309     int i, n, w, weight = 0;
01310     PIXELFORMATDESCRIPTOR pfd;
01311 
01312     /* we need a device context to do anything */
01313     if(!hdc) return 0;
01314 
01315     iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */
01316 
01317     /* obtain detailed information about
01318     the device context's first pixel format */
01319     n = 1+::DescribePixelFormat(hdc, iPixelFormat,
01320         sizeof(PIXELFORMATDESCRIPTOR), &pfd);
01321 
01322     /* choose a pixel format using the useless Windows function in case
01323         we come up empty handed */
01324     iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat );
01325 
01326     if(!iPixelFormat) return 0; /* couldn't find one to use */
01327 
01328     for(i=1; i<=n; i++) { /* not the idiom, but it's right */
01329         ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
01330         w = WeightPixelFormat(pfd);
01331         // be strict on stereo
01332         if (!((sPreferredFormat.dwFlags ^ pfd.dwFlags) & PFD_STEREO))   {
01333             if(w > weight) {
01334                 weight = w;
01335                 iPixelFormat = i;
01336             }
01337         }
01338     }
01339     if (weight == 0) {
01340         // we could find the correct stereo setting, just find any suitable format
01341         for(i=1; i<=n; i++) { /* not the idiom, but it's right */
01342             ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
01343             w = WeightPixelFormat(pfd);
01344             if(w > weight) {
01345                 weight = w;
01346                 iPixelFormat = i;
01347             }
01348         }
01349     }
01350     return iPixelFormat;
01351 }
01352 
01353