1
0
Fork 0

Modified Files:

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.
This commit is contained in:
frohlich 2007-01-07 12:02:50 +00:00
parent 4c1c10ffef
commit a788ebf487
5 changed files with 87 additions and 121 deletions

View 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);
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)) {

View 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();
// wipe out the return ...
pickList.resize(0);
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);
// we can get called early ...
if (!sceneView.valid())
return false;
osg::Node* sceneData = globals->get_scenery()->get_scene_graph();
if (!sceneData)
return false;
osg::Viewport* viewport = sceneView->getViewport();
if (!viewport)
return false;
// 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);
}
}
}
}
// 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]);
// Now build a direction from the point
FGViewer* view = globals->get_current_view();
dir = normalize(toVec3d(worldPt - SGVec3f(view->get_view_pos())));
// Copy the start point
pt = SGVec3d(view->get_absolute_view_pos());
// 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;
return true;
return !pickList.empty();
}
// end of renderer.cxx

View 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

View 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);
}
}
}

View 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 );