diff --git a/src/Canvas/canvas_mgr.cxx b/src/Canvas/canvas_mgr.cxx index b0f747cca..60a929205 100644 --- a/src/Canvas/canvas_mgr.cxx +++ b/src/Canvas/canvas_mgr.cxx @@ -22,8 +22,10 @@ #include
#include #include +#include #include +#include namespace sc = simgear::canvas; @@ -54,6 +56,31 @@ static sc::Placements addSceneObjectPlacement( SGPropertyNode* placement, ); } + +//------------------------------------------------------------------------------ +static sc::Placements addDynamicModelPlacement(SGPropertyNode* placement, + sc::CanvasPtr canvas) +{ + const string dyn_model_path = placement->getStringValue("model-path"); + if (dyn_model_path.empty()) + return {}; + + auto modelmgr = globals->get_subsystem(); + if (!modelmgr) + return {}; + + FGModelMgr::Instance* model_instance = modelmgr->findInstanceByNodePath(dyn_model_path); + if (!model_instance || !model_instance->model || !model_instance->model->getSceneGraph()) + return {}; + + return FGODGauge::set_texture( + model_instance->model->getSceneGraph(), + placement, + canvas->getTexture(), + canvas->getCullCallback(), + canvas); +} + //------------------------------------------------------------------------------ CanvasMgr::CanvasMgr(): simgear::canvas::CanvasMgr( fgGetNode("/canvas/by-index", true) ), @@ -85,6 +112,7 @@ void CanvasMgr::init() }); sc::Canvas::addPlacementFactory("scenery-object", &addSceneObjectPlacement); + sc::Canvas::addPlacementFactory("dynamic-model", &addDynamicModelPlacement); } } simgear::canvas::CanvasMgr::init(); @@ -97,6 +125,7 @@ void CanvasMgr::shutdown() sc::Canvas::removePlacementFactory("object"); sc::Canvas::removePlacementFactory("scenery-object"); + sc::Canvas::removePlacementFactory("dynamic-model"); _gui_camera = 0; } diff --git a/src/Model/modelmgr.cxx b/src/Model/modelmgr.cxx index d43cac448..142ff6a7b 100644 --- a/src/Model/modelmgr.cxx +++ b/src/Model/modelmgr.cxx @@ -25,13 +25,59 @@ #include
#include +#include #include "modelmgr.hxx" using namespace simgear; -// OSGFIXME -// extern SGShadowVolume *shadows; +namespace { + +class CheckInstanceModelLoadedVisitor : public osg::NodeVisitor +{ +public: + CheckInstanceModelLoadedVisitor() : + osg::NodeVisitor(osg::NodeVisitor::NODE_VISITOR, osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) + {} + + ~CheckInstanceModelLoadedVisitor() = default; + + void apply(osg::Node& node) override + { + if (!_loaded) + return; + traverse(node); + } + + void apply(osg::ProxyNode& node) override + { + if (!_loaded) + return; + + for (unsigned i = 0; i < node.getNumFileNames(); ++i) { + if (node.getFileName(i).empty()) + continue; + + // Check if this is already loaded. + if (i < node.getNumChildren() && node.getChild(i)) + continue; + + _loaded=false; + return; + } + traverse(node); + } + + bool isLoaded() const + { + return _loaded; + } + +private: + bool _loaded = true; +}; + +} // of anonymous namespace FGModelMgr::FGModelMgr () { @@ -76,6 +122,10 @@ FGModelMgr::add_model (SGPropertyNode * node) const char *model_path = node->getStringValue("path", "Models/Geometry/glider.ac"); osg::Node *object; + Instance * instance = new Instance; + instance->loaded_node = node->addChild("loaded"); + instance->loaded_node->setBoolValue(false); + try { std::string fullPath = simgear::SGModelLib::findDataFile(model_path); object = SGModelLib::loadDeferredModel(fullPath, globals->get_props()); @@ -85,7 +135,6 @@ FGModelMgr::add_model (SGPropertyNode * node) return; } - Instance * instance = new Instance; SGModelPlacement *model = new SGModelPlacement; instance->model = model; instance->node = node; @@ -217,6 +266,7 @@ void FGModelMgr::update(double dt) model->setHeadingDeg(heading); instance->model->update(); + instance->checkLoaded(); }); } @@ -239,31 +289,55 @@ FGModelMgr::remove_instance (Instance * instance) } } - +FGModelMgr::Instance* +FGModelMgr::findInstanceByNodePath(const std::string& node_path) const +{ + if (node_path.empty()) + return nullptr; + + SGPropertyNode* node = fgGetNode(node_path, false); + if (!node) + return nullptr; + + auto it = std::find_if(_instances.begin(), _instances.end(), + [node](const Instance* instance) + { return instance->node == node; }); + + if (it == _instances.end()) { + return nullptr; + } + + return *it; +} + //////////////////////////////////////////////////////////////////////// // Implementation of FGModelMgr::Instance //////////////////////////////////////////////////////////////////////// -FGModelMgr::Instance::Instance () - : model(0), - node(0), - lon_deg_node(0), - lat_deg_node(0), - elev_ft_node(0), - roll_deg_node(0), - pitch_deg_node(0), - heading_deg_node(0), - shadow(false) -{ -} - FGModelMgr::Instance::~Instance () { - delete model; + delete model; } +bool FGModelMgr::Instance::checkLoaded() const +{ + if (!model) + return false; + + if (loaded_node->getBoolValue()) { + return true; + } + + CheckInstanceModelLoadedVisitor cilv; + model->getSceneGraph()->accept(cilv); + const bool loadedNow = cilv.isLoaded(); + + if (loadedNow) { + loaded_node->setBoolValue(true); + } + return loadedNow; +} - //////////////////////////////////////////////////////////////////////// // Implementation of FGModelMgr::Listener //////////////////////////////////////////////////////////////////////// diff --git a/src/Model/modelmgr.hxx b/src/Model/modelmgr.hxx index 59a7f5009..365e886b2 100644 --- a/src/Model/modelmgr.hxx +++ b/src/Model/modelmgr.hxx @@ -12,6 +12,8 @@ #include // for SG_USING_STD #include +#include + // Don't pull in headers, since we don't need them here. class SGPropertyNode; class SGModelPlacement; @@ -23,6 +25,7 @@ class SGModelPlacement; class FGModelMgr : public SGSubsystem { public: + /** * A dynamically-placed model using properties. * @@ -38,9 +41,8 @@ public: */ struct Instance { - Instance (); virtual ~Instance (); - SGModelPlacement * model; + SGModelPlacement * model = nullptr; SGPropertyNode_ptr node; SGPropertyNode_ptr lon_deg_node; SGPropertyNode_ptr lat_deg_node; @@ -48,7 +50,10 @@ public: SGPropertyNode_ptr roll_deg_node; SGPropertyNode_ptr pitch_deg_node; SGPropertyNode_ptr heading_deg_node; - bool shadow; + SGPropertyNode_ptr loaded_node; + bool shadow = false; + + bool checkLoaded() const; }; FGModelMgr (); @@ -86,6 +91,15 @@ public: */ virtual void remove_instance (Instance * instance); + + /** + * Finds an instance in the model manager from a given node path in the property tree. + * A possible path could be "models/model[0]" + * + * NOTE: the manager will delete the instance as well. + */ + Instance* findInstanceByNodePath(const std::string& nodePath) const; + private: /** * Listener class that adds models at runtime.