]> git.mxchange.org Git - flightgear.git/blob - src/Main/globals.cxx
Make sure the unbind method is called for all registered subsystems proir to deleting...
[flightgear.git] / src / Main / globals.cxx
1 // globals.cxx -- Global state that needs to be shared among the sim modules
2 //
3 // Written by Curtis Olson, started July 2000.
4 //
5 // Copyright (C) 2000  Curtis L. Olson - http://www.flightgear.org/~curt
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26
27 #include <simgear/structure/commands.hxx>
28 #include <simgear/misc/sg_path.hxx>
29 #include <simgear/timing/sg_time.hxx>
30 #include <simgear/ephemeris/ephemeris.hxx>
31 #include <simgear/magvar/magvar.hxx>
32 #include <simgear/scene/material/matlib.hxx>
33 #include <simgear/structure/subsystem_mgr.hxx>
34 #include <simgear/structure/event_mgr.hxx>
35
36 #include <Aircraft/controls.hxx>
37 #include <Airports/runways.hxx>
38 #include <ATCDCL/AIMgr.hxx>
39 #include <ATCDCL/ATCmgr.hxx>
40 #include <Autopilot/route_mgr.hxx>
41 #include <Cockpit/panel.hxx>
42 #include <GUI/new_gui.hxx>
43 #include <Model/acmodel.hxx>
44 #include <Model/modelmgr.hxx>
45 #include <MultiPlayer/multiplaymgr.hxx>
46 #include <Navaids/awynet.hxx>
47 #include <Scenery/scenery.hxx>
48 #include <Scenery/tilemgr.hxx>
49 #include <Navaids/navlist.hxx>
50
51 #include "globals.hxx"
52 #include "renderer.hxx"
53 #include "viewmgr.hxx"
54
55 #include "fg_props.hxx"
56 #include "fg_io.hxx"
57
58 \f
59 ////////////////////////////////////////////////////////////////////////
60 // Implementation of FGGlobals.
61 ////////////////////////////////////////////////////////////////////////
62
63 // global global :-)
64 FGGlobals *globals;
65
66
67 // Constructor
68 FGGlobals::FGGlobals() :
69     props( new SGPropertyNode ),
70     initial_state( NULL ),
71     locale( NULL ),
72     renderer( new FGRenderer ),
73     subsystem_mgr( new SGSubsystemMgr ),
74     event_mgr( new SGEventMgr ),
75     sim_time_sec( 0.0 ),
76     fg_root( "" ),
77     warp( 0 ),
78     warp_delta( 0 ),
79     time_params( NULL ),
80     ephem( NULL ),
81     mag( NULL ),
82     matlib( NULL ),
83     route_mgr( NULL ),
84     current_panel( NULL ),
85     ATC_mgr( NULL ),
86     AI_mgr( NULL ),
87     controls( NULL ),
88     viewmgr( NULL ),
89     commands( SGCommandMgr::instance() ),
90     acmodel( NULL ),
91     model_mgr( NULL ),
92     channel_options_list( NULL ),
93     initial_waypoints( NULL ),
94     scenery( NULL ),
95     tile_mgr( NULL ),
96     fontcache ( new FGFontCache ),
97     navlist( NULL ),
98     loclist( NULL ),
99     gslist( NULL ),
100     dmelist( NULL ),
101     tacanlist( NULL ),
102     carrierlist( NULL ),
103     channellist( NULL ),
104     airwaynet( NULL ),
105     multiplayer_mgr( NULL )
106 {
107 }
108
109
110 // Destructor
111 FGGlobals::~FGGlobals() 
112 {
113     delete renderer;
114 // The AIModels manager performs a number of actions upon
115     // Shutdown that implicitly assume that other subsystems
116     // are still operational (Due to the dynamic allocation and
117     // deallocation of AIModel objects. To ensure we can safely
118     // shut down all subsystems, make sure we take down the 
119     // AIModels system first.
120     subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("ai_model");
121     // FGInput (FGInputEvent) and FGDialog calls get_subsystem() in their destructors, 
122     // which is not safe since some subsystem are already deleted but can be referred.
123     // So these subsystems must be deleted prior to deleting subsystem_mgr unless
124     // ~SGSubsystemGroup and SGSubsystemMgr::get_subsystem are changed not to refer to
125     // deleted subsystems.
126     subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("input");
127     subsystem_mgr->get_group(SGSubsystemMgr::GENERAL)->remove_subsystem("gui");
128     subsystem_mgr->unbind();
129     delete subsystem_mgr;
130     delete event_mgr;
131     delete time_params;
132     delete ephem;
133     delete mag;
134     delete matlib;
135     delete route_mgr;
136     delete current_panel;
137
138     delete ATC_mgr;
139     delete AI_mgr;
140     delete controls;
141     delete viewmgr;
142
143 //     delete commands;
144     delete acmodel;
145     delete model_mgr;
146     delete channel_options_list;
147     delete initial_waypoints;
148     delete tile_mgr;
149     delete scenery;
150     delete fontcache;
151
152     delete navlist;
153     delete loclist;
154     delete gslist;
155     delete dmelist;
156     delete tacanlist;
157     delete carrierlist;
158     delete channellist;
159     delete airwaynet;
160     delete multiplayer_mgr;
161 }
162
163
164 // set the fg_root path
165 void FGGlobals::set_fg_root (const string &root) {
166     fg_root = root;
167
168     // append /data to root if it exists
169     SGPath tmp( fg_root );
170     tmp.append( "data" );
171     tmp.append( "version" );
172     if ( ulFileExists( tmp.c_str() ) ) {
173         fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root);
174         fg_root += "/data";
175         fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root);
176         SG_LOG(SG_GENERAL, SG_ALERT, "***\n***\n*** Warning: changing bad FG_ROOT/--fg-root to '"
177                 << fg_root << "'\n***\n***");
178     }
179
180     // remove /sim/fg-root before writing to prevent hijacking
181     SGPropertyNode *n = fgGetNode("/sim", true);
182     n->removeChild("fg-root", 0, false);
183     n = n->getChild("fg-root", 0, true);
184     n->setStringValue(fg_root.c_str());
185     n->setAttribute(SGPropertyNode::WRITE, false);
186 }
187
188 void FGGlobals::set_fg_scenery (const string &scenery) {
189     SGPath s;
190     if (scenery.empty()) {
191         s.set( fg_root );
192         s.append( "Scenery" );
193     } else
194         s.set( scenery );
195
196     string_list path_list = sgPathSplit( s.str() );
197     fg_scenery.clear();
198
199     for (unsigned i = 0; i < path_list.size(); i++) {
200
201         ulDir *d = ulOpenDir( path_list[i].c_str() );
202         if (d == NULL)
203             continue;
204         ulCloseDir( d );
205
206         SGPath pt( path_list[i] ), po( path_list[i] );
207         pt.append("Terrain");
208         po.append("Objects");
209
210         ulDir *td = ulOpenDir( pt.c_str() );
211         ulDir *od = ulOpenDir( po.c_str() );
212
213         // "Terrain" and "Airports" directory don't exist. add directory as is
214         // otherwise, automatically append either Terrain, Objects, or both
215         //if (td == NULL && od == NULL)
216             fg_scenery.push_back( path_list[i] );
217         //else {
218             if (td != NULL) {
219                 fg_scenery.push_back( pt.str() );
220                 ulCloseDir( td );
221             }
222             if (od != NULL) {
223                 fg_scenery.push_back( po.str() );
224                 ulCloseDir( od );
225             }
226         //}
227         // insert a marker for FGTileEntry::load(), so that
228         // FG_SCENERY=A:B becomes list ["A/Terrain", "A/Objects", "",
229         // "B/Terrain", "B/Objects", ""]
230         fg_scenery.push_back("");
231     }
232 }
233
234
235 FGRenderer *
236 FGGlobals::get_renderer () const
237 {
238    return renderer;
239 }
240
241 SGSubsystemMgr *
242 FGGlobals::get_subsystem_mgr () const
243 {
244     return subsystem_mgr;
245 }
246
247 SGSubsystem *
248 FGGlobals::get_subsystem (const char * name)
249 {
250     return subsystem_mgr->get_subsystem(name);
251 }
252
253 void
254 FGGlobals::add_subsystem (const char * name,
255                           SGSubsystem * subsystem,
256                           SGSubsystemMgr::GroupType type,
257                           double min_time_sec)
258 {
259     subsystem_mgr->add(name, subsystem, type, min_time_sec);
260 }
261
262
263 SGEventMgr *
264 FGGlobals::get_event_mgr () const
265 {
266     return event_mgr;
267 }
268
269
270 // Save the current state as the initial state.
271 void
272 FGGlobals::saveInitialState ()
273 {
274   initial_state = new SGPropertyNode();
275
276   if (!copyProperties(props, initial_state))
277     SG_LOG(SG_GENERAL, SG_ALERT, "Error saving initial state");
278 }
279
280
281 // Restore the saved initial state, if any
282 void
283 FGGlobals::restoreInitialState ()
284 {
285     if ( initial_state == 0 ) {
286         SG_LOG(SG_GENERAL, SG_ALERT,
287                "No initial state available to restore!!!");
288         return;
289     }
290
291     SGPropertyNode *currentPresets = new SGPropertyNode;
292     SGPropertyNode *targetNode = fgGetNode( "/sim/presets" );
293
294     // stash the /sim/presets tree
295     if ( !copyProperties(targetNode, currentPresets) ) {
296         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to save /sim/presets subtree" );
297     }
298     
299     if ( copyProperties(initial_state, props) ) {
300         SG_LOG( SG_GENERAL, SG_INFO, "Initial state restored successfully" );
301     } else {
302         SG_LOG( SG_GENERAL, SG_INFO,
303                 "Some errors restoring initial state (read-only props?)" );
304     }
305
306     // recover the /sim/presets tree
307     if ( !copyProperties(currentPresets, targetNode) ) {
308         SG_LOG( SG_GENERAL, SG_ALERT,
309                 "Failed to restore /sim/presets subtree" );
310     }
311
312    delete currentPresets;
313 }
314
315 FGViewer *
316 FGGlobals::get_current_view () const
317 {
318   return viewmgr->get_current_view();
319 }
320
321 // end of globals.cxx