25#include <simgear/simgear_config.h>
31#include <osg/Transform>
32#include <osg/MatrixTransform>
33#include <osg/PositionAttitudeTransform>
34#include <osg/CameraView>
37#include <osgViewer/Viewer>
39#include <simgear/constants.h>
40#include <simgear/sg_inlines.h>
41#include <simgear/debug/logstream.hxx>
42#include <simgear/scene/tgdb/userdata.hxx>
43#include <simgear/scene/material/matlib.hxx>
44#include <simgear/scene/material/mat.hxx>
45#include <simgear/scene/util/SGNodeMasks.hxx>
46#include <simgear/scene/util/OsgMath.hxx>
47#include <simgear/scene/util/SGSceneUserData.hxx>
48#include <simgear/scene/model/CheckSceneryVisitor.hxx>
49#include <simgear/scene/sky/sky.hxx>
50#include <simgear/scene/util/SGSceneFeatures.hxx>
52#include <simgear/bvh/BVHNode.hxx>
53#include <simgear/bvh/BVHLineSegmentVisitor.hxx>
54#include <simgear/structure/commands.hxx>
77 const osgGA::GUIEventAdapter&,
84 SGGeod geod = SGGeod::fromCart(info.wgs84);
85 SG_LOG( SG_TERRAIN, SG_INFO,
"Got ground pick at " << geod );
87 SGPropertyNode *c =
fgGetNode(
"/sim/input/click",
true);
88 c->setDoubleValue(
"longitude-deg", geod.getLongitudeDeg());
89 c->setDoubleValue(
"latitude-deg", geod.getLatitudeDeg());
90 c->setDoubleValue(
"elevation-m", geod.getElevationM());
91 c->setDoubleValue(
"elevation-ft", geod.getElevationFt());
101 const osg::Node* skipNode) :
102 osg::NodeVisitor(
osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
103 _lineSegment(lineSegment),
112 {
return _lineSegment; }
114 {
return _material; }
118 if (&node == _skipNode)
120 if (!testBoundingSphere(node.getBound()))
123 addBoundingVolume(node);
126 virtual void apply(osg::Group& group)
128 if (&group == _skipNode)
130 if (!testBoundingSphere(group.getBound()))
134 addBoundingVolume(group);
137 virtual void apply(osg::Transform& transform)
138 { handleTransform(transform); }
139 virtual void apply(osg::Camera& camera)
141 if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
143 handleTransform(camera);
145 virtual void apply(osg::CameraView& transform)
146 { handleTransform(transform); }
147 virtual void apply(osg::MatrixTransform& transform)
148 { handleTransform(transform); }
149 virtual void apply(osg::PositionAttitudeTransform& transform)
150 { handleTransform(transform); }
153 void handleTransform(osg::Transform& transform)
155 if (&transform == _skipNode)
158 if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
161 if (!testBoundingSphere(transform.getBound()))
164 osg::Matrix inverseMatrix;
165 if (!transform.computeWorldToLocalMatrix(inverseMatrix,
this))
168 if (!transform.computeLocalToWorldMatrix(matrix,
this))
171 SGLineSegmentd lineSegment = _lineSegment;
172 bool haveHit = _haveHit;
173 const simgear::BVHMaterial* material = _material;
176 _lineSegment = lineSegment.transform(SGMatrixd(inverseMatrix.ptr()));
178 addBoundingVolume(transform);
182 _lineSegment = _lineSegment.transform(SGMatrixd(matrix.ptr()));
184 _lineSegment = lineSegment;
185 _material = material;
190 simgear::BVHNode* getNodeBoundingVolume(osg::Node& node)
192 SGSceneUserData* userData = SGSceneUserData::getSceneUserData(&node);
195 return userData->getBVHNode();
197 void addBoundingVolume(osg::Node& node)
199 simgear::BVHNode* bvNode = getNodeBoundingVolume(node);
204 simgear::BVHLineSegmentVisitor lineSegmentVisitor(_lineSegment,
206 bvNode->accept(lineSegmentVisitor);
207 if (!lineSegmentVisitor.empty()) {
208 _lineSegment = lineSegmentVisitor.getLineSegment();
209 _material = lineSegmentVisitor.getMaterial();
214 bool testBoundingSphere(
const osg::BoundingSphere& bound)
const
219 SGSphered sphere(toVec3d(toSG(bound._center)), bound._radius);
220 return intersects(_lineSegment, sphere);
223 SGLineSegmentd _lineSegment;
224 const osg::Node* _skipNode;
226 const simgear::BVHMaterial* _material;
246 for (
int i = 0;
i < maskNode->nChildren(); ++
i) {
247 maskNode->getChild(
i)->removeChangeListener(
this);
253 textureCacheNode->getChild(node, 0,
true)->addChangeListener(
this,
true);
258 bool b = node->getBoolValue();
259 std::string
name(node->getNameString());
261 if (
name ==
"cache-enabled") {
262 SGSceneFeatures::instance()->setTextureCacheActive(b);
264 else if (
name ==
"compress-transparent" ||
name ==
"compress") {
265 SGSceneFeatures::instance()->setTextureCacheCompressionActiveTransparent(b);
267 else if (
name ==
"compress-solid" ||
name ==
"compress") {
268 SGSceneFeatures::instance()->setTextureCacheCompressionActive(b);
289 for (
int i = 0;
i < node->nChildren(); ++
i) {
290 node->getChild(
i)->removeChangeListener(
this);
296 elevationMeshNode->getChild(node, 0,
true)->addChangeListener(
this,
true);
301 float f = node->getFloatValue();
302 std::string
name(node->getNameString());
304 if (
name ==
"constraint-gap-m") {
305 SGSceneFeatures::instance()->setVPBConstraintGap(f);
306 }
else if (
name ==
"sample-ratio") {
307 SGSceneFeatures::instance()->setVPBSampleRatio(f);
308 }
else if (
name ==
"vertical-scale") {
309 SGSceneFeatures::instance()->setVPBVerticalScale(f);
311 SG_LOG(SG_TERRAIN, SG_ALERT,
"Unexpected property in listener " << node->getPath());
322 SGPropertyNode_ptr maskNode =
fgGetNode(
"/sim/rendering/draw-mask",
true);
323 maskNode->getChild(
"terrain", 0,
true)->addChangeListener(
this,
true);
324 maskNode->getChild(
"models", 0,
true)->addChangeListener(
this,
true);
325 maskNode->getChild(
"aircraft", 0,
true)->addChangeListener(
this,
true);
326 maskNode->getChild(
"clouds", 0,
true)->addChangeListener(
this,
true);
329 fgGetNode(
"/sim/rendering/draw-otw")->addChangeListener(
this);
332 fgGetNode(
"/environment/clouds/status")->addChangeListener(
this);
334 auto vpb_active =
fgGetNode(
"/scenery/use-vpb");
336 vpb_active->addChangeListener(
this);
337 SGSceneFeatures::instance()->setVPBActive(vpb_active->getBoolValue());
347 SGPropertyNode_ptr maskNode =
fgGetNode(
"/sim/rendering/draw-mask");
348 for (
int i=0;
i < maskNode->nChildren(); ++
i) {
349 maskNode->getChild(
i)->removeChangeListener(
this);
352 fgGetNode(
"/sim/rendering/draw-otw")->removeChangeListener(
this);
353 fgGetNode(
"/environment/clouds/status")->removeChangeListener(
this);
354 fgGetNode(
"/scenery/use-vpb")->removeChangeListener(
this);
359 bool b = node->getBoolValue();
360 std::string
name(node->getNameString());
362 if (
name ==
"use-vpb") {
363 SGSceneFeatures::instance()->setVPBActive(b);
364 }
else if (
name ==
"terrain") {
365 _scenery->scene_graph->setChildValue(_scenery->terrain_branch, b);
366 }
else if (
name ==
"models") {
367 _scenery->scene_graph->setChildValue(_scenery->models_branch, b);
368 }
else if (
name ==
"aircraft") {
369 _scenery->scene_graph->setChildValue(_scenery->aircraft_branch, b);
370 }
else if (
name ==
"clouds") {
372 globals->get_renderer()->getSky()->set_clouds_enabled(b);
373 }
else if (
name ==
"draw-otw") {
375 fgGetNode(
"/sim/rendering/draw-mask")->setBoolValue(
"terrain", b);
376 fgGetNode(
"/sim/rendering/draw-mask")->setBoolValue(
"models", b);
377 }
else if (
name ==
"status") {
378 fgGetNode(
"/sim/rendering/draw-mask")->setBoolValue(
"clouds", b);
389 _listener(nullptr), _textureCacheListener(nullptr), _elevationMeshListener(nullptr)
401 delete _textureCacheListener;
412 scene_graph =
new osg::Switch;
413 scene_graph->setName(
"FGScenery" );
416 terrain_branch =
new osg::Group;
417 terrain_branch->setName(
"Terrain" );
418 scene_graph->addChild( terrain_branch.get() );
419 SGSceneUserData* userData;
420 userData = SGSceneUserData::getOrCreateSceneUserData(terrain_branch.get());
423 models_branch =
new osg::Group;
424 models_branch->setName(
"Models" );
425 scene_graph->addChild( models_branch.get() );
427 aircraft_branch =
new osg::Group;
428 aircraft_branch->setName(
"Aircraft" );
429 scene_graph->addChild( aircraft_branch.get() );
435 interior_branch =
new osg::Group;
436 interior_branch->setName(
"Interior" );
438 osg::LOD* interiorLOD =
new osg::LOD;
439 interiorLOD->addChild(interior_branch.get(), 0.0, 50.0);
440 aircraft_branch->addChild( interiorLOD );
443 auto paricles = simgear::ParticlesGlobalManager::instance();
444 particles_branch = paricles->getCommonRoot();
445 particles_branch->setName(
"Particles");
446 scene_graph->addChild(particles_branch.get());
447 paricles->setSwitchNode(
fgGetNode(
"/sim/rendering/particles",
true));
448 paricles->initFromMainThread();
451 precipitation_branch =
new osg::Group;
452 precipitation_branch->setName(
"Precipitation");
453 scene_graph->addChild(precipitation_branch.get());
456 std::string engine =
fgGetString(
"/sim/scenery/engine",
"tilecache" );
457 SG_LOG( SG_TERRAIN, SG_INFO,
"Selected scenery is " << engine );
459 if ( engine ==
"pagedLOD" ) {
468 _terrain->init( terrain_branch.get() );
481 fgSetBool(
"/sim/rendering/scenery-reload-required",
false);
487 _terrain->shutdown();
490 terrain_branch = NULL;
491 models_branch = NULL;
492 aircraft_branch = NULL;
493 particles_branch = NULL;
494 precipitation_branch = NULL;
501 simgear::ParticlesGlobalManager::clear();
507 _terrain->update(dt);
519 const simgear::BVHMaterial** material,
520 const osg::Node* butNotFrom)
522 return _terrain->get_cart_elevation_m(pos, max_altoff, alt,
523 material, butNotFrom);
528 const simgear::BVHMaterial** material,
529 const osg::Node* butNotFrom)
531 return _terrain->get_elevation_m( geod, alt, material,
538 const osg::Node* butNotFrom)
540 return _terrain->get_cart_ground_intersection( pos, dir, nearestHit, butNotFrom );
545 return _terrain->scenery_available( position, range_m );
550 return _terrain->schedule_scenery( position, range_m, duration );
555 _terrain->materialLibChanged();
558static osg::ref_ptr<SceneryPager>
pager;
575 SGSubsystemMgr::DISPLAY,
576 {{
"FGRenderer", SGSubsystemMgr::Dependency::NONSUBSYSTEM_HARD},
577 {
"SGSky", SGSubsystemMgr::Dependency::NONSUBSYSTEM_HARD}});
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter &, const Info &info)
virtual void apply(osg::Camera &camera)
const simgear::BVHMaterial * getMaterial() const
virtual void apply(osg::Group &group)
virtual void apply(osg::Node &node)
FGSceneryIntersect(const SGLineSegmentd &lineSegment, const osg::Node *skipNode)
const SGLineSegmentd & getLineSegment() const
virtual void apply(osg::MatrixTransform &transform)
virtual void apply(osg::PositionAttitudeTransform &transform)
virtual void apply(osg::CameraView &transform)
virtual void apply(osg::Transform &transform)
const char * root_node_path
virtual void valueChanged(SGPropertyNode *node)
void setupPropertyListener(SGPropertyNode_ptr elevationMeshNode, const char *node)
virtual void valueChanged(SGPropertyNode *node)
ScenerySwitchListener(FGScenery *scenery)
void setupPropertyListener(SGPropertyNode_ptr textureCacheNode, const char *node)
virtual void valueChanged(SGPropertyNode *node)
const char * root_node_path
static void resetPagerSingleton()
bool get_cart_elevation_m(const SGVec3d &pos, double max_altoff, double &elevation, const simgear::BVHMaterial **material, const osg::Node *butNotFrom=0)
Compute the elevation of the scenery below the cartesian point pos.
bool schedule_scenery(const SGGeod &position, double range_m, double duration=0.0)
bool get_cart_ground_intersection(const SGVec3d &start, const SGVec3d &dir, SGVec3d &nearestHit, const osg::Node *butNotFrom=0)
Compute the nearest intersection point of the line starting from start going in direction dir with th...
void update(double dt) override
bool get_elevation_m(const SGGeod &geod, double &alt, const simgear::BVHMaterial **material, const osg::Node *butNotFrom=0)
Compute the elevation of the scenery at geodetic latitude lat, geodetic longitude lon and not higher ...
void materialLibChanged()
friend class ElevationMeshListener
bool scenery_available(const SGGeod &position, double range_m)
Returns true if scenery is available for the given lat, lon position within a range of range_m.
static flightgear::SceneryPager * getPagerSingleton()
friend class ScenerySwitchListener
friend class TextureCacheListener
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
void addSentryBreadcrumb(const std::string &, const std::string &)
void addSentryTag(const char *, const char *)
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
SGSubsystemMgr::Registrant< FGScenery > registrantFGScenery(SGSubsystemMgr::DISPLAY, {{"FGRenderer", SGSubsystemMgr::Dependency::NONSUBSYSTEM_HARD}, {"SGSky", SGSubsystemMgr::Dependency::NONSUBSYSTEM_HARD}})
static osg::ref_ptr< SceneryPager > pager