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