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