// Filename: animInterface.I
// Created by:  drose (20Sep05)
//
////////////////////////////////////////////////////////////////////
//
// 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: AnimInterface::play
//       Access: Published
//  Description: Runs the entire animation from beginning to end and
//               stops.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
play() {
  play(0, get_num_frames() - 1);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::play
//       Access: Published
//  Description: Runs the animation from the frame "from" to and
//               including the frame "to", at which point the
//               animation is stopped.  Both "from" and "to" frame
//               numbers may be outside the range (0,
//               get_num_frames()) and the animation will follow the
//               range correctly, reporting numbers modulo
//               get_num_frames().  For instance, play(0,
//               get_num_frames() * 2) will play the animation twice
//               and then stop.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
play(double from, double to) {
  {
    CDWriter cdata(_cycler);
    cdata->play(from, to);
  }
  animation_activated();
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::loop
//       Access: Published
//  Description: Starts the entire animation looping.  If restart is
//               true, the animation is restarted from the beginning;
//               otherwise, it continues from the current frame.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
loop(bool restart) {
  loop(restart, 0, get_num_frames() - 1);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::loop
//       Access: Published
//  Description: Loops the animation from the frame "from" to and
//               including the frame "to", indefinitely.  If restart
//               is true, the animation is restarted from the
//               beginning; otherwise, it continues from the current
//               frame.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
loop(bool restart, double from, double to) {
  {
    CDWriter cdata(_cycler);
    cdata->loop(restart, from, to);
  }
  animation_activated();
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::pingpong
//       Access: Published
//  Description: Starts the entire animation bouncing back and forth
//               between its first frame and last frame.  If restart
//               is true, the animation is restarted from the
//               beginning; otherwise, it continues from the current
//               frame.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
pingpong(bool restart) {
  pingpong(restart, 0, get_num_frames() - 1);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::pingpong
//       Access: Published
//  Description: Loops the animation from the frame "from" to and
//               including the frame "to", and then back in the
//               opposite direction, indefinitely.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
pingpong(bool restart, double from, double to) {
  {
    CDWriter cdata(_cycler);
    cdata->pingpong(restart, from, to);
  }
  animation_activated();
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::stop
//       Access: Published
//  Description: Stops a currently playing or looping animation right
//               where it is.  The animation remains posed at the
//               current frame.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
stop() {
  CDWriter cdata(_cycler);
  cdata->pose(cdata->get_full_fframe());

  // Don't call animation_activated() here; stopping an animation
  // should not activate it.
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::pose
//       Access: Published
//  Description: Sets the animation to the indicated frame and holds
//               it there.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
pose(double frame) {
  {
    CDWriter cdata(_cycler);
    cdata->pose(frame);
  }
  animation_activated();
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::set_play_rate
//       Access: Published
//  Description: Changes the rate at which the animation plays.  1.0
//               is the normal speed, 2.0 is twice normal speed, and
//               0.5 is half normal speed.  0.0 is legal to pause the
//               animation, and a negative value will play the
//               animation backwards.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
set_play_rate(double play_rate) {
  CDWriter cdata(_cycler);
  cdata->internal_set_rate(cdata->_frame_rate, play_rate);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::get_play_rate
//       Access: Published
//  Description: Returns the rate at which the animation plays.  See
//               set_play_rate().
////////////////////////////////////////////////////////////////////
INLINE double AnimInterface::
get_play_rate() const {
  CDReader cdata(_cycler);
  return cdata->_play_rate;
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::get_frame_rate
//       Access: Published
//  Description: Returns the native frame rate of the animation.  This
//               is the number of frames per second that will elapse
//               when the play_rate is set to 1.0.  It is a fixed
//               property of the animation and may not be adjusted by
//               the user.
////////////////////////////////////////////////////////////////////
INLINE double AnimInterface::
get_frame_rate() const {
  CDReader cdata(_cycler);
  return cdata->_frame_rate;
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::get_frame
//       Access: Published
//  Description: Returns the current integer frame number.
//               This number will be in the range 0 <= f <
//               get_num_frames().
////////////////////////////////////////////////////////////////////
INLINE int AnimInterface::
get_frame() const {
  int num_frames = get_num_frames();
  if (num_frames <= 0) {
    return 0;
  }
  CDReader cdata(_cycler);
  return cmod(cdata->get_full_frame(0), num_frames);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::get_next_frame
//       Access: Published
//  Description: Returns the current integer frame number + 1,
//               constrained to the range 0 <= f < get_num_frames().
//
//               If the play mode is PM_play, this will clamp to the
//               same value as get_frame() at the end of the
//               animation.  If the play mode is any other value, this
//               will wrap around to frame 0 at the end of the
//               animation.
////////////////////////////////////////////////////////////////////
INLINE int AnimInterface::
get_next_frame() const {
  int num_frames = get_num_frames();
  if (num_frames <= 0) {
    return 0;
  }
  CDReader cdata(_cycler);
  return cmod(cdata->get_full_frame(1), num_frames);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::get_frac
//       Access: Published
//  Description: Returns the fractional part of the current frame.
//               Normally, this is in the range 0.0 <= f < 1.0, but in
//               the one special case of an animation playing to its
//               end frame and stopping, it might exactly equal 1.0.
//
//               It will always be true that get_full_frame() +
//               get_frac() == get_full_fframe().
////////////////////////////////////////////////////////////////////
INLINE double AnimInterface::
get_frac() const {
  CDReader cdata(_cycler);
  return cdata->get_frac();
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::get_full_frame
//       Access: Published
//  Description: Returns the current integer frame number.
//
//               Unlike the value returned by get_frame(), this frame
//               number may extend beyond the range of
//               get_num_frames() if the frame range passed to play(),
//               loop(), etc. did.
//
//               Unlike the value returned by get_full_fframe(), this
//               return value will never exceed the value passed to
//               to_frame in the play() method.
////////////////////////////////////////////////////////////////////
INLINE int AnimInterface::
get_full_frame() const {
  CDReader cdata(_cycler);
  return cdata->get_full_frame(0);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::get_full_fframe
//       Access: Published
//  Description: Returns the current floating-point frame number.
//
//               Unlike the value returned by get_frame(), this frame
//               number may extend beyond the range of
//               get_num_frames() if the frame range passed to play(),
//               loop(), etc. did.
//
//               Unlike the value returned by get_full_frame(), this
//               return value may equal (to_frame + 1.0), when the
//               animation has played to its natural end.  However, in
//               this case the return value of get_full_frame() will
//               be to_frame, not (to_frame + 1).
////////////////////////////////////////////////////////////////////
INLINE double AnimInterface::
get_full_fframe() const {
  CDReader cdata(_cycler);
  return cdata->get_full_fframe();
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::is_playing
//       Access: Published
//  Description: Returns true if the animation is currently playing,
//               false if it is stopped (e.g. because stop() or pose()
//               was called, or because it reached the end of the
//               animation after play() was called).
////////////////////////////////////////////////////////////////////
INLINE bool AnimInterface::
is_playing() const {
  CDReader cdata(_cycler);
  return cdata->is_playing();
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::set_frame_rate
//       Access: Protected
//  Description: Should be called by a derived class to specify the
//               native frame rate of the animation.  It is legal to
//               call this after the animation has already started.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
set_frame_rate(double frame_rate) {
  CDWriter cdata(_cycler);
  cdata->internal_set_rate(frame_rate, cdata->_play_rate);
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::set_num_frames
//       Access: Protected
//  Description: Should be called by a derived class to specify the
//               number of frames of the animation.  It is legal to
//               call this after the animation has already started,
//               but doing so may suddenly change the apparent current
//               frame number.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
set_num_frames(int num_frames) {
  _num_frames = num_frames;
}

////////////////////////////////////////////////////////////////////
//     Function: AnimInterface::CData::get_frac
//       Access: Published
//  Description: Returns the fractional part of the current frame.
//               Normally, this is in the range 0.0 <= f < 1.0, but in
//               the one special case of an animation playing to its
//               end frame and stopping, it might exactly equal 1.0.
//
//               It will always be true that get_full_frame() +
//               get_frac() == get_full_fframe().
////////////////////////////////////////////////////////////////////
INLINE double AnimInterface::CData::
get_frac() const {
  return get_full_fframe() - (double)get_full_frame(0);
}

INLINE ostream &
operator << (ostream &out, const AnimInterface &ai) {
  ai.output(out);
  return out;
}
