]> Dogcows Code - chaz/yoink/blobdiff - src/moof/timer.hh
pch support
[chaz/yoink] / src / moof / timer.hh
index f5c3583ccc0525c90adf616979fddfb82d8819ce..a429ba955e0206158814ce120661ef54974b6e09 100644 (file)
@@ -1,22 +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.
 *
-**************************************************************************/
+*****************************************************************************/
 
 #ifndef _MOOF_TIMER_HH_
 #define _MOOF_TIMER_HH_
 
-/**
- * \file timer.hh
- * Functions for measuring time in a friendly unit.
- */
-
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
 #include <boost/noncopyable.hpp>
 #include <moof/math.hh>
 
 
+/**
+ * \file timer.hh
+ * Functions for measuring time in a friendly unit.
+ */
+
 namespace moof {
 
 
+// forward declarations
+class runloop;
+
+/**
+ * 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;
+};
+
+
 /**
  * A class to represent a timer for scheduled events.  The timer events
  * will be executed on or sometime after their schedculed time.  The
@@ -43,27 +78,27 @@ 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          =     /// Timer is scheduled by a periodic time.
        };
 
        /**
         * Function protocol for a timer event handler.  A function matching
         * this protocol will be called when the timer expires.  The function
         * takes two parameters: the timer object that just expired, and the
-        * absolute time.
+        * absolute time of the time source which caused the timer to expire.
         */
        typedef boost::function<void(timer&,scalar)> function;
 
-
        /**
         * Construct an invalid (uninitialized) timer.
         */
        timer() :
                mode_(invalid),
-               absolute_(SCALAR(0.0)) {}
+               absolute_(SCALAR(0.0)),
+               runloop_(0) {}
 
        /**
         * Construct a scheduled timer.
@@ -80,20 +115,20 @@ 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,
+                 timer_source& source = default_source()) :
+               runloop_(0)
        {
-               init(function, seconds, mode);
+               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();
 
        /**
         * Initialize a timer with a scheduled time.  If the timer is already
@@ -114,15 +149,8 @@ public:
         */
        void init(const function& function,
                          scalar seconds,
-                         mode mode = relative);
-
-       
-       /**
-        * 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;
+                         enum mode mode = relative,
+                         timer_source& source = default_source());
 
        /**
         * Manually invalidated the timer, removing any schedule such that the
@@ -130,6 +158,10 @@ public:
         */
        void invalidate();
 
+       enum mode mode() const
+       {
+               return mode_;
+       }
 
        /**
         * Manually fire the timer event.  Usually, the timer event will be
@@ -137,19 +169,60 @@ 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);
+       void fire()
+       {
+               fire(source_->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.
+        */
+       bool fire_if_expired(scalar t)
+       {
+               if (is_expired(t))
+               {
+                       fire(t);
+                       return true;
+               }
+               return false;
+       }
+       bool 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
         * 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 next_expiration() const;
+       scalar remaining(scalar t) const
+       {
+               return expiration() - t;
+       }
+       scalar remaining() const
+       {
+               return remaining(source_->ticks());
+       }
 
        /**
         * Get whether or not the timer is expired.  A timer on a repeating
@@ -157,78 +230,104 @@ 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;
-
-       /**
-        * 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(scalar t) const
+       {
+               return remaining(t) < SCALAR(0.0);
+       }
+       bool is_expired() const
+       {
+               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();
 
-
        /**
         * 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:
 
-       /**
-        * Get the absolute time when the next timer is scheduled to expire.
-        * \return Absolute time, in seconds.
-        */
-       static scalar next_event()
+       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 = SCALAR(1.0)) :
+               scale_(timestep),
+               scalefactor_(SCALAR(1.0))
        {
-               return next_event_;
+               reset(timestep);
        }
 
+       scalar ticks() const
+       {
+               return reference_ + scalar(ticks_) * scale_;
+       }
 
-       /**
-        * Fire any timers which are not yet invalidated but have an expiration
-        * time in the past.
-        */
-       static void fire_expired_timers()
+       void reset()
+       {
+               reference_ = SCALAR(0.0);
+               ticks_ = 0;
+       }
+       void reset(scalar timestep)
        {
-               fire_expired_timers(ticks());
+               reset();
+               timestep_ = timestep;
+               scale_ = timestep_ * scalefactor_;
        }
 
-       /**
-        * 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);
+       void scale(scalar factor)
+       {
+               reference_ = ticks();
+               ticks_ = 0;
+               scale_ = timestep_ * factor;
+               scalefactor_ = factor;
+       }
 
+       scalar step(unsigned step = 1)
+       {
+               ticks_ += step;
+               return scale_;
+       }
 
 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_;
+       scalar          reference_;
+       unsigned        ticks_;
+       scalar          timestep_;
+       scalar          scale_;
+       scalar          scalefactor_;
 };
 
 
This page took 0.025554 seconds and 4 git commands to generate.