]> Dogcows Code - chaz/yoink/blobdiff - src/moof/timer.cc
remove some unused stlplus modules
[chaz/yoink] / src / moof / timer.cc
index 9b105b4c991fcb73582ff0ad86ca73091ef5c85d..82f8cfa3ec4dbf13a5a1962936b35f9d4295c226 100644 (file)
@@ -1,15 +1,15 @@
 
-/*]  Copyright (c) 2009-2010, Charles McGarvey  [**************************
+/*]  Copyright (c) 2009-2011, 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.
 *
-**************************************************************************/
+*****************************************************************************/
 
+#if HAVE_CONFIG_H
 #include "config.h"
+#endif
 
 #include <cerrno>
 #include <ctime>
@@ -18,6 +18,7 @@
 #include <SDL/SDL.h>
 
 #include "debug.hh"
+#include "runloop.hh"
 #include "timer.hh"
 
 
@@ -25,13 +26,11 @@ namespace moof {
 
 
 void timer::init(const function& function,
-                                scalar seconds,
-                                mode mode,
-                                runloop* runloop)
+               scalar seconds, enum mode mode, timer_source& source)
 {
-       invalidate();
-       ASSERT(runloop && "can't schedule timer without a runloop");
+       source_ = &source;
 
+       invalidate();
        if ((mode_ = mode) != invalid)
        {
                function_ = function;
@@ -42,78 +41,105 @@ void timer::init(const function& function,
                }
                else
                {
-                       absolute_ = seconds ticks();
+                       absolute_ = seconds + source_->ticks();
                        interval_ = seconds;
                }
-
-               runloop->add_timer(this);
-               runloop_ = runloop;
        }
 }
 
+timer::~timer()
+{
+       detach_from_runloop();
+}
 
 void timer::invalidate()
 {
-       if (mode_ != invalid)
-       {
-               mode_ = invalid;
-               absolute_ = SCALAR(0.0);
+       mode_ = invalid;
+       absolute_ = SCALAR(0.0);
+}
+
+void timer::added_to_runloop(runloop& runloop)
+{
+       detach_from_runloop();
+       runloop_ = &runloop;
+}
 
-               runloop_->remove_timer(this);
+void timer::detach_from_runloop()
+{
+       if (runloop_)
+       {
+               runloop_->remove_timer(*this);
                runloop_ = 0;
        }
 }
 
-
 void timer::fire(scalar t)
 {
        if (function_) function_(*this, t);
 
-       if (is_repeating())
+       if (mode_ == repeat)
        {
-               if (is_equal(absolute_, t, 1.0)) absolute_ += interval_;
-               else absolute_ = interval_ + t;
+               if (is_equal(absolute_, t, 1.0))
+                       absolute_ += interval_;
+               else
+                       absolute_ = interval_ + t;
+               // TODO error accumulates in absolute var
+       }
+       else
+       {
+               invalidate();
        }
-       else invalidate();
 }
 
+scalar timer::ticks()
+{
+       return default_source().ticks();
+}
 
 #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
-// become so large that it cannot be accurately stored in a float (even
-// with as little two days uptime), therefore we need to start from a more
-// recent reference (when the program starts).  Of course this isn't much
-// of an issue if scalar is a double-precision number.
-
-static time_t set_reference()
+class real_time : public timer_source
 {
-       struct timespec ts;
+public:
 
-       if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+       real_time() :
+               scale_(SCALAR(1.0))
        {
-               return 0;
+               reset();
        }
 
-       return ts.tv_sec;
-}
-
-static const time_t reference_ = set_reference();
+       scalar ticks() const
+       {
+               struct timespec ts;
+               int result = clock_gettime(CLOCK_MONOTONIC, &ts);
+               ASSERT(result == 0 && "monotonic clock not available");
+
+               return reference_ +
+                       (scalar(ts.tv_sec - start_.tv_sec) +
+                        scalar(ts.tv_nsec - start_.tv_nsec) *
+                        SCALAR(0.000000001)) * scale_;
+       }
 
+       void reset()
+       {
+               reference_ = SCALAR(0.0);
+               clock_gettime(CLOCK_MONOTONIC, &start_);
+       }
 
-scalar timer::ticks()
-{
-       struct timespec ts;
+       void scale(scalar factor)
+       {
+               reference_ = ticks();
+               clock_gettime(CLOCK_MONOTONIC, &start_);
+               scale_ = factor;
+       }
 
-       int result = clock_gettime(CLOCK_MONOTONIC, &ts);
-       ASSERT(result == 0 && "cannot access clock");
+private:
 
-       return scalar(ts.tv_sec - reference_) +
-                  scalar(ts.tv_nsec) * SCALAR(0.000000001);
-}
+       scalar          reference_;
+       struct timespec start_;
+       scalar          scale_;
+};
 
-void timer::sleep(scalar seconds, mode mode)
+void timer::sleep(scalar seconds, enum mode mode)
 {
        if (mode == absolute) seconds -= ticks();
        if (seconds < SCALAR(0.0)) return;
@@ -123,31 +149,60 @@ void timer::sleep(scalar seconds, mode mode)
        ts.tv_nsec = (seconds - scalar(ts.tv_sec)) * SCALAR(1000000000.0);
 
        int ret;
-       do ret = nanosleep(&ts, &ts); while (ret == -1 && errno == EINTR);
+       do ret = nanosleep(&ts, &ts);
+       while (ret == -1 && errno == EINTR);
 }
 
-
 #else // ! ENABLE_CLOCK_GETTIME
+class real_time : public timer_source
+{
+public:
 
+       real_time() :
+               scale_(SCALAR(0.001))
+       {
+               reset();
+       }
 
-// If we don't have posix timers, we'll have to use a different timing
-// method.  SDL only promises centisecond accuracy, but that's better than
-// a kick in the pants.  It could end up being just as good anyway.
+       scalar ticks() const
+       {
+               return reference_ + scalar(SDL_GetTicks() - start_) * scale_;
+       }
 
-scalar timer::ticks()
-{
-       return scalar(SDL_GetTicks()) * SCALAR(0.001);
-}
+       void reset()
+       {
+               reference_ = SCALAR(0.0);
+               start_ = SDL_GetTicks();
+       }
+
+       void scale(scalar factor)
+       {
+               reference_ = ticks();
+               start_ = SDL_GetTicks();
+               scale_ = factor * SCALAR(0.001);
+       }
 
-void timer::sleep(scalar seconds, mode mode)
+private:
+
+       scalar  reference_;
+       Uint32  start_;
+       scalar  scale_;
+};
+
+void timer::sleep(scalar seconds, enum mode mode)
 {
        if (mode == absolute) seconds -= ticks();
        if (seconds < SCALAR(0.0)) return;
        SDL_Delay(seconds * SCALAR(1000.0));
 }
-
 #endif // ENABLE_CLOCK_GETTIME
 
+timer_source& timer::default_source()
+{
+       static real_time t;
+       return t;
+}
+
 
 } // namespace moof
 
This page took 0.026199 seconds and 4 git commands to generate.