From: curt Date: Tue, 25 Nov 2003 21:26:01 +0000 (+0000) Subject: Nasal and event manager updates from Andy Ross. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=34e2a9dc374914418d0a414490e10e1264c0a146;p=simgear.git Nasal and event manager updates from Andy Ross. --- diff --git a/configure.ac b/configure.ac index 0f29ff32..dd44d868 100644 --- a/configure.ac +++ b/configure.ac @@ -356,6 +356,7 @@ AC_CONFIG_FILES([ \ simgear/math/Makefile \ simgear/metar/Makefile \ simgear/misc/Makefile \ + simgear/nasal/Makefile \ simgear/props/Makefile \ simgear/route/Makefile \ simgear/scene/Makefile \ diff --git a/simgear/Makefile.am b/simgear/Makefile.am index 3c32c519..26761fe8 100644 --- a/simgear/Makefile.am +++ b/simgear/Makefile.am @@ -24,6 +24,7 @@ SUBDIRS = \ magvar \ math \ $(METAR_DIRS) \ + nasal \ props \ route \ scene \ diff --git a/simgear/debug/debug_types.h b/simgear/debug/debug_types.h index 719c4c56..9ca20c2d 100644 --- a/simgear/debug/debug_types.h +++ b/simgear/debug/debug_types.h @@ -24,7 +24,8 @@ typedef enum { SG_CLIPPER = 0x00002000, SG_NETWORK = 0x00004000, SG_ATC = 0x00008000, - SG_UNDEFD = 0x00010000, // For range checking + SG_NASAL = 0x00010000, + SG_UNDEFD = 0x00020000, // For range checking SG_ALL = 0xFFFFFFFF } sgDebugClass; diff --git a/simgear/structure/event_mgr.cxx b/simgear/structure/event_mgr.cxx index 9ffb184b..32c499f9 100644 --- a/simgear/structure/event_mgr.cxx +++ b/simgear/structure/event_mgr.cxx @@ -1,258 +1,160 @@ -// -// 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) +void SGEventMgr::add(SGCallback* cb, + double interval, double delay, + bool repeat, bool simtime) { -} + SGTimer* t = new SGTimer; + t->interval = interval; + t->callback = cb; + t->mgr = this; + t->repeat = repeat; + t->simtime = simtime; -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; - } + SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue; + + q->insert(t, delay); } -SGEvent::SGEvent( const char* name, - SGSubsystem* subsystem, - interval_type repeat_value, - interval_type initial_value ) - : _name(name), - _callback(NULL), - _subsystem(subsystem), - _repeat_value(repeat_value), - _initial_value(initial_value), - _cum_time(0), - _min_time(100000), - _max_time(0), - _count(0) +void SGTimer::run() { - if (_initial_value < 0) - { - this->run(); - _ms_to_go = _repeat_value; - } - else - { - _ms_to_go = _initial_value; + (*callback)(); + + if(repeat) { + SGTimerQueue* q = simtime ? &mgr->_simQueue : &mgr->_rtQueue; + q->insert(this, interval); + } else { + delete callback; + delete this; } } - -SGEvent::~SGEvent() +void SGEventMgr::update(double delta_time_sec) { - //delete callback_; + _rtQueue.update(delta_time_sec); + if(!_freezeProp || _freezeProp->getBoolValue() == false) + _simQueue.update(delta_time_sec); } -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; - } +//////////////////////////////////////////////////////////////////////// +// SGTimerQueue +// This is the priority queue implementation: +//////////////////////////////////////////////////////////////////////// - if ( duration > _max_time ) { - _max_time = duration; - } -} - -void -SGEvent::print_stats() const +SGTimerQueue::SGTimerQueue(int size) { - 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 ); + _now = 0; + _numEntries = 0; + _tableSize = 1; + while(size > _tableSize) + _tableSize = ((_tableSize + 1)<<1) - 1; + + _table = new HeapEntry[_tableSize]; + for(int i=0; i<_tableSize; i++) { + _table[i].pri = 0; + _table[i].timer = 0; + } } - -SGEventMgr::SGEventMgr() +SGTimerQueue::~SGTimerQueue() { + delete[] _table; } -SGEventMgr::~SGEventMgr() +void SGTimerQueue::update(double deltaSecs) { + _now += deltaSecs; + while(_numEntries && nextTime() <= _now) { + SGTimer* t = remove(); + t->run(); + } } -void -SGEventMgr::init() +void SGTimerQueue::insert(SGTimer* timer, double time) { - SG_LOG( SG_EVENT, SG_INFO, "Initializing event manager" ); + if(time < 0) *(int*)0=0; - event_table.clear(); -} - -void -SGEventMgr::reinit() -{ -} + if(_numEntries >= _tableSize) + growArray(); + _numEntries++; + _table[_numEntries-1].pri = -(_now + time); + _table[_numEntries-1].timer = timer; -void -SGEventMgr::bind() -{ + siftUp(_numEntries-1); } -void -SGEventMgr::unbind() +SGTimer* SGTimerQueue::remove(SGTimer* t) { + int entry; + for(entry=0; entry<_numEntries; entry++) + if(_table[entry].timer == t) + break; + if(entry == _numEntries) + return 0; + + // Swap in the last item in the table, and sift down + swap(entry, _numEntries-1); + _numEntries--; + siftDown(entry); + + return t; } -void -SGEventMgr::update( double dt ) +SGTimer* SGTimerQueue::remove() { - int dt_ms = int(dt * 1000); - - if (dt_ms < 0) - { - SG_LOG( SG_GENERAL, SG_ALERT, - "SGEventMgr::update() called with negative delta T" ); - return; + if(_numEntries == 0) { + return 0; + } else if(_numEntries == 1) { + _numEntries = 0; + return _table[0].timer; } - 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(); + SGTimer *result = _table[0].timer; + _table[0] = _table[_numEntries - 1]; + _numEntries--; + siftDown(0); + return result; +} - // Scan all events. Run one whose interval has expired. - while (first != last) +void SGTimerQueue::siftDown(int n) +{ + // While we have a child bigger than us: + while(((lchild(n) < (_numEntries-1)) + && (_table[n].pri < _table[lchild(n)].pri)) + || + ((rchild(n) < (_numEntries-1)) + && (_table[n].pri < _table[rchild(n)].pri))) { - 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 ); + // Swap us with the biggest child + if(_table[lchild(n)].pri > _table[rchild(n)].pri) { + swap(n, lchild(n)); + n = lchild(n); + } else { + swap(n, rchild(n)); + n = rchild(n); } } } -void -SGEventMgr::add( const SGEvent& event ) +void SGTimerQueue::siftUp(int n) { - event_table.push_back( event ); - - SG_LOG( SG_EVENT, SG_INFO, "registered event " << event.name() - << " to run every " << event.repeat_value() << "ms" ); + while((n != 0) && (_table[n].pri > _table[parent(n)].pri)) { + swap(n, parent(n)); + n = parent(n); + } + siftDown(n); } -void -SGEventMgr::print_stats() const +void SGTimerQueue::growArray() { - 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(); + _tableSize = ((_tableSize+1)<<1) - 1; + HeapEntry *newTable = new HeapEntry[_tableSize]; + for(int i=0; i<_numEntries; i++) { + newTable[i].pri = _table[i].pri; + newTable[i].timer = _table[i].timer; } - - SG_LOG( SG_EVENT, SG_INFO, "" ); + delete[] _table; + _table = newTable; } diff --git a/simgear/structure/event_mgr.hxx b/simgear/structure/event_mgr.hxx index 73cac934..1ae86d13 100644 --- a/simgear/structure/event_mgr.hxx +++ b/simgear/structure/event_mgr.hxx @@ -1,209 +1,121 @@ -// 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 -{ +#ifndef _SG_EVENT_MGR_HXX +#define _SG_EVENT_MGR_HXX -public: - - typedef int interval_type; +#include +#include -private: +#include "callback.hxx" - string _name; - SGCallback* _callback; - SGSubsystem* _subsystem; - interval_type _repeat_value; - interval_type _initial_value; - int _ms_to_go; +class SGEventMgr; - 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 +struct SGTimer { + double interval; + SGCallback* callback; + SGEventMgr* mgr; + bool repeat; + bool simtime; + void run(); +}; +class SGTimerQueue { public: + SGTimerQueue(int preSize=1); + ~SGTimerQueue(); - /** - * - */ - SGEvent(); - - SGEvent( const char* desc, - SGCallback* cb, - interval_type repeat_value, - interval_type initial_value ); - - SGEvent( const char* desc, - SGSubsystem* subsystem, - interval_type repeat_value, - interval_type initial_value ); - - /** - * - */ - ~SGEvent(); - - /** - * - */ - inline void reset() - { - _ms_to_go = _repeat_value; - } + void update(double deltaSecs); - /** - * Execute this event's callback. - */ - void run(); + double now() { return _now; } - inline string name() const { return _name; } - inline interval_type repeat_value() const { return _repeat_value; } - inline int value() const { return _ms_to_go; } + void insert(SGTimer* timer, double time); + SGTimer* remove(SGTimer* timer); + SGTimer* remove(); - /** - * Display event statistics. - */ - void print_stats() const; + SGTimer* nextTimer() { return _numEntries ? _table[0].timer : 0; } + double nextTime() { return -_table[0].pri; } - /** - * 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; +private: + // The "priority" is stored as a negative time. This allows the + // implemenetation to treat the "top" of the heap as the largest + // value and avoids developer mindbugs. ;) + struct HeapEntry { double pri; SGTimer* timer; }; + + int parent(int n) { return ((n+1)/2) - 1; } + int lchild(int n) { return ((n+1)*2) - 1; } + int rchild(int n) { return ((n+1)*2 + 1) - 1; } + void swap(int a, int b) { + HeapEntry tmp = _table[a]; + _table[a] = _table[b]; + _table[b] = tmp; } + void siftDown(int n); + void siftUp(int n); + void growArray(); + void check(); + + double _now; + HeapEntry *_table; + int _numEntries; + int _tableSize; }; - 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() { _freezeProp = 0; } + virtual void init() {} + virtual void update(double delta_time_sec); -public: - SGEventMgr(); - ~SGEventMgr(); + void setFreezeProperty(SGPropertyNode* node) { _freezeProp = node; } /** - * 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. + * Add a single function callback event as a repeating task. + * ex: addTask("foo", &Function ... ) */ - void update( double dt ); + template + inline void addTask(const char* name, const FUNC& f, + double interval, double delay=0, bool sim=false) + { add(make_callback(f), interval, delay, true, sim); } /** - * 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. + * Add a single function callback event as a one-shot event. + * ex: addEvent("foo", &Function ... ) */ - 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 ) ); - } + template + inline void addEvent(const char* name, const FUNC& f, + double delay, bool sim=false) + { add(make_callback(f), 0, delay, false, sim); } /** - * 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. + * Add a object/method pair as a repeating task. + * ex: addTask("foo", &object, &ClassName::Method, ...) */ - inline void add( const char* name, - 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 ) ); - } + template + inline void addTask(const char* name, + const OBJ& o, METHOD m, + double interval, double delay=0, bool sim=false) + { add(make_callback(o,m), interval, delay, true, sim); } /** - * Display statistics for all registered events. + * Add a object/method pair as a repeating task. + * ex: addEvent("foo", &object, &ClassName::Method, ...) */ - void print_stats() const; -}; + template + inline void addEvent(const char* name, + const OBJ& o, METHOD m, + double delay, bool sim=false) + { add(make_callback(o,m), 0, delay, false, sim); } + +private: + friend class SGTimer; + + void add(SGCallback* cb, + double interval, double delay, + bool repeat, bool simtime); + SGPropertyNode* _freezeProp; + SGTimerQueue _rtQueue; + SGTimerQueue _simQueue; +}; -#endif //SG_EVENT_MGR_HXX +#endif // _SG_EVENT_MGR_HXX