Move FGEventMgr and FGSubsystemMgr over to SimGear, add SGEventMgr to FlightGear's globals structre and some small code cleanups

This commit is contained in:
ehofman 2003-09-24 17:19:22 +00:00
parent f3eeeb760f
commit d22640ef4e
18 changed files with 1322 additions and 11 deletions

View File

@ -367,6 +367,7 @@ AC_CONFIG_FILES([ \
simgear/screen/Makefile \
simgear/serial/Makefile \
simgear/sound/Makefile \
simgear/structure/Makefile \
simgear/threads/Makefile \
simgear/timing/Makefile \
simgear/xgl/Makefile \

View File

@ -30,6 +30,7 @@ SUBDIRS = \
serial \
sound \
$(SGTHREAD_DIR) \
structure \
timing \
xgl

View File

@ -3,8 +3,6 @@ includedir = @includedir@/misc
lib_LIBRARIES = libsgmisc.a
include_HEADERS = \
commands.hxx \
exception.hxx \
sg_path.hxx \
sgstream.hxx \
stopwatch.hxx \
@ -14,8 +12,6 @@ include_HEADERS = \
zfstream.hxx
libsgmisc_a_SOURCES = \
commands.cxx \
exception.cxx \
sg_path.cxx \
sgstream.cxx \
strutils.cxx \

View File

@ -13,10 +13,9 @@
// #include STL_IOSTREAM
#include <simgear/misc/exception.hxx>
#include <simgear/structure/exception.hxx>
#include "props.hxx"
#include "condition.hxx"
SG_USING_STD(istream);

View File

@ -37,7 +37,7 @@
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/misc/exception.hxx>
#include <simgear/structure/exception.hxx>
#include <string.h>
#include STL_STRING

View File

@ -17,13 +17,12 @@
#include <plib/ssg.h>
#include <plib/ul.h>
#include <simgear/misc/exception.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include "animation.hxx"
#include "model.hxx"
SG_USING_STD(vector);

View File

@ -0,0 +1,3 @@
.deps
Makefile
Makefile.in

View File

@ -0,0 +1,20 @@
includedir = @includedir@/structure
lib_LIBRARIES = libsgstructure.a
include_HEADERS = \
callback.hxx \
commands.hxx \
exception.hxx \
event_mgr.hxx \
subsystem_mgr.hxx
libsgstructure_a_SOURCES = \
commands.cxx \
exception.cxx \
event_mgr.cxx\
subsystem_mgr.cxx
INCLUDES = -I$(top_srcdir)

View File

@ -0,0 +1,148 @@
/**************************************************************************
* callback.hxx -- Wrapper classes to treat function and method pointers
* as objects.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
**************************************************************************/
#ifndef _SG_CALLBACK_HXX
#define _SG_CALLBACK_HXX
/**
* Abstract base class for all callbacks.
*/
class SGCallback
{
public:
/**
*
*/
virtual ~SGCallback() {}
/**
*
*/
virtual SGCallback* clone() const = 0;
/**
* Execute the callback function.
*/
virtual void operator()() = 0;
protected:
/**
*
*/
SGCallback() {}
private:
// Not implemented.
void operator=( const SGCallback& );
};
/**
* Callback for invoking a file scope function.
*/
template< typename Fun >
class SGFunctionCallback : public SGCallback
{
public:
/**
*
*/
SGFunctionCallback( const Fun& fun )
: SGCallback(), f_(fun) {}
SGCallback* clone() const
{
return new SGFunctionCallback( *this );
}
void operator()() { f_(); }
private:
// Not defined.
SGFunctionCallback();
private:
Fun f_;
};
/**
* Callback for invoking a member function.
*/
template< class ObjPtr, typename MemFn >
class SGMethodCallback : public SGCallback
{
public:
/**
*
*/
SGMethodCallback( const ObjPtr& pObj, MemFn pMemFn )
: SGCallback(),
pObj_(pObj),
pMemFn_(pMemFn)
{
}
/**
*
*/
SGCallback* clone() const
{
return new SGMethodCallback( *this );
}
/**
*
*/
void operator()()
{
((*pObj_).*pMemFn_)();
}
private:
// Not defined.
SGMethodCallback();
private:
ObjPtr pObj_;
MemFn pMemFn_;
};
/**
* Helper template functions.
*/
template< typename Fun >
SGCallback*
make_callback( const Fun& fun )
{
return new SGFunctionCallback<Fun>(fun);
}
template< class ObjPtr, typename MemFn >
SGCallback*
make_callback( const ObjPtr& pObj, MemFn pMemFn )
{
return new SGMethodCallback<ObjPtr,MemFn>(pObj, pMemFn );
}
#endif // _SG_CALLBACK_HXX

View File

@ -0,0 +1,258 @@
//
// SGEventMgr.cxx -- Event Manager
//
// Written by Bernie Bright, started April 2002.
//
// Copyright (C) 2002 Curtis L. Olson - curt@me.umn.edu
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include "event_mgr.hxx"
SGEvent::SGEvent()
: _name(""),
_callback(0),
_subsystem(0),
_repeat_value(0),
_initial_value(0),
_ms_to_go(0),
_cum_time(0),
_min_time(100000),
_max_time(0),
_count(0)
{
}
SGEvent::SGEvent( const char* name,
SGCallback* cb,
interval_type repeat_value,
interval_type initial_value )
: _name(name),
_callback(cb),
_subsystem(NULL),
_repeat_value(repeat_value),
_initial_value(initial_value),
_cum_time(0),
_min_time(100000),
_max_time(0),
_count(0)
{
if (_initial_value < 0)
{
this->run();
_ms_to_go = _repeat_value;
}
else
{
_ms_to_go = _initial_value;
}
}
SGEvent::SGEvent( const char* name,
const SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value )
: _name(name),
_callback(NULL),
_subsystem((SGSubsystem*)&subsystem),
_repeat_value(repeat_value),
_initial_value(initial_value),
_cum_time(0),
_min_time(100000),
_max_time(0),
_count(0)
{
if (_initial_value < 0)
{
this->run();
_ms_to_go = _repeat_value;
}
else
{
_ms_to_go = _initial_value;
}
}
SGEvent::~SGEvent()
{
//delete callback_;
}
void
SGEvent::run()
{
SGTimeStamp start_time;
SGTimeStamp finish_time;
start_time.stamp();
// run the event
if (_callback)
{
(*_callback)();
} else if (_subsystem)
{
_subsystem->update(_repeat_value);
}
finish_time.stamp();
++_count;
unsigned long duration = finish_time - start_time;
_cum_time += duration;
if ( duration < _min_time ) {
_min_time = duration;
}
if ( duration > _max_time ) {
_max_time = duration;
}
}
void
SGEvent::print_stats() const
{
SG_LOG( SG_EVENT, SG_INFO,
" " << _name
<< " int=" << _repeat_value / 1000.0
<< " cum=" << _cum_time
<< " min=" << _min_time
<< " max=" << _max_time
<< " count=" << _count
<< " ave=" << _cum_time / (double)_count );
}
SGEventMgr::SGEventMgr()
{
}
SGEventMgr::~SGEventMgr()
{
}
void
SGEventMgr::init()
{
SG_LOG( SG_EVENT, SG_INFO, "Initializing event manager" );
event_table.clear();
}
void
SGEventMgr::reinit()
{
}
void
SGEventMgr::bind()
{
}
void
SGEventMgr::unbind()
{
}
void
SGEventMgr::update( double dt )
{
int dt_ms = int(dt * 1000);
if (dt_ms < 0)
{
SG_LOG( SG_GENERAL, SG_ALERT,
"SGEventMgr::update() called with negative delta T" );
return;
}
int min_value = 0;
event_container_type::iterator first = event_table.begin();
event_container_type::iterator last = event_table.end();
event_container_type::iterator event = event_table.end();
// Scan all events. Run one whose interval has expired.
while (first != last)
{
if (first->update( dt_ms ))
{
if (first->value() < min_value)
{
// Select event with largest negative value.
// Its been waiting longest.
min_value = first->value();
event = first;
}
}
++first;
}
if (event != last)
{
event->run();
if (event->repeat_value() > 0)
{
event->reset();
}
else
{
SG_LOG( SG_GENERAL, SG_DEBUG, "Deleting event " << event->name() );
event_table.erase( event );
}
}
}
void
SGEventMgr::add( const SGEvent& event )
{
event_table.push_back( event );
SG_LOG( SG_EVENT, SG_INFO, "registered event " << event.name()
<< " to run every " << event.repeat_value() << "ms" );
}
void
SGEventMgr::print_stats() const
{
SG_LOG( SG_EVENT, SG_INFO, "" );
SG_LOG( SG_EVENT, SG_INFO, "Event Stats" );
SG_LOG( SG_EVENT, SG_INFO, "-----------" );
event_container_type::const_iterator first = event_table.begin();
event_container_type::const_iterator last = event_table.end();
for (; first != last; ++first)
{
first->print_stats();
}
SG_LOG( SG_EVENT, SG_INFO, "" );
}

View File

@ -0,0 +1,209 @@
// eventmMgr.hxx -- periodic event scheduler
//
// Written by Curtis Olson, started December 1997.
// Modified by Bernie Bright, April 2002.
//
// Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifndef SG_EVENT_MGR_HXX
#define SG_EVENT_MGR_HXX 1
#include <simgear/compiler.h>
#include <simgear/structure/callback.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/timing/timestamp.hxx>
#include <vector>
#include <string>
SG_USING_STD(vector);
SG_USING_STD(string);
class SGEvent
{
public:
typedef int interval_type;
private:
string _name;
SGCallback* _callback;
SGSubsystem* _subsystem;
interval_type _repeat_value;
interval_type _initial_value;
int _ms_to_go;
unsigned long _cum_time; // cumulative processor time of this event
unsigned long _min_time; // time of quickest execution
unsigned long _max_time; // time of slowest execution
unsigned long _count; // number of times executed
public:
/**
*
*/
SGEvent();
SGEvent( const char* desc,
SGCallback* cb,
interval_type repeat_value,
interval_type initial_value );
SGEvent( const char* desc,
const SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value );
/**
*
*/
~SGEvent();
/**
*
*/
inline void reset()
{
_ms_to_go = _repeat_value;
}
/**
* Execute this event's callback.
*/
void run();
inline string name() const { return _name; }
inline interval_type repeat_value() const { return _repeat_value; }
inline int value() const { return _ms_to_go; }
/**
* Display event statistics.
*/
void print_stats() const;
/**
* Update the elapsed time for this event.
* @param dt_ms elapsed time in milliseconds.
* @return true if elapsed time has expired.
*/
inline bool update( int dt_ms )
{
return (_ms_to_go -= dt_ms) <= 0;
}
};
class SGEventMgr : public SGSubsystem
{
private:
typedef SGEvent::interval_type interval_type;
typedef vector< SGEvent > event_container_type;
void add( const SGEvent& event );
// registered events.
event_container_type event_table;
public:
SGEventMgr();
~SGEventMgr();
/**
* Initialize the scheduling subsystem.
*/
void init();
void reinit();
void bind();
void unbind();
/*
* Update the elapsed time for all events.
* @param dt elapsed time in seconds.
*/
void update( double dt );
/**
* register a free standing function to be executed some time in the future.
* @param desc A brief description of this callback for logging.
* @param cb The callback function to be executed.
* @param repeat_value repetition rate in milliseconds.
* @param initial_value initial delay value in milliseconds. A value of
* -1 means run immediately.
*/
template< typename Fun >
inline void add( const char* name,
const Fun& f,
interval_type repeat_value,
interval_type initial_value = -1 )
{
this->add( SGEvent( name,
make_callback(f),
repeat_value,
initial_value ) );
}
/**
* register a subsystem of which the update function will be executed some
* time in the future.
* @param desc A brief description of this callback for logging.
* @param subsystem The subsystem of which the update function will be
* executed.
* @param repeat_value repetition rate in milliseconds.
* @param initial_value initial delay value in milliseconds. A value of
* -1 means run immediately.
*/
inline void add( const char* name,
const SGSubsystem* subsystem,
interval_type repeat_value,
interval_type initial_value = -1 )
{
this->add( SGEvent( name,
subsystem,
repeat_value,
initial_value ) );
}
template< class ObjPtr, typename MemFn >
inline void add( const char* name,
const ObjPtr& p,
MemFn pmf,
interval_type repeat_value,
interval_type initial_value = -1 )
{
this->add( SGEvent( name,
make_callback(p,pmf),
repeat_value,
initial_value ) );
}
/**
* Display statistics for all registered events.
*/
void print_stats() const;
};
#endif //SG_EVENT_MGR_HXX

View File

@ -0,0 +1,333 @@
#include <simgear/debug/logstream.hxx>
#include "exception.hxx"
#include "subsystem_mgr.hxx"
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystem
////////////////////////////////////////////////////////////////////////
SGSubsystem::SGSubsystem ()
: _suspended(false)
{
}
SGSubsystem::~SGSubsystem ()
{
}
void
SGSubsystem::init ()
{
}
void
SGSubsystem::reinit ()
{
}
void
SGSubsystem::bind ()
{
}
void
SGSubsystem::unbind ()
{
}
void
SGSubsystem::suspend ()
{
_suspended = true;
}
void
SGSubsystem::suspend (bool suspended)
{
_suspended = suspended;
}
void
SGSubsystem::resume ()
{
_suspended = false;
}
bool
SGSubsystem::is_suspended () const
{
return _suspended;
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystemGroup.
////////////////////////////////////////////////////////////////////////
SGSubsystemGroup::SGSubsystemGroup ()
{
}
SGSubsystemGroup::~SGSubsystemGroup ()
{
for (unsigned int i = 0; i < _members.size(); i++)
delete _members[i];
}
void
SGSubsystemGroup::init ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->init();
}
void
SGSubsystemGroup::reinit ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->reinit();
}
void
SGSubsystemGroup::bind ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->bind();
}
void
SGSubsystemGroup::unbind ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->unbind();
}
void
SGSubsystemGroup::update (double delta_time_sec)
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->update(delta_time_sec); // indirect call
}
void
SGSubsystemGroup::suspend ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->suspend();
}
void
SGSubsystemGroup::resume ()
{
for (unsigned int i = 0; i < _members.size(); i++)
_members[i]->subsystem->resume();
}
bool
SGSubsystemGroup::is_suspended () const
{
return false;
}
void
SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
double min_step_sec)
{
Member * member = get_member(name, true);
if (member->subsystem != 0)
delete member->subsystem;
member->name = name;
member->subsystem = subsystem;
member->min_step_sec = min_step_sec;
}
SGSubsystem *
SGSubsystemGroup::get_subsystem (const string &name)
{
Member * member = get_member(name);
if (member != 0)
return member->subsystem;
else
return 0;
}
void
SGSubsystemGroup::remove_subsystem (const string &name)
{
for (unsigned int i = 0; i < _members.size(); i++) {
if (name == _members[i]->name) {
_members.erase(_members.begin() + i);
return;
}
}
}
bool
SGSubsystemGroup::has_subsystem (const string &name) const
{
return (((SGSubsystemGroup *)this)->get_member(name) != 0);
}
SGSubsystemGroup::Member *
SGSubsystemGroup::get_member (const string &name, bool create)
{
for (unsigned int i = 0; i < _members.size(); i++) {
if (_members[i]->name == name)
return _members[i];
}
if (create) {
Member * member = new Member;
_members.push_back(member);
return member;
} else {
return 0;
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystemGroup::Member
////////////////////////////////////////////////////////////////////////
SGSubsystemGroup::Member::Member ()
: name(""),
subsystem(0),
min_step_sec(0),
elapsed_sec(0)
{
}
SGSubsystemGroup::Member::Member (const Member &)
{
Member();
}
SGSubsystemGroup::Member::~Member ()
{
// FIXME: causes a crash
// delete subsystem;
}
void
SGSubsystemGroup::Member::update (double delta_time_sec)
{
elapsed_sec += delta_time_sec;
if (elapsed_sec >= min_step_sec) {
if (!subsystem->is_suspended()) {
subsystem->update(elapsed_sec);
elapsed_sec = 0;
}
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of SGSubsystemMgr.
////////////////////////////////////////////////////////////////////////
SGSubsystemMgr::SGSubsystemMgr ()
{
}
SGSubsystemMgr::~SGSubsystemMgr ()
{
}
void
SGSubsystemMgr::init ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].init();
}
void
SGSubsystemMgr::reinit ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].reinit();
}
void
SGSubsystemMgr::bind ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].bind();
}
void
SGSubsystemMgr::unbind ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].unbind();
}
void
SGSubsystemMgr::update (double delta_time_sec)
{
for (int i = 0; i < MAX_GROUPS; i++) {
_groups[i].update(delta_time_sec);
}
}
void
SGSubsystemMgr::suspend ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].suspend();
}
void
SGSubsystemMgr::resume ()
{
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].resume();
}
bool
SGSubsystemMgr::is_suspended () const
{
return false;
}
void
SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem,
GroupType group, double min_time_sec)
{
SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name);
get_group(group)->set_subsystem(name, subsystem, min_time_sec);
if (_subsystem_map.find(name) != _subsystem_map.end()) {
SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name);
throw sg_exception("duplicate subsystem");
}
_subsystem_map[name] = subsystem;
}
SGSubsystemGroup *
SGSubsystemMgr::get_group (GroupType group)
{
return &(_groups[group]);
}
SGSubsystem *
SGSubsystemMgr::get_subsystem (const string &name)
{
map<string,SGSubsystem *>::iterator s =_subsystem_map.find(name);
if (s == _subsystem_map.end())
return 0;
else
return s->second;
}
// end of fgfs.cxx

View File

@ -0,0 +1,345 @@
// Written by David Megginson, started 2000-12
//
// Copyright (C) 2000 David Megginson, david@megginson.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifndef __SUBSYSTEM_MGR_HXX
#define __SUBSYSTEM_MGR_HXX 1
#include <simgear/compiler.h>
#if 0
#ifdef HAVE_WINDOWS_H
# include <windows.h>
# include <float.h>
#endif
#include STL_STRING
SG_USING_STD(string);
#include <vector>
SG_USING_STD(vector);
#endif
#include <map>
SG_USING_STD(map);
#include <simgear/props/props.hxx>
/**
* Basic interface for all FlightGear subsystems.
*
* <p>This is an abstract interface that all FlightGear subsystems
* will eventually implement. It defines the basic operations for
* each subsystem: initialization, property binding and unbinding, and
* updating. Interfaces may define additional methods, but the
* preferred way of exchanging information with other subsystems is
* through the property tree.</p>
*
* <p>To publish information through a property, a subsystem should
* bind it to a variable or (if necessary) a getter/setter pair in the
* bind() method, and release the property in the unbind() method:</p>
*
* <pre>
* void MySubsystem::bind ()
* {
* fgTie("/controls/flight/elevator", &_elevator);
* fgSetArchivable("/controls/flight/elevator");
* }
*
* void MySubsystem::unbind ()
* {
* fgUntie("/controls/flight/elevator");
* }
* </pre>
*
* <p>To reference a property (possibly) from another subsystem, there
* are two alternatives. If the property will be referenced only
* infrequently (say, in the init() method), then the fgGet* methods
* declared in fg_props.hxx are the simplest:</p>
*
* <pre>
* void MySubsystem::init ()
* {
* _errorMargin = fgGetFloat("/display/error-margin-pct");
* }
* </pre>
*
* <p>On the other hand, if the property will be referenced frequently
* (say, in the update() method), then the hash-table lookup required
* by the fgGet* methods might be too expensive; instead, the
* subsystem should obtain a reference to the actual property node in
* its init() function and use that reference in the main loop:</p>
*
* <pre>
* void MySubsystem::init ()
* {
* _errorNode = fgGetNode("/display/error-margin-pct", true);
* }
*
* void MySubsystem::update (double delta_time_sec)
* {
* do_something(_errorNode.getFloatValue());
* }
* </pre>
*
* <p>The node returned will always be a pointer to SGPropertyNode,
* and the subsystem should <em>not</em> delete it in its destructor
* (the pointer belongs to the property tree, not the subsystem).</p>
*
* <p>The program may ask the subsystem to suspend or resume
* sim-time-dependent operations; by default, the suspend() and
* resume() methods set the protected variable <var>_suspended</var>,
* which the subsystem can reference in its update() method, but
* subsystems may also override the suspend() and resume() methods to
* take different actions.</p>
*/
class SGSubsystem
{
public:
/**
* Default constructor.
*/
SGSubsystem ();
/**
* Virtual destructor to ensure that subclass destructors are called.
*/
virtual ~SGSubsystem ();
/**
* Initialize the subsystem.
*
* <p>This method should set up the state of the subsystem, but
* should not bind any properties. Note that any dependencies on
* the state of other subsystems should be placed here rather than
* in the constructor, so that FlightGear can control the
* initialization order.</p>
*/
virtual void init ();
/**
* Reinitialize the subsystem.
*
* <p>This method should cause the subsystem to reinitialize itself,
* and (normally) to reload any configuration files.</p>
*/
virtual void reinit ();
/**
* Acquire the subsystem's property bindings.
*
* <p>This method should bind all properties that the subsystem
* publishes. It will be invoked after init, but before any
* invocations of update.</p>
*/
virtual void bind ();
/**
* Release the subsystem's property bindings.
*
* <p>This method should release all properties that the subsystem
* publishes. It will be invoked by FlightGear (not the destructor)
* just before the subsystem is removed.</p>
*/
virtual void unbind ();
/**
* Update the subsystem.
*
* <p>FlightGear invokes this method every time the subsystem should
* update its state.</p>
*
* @param delta_time_sec The delta time, in seconds, since the last
* update. On first update, delta time will be 0.
*/
virtual void update (double delta_time_sec) = 0;
/**
* Suspend operation of this subsystem.
*
* <p>This method instructs the subsystem to suspend
* sim-time-dependent operations until asked to resume. The update
* method will still be invoked so that the subsystem can take any
* non-time-dependent actions, such as updating the display.</p>
*
* <p>It is not an error for the suspend method to be invoked when
* the subsystem is already suspended; the invocation should simply
* be ignored.</p>
*/
virtual void suspend ();
/**
* Suspend or resum operation of this subsystem.
*
* @param suspended true if the subsystem should be suspended, false
* otherwise.
*/
virtual void suspend (bool suspended);
/**
* Resume operation of this subsystem.
*
* <p>This method instructs the subsystem to resume
* sim-time-depended operations. It is not an error for the resume
* method to be invoked when the subsystem is not suspended; the
* invocation should simply be ignored.</p>
*/
virtual void resume ();
/**
* Test whether this subsystem is suspended.
*
* @return true if the subsystem is suspended, false if it is not.
*/
virtual bool is_suspended () const;
protected:
bool _suspended;
};
/**
* A group of FlightGear subsystems.
*/
class SGSubsystemGroup : public SGSubsystem
{
public:
SGSubsystemGroup ();
virtual ~SGSubsystemGroup ();
virtual void init ();
virtual void reinit ();
virtual void bind ();
virtual void unbind ();
virtual void update (double delta_time_sec);
virtual void suspend ();
virtual void resume ();
virtual bool is_suspended () const;
virtual void set_subsystem (const string &name,
SGSubsystem * subsystem,
double min_step_sec = 0);
virtual SGSubsystem * get_subsystem (const string &name);
virtual void remove_subsystem (const string &name);
virtual bool has_subsystem (const string &name) const;
private:
struct Member {
Member ();
Member (const Member &member);
virtual ~Member ();
virtual void update (double delta_time_sec);
string name;
SGSubsystem * subsystem;
double min_step_sec;
double elapsed_sec;
};
Member * get_member (const string &name, bool create = false);
vector<Member *> _members;
};
/**
* Manage subsystems for FlightGear.
*
* This top-level subsystem will eventually manage all of the
* subsystems in FlightGear: it broadcasts its life-cycle events
* (init, bind, etc.) to all of the subsystems it manages. Subsystems
* are grouped to guarantee order of initialization and execution --
* currently, the only two groups are INIT and GENERAL, but others
* will appear in the future.
*
* All subsystems are named as well as grouped, and subsystems can be
* looked up by name and cast to the appropriate subtype when another
* subsystem needs to invoke specialized methods.
*
* The subsystem manager owns the pointers to all the subsystems in
* it.
*/
class SGSubsystemMgr : public SGSubsystem
{
public:
/**
* Types of subsystem groups.
*/
enum GroupType {
INIT = 0,
GENERAL,
MAX_GROUPS
};
SGSubsystemMgr ();
virtual ~SGSubsystemMgr ();
virtual void init ();
virtual void reinit ();
virtual void bind ();
virtual void unbind ();
virtual void update (double delta_time_sec);
virtual void suspend ();
virtual void resume ();
virtual bool is_suspended () const;
virtual void add (const char * name,
SGSubsystem * subsystem,
GroupType group = GENERAL,
double min_time_sec = 0);
virtual SGSubsystemGroup * get_group (GroupType group);
virtual SGSubsystem * get_subsystem(const string &name);
private:
SGSubsystemGroup _groups[MAX_GROUPS];
map<string,SGSubsystem *> _subsystem_map;
};
#endif // __SUBSYSTEM_MGR_HXX

View File

@ -9,8 +9,7 @@
#define __EASYXML_HXX
#include <simgear/compiler.h>
#include <simgear/misc/exception.hxx>
#include <simgear/structure/exception.hxx>
#include STL_IOSTREAM
#include STL_STRING