diff options
Diffstat (limited to 'intern/ghost/intern/GHOST_WindowWin32.cpp')
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.cpp | 311 |
1 files changed, 216 insertions, 95 deletions
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index b3a262537fb..21d1ec0c5b1 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -17,8 +17,8 @@ * All rights reserved. */ -/** \file ghost/intern/GHOST_WindowWin32.cpp - * \ingroup GHOST +/** \file + * \ingroup GHOST */ #define _USE_MATH_DEFINES @@ -39,11 +39,14 @@ #include <Dwmapi.h> #endif +#include <windowsx.h> #include <math.h> #include <string.h> #include <assert.h> - +#ifndef GET_POINTERID_WPARAM +#define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam)) +#endif // GET_POINTERID_WPARAM const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass"; const int GHOST_WindowWin32::s_maxTitleLength = 128; @@ -80,7 +83,10 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_customCursor(0), m_wantAlphaBackground(alphaBackground), m_normal_state(GHOST_kWindowStateNormal), - m_user32(NULL), + m_user32(NULL), + m_fpGetPointerInfo(NULL), + m_fpGetPointerPenInfo(NULL), + m_fpGetPointerTouchInfo(NULL), m_parentWindowHwnd(parentwindowhwnd), m_debug_context(is_debug) { @@ -102,7 +108,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, // MSVC 2012+ returns bogus values from GetSystemMetrics, bug in Windows // http://connect.microsoft.com/VisualStudio/feedback/details/753224/regression-getsystemmetrics-delivers-different-values RECT cxrect = {0, 0, 0, 0}; - AdjustWindowRectEx(&cxrect, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_THICKFRAME | WS_DLGFRAME, FALSE, 0); + AdjustWindowRectEx(&cxrect, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_THICKFRAME | WS_DLGFRAME, FALSE, 0); int cxsizeframe = abs(cxrect.bottom); int cysizeframe = abs(cxrect.left); @@ -173,7 +179,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_hWnd = ::CreateWindowW( s_windowClassName, // pointer to registered class name title_16, // pointer to window name - WS_POPUP | WS_MAXIMIZE, // window style + WS_MAXIMIZE, // window style left, // horizontal position of window top, // vertical position of window width, // window width @@ -276,6 +282,13 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, RegisterRawInputDevices(&device, 1, sizeof(device)); } + // Initialize Windows Ink + if (m_user32) { + m_fpGetPointerInfo = (GHOST_WIN32_GetPointerInfo) ::GetProcAddress(m_user32, "GetPointerInfo"); + m_fpGetPointerPenInfo = (GHOST_WIN32_GetPointerPenInfo) ::GetProcAddress(m_user32, "GetPointerPenInfo"); + m_fpGetPointerTouchInfo = (GHOST_WIN32_GetPointerTouchInfo) ::GetProcAddress(m_user32, "GetPointerTouchInfo"); + } + // Initialize Wintab m_wintab.handle = ::LoadLibrary("Wintab32.dll"); if (m_wintab.handle) { @@ -345,6 +358,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32() if (m_Bar) { m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS); m_Bar->Release(); + m_Bar = NULL; } if (m_wintab.handle) { @@ -356,6 +370,14 @@ GHOST_WindowWin32::~GHOST_WindowWin32() memset(&m_wintab, 0, sizeof(m_wintab)); } + if (m_user32) { + FreeLibrary(m_user32); + m_user32 = NULL; + m_fpGetPointerInfo = NULL; + m_fpGetPointerPenInfo = NULL; + m_fpGetPointerTouchInfo = NULL; + } + if (m_customCursor) { DestroyCursor(m_customCursor); m_customCursor = NULL; @@ -363,6 +385,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32() if (m_hWnd != NULL && m_hDC != NULL && releaseNativeHandles()) { ::ReleaseDC(m_hWnd, m_hDC); + m_hDC = NULL; } if (m_hWnd) { @@ -371,16 +394,12 @@ GHOST_WindowWin32::~GHOST_WindowWin32() RevokeDragDrop(m_hWnd); // Release our reference of the DropTarget and it will delete itself eventually. m_dropTarget->Release(); + m_dropTarget = NULL; } ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, NULL); ::DestroyWindow(m_hWnd); m_hWnd = 0; } - - if (m_user32) { - FreeLibrary(m_user32); - m_user32 = NULL; - } } bool GHOST_WindowWin32::getValid() const @@ -526,7 +545,7 @@ GHOST_TWindowState GHOST_WindowWin32::getState() const } else if (::IsZoomed(m_hWnd)) { LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE); - if ((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE)) + if ((result & (WS_DLGFRAME | WS_MAXIMIZE)) == (WS_DLGFRAME | WS_MAXIMIZE)) state = GHOST_kWindowStateMaximized; else state = GHOST_kWindowStateFullScreen; @@ -584,7 +603,7 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) wp.showCmd = SW_SHOWMAXIMIZED; wp.ptMaxPosition.x = 0; wp.ptMaxPosition.y = 0; - ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE); + ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_MAXIMIZE); break; case GHOST_kWindowStateEmbedded: ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD); @@ -642,101 +661,80 @@ GHOST_TSuccess GHOST_WindowWin32::invalidate() GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#if !defined(WITH_GL_EGL) + GHOST_Context *context; #if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextWGL( - m_wantStereoVisual, - m_wantAlphaBackground, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - 3, 2, - GHOST_OPENGL_WGL_CONTEXT_FLAGS, - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextWGL( - m_wantStereoVisual, - m_wantAlphaBackground, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - WGL_CONTEXT_ES2_PROFILE_BIT_EXT, - 2, 0, - GHOST_OPENGL_WGL_CONTEXT_FLAGS, - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); + /* - AMD and Intel give us exactly this version + * - NVIDIA gives at least this version <-- desired behavior + * So we ask for 4.5, 4.4 ... 3.3 in descending order to get the best version on the user's system. */ + for (int minor = 5; minor >= 0; --minor) { + context = new GHOST_ContextWGL( + m_wantStereoVisual, + m_wantAlphaBackground, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 4, minor, + (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) { + return context; + } + else { + delete context; + } + } + context = new GHOST_ContextWGL( + m_wantStereoVisual, + m_wantAlphaBackground, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 3, 3, + (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) { + return context; + } + else { + MessageBox( + m_hWnd, + "A graphics card and driver with support for OpenGL 3.3 or higher is required.\n" + "Installing the latest driver for your graphics card may resolve the issue.\n\n" + "The program will now close.", + "Blender - Unsupported Graphics Card or Driver", + MB_OK | MB_ICONERROR); + delete context; + exit(0); + } + #elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextWGL( + // ask for 2.1 context, driver gives any GL version >= 2.1 (hopefully the latest compatibility profile) + // 2.1 ignores the profile bit & is incompatible with core profile + context = new GHOST_ContextWGL( m_wantStereoVisual, m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, -#if 1 - 0, // profile bit - 2, 1, // GL version requested -#else - // switch to this for Blender 2.8 development - WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - 3, 2, -#endif + 0, // no profile bit + 2, 1, (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); -#else -# error -#endif - -#else - -#if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - 3, 2, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - 0, // profile bit - 2, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_ES_API); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, -#if 1 - 0, // profile bit - 2, 1, // GL version requested -#else - // switch to this for Blender 2.8 development - EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, - 3, 2, -#endif - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else -# error -#endif -#endif - if (context->initializeDrawingContext()) + if (context->initializeDrawingContext()) { return context; - else + } + else { delete context; + } +#else +# error // must specify either core or compat at build time +#endif } return NULL; @@ -880,8 +878,101 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur return GHOST_kSuccess; } +GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, WPARAM wParam, LPARAM lParam) +{ + ZeroMemory(pointerInfo, sizeof(GHOST_PointerInfoWin32)); + + // Obtain the basic information from the event + pointerInfo->pointerId = GET_POINTERID_WPARAM(wParam); + pointerInfo->isInContact = IS_POINTER_INCONTACT_WPARAM(wParam); + pointerInfo->isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam); + + // Obtain more accurate and predicted information from the Pointer API + POINTER_INFO pointerApiInfo; + if (!(m_fpGetPointerInfo && m_fpGetPointerInfo(pointerInfo->pointerId, &pointerApiInfo))) { + return GHOST_kFailure; + } + + pointerInfo->hasButtonMask = GHOST_kSuccess; + switch (pointerApiInfo.ButtonChangeType) { + case POINTER_CHANGE_FIRSTBUTTON_DOWN: + case POINTER_CHANGE_FIRSTBUTTON_UP: + pointerInfo->buttonMask = GHOST_kButtonMaskLeft; + break; + case POINTER_CHANGE_SECONDBUTTON_DOWN: + case POINTER_CHANGE_SECONDBUTTON_UP: + pointerInfo->buttonMask = GHOST_kButtonMaskRight; + break; + case POINTER_CHANGE_THIRDBUTTON_DOWN: + case POINTER_CHANGE_THIRDBUTTON_UP: + pointerInfo->buttonMask = GHOST_kButtonMaskMiddle; + break; + case POINTER_CHANGE_FOURTHBUTTON_DOWN: + case POINTER_CHANGE_FOURTHBUTTON_UP: + pointerInfo->buttonMask = GHOST_kButtonMaskButton4; + break; + case POINTER_CHANGE_FIFTHBUTTON_DOWN: + case POINTER_CHANGE_FIFTHBUTTON_UP: + pointerInfo->buttonMask = GHOST_kButtonMaskButton5; + break; + default: + pointerInfo->hasButtonMask = GHOST_kFailure; + break; + } + + pointerInfo->pixelLocation = pointerApiInfo.ptPixelLocation; + pointerInfo->tabletData.Active = GHOST_kTabletModeNone; + pointerInfo->tabletData.Pressure = 1.0f; + pointerInfo->tabletData.Xtilt = 0.0f; + pointerInfo->tabletData.Ytilt = 0.0f; + + if (pointerApiInfo.pointerType != PT_PEN) { + return GHOST_kFailure; + } + + POINTER_PEN_INFO pointerPenInfo; + if (m_fpGetPointerPenInfo && m_fpGetPointerPenInfo(pointerInfo->pointerId, &pointerPenInfo)) { + pointerInfo->tabletData.Active = GHOST_kTabletModeStylus; + + if (pointerPenInfo.penMask & PEN_MASK_PRESSURE) { + pointerInfo->tabletData.Pressure = pointerPenInfo.pressure / 1024.0f; + } + + if (pointerPenInfo.penFlags & PEN_FLAG_ERASER) { + pointerInfo->tabletData.Active = GHOST_kTabletModeEraser; + } + + if (pointerPenInfo.penFlags & PEN_MASK_TILT_X) { + pointerInfo->tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f); + } + + if (pointerPenInfo.penFlags & PEN_MASK_TILT_Y) { + pointerInfo->tabletData.Ytilt = fmin(fabs(pointerPenInfo.tiltY / 90), 1.0f); + } + } + + return GHOST_kSuccess; +} + +void GHOST_WindowWin32::setTabletData(GHOST_TabletData * pTabletData) +{ + if (pTabletData) { + m_tabletData = *pTabletData; + } + else { + m_tabletData.Active = GHOST_kTabletModeNone; + m_tabletData.Pressure = 1.0f; + m_tabletData.Xtilt = 0.0f; + m_tabletData.Ytilt = 0.0f; + } +} + void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state) { + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; + } + if (m_wintab.enable && m_wintab.tablet) { m_wintab.enable(m_wintab.tablet, state); @@ -891,8 +982,28 @@ void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state) } } +bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const +{ + if (m_system->getTabletAPI() == api) { + return true; + } + else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) { + if (m_wintab.tablet) + return api == GHOST_kTabletWintab; + else + return api == GHOST_kTabletNative; + } + else { + return false; + } +} + void GHOST_WindowWin32::processWin32TabletInitEvent() { + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; + } + // Let's see if we can initialize tablet here if (m_wintab.info && m_wintab.tablet) { AXIS Pressure, Orientation[3]; /* The maximum tablet size */ @@ -917,10 +1028,16 @@ void GHOST_WindowWin32::processWin32TabletInitEvent() m_tabletData.Active = GHOST_kTabletModeNone; } + + m_tabletData.Active = GHOST_kTabletModeNone; } void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) { + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; + } + if (m_wintab.packet && m_wintab.tablet) { PACKET pkt; if (m_wintab.packet((HCTX)lParam, wParam, &pkt)) { @@ -986,6 +1103,10 @@ void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) void GHOST_WindowWin32::bringTabletContextToFront() { + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; + } + if (m_wintab.overlap && m_wintab.tablet) { m_wintab.overlap(m_wintab.tablet, TRUE); } |