/* -*-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 #include namespace osgViewer { /* ** WindowSizeHandler */ WindowSizeHandler::WindowSizeHandler() : _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 WindowSizeHandler::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 WindowSizeHandler::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) { 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) { 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) { changeWindowedResolution(*itr, false); } return true; } break; } default: break; } return false; } void WindowSizeHandler::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 = 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 WindowSizeHandler::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 = 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 WindowSizeHandler::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."<tick()), _animStartTime(0) { _animPath = new osg::AnimationPath(); const char* str = getenv("OSG_CAMERA_ANIMATION_FPS"); if(str) _interval = 1.0f / atof(str); else _interval = 1.0f / 25.0f; } void RecordCameraPathHandler::getUsage(osg::ApplicationUsage &usage) const { usage.addKeyboardMouseBinding("z", "Toggle camera path recording."); } bool RecordCameraPathHandler::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 (ea.getKey() == 'z') { // The user has requested to BEGIN recording. if (!_currentlyRecording) { _currentlyRecording = true; _animStartTime = osg::Timer::instance()->tick(); osg::notify(osg::NOTICE)<<"Recording camera path."<write(out); out.close(); } return true; } break; } case(osgGA::GUIEventAdapter::FRAME): { // Calculate our current delta (difference) in time between the last frame and // current frame, regardless of whether we actually store a ControlPoint... osg::Timer_t time = osg::Timer::instance()->tick(); double delta = osg::Timer::instance()->delta_s(_lastFrameTime, time); _lastFrameTime = time; // If our internal _delta is finally large enough to warrant a ControlPoint // insertion, do so now. Be sure and reset the internal _delta, so we can start // calculating when the next insert should happen. if (_currentlyRecording && _delta >= _interval) { const osg::Matrixd& m = viewer->getCamera()->getInverseViewMatrix(); _animPath->insert(osg::Timer::instance()->delta_s(_animStartTime, time), osg::AnimationPath::ControlPoint(m.getTrans(), m.getRotate())); _delta = 0.0f; } else _delta += delta; break; } default: break; } return false; } }