]> Dogcows Code - chaz/yoink/blob - src/Moof/View.cc
initial network stuff
[chaz/yoink] / src / Moof / View.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #include <algorithm>
13 #include <cstdlib> // exit, srand
14 #include <ctime> // time
15 #include <string>
16
17 #include <SDL/SDL.h>
18 #include "fastevents.h"
19
20 #include "Error.hh"
21 #include "Event.hh"
22 #include "Log.hh"
23 #include "Math.hh"
24 #include "ModalDialog.hh"
25 #include "Settings.hh"
26 #include "Timer.hh"
27 #include "Video.hh"
28 #include "View.hh"
29
30
31 namespace Mf {
32
33
34 class RootView : public View
35 {
36 void update(Scalar t, Scalar dt)
37 {
38 if (children().size() == 0) stop();
39 }
40 };
41
42 static RootView gRootView;
43
44
45 class View::Impl
46 {
47 public:
48
49 Impl(View* view, Settings& settings, Video& video) :
50 mView(*view),
51 mSettings(&settings),
52 mVideo(&video),
53 mParent(&gRootView)
54 {
55 init();
56
57 unsigned randomSeed;
58 if (settings.get("rngseed", randomSeed)) srand(randomSeed);
59 else srand(time(0));
60
61 Scalar timestep = 80.0;
62 settings.get("timestep", timestep);
63 mTimestep = 1.0 / timestep;
64
65 Scalar framerate = 40.0;
66 settings.get("framerate", framerate);
67 mFramerate = 1.0 / framerate;
68
69 mShowFps = false;
70 settings.get("showfps", mShowFps);
71 }
72
73 Impl(View* view) :
74 mView(*view),
75 mSettings(0),
76 mVideo(0),
77 mParent(&gRootView)
78 {
79 init();
80 }
81
82 void init()
83 {
84 mTimestep = SCALAR(0.01);
85 mFramerate = SCALAR(0.02);
86 mShowFps = false;
87 }
88
89
90 /**
91 * The main loop. This just calls dispatchEvents(), update(), and
92 * draw() over and over again. The timing of the update and draw are
93 * decoupled. The actual frame rate is also calculated here. This
94 * function will return the exit code used to stop the loop.
95 */
96
97 void run()
98 {
99 ASSERT(mVideo && "running without video set");
100
101 Scalar totalTime = 0.0;
102 Scalar ticks = Timer::getTicks();
103
104 Scalar nextUpdate = ticks;
105 Scalar nextDraw = ticks;
106 Scalar nextSecond = ticks + SCALAR(1.0);
107
108 mFps = 0;
109 int frameCount = 0;
110
111 const Scalar timestep = mTimestep;
112 const Scalar framerate = mFramerate;
113
114 const int MAX_FRAMESKIP = 15;
115 const Scalar inverseTimestep = SCALAR(1.0) / timestep;
116
117 mIsRunning = true;
118 for (;;)
119 {
120 Timer::fireIfExpired(); // 1. fire timers
121 dispatchEvents(); // 2. dispatch events
122
123 if (!mIsRunning) break;
124
125 int i = 0;
126 while (nextUpdate < Timer::getTicks() && i < MAX_FRAMESKIP)
127 {
128 totalTime += timestep; // 3. update state
129 mView.update(totalTime, timestep);
130
131 nextUpdate += timestep;
132 ++i;
133
134 if (!mIsRunning) break;
135 }
136
137 if (nextDraw < (ticks = Timer::getTicks()))
138 {
139 mView.draw(
140 (ticks + timestep - nextUpdate) * inverseTimestep);
141 mVideo->swap(); // 4. draw state
142
143 nextDraw += framerate;
144 ++frameCount;
145
146 if (nextSecond < Timer::getTicks())
147 {
148 mFps = frameCount;
149 frameCount = 0;
150
151 if (mShowFps) logInfo << mFps << " fps" << std::endl;
152
153 nextSecond += SCALAR(1.0);
154 }
155 }
156
157 if (!mIsRunning) break;
158
159 ticks = Timer::getTicks(); // 5. yield timeslice
160 if (ticks < nextUpdate && ticks < nextDraw) Timer::sleep(0.0);
161 }
162 }
163
164 void stop()
165 {
166 mIsRunning = false;
167 }
168
169
170 void dispatchEvents()
171 {
172 Event event;
173
174 while (FE_PollEvent(&event) == 1)
175 {
176 switch (event.type)
177 {
178 case SDL_KEYDOWN:
179 if (event.key.keysym.sym == SDLK_ESCAPE &&
180 (SDL_GetModState() & KMOD_CTRL) )
181 {
182 // emergency escape
183 logWarning("escape forced");
184 exit(1);
185 }
186 break;
187
188 case SDL_VIDEORESIZE:
189 mVideo->resize(event.resize.w, event.resize.h);
190 break;
191 }
192
193 mView.handleEvent(event);
194 }
195 }
196
197 bool handleEvent(const Event& event)
198 {
199 std::list<ViewP>::iterator it;
200 for (it = mChildren.begin(); it != mChildren.end(); ++it)
201 {
202 if ((*it)->handleEvent(event)) return true;
203 }
204
205 return false;
206 }
207
208 void update(Scalar t, Scalar dt)
209 {
210 std::list<ViewP>::iterator it;
211 for (it = mChildren.begin(); it != mChildren.end(); ++it)
212 {
213 (*it)->update(t, dt);
214 }
215 }
216
217 void draw(Scalar alpha)
218 {
219 std::list<ViewP>::iterator it;
220 for (it = mChildren.begin(); it != mChildren.end(); ++it)
221 {
222 (*it)->draw(alpha);
223 }
224 }
225
226
227 void addChild(ViewP child)
228 {
229 ASSERT(child && "adding null view");
230 ASSERT(child.get() != &mView && "adding view to itself");
231
232 child->mImpl->mParent->removeChild(child);
233 mChildren.push_back(child);
234
235 child->mImpl->mParent = &mView;
236 child->mImpl->percolateObjects();
237
238 child->didAddToView();
239 }
240
241 void percolateObjects()
242 {
243 bool recurseAgain = false;
244
245 if (mParent->mImpl->mVideo && mParent->mImpl->mVideo != mVideo)
246 {
247 mVideo = mParent->mImpl->mVideo;
248 recurseAgain = true;
249 }
250
251 if (mParent->mImpl->mSettings &&
252 mParent->mImpl->mSettings != mSettings)
253 {
254 mSettings = mParent->mImpl->mSettings;
255 recurseAgain = true;
256 }
257
258 if (recurseAgain)
259 {
260 std::list<ViewP>::iterator it;
261 for (it = mChildren.begin(); it != mChildren.end(); ++it)
262 {
263 (*it)->mImpl->percolateObjects();
264 }
265 }
266 }
267
268 ViewP removeChild(View* child)
269 {
270 ASSERT(child && "cannot remove null child");
271
272 std::list<ViewP>::iterator it;
273 for (it = mChildren.begin(); it != mChildren.end(); ++it)
274 {
275 if ((*it).get() == child)
276 {
277 ViewP found = *it;
278 found->willRemoveFromView();
279 mChildren.erase(it);
280
281 found->mImpl->mParent = &gRootView;
282
283 return found;
284 }
285 }
286
287 return ViewP();
288 }
289
290 void clear()
291 {
292 mChildren.clear();
293 }
294
295
296 bool mIsRunning;
297 View& mView;
298
299 Settings* mSettings;
300 Video* mVideo;
301
302 View* mParent;
303 std::list<ViewP> mChildren;
304
305 Scalar mTimestep;
306 Scalar mFramerate;
307
308 int mFps;
309 bool mShowFps;
310 };
311
312
313 View::View(Settings& settings, Video& video) :
314 // pass through
315 mImpl(new View::Impl(this, settings, video)) {}
316
317 View::View() :
318 mImpl(new View::Impl(this)) {}
319
320
321 void View::update(Scalar t, Scalar dt)
322 {
323 // pass through
324 mImpl->update(t, dt);
325 }
326
327 void View::draw(Scalar alpha) const
328 {
329 // pass through
330 mImpl->draw(alpha);
331 }
332
333 bool View::handleEvent(const Event& event)
334 {
335 // pass through
336 return mImpl->handleEvent(event);
337 }
338
339
340 void View::addChild(ViewP view)
341 {
342 // pass through
343 mImpl->addChild(view);
344 }
345
346 ViewP View::removeChild(View* view)
347 {
348 // pass through
349 return mImpl->removeChild(view);
350 }
351
352 ViewP View::removeChild(ViewP view)
353 {
354 // pass through
355 return mImpl->removeChild(view.get());
356 }
357
358 void View::clear()
359 {
360 // pass through
361 mImpl->clear();
362 }
363
364
365 View& View::parent() const
366 {
367 return *(mImpl->mParent);
368 }
369
370 const std::list<ViewP>& View::children() const
371 {
372 return mImpl->mChildren;
373 }
374
375
376 Settings& View::settings() const
377 {
378 ASSERT(mImpl->mSettings && "accessing null reference");
379 // pass through
380 return *(mImpl->mSettings);
381 }
382
383 Video& View::video() const
384 {
385 ASSERT(mImpl->mVideo && "accessing null reference");
386 // pass through
387 return *(mImpl->mVideo);
388 }
389
390
391 void View::run()
392 {
393 // pass through
394 return mImpl->run();
395 }
396
397 void View::stop()
398 {
399 // pass through
400 return mImpl->stop();
401 }
402
403 bool View::isRunning() const
404 {
405 // pass through
406 return mImpl->mIsRunning;
407 }
408
409
410 } // namespace Mf
411
This page took 0.051063 seconds and 4 git commands to generate.