FlightGear next
acmodel.cxx
Go to the documentation of this file.
1// acmodel.cxx - manage a 3D aircraft model.
2// Written by David Megginson, started 2002.
3//
4// This file is in the Public Domain, and comes with no warranty.
5
6#ifdef HAVE_CONFIG_H
7# include <config.h>
8#endif
9
10#include <cstring> // for strcmp()
11
12#include <simgear/compiler.h>
13#include <simgear/debug/ErrorReportingCallback.hxx>
14#include <simgear/debug/logstream.hxx>
15
16#include <simgear/structure/exception.hxx>
17#include <simgear/misc/sg_path.hxx>
18#include <simgear/scene/model/animation.hxx>
19#include <simgear/scene/model/placement.hxx>
20#include <simgear/scene/util/SGNodeMasks.hxx>
21#include <simgear/scene/model/modellib.hxx>
22
23#include <Main/globals.hxx>
24#include <Main/fg_props.hxx>
25#include <Viewer/renderer.hxx>
26#include <Viewer/viewmgr.hxx>
27#include <Viewer/view.hxx>
28#include <Scenery/scenery.hxx>
29#include <Sound/fg_fx.hxx>
30#include <GUI/Highlight.hxx>
31
32#include "acmodel.hxx"
33
34
35static osg::Node *
36fgLoad3DModel(const SGPath &path, SGPropertyNode *prop_root)
37{
38 bool autoTooltipsMaster = fgGetBool("/sim/rendering/automatic-animation-tooltips/enabled");
39 int autoTooltipsMasterMax = fgGetInt("/sim/rendering/automatic-animation-tooltips/max-count");
40 SG_LOG(SG_INPUT, SG_DEBUG, ""
41 << " autoTooltipsMaster=" << autoTooltipsMaster
42 << " autoTooltipsMasterMax=" << autoTooltipsMasterMax
43 );
44 osg::Node* node = simgear::SGModelLib::loadModel(path.utf8Str(), prop_root, NULL, autoTooltipsMaster, autoTooltipsMasterMax);
45 if (node)
46 node->setNodeMask(~SG_NODEMASK_TERRAIN_BIT);
47 return node;
48}
49
51// Implementation of FGAircraftModel
53
55 : _velocity(SGVec3d::zeros()),
56 _speed_n(0),
57 _speed_e(0),
58 _speed_d(0)
59{
60}
61
63{
64 // drop reference
65 _fx = 0;
66 shutdown();
67}
68
69
70// Gathers information about all animated nodes and the properties that they
71// depend on, and registers with Highlight::add_property_node().
72//
73struct VisitorHighlight : osg::NodeVisitor
74{
76 {
77 m_highlight = globals->get_subsystem<Highlight>();
78 setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
79 }
80 std::string spaces()
81 {
82 return std::string(m_level*4, ' ');
83 }
84 virtual void apply(osg::Node& node)
85 {
86 SG_LOG(SG_GENERAL, SG_DEBUG, spaces() << "node: " << node.libraryName() << "::" << node.className());
87 m_level += 1;
88 traverse(node);
89 m_level -= 1;
90 }
91 virtual void apply(osg::Group& group)
92 {
93 // Parent nodes of <group> are animated by properties in
94 // <m_highlight_names>, so register the association between <group> and
95 // these properties.
96 SG_LOG(SG_GENERAL, SG_DEBUG, spaces() << "group: " << group.libraryName() << "::" << group.className());
97 for (auto name: m_highlight_names)
98 {
99 if (m_highlight) {
100 m_highlight->addPropertyNode(name, &group);
101 }
102 }
103 m_level += 1;
104 traverse(group);
105 m_level -= 1;
106 }
107 virtual void apply( osg::Transform& node )
108 {
109 SG_LOG(SG_GENERAL, SG_DEBUG, spaces() << "transform: "
110 << node.libraryName() << "::" << node.className()
111 << ": " << typeid(node).name()
112 );
113
114 SGSharedPtr<SGExpressiond const> expression = TransformExpression(&node);
115 int num_added = 0;
116 if (expression) {
117 // All <nodes>'s child nodes will be affected by <expression> so
118 // add all of <expression>'s properties to <m_highlight_names> so
119 // that we can call Highlight::add_property_node() for each child
120 // node.
121 std::set<const SGPropertyNode*> properties;
122 expression->collectDependentProperties(properties);
123 SG_LOG(SG_GENERAL, SG_DEBUG, spaces() << typeid(node).name() << ":");
124 for (auto p: properties) {
125 SG_LOG(SG_GENERAL, SG_DEBUG, spaces() << " " << p->getPath(true));
126 num_added += 1;
127 m_highlight_names.push_back(p->getPath(true /*simplify*/));
128 }
129 }
130
131 m_level += 1;
132 traverse(node);
133 m_level -= 1;
134
135 // Remove the names we appended to <m_highlight_names> earlier.
136 assert((int) m_highlight_names.size() >= num_added);
137 m_highlight_names.resize(m_highlight_names.size() - num_added);
138 }
139 unsigned int m_level = 0; // Only used to indent diagnostics.
140 std::vector<std::string> m_highlight_names;
142};
143
144
145void
147{
148 if (_aircraft.get()) {
149 SG_LOG(SG_AIRCRAFT, SG_ALERT, "FGAircraftModel::init: already inited");
150 return;
151 }
152
153 simgear::ErrorReportContext ec("primary-aircraft", "yes");
154 _fx = new FGFX("fx");
155 _fx->init();
156
157 SGPropertyNode_ptr sim = fgGetNode("/sim", true);
158 for (auto model : sim->getChildren("model")) {
159 std::string path = model->getStringValue("path", "Models/Geometry/glider.ac");
160 std::string usage = model->getStringValue("usage", "external");
161
162 simgear::ErrorReportContext ec("aircraft-model", path);
163
164 SGPath resolvedPath = globals->resolve_aircraft_path(path);
165 if (resolvedPath.isNull()) {
166 simgear::reportFailure(simgear::LoadFailure::NotFound,
167 simgear::ErrorCode::XMLModelLoad,
168 "Failed to find aircraft model", SGPath::fromUtf8(path));
169 SG_LOG(SG_AIRCRAFT, SG_ALERT, "Failed to find aircraft model: " << path);
170 continue;
171 }
172
173 osg::Node* node = NULL;
174 try {
175 node = fgLoad3DModel(resolvedPath, globals->get_props());
176 } catch (const sg_exception &ex) {
177 simgear::reportFailure(simgear::LoadFailure::BadData,
178 simgear::ErrorCode::XMLModelLoad,
179 "Failed to load aircraft model:" + ex.getFormattedMessage(),
180 ex.getLocation());
181 SG_LOG(SG_AIRCRAFT, SG_ALERT, "Failed to load aircraft from " << path << ':');
182 SG_LOG(SG_AIRCRAFT, SG_ALERT, " " << ex.getFormattedMessage());
183 }
184
185 if (usage == "interior") {
186 // interior model
187 if (!_interior.get()) {
188 _interior.reset(new SGModelPlacement);
189 _interior->init(node);
190 } else {
191 _interior->add(node);
192 }
193 } else {
194 // normal / exterior model
195 if (!_aircraft.get()) {
196 _aircraft.reset(new SGModelPlacement);
197 _aircraft->init(node);
198 } else {
199 _aircraft->add(node);
200 }
201 } // of model usage switch
202 } // of models iteration
203
204 // no models loaded, load the glider instead
205 if (!_aircraft.get()) {
206 SG_LOG(SG_AIRCRAFT, SG_ALERT, "(Falling back to glider.ac.)");
207 osg::Node* model = fgLoad3DModel(SGPath::fromUtf8("Models/Geometry/glider.ac"),
208 globals->get_props());
209 _aircraft.reset(new SGModelPlacement);
210 _aircraft->init(model);
211
212 }
213
214 osg::Node* node = _aircraft->getSceneGraph();
215 globals->get_scenery()->get_aircraft_branch()->addChild(node);
216
217 if (_interior.get()) {
218 node = _interior->getSceneGraph();
219 globals->get_scenery()->get_interior_branch()->addChild(node);
220 }
221
222 // Register animated nodes and associated properties with Highlight.
223 VisitorHighlight visitor_highlight;
224 visitor_highlight.traverse(*node);
225}
226
227void
229{
230 shutdown();
231 _fx->reinit();
232 init();
233 // TODO globally create signals for all subsystems (re)initialized
234 fgSetBool("/sim/signals/model-reinit", true);
235}
236
237void
239{
240 FGScenery* scenery = globals->get_scenery();
241
242 if (_aircraft.get()) {
243 if (scenery && scenery->get_aircraft_branch()) {
244 scenery->get_aircraft_branch()->removeChild(_aircraft->getSceneGraph());
245 }
246 }
247
248 if (_interior.get()) {
249 if (scenery && scenery->get_interior_branch()) {
250 scenery->get_interior_branch()->removeChild(_interior->getSceneGraph());
251 }
252 }
253
254 _aircraft.reset();
255 _interior.reset();
256}
257
258void
260{
261 _speed_n = fgGetNode("velocities/speed-north-fps", true);
262 _speed_e = fgGetNode("velocities/speed-east-fps", true);
263 _speed_d = fgGetNode("velocities/speed-down-fps", true);
264}
265
266void
268{
269 _fx->unbind();
270}
271
272void
274{
275 int view_number = globals->get_viewmgr()->getCurrentViewIndex();
276 int is_internal = fgGetBool("/sim/current-view/internal");
277
278 if (view_number == 0 && !is_internal) {
279 _aircraft->setVisible(false);
280 } else {
281 _aircraft->setVisible(true);
282 }
283
284 double heading, pitch, roll;
285 globals->get_aircraft_orientation(heading, pitch, roll);
286 SGQuatd orient = SGQuatd::fromYawPitchRollDeg(heading, pitch, roll);
287
288 SGGeod pos = globals->get_aircraft_position();
289
290 _aircraft->setPosition(pos);
291 _aircraft->setOrientation(orient);
292 _aircraft->update();
293
294 if (_interior.get()) {
295 _interior->setPosition(pos);
296 _interior->setOrientation(orient);
297 _interior->update();
298 }
299
300 // update model's audio sample values
301 _fx->set_position_geod( pos );
302 _fx->set_orientation( orient );
303
304 _velocity = SGVec3d( _speed_n->getDoubleValue(),
305 _speed_e->getDoubleValue(),
306 _speed_d->getDoubleValue() );
307 _fx->set_velocity( _velocity );
308
309 float temp_c = fgGetFloat("/environment/temperature-degc");
310 float humidity = fgGetFloat("/environment/relative-humidity");
311 float pressure = fgGetFloat("/environment/pressure-inhg")*SG_INHG_TO_PA/1000.0f;
312 _fx->set_atmosphere( temp_c, humidity, pressure );
313}
314
315
316// Register the subsystem.
317SGSubsystemMgr::Registrant<FGAircraftModel> registrantFGAircraftModel(
318 SGSubsystemMgr::DISPLAY);
319
320// end of model.cxx
#define p(x)
static osg::Node * fgLoad3DModel(const SGPath &path, SGPropertyNode *prop_root)
Definition acmodel.cxx:36
SGSubsystemMgr::Registrant< FGAircraftModel > registrantFGAircraftModel(SGSubsystemMgr::DISPLAY)
void reinit() override
Definition acmodel.cxx:228
virtual ~FGAircraftModel()
Definition acmodel.cxx:62
void update(double dt) override
Definition acmodel.cxx:273
void shutdown() override
Definition acmodel.cxx:238
void bind() override
Definition acmodel.cxx:259
void init() override
Definition acmodel.cxx:146
void unbind() override
Definition acmodel.cxx:267
Generator for FlightGear model sound effects.
Definition fg_fx.hxx:48
osg::Group * get_aircraft_branch() const
Definition scenery.hxx:132
osg::Group * get_interior_branch() const
Definition scenery.hxx:133
const char * name
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
Definition fg_props.cxx:532
FGGlobals * globals
Definition globals.cxx:142
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
Definition proptest.cpp:25
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
Definition proptest.cpp:24
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27
float fgGetFloat(const char *name, float defaultValue)
Get a float value for a property.
Definition proptest.cpp:29
virtual void apply(osg::Transform &node)
Definition acmodel.cxx:107
virtual void apply(osg::Node &node)
Definition acmodel.cxx:84
std::string spaces()
Definition acmodel.cxx:80
std::vector< std::string > m_highlight_names
Definition acmodel.cxx:140
unsigned int m_level
Definition acmodel.cxx:139
virtual void apply(osg::Group &group)
Definition acmodel.cxx:91
Highlight * m_highlight
Definition acmodel.cxx:141
int usage()