initial runloop implementation
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Sat, 7 Aug 2010 18:16:39 +0000 (12:16 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Sat, 7 Aug 2010 18:16:39 +0000 (12:16 -0600)
12 files changed:
src/Main.cc
src/Main.hh
src/moof/application.cc [new file with mode: 0644]
src/moof/application.hh [new file with mode: 0644]
src/moof/modal_dialog.hh
src/moof/opengl.hh
src/moof/resource.cc
src/moof/runloop.cc [new file with mode: 0644]
src/moof/runloop.hh [new file with mode: 0644]
src/moof/timer.cc
src/moof/timer.hh
src/moof/view.cc

index c76a6148bf84abb6a8b48c03f92f1e6de4055185..e16803739ae6e809d5bf049040debbb3b75e93fd 100644 (file)
@@ -40,8 +40,8 @@ inline int isatty(int dummy) { return 0; }
 #include "version.h"
 
 
-Main::Main(moof::settings& settings, moof::video& video) :
-       moof::view(settings, video)
+Main::Main(moof::settings& settings) :
+       moof::application(settings)
 {
        moof::dispatcher& dispatcher = moof::dispatcher::global();
        video_reloaded_ = dispatcher.add_target("video.newcontext",
@@ -58,15 +58,6 @@ Main::Main(moof::settings& settings, moof::video& video) :
 
 void Main::update(moof::scalar t, moof::scalar dt)
 {
-       if (children().size() == 0)
-       {
-               //moof::log_warning("main view has no children");
-               //stop();
-               //return;
-               add_child(TitleLayer::alloc());
-       }
-
-       moof::view::update(t, dt);
 }
 
 void Main::draw(moof::scalar alpha) const
@@ -78,38 +69,38 @@ void Main::draw(moof::scalar alpha) const
 
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
-
-       moof::view::draw(alpha);
 }
 
-bool Main::handle_event(const moof::event& event)
+void Main::handle_event(const moof::event& event)
 {
-       if (moof::view::handle_event(event)) return true;
-
        switch (event.type)
        {
                case SDL_KEYUP:
+
                        if (event.key.keysym.sym == SDLK_f)
                        {
-                               video().toggle_fullscreen();
+                               moof::video::current()->toggle_fullscreen();
                        }
                        else if (event.key.keysym.sym == SDLK_l)
                        {
-                               video().toggle_cursor_captured();
-                               video().toggle_cursor_visible();
+                               moof::video::current()->toggle_cursor_captured();
+                               moof::video::current()->toggle_cursor_visible();
+                       }
+                       else if (event.key.keysym.sym == SDLK_ESCAPE)
+                       {
+                               stop();
                        }
                        break;
 
                case SDL_VIDEORESIZE:
+
                        glViewport(0, 0, event.resize.w, event.resize.h);
                        break;
 
                case SDL_QUIT:
+
                        stop();
-                       return true;
        }
-
-       return false;
 }
 
 
@@ -173,7 +164,7 @@ void Main::setup_opengl()
        glEnable(GL_ALPHA_TEST);
        glAlphaFunc(GL_GREATER, 0.0);
 
-       glClearColor(0.0, 0.0, 0.0, 1.0);
+       glClearColor(1.0, 0.0, 0.0, 1.0);
 
        //glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
@@ -279,7 +270,7 @@ void Main::print_info(int argc, char* argv[])
 #else
        print_option("hotload", false);
 #endif
-#if PROFILING_ENABLED
+#if ENABLE_PROFILING
        print_option("profile", true);
 #else
        print_option("profile", false);
@@ -331,7 +322,7 @@ void goodbye()
 
 int main(int argc, char* argv[])
 {
-       //moof::backend backend;
+       moof::backend backend;
 
        if (argc > 1)
        {
@@ -361,10 +352,6 @@ int main(int argc, char* argv[])
 
        try
        {
-               //std::string iconPath(PACKAGE".png");
-               //iconPath = moof::resource::find_file(iconPath);
-               //moof::image icon(iconPath);
-               //icon.set_as_icon();
                moof::image_handle icon(PACKAGE, "png");
                if (icon) icon->set_as_icon();
                else moof::log_error("no icon loaded");
@@ -372,10 +359,9 @@ int main(int argc, char* argv[])
 
                class moof::video::attributes attributes(settings);
                moof::video video(PACKAGE_STRING, attributes);
-               Main            mainView(settings, video);
 
-               mainView.run();
-               return 0;
+               Main app(settings);
+               return app.run();
        }
        catch (const std::exception& e)
        {
index 4532e41ea2e3b4a409513fea1b30df1d9ab76a64..47163d11c5bd14232e2c3340e00a7d7c77bc4118 100644 (file)
 
 #include <boost/shared_ptr.hpp>
 
+#include <moof/application.hh>
 #include <moof/dispatcher.hh>
 #include <moof/math.hh>
 #include <moof/timer.hh>
-#include <moof/view.hh>
 
 
-namespace moof
-{
-       class settings;
-       class view;
-}
-
-
-class Main;
-typedef boost::shared_ptr<Main> MainP;
-
-class Main : public moof::view
+class Main : public moof::application
 {
 public:
 
-       Main(moof::settings& settings, moof::video& video);
+       Main(moof::settings& settings);
 
        void update(moof::scalar t, moof::scalar dt);
        void draw(moof::scalar alpha) const;
-       bool handle_event(const moof::event& event);
+       void handle_event(const moof::event& event);
 
        static std::string search_paths();
        static std::string config_paths();
diff --git a/src/moof/application.cc b/src/moof/application.cc
new file mode 100644 (file)
index 0000000..fd9ea45
--- /dev/null
@@ -0,0 +1,105 @@
+
+/*]  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 <cstdlib>                                     // exit, srand
+#include <boost/noncopyable.hpp>
+
+#include <SDL/SDL.h>
+#include "fastevents.h"
+
+#include "application.hh"
+#include "log.hh"
+#include "settings.hh"
+#include "timer.hh"
+#include "video.hh"
+
+
+namespace moof {
+
+
+application::application(settings& settings) :
+       next_update_(timer::ticks()),
+       total_time_(SCALAR(0.0))
+{
+       unsigned random_seed;
+       if (settings.get("rngseed", random_seed)) srand(random_seed);
+       else srand(time(0));
+
+       scalar timestep = SCALAR(80.0);
+       settings.get("timestep", timestep);
+       timestep_ = SCALAR(1.0) / timestep;
+       inverse_timestep_ = timestep;
+
+       scalar framerate = SCALAR(40.0);
+       settings.get("framerate", framerate);
+       framerate = SCALAR(1.0) / framerate;
+
+       update_timer_.init(boost::bind(&application::dispatch_update, this, _1, _2),
+                                          timestep_, timer::repeat, this);
+       draw_timer_.init(boost::bind(&application::dispatch_draw, this, _1, _2),
+                                        framerate, timer::repeat, this);
+}
+
+
+void application::dispatch_update(timer& timer, scalar t)
+{
+       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::current()->resize(event.resize.w, event.resize.h);
+                               break;
+               }
+
+               handle_event(event);
+       }
+
+
+       const int MAX_FRAMESKIP = 15;
+
+       int i = 0;
+       while (next_update_ < t && ++i < MAX_FRAMESKIP)
+       {
+               total_time_ += timestep_;
+               update(total_time_, timestep_);
+
+               next_update_ += timestep_;
+       }
+}
+
+void application::dispatch_draw(timer& timer, scalar t)
+{
+       scalar alpha = (t + timestep_ - next_update_) * inverse_timestep_;
+       if (alpha < SCALAR(0.0)) log_error("UH OH!!!!!  It's NEGATIVE", alpha);
+       if (alpha > SCALAR(1.0)) log_error("UH OH!!!!!  It's POSITIVE", alpha);
+
+       draw(alpha);
+       video::current()->swap();
+}
+
+
+} // namespace moof
+
diff --git a/src/moof/application.hh b/src/moof/application.hh
new file mode 100644 (file)
index 0000000..671011f
--- /dev/null
@@ -0,0 +1,65 @@
+
+/*]  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.
+*
+**************************************************************************/
+
+#ifndef _MOOF_APPLICATION_HH_
+#define _MOOF_APPLICATION_HH_
+
+/**
+ * \file application.hh
+ * The main loop.
+ */
+
+#include <boost/noncopyable.hpp>
+
+#include <moof/event.hh>
+#include <moof/math.hh>
+#include <moof/runloop.hh>
+#include <moof/timer.hh>
+
+
+namespace moof {
+
+
+class settings;
+
+class application : public runloop
+{
+public:
+
+       application(settings& settings);
+       virtual ~application() {}
+
+       virtual void update(scalar t, scalar dt) = 0;
+       virtual void draw(scalar alpha) const = 0;
+       virtual void handle_event(const event& event) = 0;
+
+
+private:
+
+       void dispatch_update(timer& timer, scalar t);
+       void dispatch_draw(timer& timer, scalar t);
+
+       scalar  next_update_;
+       scalar  total_time_;
+
+       timer   update_timer_;
+       timer   draw_timer_;
+
+
+       scalar  timestep_;
+       scalar  inverse_timestep_;
+};
+
+
+} // namespace moof
+
+#endif // _MOOF_APPLICATION_HH_
+
index e1d773989bebcf41c8912c0004b05221eeb686ac..c53766237df20bd20ae5153c6eea872f1de5825c 100644 (file)
@@ -24,9 +24,9 @@
 
 #if defined(_WIN32)
 #include <windows.h>
-#elif USE_GTK
+#elif WITH_GTK
 #include <gtk/gtk.h>
-#elif USE_QT4
+#elif WITH_QT4
 #include <QApplication>
 #include <QIcon>
 #include <QMessageBox>
@@ -113,7 +113,7 @@ struct modal_dialog
                MessageBox(0, (text1 + "\n" + text2).c_str(), title.c_str(),
                                   MB_OK | icon_type);
 
-#elif USE_GTK
+#elif WITH_GTK
 
                int             argc = 0;
                char**  argv;
@@ -153,7 +153,7 @@ struct modal_dialog
                // FIXME - this doesn't seem to actually remove the window from the
                // screen when it closes
 
-#elif USE_QT4
+#elif WITH_QT4
 
                int             argc = 0;
                char**  argv;
index 06ffbaa9866dec512ce397be6179ed867e0d06f5..3367bc8616ddcf569dfa78261bec5f90b9432462 100644 (file)
@@ -59,7 +59,7 @@
 #define PASS_V4                v[0], v[1], v[2], v[3]
 
 
-#if USE_DOUBLE_PRECISION
+#if ENABLE_DOUBLE_PRECISION
 
 #define OPENGL_GENERIC_FUNC(R, N, L)                                                                   \
        inline R gl##N(ARGS_##L) { gl##N##d(PASS_##L); }//
@@ -114,7 +114,7 @@ inline void glMaterial(GLenum face, GLenum pname, moof::scalar s)
 
 inline void glMaterial(GLenum face, GLenum pname, const moof::vector4& v)
 {
-#if USE_DOUBLE_PRECISION
+#if ENABLE_DOUBLE_PRECISION
        float f[] = {v[0], v[1], v[2], v[3]};
        glMaterialfv(face, pname, f);
 #else
@@ -137,7 +137,7 @@ inline void glDrawElements(GLenum type, const std::vector<GLuint>& v)
 }
 
 
-#if USE_DOUBLE_PRECISION
+#if ENABLE_DOUBLE_PRECISION
 inline void glGetScalar(GLenum a, GLscalar* b) { glGetDoublev(a, b); }
 #else
 inline void glGetScalar(GLenum a, GLscalar* b) { glGetFloatv(a, b); }
index 35cd663ded7decff86f96321916b8ab5cef71f5b..95b4c698501a05686a02d1789a3f428298939cb1 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <queue>
 
-#ifdef USE_HOTLOADING
+#if ENABLE_HOTLOADING
 #include <sys/inotify.h>
 #include <sys/ioctl.h>
 #endif
@@ -112,7 +112,7 @@ static struct rsrc_list
 #endif
 } rsrc_list;
 
-#ifdef USE_HOTLOADING
+#if ENABLE_HOTLOADING
 static struct watch_list
 {
        // this table associates a watch descriptor with a loaded resource
@@ -179,7 +179,7 @@ resource_ptr resource::load_with_path(const std::string& path,
                rsrc_list.table[path] = rsrc;
                rsrc->path_ = path;
                rsrc->type_ = ext;
-#ifdef USE_HOTLOADING
+#if ENABLE_HOTLOADING
                rsrc->wd_ = watch_list.add(rsrc);
 #endif
                return rsrc;
@@ -197,7 +197,7 @@ int resource::reload_as_needed()
 {
        int count = 0;
 
-#ifdef USE_HOTLOADING
+#if ENABLE_HOTLOADING
        char bytes[BUF_SIZE];
        int num_bytes;
        // an inotify file descriptor lets your read inotify_event structures
@@ -255,7 +255,7 @@ void resource::reload()
 resource::~resource()
 {
        rsrc_list.table.erase(path_);
-#ifdef USE_HOTLOADING
+#if ENABLE_HOTLOADING
        watch_list.remove(wd_);
 #endif
 }
diff --git a/src/moof/runloop.cc b/src/moof/runloop.cc
new file mode 100644 (file)
index 0000000..db59814
--- /dev/null
@@ -0,0 +1,148 @@
+
+/*]  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 "hash.hh"
+#include "runloop.hh"
+#include "timer.hh"
+
+
+namespace moof {
+
+
+enum registry_action
+{
+       lookup,
+       set
+};
+
+static uint32_t call_registry(runloop*& runloop, registry_action action)
+{
+       typedef stlplus::hash<uint32_t,moof::runloop*,hash_function> table_t;
+       static table_t table;
+
+       uint32_t thread_id = thread::current_identifier();
+
+       static MOOF_DECLARE_MUTEX(table_mutex);
+       MOOF_MUTEX_LOCK(table_mutex);
+
+       switch (action)
+       {
+               case set:
+               {
+                       if (runloop) table[thread_id] = runloop;
+                       else         table.erase(thread_id);
+                       break;
+               }
+
+               case lookup:
+               {
+                       table_t::iterator it = table.find(thread_id);
+                       if (it != table.end()) runloop = (*it).second;
+                       break;
+               }
+       }
+
+       return thread_id;
+}
+
+
+int runloop::run()
+{
+#if ENABLE_THREADS
+       runloop* runloop = this;
+       thread_id_ = call_registry(runloop, set);
+#endif
+
+       stop_ = false;
+       while (!stop_)
+       {
+               scalar next_event = SCALAR(0.0);
+               {
+                       MOOF_MUTEX_LOCK(timers_mutex_);
+
+                       for (timers_it_ = timers_.begin();
+                                timers_it_ != timers_.end();
+                                ++timers_it_)
+                       {
+                               scalar absolute = (*timers_it_)->fire_if_expired();
+                               if (next_event == SCALAR(0.0) ||
+                                       (absolute != SCALAR(0.0) && absolute < next_event))
+                               {
+                                       next_event = absolute;
+                               }
+                       }
+               }
+               timer::sleep(next_event, timer::absolute);
+       }
+
+       return code_;
+}
+
+
+runloop::~runloop()
+{
+       runloop* runloop = 0;
+       call_registry(runloop, set);
+}
+
+
+void runloop::stop(int code)
+{
+       code_ = code;
+       stop_ = true;
+}
+
+
+runloop* runloop::current()
+{
+       runloop* runloop;
+       call_registry(runloop, lookup);
+       return runloop;
+}
+
+
+void runloop::add_timer(timer* timer)
+{
+#if ENABLE_THREADS
+       if (thread_id_ != thread::current_identifier())
+       {
+               MOOF_MUTEX_LOCK(timers_mutex_);
+               timers_.insert(timer);
+               timers_it_ = timers_.end();
+       }
+       else
+#endif
+       {
+               timers_.insert(timer);
+               timers_it_ = timers_.end();
+       }
+}
+
+void runloop::remove_timer(timer* timer)
+{
+#if ENABLE_THREADS
+       if (thread_id_ != thread::current_identifier())
+       {
+               MOOF_MUTEX_LOCK(timers_mutex_);
+               timers_.erase(timer);
+               timers_it_ = timers_.end();
+       }
+       else
+#endif
+       {
+               timers_.erase(timer);
+               timers_it_ = timers_.end();
+       }
+}
+
+
+} // namespace moof
+
diff --git a/src/moof/runloop.hh b/src/moof/runloop.hh
new file mode 100644 (file)
index 0000000..0aad06d
--- /dev/null
@@ -0,0 +1,103 @@
+
+/*]  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.
+*
+**************************************************************************/
+
+#ifndef _MOOF_RUNLOOP_HH_
+#define _MOOF_RUNLOOP_HH_
+
+/**
+ * \file runloop.hh
+ * Thread timer management class.
+ */
+
+#include <set>
+
+#include <boost/noncopyable.hpp>
+
+#include <moof/backend.hh>
+#include <moof/thread.hh>
+
+
+namespace moof {
+
+
+// forward declarations
+class timer;
+       
+
+/**
+ * A runloop is a loop with scheduled timers.
+ */
+class runloop
+{
+public:
+
+       /**
+        * Construct a runloop.
+        */
+       runloop() :
+               stop_(false),
+               thread_id_(0) {}
+
+       /**
+        * Deconstruct the runloop.
+        */
+       ~runloop();
+
+
+       /**
+        * Start running the runloop.
+        * \return The exit code.
+        */
+       int run();
+
+       /**
+        * Stop the runloop.
+        * \param code The exit code.
+        */
+       void stop(int code = 0);
+
+
+       /** Get the runloop of the current thread.
+        * \return The current runloop or 0 if none is running in the current
+        * thread.
+        */
+       static runloop* current();
+
+
+private:
+
+       friend class timer;
+
+       void add_timer(timer* timer);
+       void remove_timer(timer* timer);
+
+
+       bool            stop_;
+       int                     code_;
+
+       typedef std::set<timer*> timer_table;
+       timer_table     timers_;
+       timer_table::iterator timers_it_;
+
+#if ENABLE_THREADS
+       MOOF_DECLARE_MUTEX(timers_mutex_);
+       uint32_t        thread_id_;
+#endif
+
+
+       backend         backend_;
+};
+
+
+} // namespace moof
+
+#endif // _MOOF_RUNLOOP_HH_
+
index f16a962dfa688b032ad92da9506a92c6b24ab416..9b105b4c991fcb73582ff0ad86ca73091ef5c85d 100644 (file)
 namespace moof {
 
 
-scalar timer::next_event_ = std::numeric_limits<scalar>::max();
-hash<unsigned,timer*,hash_function> timer::timers_;
-
-
-unsigned timer::new_identifier()
-{
-       static unsigned id = 1;
-       return id++;
-}
-
-
-void timer::init(const function& function, scalar seconds, mode mode)
+void timer::init(const function& function,
+                                scalar seconds,
+                                mode mode,
+                                runloop* runloop)
 {
        invalidate();
+       ASSERT(runloop && "can't schedule timer without a runloop");
 
-       mode_ = mode;
-
-       if (mode_ != invalid)
+       if ((mode_ = mode) != invalid)
        {
                function_ = function;
 
@@ -55,111 +46,39 @@ void timer::init(const function& function, scalar seconds, mode mode)
                        interval_ = seconds;
                }
 
-               id_ = new_identifier();
-               timers_.insert(std::pair<unsigned,timer*>(id_, this));
-
-               if (absolute_ < next_event_) next_event_ = absolute_;
+               runloop->add_timer(this);
+               runloop_ = runloop;
        }
 }
 
 
-bool timer::is_valid() const
-{
-       return mode_ != invalid;
-}
-
 void timer::invalidate()
 {
        if (mode_ != invalid)
        {
-               timers_.erase(id_);
                mode_ = invalid;
+               absolute_ = SCALAR(0.0);
 
-               if (is_equal(absolute_, next_event_))
-               {
-                       next_event_ = find_next_event();
-               }
+               runloop_->remove_timer(this);
+               runloop_ = 0;
        }
 }
 
 
-void timer::fire()
+void timer::fire(scalar t)
 {
-       scalar t = ticks();
-
        if (function_) function_(*this, t);
 
        if (is_repeating())
        {
-               scalar absolute = absolute_;
-
                if (is_equal(absolute_, t, 1.0)) absolute_ += interval_;
                else absolute_ = interval_ + t;
-
-               if (is_equal(absolute, next_event_))
-               {
-                       next_event_ = find_next_event();
-               }
-       }
-       else
-       {
-               invalidate();
-       }
-}
-
-
-scalar timer::find_next_event()
-{
-       scalar next_fire = std::numeric_limits<scalar>::max();
-
-       hash<unsigned,timer*,hash_function>::iterator it;
-       for (it = timers_.begin(); it.valid(); ++it)
-       {
-               scalar absolute = (*it).second->absolute_;
-               if (absolute < next_fire) next_fire = absolute;
-       }
-
-       return next_fire;
-}
-
-
-scalar timer::seconds_remaining() const
-{
-       return absolute_ - ticks();
-}
-
-scalar timer::next_expiration() const
-{
-       return absolute_;
-}
-
-bool timer::is_expired() const
-{
-       return seconds_remaining() < 0.0;
-}
-
-bool timer::is_repeating() const
-{
-       return mode_ == repeat;
-}
-
-
-void timer::fire_expired_timers(scalar t)
-{
-       if (t < next_event_) return;
-
-       hash<unsigned,timer*,hash_function>::iterator it;
-       for (it = timers_.begin(); it.valid(); ++it)
-       {
-               timer* timer = (*it).second;
-               if (timer->is_expired()) timer->fire();
-
-               if (it.end()) break;
        }
+       else invalidate();
 }
 
 
-#if USE_CLOCK_GETTIME
+#if ENABLE_CLOCK_GETTIME
 
 // Since the monotonic clock will provide us with the time since the
 // computer started, the number of seconds since that time could easily
@@ -208,7 +127,7 @@ void timer::sleep(scalar seconds, mode mode)
 }
 
 
-#else // ! USE_CLOCK_GETTIME
+#else // ! ENABLE_CLOCK_GETTIME
 
 
 // If we don't have posix timers, we'll have to use a different timing
@@ -227,7 +146,7 @@ void timer::sleep(scalar seconds, mode mode)
        SDL_Delay(seconds * SCALAR(1000.0));
 }
 
-#endif // USE_CLOCK_GETTIME
+#endif // ENABLE_CLOCK_GETTIME
 
 
 } // namespace moof
index 3ec4ef9d8e04bd23a1e6141d4c242e430f6d0d5e..90c53ceb034452208b6262aeb039938ea650369f 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <moof/hash.hh>
 #include <moof/math.hh>
+#include <moof/runloop.hh>
 
 
 namespace moof {
@@ -80,9 +81,12 @@ public:
         * again at that many seconds from the expiration time.  A repeating
         * timer can be invalidated manually using invalidate().
         */
-       timer(const function& function, scalar seconds, mode mode = relative)
+       timer(const function& function,
+                 scalar seconds,
+                 mode mode = relative,
+                 runloop* runloop = runloop::current())
        {
-               init(function, seconds, mode);
+               init(function, seconds, mode, runloop);
        }
 
        /**
@@ -114,7 +118,8 @@ public:
         */
        void init(const function& function,
                          scalar seconds,
-                         mode mode = relative);
+                         mode mode = relative,
+                         runloop* runloop = runloop::current());
 
        
        /**
@@ -122,7 +127,10 @@ public:
         * still scheduled to expired.  You can get the time remaining from
         * seconds_remaining().
         */
-       bool is_valid() const;
+       bool is_valid() const
+       {
+               return mode_ != invalid;
+       }
 
        /**
         * Manually invalidated the timer, removing any schedule such that the
@@ -137,23 +145,46 @@ public:
         * prematurely.  If the timer is scheduled, it will be invalidated.  If
         * the timer is already invalid (but is initialized with an event
         * handler), the event will be fired and the timer will remain invalid.
+        * \param t The absolute time passed to the timer event function.
         */
-       void fire();
+       void fire(scalar t = ticks());
+
+
+       /**
+        * Fire the timer event if it is expired.
+        * \param t The absolute time used as a reference to determine if the
+        * timer is expired; defaults to the current time.
+        * \return The absolute time of the next expiration (if repeating), or
+        * 0.0 otherwise.
+        */
+       scalar fire_if_expired(scalar t = ticks())
+       {
+               if (is_expired()) fire();
+               return absolute_;
+       }
 
 
        /**
         * Get the number of seconds remaining before the timer is scheduled to
         * expired.  If the timer is invalid, the retured value will be
         * negative.
+        * \param t The absolute time used as a reference to determine the
+        * amount of time left; defaults to the current time.
         * \return Seconds.
         */
-       scalar seconds_remaining() const;
+       scalar seconds_remaining(scalar t = ticks()) const
+       {
+               return next_expiration() - t;
+       }
 
        /**
         * Get the absolute time of the next expiration of this timer.
         * \return Seconds.
         */
-       scalar next_expiration() const;
+       scalar next_expiration() const
+       {
+               return absolute_;
+       }
 
 
        /**
@@ -162,15 +193,23 @@ public:
         * expiration time in the future.  If the timer is expired but not
         * invalid, the timer event has not yet fired; the timer will be
         * invalidated when it does fire.
+        * \param t The absolute time used as a reference to determine if the
+        * timer is expired; defaults to the current time.
         * \return True if the timer is expired, false otherwise.
         */
-       bool is_expired() const;
+       bool is_expired(scalar t = ticks()) const
+       {
+               return seconds_remaining(t) < SCALAR(0.0);
+       }
 
        /**
         * Get whether or not the timer is on a repeating schedule.
         * \return True if the timer is repeating, false otherwise.
         */
-       bool is_repeating() const;
+       bool is_repeating() const
+       {
+               return mode_ == repeat;
+       }
 
 
        /**
@@ -195,45 +234,13 @@ public:
        static void sleep(scalar seconds, mode mode = relative);
 
 
-       /**
-        * Get the absolute time when the next timer is scheduled to expire.
-        * \return Absolute time, in seconds.
-        */
-       static scalar next_event()
-       {
-               return next_event_;
-       }
-
-
-       /**
-        * Fire any timers which are not yet invalidated but have an expiration
-        * time in the past.
-        */
-       static void fire_expired_timers()
-       {
-               fire_expired_timers(ticks());
-       }
-
-       /**
-        * Fire any timers which are not yet invalidated but have an expiration
-        * time before a given absolute time.
-        */
-       static void fire_expired_timers(scalar t);
-
-
 private:
 
-       static unsigned new_identifier();
-       static scalar find_next_event();
-
        function        function_;
        mode            mode_;
        scalar          absolute_;
        scalar          interval_;
-       unsigned        id_;
-
-       static scalar                                                           next_event_;
-       static hash<unsigned,timer*,hash_function>      timers_;
+       runloop*        runloop_;
 };
 
 
index ab0058b5b115954262d0c105d3cba85791484a2d..62fcd93ac04155c12accbb949a8a80beede3356d 100644 (file)
@@ -209,26 +209,26 @@ public:
                nextUpdate = timer::ticks();
 
 
-               scalar totalTime = 0.0;
-               scalar ticks = timer::ticks();
+               //scalar totalTime = 0.0;
+               //scalar ticks = timer::ticks();
 
-               scalar nextUpdate = ticks;
-               scalar nextDraw = ticks;
-               scalar nextSecond = ticks + SCALAR(1.0);
+               //scalar nextUpdate = ticks;
+               //scalar nextDraw = ticks;
+               //scalar nextSecond = ticks + SCALAR(1.0);
 
                fps_ = 0;
-               int frameCount = 0;
+               //int frameCount = 0;
 
-               const scalar timestep = SCALAR(0.01);//timestep_;
-               const scalar framerate = framerate_;
+               //const scalar timestep = SCALAR(0.01);//timestep_;
+               //const scalar framerate = framerate_;
 
-               const int MAX_FRAMESKIP = 15;
-               const scalar inverseTimestep = SCALAR(1.0) / timestep;
+               //const int MAX_FRAMESKIP = 15;
+               //const scalar inverseTimestep = SCALAR(1.0) / timestep;
 
                is_running_ = true;
                for (;;)
                {
-                       timer::fire_expired_timers();           // 1. fire timers
+                       //timer::fire_expired_timers();         // 1. fire timers
                        dispatch_events();                                      // 2. dispatch events
 
                        //if (!is_running_) break;
@@ -313,7 +313,7 @@ public:
                        //next = std::min(next, timer::next_event());
                        //if (ticks < next) timer::sleep(next, timer::absolute);
 
-                       timer::sleep(timer::next_event(), timer::absolute);
+                       //timer::sleep(timer::next_event(), timer::absolute);
 
                        // Animation is choppy... the sound timer makes the draw occur
                        // late.  It's not usually enough to make the FPS drop, but it
This page took 0.056006 seconds and 4 git commands to generate.