#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
*/
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.
};
/**
*/
timer() :
mode_(invalid),
- absolute_(SCALAR(0.0)) {}
+ absolute_(SCALAR(0.0)),
+ runloop_(0) {}
/**
* Construct a scheduled timer.
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();
/**
*/
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.
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
* 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());
+ }
/**
* \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
* 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());
}
* 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();
/**
* 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_;
};