]> git.mxchange.org Git - simgear.git/blob - simgear/structure/subsystem_mgr.cxx
Boolean uniforms are now updatable by properties
[simgear.git] / simgear / structure / subsystem_mgr.cxx
1 // Written by David Megginson, started 2000-12
2 //
3 // Copyright (C) 2000  David Megginson, david@megginson.com
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //
19 // $Id$
20
21 #ifdef HAVE_CONFIG_H
22 #  include <simgear_config.h>
23 #endif
24
25 #include <simgear/debug/logstream.hxx>
26 #include <simgear/timing/timestamp.hxx>
27
28 #include "exception.hxx"
29 #include "subsystem_mgr.hxx"
30
31 #include <simgear/math/SGMath.hxx>
32 #include "SGSmplstat.hxx"
33
34 const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
35
36 ////////////////////////////////////////////////////////////////////////
37 // Implementation of SGSubsystem
38 ////////////////////////////////////////////////////////////////////////
39
40 SGSubsystemTimingCb SGSubsystem::reportTimingCb = NULL;
41 void* SGSubsystem::reportTimingUserData = NULL;
42
43 SGSubsystem::SGSubsystem ()
44   : _suspended(false)
45 {
46 }
47
48 SGSubsystem::~SGSubsystem ()
49 {
50 }
51
52 void
53 SGSubsystem::init ()
54 {
55 }
56
57 void
58 SGSubsystem::postinit ()
59 {
60 }
61
62 void
63 SGSubsystem::reinit ()
64 {
65 }
66
67 void
68 SGSubsystem::shutdown ()
69 {
70 }
71
72 void
73 SGSubsystem::bind ()
74 {
75 }
76
77 void
78 SGSubsystem::unbind ()
79 {
80 }
81
82 void
83 SGSubsystem::suspend ()
84 {
85   _suspended = true;
86 }
87
88 void
89 SGSubsystem::suspend (bool suspended)
90 {
91   _suspended = suspended;
92 }
93
94 void
95 SGSubsystem::resume ()
96 {
97   _suspended = false;
98 }
99
100 bool
101 SGSubsystem::is_suspended () const
102 {
103   return _suspended;
104 }
105
106 void SGSubsystem::stamp(const string& name)
107 {
108     timingInfo.push_back(TimingInfo(name, SGTimeStamp::now()));
109 }
110
111 \f
112 ////////////////////////////////////////////////////////////////////////
113 // Implementation of SGSubsystemGroup.
114 ////////////////////////////////////////////////////////////////////////
115
116 class SGSubsystemGroup::Member
117 {    
118 private:
119     Member (const Member &member);
120 public:
121     Member ();
122     virtual ~Member ();
123     
124     virtual void update (double delta_time_sec);
125
126     void reportTiming(void) { if (reportTimingCb) reportTimingCb(reportTimingUserData, name, &timeStat); }
127     void updateExecutionTime(double time) { timeStat += time;}
128
129     SampleStatistic timeStat;
130     std::string name;
131     SGSubsystem * subsystem;
132     double min_step_sec;
133     double elapsed_sec;
134     bool collectTimeStats;
135     int exceptionCount;
136 };
137
138
139
140 SGSubsystemGroup::SGSubsystemGroup () :
141   _fixedUpdateTime(-1.0),
142   _updateTimeRemainder(0.0)
143 {
144 }
145
146 SGSubsystemGroup::~SGSubsystemGroup ()
147 {
148     // reverse order to prevent order dependency problems
149     for (unsigned int i = _members.size(); i > 0; i--)
150     {
151         delete _members[i-1];
152     }
153 }
154
155 void
156 SGSubsystemGroup::init ()
157 {
158     for (unsigned int i = 0; i < _members.size(); i++)
159         _members[i]->subsystem->init();
160 }
161
162 void
163 SGSubsystemGroup::postinit ()
164 {
165     for (unsigned int i = 0; i < _members.size(); i++)
166         _members[i]->subsystem->postinit();
167 }
168
169 void
170 SGSubsystemGroup::reinit ()
171 {
172     for (unsigned int i = 0; i < _members.size(); i++)
173         _members[i]->subsystem->reinit();
174 }
175
176 void
177 SGSubsystemGroup::shutdown ()
178 {
179     // reverse order to prevent order dependency problems
180     for (unsigned int i = _members.size(); i > 0; i--)
181         _members[i-1]->subsystem->shutdown();
182 }
183
184 void
185 SGSubsystemGroup::bind ()
186 {
187     for (unsigned int i = 0; i < _members.size(); i++)
188         _members[i]->subsystem->bind();
189 }
190
191 void
192 SGSubsystemGroup::unbind ()
193 {
194     // reverse order to prevent order dependency problems
195     for (unsigned int i = _members.size(); i > 0; i--)
196        _members[i-1]->subsystem->unbind();
197 }
198
199 void
200 SGSubsystemGroup::update (double delta_time_sec)
201 {
202     int loopCount = 1;
203     // if dt == 0.0, we are paused, so we need to run one iteration
204     // of our members; if we have a fixed update time, we compute a
205     // loop count, and locally adjust dt
206     if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
207       double localDelta = delta_time_sec + _updateTimeRemainder;
208       loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
209       _updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
210       delta_time_sec = _fixedUpdateTime;
211     }
212
213     SGTimeStamp timeStamp;
214     while (loopCount-- > 0) {
215       for (unsigned int i = 0; i < _members.size(); i++)
216       {
217           bool recordTime = (reportTimingCb != NULL);
218           if (recordTime)
219               timeStamp = SGTimeStamp::now();
220
221           _members[i]->update(delta_time_sec); // indirect call
222
223           if ((recordTime)&&(reportTimingCb))
224           {
225               timeStamp = SGTimeStamp::now() - timeStamp;
226               _members[i]->updateExecutionTime(timeStamp.toUSecs());
227           }
228       }
229     } // of multiple update loop
230 }
231
232 void
233 SGSubsystemGroup::reportTiming(void)
234 {
235     for (unsigned int i = _members.size(); i > 0; i--)
236     {
237         _members[i-1]->reportTiming();
238     }
239 }
240
241 void
242 SGSubsystemGroup::suspend ()
243 {
244     for (unsigned int i = 0; i < _members.size(); i++)
245         _members[i]->subsystem->suspend();
246 }
247
248 void
249 SGSubsystemGroup::resume ()
250 {
251     for (unsigned int i = 0; i < _members.size(); i++)
252         _members[i]->subsystem->resume();
253 }
254
255 bool
256 SGSubsystemGroup::is_suspended () const
257 {
258     return false;
259 }
260
261 void
262 SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
263                                  double min_step_sec)
264 {
265     Member * member = get_member(name, true);
266     if (member->subsystem != 0)
267         delete member->subsystem;
268     member->name = name;
269     member->subsystem = subsystem;
270     member->min_step_sec = min_step_sec;
271 }
272
273 SGSubsystem *
274 SGSubsystemGroup::get_subsystem (const string &name)
275 {
276     Member * member = get_member(name);
277     if (member != 0)
278         return member->subsystem;
279     else
280         return 0;
281 }
282
283 void
284 SGSubsystemGroup::remove_subsystem (const string &name)
285 {
286     for (unsigned int i = 0; i < _members.size(); i++) {
287         if (name == _members[i]->name) {
288             _members.erase(_members.begin() + i);
289             return;
290         }
291     }
292 }
293
294 void
295 SGSubsystemGroup::set_fixed_update_time(double dt)
296 {
297   _fixedUpdateTime = dt;
298 }
299
300 bool
301 SGSubsystemGroup::has_subsystem (const string &name) const
302 {
303     return (((SGSubsystemGroup *)this)->get_member(name) != 0);
304 }
305
306 SGSubsystemGroup::Member *
307 SGSubsystemGroup::get_member (const string &name, bool create)
308 {
309     for (unsigned int i = 0; i < _members.size(); i++) {
310         if (_members[i]->name == name)
311             return _members[i];
312     }
313     if (create) {
314         Member * member = new Member;
315         _members.push_back(member);
316         return member;
317     } else {
318         return 0;
319     }
320 }
321
322
323 \f
324 ////////////////////////////////////////////////////////////////////////
325 // Implementation of SGSubsystemGroup::Member
326 ////////////////////////////////////////////////////////////////////////
327
328
329 SGSubsystemGroup::Member::Member ()
330     : name(""),
331       subsystem(0),
332       min_step_sec(0),
333       elapsed_sec(0),
334       exceptionCount(0)
335 {
336 }
337
338 // This shouldn't be called due to subsystem pointer ownership issues.
339 SGSubsystemGroup::Member::Member (const Member &)
340 {
341 }
342
343 SGSubsystemGroup::Member::~Member ()
344 {
345     delete subsystem;
346 }
347
348 void
349 SGSubsystemGroup::Member::update (double delta_time_sec)
350 {
351     elapsed_sec += delta_time_sec;
352     if (elapsed_sec < min_step_sec) {
353         return;
354     }
355     
356     if (subsystem->is_suspended()) {
357         return;
358     }
359     
360     try {
361       subsystem->update(elapsed_sec);
362       elapsed_sec = 0;
363     } catch (sg_exception& e) {
364       SG_LOG(SG_GENERAL, SG_ALERT, "caught exception processing subsystem:" << name
365         << "\nmessage:" << e.getMessage());
366       
367       if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
368         SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
369           ", suspending)");
370         subsystem->suspend();
371       }
372     }
373 }
374
375
376 ////////////////////////////////////////////////////////////////////////
377 // Implementation of SGSubsystemMgr.
378 ////////////////////////////////////////////////////////////////////////
379
380
381 SGSubsystemMgr::SGSubsystemMgr ()
382 {
383   for (int i = 0; i < MAX_GROUPS; i++) {
384     _groups[i] = new SGSubsystemGroup;
385   }
386 }
387
388 SGSubsystemMgr::~SGSubsystemMgr ()
389 {
390   // ensure get_subsystem returns NULL from now onwards,
391   // before the SGSubsystemGroup destructors are run
392   _subsystem_map.clear();
393   
394   for (int i = 0; i < MAX_GROUPS; i++) {
395     delete _groups[i];
396   }
397 }
398
399 void
400 SGSubsystemMgr::init ()
401 {
402     for (int i = 0; i < MAX_GROUPS; i++)
403             _groups[i]->init();
404 }
405
406 void
407 SGSubsystemMgr::postinit ()
408 {
409     for (int i = 0; i < MAX_GROUPS; i++)
410             _groups[i]->postinit();
411 }
412
413 void
414 SGSubsystemMgr::reinit ()
415 {
416     for (int i = 0; i < MAX_GROUPS; i++)
417             _groups[i]->reinit();
418 }
419
420 void
421 SGSubsystemMgr::shutdown ()
422 {
423     // reverse order to prevent order dependency problems
424     for (int i = MAX_GROUPS-1; i >= 0; i--)
425         _groups[i]->shutdown();
426 }
427
428
429 void
430 SGSubsystemMgr::bind ()
431 {
432     for (int i = 0; i < MAX_GROUPS; i++)
433         _groups[i]->bind();
434 }
435
436 void
437 SGSubsystemMgr::unbind ()
438 {
439     // reverse order to prevent order dependency problems
440     for (int i = MAX_GROUPS-1; i >= 0; i--)
441         _groups[i]->unbind();
442 }
443
444 void
445 SGSubsystemMgr::update (double delta_time_sec)
446 {
447     for (int i = 0; i < MAX_GROUPS; i++) {
448         _groups[i]->update(delta_time_sec);
449     }
450 }
451
452 void
453 SGSubsystemMgr::suspend ()
454 {
455     for (int i = 0; i < MAX_GROUPS; i++)
456         _groups[i]->suspend();
457 }
458
459 void
460 SGSubsystemMgr::resume ()
461 {
462     for (int i = 0; i < MAX_GROUPS; i++)
463         _groups[i]->resume();
464 }
465
466 bool
467 SGSubsystemMgr::is_suspended () const
468 {
469     return false;
470 }
471
472 void
473 SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
474                      GroupType group, double min_time_sec)
475 {
476     SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
477     get_group(group)->set_subsystem(name, subsystem, min_time_sec);
478
479     if (_subsystem_map.find(name) != _subsystem_map.end()) {
480         SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
481         throw sg_exception("duplicate subsystem");
482     }
483     _subsystem_map[name] = subsystem;
484 }
485
486 SGSubsystem* 
487 SGSubsystemMgr::remove(const char* name)
488 {
489   SubsystemDict::iterator s =_subsystem_map.find(name);
490   if (s == _subsystem_map.end()) {
491     return NULL;
492   }
493   
494   SGSubsystem* sub = s->second;
495   _subsystem_map.erase(s);
496   
497 // tedious part - we don't know which group the subsystem belongs too
498   for (int i = 0; i < MAX_GROUPS; i++) {
499     if (_groups[i]->get_subsystem(name) == sub) {
500       _groups[i]->remove_subsystem(name);
501       break;
502     }
503   } // of groups iteration
504   
505   return sub;
506 }
507
508
509 SGSubsystemGroup *
510 SGSubsystemMgr::get_group (GroupType group)
511 {
512     return _groups[group];
513 }
514
515 SGSubsystem *
516 SGSubsystemMgr::get_subsystem (const string &name) const
517 {
518     SubsystemDict::const_iterator s =_subsystem_map.find(name);
519
520     if (s == _subsystem_map.end())
521         return 0;
522     else
523         return s->second;
524 }
525
526 /** Trigger the timing callback to report data for all subsystems. */
527 void
528 SGSubsystemMgr::reportTiming()
529 {
530     for (int i = 0; i < MAX_GROUPS; i++) {
531         _groups[i]->reportTiming();
532     } // of groups iteration
533 }
534
535 // end of subsystem_mgr.cxx