]> git.mxchange.org Git - flightgear.git/commitdiff
Allow placing canvas on scenery objects.
authorThomas Geymayer <tomgey@gmail.com>
Thu, 21 Mar 2013 00:16:01 +0000 (01:16 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Thu, 21 Mar 2013 00:16:47 +0000 (01:16 +0100)
src/Canvas/canvas_mgr.cxx
src/Cockpit/od_gauge.cxx
src/Cockpit/od_gauge.hxx
src/Scripting/NasalModelData.cxx
src/Scripting/NasalModelData.hxx
src/Scripting/NasalSys.cxx
src/Scripting/NasalSys.hxx

index 8da7a5a85494fbf2f0adff8e4b583dad9e3e39df..b57dcaeb91952137159e1672ad1c8baa55f3dc0d 100644 (file)
 #include <Canvas/FGCanvasSystemAdapter.hxx>
 #include <Cockpit/od_gauge.hxx>
 #include <Main/fg_props.hxx>
+#include <Scripting/NasalModelData.hxx>
 #include <Viewer/CameraGroup.hxx>
 
 #include <simgear/canvas/Canvas.hxx>
 
-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<unsigned int>(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<Canvas>(_elements[i])
+    boost::static_pointer_cast<sc::Canvas>(_elements[i])
       ->reloadPlacements("object");
 }
index 4f569acb1af97733c67d753b7d51335301c99108..ff26b8f0c09cfea1dbf08750e4c3470d16ef7e70 100644 (file)
@@ -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
+  );
+}
index cd22107ca4ba663d0828408cccc752b43f82dc4c..2578651945508992f7da59a32e33fc7619f08b80 100644 (file)
@@ -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
index 672cc6116f5c9fcf45ce8503b94bb72cf1412900..24033c527f69d559b4cf640592cd13ed64cc72d3 100644 (file)
@@ -1,24 +1,50 @@
 
 #include "NasalModelData.hxx"
+#include "NasalSys.hxx"
+#include <Main/globals.hxx>
 
-#include <cstring> // for strlen
 #include <simgear/debug/logstream.hxx>
 
-#include "NasalSys.hxx"
-#include <Main/globals.hxx>
+#include <boost/bind.hpp>
 
+#include <algorithm>
+#include <cstring> // for strlen
 
 // FGNasalModelData class.  If sgLoad3DModel() is called with a pointer to
 // such a class, then it lets modelLoaded() run the <load> script, and the
 // destructor the <unload> 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 <unload> 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);
-}
index ea472451b9de71bce4691df9666b3affb0426239..8c8b13d6e1dd2e52f0996c414a7505aff25314e6 100644 (file)
@@ -20,7 +20,9 @@
 #include <simgear/nasal/nasal.h>
 #include <simgear/scene/model/modellib.hxx>
 
-using std::string;
+class FGNasalModelData;
+typedef SGSharedPtr<FGNasalModelData> FGNasalModelDataRef;
+typedef std::list<FGNasalModelData*> 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<FGNasalModelData> _data;
+    FGNasalModelDataRef _data;
 };
 
 #endif // of NASAL_MODEL_DATA_HXX
index 184e75f7eb09b6bd17ca78797bff8af788a14922..1ba313bcba981638bb06965cd4b2b9a01c439ada 100644 (file)
@@ -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<nasal::Hash>("props");
+        nasal::Hash props = getGlobals().get<nasal::Hash>("props");
         wrapNodeFunc = props.get("wrapNode");
     }
     
index fc24f9959b9d57fe3e53d73619b8a1a4a0c3753b..b2c569e6a325d52e5b36fe487c1771782600701b 100644 (file)
@@ -4,6 +4,7 @@
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/misc/sg_dir.hxx>
+#include <simgear/nasal/cppbind/NasalHash.hxx>
 #include <simgear/nasal/nasal.h>
 #include <simgear/threads/SGQueue.hxx>
 #include <simgear/props/props.hxx>
@@ -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