Allow placing canvas on scenery objects.
[fg:hoorays-flightgear.git] / src / Scripting / NasalModelData.cxx
1
2 #include "NasalModelData.hxx"
3 #include "NasalSys.hxx"
4 #include <Main/globals.hxx>
5
6 #include <simgear/debug/logstream.hxx>
7
8 #include <boost/bind.hpp>
9
10 #include <algorithm>
11 #include <cstring> // for strlen
12
13 // FGNasalModelData class.  If sgLoad3DModel() is called with a pointer to
14 // such a class, then it lets modelLoaded() run the <load> script, and the
15 // destructor the <unload> script. The latter happens when the model branch
16 // is removed from the scene graph.
17
18 unsigned int FGNasalModelData::_max_module_id = 0;
19 FGNasalModelDataList FGNasalModelData::_loaded_models;
20
21 //------------------------------------------------------------------------------
22 FGNasalModelData::FGNasalModelData( SGPropertyNode *root,
23                                     const std::string& path,
24                                     SGPropertyNode *prop,
25                                     SGPropertyNode* load,
26                                     SGPropertyNode* unload,
27                                     osg::Node* branch ):
28   _path(path),
29   _root(root), _prop(prop),
30   _load(load), _unload(unload),
31   _branch(branch),
32   _module_id( _max_module_id++ )
33 {
34   _loaded_models.push_back(this);
35 }
36
37 //------------------------------------------------------------------------------
38 FGNasalModelData::~FGNasalModelData()
39 {
40   _loaded_models.remove(this);
41 }
42
43 //------------------------------------------------------------------------------
44 void FGNasalModelData::load()
45 {
46     std::stringstream m;
47     m << "__model" << _module_id;
48     _module = m.str();
49     
50     SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str());
51     
52     const char *s = _load ? _load->getStringValue() : "";
53     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
54     
55     // Add _module_id to script local hash to allow placing canvasses on objects
56     // inside the model.
57     nasalSys->getGlobals().createHash(_module).set("_module_id", _module_id);
58
59     naRef arg[2];
60     arg[0] = nasalSys->propNodeGhost(_root);
61     arg[1] = nasalSys->propNodeGhost(_prop);
62     nasalSys->createModule(_module.c_str(), _path.c_str(), s, strlen(s),
63                            _root, 2, arg);
64 }
65
66 //------------------------------------------------------------------------------
67 void FGNasalModelData::unload()
68 {
69     if (_module.empty())
70         return;
71
72     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
73     if(!nasalSys) {
74         SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script "
75                "without Nasal subsystem present.");
76         return;
77     }
78
79     SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str());
80
81     if (_unload)
82     {
83         const char *s = _unload->getStringValue();
84         nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root);
85     }
86
87     nasalSys->deleteModule(_module.c_str());
88 }
89
90 //------------------------------------------------------------------------------
91 osg::Node* FGNasalModelData::getNode()
92 {
93   return _branch;
94 }
95
96 //------------------------------------------------------------------------------
97 FGNasalModelData* FGNasalModelData::getByModuleId(unsigned int id)
98 {
99   FGNasalModelDataList::iterator it = std::find_if
100   (
101     _loaded_models.begin(),
102     _loaded_models.end(),
103     boost::bind(&FGNasalModelData::_module_id, _1) == id
104   );
105
106   if( it != _loaded_models.end() )
107     return *it;
108
109   return 0;
110 }
111
112 //------------------------------------------------------------------------------
113 FGNasalModelDataProxy::~FGNasalModelDataProxy()
114 {
115     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
116     // when necessary, register Nasal module to be destroyed/unloaded
117     // in the main thread.
118     if ((_data.valid())&&(nasalSys))
119         nasalSys->registerToUnload(_data);
120 }
121
122 //------------------------------------------------------------------------------
123 void FGNasalModelDataProxy::modelLoaded( const std::string& path,
124                                          SGPropertyNode *prop,
125                                          osg::Node *branch )
126 {
127     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
128     if(!nasalSys) {
129         SG_LOG(SG_NASAL, SG_WARN, "Trying to run a <load> script "
130                "without Nasal subsystem present.");
131         return;
132     }
133     
134     if(!prop)
135         return;
136     
137     SGPropertyNode *nasal = prop->getNode("nasal");
138     if(!nasal)
139         return;
140     
141     SGPropertyNode* load   = nasal->getNode("load");
142     SGPropertyNode* unload = nasal->getNode("unload");
143     
144     if ((!load) && (!unload))
145         return;
146     
147     _data = new FGNasalModelData(_root, path, prop, load, unload, branch);
148     
149     // register Nasal module to be created and loaded in the main thread.
150     nasalSys->registerToLoad(_data);
151 }