]> git.mxchange.org Git - flightgear.git/commitdiff
Modified Files:
authorfrohlich <frohlich>
Thu, 4 Jan 2007 13:22:27 +0000 (13:22 +0000)
committerfrohlich <frohlich>
Thu, 4 Jan 2007 13:22:27 +0000 (13:22 +0000)
src/Cockpit/panel.cxx src/Cockpit/panel.hxx
  src/Cockpit/panel_io.cxx src/GUI/dialog.cxx src/GUI/dialog.hxx
src/GUI/menubar.cxx src/GUI/menubar.hxx src/GUI/new_gui.hxx
src/Input/input.cxx src/Input/input.hxx src/Main/renderer.cxx
src/Scenery/scenery.cxx src/Scenery/scenery.hxx:
Use SGBinding instead of FGBinding. Remove FGBinding. Install hooks
to make the pick animation work.

13 files changed:
src/Cockpit/panel.cxx
src/Cockpit/panel.hxx
src/Cockpit/panel_io.cxx
src/GUI/dialog.cxx
src/GUI/dialog.hxx
src/GUI/menubar.cxx
src/GUI/menubar.hxx
src/GUI/new_gui.hxx
src/Input/input.cxx
src/Input/input.hxx
src/Main/renderer.cxx
src/Scenery/scenery.cxx
src/Scenery/scenery.hxx

index 90ee33b1d15659e1eec96db5a03a36d0ee497eae..68151bcb7046598a8f448519fb4917c5ef5d4776 100644 (file)
@@ -661,7 +661,7 @@ FGPanelAction::~FGPanelAction ()
 }
 
 void
-FGPanelAction::addBinding (FGBinding * binding, int updown)
+FGPanelAction::addBinding (SGBinding * binding, int updown)
 {
   _bindings[updown].push_back(binding);
 }
index 81f7bc3a83c59dfe7171671db5cf9cda2e17e35c..0eb883ddb8a69ee00f90f0ab17ddbaa72d4df867 100644 (file)
@@ -250,7 +250,7 @@ public:
                                // Setters.
 
                                // transfer pointer ownership
-  virtual void addBinding (FGBinding * binding, int updown);
+  virtual void addBinding (SGBinding * binding, int updown);
   virtual void setButton (int button) { _button = button; }
   virtual void setX (int x) { _x = x; }
   virtual void setY (int y) { _y = y; }
@@ -271,7 +271,7 @@ public:
   virtual bool doAction (int updown);
 
 private:
-  typedef vector<FGBinding *> binding_list_t;
+  typedef vector<SGBinding *> binding_list_t;
 
   int _button;
   int _x;
index 64c94f496b1fedcbb0c18b3a98b9dba88aa812a2..95781b9373a6c9453e5d6badc23a6f9fa6f097dc 100644 (file)
@@ -178,7 +178,7 @@ readAction (const SGPropertyNode * node, float w_scale, float h_scale)
   // button-less actions are fired initially
   if (!node->hasValue("w") || !node->hasValue("h")) {
     for (i = 0; i < bindings.size(); i++) {
-      FGBinding b(bindings[i]);
+      SGBinding b(bindings[i], globals->get_props());
       b.fire();
     }
     return 0;
@@ -207,7 +207,7 @@ readAction (const SGPropertyNode * node, float w_scale, float h_scale)
 
     binding = dest->getChild("binding", j, true);
     copyProperties(bindings[i], binding);
-    action->addBinding(new FGBinding(binding), 0);
+    action->addBinding(new SGBinding(binding, globals->get_props()), 0);
   }
 
   if (node->hasChild("mod-up")) {
@@ -219,7 +219,7 @@ readAction (const SGPropertyNode * node, float w_scale, float h_scale)
 
       binding = dest->getChild("binding", j, true);
       copyProperties(bindings[i], binding);
-      action->addBinding(new FGBinding(binding), 1);
+      action->addBinding(new SGBinding(binding, globals->get_props()), 1);
     }
   }
 
index 63e3ac7a1d92fba95c16bbc53e5289ad647a4698..1a1bbd88fdfa133f23b35eebb8e0ba722d0cca34 100644 (file)
@@ -32,7 +32,7 @@ struct GUIInfo
     virtual ~GUIInfo ();
 
     FGDialog * dialog;
-    vector <FGBinding *> bindings;
+    vector <SGBinding *> bindings;
     int key;
 };
 
@@ -746,7 +746,7 @@ FGDialog::setupObject (puObject * object, SGPropertyNode * props)
 
             binding = dest->getChild("binding", j, true);
             copyProperties(bindings[i], binding);
-            info->bindings.push_back(new FGBinding(binding));
+            info->bindings.push_back(new SGBinding(binding, globals->get_props()));
         }
         object->setCallback(action_callback);
 
index df981c81f07cbe60b6734db462d0f3f897d8f1df..6430b75cdb9923955194189b59ae892d9aecf434 100644 (file)
@@ -30,7 +30,6 @@ class GUI_ID { public: GUI_ID(int id) : id(id) {} int id; };
 
 
 class FGDialog;
-class FGBinding;
 class NewGUI;
 class FGColor;
 
index 9cacef59c7d68e840ea3600eff0f12c569f49bc7..da905ee25647b0afd7229a27a1a0ad39d11021b2 100644 (file)
@@ -156,7 +156,7 @@ void
 FGMenuBar::fireItem (puObject * item)
 {
     const char * name = item->getLegend();
-    vector<FGBinding *> &bindings = _bindings[name];
+    vector<SGBinding *> &bindings = _bindings[name];
     int nBindings = bindings.size();
 
     for (int i = 0; i < nBindings; i++)
@@ -194,7 +194,7 @@ FGMenuBar::make_menu (SGPropertyNode * node)
 
             binding = dest->getChild("binding", m, true);
             copyProperties(bindings[k], binding);
-            _bindings[items[j]].push_back(new FGBinding(binding));
+            _bindings[items[j]].push_back(new SGBinding(binding, globals->get_props()));
         }
     }
 
@@ -283,7 +283,7 @@ FGMenuBar::destroy_menubar ()
 
                                 // Delete all those bindings
     SG_LOG(SG_GENERAL, SG_INFO, "Deleting bindings");
-    map<string,vector<FGBinding *> >::iterator it;
+    map<string,vector<SGBinding *> >::iterator it;
     it = _bindings.begin();
     for (it = _bindings.begin(); it != _bindings.end(); it++) {
         SG_LOG(SG_GENERAL, SG_INFO, "Deleting bindings for " << it->first);
index 2bcef85f3548fc8c05d0de4bbaed02b870521ef8..e3a97d57e40112330d481f2427e05ea8df528f11 100644 (file)
@@ -21,7 +21,7 @@ SG_USING_STD(vector);
 
 class puMenuBar;
 class puObject;
-class FGBinding;
+class SGBinding;
 
 
 /**
@@ -124,7 +124,7 @@ private:
     puMenuBar * _menuBar;
 
     // A map of bindings for the menubar.
-    map<string,vector<FGBinding *> > _bindings;
+    map<string,vector<SGBinding *> > _bindings;
 
     // These are hoops that we have to jump through because PUI doesn't
     // do memory management for lists.  We have to allocate the arrays,
index 352024a66b07511f153e3b4602dee0962979b54b..d258399f60ef760f535d48f71ead9b4c09f36fc8 100644 (file)
@@ -27,9 +27,10 @@ SG_USING_STD(string);
 
 #include <Main/fg_props.hxx>
 
+class SGBinding;
+
 class FGMenuBar;
 class FGDialog;
-class FGBinding;
 class FGColor;
 class FGFontCache;
 
index 30639bc19dada40f29f3f40d5dab90ab5fcc2dbe..93dfbb90231a087e1aabb77db8f3ba573100b9d9 100644 (file)
@@ -41,7 +41,9 @@
 
 #include <simgear/constants.h>
 #include <simgear/debug/logstream.hxx>
+#include <simgear/math/SGMath.hxx>
 #include <simgear/props/props.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
 
 #include <Aircraft/aircraft.hxx>
 #include <Autopilot/xmlauto.hxx>
@@ -59,7 +61,6 @@
 
 #include <Scenery/scenery.hxx>
 #include <Main/renderer.hxx>
-#include <simgear/math/sg_geodesy.hxx>
 
 SG_USING_STD(ifstream);
 SG_USING_STD(string);
@@ -99,87 +100,6 @@ getModAlt ()
   return bool(fgGetKeyModifiers() & KEYMOD_ALT);
 }
 
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGBinding.
-////////////////////////////////////////////////////////////////////////
-
-FGBinding::FGBinding ()
-  : _command(0),
-    _arg(new SGPropertyNode),
-    _setting(0)
-{
-}
-
-FGBinding::FGBinding (const SGPropertyNode * node)
-  : _command(0),
-    _arg(0),
-    _setting(0)
-{
-  read(node);
-}
-
-FGBinding::~FGBinding ()
-{
-  _arg->getParent()->removeChild(_arg->getName(), _arg->getIndex(), false);
-}
-
-void
-FGBinding::read (const SGPropertyNode * node)
-{
-  const SGPropertyNode * conditionNode = node->getChild("condition");
-  if (conditionNode != 0)
-    setCondition(sgReadCondition(globals->get_props(), conditionNode));
-
-  _command_name = node->getStringValue("command", "");
-  if (_command_name.empty()) {
-    SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding.");
-    _command = 0;
-    return;
-  }
-
-  _arg = (SGPropertyNode *)node;
-  _setting = 0;
-}
-
-void
-FGBinding::fire () const
-{
-  if (test()) {
-    if (_command == 0)
-      _command = globals->get_commands()->getCommand(_command_name);
-    if (_command == 0) {
-      SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding");
-    } else if (!(*_command)(_arg)) {
-      SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command "
-             << _command_name);
-    }
-  }
-}
-
-void
-FGBinding::fire (double offset, double max) const
-{
-  if (test()) {
-    _arg->setDoubleValue("offset", offset/max);
-    fire();
-  }
-}
-
-void
-FGBinding::fire (double setting) const
-{
-  if (test()) {
-                                // A value is automatically added to
-                                // the args
-    if (_setting == 0)          // save the setting node for efficiency
-      _setting = _arg->getChild("setting", 0, true);
-    _setting->setDoubleValue(setting);
-    fire();
-  }
-}
-
-
 \f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of FGInput.
@@ -341,6 +261,16 @@ FGInput::doMouseClick (int b, int updown, int x, int y)
                                 // Pass on to PUI and the panel if
                                 // requested, and return if one of
                                 // them consumes the event.
+
+  if (updown != MOUSE_BUTTON_DOWN) {
+    // Execute the mouse up event in any case, may be we should
+    // stop processing here?
+    while (!_activePickCallbacks[b].empty()) {
+      _activePickCallbacks[b].front()->buttonReleased();
+      _activePickCallbacks[b].pop_front();
+    }
+  }
+
   if (mode.pass_through) {
     if (puMouse(b, updown, x, y))
       return;
@@ -351,28 +281,33 @@ FGInput::doMouseClick (int b, int updown, int x, int y)
     else if (fgHandle3DPanelMouseEvent(b, updown, x, y))
       return;
     else {
-      // pui and the panel didn't want the click event so compute a
-      // terrain intersection point corresponding to the mouse click
-      // and be happy.
-      FGScenery* scenery = globals->get_scenery();
-      SGVec3d start, dir, hit;
-      if (!b && updown == MOUSE_BUTTON_DOWN
-          && FGRenderer::getPickInfo(start, dir, x, y)
-          && scenery->get_cart_ground_intersection(start, dir, hit)) {
-
-        SGGeod geod = SGGeod::fromCart(hit);
-        SGPropertyNode *c = fgGetNode("/sim/input/click", true);
-        c->setDoubleValue("longitude-deg", geod.getLongitudeDeg());
-        c->setDoubleValue("latitude-deg", geod.getLatitudeDeg());
-        c->setDoubleValue("elevation-m", geod.getElevationM());
-        c->setDoubleValue("elevation-ft", geod.getElevationFt());
-
-        fgSetBool("/sim/signals/click", 1);
+      // pui didn't want the click event so compute a
+      // scenegraph intersection point corresponding to the mouse click
+      if (updown == MOUSE_BUTTON_DOWN) {
+        FGScenery* scenery = globals->get_scenery();
+        SGVec3d start, dir;
+
+        // Get the list of hit callbacks. Take the first callback that
+        // accepts the mouse button press and ignore the rest of them
+        // 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.
+        if (FGRenderer::getPickInfo(start, dir, x, y)) {
+          std::vector<SGSceneryPick> pickList;
+          scenery->pick(start, dir, pickList);
+          std::vector<SGSceneryPick>::const_iterator i;
+          for (i = pickList.begin(); i != pickList.end(); ++i) {
+            if (i->callback->buttonPressed(b, i->info)) {
+              _activePickCallbacks[b].push_back(i->callback);
+              break;
+            }
+          }
+        }
       }
     }
   }
 
-                                // OK, PUI and the panel didn't want the click
+  // OK, PUI and the panel didn't want the click
   if (b >= MAX_MOUSE_BUTTONS) {
     SG_LOG(SG_INPUT, SG_ALERT, "Mouse button " << b
            << " where only " << MAX_MOUSE_BUTTONS << " expected");
@@ -924,6 +859,16 @@ FGInput::_update_mouse ( double dt )
       m.save_x = m.x;
       m.save_y = m.y;
   }
+
+  // handle repeatable mouse press events
+  std::map<int, std::list<SGSharedPtr<SGPickCallback> > >::iterator mi;
+  for (mi = _activePickCallbacks.begin();
+       mi != _activePickCallbacks.end(); ++mi) {
+    std::list<SGSharedPtr<SGPickCallback> >::iterator li;
+    for (li = mi->second.begin(); li != mi->second.end(); ++li) {
+      (*li)->update(dt);
+    }
+  }
 }
 
 void
@@ -934,8 +879,9 @@ FGInput::_update_button (button &b, int modifiers, bool pressed,
                                 // The press event may be repeated.
     if (!b.last_state || b.is_repeatable) {
       SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" );
-      for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++)
+      for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++) {
         b.bindings[modifiers][k]->fire(x, y);
+      }
     }
   } else {
                                 // The release event is never repeated.
@@ -963,7 +909,7 @@ FGInput::_read_bindings (const SGPropertyNode * node,
 
     if (!strcmp(cmd, "nasal") && _module[0])
       bindings[i]->setStringValue("module", _module);
-    binding_list[modifiers].push_back(new FGBinding(bindings[i]));
+    binding_list[modifiers].push_back(new SGBinding(bindings[i], globals->get_props()));
   }
 
                                 // Read nested bindings for modifiers
@@ -985,7 +931,7 @@ FGInput::_read_bindings (const SGPropertyNode * node,
 }
 
 
-const vector<FGBinding *> &
+const FGInput::binding_list_t&
 FGInput::_find_key_bindings (unsigned int k, int modifiers)
 {
   unsigned char kc = (unsigned char)k;
index c8dcec3acf20910f5d3ae99ff12117360e9c7d7f..ca15e458d873a1eb33f0ea7e0e8b1c7f469894ea 100644 (file)
 
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
-#include <simgear/structure/commands.hxx>
+#include <simgear/structure/SGBinding.hxx>
 #include <simgear/props/condition.hxx>
 #include <simgear/props/props.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
 
 #include <Main/fg_os.hxx>
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
 
 #include <map>
+#include <list>
 #include <vector>
 
 SG_USING_STD(map);
@@ -61,110 +63,6 @@ SG_USING_STD(vector);
 #endif
 
 
-\f
-////////////////////////////////////////////////////////////////////////
-// General binding support.
-////////////////////////////////////////////////////////////////////////
-
-
-/**
- * An input binding of some sort.
- *
- * <p>This class represents a binding that can be assigned to a
- * keyboard key, a joystick button or axis, or even a panel
- * instrument.</p>
- */
-class FGBinding : public SGConditional
-{
-public:
-
-  /**
-   * Default constructor.
-   */
-  FGBinding ();
-
-
-  /**
-   * Convenience constructor.
-   *
-   * @param node The binding will be built from this node.
-   */
-  FGBinding (const SGPropertyNode * node);
-
-
-  /**
-   * Destructor.
-   */
-  virtual ~FGBinding ();
-
-
-  /**
-   * Get the command name.
-   *
-   * @return The string name of the command for this binding.
-   */
-  virtual const string &getCommandName () const { return _command_name; }
-
-
-  /**
-   * Get the command itself.
-   *
-   * @return The command associated with this binding, or 0 if none
-   * is present.
-   */
-  virtual SGCommandMgr::command_t getCommand () const { return _command; }
-
-
-  /**
-   * Get the argument that will be passed to the command.
-   *
-   * @return A property node that will be passed to the command as its
-   * argument, or 0 if none was supplied.
-   */
-  virtual const SGPropertyNode * getArg () { return _arg; }
-  
-
-  /**
-   * Read a binding from a property node.
-   *
-   * @param node The property node containing the binding.
-   */
-  virtual void read (const SGPropertyNode * node);
-
-
-  /**
-   * Fire a binding.
-   */
-  virtual void fire () const;
-
-
-  /**
-   * Fire a binding with a scaled movement (rather than absolute position).
-   */
-  virtual void fire (double offset, double max) const;
-
-
-  /**
-   * Fire a binding with a setting (i.e. joystick axis).
-   *
-   * A double 'setting' property will be added to the arguments.
-   *
-   * @param setting The input setting, usually between -1.0 and 1.0.
-   */
-  virtual void fire (double setting) const;
-
-
-private:
-                                // just to be safe.
-  FGBinding (const FGBinding &binding);
-
-  string _command_name;
-  mutable SGCommandMgr::command_t _command;
-  mutable SGPropertyNode_ptr _arg;
-  mutable SGPropertyNode_ptr _setting;
-};
-
-
 \f
 ////////////////////////////////////////////////////////////////////////
 // General input mapping support.
@@ -268,7 +166,7 @@ private:
   struct mouse;
   friend struct mouse;
 
-  typedef vector<FGBinding *> binding_list_t;
+  typedef vector<SGSharedPtr<SGBinding> > binding_list_t;
 
   /**
    * Settings for a key or button.
@@ -424,8 +322,8 @@ private:
   /**
    * Look up the bindings for a key code.
    */
-  const vector<FGBinding *> &_find_key_bindings (unsigned int k,
-                                                int modifiers);
+  const binding_list_t& _find_key_bindings (unsigned int k,
+                                            int modifiers);
 
   button _key_bindings[MAX_KEYS];
   joystick _joystick_bindings[MAX_JOYSTICKS];
@@ -435,6 +333,11 @@ private:
    * Nasal module name/namespace.
    */
   char _module[32];
+
+  /**
+   * List of currently pressed mouse button events
+   */
+  std::map<int, std::list<SGSharedPtr<SGPickCallback> > > _activePickCallbacks;
 };
 
 #endif // _INPUT_HXX
index c123fbf55b7129a5df19e8a11d4c45eeaf8daea1..a6aa86f8a0dd00814741bdcef0599d187d425c08 100644 (file)
 #include <osg/LightSource>
 #include <osg/NodeCallback>
 #include <osg/Notify>
-#include <osg/MatrixTransform>
-#include <osg/Multisample>
-#include <osg/Point>
 #include <osg/PolygonMode>
+#include <osg/PolygonOffset>
 #include <osg/ShadeModel>
 #include <osg/TexEnv>
-#include <osg/TexEnvCombine>
-#include <osg/TexGen>
-#include <osg/TexMat>
-#include <osg/ColorMatrix>
 
 #include <osgUtil/SceneView>
 #include <osgUtil/UpdateVisitor>
@@ -136,7 +130,6 @@ public:
        || (fgGetBool("/sim/ai-traffic/enabled")))
       globals->get_ATC_display()->update(delta_time_sec, state);
 
-
     puDisplay();
 
     // Fade out the splash screen over the first three seconds.
@@ -357,6 +350,12 @@ FGRenderer::init( void ) {
 
     osg::initNotifyLevel();
 
+    // The number of polygon-offset "units" to place between layers.  In
+    // principle, one is supposed to be enough.  In practice, I find that
+    // my hardware/driver requires many more.
+    osg::PolygonOffset::setUnitsMultiplier(1);
+    osg::PolygonOffset::setFactorMultiplier(1);
+
     // Go full screen if requested ...
     if ( fgGetBool("/sim/startup/fullscreen") )
         fgOSFullScreen();
@@ -797,6 +796,12 @@ FGRenderer::update( bool refresh_camera_settings ) {
     mUpdateVisitor->setLight(direction, l->scene_ambient(),
                              l->scene_diffuse(), l->scene_specular());
     mUpdateVisitor->setVisibility(actual_visibility);
+
+    if (fgGetBool("/sim/panel-hotspots"))
+      sceneView->setCullMask(~0u);
+    else
+      sceneView->setCullMask(~SG_NODEMASK_PICK_BIT);
+
     sceneView->update();
     sceneView->cull();
     sceneView->draw();
@@ -839,9 +844,6 @@ FGRenderer::resize( int width, int height ) {
 
       setFOV( viewmgr->get_current_view()->get_h_fov(),
               viewmgr->get_current_view()->get_v_fov() );
-      // cout << "setFOV(" << viewmgr->get_current_view()->get_h_fov()
-      //      << ", " << viewmgr->get_current_view()->get_v_fov() << ")"
-      //      << endl;
     }
 }
 
index 1f04b6c1b24d771c20b9b62d7ec4a6687f2478ba..bcd7d1865e8b220691e7bd16901fdc3940cbfe43 100644 (file)
 #include <simgear/scene/model/placementtrans.hxx>
 #include <simgear/scene/material/matlib.hxx>
 #include <simgear/scene/util/SGNodeMasks.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
 
 #include <Main/fg_props.hxx>
 
 #include "scenery.hxx"
 
+class FGGroundPickCallback : public SGPickCallback {
+public:
+  virtual bool buttonPressed(int button, const Info& info)
+  {
+    // only on left mouse button
+    if (button != 0)
+      return false;
+
+    SGGeod geod = SGGeod::fromCart(info.wgs84);
+    SG_LOG( SG_TERRAIN, SG_INFO, "Got ground pick at " << geod );
+
+    SGPropertyNode *c = fgGetNode("/sim/input/click", true);
+    c->setDoubleValue("longitude-deg", geod.getLongitudeDeg());
+    c->setDoubleValue("latitude-deg", geod.getLatitudeDeg());
+    c->setDoubleValue("elevation-m", geod.getElevationM());
+    c->setDoubleValue("elevation-ft", geod.getElevationFt());
+    fgSetBool("/sim/signals/click", 1);
+
+    return true;
+  }
+};
 
 // Scenery Management system
 FGScenery::FGScenery() :
@@ -64,6 +86,9 @@ void FGScenery::init() {
     terrain_branch = new osg::Group;
     terrain_branch->setName( "Terrain" );
     scene_graph->addChild( terrain_branch.get() );
+    SGSceneUserData* userData;
+    userData = SGSceneUserData::getOrCreateSceneUserData(terrain_branch.get());
+    userData->setPickCallback(new FGGroundPickCallback);
 
     models_branch = new osg::Group;
     models_branch->setName( "Models" );
@@ -192,6 +217,25 @@ FGScenery::get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
   return hits;
 }
 
+static const osgUtil::Hit*
+getNearestHit(const osgUtil::IntersectVisitor::HitList& hitList,
+              const SGVec3d& start)
+{
+  const osgUtil::Hit* nearestHit = 0;
+  double dist = SGLimitsd::max();
+  osgUtil::IntersectVisitor::HitList::const_iterator hit;
+  for (hit = hitList.begin(); hit != hitList.end(); ++hit) {
+    SGVec3d point(hit->getWorldIntersectPoint());
+    double newdist = length(start - point);
+    if (newdist < dist) {
+      dist = newdist;
+      nearestHit = &*hit;
+    }
+  }
+
+  return nearestHit;
+}
+
 bool
 FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
                                         SGVec3d& nearestHit, bool exact)
@@ -215,7 +259,7 @@ FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
   // Make really sure the direction is normalized, is really cheap compared to
   // computation of ground intersection.
   SGVec3d start = pos - center;
-  SGVec3d end = start + 1e5*dir;
+  SGVec3d end = start + 1e5*normalize(dir); // FIXME visibility ???
   
   osgUtil::IntersectVisitor intersectVisitor;
   intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
@@ -246,3 +290,52 @@ FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
   return hits;
 }
 
+void
+FGScenery::pick(const SGVec3d& pos, const SGVec3d& dir,
+                std::vector<SGSceneryPick>& pickList)
+{
+  pickList.clear();
+
+  // Make really sure the direction is normalized, is really cheap compared to
+  // computation of ground intersection.
+  SGVec3d start = pos - center;
+  SGVec3d end = start + 1e5*normalize(dir); // FIXME visibility ???
+  
+  osgUtil::IntersectVisitor intersectVisitor;
+//   osgUtil::PickVisitor intersectVisitor;
+//   intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
+  osg::ref_ptr<osg::LineSegment> lineSegment;
+  lineSegment = new osg::LineSegment(start.osg(), end.osg());
+  intersectVisitor.addLineSegment(lineSegment.get());
+  get_scene_graph()->accept(intersectVisitor);
+  if (!intersectVisitor.hits())
+    return;
+
+  // collect all interaction callbacks on the pick ray.
+  // They get stored in the pickCallbacks list where they are sorted back
+  // to front and croasest to finest wrt the scenery node they are attached to
+  osgUtil::IntersectVisitor::HitList::const_iterator hi;
+  for (hi = intersectVisitor.getHitList(lineSegment.get()).begin();
+       hi != intersectVisitor.getHitList(lineSegment.get()).end();
+       ++hi) {
+
+    // ok, go back the nodes and ask for intersection callbacks,
+    // execute them in top down order
+    const osg::NodePath& np = hi->getNodePath();
+    osg::NodePath::const_reverse_iterator npi;
+    for (npi = np.rbegin(); npi != np.rend(); ++npi) {
+      SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
+      if (!ud)
+        continue;
+      SGPickCallback* pickCallback = ud->getPickCallback();
+      if (!pickCallback)
+        continue;
+
+      SGSceneryPick sceneryPick;
+      sceneryPick.info.wgs84 = center + SGVec3d(hi->getWorldIntersectPoint());
+      sceneryPick.info.local = SGVec3d(hi->getLocalIntersectPoint());
+      sceneryPick.callback = pickCallback;
+      pickList.push_back(sceneryPick);
+    }
+  }
+}
index 282bea2afc4c3ef146086fc4ef371f7367aec3de..a1cf2a77b7875ce9ae97bac44ab5cd8a935b55bc 100644 (file)
@@ -38,6 +38,7 @@
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/math/point3d.hxx>
 #include <simgear/scene/model/placementtrans.hxx>
+#include <simgear/scene/util/SGPickCallback.hxx>
 
 SG_USING_STD(list);
 
@@ -114,6 +115,8 @@ public:
     /// On success, true is returned.
     bool get_cart_ground_intersection(const SGVec3d& start, const SGVec3d& dir,
                                       SGVec3d& nearestHit, bool exact = false);
+    void pick(const SGVec3d& pos, const SGVec3d& dir,
+              std::vector<SGSceneryPick>& pickList);
 
     const SGVec3d& get_center() const { return center; }
     void set_center( const SGVec3d& p );