]> git.mxchange.org Git - simgear.git/commitdiff
Nasal and event manager updates from Andy Ross.
authorcurt <curt>
Tue, 25 Nov 2003 21:26:01 +0000 (21:26 +0000)
committercurt <curt>
Tue, 25 Nov 2003 21:26:01 +0000 (21:26 +0000)
configure.ac
simgear/Makefile.am
simgear/debug/debug_types.h
simgear/structure/event_mgr.cxx
simgear/structure/event_mgr.hxx

index 0f29ff32807b8f4c03a97f7cf11cf867c9c0ca65..dd44d8688ec5cad465bcbdde1d9731fde31a8135 100644 (file)
@@ -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 \
index 3c32c5191a938ee4f04ee34c96099a8c770d2272..26761fe836a723c16a5d5e2b368349dbc99f1634 100644 (file)
@@ -24,6 +24,7 @@ SUBDIRS = \
        magvar \
        math \
        $(METAR_DIRS) \
+       nasal \
        props \
        route \
        scene \
index 719c4c566c135b887d9118997296df65bcb3707e..9ca20c2d4679da95fb2d6bd14e3219e2b5c024b1 100644 (file)
@@ -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;
index 9ffb184be4d1576bac9b690e9a60ba1c6b3e10ec..32c499f9988961dabc906ee5900cb507a371ad22 100644 (file)
-//
-// 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)
+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;
 }
index 73cac934ddd7e96f6534f2e59b13424363185d37..1ae86d135ffbe57463b0cf0aef9f19fc2161fd73 100644 (file)
-// 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
-{
+#ifndef _SG_EVENT_MGR_HXX
+#define _SG_EVENT_MGR_HXX
 
-public:
-
-    typedef int interval_type;
+#include <simgear/props/props.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
 
-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<typename FUNC>
+    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<typename FUNC>
+    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<class OBJ, typename METHOD>
+    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<class OBJ, typename METHOD>
+    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