]> git.mxchange.org Git - flightgear.git/commitdiff
Modified Files:
authorfrohlich <frohlich>
Sun, 7 Jan 2007 12:02:50 +0000 (12:02 +0000)
committerfrohlich <frohlich>
Sun, 7 Jan 2007 12:02:50 +0000 (12:02 +0000)
src/Input/input.cxx src/Main/renderer.cxx
src/Main/renderer.hxx src/Scenery/scenery.cxx
src/Scenery/scenery.hxx: Move scenery picking into the renderer.
There is most of the required data defined. Also we can better use
the pick visitor that will be needed with th upcommung panel code.

src/Input/input.cxx
src/Main/renderer.cxx
src/Main/renderer.hxx
src/Scenery/scenery.cxx
src/Scenery/scenery.hxx

index 9c8f6135134969293b7b642735453d107d247485..971ffeb987f397109b836d63b9fee00cebf9ce4c 100644 (file)
@@ -284,17 +284,14 @@ FGInput::doMouseClick (int b, int updown, int x, int y)
       // 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> pickList;
+        if (FGRenderer::pick(x, y, pickList)) {
           std::vector<SGSceneryPick>::const_iterator i;
           for (i = pickList.begin(); i != pickList.end(); ++i) {
             if (i->callback->buttonPressed(b, i->info)) {
index 9d0581acf19b8e371d19f4785c99ac606fece0ec..8b3c895e76125c63ccd4323b57607b6455af89a5 100644 (file)
@@ -53,6 +53,7 @@
 
 #include <osgUtil/SceneView>
 #include <osgUtil/UpdateVisitor>
+#include <osgUtil/IntersectVisitor>
 
 #include <osg/io_utils>
 #include <osgDB/WriteFile>
@@ -975,55 +976,94 @@ n = 0.2;
     fgHackFrustum();
 }
 
-bool FGRenderer::getPickInfo( SGVec3d& pt, SGVec3d& dir,
-                              unsigned x, unsigned y )
+bool
+FGRenderer::pick( unsigned x, unsigned y,
+                  std::vector<SGSceneryPick>& pickList )
 {
-  // Get the matrices involved in the transform from global to screen
-  // coordinates.
-  osg::Matrix pm = sceneView->getCamera()->getProjectionMatrix();
-
-  osg::Matrix mv;
-  osg::NodePathList paths;
-  paths = globals->get_scenery()->get_scene_graph()->getParentalNodePaths();
-  if (!paths.empty()) {
-    // Ok, we know that this should not have multiple parents ...
-    // FIXME: is this allways true?
-    mv = osg::computeLocalToEye(sceneView->getCamera()->getViewMatrix(),
-                                paths.front(), false);
-  }
-  
-  // Compose and invert
-  osg::Matrix m = osg::Matrix::inverse(mv*pm);
-  
-  // Get the width and height of the display to be able to normalize the
-  // mouse coordinate
-  float width = fgGetInt("/sim/startup/xsize");
-  float height = fgGetInt("/sim/startup/ysize");
-  
-  // Compute some coordinates of in the line from the eyepoint to the
-  // mouse click coodinates.
-  // First build the normalized projection coordinates
-  osg::Vec4 normPt((2*x - width)/width, -(2*y - height)/height, 1, 1);
-  // Transform them into the real world
-  osg::Vec4 worldPt4 = m.preMult(normPt);
-  if (fabs(worldPt4[3]) < SGLimitsf::min())
-    return false;
-  SGVec3f worldPt(worldPt4[0]/worldPt4[3],
-                  worldPt4[1]/worldPt4[3],
-                  worldPt4[2]/worldPt4[3]);
+  // wipe out the return ...
+  pickList.resize(0);
 
-  // Now build a direction from the point
-  FGViewer* view = globals->get_current_view();
-  dir = normalize(toVec3d(worldPt - SGVec3f(view->get_view_pos())));
+  // we can get called early ...
+  if (!sceneView.valid())
+    return false;
 
-  // Copy the start point
-  pt = SGVec3d(view->get_absolute_view_pos());
+  osg::Node* sceneData = globals->get_scenery()->get_scene_graph();
+  if (!sceneData)
+    return false;
+  osg::Viewport* viewport = sceneView->getViewport();
+  if (!viewport)
+    return false;
 
-  // OSGFIXME: ist this sufficient??? especially the precision problems here??
-// bool mSceneView->projectWindowXYIntoObject(int x,int y,osg::Vec3& near_point,osg::Vec3& far_point) const;
+  // good old scenery center
+  SGVec3d center = globals->get_scenery()->get_center();
+
+  // don't know why, but the update has partly happened somehow,
+  // so update the scneery part of the viewer
+  FGViewer *current_view = globals->get_current_view();
+  // Force update of center dependent values ...
+  current_view->set_dirty();
+  SGVec3d position = current_view->getViewPosition();
+  SGQuatd attitude = current_view->getViewOrientation();
+  SGVec3d osgPosition = attitude.transform(center - position);
+  mCameraView->setPosition(osgPosition.osg());
+  mCameraView->setAttitude(inverse(attitude).osg());
+
+  osg::Matrix projection(sceneView->getProjectionMatrix());
+  osg::Matrix modelview(sceneView->getViewMatrix());
+
+  osg::NodePathList nodePath = sceneData->getParentalNodePaths();
+  // modify the view matrix so that it accounts for this nodePath's
+  // accumulated transform
+  if (!nodePath.empty())
+    modelview.preMult(computeLocalToWorld(nodePath.front()));
+
+  // swap the y values ...
+  y = viewport->height() - y;
+  // set up the pick visitor
+  osgUtil::PickVisitor pickVisitor(viewport, projection, modelview, x, y);
+  sceneData->accept(pickVisitor);
+  if (!pickVisitor.hits())
+    return false;
 
+  // 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::PickVisitor::LineSegmentHitListMap::const_iterator mi;
+  for (mi = pickVisitor.getSegHitList().begin();
+       mi != pickVisitor.getSegHitList().end();
+       ++mi) {
+    osgUtil::IntersectVisitor::HitList::const_iterator hi;
+    for (hi = mi->second.begin(); hi != mi->second.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;
+        for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
+          SGPickCallback* pickCallback = ud->getPickCallback(i);
+          if (!pickCallback)
+            continue;
+          SGSceneryPick sceneryPick;
+          /// note that this is done totally in doubles instead of
+          /// just using getWorldIntersectionPoint
+          osg::Vec3d localPt = hi->getLocalIntersectPoint();
+          sceneryPick.info.local = SGVec3d(localPt);
+          if (hi->getMatrix())
+            sceneryPick.info.wgs84 = SGVec3d(localPt*(*hi->getMatrix()));
+          else
+            sceneryPick.info.wgs84 = SGVec3d(localPt);
+          sceneryPick.info.wgs84 += globals->get_scenery()->get_center();
+          sceneryPick.callback = pickCallback;
+          pickList.push_back(sceneryPick);
+        }
+      }
+    }
+  }
 
-  return true;
+  return !pickList.empty();
 }
 
 // end of renderer.cxx
index 83faba51ba7ea2d15a8f8361efa29ae260ee21e6..b80087da6b8e1ff8fd0b1c6b11050227447a14ec 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <simgear/screen/extensions.hxx>
 #include <simgear/scene/sky/sky.hxx>
+#include <simgear/scene/util/SGPickCallback.hxx>
 
 #define FG_ENABLE_MULTIPASS_CLOUDS 1
 
@@ -45,11 +46,10 @@ public:
      */
     static void setNearFar( float n, float f );
 
-    /** Get the pick start point and direction in global coordinates.
-     *  The inputs are expected to be the x and y coordinates of the
-     *  screen point relative to the window.
+    /** Just pick into the scene and return the pick callbacks on the way ...
      */
-    static bool getPickInfo( SGVec3d& p, SGVec3d& d, unsigned x, unsigned y );
+    static bool pick( unsigned x, unsigned y,
+                      std::vector<SGSceneryPick>& pickList );
 };
 
 #endif
index bcd7d1865e8b220691e7bd16901fdc3940cbfe43..a4b32d73d0d373e87be6720e68d948c9d782c58c 100644 (file)
@@ -217,25 +217,6 @@ 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)
@@ -289,53 +270,3 @@ 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 a1cf2a77b7875ce9ae97bac44ab5cd8a935b55bc..4229e4c583fdcfe99094285051b31702d801a701 100644 (file)
@@ -115,8 +115,6 @@ 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 );