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