#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
(
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);
}
//------------------------------------------------------------------------------
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");
}
//------------------------------------------------------------------------------
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
+ );
+}
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
*/
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
#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());
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);
_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) {
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);
-}
#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). */
{
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.
~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
{
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");
}
#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>
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