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