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