From 43549f3df60a19957085361665ad880303c2ce72 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 14 May 2007 14:41:22 +0000 Subject: [PATCH] From Serge Lages, "Here is a ViewerEventHandler file with a collection of helper handlers for osgViewer. Most of the code is from the osgviewer application, I have took the fullscreen handler and the threading one, and I have just added a fonctionality to be able to change the screen resolution in windowed mode." --- include/osgViewer/ViewerEventHandler | 105 ++++++++ src/osgViewer/CMakeLists.txt | 2 + src/osgViewer/ViewerEventHandler.cpp | 345 +++++++++++++++++++++++++++ 3 files changed, 452 insertions(+) create mode 100644 include/osgViewer/ViewerEventHandler create mode 100644 src/osgViewer/ViewerEventHandler.cpp diff --git a/include/osgViewer/ViewerEventHandler b/include/osgViewer/ViewerEventHandler new file mode 100644 index 000000000..cbd3e041c --- /dev/null +++ b/include/osgViewer/ViewerEventHandler @@ -0,0 +1,105 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield +* +* This library is open source and may be redistributed and/or modified under +* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or +* (at your option) any later version. The full license is in LICENSE file +* included with this distribution, and on the openscenegraph.org website. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGVIEWER_VIEWEREVENTHANDLER +#define OSGVIEWER_VIEWEREVENTHANDLER 1 + +#include + +namespace osgViewer { + + /** + Handler allowing to change the screen resolution (in windowed mode) and toggle between fullscreen and windowed mode. + */ + class OSGVIEWER_EXPORT ScreenHandler : public osgGA::GUIEventHandler + { + public: + + ScreenHandler(); + + /** Get the keyboard and mouse usage of this manipulator.*/ + virtual void getUsage(osg::ApplicationUsage &usage) const; + + void setKeyEventToggleFullscreen(int key) { _keyEventToggleFullscreen = key; } + int getKeyEventToggleFullscreen() const { return (_keyEventToggleFullscreen); } + + void setToggleFullscreen(bool flag) { _toggleFullscreen = flag; } + bool getToggleFullscreen() const { return (_toggleFullscreen); } + + void setKeyEventWindowedResolutionUp(int key) { _keyEventWindowedResolutionUp = key; } + int getKeyEventWindowedResolutionUp() const { return (_keyEventWindowedResolutionUp); } + void setKeyEventWindowedResolutionDown(int key) { _keyEventWindowedResolutionDown = key; } + int getKeyEventWindowedResolutionDown() const { return (_keyEventWindowedResolutionUp); } + + void setChangeWindowedResolution(bool flag) { _changeWindowedResolution = flag; } + bool getChangeWindowedResolution() const { return (_changeWindowedResolution); } + + virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa); + + protected: + + void toggleFullscreen(osgViewer::GraphicsWindow *window); + void changeWindowedResolution(osgViewer::GraphicsWindow *window, bool increase); + + unsigned int getNearestResolution(int screenWidth, int screenHeight, int width, int height) const; + + int _keyEventToggleFullscreen; + bool _toggleFullscreen; + + int _keyEventWindowedResolutionUp; + int _keyEventWindowedResolutionDown; + bool _changeWindowedResolution; + std::vector _resolutionList; + int _currentResolutionIndex; + }; + + /** + Handler allowing to change the viewer threading model + */ + class OSGVIEWER_EXPORT ThreadingHandler : public osgGA::GUIEventHandler + { + public: + + ThreadingHandler(); + + /** Get the keyboard and mouse usage of this manipulator.*/ + virtual void getUsage(osg::ApplicationUsage &usage) const; + + void setKeyEventChangeThreadingModel(int key) { _keyEventChangeThreadingModel = key; } + int getKeyEventChangeThreadingModel() const { return (_keyEventChangeThreadingModel); } + + void setChangeThreadingModel(bool flag) { _changeThreadingModel = flag; } + bool getChangeThreadingModel() const { return (_changeThreadingModel); } + + void setKeyEventChangeEndBarrierPosition(int key) { _keyEventChangeEndBarrierPosition = key; } + int getKeyEventChangeEndBarrierPosition() const { return (_keyEventChangeEndBarrierPosition); } + + void setChangeEndBarrierPosition(bool flag) { _changeEndBarrierPosition = flag; } + bool getChangeEndBarrierPosition() const { return (_changeEndBarrierPosition); } + + bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa); + + protected: + + int _keyEventChangeThreadingModel; + bool _changeThreadingModel; + + int _keyEventChangeEndBarrierPosition; + bool _changeEndBarrierPosition; + + osg::Timer_t _tickOrLastKeyPress; + bool _done; + }; +} + +#endif diff --git a/src/osgViewer/CMakeLists.txt b/src/osgViewer/CMakeLists.txt index 9dd6d7614..f998f271b 100644 --- a/src/osgViewer/CMakeLists.txt +++ b/src/osgViewer/CMakeLists.txt @@ -19,6 +19,7 @@ SET(LIB_PUBLIC_HEADERS ${HEADER_PATH}/Version ${HEADER_PATH}/View ${HEADER_PATH}/Viewer + ${HEADER_PATH}/ViewerEventHandler ) SET(LIB_PRIVATE_HEADERS @@ -36,6 +37,7 @@ SET(LIB_COMMON_FILES Version.cpp View.cpp Viewer.cpp + ViewerEventHandler.cpp ) diff --git a/src/osgViewer/ViewerEventHandler.cpp b/src/osgViewer/ViewerEventHandler.cpp new file mode 100644 index 000000000..ca1b8471f --- /dev/null +++ b/src/osgViewer/ViewerEventHandler.cpp @@ -0,0 +1,345 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield +* +* This library is open source and may be redistributed and/or modified under +* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or +* (at your option) any later version. The full license is in LICENSE file +* included with this distribution, and on the openscenegraph.org website. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* OpenSceneGraph Public License for more details. +*/ + +#include +#include + +namespace osgViewer +{ + +/* +** ScreenHandler +*/ + +ScreenHandler::ScreenHandler() : +_keyEventToggleFullscreen('f'), +_toggleFullscreen(true), +_keyEventWindowedResolutionUp('>'), +_keyEventWindowedResolutionDown('<'), +_changeWindowedResolution(true), +_currentResolutionIndex(-1) +{ + _resolutionList.push_back(osg::Vec2(640, 480)); + _resolutionList.push_back(osg::Vec2(800, 600)); + _resolutionList.push_back(osg::Vec2(1024, 768)); + _resolutionList.push_back(osg::Vec2(1152, 864)); + _resolutionList.push_back(osg::Vec2(1280, 720)); + _resolutionList.push_back(osg::Vec2(1280, 768)); + _resolutionList.push_back(osg::Vec2(1280, 1024)); + _resolutionList.push_back(osg::Vec2(1440, 900)); + _resolutionList.push_back(osg::Vec2(1400, 1050)); + _resolutionList.push_back(osg::Vec2(1600, 900)); + _resolutionList.push_back(osg::Vec2(1600, 1024)); + _resolutionList.push_back(osg::Vec2(1600, 1200)); + _resolutionList.push_back(osg::Vec2(1680, 1050)); + _resolutionList.push_back(osg::Vec2(1920, 1080)); + _resolutionList.push_back(osg::Vec2(1920, 1200)); + _resolutionList.push_back(osg::Vec2(2048, 1536)); + _resolutionList.push_back(osg::Vec2(2560, 2048)); + _resolutionList.push_back(osg::Vec2(3200, 2400)); + _resolutionList.push_back(osg::Vec2(3840, 2400)); +} + +void ScreenHandler::getUsage(osg::ApplicationUsage &usage) const +{ + usage.addKeyboardMouseBinding("f", "Toggle full screen."); + usage.addKeyboardMouseBinding(">", "Increase the screen resolution (in windowed mode)."); + usage.addKeyboardMouseBinding("<", "Decrease the screen resolution (in windowed mode)."); +} + +bool ScreenHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) +{ + osgViewer::Viewer *viewer = dynamic_cast(&aa); + + if (viewer == NULL) + { + return (false); + } + + switch(ea.getEventType()) + { + case(osgGA::GUIEventAdapter::KEYUP): + { + if (_toggleFullscreen == true && ea.getKey() == _keyEventToggleFullscreen) + { + osgViewer::Viewer::Windows windows; + + viewer->getWindows(windows); + for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); + itr != windows.end(); + ++itr) + { + this->toggleFullscreen(*itr); + } + return (true); + } + else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionUp) + { + // Increase resolution + osgViewer::Viewer::Windows windows; + + viewer->getWindows(windows); + for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); + itr != windows.end(); + ++itr) + { + this->changeWindowedResolution(*itr, true); + } + return (true); + } + else if (_changeWindowedResolution == true && ea.getKey() == _keyEventWindowedResolutionDown) + { + // Decrease resolution + osgViewer::Viewer::Windows windows; + + viewer->getWindows(windows); + for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); + itr != windows.end(); + ++itr) + { + this->changeWindowedResolution(*itr, false); + } + return (true); + } + break; + } + default: + break; + } + return (false); +} + +void ScreenHandler::toggleFullscreen(osgViewer::GraphicsWindow *window) +{ + osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); + + if (wsi == NULL) + { + osg::notify(osg::NOTICE) << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl; + return; + } + + unsigned int screenWidth; + unsigned int screenHeight; + + wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight); + + int x; + int y; + int width; + int height; + + window->getWindowRectangle(x, y, width, height); + + bool isFullScreen = x == 0 && y == 0 && width == screenWidth && height == screenHeight; + + if (isFullScreen) + { + osg::Vec2 resolution; + + if (_currentResolutionIndex == -1) + { + _currentResolutionIndex = this->getNearestResolution(screenWidth, screenHeight, screenWidth / 2, screenHeight / 2); + } + resolution = _resolutionList[_currentResolutionIndex]; + window->setWindowDecoration(true); + window->setWindowRectangle((screenWidth - (int)resolution.x()) / 2, (screenHeight - (int)resolution.y()) / 2, (int)resolution.x(), (int)resolution.y()); + osg::notify(osg::INFO) << "Screen resolution = " << (int)resolution.x() << "x" << (int)resolution.y() << std::endl; + } + else + { + window->setWindowDecoration(false); + window->setWindowRectangle(0, 0, screenWidth, screenHeight); + } + + window->grabFocusIfPointerInWindow(); +} + +void ScreenHandler::changeWindowedResolution(osgViewer::GraphicsWindow *window, bool increase) +{ + osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); + + if (wsi == NULL) + { + osg::notify(osg::NOTICE) << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl; + return; + } + + unsigned int screenWidth; + unsigned int screenHeight; + + wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight); + + int x; + int y; + int width; + int height; + + window->getWindowRectangle(x, y, width, height); + + bool isFullScreen = x == 0 && y == 0 && width == screenWidth && height == screenHeight; + + if (window->getWindowDecoration() == true || isFullScreen == false) + { + osg::Vec2 resolution; + + if (_currentResolutionIndex == -1) + { + _currentResolutionIndex = this->getNearestResolution(screenWidth, screenHeight, width, height); + } + + if (increase == true) + { + // Find the next resolution + for (int i = _currentResolutionIndex + 1; i < (int)_resolutionList.size(); ++i) + { + if ((unsigned int)_resolutionList[i].x() <= screenWidth && (unsigned int)_resolutionList[i].y() <= screenHeight) + { + _currentResolutionIndex = i; + break; + } + } + } + else + { + // Find the previous resolution + for (int i = _currentResolutionIndex - 1; i >= 0; --i) + { + if ((unsigned int)_resolutionList[i].x() <= screenWidth && (unsigned int)_resolutionList[i].y() <= screenHeight) + { + _currentResolutionIndex = i; + break; + } + } + } + + resolution = _resolutionList[_currentResolutionIndex]; + window->setWindowDecoration(true); + window->setWindowRectangle((screenWidth - (int)resolution.x()) / 2, (screenHeight - (int)resolution.y()) / 2, (int)resolution.x(), (int)resolution.y()); + osg::notify(osg::INFO) << "Screen resolution = " << (int)resolution.x() << "x" << (int)resolution.y() << std::endl; + + window->grabFocusIfPointerInWindow(); + } +} + +unsigned int ScreenHandler::getNearestResolution(int screenWidth, int screenHeight, int width, int height) const +{ + unsigned int position = 0; + unsigned int result = 0; + int delta = INT_MAX; + + for (std::vector::const_iterator it = _resolutionList.begin(); + it != _resolutionList.end(); + ++it, ++position) + { + if ((int)it->x() <= screenWidth && (int)it->y() <= screenHeight) + { + int tmp = static_cast(osg::absolute((width * height) - (it->x() * it->y()))); + + if (tmp < delta) + { + delta = tmp; + result = position; + } + } + } + return (result); +} + +/* +** ThreadingHandler +*/ + +ThreadingHandler::ThreadingHandler() : +_keyEventChangeThreadingModel('m'), +_changeThreadingModel(true), +_keyEventChangeEndBarrierPosition('e'), +_changeEndBarrierPosition(true) +{ + _tickOrLastKeyPress = osg::Timer::instance()->tick(); +} + +void ThreadingHandler::getUsage(osg::ApplicationUsage &usage) const +{ + usage.addKeyboardMouseBinding("m", "Toggle threading model."); + usage.addKeyboardMouseBinding("e", "Toggle the placement of the end of frame barrier."); +} + +bool ThreadingHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) +{ + osgViewer::Viewer *viewer = dynamic_cast(&aa); + + if (viewer == NULL) + { + return (false); + } + + switch(ea.getEventType()) + { + case(osgGA::GUIEventAdapter::KEYUP): + { + double delta = osg::Timer::instance()->delta_s(_tickOrLastKeyPress, osg::Timer::instance()->tick()); + + if (_changeThreadingModel == true && ea.getKey() == _keyEventChangeThreadingModel && delta > 1.0) + { + _tickOrLastKeyPress = osg::Timer::instance()->tick(); + + switch(viewer->getThreadingModel()) + { + case(osgViewer::Viewer::SingleThreaded): + viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext); + osg::notify(osg::NOTICE)<<"Threading model 'CullDrawThreadPerContext' selected."<setThreadingModel(osgViewer::Viewer::DrawThreadPerContext); + osg::notify(osg::NOTICE)<<"Threading model 'DrawThreadPerContext' selected."<setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext); + osg::notify(osg::NOTICE)<<"Threading model 'CullThreadPerCameraDrawThreadPerContext' selected."<setThreadingModel(osgViewer::Viewer::SingleThreaded); + osg::notify(osg::NOTICE)<<"Threading model 'SingleThreaded' selected."<setThreadingModel(viewer->suggestBestThreadingModel()); + osg::notify(osg::NOTICE)<<"Threading model 'AutomaticSelection' selected."<getEndBarrierPosition()) + { + case(osgViewer::Viewer::BeforeSwapBuffers): + viewer->setEndBarrierPosition(osgViewer::Viewer::AfterSwapBuffers); + osg::notify(osg::NOTICE)<<"Threading model 'AfterSwapBuffers' selected."<setEndBarrierPosition(osgViewer::Viewer::BeforeSwapBuffers); + osg::notify(osg::NOTICE)<<"Threading model 'BeforeSwapBuffers' selected."<