]> git.mxchange.org Git - simgear.git/blob - simgear/structure/event_mgr.cxx
63e4672faaeb0a95212cb39760af5925dc050619
[simgear.git] / simgear / structure / event_mgr.cxx
1 #include "event_mgr.hxx"
2
3 #include <simgear/math/SGMath.hxx>
4 #include <simgear/debug/logstream.hxx>
5
6 void SGEventMgr::add(const std::string& name, SGCallback* cb,
7                      double interval, double delay,
8                      bool repeat, bool simtime)
9 {
10     // Clamp the delay value to 1 usec, so that user code can use
11     // "zero" as a synonym for "next frame".
12     if(delay <= 0) delay = 0.000001;
13
14     SGTimer* t = new SGTimer;
15     t->interval = interval;
16     t->callback = cb;
17     t->repeat = repeat;
18     t->name = name;
19     
20     SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue;
21
22     q->insert(t, delay);
23 }
24
25 SGTimer::~SGTimer()
26 {
27     delete callback;
28     callback = NULL;
29 }
30
31 void SGTimer::run()
32 {
33     (*callback)();
34 }
35
36 void SGEventMgr::update(double delta_time_sec)
37 {
38     _simQueue.update(delta_time_sec);
39     
40     double rt = _rtProp ? _rtProp->getDoubleValue() : 0;
41     _rtQueue.update(rt);
42 }
43
44 void SGEventMgr::removeTask(const std::string& name)
45 {
46   SGTimer* t = _simQueue.findByName(name);
47   if (t) {
48     _simQueue.remove(t);
49   } else if ((t = _rtQueue.findByName(name))) {
50     _rtQueue.remove(t);
51   } else {
52     SG_LOG(SG_GENERAL, SG_WARN, "removeTask: no task found with name:" << name);
53     return;
54   }
55   
56   delete t;
57 }
58
59 ////////////////////////////////////////////////////////////////////////
60 // SGTimerQueue
61 // This is the priority queue implementation:
62 ////////////////////////////////////////////////////////////////////////
63
64 SGTimerQueue::SGTimerQueue(int size)
65 {
66     _now = 0;
67     _numEntries = 0;
68     _tableSize = 1;
69     while(size > _tableSize)
70         _tableSize = ((_tableSize + 1)<<1) - 1;
71
72     _table = new HeapEntry[_tableSize];
73     for(int i=0; i<_tableSize; i++) {
74         _table[i].pri = 0;
75         _table[i].timer = 0;
76     }
77 }
78
79
80 SGTimerQueue::~SGTimerQueue()
81 {
82     for(int i=0; i<_numEntries; i++) {
83         delete _table[i].timer;
84         _table[i].timer = 0;
85     }
86     _numEntries = 0;
87     delete[] _table;
88     _table = 0;
89     _tableSize = 0;
90 }
91
92 void SGTimerQueue::update(double deltaSecs)
93 {
94     _now += deltaSecs;
95     while(_numEntries && nextTime() <= _now) {
96         SGTimer* t = remove();
97         t->run();
98         if(t->repeat) {
99             insert(t, t->interval);
100         } else {
101             delete t;
102         }
103     }
104 }
105
106 void SGTimerQueue::insert(SGTimer* timer, double time)
107 {
108     if(_numEntries >= _tableSize)
109         growArray();
110
111     _numEntries++;
112     _table[_numEntries-1].pri = -(_now + time);
113     _table[_numEntries-1].timer = timer;
114
115     siftUp(_numEntries-1);
116 }
117
118 SGTimer* SGTimerQueue::remove(SGTimer* t)
119 {
120     int entry;
121     for(entry=0; entry<_numEntries; entry++)
122         if(_table[entry].timer == t)
123             break;
124     if(entry == _numEntries)
125         return 0;
126
127     // Swap in the last item in the table, and sift down
128     swap(entry, _numEntries-1);
129     _numEntries--;
130     siftDown(entry);
131
132     return t;
133 }
134
135 SGTimer* SGTimerQueue::remove()
136 {
137     if(_numEntries == 0) {
138         return 0;
139     } else if(_numEntries == 1) {
140         _numEntries = 0;
141         return _table[0].timer;
142     }
143
144     SGTimer *result = _table[0].timer;
145     _table[0] = _table[_numEntries - 1];
146     _numEntries--;
147     siftDown(0);
148     return result;
149 }
150
151 void SGTimerQueue::siftDown(int n)
152 {
153     // While we have children bigger than us, swap us with the biggest
154     // child.
155     while(lchild(n) < _numEntries) {
156         int bigc = lchild(n);
157         if(rchild(n) < _numEntries && pri(rchild(n)) > pri(bigc))
158             bigc = rchild(n);
159         if(pri(bigc) <= pri(n))
160             break;
161         swap(n, bigc);
162         n = bigc;
163     }
164 }
165
166 void SGTimerQueue::siftUp(int n)
167 {
168     while((n != 0) && (_table[n].pri > _table[parent(n)].pri)) {
169         swap(n, parent(n));
170         n = parent(n);
171     }
172     siftDown(n);
173 }
174
175 void SGTimerQueue::growArray()
176 {
177     _tableSize = ((_tableSize+1)<<1) - 1;
178     HeapEntry *newTable = new HeapEntry[_tableSize];
179     for(int i=0; i<_numEntries; i++) {
180         newTable[i].pri  = _table[i].pri;
181         newTable[i].timer = _table[i].timer;
182     }
183     delete[] _table;
184     _table = newTable;
185 }
186
187 SGTimer* SGTimerQueue::findByName(const std::string& name) const
188 {
189   for (int i=0; i < _numEntries; ++i) {
190     if (_table[i].timer->name == name) {
191       return _table[i].timer;
192     }
193   }
194   
195   return NULL;
196 }