From ac20eca87af6cc0da23fd9fac571e0e132c2351a Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 12 Jun 2006 11:32:11 +0000 Subject: [PATCH] Revamped osgkeyboardmouse to use the osgGA. --- examples/osgkeyboardmouse/GNUmakefile | 2 +- .../osgkeyboardmouse/osgkeyboardmouse.cpp | 328 +++++++----------- 2 files changed, 135 insertions(+), 195 deletions(-) diff --git a/examples/osgkeyboardmouse/GNUmakefile b/examples/osgkeyboardmouse/GNUmakefile index 41876cd8b..daf2c61a2 100644 --- a/examples/osgkeyboardmouse/GNUmakefile +++ b/examples/osgkeyboardmouse/GNUmakefile @@ -4,7 +4,7 @@ include $(TOPDIR)/Make/makedefs CXXFILES =\ osgkeyboardmouse.cpp\ -LIBS += -lProducer -losgFX -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) -lOpenThreads +LIBS += -lProducer -losgFX -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) -lOpenThreads INSTFILES = \ $(CXXFILES)\ diff --git a/examples/osgkeyboardmouse/osgkeyboardmouse.cpp b/examples/osgkeyboardmouse/osgkeyboardmouse.cpp index d00c461dc..900dd1e02 100644 --- a/examples/osgkeyboardmouse/osgkeyboardmouse.cpp +++ b/examples/osgkeyboardmouse/osgkeyboardmouse.cpp @@ -16,59 +16,22 @@ #include #include +#include +#include +#include +#include + #include - -class CreateModelToSaveVisitor : public osg::NodeVisitor -{ -public: - - CreateModelToSaveVisitor(): - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) - { - _group = new osg::Group; - _addToModel = false; - } - - virtual void apply(osg::Node& node) - { - osgFX::Scribe* scribe = dynamic_cast(&node); - if (scribe) - { - for(unsigned int i=0; igetNumChildren(); ++i) - { - _group->addChild(scribe->getChild(i)); - } - } - else - { - traverse(node); - } - } - - osg::ref_ptr _group; - bool _addToModel; -}; - +// Begining of glue classes to adapter Producer's keyboard mouse events to osgGA's abstraction events. class MyKeyboardMouseCallback : public Producer::KeyboardMouseCallback { public: - MyKeyboardMouseCallback(osgUtil::SceneView* sceneView) : - Producer::KeyboardMouseCallback(), - _mx(0.0f),_my(0.0f),_mbutton(0), + MyKeyboardMouseCallback(osgGA::EventQueue* eventQueue) : _done(false), - _trackBall(new Producer::Trackball), - _sceneView(sceneView) + _eventQueue(eventQueue) { - resetTrackball(); - _mouseMovingOnPreviousRelease = false; - } - - virtual void specialKeyPress( Producer::KeyCharacter key ) - { - if (key==Producer::KeyChar_Escape) - shutdown(); } virtual void shutdown() @@ -76,172 +39,69 @@ public: _done = true; } + virtual void specialKeyPress( Producer::KeyCharacter key ) + { + if (key==Producer::KeyChar_Escape) + shutdown(); + + _eventQueue->keyPress( (osgGA::GUIEventAdapter::KeySymbol) key ); + } + + virtual void specialKeyRelease( Producer::KeyCharacter key ) + { + _eventQueue->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) key ); + } + virtual void keyPress( Producer::KeyCharacter key) { - if (key==' ') resetTrackball(); - else if (key=='o') saveSelectedModel(); + _eventQueue->keyPress( (osgGA::GUIEventAdapter::KeySymbol) key ); + } + + virtual void keyRelease( Producer::KeyCharacter key) + { + _eventQueue->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) key ); } virtual void mouseMotion( float mx, float my ) { - _mx = mx; - _my = my; + _eventQueue->mouseMotion( mx, my ); } virtual void buttonPress( float mx, float my, unsigned int mbutton ) { - _mx = mx; - _my = my; - _mbutton |= (1<<(mbutton-1)); - - _mx_buttonPress = _mx; - _my_buttonPress = _my; + _eventQueue->mouseButtonPress(mx, my, mbutton); } + virtual void buttonRelease( float mx, float my, unsigned int mbutton ) { - _mx = mx; - _my = my; - _mbutton &= ~(1<<(mbutton-1)); - - if (_mx==_mx_buttonPress && _my_buttonPress==_my) - { - if (!_mouseMovingOnPreviousRelease) - { - // button press and release without moving so assume this means - // the users wants to pick. - pick(_mx,_my); - } - _mouseMovingOnPreviousRelease = false; - } - else - { - _mouseMovingOnPreviousRelease = true; - } + _eventQueue->mouseButtonRelease(mx, my, mbutton); } bool done() { return _done; } - float mx() { return _mx; } - float my() { return _my; } - unsigned int mbutton() { return _mbutton; } - - void resetTrackball() - { - osg::Node* scene = _sceneView->getSceneData(); - if (scene) - { - const osg::BoundingSphere& bs = scene->getBound(); - if (bs.valid()) - { - _trackBall->reset(); - _trackBall->setOrientation( Producer::Trackball::Z_UP ); - _trackBall->setDistance(bs.radius()*2.0f); - _trackBall->translate(-bs.center().x(),-bs.center().y(),-bs.center().z()); - } - } - } - - osg::Matrixd getViewMatrix() - { - _trackBall->input( mx(), my(), mbutton() ); - return osg::Matrixd(_trackBall->getMatrix().ptr()); - } - - void pick(float x, float y) - { - osg::Node* scene = _sceneView->getSceneData(); - if (scene) - { - std::cout<<"Picking "<getViewport(origX,origY,width,height); - - // convert Producer's non dimensional x,y coords back into pixel coords. - int pixel_x = (int)((x+1.0f)*0.5f*(float)width); - int pixel_y = (int)((y+1.0f)*0.5f*(float)height); - - - osgUtil::PickVisitor pick(_sceneView->getViewport(), - _sceneView->getProjectionMatrix(), - _sceneView->getViewMatrix(), - pixel_x, pixel_y); - - scene->accept(pick); - - osgUtil::PickVisitor::LineSegmentHitListMap& segHitList = pick.getSegHitList(); - if (!segHitList.empty() && !segHitList.begin()->second.empty()) - { - std::cout<<"Got hits"<second; - - // just take the first hit - nearest the eye point. - osgUtil::Hit& hit = hits.front(); - - osg::NodePath& nodePath = hit._nodePath; - osg::Node* node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0; - osg::Group* parent = (nodePath.size()>=2)?dynamic_cast(nodePath[nodePath.size()-2]):0; - - if (node) std::cout<<" Hits "<className()<<" nodePath size"<className()<(parent); - if (!parentAsScribe) - { - // node not already picked, so highlight it with an osgFX::Scribe - osgFX::Scribe* scribe = new osgFX::Scribe(); - scribe->addChild(node); - parent->replaceChild(node,scribe); - } - else - { - // node already picked so we want to remove scribe to unpick it. - osg::Node::ParentList parentList = parentAsScribe->getParents(); - for(osg::Node::ParentList::iterator itr=parentList.begin(); - itr!=parentList.end(); - ++itr) - { - (*itr)->replaceChild(parentAsScribe,node); - } - } - } - - } - - } - - } - - void saveSelectedModel() - { - CreateModelToSaveVisitor cmtsv; - _sceneView->getSceneData()->accept(cmtsv); - - if (cmtsv._group->getNumChildren()>0) - { - osgDB::writeNodeFile(*cmtsv._group, "selected_model.osg"); - } - } private: - float _mx, _my; - float _mx_buttonPress, _my_buttonPress; - unsigned int _mbutton; - bool _mouseMovingOnPreviousRelease; - bool _done; - - osg::ref_ptr _trackBall; - osg::ref_ptr _sceneView; + osg::ref_ptr _eventQueue; }; +class MyActionAdapter : public osgGA::GUIActionAdapter, public osg::Referenced +{ +public: + // Override from GUIActionAdapter + virtual void requestRedraw() {} + + // Override from GUIActionAdapter + virtual void requestContinuousUpdate(bool =true) {} + + // Override from GUIActionAdapter + virtual void requestWarpPointer(float ,float ) {} + +}; + +// End of glue classes to adapter Producer's keyboard mouse events to osgGA's abstraction events. + + int main( int argc, char **argv ) { if (argc<2) @@ -270,20 +130,52 @@ int main( int argc, char **argv ) osg::ref_ptr sceneView = new osgUtil::SceneView; sceneView->setDefaults(); sceneView->setSceneData(loadedModel.get()); - + + // create the event queue, note that Producer has the y axis increase upwards, like OpenGL, and contary to most Windowing toolkits, so + // we need to construct the event queue so that it knows about this convention. + osg::ref_ptr eventQueue = new osgGA::EventQueue(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); // set up a KeyboardMouse to manage the events comming in from the RenderSurface osg::ref_ptr kbm = new Producer::KeyboardMouse(renderSurface.get()); // create a KeyboardMouseCallback to handle the mouse events within this applications - osg::ref_ptr kbmcb = new MyKeyboardMouseCallback(sceneView.get()); + osg::ref_ptr kbmcb = new MyKeyboardMouseCallback(eventQueue.get()); + // create a tracball manipulator to move the camera around in response to keyboard/mouse events + osg::ref_ptr cameraManipulator = new osgGA::TrackballManipulator; + + // keep a list of event handlers to manipulate the application/scene with in response to keyboard/mouse events + typedef std::list< osg::ref_ptr > EventHandlers; + EventHandlers eventHandlers; + + osg::ref_ptr statesetManipulator = new osgGA::StateSetManipulator; + statesetManipulator->setStateSet(sceneView->getGlobalStateSet()); + eventHandlers.push_back(statesetManipulator.get()); + + // create an event visitor to pass the events down to the scene graph nodes + osg::ref_ptr eventVisitor = new osgGA::EventVisitor; + + // create an action adapter to allow event handlers to request actions from the GUI. + osg::ref_ptr actionAdapter = new MyActionAdapter; // record the timer tick at the start of rendering. osg::Timer_t start_tick = osg::Timer::instance()->tick(); unsigned int frameNum = 0; + eventQueue->setStartTick(start_tick); + + // set the mouse input range (note WindowSize name in appropriate here so osgGA::GUIEventAdapter API really needs looking at, Robert Osfield, June 2006). + // Producer defaults to using non-dimensional units, so we pass this onto osgGA, most windowing toolkits use pixel coords so use the window size instead. + eventQueue->getCurrentEventState()->setWindowSize(-1.0, -1.0, 1.0, 1.0); + + + // home the manipulator. + osg::ref_ptr dummyEvent = eventQueue->createEvent(); + cameraManipulator->setNode(sceneView->getSceneData()); + cameraManipulator->home(*dummyEvent, *actionAdapter); + + // main loop (note, window toolkits which take control over the main loop will require a window redraw callback containing the code below.) while( renderSurface->isRealized() && !kbmcb->done()) { @@ -295,11 +187,59 @@ int main( int argc, char **argv ) // pass frame stamp to the SceneView so that the update, cull and draw traversals all use the same FrameStamp sceneView->setFrameStamp(frameStamp); - // pass any keyboard mouse events onto the local keyboard mouse callback. + // pass any keyboard mouse events onto the local keyboard mouse callback. kbm->update( *kbmcb ); - // set the view - sceneView->setViewMatrix(kbmcb->getViewMatrix()); + // create an event to signal the new frame. + eventQueue->frame(frameStamp->getReferenceTime()); + + // get the event since the last frame. + osgGA::EventQueue::Events events; + eventQueue->takeEvents(events); + + if (eventVisitor.valid()) + { + eventVisitor->setTraversalNumber(frameStamp->getFrameNumber()); + } + + // dispatch the events in order of arrival. + for(osgGA::EventQueue::Events::iterator event_itr = events.begin(); + event_itr != events.end(); + ++event_itr) + { + bool handled = false; + + if (eventVisitor.valid() && sceneView->getSceneData()) + { + eventVisitor->reset(); + eventVisitor->addEvent(event_itr->get()); + sceneView->getSceneData()->accept(*eventVisitor); + if (eventVisitor->getEventHandled()) + handled = true; + } + + if (cameraManipulator.valid() && !handled) + { + /*handled =*/ cameraManipulator->handle(*(*event_itr), *actionAdapter); + } + + for(EventHandlers::iterator handler_itr=eventHandlers.begin(); + handler_itr!=eventHandlers.end() && !handled; + ++handler_itr) + { + handled = (*handler_itr)->handle(*(*event_itr),*actionAdapter,0,0); + } + + // osg::notify(osg::NOTICE)<<" Handled event "<<(*event_itr)->getTime()<<" "<< handled<setViewMatrix(cameraManipulator->getInverseMatrix()); + } // update the viewport dimensions, incase the window has been resized. sceneView->setViewport(0,0,renderSurface->getWindowWidth(),renderSurface->getWindowHeight());