From eba03b5e469824ee8f1494723fcddbbc56155a08 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Thu, 21 Mar 2013 01:16:01 +0100 Subject: [PATCH] Allow placing canvas on scenery objects. --- src/Canvas/canvas_mgr.cxx | 43 ++++++++++--- src/Cockpit/od_gauge.cxx | 40 +++++++++++-- src/Cockpit/od_gauge.hxx | 44 ++++++++++++-- src/Scripting/NasalModelData.cxx | 100 ++++++++++++++++++++++++------- src/Scripting/NasalModelData.hxx | 49 +++++++++++---- src/Scripting/NasalSys.cxx | 3 +- src/Scripting/NasalSys.hxx | 4 ++ 7 files changed, 228 insertions(+), 55 deletions(-) diff --git a/src/Canvas/canvas_mgr.cxx b/src/Canvas/canvas_mgr.cxx index 8da7a5a85..b57dcaeb9 100644 --- a/src/Canvas/canvas_mgr.cxx +++ b/src/Canvas/canvas_mgr.cxx @@ -21,18 +21,45 @@ #include #include #include
+#include #include #include -using simgear::canvas::Canvas; +namespace sc = simgear::canvas; + +//------------------------------------------------------------------------------ +static sc::Placements addSceneObjectPlacement( SGPropertyNode* placement, + sc::CanvasPtr canvas ) +{ + int module_id = placement->getIntValue("module-id", -1); + if( module_id < 0 ) + return sc::Placements(); + + FGNasalModelData* model_data = + FGNasalModelData::getByModuleId( static_cast(module_id) ); + + if( !model_data ) + return sc::Placements(); + + if( !model_data->getNode() ) + return sc::Placements(); + + return FGODGauge::set_texture + ( + model_data->getNode(), + placement, + canvas->getTexture(), + canvas->getCullCallback() + ); +} //------------------------------------------------------------------------------ CanvasMgr::CanvasMgr(): simgear::canvas::CanvasMgr ( fgGetNode("/canvas/by-index", true), - simgear::canvas::SystemAdapterPtr( new canvas::FGCanvasSystemAdapter ) + sc::SystemAdapterPtr( new canvas::FGCanvasSystemAdapter ) ), _cb_model_reinit ( @@ -41,17 +68,19 @@ CanvasMgr::CanvasMgr(): fgGetNode("/sim/signals/model-reinit", true) ) { - Canvas::addPlacementFactory + sc::Canvas::addPlacementFactory ( "object", boost::bind ( - &FGODGauge::set_texture, + &FGODGauge::set_aircraft_texture, _1, - boost::bind(&Canvas::getTexture, _2), - boost::bind(&Canvas::getCullCallback, _2) + boost::bind(&sc::Canvas::getTexture, _2), + boost::bind(&sc::Canvas::getCullCallback, _2) ) ); + + sc::Canvas::addPlacementFactory("scenery-object", &addSceneObjectPlacement); } //------------------------------------------------------------------------------ @@ -87,6 +116,6 @@ CanvasMgr::getCanvasTexId(const simgear::canvas::CanvasPtr& canvas) const void CanvasMgr::handleModelReinit(SGPropertyNode*) { for(size_t i = 0; i < _elements.size(); ++i) - boost::static_pointer_cast(_elements[i]) + boost::static_pointer_cast(_elements[i]) ->reloadPlacements("object"); } diff --git a/src/Cockpit/od_gauge.cxx b/src/Cockpit/od_gauge.cxx index 4f569acb1..ff26b8f0c 100644 --- a/src/Cockpit/od_gauge.cxx +++ b/src/Cockpit/od_gauge.cxx @@ -303,23 +303,51 @@ class ReplaceStaticTextureVisitor: //------------------------------------------------------------------------------ simgear::canvas::Placements -FGODGauge::set_texture( const char* name, +FGODGauge::set_texture( osg::Node* branch, + const char * name, osg::Texture2D* new_texture ) { - osg::Group* root = globals->get_scenery()->get_aircraft_branch(); ReplaceStaticTextureVisitor visitor(name, new_texture); - root->accept(visitor); + branch->accept(visitor); return visitor.getPlacements(); } //------------------------------------------------------------------------------ simgear::canvas::Placements -FGODGauge::set_texture( SGPropertyNode* placement, +FGODGauge::set_aircraft_texture( const char* name, + osg::Texture2D* new_texture ) +{ + return set_texture + ( + globals->get_scenery()->get_aircraft_branch(), + name, + new_texture + ); +} + +//------------------------------------------------------------------------------ +simgear::canvas::Placements +FGODGauge::set_texture( osg::Node* branch, + SGPropertyNode* placement, osg::Texture2D* new_texture, osg::NodeCallback* cull_callback ) { - osg::Group* root = globals->get_scenery()->get_aircraft_branch(); ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback); - root->accept(visitor); + branch->accept(visitor); return visitor.getPlacements(); } + +//------------------------------------------------------------------------------ +simgear::canvas::Placements +FGODGauge::set_aircraft_texture( SGPropertyNode* placement, + osg::Texture2D* new_texture, + osg::NodeCallback* cull_callback ) +{ + return set_texture + ( + globals->get_scenery()->get_aircraft_branch(), + placement, + new_texture, + cull_callback + ); +} diff --git a/src/Cockpit/od_gauge.hxx b/src/Cockpit/od_gauge.hxx index cd22107ca..257865194 100644 --- a/src/Cockpit/od_gauge.hxx +++ b/src/Cockpit/od_gauge.hxx @@ -39,24 +39,42 @@ class FGODGauge: virtual ~FGODGauge(); /** - * Replace an opengl texture name inside the aircraft scene graph. + * Replace an opengl texture name inside a given branch of the scene graph. * This is to replace a static texture by a dynamic one - * @param name texture filename - * @param new_texture dynamic texture to replace the old one + * + * @param branch Scene graph branch to use for search + * @param name texture filename + * @param new_texture dynamic texture to replace the old one * @return A list of groups which override the given texture */ static - simgear::canvas::Placements set_texture( const char * name, + simgear::canvas::Placements set_texture( osg::Node* branch, + const char * name, osg::Texture2D* new_texture ); /** * Replace an opengl texture name inside the aircraft scene graph. + * This is to replace a static texture by a dynamic one + * + * @param branch Scene graph branch to search for matching + * @param name texture filename + * @param new_texture dynamic texture to replace the old one + * @return A list of groups which override the given texture + */ + static + simgear::canvas::Placements + set_aircraft_texture( const char * name, + osg::Texture2D* new_texture ); + + /** + * Replace an opengl texture name inside a given branch of the scene graph. * This is to replace a static texture by a dynamic one. The replacement * is base on certain filtering criteria which have to be stored in string * value childs of the placement node. Recognized nodes are: * - texture Match the name of the texture * - node Match the name of the object * - parent Match any of the object parents names (all the tree upwards) + * * @param placement the node containing the replacement criteria * @param new_texture dynamic texture to replace the old one * @param an optional cull callback which will be installed on any matching @@ -65,10 +83,26 @@ class FGODGauge: */ static simgear::canvas::Placements - set_texture( SGPropertyNode* placement, + set_texture( osg::Node* branch, + SGPropertyNode* placement, osg::Texture2D* new_texture, osg::NodeCallback* cull_callback = 0 ); + /** + * Replace an opengl texture name inside the aircraft scene graph. + * + * @param placement the node containing the replacement criteria + * @param new_texture dynamic texture to replace the old one + * @param an optional cull callback which will be installed on any matching + * object + * @return A list of groups which override the given texture + */ + static + simgear::canvas::Placements + set_aircraft_texture( SGPropertyNode* placement, + osg::Texture2D* new_texture, + osg::NodeCallback* cull_callback = 0 ); + }; #endif // _OD_GAUGE_HXX diff --git a/src/Scripting/NasalModelData.cxx b/src/Scripting/NasalModelData.cxx index 672cc6116..24033c527 100644 --- a/src/Scripting/NasalModelData.cxx +++ b/src/Scripting/NasalModelData.cxx @@ -1,24 +1,50 @@ #include "NasalModelData.hxx" - -#include // for strlen -#include - #include "NasalSys.hxx" #include
+#include + +#include + +#include +#include // for strlen // FGNasalModelData class. If sgLoad3DModel() is called with a pointer to // such a class, then it lets modelLoaded() run the script, and the // destructor the script. The latter happens when the model branch // is removed from the scene graph. -unsigned int FGNasalModelData::_module_id = 0; +unsigned int FGNasalModelData::_max_module_id = 0; +FGNasalModelDataList FGNasalModelData::_loaded_models; +//------------------------------------------------------------------------------ +FGNasalModelData::FGNasalModelData( SGPropertyNode *root, + const std::string& path, + SGPropertyNode *prop, + SGPropertyNode* load, + SGPropertyNode* unload, + osg::Node* branch ): + _path(path), + _root(root), _prop(prop), + _load(load), _unload(unload), + _branch(branch), + _module_id( _max_module_id++ ) +{ + _loaded_models.push_back(this); +} + +//------------------------------------------------------------------------------ +FGNasalModelData::~FGNasalModelData() +{ + _loaded_models.remove(this); +} + +//------------------------------------------------------------------------------ void FGNasalModelData::load() { std::stringstream m; - m << "__model" << _module_id++; + m << "__model" << _module_id; _module = m.str(); SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str()); @@ -26,6 +52,10 @@ void FGNasalModelData::load() const char *s = _load ? _load->getStringValue() : ""; FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal"); + // Add _module_id to script local hash to allow placing canvasses on objects + // inside the model. + nasalSys->getGlobals().createHash(_module).set("_module_id", _module_id); + naRef arg[2]; arg[0] = nasalSys->propNodeGhost(_root); arg[1] = nasalSys->propNodeGhost(_prop); @@ -33,31 +63,66 @@ void FGNasalModelData::load() _root, 2, arg); } +//------------------------------------------------------------------------------ void FGNasalModelData::unload() { if (_module.empty()) return; - + FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal"); if(!nasalSys) { SG_LOG(SG_NASAL, SG_WARN, "Trying to run an script " "without Nasal subsystem present."); return; } - + SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str()); - + if (_unload) { const char *s = _unload->getStringValue(); nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root); } - + nasalSys->deleteModule(_module.c_str()); } -void FGNasalModelDataProxy::modelLoaded(const std::string& path, SGPropertyNode *prop, - osg::Node *) +//------------------------------------------------------------------------------ +osg::Node* FGNasalModelData::getNode() +{ + return _branch; +} + +//------------------------------------------------------------------------------ +FGNasalModelData* FGNasalModelData::getByModuleId(unsigned int id) +{ + FGNasalModelDataList::iterator it = std::find_if + ( + _loaded_models.begin(), + _loaded_models.end(), + boost::bind(&FGNasalModelData::_module_id, _1) == id + ); + + if( it != _loaded_models.end() ) + return *it; + + return 0; +} + +//------------------------------------------------------------------------------ +FGNasalModelDataProxy::~FGNasalModelDataProxy() +{ + FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal"); + // when necessary, register Nasal module to be destroyed/unloaded + // in the main thread. + if ((_data.valid())&&(nasalSys)) + nasalSys->registerToUnload(_data); +} + +//------------------------------------------------------------------------------ +void FGNasalModelDataProxy::modelLoaded( const std::string& path, + SGPropertyNode *prop, + osg::Node *branch ) { FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal"); if(!nasalSys) { @@ -79,17 +144,8 @@ void FGNasalModelDataProxy::modelLoaded(const std::string& path, SGPropertyNode if ((!load) && (!unload)) return; - _data = new FGNasalModelData(_root, path, prop, load, unload); + _data = new FGNasalModelData(_root, path, prop, load, unload, branch); // register Nasal module to be created and loaded in the main thread. nasalSys->registerToLoad(_data); } - -FGNasalModelDataProxy::~FGNasalModelDataProxy() -{ - FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal"); - // when necessary, register Nasal module to be destroyed/unloaded - // in the main thread. - if ((_data.valid())&&(nasalSys)) - nasalSys->registerToUnload(_data); -} diff --git a/src/Scripting/NasalModelData.hxx b/src/Scripting/NasalModelData.hxx index ea472451b..8c8b13d6e 100644 --- a/src/Scripting/NasalModelData.hxx +++ b/src/Scripting/NasalModelData.hxx @@ -20,7 +20,9 @@ #include #include -using std::string; +class FGNasalModelData; +typedef SGSharedPtr FGNasalModelDataRef; +typedef std::list FGNasalModelDataList; /** Nasal model data container. * load and unload methods must be run in main thread (not thread-safe). */ @@ -28,26 +30,45 @@ class FGNasalModelData : public SGReferenced { public: /** Constructor to be run in an arbitrary thread. */ - FGNasalModelData(SGPropertyNode *root, const string& path, SGPropertyNode *prop, - SGPropertyNode* load, SGPropertyNode* unload) : - _path(path), - _root(root), _prop(prop), - _load(load), _unload(unload) - { - } + FGNasalModelData( SGPropertyNode *root, + const std::string& path, + SGPropertyNode *prop, + SGPropertyNode* load, + SGPropertyNode* unload, + osg::Node* branch ); + ~FGNasalModelData(); + /** Load hook. Always call from inside the main loop. */ void load(); /** Unload hook. Always call from inside the main loop. */ void unload(); + /** + * Get osg scenegraph node of model + */ + osg::Node* getNode(); + + /** + * Get FGNasalModelData for model with the given module id. Every scenery + * model containing a nasal load or unload tag gets assigned a module id + * automatically. + * + * @param id Module id + * @return model data or NULL if does not exists + */ + static FGNasalModelData* getByModuleId(unsigned int id); + private: - static unsigned int _module_id; - - string _module, _path; + static unsigned int _max_module_id; + static FGNasalModelDataList _loaded_models; + + std::string _module, _path; SGPropertyNode_ptr _root, _prop; SGConstPropertyNode_ptr _load, _unload; + osg::Node *_branch; + unsigned int _module_id; }; /** Thread-safe proxy for FGNasalModelData. @@ -64,11 +85,13 @@ public: ~FGNasalModelDataProxy(); - void modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *); + void modelLoaded( const std::string& path, + SGPropertyNode *prop, + osg::Node *branch ); protected: SGPropertyNode_ptr _root; - SGSharedPtr _data; + FGNasalModelDataRef _data; }; #endif // of NASAL_MODEL_DATA_HXX diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 184e75f7e..1ba313bcb 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -822,8 +822,7 @@ naRef FGNasalSys::wrappedPropsNode(SGPropertyNode* aProps) { static naRef wrapNodeFunc = naNil(); if (naIsNil(wrapNodeFunc)) { - nasal::Hash g(_globals, _context); - nasal::Hash props = g.get("props"); + nasal::Hash props = getGlobals().get("props"); wrapNodeFunc = props.get("wrapNode"); } diff --git a/src/Scripting/NasalSys.hxx b/src/Scripting/NasalSys.hxx index fc24f9959..b2c569e6a 100644 --- a/src/Scripting/NasalSys.hxx +++ b/src/Scripting/NasalSys.hxx @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,9 @@ public: naContext context() const { return _context; } + + nasal::Hash getGlobals() const + { return nasal::Hash(_globals, _context); } // This mechanism is here to allow naRefs to be passed to // locations "outside" the interpreter. Normally, such a