+ // Terrain branch
+ 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" );
+ scene_graph->addChild( models_branch.get() );
+
+ aircraft_branch = new osg::Group;
+ aircraft_branch->setName( "Aircraft" );
+ scene_graph->addChild( aircraft_branch.get() );
+
+ // Initials values needed by the draw-time object loader
+ sgUserDataInit( globals->get_props() );
+}
+
+
+void FGScenery::update(double dt)
+{
+ SG_UNUSED(dt);
+ // nothing here, don't call again
+ suspend();
+}
+
+
+void FGScenery::bind() {
+}
+
+
+void FGScenery::unbind() {
+}
+
+bool
+FGScenery::get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
+ double& alt,
+ const simgear::BVHMaterial** material,
+ const osg::Node* butNotFrom)
+{
+ SGGeod geod = SGGeod::fromCart(pos);
+ geod.setElevationM(geod.getElevationM() + max_altoff);
+ return get_elevation_m(geod, alt, material, butNotFrom);
+}
+
+bool
+FGScenery::get_elevation_m(const SGGeod& geod, double& alt,
+ const simgear::BVHMaterial** material,
+ const osg::Node* butNotFrom)
+{
+ SGVec3d start = SGVec3d::fromGeod(geod);
+
+ SGGeod geodEnd = geod;
+ geodEnd.setElevationM(SGMiscd::min(geod.getElevationM() - 10, -10000));
+ SGVec3d end = SGVec3d::fromGeod(geodEnd);
+
+ FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
+ intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
+ get_scene_graph()->accept(intersectVisitor);
+
+ if (!intersectVisitor.getHaveHit())
+ return false;
+
+ geodEnd = SGGeod::fromCart(intersectVisitor.getLineSegment().getEnd());
+ alt = geodEnd.getElevationM();
+ if (material)
+ *material = intersectVisitor.getMaterial();
+
+ return true;
+}
+
+bool
+FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
+ SGVec3d& nearestHit,
+ const osg::Node* butNotFrom)
+{
+ // We assume that starting positions in the center of the earth are invalid
+ if ( norm1(pos) < 1 )
+ return false;
+
+ // Make really sure the direction is normalized, is really cheap compared to
+ // computation of ground intersection.
+ SGVec3d start = pos;
+ SGVec3d end = start + 1e5*normalize(dir); // FIXME visibility ???
+
+ FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
+ intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
+ get_scene_graph()->accept(intersectVisitor);
+
+ if (!intersectVisitor.getHaveHit())
+ return false;
+
+ nearestHit = intersectVisitor.getLineSegment().getEnd();
+ return true;
+}
+
+bool FGScenery::scenery_available(const SGGeod& position, double range_m)
+{
+ if(globals->get_tile_mgr()->schedule_scenery(position, range_m, 0.0))
+ {
+ double elev;
+ if (!get_elevation_m(SGGeod::fromGeodM(position, SG_MAX_ELEVATION_M), elev, 0, 0))
+ return false;
+ SGVec3f p = SGVec3f::fromGeod(SGGeod::fromGeodM(position, elev));
+ osg::FrameStamp* framestamp
+ = globals->get_renderer()->getViewer()->getFrameStamp();
+ simgear::CheckSceneryVisitor csnv(_pager, toOsg(p), range_m, framestamp);
+ // currently the PagedLODs will not be loaded by the DatabasePager
+ // while the splashscreen is there, so CheckSceneryVisitor force-loads
+ // missing objects in the main thread
+ get_scene_graph()->accept(csnv);
+ if(!csnv.isLoaded())
+ return false;
+ return true;
+ }
+ return false;
+}
+
+SceneryPager* FGScenery::getPagerSingleton()
+{
+ static osg::ref_ptr<SceneryPager> pager = new SceneryPager;
+ return pager.get();