]> Dogcows Code - chaz/yoink/blobdiff - src/moof/timer.hh
further implementing runloop support
[chaz/yoink] / src / moof / timer.hh
index 90c53ceb034452208b6262aeb039938ea650369f..9f3e9846096d7e09600a053ea929c66e7af91d19 100644 (file)
 
 #include <moof/hash.hh>
 #include <moof/math.hh>
-#include <moof/runloop.hh>
 
 
 namespace moof {
 
 
+/**
+ * A timer source is an object that keeps track of increasing time in units
+ * of seconds.  A timer source does not necessarily have to increment at
+ * the same rate or in the same way as the real time.  The time source must
+ * begin at zero and always remain the same or increase each time the time
+ * is queried.
+ */
+class timer_source
+{
+public:
+
+       /**
+        * Deconstruct a timer source.
+        */
+       virtual ~timer_source() {}
+
+       /**
+        * Get the number seconds since the timer source was created or reset.
+        */
+       virtual scalar ticks() const = 0;
+
+       /**
+        * Reset the timer such that the current time will become zero.
+        */
+       virtual void reset() = 0;
+
+       /**
+        * Scale the time.  After calling this, the timer source should either
+        * increment faster or slower, depending on the scale factor.
+        */
+       virtual void scale(scalar factor) = 0;
+};
+
+
+class runloop;
+
+
 /**
  * A class to represent a timer for scheduled events.  The timer events
  * will be executed on or sometime after their schedculed time.  The
@@ -44,10 +80,10 @@ public:
         */
        enum mode
        {
-               invalid         = -1,   /// Timer is not scheduled.
-               relative        =  0,   /// Timer is scheduled by a relative time.
-               absolute        =  1,   /// Timer is scheduled by an absolute time.
-               repeat          =  2    /// Timer is scheduled by a periodic time.
+               invalid         = 0,    /// Timer is not scheduled.
+               relative        = 1,    /// Timer is scheduled by a relative time.
+               absolute        = 2,    /// Timer is scheduled by an absolute time.
+               repeat          = 3             /// Timer is scheduled by a periodic time.
        };
 
        /**
@@ -64,7 +100,8 @@ public:
         */
        timer() :
                mode_(invalid),
-               absolute_(SCALAR(0.0)) {}
+               absolute_(SCALAR(0.0)),
+               runloop_(0) {}
 
        /**
         * Construct a scheduled timer.
@@ -84,19 +121,18 @@ public:
        timer(const function& function,
                  scalar seconds,
                  mode mode = relative,
-                 runloop* runloop = runloop::current())
+                 timer_source& source = default_source()) :
+               runloop_(0)
        {
-               init(function, seconds, mode, runloop);
+               init(function, seconds, mode, source);
        }
 
+
        /**
         * Deconstruct a timer.  This will automagically invalidate the timer,
         * so it will not expire or fire an event.
         */
-       ~timer()
-       {
-               invalidate();
-       }
+       ~timer();
 
 
        /**
@@ -118,20 +154,10 @@ public:
         */
        void init(const function& function,
                          scalar seconds,
-                         mode mode = relative,
-                         runloop* runloop = runloop::current());
+                         enum mode mode = relative,
+                         timer_source& source = default_source());
 
        
-       /**
-        * Get whether or not the timer is valid.  If a timer is valid, it is
-        * still scheduled to expired.  You can get the time remaining from
-        * seconds_remaining().
-        */
-       bool is_valid() const
-       {
-               return mode_ != invalid;
-       }
-
        /**
         * Manually invalidated the timer, removing any schedule such that the
         * timer will not expired and no event will be fired.
@@ -139,6 +165,12 @@ public:
        void invalidate();
 
 
+       enum mode mode() const
+       {
+               return mode_;
+       }
+
+
        /**
         * Manually fire the timer event.  Usually, the timer event will be
         * fired when the timer expires, but this can be used to fire it
@@ -147,7 +179,11 @@ public:
         * 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(scalar t = ticks());
+       void fire(scalar t);
+       void fire()
+       {
+               fire(source_->ticks());
+       }
 
 
        /**
@@ -157,13 +193,26 @@ public:
         * \return The absolute time of the next expiration (if repeating), or
         * 0.0 otherwise.
         */
-       scalar fire_if_expired(scalar t = ticks())
+       scalar fire_if_expired(scalar t)
        {
-               if (is_expired()) fire();
+               if (is_expired(t)) fire(t);
                return absolute_;
        }
+       scalar fire_if_expired()
+       {
+               return fire_if_expired(source_->ticks());
+       }
 
 
+       /**
+        * Get the absolute time of the next expiration of this timer.
+        * \return Seconds.
+        */
+       scalar expiration() const
+       {
+               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
@@ -172,18 +221,13 @@ public:
         * amount of time left; defaults to the current time.
         * \return Seconds.
         */
-       scalar seconds_remaining(scalar t = ticks()) const
+       scalar remaining(scalar t) const
        {
-               return next_expiration() - t;
+               return expiration() - t;
        }
-
-       /**
-        * Get the absolute time of the next expiration of this timer.
-        * \return Seconds.
-        */
-       scalar next_expiration() const
+       scalar remaining() const
        {
-               return absolute_;
+               return remaining(source_->ticks());
        }
 
 
@@ -197,24 +241,21 @@ public:
         * timer is expired; defaults to the current time.
         * \return True if the timer is expired, false otherwise.
         */
-       bool is_expired(scalar t = ticks()) const
+       bool is_expired(scalar t) const
        {
-               return seconds_remaining(t) < SCALAR(0.0);
+               return 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_expired() const
        {
-               return mode_ == repeat;
+               return is_expired(source_->ticks());
        }
 
 
+       static timer_source& default_source();
+
        /**
-        * Get the number of seconds since a fixed, arbitrary point in the
-        * past.
+        * Get the number of real seconds since the default timer was first
+        * created or last reset.
         * \return Seconds.
         */
        static scalar ticks();
@@ -222,25 +263,78 @@ public:
 
        /**
         * Put the thread to sleep for a certain period of time.  If absolute
-        * is true, then it will sleep until seconds after the fixed time in
-        * the past.  If absolute is false, it will sleep for seconds starting
-        * now.  Unlike system sleep functions, this one automatically resumes
-        * sleep if sleep was interrupted by a signal.  Therefore, calling this
-        * function is guaranteed to sleep for the requested amount of time
-        * (and maybe longer).
+        * is true, then it will sleep until the default timer reaches the
+        * specified number of seconds.  If the mode is relative, the thread
+        * will sleep for that many seconds.  Unlike system sleep functions,
+        * this one automatically resumes sleep if sleep was interrupted by a
+        * signal.  Therefore, calling this function is guaranteed to sleep for
+        * at least the requested amount of time.
         * \param seconds Number of seconds.
         * \param mode The timer mode.
         */
-       static void sleep(scalar seconds, mode mode = relative);
+       static void sleep(scalar seconds, enum mode mode = relative);
+
+
+private:
+
+       void added_to_runloop(runloop& runloop);
+       void detach_from_runloop();
+
+
+       function                function_;
+       enum mode               mode_;
+       scalar                  absolute_;
+       scalar                  interval_;
+       timer_source*   source_;
+       runloop*                runloop_;
+};
+
+
+
+
+class game_time : public timer_source
+{
+public:
+
+       game_time(scalar timestep) :
+               timestep_(timestep),
+               scale_(timestep)
+       {
+               reset();
+       }
+
+       scalar ticks() const
+       {
+               return reference_ + scalar(ticks_) * scale_;
+       }
+
+       void reset()
+       {
+               reference_ = SCALAR(0.0);
+               ticks_ = 0;
+       }
+
+       void scale(scalar factor)
+       {
+               reference_ = ticks();
+               ticks_ = 1;
+               scale_ = timestep_ * factor;
+       }
+
+
+       unsigned step(unsigned step = 1)
+       {
+               ticks_ += step;
+               return ticks_;
+       }
 
 
 private:
 
-       function        function_;
-       mode            mode_;
-       scalar          absolute_;
-       scalar          interval_;
-       runloop*        runloop_;
+       scalar          reference_;
+       unsigned        ticks_;
+       scalar          timestep_;
+       scalar          scale_;
 };
 
 
This page took 0.025136 seconds and 4 git commands to generate.