| 102 | | // End of glue classes to adapter Producer's keyboard mouse events to osgGA's abstraction events. |
| 103 | | |
| | 103 | // ----------- End of glue classes to adapter Producer's keyboard mouse events to osgGA's abstraction events. |
| | 104 | |
| | 105 | |
| | 106 | class CreateModelToSaveVisitor : public osg::NodeVisitor |
| | 107 | { |
| | 108 | public: |
| | 109 | |
| | 110 | CreateModelToSaveVisitor(): |
| | 111 | osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) |
| | 112 | { |
| | 113 | _group = new osg::Group; |
| | 114 | _addToModel = false; |
| | 115 | } |
| | 116 | |
| | 117 | virtual void apply(osg::Node& node) |
| | 118 | { |
| | 119 | osgFX::Scribe* scribe = dynamic_cast<osgFX::Scribe*>(&node); |
| | 120 | if (scribe) |
| | 121 | { |
| | 122 | for(unsigned int i=0; i<scribe->getNumChildren(); ++i) |
| | 123 | { |
| | 124 | _group->addChild(scribe->getChild(i)); |
| | 125 | } |
| | 126 | } |
| | 127 | else |
| | 128 | { |
| | 129 | traverse(node); |
| | 130 | } |
| | 131 | } |
| | 132 | |
| | 133 | osg::ref_ptr<osg::Group> _group; |
| | 134 | bool _addToModel; |
| | 135 | }; |
| | 136 | |
| | 137 | // class to handle events with a pick |
| | 138 | class PickHandler : public osgGA::GUIEventHandler { |
| | 139 | public: |
| | 140 | |
| | 141 | PickHandler(osgUtil::SceneView* sceneView): |
| | 142 | _sceneView(sceneView), |
| | 143 | _mx(0.0),_my(0.0) {} |
| | 144 | |
| | 145 | ~PickHandler() {} |
| | 146 | |
| | 147 | bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&) |
| | 148 | { |
| | 149 | switch(ea.getEventType()) |
| | 150 | { |
| | 151 | case(osgGA::GUIEventAdapter::KEYUP): |
| | 152 | { |
| | 153 | if (ea.getKey()=='s') |
| | 154 | { |
| | 155 | saveSelectedModel(); |
| | 156 | } |
| | 157 | return false; |
| | 158 | } |
| | 159 | case(osgGA::GUIEventAdapter::PUSH): |
| | 160 | case(osgGA::GUIEventAdapter::MOVE): |
| | 161 | { |
| | 162 | _mx = ea.getX(); |
| | 163 | _my = ea.getY(); |
| | 164 | return false; |
| | 165 | } |
| | 166 | case(osgGA::GUIEventAdapter::RELEASE): |
| | 167 | { |
| | 168 | if (_mx == ea.getX() && _my == ea.getY()) |
| | 169 | { |
| | 170 | // only do a pick if the mouse hasn't moved |
| | 171 | pick(ea); |
| | 172 | } |
| | 173 | return true; |
| | 174 | } |
| | 175 | |
| | 176 | default: |
| | 177 | return false; |
| | 178 | } |
| | 179 | } |
| | 180 | |
| | 181 | void pick(const osgGA::GUIEventAdapter& ea) |
| | 182 | { |
| | 183 | |
| | 184 | osg::Node* scene = _sceneView.valid() ? _sceneView->getSceneData() : 0; |
| | 185 | if (!scene) return; |
| | 186 | |
| | 187 | // remap the mouse x,y into viewport coordinates. |
| | 188 | |
| | 189 | float mx = _sceneView->getViewport()->x() + (int)((float)_sceneView->getViewport()->width()*(ea.getXnormalized()*0.5f+0.5f)); |
| | 190 | float my = _sceneView->getViewport()->y() + (int)((float)_sceneView->getViewport()->height()*(ea.getYnormalized()*0.5f+0.5f)); |
| | 191 | |
| | 192 | // do the pick traversal. |
| | 193 | osgUtil::PickVisitor pick(_sceneView->getViewport(), |
| | 194 | _sceneView->getProjectionMatrix(), |
| | 195 | _sceneView->getViewMatrix(), mx, my); |
| | 196 | scene->accept(pick); |
| | 197 | |
| | 198 | osgUtil::PickVisitor::LineSegmentHitListMap& segHitList = pick.getSegHitList(); |
| | 199 | if (!segHitList.empty() && !segHitList.begin()->second.empty()) |
| | 200 | { |
| | 201 | std::cout<<"Got hits"<<std::endl; |
| | 202 | |
| | 203 | // get the hits for the first segment |
| | 204 | osgUtil::PickVisitor::HitList& hits = segHitList.begin()->second; |
| | 205 | |
| | 206 | // just take the first hit - nearest the eye point. |
| | 207 | osgUtil::Hit& hit = hits.front(); |
| | 208 | |
| | 209 | osg::NodePath& nodePath = hit._nodePath; |
| | 210 | osg::Node* node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0; |
| | 211 | osg::Group* parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0; |
| | 212 | |
| | 213 | if (node) std::cout<<" Hits "<<node->className()<<" nodePath size"<<nodePath.size()<<std::endl; |
| | 214 | |
| | 215 | // now we try to decorate the hit node by the osgFX::Scribe to show that its been "picked" |
| | 216 | if (parent && node) |
| | 217 | { |
| | 218 | |
| | 219 | std::cout<<" parent "<<parent->className()<<std::endl; |
| | 220 | |
| | 221 | osgFX::Scribe* parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent); |
| | 222 | if (!parentAsScribe) |
| | 223 | { |
| | 224 | // node not already picked, so highlight it with an osgFX::Scribe |
| | 225 | osgFX::Scribe* scribe = new osgFX::Scribe(); |
| | 226 | scribe->addChild(node); |
| | 227 | parent->replaceChild(node,scribe); |
| | 228 | } |
| | 229 | else |
| | 230 | { |
| | 231 | // node already picked so we want to remove scribe to unpick it. |
| | 232 | osg::Node::ParentList parentList = parentAsScribe->getParents(); |
| | 233 | for(osg::Node::ParentList::iterator itr=parentList.begin(); |
| | 234 | itr!=parentList.end(); |
| | 235 | ++itr) |
| | 236 | { |
| | 237 | (*itr)->replaceChild(parentAsScribe,node); |
| | 238 | } |
| | 239 | } |
| | 240 | } |
| | 241 | |
| | 242 | } |
| | 243 | } |
| | 244 | |
| | 245 | void saveSelectedModel() |
| | 246 | { |
| | 247 | CreateModelToSaveVisitor cmtsv; |
| | 248 | _sceneView->getSceneData()->accept(cmtsv); |
| | 249 | |
| | 250 | if (cmtsv._group->getNumChildren()>0) |
| | 251 | { |
| | 252 | std::cout<<"Writing selected compoents to 'selected_model.osg'"<<std::endl; |
| | 253 | osgDB::writeNodeFile(*cmtsv._group, "selected_model.osg"); |
| | 254 | } |
| | 255 | } |
| | 256 | |
| | 257 | protected: |
| | 258 | |
| | 259 | osg::observer_ptr<osgUtil::SceneView> _sceneView; |
| | 260 | float _mx,_my; |
| | 261 | }; |