2 #include "NasalModelData.hxx"
3 #include "NasalSys.hxx"
4 #include <Main/fg_props.hxx>
5 #include <Main/globals.hxx>
7 #include <simgear/math/SGMath.hxx>
8 #include <simgear/nasal/cppbind/Ghost.hxx>
9 #include <simgear/scene/util/OsgDebug.hxx>
10 #include <simgear/scene/util/OsgMath.hxx>
11 #include <simgear/debug/logstream.hxx>
13 #include <osg/Transform>
15 #include <boost/bind.hpp>
18 #include <cstring> // for strlen
20 // FGNasalModelData class. If sgLoad3DModel() is called with a pointer to
21 // such a class, then it lets modelLoaded() run the <load> script, and the
22 // destructor the <unload> script. The latter happens when the model branch
23 // is removed from the scene graph.
25 unsigned int FGNasalModelData::_max_module_id = 0;
26 FGNasalModelDataList FGNasalModelData::_loaded_models;
28 typedef osg::ref_ptr<osg::Node> NodeRef;
29 typedef nasal::Ghost<NodeRef> NasalNode;
32 * Get position (lat, lon, elevation) and orientation (heading, pitch, roll) of
35 static naRef f_node_getPose( const osg::Node& node,
36 const nasal::CallContext& ctx )
38 osg::NodePathList parent_paths = node.getParentalNodePaths();
39 for( osg::NodePathList::const_iterator path = parent_paths.begin();
40 path != parent_paths.end();
43 osg::Matrix local_to_world = osg::computeLocalToWorld(*path);
44 if( !local_to_world.valid() )
47 SGGeod coord = SGGeod::fromCart( toSG(local_to_world.getTrans()) );
48 if( !coord.isValid() )
51 osg::Matrix local_frame = makeZUpFrameRelative(coord),
53 inv_local.invert_4x3(local_frame);
54 local_to_world.postMult(inv_local);
56 SGQuatd rotate = toSG(local_to_world.getRotate());
57 double hdg, pitch, roll;
58 rotate.getEulerDeg(hdg, pitch, roll);
60 nasal::Hash pose(ctx.to_nasal(coord), ctx.c);
61 pose.set("heading", hdg);
62 pose.set("pitch", pitch);
63 pose.set("roll", roll);
64 return pose.get_naRef();
70 //------------------------------------------------------------------------------
71 FGNasalModelData::FGNasalModelData( SGPropertyNode *root,
72 const std::string& path,
75 SGPropertyNode* unload,
78 _root(root), _prop(prop),
79 _load(load), _unload(unload),
81 _module_id( _max_module_id++ )
83 _loaded_models.push_back(this);
89 "New model with attached script(s) "
90 "(branch = " << branch << ","
91 " path = " << simgear::getNodePathString(branch) << ")"
95 //------------------------------------------------------------------------------
96 FGNasalModelData::~FGNasalModelData()
98 _loaded_models.remove(this);
104 "Removed model with script(s) (branch = " << _branch.get() << ")"
108 //------------------------------------------------------------------------------
109 void FGNasalModelData::load()
112 m << "__model" << _module_id;
115 SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str());
117 const char *s = _load ? _load->getStringValue() : "";
118 FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
120 // Add _module_id to script local hash to allow placing canvasses on objects
122 nasal::Hash module = nasalSys->getGlobals().createHash(_module);
123 module.set("_module_id", _module_id);
125 if( !NasalNode::isInit() )
127 NasalNode::init("osg.Node")
128 .method("getPose", &f_node_getPose);
131 module.set("_model", _branch);
134 arg[0] = nasalSys->propNodeGhost(_root);
135 arg[1] = nasalSys->propNodeGhost(_prop);
136 nasalSys->createModule(_module.c_str(), _path.c_str(), s, strlen(s),
140 //------------------------------------------------------------------------------
141 void FGNasalModelData::unload()
146 FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
148 SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script "
149 "without Nasal subsystem present.");
153 SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str());
157 const char *s = _unload->getStringValue();
158 nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root);
161 nasalSys->deleteModule(_module.c_str());
164 //------------------------------------------------------------------------------
165 osg::Node* FGNasalModelData::getNode()
167 return _branch.get();
170 //------------------------------------------------------------------------------
171 FGNasalModelData* FGNasalModelData::getByModuleId(unsigned int id)
173 FGNasalModelDataList::iterator it = std::find_if
175 _loaded_models.begin(),
176 _loaded_models.end(),
177 boost::bind(&FGNasalModelData::_module_id, _1) == id
180 if( it != _loaded_models.end() )
186 //------------------------------------------------------------------------------
187 FGNasalModelDataProxy::~FGNasalModelDataProxy()
189 FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
190 // when necessary, register Nasal module to be destroyed/unloaded
191 // in the main thread.
192 if ((_data.valid())&&(nasalSys))
193 nasalSys->registerToUnload(_data);
196 //------------------------------------------------------------------------------
197 void FGNasalModelDataProxy::modelLoaded( const std::string& path,
198 SGPropertyNode *prop,
201 if( fgGetBool("/sim/disable-embedded-nasal") )
207 SGPropertyNode *nasal = prop->getNode("nasal");
211 FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
218 "Can not load model script(s) (Nasal subsystem not available)."
223 SGPropertyNode* load = nasal->getNode("load");
224 SGPropertyNode* unload = nasal->getNode("unload");
226 if ((!load) && (!unload))
229 _data = new FGNasalModelData(_root, path, prop, load, unload, branch);
231 // register Nasal module to be created and loaded in the main thread.
232 nasalSys->registerToLoad(_data);