]> Dogcows Code - chaz/yoink/blobdiff - src/moof/view.cc
the massive refactoring effort
[chaz/yoink] / src / moof / view.cc
diff --git a/src/moof/view.cc b/src/moof/view.cc
new file mode 100644 (file)
index 0000000..5c10378
--- /dev/null
@@ -0,0 +1,410 @@
+
+/*]  Copyright (c) 2009-2010, Charles McGarvey  [**************************
+**]  All rights reserved.
+*
+* vi:ts=4 sw=4 tw=75
+*
+* Distributable under the terms and conditions of the 2-clause BSD license;
+* see the file COPYING for a complete text of the license.
+*
+**************************************************************************/
+
+#include <algorithm>
+#include <cstdlib>                     // exit, srand
+#include <ctime>                       // time
+#include <string>
+
+#include <SDL/SDL.h>
+#include "fastevents.h"
+
+#include "event.hh"
+#include "log.hh"
+#include "math.hh"
+#include "modal_dialog.hh"
+#include "settings.hh"
+#include "timer.hh"
+#include "video.hh"
+#include "view.hh"
+
+
+namespace moof {
+
+
+class root_view : public view
+{
+       void update(scalar t, scalar dt)
+       {
+               if (children().size() == 0) stop();
+       }
+};
+
+static root_view gRootView;
+
+
+class view::impl
+{
+public:
+
+       impl(view* view, moof::settings& settings, moof::video& video) :
+               view_(*view),
+               settings_(&settings),
+               video_(&video),
+               parent_(&gRootView)
+       {
+               init();
+
+               unsigned randomSeed;
+               if (settings.get("rngseed", randomSeed)) srand(randomSeed);
+               else srand(time(0));
+
+               scalar timestep = 80.0;
+               settings.get("timestep", timestep);
+               timestep_ = 1.0 / timestep;
+
+               scalar framerate = 40.0;
+               settings.get("framerate", framerate);
+               framerate_ = 1.0 / framerate;
+
+               show_fps_ = false;
+               settings.get("showfps", show_fps_);
+       }
+
+       impl(view* view) :
+               view_(*view),
+               settings_(0),
+               video_(0),
+               parent_(&gRootView)
+       {
+               init();
+       }
+
+       void init()
+       {
+               timestep_ = SCALAR(0.01);
+               framerate_ = SCALAR(0.02);
+               show_fps_ = false;
+       }
+
+
+       /**
+        * The main loop.  This just calls dispatch_events(), update(), and
+        * draw() over and over again.  The timing of the update and draw are
+        * decoupled.  The actual frame rate is also calculated here.  This
+        * function will return the exit code used to stop the loop.
+        */
+
+       void run()
+       {
+               ASSERT(video_ && "running without video set");
+
+               scalar totalTime = 0.0;
+               scalar ticks = timer::ticks();
+
+               scalar nextUpdate = ticks;
+               scalar nextDraw = ticks;
+               scalar nextSecond = ticks + SCALAR(1.0);
+
+               fps_ = 0;
+               int frameCount = 0;
+
+               const scalar timestep = timestep_;
+               const scalar framerate = framerate_;
+
+               const int MAX_FRAMESKIP = 15;
+               const scalar inverseTimestep = SCALAR(1.0) / timestep;
+
+               is_running_ = true;
+               for (;;)
+               {
+                       timer::fire_expired_timers();           // 1. fire timers
+                       dispatch_events();                                      // 2. dispatch events
+
+                       if (!is_running_) break;
+
+                       int i = 0;
+                       while (nextUpdate < timer::ticks() && i < MAX_FRAMESKIP)
+                       {
+                               totalTime += timestep;                  // 3. update state
+                               view_.update(totalTime, timestep);
+
+                               nextUpdate += timestep;
+                               ++i;
+
+                               if (!is_running_) break;
+                       }
+
+                       if (nextDraw < (ticks = timer::ticks()))
+                       {
+                               view_.draw(
+                                        (ticks + timestep - nextUpdate) * inverseTimestep);
+                               video_->swap();                                 // 4. draw state
+
+                               nextDraw += framerate;
+                               ++frameCount;
+
+                               if (nextSecond < timer::ticks())
+                               {
+                                       fps_ = frameCount;
+                                       frameCount = 0;
+
+                                       if (show_fps_) log_info << fps_ << " fps" << std::endl;
+
+                                       nextSecond += SCALAR(1.0);
+                               }
+                       }
+
+                       if (!is_running_) break;
+
+                       ticks = timer::ticks();                         // 5. yield timeslice
+                       if (ticks < nextUpdate && ticks < nextDraw) timer::sleep(0.0);
+               }
+       }
+
+       void stop()
+       {
+               is_running_ = false;
+       }
+
+
+       void dispatch_events()
+       {
+               event event;
+
+               while (FE_PollEvent(&event) == 1)
+               {
+                       switch (event.type)
+                       {
+                               case SDL_KEYDOWN:
+                                       if (event.key.keysym.sym == SDLK_ESCAPE &&
+                                                       (SDL_GetModState() & KMOD_CTRL) )
+                                       {
+                                               // emergency escape
+                                               log_warning("escape forced");
+                                               exit(1);
+                                       }
+                                       break;
+
+                               case SDL_VIDEORESIZE:
+                                       video_->resize(event.resize.w, event.resize.h);
+                                       break;
+                       }
+
+                       view_.handle_event(event);
+               }
+       }
+
+       bool handle_event(const event& event)
+       {
+               std::list<view_ptr>::iterator it;
+               for (it = children_.begin(); it != children_.end(); ++it)
+               {
+                       if ((*it)->handle_event(event)) return true;
+               }
+
+               return false;
+       }
+
+       void update(scalar t, scalar dt)
+       {
+               std::list<view_ptr>::iterator it;
+               for (it = children_.begin(); it != children_.end(); ++it)
+               {
+                       (*it)->update(t, dt);
+               }
+       }
+
+       void draw(scalar alpha)
+       {
+               std::list<view_ptr>::iterator it;
+               for (it = children_.begin(); it != children_.end(); ++it)
+               {
+                       (*it)->draw(alpha);
+               }
+       }
+
+
+       void add_child(view_ptr child)
+       {
+               ASSERT(child && "adding null view");
+               ASSERT(child.get() != &view_ && "adding view to itself");
+
+               child->impl_->parent_->remove_child(child);
+               children_.push_back(child);
+
+               child->impl_->parent_ = &view_;
+               child->impl_->percolate_objects();
+
+               child->did_add_to_view();
+       }
+
+       void percolate_objects()
+       {
+               bool recurseAgain = false;
+
+               if (parent_->impl_->video_ && parent_->impl_->video_ != video_)
+               {
+                       video_ = parent_->impl_->video_;
+                       recurseAgain = true;
+               }
+
+               if (parent_->impl_->settings_ &&
+                       parent_->impl_->settings_ != settings_)
+               {
+                       settings_ = parent_->impl_->settings_;
+                       recurseAgain = true;
+               }
+
+               if (recurseAgain)
+               {
+                       std::list<view_ptr>::iterator it;
+                       for (it = children_.begin(); it != children_.end(); ++it)
+                       {
+                               (*it)->impl_->percolate_objects();
+                       }
+               }
+       }
+
+       view_ptr remove_child(view* child)
+       {
+               ASSERT(child && "cannot remove null child");
+
+               std::list<view_ptr>::iterator it;
+               for (it = children_.begin(); it != children_.end(); ++it)
+               {
+                       if ((*it).get() == child)
+                       {
+                               view_ptr found = *it;
+                               found->will_remove_from_view();
+                               children_.erase(it);
+
+                               found->impl_->parent_ = &gRootView;
+
+                               return found;
+                       }
+               }
+
+               return view_ptr();
+       }
+
+       void clear()
+       {
+               children_.clear();
+       }
+
+
+       bool                                    is_running_;
+       view&                                   view_;
+
+       moof::settings*                 settings_;
+       moof::video*                    video_;
+
+       view*                                   parent_;
+       std::list<view_ptr>             children_;
+
+       scalar                                  timestep_;
+       scalar                                  framerate_;
+
+       int                                             fps_;
+       bool                                    show_fps_;
+};
+
+
+view::view(moof::settings& settings, moof::video& video) :
+       // pass through
+       impl_(new view::impl(this, settings, video)) {}
+
+view::view() :
+       impl_(new view::impl(this)) {}
+
+
+void view::update(scalar t, scalar dt)
+{
+       // pass through
+       impl_->update(t, dt);
+}
+
+void view::draw(scalar alpha) const
+{
+       // pass through
+       impl_->draw(alpha);
+}
+
+bool view::handle_event(const event& event)
+{
+       // pass through
+       return impl_->handle_event(event);
+}
+
+
+void view::add_child(view_ptr view)
+{
+       // pass through
+       impl_->add_child(view);
+}
+
+view_ptr view::remove_child(view* view)
+{
+       // pass through
+       return impl_->remove_child(view);
+}
+
+view_ptr view::remove_child(view_ptr view)
+{
+       // pass through
+       return impl_->remove_child(view.get());
+}
+
+void view::clear()
+{
+       // pass through
+       impl_->clear();
+}
+
+
+view& view::parent() const
+{
+       return *(impl_->parent_);
+}
+
+const std::list<view_ptr>& view::children() const
+{
+       return impl_->children_;
+}
+
+
+moof::settings& view::settings() const
+{
+       ASSERT(impl_->settings_ && "accessing null reference");
+       // pass through
+       return *(impl_->settings_);
+}
+
+video& view::video() const
+{
+       ASSERT(impl_->video_ && "accessing null reference");
+       // pass through
+       return *(impl_->video_);
+}
+
+
+void view::run()
+{
+       // pass through
+       return impl_->run();
+}
+
+void view::stop()
+{
+       // pass through
+       return impl_->stop();
+}
+
+bool view::is_running() const
+{
+       // pass through
+       return impl_->is_running_;
+}
+
+
+} // namespace moof
+
This page took 0.023752 seconds and 4 git commands to generate.