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