diff --git a/include/osg/GraphicsContext b/include/osg/GraphicsContext index 2e4568772..bb099edc7 100644 --- a/include/osg/GraphicsContext +++ b/include/osg/GraphicsContext @@ -16,6 +16,7 @@ #include #include +#include namespace osg { @@ -150,23 +151,72 @@ class OSG_EXPORT GraphicsContext : public Object // X11 hint whether to override the window managers window size/position redirection bool overrideRedirect; }; - - + + /** Simple resolution structure used by WindowingSystemInterface to get and set screen resolution. + * Note the '0' value stands for 'unset'. */ + struct ScreenSettings { + ScreenSettings() : + width(0), + height(0), + colorDepth(0), + refreshRate(0) + {} + ScreenSettings(int width, int height, double refreshRate=0, unsigned int colorDepth=0) : + width(width), + height(height), + colorDepth(colorDepth), + refreshRate(refreshRate) + {} + + int width; + int height; + double refreshRate; ///< Screen refresh rate, in Hz. + unsigned int colorDepth; ///< RGB(A) color buffer depth. + }; + + typedef std::vector ScreenSettingsList; + /** Callback to be implemented to provide access to Windowing API's ability to create Windows/pbuffers.*/ struct WindowingSystemInterface : public osg::Referenced { - virtual unsigned int getNumScreens(const ScreenIdentifier& screenIdentifier = ScreenIdentifier()) = 0; - virtual void getScreenResolution(const ScreenIdentifier& screenIdentifier, unsigned int& width, unsigned int& height) = 0; + virtual void getScreenSettings(const ScreenIdentifier& screenIdentifier, ScreenSettings & resolution) = 0; - virtual bool setScreenResolution(const ScreenIdentifier& /*screenIdentifier*/, unsigned int /*width*/, unsigned int /*height*/) { return false; } - - virtual bool setScreenRefreshRate(const ScreenIdentifier& /*screenIdentifier*/, double /*refreshRate*/) { return false; } + virtual bool setScreenSettings(const ScreenIdentifier& /*screenIdentifier*/, const ScreenSettings & /*resolution*/) { return false; } + + virtual void enumerateScreenSettings(const ScreenIdentifier& screenIdentifier, ScreenSettingsList & resolutionList) = 0; virtual GraphicsContext* createGraphicsContext(Traits* traits) = 0; - virtual ~WindowingSystemInterface() {}; + virtual ~WindowingSystemInterface() {} + + + /** Gets screen resolution without using the ScreenResolution structure. + * \deprecated Provided only for backward compatibility. */ + inline void getScreenResolution(const ScreenIdentifier& screenIdentifier, unsigned int& width, unsigned int& height) + { + ScreenSettings settings; + getScreenSettings(screenIdentifier, settings); + width = settings.width; + height = settings.height; + } + + /** Sets screen resolution without using the ScreenSettings structure. + * \deprecated Provided only for backward compatibility. */ + inline bool setScreenResolution(const ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height) + { + return setScreenSettings(screenIdentifier, ScreenSettings(width, height)); + } + + /** \deprecated Provided only for backward compatibility. */ + inline bool setScreenRefreshRate(const ScreenIdentifier& screenIdentifier, double refreshRate) + { + ScreenSettings settings; + getScreenSettings(screenIdentifier, settings); + settings.refreshRate = refreshRate; + return setScreenSettings(screenIdentifier, settings); + } }; diff --git a/src/osgViewer/CMakeLists.txt b/src/osgViewer/CMakeLists.txt index 2390cf7bc..918657fd4 100644 --- a/src/osgViewer/CMakeLists.txt +++ b/src/osgViewer/CMakeLists.txt @@ -86,7 +86,22 @@ ELSE(WIN32) ELSE(${OSG_WINDOWING_SYSTEM} STREQUAL "Carbon") # X11 for everybody else - OPTION(OSGVIEWER_USE_XRANDR "Set to ON to enable Xrandr support for GraphicsWindowX11." OFF) + + + INCLUDE(FindPkgConfig) + IF (PKG_CONFIG_FOUND) + + PKG_CHECK_MODULES(XRANDR xrandr) + + IF (XRANDR_FOUND) + OPTION(OSGVIEWER_USE_XRANDR "Set to ON to enable Xrandr support for GraphicsWindowX11." ON) + ELSE(XRANDR_FOUND) + SET(OSGVIEWER_USE_XRANDR OFF) + ENDIF (XRANDR_FOUND) + ELSE(PKG_CONFIG_FOUND) + SET(OSGVIEWER_USE_XRANDR OFF) + ENDIF(PKG_CONFIG_FOUND) + SET(LIB_PUBLIC_HEADERS ${LIB_PUBLIC_HEADERS} ${HEADER_PATH}/api/X11/GraphicsWindowX11 @@ -99,8 +114,6 @@ ELSE(WIN32) ) IF(OSGVIEWER_USE_XRANDR) - INCLUDE(FindPkgConfig) - PKG_CHECK_MODULES(XRANDR REQUIRED xrandr) ADD_DEFINITIONS(-DOSGVIEWER_USE_XRANDR) SET(LIB_PUBLIC_HEADERS ${LIB_PUBLIC_HEADERS} ${XRANDR_INCLUDE_DIRS}) LINK_LIBRARIES(Xrandr) diff --git a/src/osgViewer/GraphicsWindowCarbon.cpp b/src/osgViewer/GraphicsWindowCarbon.cpp index f770ac174..24e760c33 100644 --- a/src/osgViewer/GraphicsWindowCarbon.cpp +++ b/src/osgViewer/GraphicsWindowCarbon.cpp @@ -389,11 +389,14 @@ struct OSXCarbonWindowingSystemInterface : public osg::GraphicsContext::Windowin } /** returns the resolution of a specific display */ - virtual void getScreenResolution(const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height) + virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution) { CGDirectDisplayID id = getDisplayID(si); - width = CGDisplayPixelsWide(id); - height = CGDisplayPixelsHigh(id); + resolution.width = CGDisplayPixelsWide(id); + resolution.height = CGDisplayPixelsHigh(id); + resolution.colorDepth = CGDisplayBitsPerPixel(id); + resolution.refreshRate = getDictDouble (CGDisplayCurrentMode(displayID), kCGDisplayRefreshRate); // Not tested + if (resolution.refreshRate<0) resolution.refreshRate = 0; } /** return the top left coord of a specific screen in global screen space */ @@ -405,66 +408,75 @@ struct OSXCarbonWindowingSystemInterface : public osg::GraphicsContext::Windowin // osg::notify(osg::DEBUG_INFO) << "topleft of screen " << si.screenNum <<" " << bounds.origin.x << "/" << bounds.origin.y << std::endl; } - /** helper method to get a value out of a CFDictionary */ + /** Helper method to get a double value out of a CFDictionary */ static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) { - double double_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it + double value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it return -1; // fail - return double_value; // otherwise return the long value + return value; // otherwise return the long value } - - /** implementation of setScreenResolution */ - virtual bool setScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height) + /** Helper method to get a long value out of a CFDictionary */ + static long getDictLong(CFDictionaryRef refDict, CFStringRef key) // const void* key? + { + long value = 0; + CFNumberRef number_value = (CFNumberRef)CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberLongType, &value)) // or if cant convert it + return -1; // fail + return value; + } + + /** implementation of setScreenSettings */ + virtual bool setScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, const osg::GraphicsContext::ScreenSettings & resolution) { CGDirectDisplayID displayID = getDisplayID(screenIdentifier); - // add next line and on following line replace hard coded depth and refresh rate - CGRefreshRate refresh = getDictDouble (CGDisplayCurrentMode(displayID), kCGDisplayRefreshRate); + CGRefreshRate refresh = resolution.refreshRate>0 ? resolution.refreshRate : getDictDouble (CGDisplayCurrentMode(displayID), kCGDisplayRefreshRate); + sizt_t depth = resolution.colorDepth>0 ? resolution.colorDepth : CGDisplayBitsPerPixel(displayID); CFDictionaryRef display_mode_values = CGDisplayBestModeForParametersAndRefreshRate( displayID, - CGDisplayBitsPerPixel(displayID), - width, height, + depth, + resolution.width, resolution.height, refresh, NULL); - + CGDisplaySwitchToMode(displayID, display_mode_values); return true; } - - /** implementation of setScreenRefreshRate */ - virtual bool setScreenRefreshRate(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate) { - - boolean_t success(false); - unsigned width, height; - getScreenResolution(screenIdentifier, width, height); - - CGDirectDisplayID displayID = getDisplayID(screenIdentifier); - - // add next line and on following line replace hard coded depth and refresh rate - CFDictionaryRef display_mode_values = - CGDisplayBestModeForParametersAndRefreshRate( - displayID, - CGDisplayBitsPerPixel(displayID), - width, height, - refreshRate, - &success); - - if (success) - CGDisplaySwitchToMode(displayID, display_mode_values); - - return (success != 0); + virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolutionList) { + // Warning! This method has not been tested. + resolutionList.clear(); + + CGDirectDisplayID displayID = getDisplayID(screenIdentifier); + CFArrayRef availableModes = CGDisplayAvailableModes(displayID); + unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes); + for (unsigned int i=0; ipbuffer) diff --git a/src/osgViewer/GraphicsWindowWin32.cpp b/src/osgViewer/GraphicsWindowWin32.cpp index 29b60fc0f..2ef90b4f2 100644 --- a/src/osgViewer/GraphicsWindowWin32.cpp +++ b/src/osgViewer/GraphicsWindowWin32.cpp @@ -237,17 +237,17 @@ class Win32WindowingSystem : public osg::GraphicsContext::WindowingSystemInterfa // Return the resolution of specified screen // (0,0) is returned if screen is unknown - virtual void getScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height ); + virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution ); // Return the bits per pixel of specified screen // (0) is returned if screen is unknown virtual void getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel ); // Set the resolution for given screen - virtual bool setScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int width, unsigned int height ); + virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution ); - // Set the refresh rate for given screen - virtual bool setScreenRefreshRate( const osg::GraphicsContext::ScreenIdentifier& si, double refreshRate ); + // Enumerates available resolutions + virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolution); // Return the screen position and width/height. // all zeros returned if screen is unknown @@ -800,21 +800,40 @@ bool Win32WindowingSystem::getScreenInformation( const osg::GraphicsContext::Scr return true; } -void Win32WindowingSystem::getScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height ) +void Win32WindowingSystem::getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution ) { DISPLAY_DEVICE displayDevice; DEVMODE deviceMode; - if (getScreenInformation(si, displayDevice, deviceMode)) - { - width = deviceMode.dmPelsWidth; - height = deviceMode.dmPelsHeight; + if (!getScreenInformation(si, displayDevice, deviceMode)) + deviceMode.dmFields = 0; // Set the fields to 0 so that it says 'nothing'. + + // Get resolution + if ((deviceMode.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != 0) { + resolution.width = deviceMode.dmPelsWidth; + resolution.height = deviceMode.dmPelsHeight; + } else { + resolution.width = 0; + resolution.height = 0; } + + // Get refersh rate + if ((deviceMode.dmFields & DM_DISPLAYFREQUENCY) != 0) { + resolution.refreshRate = deviceMode.dmDisplayFrequency; + if (resolution.refreshRate == 0 || resolution.refreshRate == 1) { + // Windows specific: 0 and 1 represent the hhardware's default refresh rate. + // If someone knows how to get this refresh rate (in Hz)... + osg::notify(osg::NOTICE) << "Win32WindowingSystem::getScreenSettings() is not fully implemented (cannot retreive the hardware's default refresh rate)."<0 && resolution.height>0) { + deviceMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; + deviceMode.dmPelsWidth = static_cast(resolution.width); + deviceMode.dmPelsHeight = static_cast(resolution.height); + } + // Set refersh rate + if (resolution.refreshRate>0) { + deviceMode.dmFields |= DM_DISPLAYFREQUENCY; + deviceMode.dmDisplayFrequency = static_cast(resolution.refreshRate); + } + // Set bits per pixel for color buffer + if (resolution.colorDepth>0) { + deviceMode.dmFields |= DM_BITSPERPEL; + deviceMode.dmBitsPerPel = static_cast(resolution.colorDepth); + } return changeScreenSettings(si, displayDevice, deviceMode); } -bool Win32WindowingSystem::setScreenRefreshRate( const osg::GraphicsContext::ScreenIdentifier& si, double refreshRate ) -{ - DISPLAY_DEVICE displayDevice; - DEVMODE deviceMode; +void Win32WindowingSystem::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList) { + resolutionList.clear(); - unsigned int width, height; - getScreenResolution(si, width, height); + if (si.displayNum>0) + { + osg::notify(osg::WARN) << "Win32WindowingSystem::enumerateScreenSettings() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl; + return; + } - if (!getScreenInformation(si, displayDevice, deviceMode)) return false; + DisplayDevices displayDevices; + enumerateDisplayDevices(displayDevices); - deviceMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - deviceMode.dmPelsWidth = width; - deviceMode.dmPelsHeight = height; - deviceMode.dmDisplayFrequency = (DWORD)refreshRate; - - return changeScreenSettings(si, displayDevice, deviceMode); + if (si.screenNum>=static_cast(displayDevices.size())) + { + osg::notify(osg::WARN) << "Win32WindowingSystem::enumerateScreenSettings() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl; + return; + } + + DISPLAY_DEVICE displayDevice = displayDevices[si.screenNum]; + + // Do the enumeration + DEVMODE deviceMode; + static const unsigned int MAX_RESOLUTIONS = 4046; // Upper limit to avoid infinite (= very long) loop. + for (unsigned int i=0; i0) + osg::notify(osg::NOTICE) << "X11WindowingSystemInterface::_setScreen() is not fully implemented (missing depth)."< 1 || ( major == 1 && minor >= 2 ) ); + } +#endif + return false; + } + + virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution ) { Display* display = XOpenDisplay(si.displayName().c_str()); if(display) { - width = DisplayWidth(display, si.screenNum); - height = DisplayHeight(display, si.screenNum); + resolution.width = DisplayWidth(display, si.screenNum); + resolution.height = DisplayHeight(display, si.screenNum); + resolution.colorDepth = DefaultDepth(display, si.screenNum); + resolution.refreshRate = 0; // Missing call. Need a X11 expert. + XCloseDisplay(display); } else { osg::notify(osg::NOTICE) << "Unable to open display \"" << XDisplayName(si.displayName().c_str()) << "\"."<0) + { + for(int i=0; i0) + { + for(int j=0; j