diff --git a/modules/highgui/include/opencv2/highgui.hpp b/modules/highgui/include/opencv2/highgui.hpp index c5b5ed42c2..dd17362249 100644 --- a/modules/highgui/include/opencv2/highgui.hpp +++ b/modules/highgui/include/opencv2/highgui.hpp @@ -202,7 +202,8 @@ enum WindowPropertyFlags { WND_PROP_ASPECT_RATIO = 2, //!< window's aspect ration (can be set to WINDOW_FREERATIO or WINDOW_KEEPRATIO). WND_PROP_OPENGL = 3, //!< opengl support. WND_PROP_VISIBLE = 4, //!< checks whether the window exists and is visible - WND_PROP_TOPMOST = 5 //!< property to toggle normal window being topmost or not + WND_PROP_TOPMOST = 5, //!< property to toggle normal window being topmost or not + WND_PROP_VSYNC = 6 //!< enable or disable VSYNC (in OpenGL mode) }; //! Mouse Events see cv::MouseCallback diff --git a/modules/highgui/src/precomp.hpp b/modules/highgui/src/precomp.hpp index 6ffd154a19..a5b176c9dd 100644 --- a/modules/highgui/src/precomp.hpp +++ b/modules/highgui/src/precomp.hpp @@ -115,6 +115,9 @@ double cvGetPropTopmost_COCOA(const char* name); void cvSetPropTopmost_W32(const char* name, const bool topmost); void cvSetPropTopmost_COCOA(const char* name, const bool topmost); +double cvGetPropVsync_W32(const char* name); +void cvSetPropVsync_W32(const char* name, const bool enabled); + //for QT #if defined (HAVE_QT) CvRect cvGetWindowRect_QT(const char* name); diff --git a/modules/highgui/src/window.cpp b/modules/highgui/src/window.cpp index 8b26ea989b..0d1b137270 100644 --- a/modules/highgui/src/window.cpp +++ b/modules/highgui/src/window.cpp @@ -92,6 +92,14 @@ CV_IMPL void cvSetWindowProperty(const char* name, int prop_id, double prop_valu #endif break; + case cv::WND_PROP_VSYNC: + #if defined (HAVE_WIN32UI) + cvSetPropVsync_W32(name, (prop_value != 0)); + #else + // not implemented yet for other toolkits + #endif + break; + default:; } } @@ -182,6 +190,14 @@ CV_IMPL double cvGetWindowProperty(const char* name, int prop_id) #endif break; + case cv::WND_PROP_VSYNC: + #if defined (HAVE_WIN32UI) + return cvGetPropVsync_W32(name); + #else + return -1; + #endif + break; + default: return -1; } diff --git a/modules/highgui/src/window_w32.cpp b/modules/highgui/src/window_w32.cpp index 67fbc380e1..18aa323fa4 100644 --- a/modules/highgui/src/window_w32.cpp +++ b/modules/highgui/src/window_w32.cpp @@ -596,6 +596,89 @@ void cvSetPropTopmost_W32(const char* name, const bool topmost) } } +double cvGetPropVsync_W32(const char* name) +{ +#ifndef HAVE_OPENGL + CV_UNUSED(name); + CV_Error(Error::OpenGlNotSupported, "Library was built without OpenGL support"); +#else + if (!name) + CV_Error(Error::StsNullPtr, "'name' argument must not be NULL"); + + CvWindow* window = icvFindWindowByName(name); + if (!window) + CV_Error_(Error::StsBadArg, ("there is no window named '%s'", name)); + + // https://www.khronos.org/opengl/wiki/Swap_Interval + // https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_extensions_string.txt + // https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_swap_control.txt + + if (!wglMakeCurrent(window->dc, window->hGLRC)) + CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context"); + + typedef const char* (APIENTRY* PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); + PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsString = NULL; + wglGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); + if (wglGetExtensionsString == NULL) + return -1; // wglGetProcAddress failed to get wglGetExtensionsStringEXT + + const char* wgl_extensions = wglGetExtensionsString(); + if (wgl_extensions == NULL) + return -1; // Can't get WGL extensions string + + if (strstr(wgl_extensions, "WGL_EXT_swap_control") == NULL) + return -1; // WGL extensions don't contain WGL_EXT_swap_control + + typedef int (APIENTRY* PFNWGLGETSWAPINTERVALPROC)(void); + PFNWGLGETSWAPINTERVALPROC wglGetSwapInterval = 0; + wglGetSwapInterval = (PFNWGLGETSWAPINTERVALPROC)wglGetProcAddress("wglGetSwapIntervalEXT"); + if (wglGetSwapInterval == NULL) + return -1; // wglGetProcAddress failed to get wglGetSwapIntervalEXT + + return wglGetSwapInterval(); +#endif +} + +void cvSetPropVsync_W32(const char* name, const bool enable_vsync) +{ +#ifndef HAVE_OPENGL + CV_UNUSED(name); + CV_UNUSED(enable_vsync); + CV_Error(Error::OpenGlNotSupported, "Library was built without OpenGL support"); +#else + if (!name) + CV_Error(Error::StsNullPtr, "'name' argument must not be NULL"); + + CvWindow* window = icvFindWindowByName(name); + if (!window) + CV_Error_(Error::StsBadArg, ("there is no window named '%s'", name)); + + if (!wglMakeCurrent(window->dc, window->hGLRC)) + CV_Error(Error::OpenGlApiCallError, "Can't Activate The GL Rendering Context"); + + typedef const char* (APIENTRY* PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); + PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsString = NULL; + wglGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); + if (wglGetExtensionsString == NULL) + CV_Error(Error::OpenGlApiCallError, "wglGetProcAddress failed to get wglGetExtensionsStringEXT"); + + const char* wgl_extensions = wglGetExtensionsString(); + if (wgl_extensions == NULL) + CV_Error(Error::OpenGlApiCallError, "Can't get WGL extensions string"); + + if (strstr(wgl_extensions, "WGL_EXT_swap_control") == NULL) + CV_Error(Error::OpenGlApiCallError, "WGL extensions don't contain WGL_EXT_swap_control"); + + typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALPROC)(int); + PFNWGLSWAPINTERVALPROC wglSwapInterval = 0; + wglSwapInterval = (PFNWGLSWAPINTERVALPROC)wglGetProcAddress("wglSwapIntervalEXT"); + if (wglSwapInterval == NULL) + CV_Error(Error::OpenGlApiCallError, "wglGetProcAddress failed to get wglSwapIntervalEXT"); + + wglSwapInterval(enable_vsync); +#endif +} + void cv::setWindowTitle(const String& winname, const String& title) { CvWindow* window = icvFindWindowByName(winname.c_str());