]> git.mxchange.org Git - simgear.git/blob - simgear/structure/event_mgr.cxx
Merge branch 'next' of git://gitorious.org/fg/simgear into fredb/winbuild
[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->mgr = this;
18     t->repeat = repeat;
19     t->simtime = simtime;
20     t->name = name;
21     
22     SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue;
23
24     q->insert(t, delay);
25 }
26
27 void SGTimer::run()
28 {
29     (*callback)();
30
31     if(repeat) {
32         SGTimerQueue* q = simtime ? &mgr->_simQueue : &mgr->_rtQueue;
33         q->insert(this, interval);
34     } else {
35         delete callback;
36         delete this;
37     }
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   
60   delete t;
61 }
62
63 ////////////////////////////////////////////////////////////////////////
64 // SGTimerQueue
65 // This is the priority queue implementation:
66 ////////////////////////////////////////////////////////////////////////
67
68 SGTimerQueue::SGTimerQueue(int size)
69 {
70     _now = 0;
71     _numEntries = 0;
72     _tableSize = 1;
73     while(size > _tableSize)
74         _tableSize = ((_tableSize + 1)<<1) - 1;
75
76     _table = new HeapEntry[_tableSize];
77     for(int i=0; i<_tableSize; i++) {
78         _table[i].pri = 0;
79         _table[i].timer = 0;
80     }
81 }
82
83
84 SGTimerQueue::~SGTimerQueue()
85 {
86     for(int i=0; i<_numEntries; i++) {
87         delete _table[i].timer;
88         _table[i].timer = 0;
89     }
90     _numEntries = 0;
91     delete[] _table;
92     _table = 0;
93     _tableSize = 0;
94 }
95
96 void SGTimerQueue::update(double deltaSecs)
97 {
98     _now += deltaSecs;
99     while(_numEntries && nextTime() <= _now) {
100         SGTimer* t = remove();
101         t->run();
102     }
103 }
104
105 void SGTimerQueue::insert(SGTimer* timer, double time)
106 {
107     if(_numEntries >= _tableSize)
108         growArray();
109
110     _numEntries++;
111     _table[_numEntries-1].pri = -(_now + time);
112     _table[_numEntries-1].timer = timer;
113
114     siftUp(_numEntries-1);
115 }
116
117 SGTimer* SGTimerQueue::remove(SGTimer* t)
118 {
119     int entry;
120     for(entry=0; entry<_numEntries; entry++)
121         if(_table[entry].timer == t)
122             break;
123     if(entry == _numEntries)
124         return 0;
125
126     // Swap in the last item in the table, and sift down
127     swap(entry, _numEntries-1);
128     _numEntries--;
129     siftDown(entry);
130
131     return t;
132 }
133
134 SGTimer* SGTimerQueue::remove()
135 {
136     if(_numEntries == 0) {
137         return 0;
138     } else if(_numEntries == 1) {
139         _numEntries = 0;
140         return _table[0].timer;
141     }
142
143     SGTimer *result = _table[0].timer;
144     _table[0] = _table[_numEntries - 1];
145     _numEntries--;
146     siftDown(0);
147     return result;
148 }
149
150 void SGTimerQueue::siftDown(int n)
151 {
152     // While we have children bigger than us, swap us with the biggest
153     // child.
154     while(lchild(n) < _numEntries) {
155         int bigc = lchild(n);
156         if(rchild(n) < _numEntries && pri(rchild(n)) > pri(bigc))
157             bigc = rchild(n);
158         if(pri(bigc) <= pri(n))
159             break;
160         swap(n, bigc);
161         n = bigc;
162     }
163 }
164
165 void SGTimerQueue::siftUp(int n)
166 {
167     while((n != 0) && (_table[n].pri > _table[parent(n)].pri)) {
168         swap(n, parent(n));
169         n = parent(n);
170     }
171     siftDown(n);
172 }
173
174 void SGTimerQueue::growArray()
175 {
176     _tableSize = ((_tableSize+1)<<1) - 1;
177     HeapEntry *newTable = new HeapEntry[_tableSize];
178     for(int i=0; i<_numEntries; i++) {
179         newTable[i].pri  = _table[i].pri;
180         newTable[i].timer = _table[i].timer;
181     }
182     delete[] _table;
183     _table = newTable;
184 }
185
186 SGTimer* SGTimerQueue::findByName(const std::string& name) const
187 {
188   for (int i=0; i < _numEntries; ++i) {
189     if (_table[i].timer->name == name) {
190       return _table[i].timer;
191     }
192   }
193   
194   return NULL;
195 }
196