|
Blender
V2.59
|
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