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:
parent
4c1c10ffef
commit
a788ebf487
5 changed files with 87 additions and 121 deletions
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// 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())
|
||||
// we can get called early ...
|
||||
if (!sceneView.valid())
|
||||
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())));
|
||||
osg::Node* sceneData = globals->get_scenery()->get_scene_graph();
|
||||
if (!sceneData)
|
||||
return false;
|
||||
osg::Viewport* viewport = sceneView->getViewport();
|
||||
if (!viewport)
|
||||
return false;
|
||||
|
||||
// Copy the start point
|
||||
pt = SGVec3d(view->get_absolute_view_pos());
|
||||
// good old scenery center
|
||||
SGVec3d center = globals->get_scenery()->get_center();
|
||||
|
||||
// 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;
|
||||
// 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());
|
||||
|
||||
return true;
|
||||
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 !pickList.empty();
|
||||
}
|
||||
|
||||
// end of renderer.cxx
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue