diff --git a/src/PickHandler.cpp b/src/PickHandler.cpp index d3764c2..1322279 100644 --- a/src/PickHandler.cpp +++ b/src/PickHandler.cpp @@ -17,8 +17,7 @@ using namespace vizkit3d; PickHandler::PickHandler(): _mx(0.0),_my(0.0), - _usePolytopeIntersector(false), - _useWindowCoordinates(false) {} + _usePolytopeIntersector(true) {} PickHandler::~PickHandler() {} @@ -67,94 +66,84 @@ bool PickHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapt switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN): + { + if (ea.getKey()=='w') { - if (ea.getKey()=='w') - { - this->wireFrameModeOn(viewer->getSceneData()); - } - else if (ea.getKey()=='n') - { - this->wireFrameModeOff(viewer->getSceneData()); - } - else - { - keyFunctionMap::iterator itr = keyFuncMap.find(ea.getKey()); - if (itr != keyFuncMap.end()) - { - if ( (*itr).second.keyState == KEY_UP ) - { - (*itr).second.keyState = KEY_DOWN; - newKeyDownEvent = true; - } - if (newKeyDownEvent) - { - (*itr).second.keyFunction(); - newKeyDownEvent = false; - } - return true; - } - } - return false; + this->wireFrameModeOn(viewer->getSceneData()); } - case(osgGA::GUIEventAdapter::KEYUP): - { - if (ea.getKey()=='p') - { - _usePolytopeIntersector = !_usePolytopeIntersector; - if (_usePolytopeIntersector) - { - osg::notify(osg::NOTICE)<<"Using PolytopeIntersector"<wireFrameModeOff(viewer->getSceneData()); + } + else + { + keyFunctionMap::iterator itr = keyFuncMap.find(ea.getKey()); + if (itr != keyFuncMap.end()) { - keyFunctionMap::iterator itr = keyFuncMap.find(ea.getKey()); - if (itr != keyFuncMap.end() ) + if ( (*itr).second.keyState == KEY_UP ) { - (*itr).second.keyState = KEY_UP; + (*itr).second.keyState = KEY_DOWN; + newKeyDownEvent = true; } - - itr = keyUPFuncMap.find(ea.getKey()); - if (itr != keyUPFuncMap.end()) + if (newKeyDownEvent) { (*itr).second.keyFunction(); - return true; + newKeyDownEvent = false; } + return true; + } + } + return false; + } + case(osgGA::GUIEventAdapter::KEYUP): + { + if (ea.getKey()=='p') + { + _usePolytopeIntersector = !_usePolytopeIntersector; + if (_usePolytopeIntersector) + { + osg::notify(osg::NOTICE)<<"Using PolytopeIntersector"<getSceneData(); if (!scene) return; - osg::notify(osg::NOTICE)<getCamera()->getViewport(); - double mx = viewport->x() + (int)((double )viewport->width()*(ea.getXnormalized()*0.5+0.5)); - double my = viewport->y() + (int)((double )viewport->height()*(ea.getYnormalized()*0.5+0.5)); - - // half width, height. - double w = 5.0f; - double h = 5.0f; - picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::WINDOW, mx-w, my-h, mx+w, my+h ); - } else { - double mx = ea.getXnormalized(); - double my = ea.getYnormalized(); - double w = 0.05; - double h = 0.05; - picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx-w, my-h, mx+w, my+h ); - } - osgUtil::IntersectionVisitor iv(picker); - - viewer->getCamera()->accept(iv); - - if (picker->containsIntersections()) - { - for(std::multiset::iterator it = picker->getIntersections().begin(); - it != picker->getIntersections().end(); it++) - { - const osgUtil::PolytopeIntersector::Intersection &intersection = *it; - - /* - osg::notify(osg::NOTICE)<<"Picked "<=1)?nodePath[nodePath.size()-1]:0; - - //osg::Matrixd l2w = osg::computeLocalToWorld( nodePath ); - //osg::Vec3 global = *intersection.matrix.get() * intersection.localIntersectionPoint; - osg::Vec3 global = intersection.localIntersectionPoint * *intersection.matrix.get(); - - QVector3D globalPoint( global.x(), global.y(), global.z()); - emit picked(globalPoint); - } - } + //projection space is [-1 ... 1], thus we can directly use the normalized + //mouse coordinates + double mx = ea.getXnormalized(); + double my = ea.getYnormalized(); + double w = 0.01; + double h = 0.01; + osg::ref_ptr picker; + picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx-w, my-h, mx+w, my+h ); + picker->setIntersectionLimit(osgUtil::Intersector::LIMIT_ONE_PER_DRAWABLE);// a single drawable will appear at most once while calculating intersections. + + osgUtil::IntersectionVisitor iv(picker); + viewer->getCamera()->accept(iv); + + if (picker->containsIntersections()) + { + const osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection(); + const osg::NodePath& nodePath = intersection.nodePath; + osg::Vec3 global = intersection.localIntersectionPoint * *intersection.matrix.get(); + pickNodePath(nodePath, global, viewer); + } } else { - osgUtil::LineSegmentIntersector* picker; - if (!_useWindowCoordinates) - { - // use non dimensional coordinates - in projection/clip space - picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); - } else { - // use window coordinates - // remap the mouse x,y into viewport coordinates. - osg::Viewport* viewport = viewer->getCamera()->getViewport(); - float mx = viewport->x() + (int)((float)viewport->width()*(ea.getXnormalized()*0.5f+0.5f)); - float my = viewport->y() + (int)((float)viewport->height()*(ea.getYnormalized()*0.5f+0.5f)); - picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, mx, my ); - } - osgUtil::IntersectionVisitor iv(picker); - - viewer->getCamera()->accept(iv); - - if (picker->containsIntersections()) - { - osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); - - osg::NodePath& nodePath = intersection.nodePath; - node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0; - - // see if the object has a user object which is derived from pickcallback - PickedCallback *pc = dynamic_cast(node->getUserData()); - if( pc ) - pc->picked(); - - for(int i = nodePath.size()-1; i >= 0; i--) - { - osg::Node *node = nodePath[i]; - osg::Referenced *user_data = node->getUserData(); - if (!user_data) - continue; - PickedUserData *plugin_data = dynamic_cast(user_data); - if(!plugin_data) - continue; - - // Transform OSG viewport coordinates to QWidget coordinates (invert y axis) - float wy = (float)viewer->getCamera()->getViewport()->height() - _my; - float wx = _mx; - plugin_data->getPlugin()->click(wx, wy); - - osg::Vec3 global = intersection.localIntersectionPoint * *intersection.matrix.get(); - emit plugin_data->getPlugin()->picked(global.x(),global.y(),global.z()); - break; - } - // setTrackedNode(viewer, node); - } + osg::ref_ptr picker; + + // use non dimensional coordinates - in projection/clip space + picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); + // Using this setting, a single drawable will appear at most once while calculating intersections. + picker->setIntersectionLimit(osgUtil::Intersector::LIMIT_ONE_PER_DRAWABLE); + osgUtil::IntersectionVisitor iv(picker); + viewer->getCamera()->accept(iv); + + if (picker->containsIntersections()) + { + osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); + const osg::NodePath& nodePath = intersection.nodePath; + const osg::Vec3 global = intersection.localIntersectionPoint * *intersection.matrix.get(); + pickNodePath(nodePath, global, viewer); + } } } +void PickHandler::pickNodePath(const osg::NodePath& nodePath, osg::Vec3 global, + osgViewer::View* viewer) const +{ + if(nodePath.empty()) + return; + + osg::Node* node = nodePath[nodePath.size()-1]; + // see if the object has a user object which is derived from pickcallback + PickedCallback *pc = dynamic_cast(node->getUserData()); + if( pc ) + pc->picked(); + + for(int i = nodePath.size()-1; i >= 0; i--) + { + osg::Node *node = nodePath[i]; + osg::Referenced *user_data = node->getUserData(); + if (!user_data) + continue; + PickedUserData *plugin_data = dynamic_cast(user_data); + if(!plugin_data) + continue; + + // Transform OSG viewport coordinates to QWidget coordinates (invert y axis) + float wy = (float)viewer->getCamera()->getViewport()->height() - _my; + float wx = _mx; + plugin_data->getPlugin()->click(wx, wy); + emit plugin_data->getPlugin()->picked(global.x(),global.y(),global.z()); + break; + } + + const QVector3D globalPoint( global.x(), global.y(), global.z()); + emit picked(globalPoint); + emit pickedNodePath(nodePath); +} + void PickHandler::setTrackedNode(osgViewer::View* viewer, osg::ref_ptr< osg::Node > node) { osgGA::KeySwitchMatrixManipulator *keyswitchManipulator = diff --git a/src/PickHandler.hpp b/src/PickHandler.hpp index 1835d1a..4eba673 100644 --- a/src/PickHandler.hpp +++ b/src/PickHandler.hpp @@ -56,17 +56,24 @@ class PickHandler : public QObject, public osgGA::GUIEventHandler void pick(const osgGA::GUIEventAdapter& ea, osgViewer::View* viewer); signals: - void picked(const QVector3D& coord); + void picked(const QVector3D& coord) const; + /**Is emitted whenenver the user picks a node. + * @p path The path from the root node to the picked node*/ + void pickedNodePath(const osg::NodePath& path) const; protected: void setTrackedNode(osgViewer::View* viewer, osg::ref_ptr< osg::Node > node); + + /** @param nodePath NodePath to the picked node + * @param global global coordinates of the clicked point*/ + void pickNodePath(const osg::NodePath& nodePath, osg::Vec3 global, + osgViewer::View* viewer) const; void wireFrameModeOn(osg::Node *srcNode); void wireFrameModeOff(osg::Node *srcNode); float _mx,_my; bool _usePolytopeIntersector; - bool _useWindowCoordinates; typedef std::map keyFunctionMap; keyFunctionMap keyFuncMap; diff --git a/src/TransformerGraph.cpp b/src/TransformerGraph.cpp index c215629..c33d5e1 100644 --- a/src/TransformerGraph.cpp +++ b/src/TransformerGraph.cpp @@ -407,6 +407,13 @@ std::string TransformerGraph::getWorldName(const osg::Node &transformer) return std::string(transformer.getName()); } +void TransformerGraph::setWorldName(osg::Node &transformer, const std::string &name) +{ + transformer.setName(name); + osgText::Text* text = getFrameText(&transformer); + text->setText(name); +} + void TransformerGraph::setTextSize(osg::Node &transformer, float size) { TextSizeSetter::set(transformer, size); diff --git a/src/TransformerGraph.hpp b/src/TransformerGraph.hpp index d7e67ac..9a1784a 100644 --- a/src/TransformerGraph.hpp +++ b/src/TransformerGraph.hpp @@ -34,6 +34,11 @@ namespace vizkit3d */ static std::string getWorldName(const osg::Node &transformer); + /** + * Sets the name of the world (root) frame. + */ + static void setWorldName(osg::Node &transformer, const std::string &name); + /** * Sets the size of the frame annotations */ diff --git a/src/Vizkit3DPlugin.hpp b/src/Vizkit3DPlugin.hpp index 839e541..27aadf8 100644 --- a/src/Vizkit3DPlugin.hpp +++ b/src/Vizkit3DPlugin.hpp @@ -129,15 +129,15 @@ class VizPluginBase : public QObject */ Vizkit3DWidget* getWidget() const; - /** @return true if the plugins internal state has been updated */ - virtual bool isDirty() const; - /** mark the internal state as modified */ - void setDirty(); + /** @return true if the plugins internal state has been updated */ + virtual bool isDirty() const; + /** mark the internal state as modified */ + void setDirty(); - /** @return a pointer to the internal Group that is used to maintain the - * plugin's nodes */ - osg::ref_ptr getVizNode() const; - osg::ref_ptr getRootNode() const; + /** @return a pointer to the internal Group that is used to maintain the + * plugin's nodes */ + osg::ref_ptr getVizNode() const; + osg::ref_ptr getRootNode() const; /** * @return a vector of QDockWidgets provided by this class. @@ -155,8 +155,8 @@ class VizPluginBase : public QObject */ virtual void setPluginEnabled(bool enabled); - /** @return the name of the plugin */ - virtual const QString getPluginName() const; + /** @return the name of the plugin */ + virtual const QString getPluginName() const; virtual void setPluginName(const QString &name); /** @@ -176,11 +176,11 @@ class VizPluginBase : public QObject void setKeepOldData(bool value); bool isKeepOldDataEnabled(); - /** - * Clears the visualization of the plugin - * */ - virtual void clearVisualization(); - + /** + * Clears the visualization of the plugin + * */ + virtual void clearVisualization(); + /** * deletes all copies of the osg graph which were genereted by keepCurrentViz */ @@ -189,7 +189,7 @@ class VizPluginBase : public QObject int getMaxOldData()const {return max_old_data;}; void setMaxOldData(int value); - void setPose(const QVector3D &position, const QQuaternion &orientation); + void setPose(const QVector3D &position, const QQuaternion &orientation); /** Returns the list of available visualization frames * @@ -247,15 +247,15 @@ class VizPluginBase : public QObject void picked(float x, float y,float z); protected: - /** override this function to update the visualisation. - * @param node contains a point to the node which can be modified. - */ - virtual void updateMainNode(osg::Node* node) = 0; + /** override this function to update the visualisation. + * @param node contains a point to the node which can be modified. + */ + virtual void updateMainNode(osg::Node* node) = 0; - /** override this method to provide your own main node. - * @return node derived from osg::Group - */ - virtual osg::ref_ptr createMainNode(); + /** override this method to provide your own main node. + * @return node derived from osg::Group + */ + virtual osg::ref_ptr createMainNode(); /** override this method to provide your own QDockWidgets. * The QDockWidgets will automatically attached to the main window. @@ -267,19 +267,19 @@ class VizPluginBase : public QObject */ virtual osg::ref_ptr cloneCurrentViz(); - /** lock this mutex outside updateMainNode if you update the internal - * state of the visualization. - */ - boost::mutex updateMutex; + /** lock this mutex outside updateMainNode if you update the internal + * state of the visualization. + */ + boost::mutex updateMutex; std::vector dockWidgets; QString vizkit3d_plugin_name; VizPluginRubyAdapterCollection adapterCollection; private: - class CallbackAdapter; - osg::ref_ptr nodeCallback; - void updateCallback(osg::Node* node); + class CallbackAdapter; + osg::ref_ptr nodeCallback; + void updateCallback(osg::Node* node); osg::ref_ptr mainNode; //node which is used by the child class osg::ref_ptr rootNode; //node which is the osg root node of the pluign @@ -292,8 +292,8 @@ class VizPluginBase : public QObject //orientation of the viznode QQuaternion orientation; - bool isAttached; - bool dirty; + bool isAttached; + bool dirty; bool plugin_enabled; bool keep_old_data; unsigned int max_old_data; diff --git a/src/Vizkit3DWidget.cpp b/src/Vizkit3DWidget.cpp index 9148dc2..c5201b5 100644 --- a/src/Vizkit3DWidget.cpp +++ b/src/Vizkit3DWidget.cpp @@ -13,7 +13,6 @@ #include "Vizkit3DBase.hpp" #include "Vizkit3DWidget.hpp" #include "Vizkit3DPlugin.hpp" -#include "PickHandler.hpp" #include "QPropertyBrowserWidget.hpp" #include "AxesNode.hpp" #include "OsgVisitors.hpp" @@ -35,6 +34,8 @@ #include #include #include +#include +#include using namespace vizkit3d; using namespace std; @@ -205,7 +206,7 @@ void Vizkit3DConfig::setCameraManipulator(QStringList const& manipulator) Vizkit3DWidget::Vizkit3DWidget( QWidget* parent,const QString &world_name,bool auto_update) : QWidget(parent) - , env_plugin(NULL) + , env_plugin(NULL), pickHandler(new PickHandler()) { //create layout //objects will be owned by the parent widget (this) @@ -231,6 +232,16 @@ Vizkit3DWidget::Vizkit3DWidget( QWidget* parent,const QString &world_name,bool a // create root scene node root = createSceneGraph(world_name); + + //create geode that will be used as marker for the current selection + selectorGeode = new osg::Geode(); + osg::ShapeDrawable* sphere = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(), 0.2f)); + sphere->setColor(osg::Vec4(1.0f, 0.0f, 0.0f, 0.3f)); + sphere->getOrCreateStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON); + selectorGeode->addDrawable(sphere); + osg::StateSet* set = selectorGeode->getOrCreateStateSet(); + set->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + set->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA ,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON); // create osg widget QWidget* widget = addViewWidget(createGraphicsWindow(0,0,800,600), root); @@ -252,7 +263,8 @@ Vizkit3DWidget::Vizkit3DWidget( QWidget* parent,const QString &world_name,bool a //connect signals and slots connect(this, SIGNAL(addPlugins(QObject*,QObject*)), this, SLOT(addPluginIntern(QObject*,QObject*))); connect(this, SIGNAL(removePlugins(QObject*)), this, SLOT(removePluginIntern(QObject*))); - connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) ); + connect(&_timer, SIGNAL(timeout()), this, SLOT(update()) ); + connect(pickHandler.get(), SIGNAL(pickedNodePath(const osg::NodePath&)), this, SLOT(pickNodePath(const osg::NodePath&))); current_frame = QString(root->getName().c_str()); @@ -362,8 +374,7 @@ QWidget* Vizkit3DWidget::addViewWidget( osgQt::GraphicsWindowQt* gw, ::osg::Node setCameraManipulator(TERRAIN_MANIPULATOR); // pickhandler is for selecting objects in the opengl view - PickHandler* pickHandler = new PickHandler(); - view->addEventHandler(pickHandler); + view->addEventHandler(pickHandler.get()); return gw->getGLWidget(); } @@ -889,6 +900,13 @@ void Vizkit3DWidget::setTransformation(const QString &source_frame,const QString TransformerGraph::makeRoot(*getRootNode(), root_frame.toStdString()); } +void Vizkit3DWidget::removeFrame(const QString& frame) +{ + const bool worked = TransformerGraph::removeFrame(*getRootNode(), frame.toStdString()); + if(!worked) + std::cerr << "WARN: Unable to remove frame " << frame.toStdString() << std::endl; +} + void Vizkit3DWidget::setRootFrame(QString frame) { TransformerGraph::makeRoot(*getRootNode(), frame.toStdString()); @@ -908,6 +926,24 @@ QString Vizkit3DWidget::getWorldName()const return QString(TransformerGraph::getWorldName(*getRootNode()).c_str()); } +void Vizkit3DWidget::setWorldName(const QString& name) +{ + const QString oldWorldName = getWorldName(); + TransformerGraph::setWorldName(*getRootNode(), name.toStdString()); + PluginMap::iterator it = plugins.begin(); + + //find all plugins that use the old world name as visualization frame + //and update them. Otherwise the old world name might be re-added when + //setting transformations + for(;it != plugins.end();++it) + { + if(it->first->getVisualizationFrame() == oldWorldName) + { + it->first->setVisualizationFrame(name); + } + } +} + bool Vizkit3DWidget::isTransformer() const { return TransformerGraph::areFrameAnnotationVisible(*getRootNode()); @@ -1060,19 +1096,19 @@ QObject* Vizkit3DWidget::loadPlugin(QString lib_name,QString plugin_name) QStringList plugin_strings = lib_name.split("@"); if(plugin_strings.size() == 2) { - lib_name = plugin_strings.at(0); - plugin_name = plugin_strings.at(1); + plugin_name = plugin_strings.at(0); + lib_name = plugin_strings.at(1); } //if no lib_name is given try to find it from plugin_name if(lib_name.isEmpty() && !plugin_name.isEmpty()) lib_name = findPluginPath(plugin_name); - + //check if the lib name is a path QFileInfo file_info(lib_name); QString path; if(file_info.isFile()) - path = file_info.absolutePath(); + path = file_info.absoluteFilePath(); else path = findLibPath(lib_name); @@ -1190,3 +1226,72 @@ void Vizkit3DWidget::setCameraManipulator(CAMERA_MANIPULATORS manipulatorType, b } } +void Vizkit3DWidget::pickNodePath(const osg::NodePath& path) +{ + for(int i = 0; i < path.size(); ++i) + { + std::cout << path[i]->className() << " | " << path[i]->getName() << std::endl; + } + + const osg::Node* clickedNode = path.back(); + + //ignore links created by the transformer graph. + //if the user clicks on a link, nothing happens + if(strcmp(clickedNode->className(), "Geode") == 0 && clickedNode->getName() == "link") + { + return; + } + + //FIXME handle plugins as well + //walk backwards in the graph structure and search for the first interessting + //node + for(int i = path.size() - 1; i >= 0; --i) + { + const osg::Node* node = path[i]; + + //check if it is a plugin + const PickedUserData* plugin_data = dynamic_cast(node->getUserData()); + if(plugin_data != NULL) + { + //FIXME maybe emit something + } + + //check if it is a frame + if(strcmp(node->className(), "PositionAttitudeTransform") == 0 && + TransformerGraph::hasFrame(*getRootNode(), node->getName())) + { + emit framePicked(QString::fromStdString(node->getName())); + break; + } + } +} + +void Vizkit3DWidget::setFrameHighlight(const QString& frame, const bool highlight) +{ + osg::ref_ptr group = TransformerGraph::getFrameGroup(*getRootNode(), frame.toStdString()); + if(group == NULL) + throw std::runtime_error("Cannot un/highlight frame " + frame.toStdString() + ". Frame doesn't exist."); + + if(highlight) + group->addChild(selectorGeode); + else + group->removeChild(selectorGeode); +} + +void Vizkit3DWidget::clear() +{ + //remove plugins, while loop because removing invalidates iterators + while(plugins.size() > 0) + { + removePlugin(plugins.begin()->first); + } + + //remove frames + const std::vector frames = TransformerGraph::getFrameNames(*getRootNode()); + for(unsigned i = 0; i < frames.size(); ++i) + { + //removeFrame internally skips the world frame + TransformerGraph::removeFrame(*getRootNode(), frames[i]); + } +} + diff --git a/src/Vizkit3DWidget.hpp b/src/Vizkit3DWidget.hpp index 5f7eae1..b884196 100644 --- a/src/Vizkit3DWidget.hpp +++ b/src/Vizkit3DWidget.hpp @@ -2,6 +2,7 @@ #define __VIZKIT_QVIZKITWIDGET__ #include "Vizkit3DPlugin.hpp" +#include "PickHandler.hpp" #include #include @@ -242,12 +243,18 @@ namespace vizkit3d /** Require the given frame to be directly attached to the root */ void setRootFrame(QString frame); - + + /*Removes all plugins and all frames except the world frame.*/ + void clear(); + // we have to use a pointer here otherwise qt ruby is crashing QStringList* getVisualizationFramesRuby() const; QStringList getVisualizationFrames() const; QString getVisualizationFrame() const; - + + /**Highlight the given frame*/ + void setFrameHighlight(const QString& frame, const bool highlight); + /** * Sets frame plugin data for a given plugin. * The pluging data frame is the frame in which the @@ -261,6 +268,10 @@ namespace vizkit3d const QVector3D &position, const QQuaternion &orientation); void getTransformation(const QString &source_frame,const QString &target_frame, QVector3D &position, QQuaternion &orientation)const; QString getWorldName()const; + void setWorldName(const QString& name); + + /**Removes @p frame from the visualization */ + void removeFrame(const QString& frame); void setCameraLookAt(double x, double y, double z); void setCameraEye(double x, double y, double z); @@ -349,11 +360,15 @@ namespace vizkit3d * remove the plugin itself */ void clearEnvironmentPlugin(); - + + signals: void addPlugins(QObject* plugin,QObject* parent); void removePlugins(QObject* plugin); void propertyChanged(QString propertyName); + + /**Emitted when the user picks (clicks on) a frame */ + void framePicked(const QString& frame) const; protected: virtual void paintEvent( QPaintEvent* event ); @@ -365,6 +380,7 @@ namespace vizkit3d void pluginActivityChanged(bool enabled); void pluginChildrenChanged(); void addProperties(QObject* plugin,QObject *parent=NULL); + void pickNodePath(const osg::NodePath& path); private: // Helper method for setPluginEnabled @@ -418,6 +434,10 @@ namespace vizkit3d osg::ref_ptr captureHandler; osg::ref_ptr captureOperation; + + //geode used to mark the currently highlighted node + osg::ref_ptr selectorGeode; + osg::ref_ptr pickHandler; }; } #endif