]> Dogcows Code - chaz/yoink/blob - src/moof/view.cc
ab0058b5b115954262d0c105d3cba85791484a2d
[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 // Timestep Example Source Code
34 // Copyright (c) Glenn Fiedler 2004
35 // http://www.gaffer.org/articles
36
37 struct State
38 {
39 float x;
40 float v;
41 };
42
43 struct Derivative
44 {
45 float dx;
46 float dv;
47 };
48
49 State interpolate(const State &previous, const State &current, float alpha)
50 {
51 State state;
52 state.x = current.x*alpha + previous.x*(1-alpha);
53 state.v = current.v*alpha + previous.v*(1-alpha);
54 return state;
55 }
56
57 float acceleration(const State &state, float t)
58 {
59 const float k = 10;
60 const float b = 1;
61 return - k*state.x - b*state.v;
62 }
63
64 Derivative evaluate(const State &initial, float t)
65 {
66 Derivative output;
67 output.dx = initial.v;
68 output.dv = acceleration(initial, t);
69 return output;
70 }
71
72 Derivative evaluate(const State &initial, float t, float dt, const Derivative &d)
73 {
74 State state;
75 state.x = initial.x + d.dx*dt;
76 state.v = initial.v + d.dv*dt;
77 Derivative output;
78 output.dx = state.v;
79 output.dv = acceleration(state, t+dt);
80 return output;
81 }
82
83 void integrate(State &state, float t, float dt)
84 {
85 Derivative a = evaluate(state, t);
86 Derivative b = evaluate(state, t, dt*0.5f, a);
87 Derivative c = evaluate(state, t, dt*0.5f, b);
88 Derivative d = evaluate(state, t, dt, c);
89
90 const float dxdt = 1.0f/6.0f * (a.dx + 2.0f*(b.dx + c.dx) + d.dx);
91 const float dvdt = 1.0f/6.0f * (a.dv + 2.0f*(b.dv + c.dv) + d.dv);
92
93 state.x = state.x + dxdt*dt;
94 state.v = state.v + dvdt*dt;
95 }
96
97
98 class root_view : public view
99 {
100 void update(scalar t, scalar dt)
101 {
102 if (children().size() == 0) stop();
103 }
104 };
105
106 static root_view gRootView;
107
108
109 class view::impl
110 {
111 public:
112
113 impl(view* view, moof::settings& settings, moof::video& video) :
114 view_(*view),
115 settings_(&settings),
116 video_(&video),
117 parent_(&gRootView)
118 {
119 init();
120
121 unsigned randomSeed;
122 if (settings.get("rngseed", randomSeed)) srand(randomSeed);
123 else srand(time(0));
124
125 scalar timestep = 80.0;
126 settings.get("timestep", timestep);
127 timestep_ = 1.0 / timestep;
128
129 scalar framerate = 40.0;
130 settings.get("framerate", framerate);
131 framerate_ = 1.0 / framerate;
132
133 show_fps_ = false;
134 settings.get("showfps", show_fps_);
135 }
136
137 impl(view* view) :
138 view_(*view),
139 settings_(0),
140 video_(0),
141 parent_(&gRootView)
142 {
143 init();
144 }
145
146 void init()
147 {
148 timestep_ = SCALAR(0.01);
149 framerate_ = SCALAR(0.02);
150 show_fps_ = false;
151 }
152
153
154 /**
155 * The main loop. This just calls dispatch_events(), update(), and
156 * draw() over and over again. The timing of the update and draw are
157 * decoupled. The actual frame rate is also calculated here. This
158 * function will return the exit code used to stop the loop.
159 */
160
161 scalar nextUpdate;
162 scalar totalTime;
163
164 void U(timer& T, scalar t)
165 {
166 const int MAX_FRAMESKIP = 15;
167
168 log_info("update");
169
170 int i = 0;
171 while (nextUpdate < t && ++i < MAX_FRAMESKIP)
172 {
173 totalTime += timestep_; // 3. update state
174 view_.update(totalTime, timestep_);
175
176 //previous = current;
177 //integrate(current, totalTime, timestep);
178
179 nextUpdate += timestep_;
180 }
181 }
182
183 void D(timer& T, scalar t)
184 {
185 const scalar inverseTimestep = SCALAR(1.0) / timestep_;
186
187 log_info("draw");
188
189 scalar alpha = (t + timestep_ - nextUpdate) * inverseTimestep;
190 //scalar alpha = (nextUpdate - t) * inverseTimestep;
191 if (alpha < SCALAR(0.0)) log_error("UH OH!!!!! It's NEGATIVE", alpha);
192 if (alpha > SCALAR(1.0)) log_error("UH OH!!!!! It's POSITIVE", alpha);
193 log_info("alpha:", alpha);
194
195 view_.draw(alpha);
196 video_->swap(); // 4. draw state
197 }
198
199 timer utimer, dtimer;
200
201 void run()
202 {
203 ASSERT(video_ && "running without video set");
204
205 utimer.init(boost::bind(&impl::U, this, _1, _2), timestep_, timer::repeat);
206 dtimer.init(boost::bind(&impl::D, this, _1, _2), framerate_, timer::repeat);
207
208 totalTime = 0.0f;
209 nextUpdate = timer::ticks();
210
211
212 scalar totalTime = 0.0;
213 scalar ticks = timer::ticks();
214
215 scalar nextUpdate = ticks;
216 scalar nextDraw = ticks;
217 scalar nextSecond = ticks + SCALAR(1.0);
218
219 fps_ = 0;
220 int frameCount = 0;
221
222 const scalar timestep = SCALAR(0.01);//timestep_;
223 const scalar framerate = framerate_;
224
225 const int MAX_FRAMESKIP = 15;
226 const scalar inverseTimestep = SCALAR(1.0) / timestep;
227
228 is_running_ = true;
229 for (;;)
230 {
231 timer::fire_expired_timers(); // 1. fire timers
232 dispatch_events(); // 2. dispatch events
233
234 //if (!is_running_) break;
235
236 //int i = 0;
237 //while (nextUpdate < timer::ticks() && i < MAX_FRAMESKIP)
238 //{
239 //totalTime += timestep; // 3. update state
240 //view_.update(totalTime, timestep);
241
242 ////previous = current;
243 ////integrate(current, totalTime, timestep);
244
245 //nextUpdate += timestep;
246 //++i;
247
248 //if (!is_running_) break;
249 //}
250
251 ////const float newTime = timer::ticks();
252 ////float deltaTime = newTime - currentTime;
253 ////currentTime = newTime;
254
255 ////if (deltaTime>0.25f)
256 ////deltaTime = 0.25f;
257
258 ////accumulator += deltaTime;
259
260 ////while (accumulator>=dt)
261 ////{
262 ////accumulator -= dt;
263 ////previous = current;
264 ////integrate(current, t, dt);
265 ////t += dt;
266 ////}
267
268 ////if (nextDraw < (ticks = timer::ticks()))
269 ////{
270 //ticks = timer::ticks();
271 //scalar diff = ticks - nextDraw;
272 ////log_info("difference:", diff);
273 //scalar alpha = (ticks + timestep - nextUpdate) * inverseTimestep;
274 ////scalar alpha = (nextUpdate - ticks) * inverseTimestep;
275 ////float alpha = accumulator/dt;
276 //if (alpha < SCALAR(0.0)) log_error("UH OH!!!!! It's NEGATIVE", alpha);
277 //if (alpha > SCALAR(1.0)) log_error("UH OH!!!!! It's POSITIVE", alpha);
278 //log_info("alpha:", alpha);
279
280 //view_.draw(alpha);
281
282 //// TEMP
283 ////State state = interpolate(previous, current, alpha);
284 ////glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
285
286 ////glBegin(GL_POINTS);
287 ////glColor3f(1,1,1);
288 ////glVertex3f(state.x, 0, 0);
289 ////glEnd();
290
291
292
293 //video_->swap(); // 4. draw state
294
295 //nextDraw += framerate;
296 //++frameCount;
297
298 //if (nextSecond < ticks)//timer::ticks())
299 //{
300 //fps_ = frameCount;
301 //frameCount = 0;
302
303 //if (show_fps_) log_info << fps_ << " fps" << std::endl;
304
305 //nextSecond += SCALAR(1.0);
306 //}
307 ////}
308
309 if (!is_running_) break;
310
311 //ticks = timer::ticks(); // 5. yield timeslice
312 //scalar next = std::min(nextUpdate, nextDraw);
313 //next = std::min(next, timer::next_event());
314 //if (ticks < next) timer::sleep(next, timer::absolute);
315
316 timer::sleep(timer::next_event(), timer::absolute);
317
318 // Animation is choppy... the sound timer makes the draw occur
319 // late. It's not usually enough to make the FPS drop, but it
320 // certainly is noticeably choppy. Maybe update and draw
321 // should both be scheduled like timers. That should reduce
322 // the number of times either update or draw occur late. It
323 // doesn't really matter if update is late, but it's ugly if
324 // draw is late.
325 }
326 }
327
328 void stop()
329 {
330 is_running_ = false;
331 }
332
333
334 void dispatch_events()
335 {
336 event event;
337
338 while (FE_PollEvent(&event) == 1)
339 {
340 switch (event.type)
341 {
342 case SDL_KEYDOWN:
343 if (event.key.keysym.sym == SDLK_ESCAPE &&
344 (SDL_GetModState() & KMOD_CTRL) )
345 {
346 // emergency escape
347 log_warning("escape forced");
348 exit(1);
349 }
350 break;
351
352 case SDL_VIDEORESIZE:
353 video_->resize(event.resize.w, event.resize.h);
354 break;
355 }
356
357 view_.handle_event(event);
358 }
359 }
360
361 bool handle_event(const event& event)
362 {
363 std::list<view_ptr>::iterator it;
364 for (it = children_.begin(); it != children_.end(); ++it)
365 {
366 if ((*it)->handle_event(event)) return true;
367 }
368
369 return false;
370 }
371
372 void update(scalar t, scalar dt)
373 {
374 std::list<view_ptr>::iterator it;
375 for (it = children_.begin(); it != children_.end(); ++it)
376 {
377 (*it)->update(t, dt);
378 }
379 }
380
381 void draw(scalar alpha)
382 {
383 std::list<view_ptr>::iterator it;
384 for (it = children_.begin(); it != children_.end(); ++it)
385 {
386 (*it)->draw(alpha);
387 }
388 }
389
390
391 void add_child(view_ptr child)
392 {
393 ASSERT(child && "adding null view");
394 ASSERT(child.get() != &view_ && "adding view to itself");
395
396 child->impl_->parent_->remove_child(child);
397 children_.push_back(child);
398
399 child->impl_->parent_ = &view_;
400 child->impl_->percolate_objects();
401
402 child->did_add_to_view();
403 }
404
405 void percolate_objects()
406 {
407 bool recurseAgain = false;
408
409 if (parent_->impl_->video_ && parent_->impl_->video_ != video_)
410 {
411 video_ = parent_->impl_->video_;
412 recurseAgain = true;
413 }
414
415 if (parent_->impl_->settings_ &&
416 parent_->impl_->settings_ != settings_)
417 {
418 settings_ = parent_->impl_->settings_;
419 recurseAgain = true;
420 }
421
422 if (recurseAgain)
423 {
424 std::list<view_ptr>::iterator it;
425 for (it = children_.begin(); it != children_.end(); ++it)
426 {
427 (*it)->impl_->percolate_objects();
428 }
429 }
430 }
431
432 view_ptr remove_child(view* child)
433 {
434 ASSERT(child && "cannot remove null child");
435
436 std::list<view_ptr>::iterator it;
437 for (it = children_.begin(); it != children_.end(); ++it)
438 {
439 if ((*it).get() == child)
440 {
441 view_ptr found = *it;
442 found->will_remove_from_view();
443 children_.erase(it);
444
445 found->impl_->parent_ = &gRootView;
446
447 return found;
448 }
449 }
450
451 return view_ptr();
452 }
453
454 void clear()
455 {
456 children_.clear();
457 }
458
459
460 bool is_running_;
461 view& view_;
462
463 moof::settings* settings_;
464 moof::video* video_;
465
466 view* parent_;
467 std::list<view_ptr> children_;
468
469 scalar timestep_;
470 scalar framerate_;
471
472 int fps_;
473 bool show_fps_;
474 };
475
476
477 view::view(moof::settings& settings, moof::video& video) :
478 // pass through
479 impl_(new view::impl(this, settings, video)) {}
480
481 view::view() :
482 impl_(new view::impl(this)) {}
483
484
485 void view::update(scalar t, scalar dt)
486 {
487 // pass through
488 impl_->update(t, dt);
489 }
490
491 void view::draw(scalar alpha) const
492 {
493 // pass through
494 impl_->draw(alpha);
495 }
496
497 bool view::handle_event(const event& event)
498 {
499 // pass through
500 return impl_->handle_event(event);
501 }
502
503
504 void view::add_child(view_ptr view)
505 {
506 // pass through
507 impl_->add_child(view);
508 }
509
510 view_ptr view::remove_child(view* view)
511 {
512 // pass through
513 return impl_->remove_child(view);
514 }
515
516 view_ptr view::remove_child(view_ptr view)
517 {
518 // pass through
519 return impl_->remove_child(view.get());
520 }
521
522 void view::clear()
523 {
524 // pass through
525 impl_->clear();
526 }
527
528
529 view& view::parent() const
530 {
531 return *(impl_->parent_);
532 }
533
534 const std::list<view_ptr>& view::children() const
535 {
536 return impl_->children_;
537 }
538
539
540 moof::settings& view::settings() const
541 {
542 ASSERT(impl_->settings_ && "accessing null reference");
543 // pass through
544 return *(impl_->settings_);
545 }
546
547 video& view::video() const
548 {
549 ASSERT(impl_->video_ && "accessing null reference");
550 // pass through
551 return *(impl_->video_);
552 }
553
554
555 void view::run()
556 {
557 // pass through
558 return impl_->run();
559 }
560
561 void view::stop()
562 {
563 // pass through
564 return impl_->stop();
565 }
566
567 bool view::is_running() const
568 {
569 // pass through
570 return impl_->is_running_;
571 }
572
573
574 } // namespace moof
575
This page took 0.058548 seconds and 3 git commands to generate.