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