]> git.mxchange.org Git - flightgear.git/blob - src/Scripting/NasalModelData.cxx
MapWidget: silence compiler warning
[flightgear.git] / src / Scripting / NasalModelData.cxx
1
2 #include "NasalModelData.hxx"
3 #include "NasalSys.hxx"
4 #include <Main/fg_props.hxx>
5 #include <Main/globals.hxx>
6
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>
12
13 #include <osg/Transform>
14
15 #include <boost/bind.hpp>
16
17 #include <algorithm>
18 #include <cstring> // for strlen
19
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.
24
25 unsigned int FGNasalModelData::_max_module_id = 0;
26 FGNasalModelDataList FGNasalModelData::_loaded_models;
27
28 typedef osg::ref_ptr<osg::Node> NodeRef;
29 typedef nasal::Ghost<NodeRef> NasalNode;
30
31 /**
32  * Get position (lat, lon, elevation) and orientation (heading, pitch, roll) of
33  * model.
34  */
35 static naRef f_node_getPose( const osg::Node& node,
36                              const nasal::CallContext& ctx )
37 {
38   osg::NodePathList parent_paths = node.getParentalNodePaths();
39   for( osg::NodePathList::const_iterator path = parent_paths.begin();
40                                          path != parent_paths.end();
41                                        ++path )
42   {
43     osg::Matrix local_to_world = osg::computeLocalToWorld(*path);
44     if( !local_to_world.valid() )
45       continue;
46
47     SGGeod coord = SGGeod::fromCart( toSG(local_to_world.getTrans()) );
48     if( !coord.isValid() )
49       continue;
50
51     osg::Matrix local_frame = makeZUpFrameRelative(coord),
52                 inv_local;
53     inv_local.invert_4x3(local_frame);
54     local_to_world.postMult(inv_local);
55
56     SGQuatd rotate = toSG(local_to_world.getRotate());
57     double hdg, pitch, roll;
58     rotate.getEulerDeg(hdg, pitch, roll);
59
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();
65   }
66
67   return naNil();
68 }
69
70 //------------------------------------------------------------------------------
71 FGNasalModelData::FGNasalModelData( SGPropertyNode *root,
72                                     const std::string& path,
73                                     SGPropertyNode *prop,
74                                     SGPropertyNode* load,
75                                     SGPropertyNode* unload,
76                                     osg::Node* branch ):
77   _path(path),
78   _root(root), _prop(prop),
79   _load(load), _unload(unload),
80   _branch(branch),
81   _module_id( _max_module_id++ )
82 {
83   _loaded_models.push_back(this);
84
85   SG_LOG
86   (
87     SG_NASAL,
88     SG_INFO,
89     "New model with attached script(s) "
90     "(branch = " << branch << ","
91     " path = " << simgear::getNodePathString(branch) << ")"
92   );
93 }
94
95 //------------------------------------------------------------------------------
96 FGNasalModelData::~FGNasalModelData()
97 {
98   _loaded_models.remove(this);
99
100   SG_LOG
101   (
102     SG_NASAL,
103     SG_INFO,
104     "Removed model with script(s) (branch = " << _branch.get() << ")"
105   );
106 }
107
108 //------------------------------------------------------------------------------
109 void FGNasalModelData::load()
110 {
111   std::stringstream m;
112   m << "__model" << _module_id;
113   _module = m.str();
114
115   SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str());
116
117   const char *s = _load ? _load->getStringValue() : "";
118   FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
119
120   // Add _module_id to script local hash to allow placing canvasses on objects
121   // inside the model.
122   nasal::Hash module = nasalSys->getGlobals().createHash(_module);
123   module.set("_module_id", _module_id);
124
125   NasalNode::init("osg.Node")
126       .method("getPose", &f_node_getPose);
127   module.set("_model", _branch);
128
129   naRef arg[2];
130   arg[0] = nasalSys->propNodeGhost(_root);
131   arg[1] = nasalSys->propNodeGhost(_prop);
132   nasalSys->createModule(_module.c_str(), _path.c_str(), s, strlen(s),
133                          _root, 2, arg);
134 }
135
136 //------------------------------------------------------------------------------
137 void FGNasalModelData::unload()
138 {
139     if (_module.empty())
140         return;
141
142     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
143     if(!nasalSys) {
144         SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script "
145                "without Nasal subsystem present.");
146         return;
147     }
148
149     SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str());
150
151     if (_unload)
152     {
153         const char *s = _unload->getStringValue();
154         nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root);
155     }
156
157     nasalSys->deleteModule(_module.c_str());
158 }
159
160 //------------------------------------------------------------------------------
161 osg::Node* FGNasalModelData::getNode()
162 {
163   return _branch.get();
164 }
165
166 //------------------------------------------------------------------------------
167 FGNasalModelData* FGNasalModelData::getByModuleId(unsigned int id)
168 {
169   FGNasalModelDataList::iterator it = std::find_if
170   (
171     _loaded_models.begin(),
172     _loaded_models.end(),
173     boost::bind(&FGNasalModelData::_module_id, _1) == id
174   );
175
176   if( it != _loaded_models.end() )
177     return *it;
178
179   return 0;
180 }
181
182 //------------------------------------------------------------------------------
183 FGNasalModelDataProxy::~FGNasalModelDataProxy()
184 {
185     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
186     // when necessary, register Nasal module to be destroyed/unloaded
187     // in the main thread.
188     if ((_data.valid())&&(nasalSys))
189         nasalSys->registerToUnload(_data);
190 }
191
192 //------------------------------------------------------------------------------
193 void FGNasalModelDataProxy::modelLoaded( const std::string& path,
194                                          SGPropertyNode *prop,
195                                          osg::Node *branch )
196 {
197     if( fgGetBool("/sim/disable-embedded-nasal") )
198         return;
199
200     if(!prop)
201         return;
202     
203     SGPropertyNode *nasal = prop->getNode("nasal");
204     if(!nasal)
205         return;
206     
207     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
208     if(!nasalSys)
209     {
210         SG_LOG
211         (
212           SG_NASAL,
213           SG_WARN,
214           "Can not load model script(s) (Nasal subsystem not available)."
215         );
216         return;
217     }
218
219     SGPropertyNode* load   = nasal->getNode("load");
220     SGPropertyNode* unload = nasal->getNode("unload");
221     
222     if ((!load) && (!unload))
223         return;
224
225     _data = new FGNasalModelData(_root, path, prop, load, unload, branch);
226     
227     // register Nasal module to be created and loaded in the main thread.
228     nasalSys->registerToLoad(_data);
229 }