diff --git a/configure.ac b/configure.ac index d3f68ffd..eac3f371 100644 --- a/configure.ac +++ b/configure.ac @@ -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 \ diff --git a/simgear/Makefile.am b/simgear/Makefile.am index 9422b2eb..24681e0d 100644 --- a/simgear/Makefile.am +++ b/simgear/Makefile.am @@ -30,6 +30,7 @@ SUBDIRS = \ serial \ sound \ $(SGTHREAD_DIR) \ + structure \ timing \ xgl diff --git a/simgear/misc/Makefile.am b/simgear/misc/Makefile.am index 1d0ac77b..d8a4555f 100644 --- a/simgear/misc/Makefile.am +++ b/simgear/misc/Makefile.am @@ -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 \ diff --git a/simgear/props/condition.cxx b/simgear/props/condition.cxx index b1314af4..014aff45 100644 --- a/simgear/props/condition.cxx +++ b/simgear/props/condition.cxx @@ -13,10 +13,9 @@ // #include STL_IOSTREAM -#include +#include #include "props.hxx" - #include "condition.hxx" SG_USING_STD(istream); diff --git a/simgear/scene/material/matlib.cxx b/simgear/scene/material/matlib.cxx index d6ba0382..9d0ee86d 100644 --- a/simgear/scene/material/matlib.cxx +++ b/simgear/scene/material/matlib.cxx @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include STL_STRING diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 311ee707..9d387ae2 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -17,13 +17,12 @@ #include #include -#include +#include #include #include #include #include "animation.hxx" - #include "model.hxx" SG_USING_STD(vector); diff --git a/simgear/structure/.cvsignore b/simgear/structure/.cvsignore new file mode 100644 index 00000000..e9955884 --- /dev/null +++ b/simgear/structure/.cvsignore @@ -0,0 +1,3 @@ +.deps +Makefile +Makefile.in diff --git a/simgear/structure/Makefile.am b/simgear/structure/Makefile.am new file mode 100644 index 00000000..386c9d94 --- /dev/null +++ b/simgear/structure/Makefile.am @@ -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) + diff --git a/simgear/structure/callback.hxx b/simgear/structure/callback.hxx new file mode 100644 index 00000000..a5fab150 --- /dev/null +++ b/simgear/structure/callback.hxx @@ -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); +} + +template< class ObjPtr, typename MemFn > +SGCallback* +make_callback( const ObjPtr& pObj, MemFn pMemFn ) +{ + return new SGMethodCallback(pObj, pMemFn ); +} + +#endif // _SG_CALLBACK_HXX + diff --git a/simgear/misc/commands.cxx b/simgear/structure/commands.cxx similarity index 100% rename from simgear/misc/commands.cxx rename to simgear/structure/commands.cxx diff --git a/simgear/misc/commands.hxx b/simgear/structure/commands.hxx similarity index 100% rename from simgear/misc/commands.hxx rename to simgear/structure/commands.hxx diff --git a/simgear/structure/event_mgr.cxx b/simgear/structure/event_mgr.cxx new file mode 100644 index 00000000..979420d7 --- /dev/null +++ b/simgear/structure/event_mgr.cxx @@ -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 +#endif + +#include + +#include + +#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, "" ); +} diff --git a/simgear/structure/event_mgr.hxx b/simgear/structure/event_mgr.hxx new file mode 100644 index 00000000..bcfd2d25 --- /dev/null +++ b/simgear/structure/event_mgr.hxx @@ -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 + +#include +#include +#include + +#include +#include + +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 diff --git a/simgear/misc/exception.cxx b/simgear/structure/exception.cxx similarity index 100% rename from simgear/misc/exception.cxx rename to simgear/structure/exception.cxx diff --git a/simgear/misc/exception.hxx b/simgear/structure/exception.hxx similarity index 100% rename from simgear/misc/exception.hxx rename to simgear/structure/exception.hxx diff --git a/simgear/structure/subsystem_mgr.cxx b/simgear/structure/subsystem_mgr.cxx new file mode 100644 index 00000000..8b1d5ea4 --- /dev/null +++ b/simgear/structure/subsystem_mgr.cxx @@ -0,0 +1,333 @@ + +#include + +#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::iterator s =_subsystem_map.find(name); + + if (s == _subsystem_map.end()) + return 0; + else + return s->second; +} + +// end of fgfs.cxx diff --git a/simgear/structure/subsystem_mgr.hxx b/simgear/structure/subsystem_mgr.hxx new file mode 100644 index 00000000..cd612335 --- /dev/null +++ b/simgear/structure/subsystem_mgr.hxx @@ -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 + +#if 0 +#ifdef HAVE_WINDOWS_H +# include +# include +#endif + +#include STL_STRING +SG_USING_STD(string); + +#include +SG_USING_STD(vector); +#endif + +#include +SG_USING_STD(map); + +#include + + + +/** + * Basic interface for all FlightGear subsystems. + * + *

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.

+ * + *

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:

+ * + *
+ * void MySubsystem::bind ()
+ * {
+ *   fgTie("/controls/flight/elevator", &_elevator);
+ *   fgSetArchivable("/controls/flight/elevator");
+ * }
+ *
+ * void MySubsystem::unbind ()
+ * {
+ *   fgUntie("/controls/flight/elevator");
+ * }
+ * 
+ * + *

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:

+ * + *
+ * void MySubsystem::init ()
+ * {
+ *   _errorMargin = fgGetFloat("/display/error-margin-pct");
+ * }
+ * 
+ * + *

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:

+ * + *
+ * void MySubsystem::init ()
+ * {
+ *   _errorNode = fgGetNode("/display/error-margin-pct", true);
+ * }
+ *
+ * void MySubsystem::update (double delta_time_sec)
+ * {
+ *   do_something(_errorNode.getFloatValue());
+ * }
+ * 
+ * + *

The node returned will always be a pointer to SGPropertyNode, + * and the subsystem should not delete it in its destructor + * (the pointer belongs to the property tree, not the subsystem).

+ * + *

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 _suspended, + * which the subsystem can reference in its update() method, but + * subsystems may also override the suspend() and resume() methods to + * take different actions.

+ */ +class SGSubsystem +{ +public: + + /** + * Default constructor. + */ + SGSubsystem (); + + /** + * Virtual destructor to ensure that subclass destructors are called. + */ + virtual ~SGSubsystem (); + + + /** + * Initialize the subsystem. + * + *

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.

+ */ + virtual void init (); + + + /** + * Reinitialize the subsystem. + * + *

This method should cause the subsystem to reinitialize itself, + * and (normally) to reload any configuration files.

+ */ + virtual void reinit (); + + + /** + * Acquire the subsystem's property bindings. + * + *

This method should bind all properties that the subsystem + * publishes. It will be invoked after init, but before any + * invocations of update.

+ */ + virtual void bind (); + + + /** + * Release the subsystem's property bindings. + * + *

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.

+ */ + virtual void unbind (); + + + /** + * Update the subsystem. + * + *

FlightGear invokes this method every time the subsystem should + * update its state.

+ * + * @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. + * + *

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.

+ * + *

It is not an error for the suspend method to be invoked when + * the subsystem is already suspended; the invocation should simply + * be ignored.

+ */ + 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. + * + *

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.

+ */ + 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 _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 _subsystem_map; + +}; + + + +#endif // __SUBSYSTEM_MGR_HXX + diff --git a/simgear/xml/easyxml.hxx b/simgear/xml/easyxml.hxx index 348151ef..d3f6a90a 100644 --- a/simgear/xml/easyxml.hxx +++ b/simgear/xml/easyxml.hxx @@ -9,8 +9,7 @@ #define __EASYXML_HXX #include - -#include +#include #include STL_IOSTREAM #include STL_STRING