// Filename: clockObject.I
// Created by:  drose (17Feb00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::Destructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
INLINE ClockObject::
~ClockObject() {
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_mode
//       Access: Published
//  Description: Returns the current mode of the clock.  See
//               set_mode().
////////////////////////////////////////////////////////////////////
INLINE ClockObject::Mode ClockObject::
get_mode() const {
  return _mode;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_frame_time
//       Access: Published
//  Description: Returns the time in seconds as of the last time
//               tick() was called (typically, this will be as of the
//               start of the current frame).
//
//               This is generally the kind of time you want to ask
//               for in most rendering and animation contexts, since
//               it's important that all of the animation for a given
//               frame remains in sync with each other.
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_frame_time(Thread *current_frame) const {
  CDReader cdata(_cycler, current_frame);
  return cdata->_reported_frame_time;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_real_time
//       Access: Published
//  Description: Returns the actual number of seconds elapsed since
//               the ClockObject was created, or since it was last
//               reset.  This is useful for doing real timing
//               measurements, e.g. for performance statistics.
//
//               This returns the most precise timer we have for short
//               time intervals, but it may tend to drift over the
//               long haul.  If more accurate timekeeping is needed
//               over a long period of time, use get_long_time()
//               instead.
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_real_time() const {
  return (_true_clock->get_short_time() - _start_short_time);
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_long_time
//       Access: Published
//  Description: Returns the actual number of seconds elapsed since
//               the ClockObject was created, or since it was last
//               reset.
//
//               This is similar to get_real_time(), except that it
//               uses the most accurate counter we have over a long
//               period of time, and so it is less likely to drift.
//               However, it may not be very precise for measuring
//               short intervals.  On Windows, for instace, this is
//               only accurate to within about 55 milliseconds.
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_long_time() const {
  return (_true_clock->get_long_time() - _start_long_time);
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::reset
//       Access: Published
//  Description: Simultaneously resets both the time and the frame
//               count to zero.
////////////////////////////////////////////////////////////////////
INLINE void ClockObject::
reset() {
  set_real_time(0.0);
  set_frame_time(0.0);
  set_frame_count(0);
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_frame_count
//       Access: Published
//  Description: Returns the number of times tick() has been called
//               since the ClockObject was created, or since it was
//               last reset.  This is generally the number of frames
//               that have been rendered.
////////////////////////////////////////////////////////////////////
INLINE int ClockObject::
get_frame_count(Thread *current_thread) const {
  CDReader cdata(_cycler, current_thread);
  return cdata->_frame_count;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_net_frame_rate
//       Access: Published
//  Description: Returns the average frame rate since the last reset.
//               This is simply the total number of frames divided by
//               the total elapsed time.  This reports the virtual
//               frame rate if the clock is in (or has been in)
//               M_non_real_time mode.
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_net_frame_rate(Thread *current_thread) const {
  CDReader cdata(_cycler, current_thread);
  return (double)cdata->_frame_count / cdata->_reported_frame_time;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_dt
//       Access: Published
//  Description: Returns the elapsed time for the previous frame: the
//               number of seconds elapsed between the last two calls
//               to tick().
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_dt(Thread *current_thread) const {
  CDReader cdata(_cycler, current_thread);
  if (_max_dt > 0.0) {
    return min(_max_dt, cdata->_dt);
  }
  return cdata->_dt;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::set_dt
//       Access: Published
//  Description: In non-real-time mode, sets the number of seconds
//               that should appear to elapse between frames.  In
//               forced mode or limited mode, sets our target dt.  In
//               normal mode, this has no effect.  
//
//               Also see set_frame_rate(), which is a different way
//               to specify the same quantity.
////////////////////////////////////////////////////////////////////
INLINE void ClockObject::
set_dt(double dt) {
  nassertv(dt != 0.0);
  set_frame_rate(1.0 / dt);
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_max_dt
//       Access: Published
//  Description: Returns the current maximum allowable time elapsed
//               between any two frames.  See set_max_dt().
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_max_dt() const {
  return _max_dt;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::set_max_dt
//       Access: Published
//  Description: Sets a limit on the value returned by get_dt().  If
//               this value is less than zero, no limit is imposed;
//               otherwise, this is the maximum value that will ever
//               be returned by get_dt(), regardless of how much time
//               has actually elapsed between frames.
//
//               This limit is only imposed in real-time mode; in
//               non-real-time mode, the dt is fixed anyway and max_dt
//               is ignored.
//
//               This is generally used to guarantee reasonable
//               behavior even in the presence of a very slow or
//               chuggy frame rame.
////////////////////////////////////////////////////////////////////
INLINE void ClockObject::
set_max_dt(double max_dt) {
  _max_dt = max_dt;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_degrade_factor
//       Access: Published
//  Description: In degrade mode, returns the ratio by which the
//               performance is degraded.  A value of 2.0 causes the
//               clock to be slowed down by a factor of two (reducing
//               performance to 1/2 what would be otherwise).
//
//               This has no effect if mode is not M_degrade.
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_degrade_factor() const {
  return _degrade_factor;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::set_degrade_factor
//       Access: Published
//  Description: In degrade mode, sets the ratio by which the
//               performance is degraded.  A value of 2.0 causes the
//               clock to be slowed down by a factor of two (reducing
//               performance to 1/2 what would be otherwise).
//
//               This has no effect if mode is not M_degrade.
////////////////////////////////////////////////////////////////////
INLINE void ClockObject::
set_degrade_factor(double degrade_factor) {
  _degrade_factor = degrade_factor;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::set_average_frame_rate_interval
//       Access: Published
//  Description: Specifies the interval of time (in seconds) over
//               which get_average_frame_rate() averages the number of
//               frames per second to compute the frame rate.
//               Changing this does not necessarily immediately change
//               the result of get_average_frame_rate(), until this
//               interval of time has elapsed again.
//
//               Setting this to zero disables the computation of
//               get_average_frame_rate().
////////////////////////////////////////////////////////////////////
INLINE void ClockObject::
set_average_frame_rate_interval(double time) {
  _average_frame_rate_interval = time;
  if (_average_frame_rate_interval == 0.0) {
    _ticks.clear();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_average_frame_rate_interval
//       Access: Published
//  Description: Returns the interval of time (in seconds) over
//               which get_average_frame_rate() averages the number of frames
//               per second to compute the frame rate.
////////////////////////////////////////////////////////////////////
INLINE double ClockObject::
get_average_frame_rate_interval() const {
  return _average_frame_rate_interval;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::check_errors
//       Access: Published
//  Description: Returns true if a clock error was detected since the
//               last time check_errors() was called.  A clock error
//               means that something happened, an OS or BIOS bug, for
//               instance, that makes the current value of the clock
//               somewhat suspect, and an application may wish to
//               resynchronize with any external clocks.
////////////////////////////////////////////////////////////////////
INLINE bool ClockObject::
check_errors(Thread *current_thread) {
  CDReader cdata(_cycler, current_thread);  // Just to hold a mutex.
  int orig_error_count = _error_count;
  _error_count = _true_clock->get_error_count();
  return (_error_count != orig_error_count);
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::get_global_clock
//       Access: Published
//  Description: Returns a pointer to the global ClockObject.  This is
//               the ClockObject that most code should use for
//               handling scene graph rendering and animation.
////////////////////////////////////////////////////////////////////
INLINE ClockObject *ClockObject::
get_global_clock() {
  if (_global_clock == (ClockObject *)NULL) {
    make_global_clock();
  }
  return _global_clock;
}

////////////////////////////////////////////////////////////////////
//     Function: ClockObject::CData::Copy Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
INLINE ClockObject::CData::
CData(const ClockObject::CData &copy) : 
  _frame_count(copy._frame_count), 
  _reported_frame_time(copy._reported_frame_time),
  _dt(copy._dt)
{
}

////////////////////////////////////////////////////////////////////
//     Function: TimeVal::contructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
INLINE TimeVal::
TimeVal() {
}

////////////////////////////////////////////////////////////////////
//     Function: TimeVal::get_sec
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
INLINE ulong TimeVal::
get_sec() const {
  return tv[0];
}

////////////////////////////////////////////////////////////////////
//     Function: TimeVal::get_usec
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
INLINE ulong TimeVal::
get_usec() const {
  return tv[1];
}
