diff --git a/src/Canvas/canvas_mgr.cxx b/src/Canvas/canvas_mgr.cxx index b57dcaeb9..29a1228bc 100644 --- a/src/Canvas/canvas_mgr.cxx +++ b/src/Canvas/canvas_mgr.cxx @@ -50,7 +50,8 @@ static sc::Placements addSceneObjectPlacement( SGPropertyNode* placement, model_data->getNode(), placement, canvas->getTexture(), - canvas->getCullCallback() + canvas->getCullCallback(), + canvas ); } @@ -76,7 +77,8 @@ CanvasMgr::CanvasMgr(): &FGODGauge::set_aircraft_texture, _1, boost::bind(&sc::Canvas::getTexture, _2), - boost::bind(&sc::Canvas::getCullCallback, _2) + boost::bind(&sc::Canvas::getCullCallback, _2), + _2 ) ); diff --git a/src/Canvas/gui_mgr.cxx b/src/Canvas/gui_mgr.cxx index 91424d9b2..e76571e3a 100644 --- a/src/Canvas/gui_mgr.cxx +++ b/src/Canvas/gui_mgr.cxx @@ -294,8 +294,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) return false; namespace sc = simgear::canvas; - sc::MouseEventPtr event(new sc::MouseEvent); - event->time = ea.getTime(); + sc::MouseEventPtr event(new sc::MouseEvent(ea)); event->screen_pos.x() = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5; event->screen_pos.y() = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5; @@ -310,9 +309,6 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) _last_y = event->getScreenY(); event->client_pos = event->screen_pos; - event->button = ea.getButton(); - event->state = ea.getButtonMask(); - event->mod = ea.getModKeyMask(); if( !_resize_window.expired() ) { diff --git a/src/Cockpit/od_gauge.cxx b/src/Cockpit/od_gauge.cxx index ff26b8f0c..f2343a0aa 100644 --- a/src/Cockpit/od_gauge.cxx +++ b/src/Cockpit/od_gauge.cxx @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -45,6 +44,7 @@ #include +#include #include #include @@ -86,12 +86,15 @@ class ReplaceStaticTextureVisitor: osg::Texture2D* new_texture ): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _tex_name( osgDB::getSimpleFileName(name) ), - _new_texture(new_texture) + _new_texture(new_texture), + _cull_callback(0) {} ReplaceStaticTextureVisitor( SGPropertyNode* placement, osg::Texture2D* new_texture, - osg::NodeCallback* cull_callback = 0 ): + osg::NodeCallback* cull_callback = 0, + const simgear::canvas::CanvasWeakPtr& canvas = + simgear::canvas::CanvasWeakPtr() ): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _tex_name( osgDB::getSimpleFileName( placement->getStringValue("texture")) @@ -100,7 +103,8 @@ class ReplaceStaticTextureVisitor: _parent_name( placement->getStringValue("parent") ), _node(placement), _new_texture(new_texture), - _cull_callback(cull_callback) + _cull_callback(cull_callback), + _canvas(canvas) { if( _tex_name.empty() && _node_name.empty() @@ -200,7 +204,7 @@ class ReplaceStaticTextureVisitor: osg::StateAttribute::ON ); _placements.push_back( simgear::canvas::PlacementPtr( - new ObjectPlacement(_node, group) + new simgear::canvas::ObjectPlacement(_node, group, _canvas) )); SG_LOG @@ -218,77 +222,6 @@ class ReplaceStaticTextureVisitor: protected: - class ObjectPlacement: - public simgear::canvas::Placement - { - public: - - ObjectPlacement( SGPropertyNode* node, - GroupPtr group ): - Placement(node), - _group(group) - { - // TODO make more generic and extendable for more properties - if( node->hasValue("emission") ) - setEmission( node->getFloatValue("emission") ); - } - - virtual bool childChanged(SGPropertyNode* node) - { - if( node->getParent() != _node ) - return false; - - if( node->getNameString() == "emission" ) - setEmission( node->getFloatValue() ); - else - return false; - - return true; - } - - void setEmission(float emit) - { - emit = SGMiscf::clip(emit, 0, 1); - - if( !_material ) - { - _material = new osg::Material; - _material->setColorMode(osg::Material::OFF); - _material->setDataVariance(osg::Object::DYNAMIC); - _group->getOrCreateStateSet() - ->setAttribute(_material, ( osg::StateAttribute::ON - | osg::StateAttribute::OVERRIDE ) ); - } - - _material->setEmission( - osg::Material::FRONT_AND_BACK, - osg::Vec4(emit, emit, emit, emit) - ); - } - - /** - * Remove placement from the scene - */ - virtual ~ObjectPlacement() - { - assert( _group->getNumChildren() == 1 ); - osg::Node *child = _group->getChild(0); - - if( _group->getNumParents() ) - { - osg::Group *parent = _group->getParent(0); - parent->addChild(child); - parent->removeChild(_group); - } - - _group->removeChild(child); - } - - private: - GroupPtr _group; - MaterialPtr _material; - }; - std::string _tex_name, ///accept(visitor); return visitor.getPlacements(); } @@ -341,13 +279,15 @@ FGODGauge::set_texture( osg::Node* branch, simgear::canvas::Placements FGODGauge::set_aircraft_texture( SGPropertyNode* placement, osg::Texture2D* new_texture, - osg::NodeCallback* cull_callback ) + osg::NodeCallback* cull_callback, + const simgear::canvas::CanvasWeakPtr& canvas ) { return set_texture ( globals->get_scenery()->get_aircraft_branch(), placement, new_texture, - cull_callback + cull_callback, + canvas ); } diff --git a/src/Cockpit/od_gauge.hxx b/src/Cockpit/od_gauge.hxx index 257865194..e819a8e3b 100644 --- a/src/Cockpit/od_gauge.hxx +++ b/src/Cockpit/od_gauge.hxx @@ -86,7 +86,9 @@ class FGODGauge: set_texture( osg::Node* branch, SGPropertyNode* placement, osg::Texture2D* new_texture, - osg::NodeCallback* cull_callback = 0 ); + osg::NodeCallback* cull_callback = 0, + const simgear::canvas::CanvasWeakPtr& canvas = + simgear::canvas::CanvasWeakPtr() ); /** * Replace an opengl texture name inside the aircraft scene graph. @@ -101,7 +103,9 @@ class FGODGauge: simgear::canvas::Placements set_aircraft_texture( SGPropertyNode* placement, osg::Texture2D* new_texture, - osg::NodeCallback* cull_callback = 0 ); + osg::NodeCallback* cull_callback = 0, + const simgear::canvas::CanvasWeakPtr& canvas = + simgear::canvas::CanvasWeakPtr() ); }; diff --git a/src/Input/FGMouseInput.cxx b/src/Input/FGMouseInput.cxx index ffd9c9e15..218b3342b 100644 --- a/src/Input/FGMouseInput.cxx +++ b/src/Input/FGMouseInput.cxx @@ -49,13 +49,19 @@ using std::ios_base; const int MAX_MICE = 1; const int MAX_MOUSE_BUTTONS = 8; +typedef std::vector SGSceneryPicks; +typedef SGSharedPtr SGPickCallbackPtr; +typedef std::list SGPickCallbackList; + //////////////////////////////////////////////////////////////////////// /** * List of currently pressed mouse button events */ -class ActivePickCallbacks : public std::map > > { -public: +class ActivePickCallbacks: + public std::map +{ + public: void update( double dt, unsigned int keyModState ); void init( int button, const osgGA::GUIEventAdapter* ea ); }; @@ -71,14 +77,14 @@ void ActivePickCallbacks::init( int button, const osgGA::GUIEventAdapter* ea ) // That is they get sorted by distance and by scenegraph depth. // The nearest one is the first one and the deepest // (the most specialized one in the scenegraph) is the first. - std::vector pickList; + SGSceneryPicks pickList; if (!globals->get_renderer()->pick(pickList, windowPos)) { return; } - std::vector::const_iterator i; + SGSceneryPicks::const_iterator i; for (i = pickList.begin(); i != pickList.end(); ++i) { - if (i->callback->buttonPressed(button, ea, i->info)) { + if (i->callback->buttonPressed(button, *ea, i->info)) { (*this)[button].push_back(i->callback); return; } @@ -89,7 +95,7 @@ void ActivePickCallbacks::update( double dt, unsigned int keyModState ) { // handle repeatable mouse press events for( iterator mi = begin(); mi != end(); ++mi ) { - std::list >::iterator li; + SGPickCallbackList::iterator li; for (li = mi->second.begin(); li != mi->second.end(); ++li) { (*li)->update(dt, keyModState); } @@ -130,6 +136,18 @@ struct mouse { mouse_mode * modes; }; +static +const SGSceneryPick* +getPick( const SGSceneryPicks& pick_list, + const SGPickCallback* cb ) +{ + for(size_t i = 0; i < pick_list.size(); ++i) + if( pick_list[i].callback == cb ) + return &pick_list[i]; + + return 0; +} + //////////////////////////////////////////////////////////////////////// class FGMouseInput::FGMouseInputPrivate : public SGPropertyChangeListener @@ -197,37 +215,44 @@ public: void doHoverPick(const osg::Vec2d& windowPos) { - std::vector pickList; - SGPickCallback::Priority priority = SGPickCallback::PriorityScenery; - FGMouseCursor::Cursor cur = FGMouseCursor::CURSOR_ARROW; bool explicitCursor = false; bool didPick = false; - - if (globals->get_renderer()->pick(pickList, windowPos)) { + + SGPickCallback::Priority priority = SGPickCallback::PriorityScenery; + SGSceneryPicks pickList; + globals->get_renderer()->pick(pickList, windowPos); + + SGSceneryPicks::const_iterator i; + for( i = pickList.begin(); i != pickList.end(); ++i ) + { + bool done = i->callback->hover(windowPos, i->info); + std::string curName(i->callback->getCursor()); + if (!curName.empty()) { + explicitCursor = true; + cur = FGMouseCursor::cursorFromString(curName.c_str()); + } - std::vector::const_iterator i; - for (i = pickList.begin(); i != pickList.end(); ++i) { - bool done = i->callback->hover(windowPos, i->info); - std::string curName(i->callback->getCursor()); - if (!curName.empty()) { - explicitCursor = true; - cur = FGMouseCursor::cursorFromString(curName.c_str()); - } - // if the callback is of higher prioirty (lower enum index), // record that. - if (i->callback->getPriority() < priority) { - priority = i->callback->getPriority(); - } - - if (done) { - didPick = true; - break; - } - } // of picks iteration - } else { // of have valid pick + if (i->callback->getPriority() < priority) { + priority = i->callback->getPriority(); + } + + if (done) { + didPick = true; + break; + } + } // of picks iteration + + // Check if any pick from the previous iteration has disappeared. If so + // notify the callback that the mouse has left its element. + for( i = _previous_picks.begin(); i != _previous_picks.end(); ++i ) + { + if( !getPick(pickList, i->callback) ) + i->callback->mouseLeave(windowPos); } + _previous_picks = pickList; if (!explicitCursor && (priority == SGPickCallback::PriorityPanel)) { cur = FGMouseCursor::CURSOR_HAND; @@ -245,12 +270,27 @@ public: { FGMouseCursor::Cursor cur = FGMouseCursor::CURSOR_CLOSED_HAND; - BOOST_FOREACH(SGPickCallback* cb, activePickCallbacks[0]) { - cb->mouseMoved(ea); - std::string curName(cb->getCursor()); - if (!curName.empty()) { - cur = FGMouseCursor::cursorFromString(curName.c_str()); - } + osg::Vec2d windowPos; + flightgear::eventToWindowCoords(ea, windowPos.x(), windowPos.y()); + + SGSceneryPicks pickList; + if( !globals->get_renderer()->pick(pickList, windowPos) ) + return; + + for( ActivePickCallbacks::iterator mi = activePickCallbacks.begin(); + mi != activePickCallbacks.end(); + ++mi ) + { + SGPickCallbackList::iterator li; + for( li = mi->second.begin(); li != mi->second.end(); ++li ) + { + const SGSceneryPick* pick = getPick(pickList, *li); + (*li)->mouseMoved(*ea, pick ? &pick->info : 0); + + std::string curName((*li)->getCursor()); + if( !curName.empty() ) + cur = FGMouseCursor::cursorFromString(curName.c_str()); + } } FGMouseCursor::instance()->setCursor(cur); @@ -278,6 +318,7 @@ public: } ActivePickCallbacks activePickCallbacks; + SGSceneryPicks _previous_picks; mouse mice[MAX_MICE]; @@ -513,12 +554,26 @@ void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindo // requested, and return if one of // them consumes the event. - if (updown != MOUSE_BUTTON_DOWN) { + osg::Vec2d windowPos; + flightgear::eventToWindowCoords(ea, windowPos.x(), windowPos.y()); + + SGSceneryPicks pickList; + globals->get_renderer()->pick(pickList, windowPos); + + if( updown != MOUSE_BUTTON_DOWN ) + { // Execute the mouse up event in any case, may be we should // stop processing here? - while (!d->activePickCallbacks[b].empty()) { - d->activePickCallbacks[b].front()->buttonReleased(ea->getModKeyMask()); - d->activePickCallbacks[b].pop_front(); + + SGPickCallbackList& callbacks = d->activePickCallbacks[b]; + + while( !callbacks.empty() ) + { + SGPickCallbackPtr& cb = callbacks.front(); + const SGSceneryPick* pick = getPick(pickList, cb); + cb->buttonReleased(ea->getModKeyMask(), *ea, pick ? &pick->info : 0); + + callbacks.pop_front(); } } @@ -540,8 +595,6 @@ void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindo } } else { // do a hover pick now, to fix up cursor - osg::Vec2d windowPos; - flightgear::eventToWindowCoords(ea, windowPos.x(), windowPos.y()); d->doHoverPick(windowPos); } // mouse button was released } // of pass-through mode diff --git a/src/Viewer/renderer.cxx b/src/Viewer/renderer.cxx index 2584df141..6dcfd3159 100644 --- a/src/Viewer/renderer.cxx +++ b/src/Viewer/renderer.cxx @@ -1723,6 +1723,62 @@ FGRenderer::resize( int width, int height ) } } +typedef osgUtil::LineSegmentIntersector::Intersection Intersection; +SGVec2d uvFromIntersection(const Intersection& hit) +{ + // Taken from http://trac.openscenegraph.org/projects/osg/browser/OpenSceneGraph/trunk/examples/osgmovie/osgmovie.cpp + + osg::Drawable* drawable = hit.drawable.get(); + osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0; + osg::Vec3Array* vertices = + geometry ? dynamic_cast(geometry->getVertexArray()) : 0; + + if( !vertices ) + { + SG_LOG(SG_INPUT, SG_WARN, "Unable to get vertices for intersection."); + return SGVec2d(-9999,-9999); + } + + // get the vertex indices. + const Intersection::IndexList& indices = hit.indexList; + const Intersection::RatioList& ratios = hit.ratioList; + + if( indices.size() != 3 || ratios.size() != 3 ) + { + SG_LOG( SG_INPUT, + SG_WARN, + "Intersection has insufficient indices to work with." ); + return SGVec2d(-9999,-9999); + } + + unsigned int i1 = indices[0]; + unsigned int i2 = indices[1]; + unsigned int i3 = indices[2]; + + float r1 = ratios[0]; + float r2 = ratios[1]; + float r3 = ratios[2]; + + osg::Array* texcoords = + (geometry->getNumTexCoordArrays() > 0) ? geometry->getTexCoordArray(0) : 0; + osg::Vec2Array* texcoords_Vec2Array = + dynamic_cast(texcoords); + + if( !texcoords_Vec2Array ) + { + SG_LOG(SG_INPUT, SG_WARN, "Unable to get texcoords for intersection."); + return SGVec2d(-9999,-9999); + } + + // we have tex coord array so now we can compute the final tex coord at the + // point of intersection. + osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1]; + osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2]; + osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3]; + + return toSG( osg::Vec2d(tc1 * r1 + tc2 * r2 + tc3 * r3) ); +} + bool FGRenderer::pick(std::vector& pickList, const osg::Vec2& windowPos) { @@ -1750,6 +1806,10 @@ FGRenderer::pick(std::vector& pickList, const osg::Vec2& windowPo SGSceneryPick sceneryPick; sceneryPick.info.local = toSG(hit->getLocalIntersectPoint()); sceneryPick.info.wgs84 = toSG(hit->getWorldIntersectPoint()); + + if( pickCallback->needsUV() ) + sceneryPick.info.uv = uvFromIntersection(*hit); + sceneryPick.callback = pickCallback; pickList.push_back(sceneryPick); }