/* -*-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 using namespace osgViewer; SimpleViewer::SimpleViewer(): _firstFrame(true) { _sceneView = new osgUtil::SceneView; _sceneView->setDefaults(); _sceneView->getState()->setContextID(osg::GraphicsContext::createNewContextID()); _frameStamp = new osg::FrameStamp; _frameStamp->setFrameNumber(0); _frameStamp->setReferenceTime(0); _frameStamp->setSimulationTime(0); _eventVisitor = new osgGA::EventVisitor; setDatabasePager(new osgDB::DatabasePager); _databasePager->setCompileGLObjectsForContextID(_sceneView->getState()->getContextID(), true); } SimpleViewer::~SimpleViewer() { _sceneView->releaseAllGLObjects(); osg::GraphicsContext::decrementContextIDUsageCount(_sceneView->getState()->getContextID()); _databasePager->setCompileGLObjectsForContextID(_sceneView->getState()->getContextID(), false); } void SimpleViewer::setSceneData(osg::Node* node) { _sceneView->setSceneData(node); if (_cameraManipulator.valid()) { _cameraManipulator->setNode(node); osg::ref_ptr dummyEvent = _eventQueue->createEvent(); _cameraManipulator->home(*dummyEvent, *this); } if (_databasePager.valid()) { // register any PagedLOD that need to be tracked in the scene graph _databasePager->registerPagedLODs(node); } } osg::Node* SimpleViewer::getSceneData() { return _sceneView->getSceneData(); } const osg::Node* SimpleViewer::getSceneData() const { return _sceneView->getSceneData(); } osg::Camera* SimpleViewer::getCamera() { return _sceneView->getCamera(); } const osg::Camera* SimpleViewer::getCamera() const { return _sceneView->getCamera(); } void SimpleViewer::setCameraManipulator(osgGA::MatrixManipulator* manipulator) { if (_cameraManipulator == manipulator) return; _cameraManipulator = manipulator; if (_cameraManipulator.valid()) { _cameraManipulator->setNode(_sceneView->getSceneData()); osg::ref_ptr dummyEvent = _eventQueue->createEvent(); _cameraManipulator->home(*dummyEvent, *this); } } void SimpleViewer::addEventHandler(osgGA::GUIEventHandler* eventHandler) { _eventHandlers.push_back(eventHandler); } void SimpleViewer::setDatabasePager(osgDB::DatabasePager* dp) { _databasePager = dp; if (dp && _sceneView.valid()) { // need to register the DatabasePager with the SceneView's CullVisitor so it can pass on request // for files to be loaded. _sceneView->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get()); } } void SimpleViewer::init() { osg::ref_ptr initEvent = _eventQueue->createEvent(); initEvent->setEventType(osgGA::GUIEventAdapter::FRAME); if (_cameraManipulator.valid()) { _cameraManipulator->init(*initEvent, *this); } } void SimpleViewer::frame(double simulationTime) { if (_firstFrame) { init(); _firstFrame = false; } advance(simulationTime); eventTraversal(); updateTraversal(); renderingTraversal(); } void SimpleViewer::advance(double simulationTime) { _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1); _frameStamp->setReferenceTime(osg::Timer::instance()->time_s()); if (simulationTime==USE_REFERENCE_TIME) { _frameStamp->setSimulationTime(_frameStamp->getReferenceTime()); } else { _frameStamp->setSimulationTime(simulationTime); } _sceneView->setFrameStamp(_frameStamp.get()); } void SimpleViewer::eventTraversal() { _eventQueue->frame( _frameStamp->getReferenceTime() ); osgGA::EventQueue::Events events; _eventQueue->takeEvents(events); if (_eventVisitor.valid()) { _eventVisitor->setTraversalNumber(_frameStamp->getFrameNumber()); } for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::GUIEventAdapter* event = itr->get(); if (_cameraManipulator.valid()) { if (_cameraManipulator->handle( *event, *this )) event->setHandled(true); } for(EventHandlers::iterator hitr = _eventHandlers.begin(); hitr != _eventHandlers.end(); ++hitr) { if ((*hitr)->handle( *event, *this, 0, 0)) event->setHandled(true); } if (_eventVisitor.valid() && getSceneData()) { _eventVisitor->reset(); _eventVisitor->addEvent( event ); getSceneData()->accept(*_eventVisitor); } } } void SimpleViewer::updateTraversal() { double previousAspectRatio = ( static_cast(_sceneView->getViewport()->width())/ static_cast(_sceneView->getViewport()->height()) ); // update the viewport int width = _eventQueue->getCurrentEventState()->getWindowWidth(); int height = _eventQueue->getCurrentEventState()->getWindowHeight(); _sceneView->setViewport(0,0,width,height); double newAspectRatio = ( static_cast(_sceneView->getViewport()->width())/ static_cast(_sceneView->getViewport()->height()) ); // if aspect ratio adjusted change the project matrix to suit. if (previousAspectRatio != newAspectRatio) { osg::Matrixd& pm = _sceneView->getProjectionMatrix(); bool orthographicCamera = (pm(0,3)==0.0) && (pm(1,3)==0.0) && (pm(2,3)==0.0) && (pm(3,3)==1.0); if (orthographicCamera) { double left, right, bottom, top, zNear, zFar; _sceneView->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar); double mid = (right+left)*0.5; double halfWidth = (right-left)*0.5; left = mid - halfWidth * (newAspectRatio/previousAspectRatio); right = mid + halfWidth * (newAspectRatio/previousAspectRatio); _sceneView->setProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar); } else { double left, right, bottom, top, zNear, zFar; _sceneView->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar); double mid = (right+left)*0.5; double halfWidth = (right-left)*0.5; left = mid - halfWidth * (newAspectRatio/previousAspectRatio); right = mid + halfWidth * (newAspectRatio/previousAspectRatio); _sceneView->setProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar); } } if (_cameraManipulator.valid()) { _sceneView->setViewMatrix(_cameraManipulator->getInverseMatrix()); } if (_databasePager.valid()) { // syncronize changes required by the DatabasePager thread to the scene graph _databasePager->updateSceneGraph(_frameStamp->getReferenceTime()); } _sceneView->update(); } void SimpleViewer::renderingTraversal() { if (_databasePager.valid()) { // tell the DatabasePager the frame number of that the scene graph is being actively used to render a frame _databasePager->signalBeginFrame(_frameStamp.get()); } _sceneView->cull(); _sceneView->draw(); if (_databasePager.valid()) { // tell the DatabasePager the frame number of that the scene graph is being actively used to render a frame _databasePager->signalEndFrame(); // clean up and compile gl objects with a specified limit double availableTime = 0.0025; // 2.5 ms // compile any GL objects that are required. _databasePager->compileGLObjects(*(_sceneView->getState()),availableTime); // flush deleted GL objects. _sceneView->flushDeletedGLObjects(availableTime); } } void SimpleViewer::releaseAllGLObjects() { for(EventHandlers::iterator hitr = _eventHandlers.begin(); hitr != _eventHandlers.end(); ++hitr) { (*hitr)->releaseGLObjects(_sceneView->getState()); } if (_databasePager.valid()) { // clear the database pager so its starts a fresh on the next update/cull/draw traversals _databasePager->clear(); } // release the GL objects stored in the scene graph. _sceneView->releaseAllGLObjects(); } void SimpleViewer::cleanup() { releaseAllGLObjects(); // do a flush to delete all the OpenGL objects that have been deleted or released from the scene graph. _sceneView->flushAllDeletedGLObjects(); }