Bladeren bron

SequenceNode inherits from AnimInterface

David Rose 20 jaren geleden
bovenliggende
commit
5465571963

+ 23 - 3
panda/src/egg2pg/eggLoader.cxx

@@ -202,6 +202,7 @@ build_graph() {
   make_node(_data, _root);
 
   reparent_decals();
+  start_sequences();
 
   apply_deferred_nodes(_root, DeferredNodeProperty());
 }
@@ -217,7 +218,7 @@ build_graph() {
 ////////////////////////////////////////////////////////////////////
 void EggLoader::
 reparent_decals() {
-  Decals::const_iterator di;
+  ExtraNodes::const_iterator di;
   for (di = _decals.begin(); di != _decals.end(); ++di) {
     PandaNode *node = (*di);
     nassertv(node != (PandaNode *)NULL);
@@ -271,6 +272,24 @@ reparent_decals() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggLoader::start_sequences
+//       Access: Public
+//  Description: Starts all of the SequenceNodes we created looping.
+//               We have to wait until the entire graph is built up to
+//               do this, because the SequenceNode needs its full set
+//               of children before it can know how many frames to
+//               loop.
+////////////////////////////////////////////////////////////////////
+void EggLoader::
+start_sequences() {
+  ExtraNodes::const_iterator ni;
+  for (ni = _sequences.begin(); ni != _sequences.end(); ++ni) {
+    SequenceNode *node = DCAST(SequenceNode, (*ni));
+    node->loop(true);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggLoader::make_polyset
 //       Access: Public
@@ -1593,8 +1612,9 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
   } else if (egg_group->get_switch_flag()) {
     if (egg_group->get_switch_fps() != 0.0) {
       // Create a sequence node.
-      node = new SequenceNode(egg_group->get_switch_fps(), 
-                              egg_group->get_name());
+      node = new SequenceNode(egg_group->get_name());
+      ((SequenceNode *)node.p())->set_frame_rate(egg_group->get_switch_fps());
+      _sequences.insert(node);
     } else {
       // Create a switch node.
       node = new SwitchNode(egg_group->get_name());

+ 4 - 2
panda/src/egg2pg/eggLoader.h

@@ -75,6 +75,7 @@ public:
 
   void build_graph();
   void reparent_decals();
+  void start_sequences();
 
   void make_polyset(EggBin *egg_bin, PandaNode *parent, 
                     const LMatrix4d *transform, bool is_dynamic,
@@ -212,8 +213,9 @@ private:
   Materials _materials;
   Materials _materials_bface;
 
-  typedef pset<PandaNode *> Decals;
-  Decals _decals;
+  typedef pset<PandaNode *> ExtraNodes;
+  ExtraNodes _decals;
+  ExtraNodes _sequences;
 
   class VertexPoolTransform {
   public:

+ 8 - 95
panda/src/pgraph/sequenceNode.I

@@ -17,113 +17,26 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::CData::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE SequenceNode::CData::
-CData() {
-  _cycle_rate = 0.0f;
-  _frame_offset = 0.0f;
-  _start_time = 0.0f;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::CData::Copy Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE SequenceNode::CData::
-CData(const SequenceNode::CData &copy) :
-  _cycle_rate(copy._cycle_rate),
-  _frame_offset(copy._frame_offset),
-  _start_time(copy._start_time)
-{
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: SequenceNode::Constructor
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE SequenceNode::
-SequenceNode(float cycle_rate, const string &name) :
+SequenceNode(const string &name) :
   SelectiveChildNode(name)
 {
-  CDWriter cdata(_cycler);
-  cdata->_cycle_rate = cycle_rate;
-  cdata->_frame_offset = 0.0f;
-
-  float now = ClockObject::get_global_clock()->get_frame_time();
-  cdata->_start_time = now;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::set_cycle_rate
+//     Function: SequenceNode::set_frame_rate
 //       Access: Published
-//  Description: Sets the rate of cycling for the children of the
-//               SequenceNode, in cycles per second.
+//  Description: Changes the advertised frame rate of the
+//               SequenceNode.  This can be used in conjunction with
+//               get_play_rate() to change the effective frame rate of
+//               the node.
 ////////////////////////////////////////////////////////////////////
 INLINE void SequenceNode::
-set_cycle_rate(float cycle_rate) {
-  // Do some fussing so we keep the same frame visible while we
-  // change this.
-  CDWriter cdata(_cycler);
-  float now = ClockObject::get_global_clock()->get_frame_time();
-  cdata->_frame_offset = calc_frame(now);
-  cdata->_start_time = now;
-  cdata->_cycle_rate = cycle_rate;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::get_cycle_rate
-//       Access: Published
-//  Description: Returns the rate of cycling for the children of the
-//               SequenceNode, in cycles per second.
-////////////////////////////////////////////////////////////////////
-INLINE float SequenceNode::
-get_cycle_rate() const {
-  CDReader cdata(_cycler);
-  return cdata->_cycle_rate;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::set_visible_child
-//       Access: Published
-//  Description: Sets the particular child that this SequenceNode will
-//               display this frame.  Future frames will proceed from
-//               here.
-////////////////////////////////////////////////////////////////////
-INLINE void SequenceNode::
-set_visible_child(int index) {
-  int num_children = get_num_children();
-  if (num_children != 0) {
-    CDWriter cdata(_cycler);
-    float now = ClockObject::get_global_clock()->get_frame_time();
-    cdata->_frame_offset = (index - (now - cdata->_start_time) * cdata->_cycle_rate);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::calc_frame
-//       Access: Private
-//  Description: Returns the floating-point frame number at the
-//               indicated time.
-////////////////////////////////////////////////////////////////////
-INLINE float SequenceNode::
-calc_frame(float now) const {
-  CDReader cdata(_cycler);
-  return (now - cdata->_start_time) * cdata->_cycle_rate + cdata->_frame_offset;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::calc_frame
-//       Access: Private
-//  Description: Returns the floating-point frame number at the
-//               current time.
-////////////////////////////////////////////////////////////////////
-INLINE float SequenceNode::
-calc_frame() const {
-  return calc_frame(ClockObject::get_global_clock()->get_frame_time());
+set_frame_rate(double frame_rate) {
+  AnimInterface::set_frame_rate(frame_rate);
 }

+ 39 - 65
panda/src/pgraph/sequenceNode.cxx

@@ -23,13 +23,30 @@
 TypeHandle SequenceNode::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::CData::make_copy
-//       Access: Public, Virtual
+//     Function: SequenceNode::Copy Constructor
+//       Access: Protected
 //  Description:
 ////////////////////////////////////////////////////////////////////
-CycleData *SequenceNode::CData::
-make_copy() const {
-  return new CData(*this);
+SequenceNode::
+SequenceNode(const SequenceNode &copy) :
+  SelectiveChildNode(copy),
+  AnimInterface(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SequenceNode::get_num_frames
+//       Access: Published, Virtual
+//  Description: Returns the number of frames in the animation.  This
+//               is a property of the animation and may not be
+//               directly adjusted by the user (although it may change
+//               without warning with certain kinds of animations,
+//               since this is a virtual method that may be
+//               overridden).
+////////////////////////////////////////////////////////////////////
+int SequenceNode::
+get_num_frames() const {
+  return get_num_children();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -47,49 +64,6 @@ safe_to_combine() const {
   return false;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::CData::write_datagram
-//       Access: Public, Virtual
-//  Description: Writes the contents of this object to the datagram
-//               for shipping out to a Bam file.
-////////////////////////////////////////////////////////////////////
-void SequenceNode::CData::
-write_datagram(BamWriter *manager, Datagram &dg) const {
-  dg.add_float32(_cycle_rate);
-
-  float now = ClockObject::get_global_clock()->get_frame_time();
-  float frame = (now - _start_time) * _cycle_rate + _frame_offset;
-  dg.add_float32(frame);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::CData::fillin
-//       Access: Public, Virtual
-//  Description: This internal function is called by make_from_bam to
-//               read in all of the relevant data from the BamFile for
-//               the new SequenceNode.
-////////////////////////////////////////////////////////////////////
-void SequenceNode::CData::
-fillin(DatagramIterator &scan, BamReader *manager) {
-  _cycle_rate = scan.get_float32();
-  _frame_offset = scan.get_float32();
-
-  float now = ClockObject::get_global_clock()->get_frame_time();
-  _start_time = now;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::Copy Constructor
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-SequenceNode::
-SequenceNode(const SequenceNode &copy) :
-  SelectiveChildNode(copy),
-  _cycler(copy._cycler)
-{
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: SequenceNode::make_copy
 //       Access: Public, Virtual
@@ -138,7 +112,7 @@ has_cull_callback() const {
 ////////////////////////////////////////////////////////////////////
 bool SequenceNode::
 cull_callback(CullTraverser *, CullTraverserData &) {
-  select_child(get_visible_child());
+  select_child(get_frame());
   return true;
 }
 
@@ -164,21 +138,14 @@ has_single_child_visibility() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: SequenceNode::get_visible_child
+//     Function: SequenceNode::output
 //       Access: Published, Virtual
-//  Description: Returns the index of the child that should be visible
-//               for this particular frame, if there are any children.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
-int SequenceNode::
-get_visible_child() const {
-  int num_children = get_num_children();
-  if (num_children == 0) {
-    return 0;
-  }
-
-  float frame = calc_frame();
-
-  return ((int)frame) % num_children;
+void SequenceNode::
+output(ostream &out) const {
+  out << get_type() << " " << get_name() << ": ";
+  AnimInterface::output(out);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -201,7 +168,7 @@ register_with_read_factory() {
 void SequenceNode::
 write_datagram(BamWriter *manager, Datagram &dg) {
   SelectiveChildNode::write_datagram(manager, dg);
-  manager->write_cdata(dg, _cycler);
+  AnimInterface::write_datagram(manager, dg);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -214,7 +181,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
 ////////////////////////////////////////////////////////////////////
 TypedWritable *SequenceNode::
 make_from_bam(const FactoryParams &params) {
-  SequenceNode *node = new SequenceNode(0.0f, "");
+  SequenceNode *node = new SequenceNode("");
   DatagramIterator scan;
   BamReader *manager;
 
@@ -234,5 +201,12 @@ make_from_bam(const FactoryParams &params) {
 void SequenceNode::
 fillin(DatagramIterator &scan, BamReader *manager) {
   SelectiveChildNode::fillin(scan, manager);
-  manager->read_cdata(scan, _cycler);
+  if (manager->get_file_minor_ver() < 4) {
+    float cycle_rate = scan.get_float32();
+    scan.get_float32();
+    set_frame_rate(cycle_rate);
+    loop(true);
+  } else {
+    AnimInterface::fillin(scan, manager);
+  }
 }

+ 13 - 31
panda/src/pgraph/sequenceNode.h

@@ -22,6 +22,7 @@
 #include "pandabase.h"
 
 #include "selectiveChildNode.h"
+#include "animInterface.h"
 #include "clockObject.h"
 
 ////////////////////////////////////////////////////////////////////
@@ -29,13 +30,18 @@
 // Description : A node that automatically cycles through rendering
 //               each one of its children according to its frame rate.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA SequenceNode : public SelectiveChildNode {
+class EXPCL_PANDA SequenceNode : public SelectiveChildNode, public AnimInterface {
 PUBLISHED:
-  INLINE SequenceNode(float cycle_rate, const string &name);
+  INLINE SequenceNode(const string &name);
 
-public:
+protected:
   SequenceNode(const SequenceNode &copy);
 
+PUBLISHED:
+  virtual int get_num_frames() const;
+  INLINE void set_frame_rate(double frame_rate);
+
+public:
   virtual PandaNode *make_copy() const;
   virtual bool safe_to_combine() const;
 
@@ -43,33 +49,7 @@ public:
   virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
   virtual bool has_single_child_visibility() const;
 
-PUBLISHED:
-  INLINE void set_cycle_rate(float cycle_rate);
-  INLINE float get_cycle_rate() const;
-
-  INLINE void set_visible_child(int index);
-  virtual int get_visible_child() const;
-
-private:
-  INLINE float calc_frame(float now) const;
-  INLINE float calc_frame() const;
-
-  class EXPCL_PANDA CData : public CycleData {
-  public:
-    INLINE CData();
-    INLINE CData(const CData &copy);
-    virtual CycleData *make_copy() const;
-    virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
-    virtual void fillin(DatagramIterator &scan, BamReader *manager);
-
-    float _cycle_rate;
-    float _frame_offset;
-    float _start_time;
-  };
-
-  PipelineCycler<CData> _cycler;
-  typedef CycleDataReader<CData> CDReader;
-  typedef CycleDataWriter<CData> CDWriter;
+  virtual void output(ostream &out) const;
 
 public:
   static void register_with_read_factory();
@@ -85,8 +65,10 @@ public:
   }
   static void init_type() {
     SelectiveChildNode::init_type();
+    AnimInterface::init_type();
     register_type(_type_handle, "SequenceNode",
-                  SelectiveChildNode::get_class_type());
+                  SelectiveChildNode::get_class_type(),
+		  AnimInterface::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 148 - 19
panda/src/putil/animInterface.I

@@ -28,6 +28,26 @@ 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
@@ -40,6 +60,22 @@ 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
@@ -54,6 +90,20 @@ 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
@@ -66,6 +116,19 @@ stop() {
   pose(get_frame());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::pose
+//       Access: Published
+//  Description: Sets the animation to the indicated frame and holds
+//               it there.
+////////////////////////////////////////////////////////////////////
+INLINE void AnimInterface::
+pose(int frame) {
+  CDWriter cdata(_cycler);
+  cdata->pose(frame);
+  animation_activated();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimInterface::set_play_rate
 //       Access: Published
@@ -77,7 +140,8 @@ stop() {
 ////////////////////////////////////////////////////////////////////
 INLINE void AnimInterface::
 set_play_rate(double play_rate) {
-  internal_set_rate(_frame_rate, play_rate);
+  CDWriter cdata(_cycler);
+  cdata->internal_set_rate(cdata->_frame_rate, play_rate);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -88,7 +152,8 @@ set_play_rate(double play_rate) {
 ////////////////////////////////////////////////////////////////////
 INLINE double AnimInterface::
 get_play_rate() const {
-  return _play_rate;
+  CDReader cdata(_cycler);
+  return cdata->_play_rate;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -102,19 +167,8 @@ get_play_rate() const {
 ////////////////////////////////////////////////////////////////////
 INLINE double AnimInterface::
 get_frame_rate() const {
-  return _frame_rate;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::get_num_frames
-//       Access: Published
-//  Description: Returns the number of frames in the animation.  This
-//               is a fixed property of the animation and may not be
-//               adjusted by the user.
-////////////////////////////////////////////////////////////////////
-INLINE int AnimInterface::
-get_num_frames() const {
-  return _num_frames;
+  CDReader cdata(_cycler);
+  return cdata->_frame_rate;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -126,10 +180,11 @@ get_num_frames() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int AnimInterface::
 get_frame() const {
-  if (get_num_frames() <= 0) {
+  int num_frames = get_num_frames();
+  if (num_frames <= 0) {
     return 0;
   }
-  return cmod(get_full_frame(), get_num_frames());
+  return cmod(get_full_frame(), num_frames);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -145,7 +200,64 @@ get_frame() const {
 ////////////////////////////////////////////////////////////////////
 INLINE double AnimInterface::
 get_frac() const {
-  return get_full_fframe() - (double)get_full_frame();
+  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();
+}
+
+////////////////////////////////////////////////////////////////////
+//     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();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -157,7 +269,8 @@ get_frac() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void AnimInterface::
 set_frame_rate(double frame_rate) {
-  internal_set_rate(frame_rate, _play_rate);
+  CDWriter cdata(_cycler);
+  cdata->internal_set_rate(frame_rate, cdata->_play_rate);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -174,6 +287,22 @@ 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();
+}
+
 INLINE ostream &
 operator << (ostream &out, const AnimInterface &ai) {
   ai.output(out);

+ 197 - 78
panda/src/putil/animInterface.cxx

@@ -18,6 +18,10 @@
 
 #include "animInterface.h"
 #include "clockObject.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "datagram.h"
+#include "datagramIterator.h"
 
 TypeHandle AnimInterface::_type_handle;
 
@@ -28,8 +32,101 @@ TypeHandle AnimInterface::_type_handle;
 ////////////////////////////////////////////////////////////////////
 AnimInterface::
 AnimInterface() :
+  _num_frames(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::Copy Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+AnimInterface::
+AnimInterface(const AnimInterface &copy) :
+  _num_frames(copy._num_frames),
+  _cycler(copy._cycler)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+AnimInterface::
+~AnimInterface() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::get_num_frames
+//       Access: Published, Virtual
+//  Description: Returns the number of frames in the animation.  This
+//               is a property of the animation and may not be
+//               directly adjusted by the user (although it may change
+//               without warning with certain kinds of animations,
+//               since this is a virtual method that may be
+//               overridden).
+////////////////////////////////////////////////////////////////////
+int AnimInterface::
+get_num_frames() const {
+  return _num_frames;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::output
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+output(ostream &out) const {
+  CDReader cdata(_cycler);
+  cdata->output(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::animation_activated
+//       Access: Protected, Virtual
+//  Description: This is provided as a callback method for when the
+//               user calls one of the play/loop/pose type methods to
+//               start the animation playing.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+animation_activated() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  dg.add_int32(_num_frames);
+  manager->write_cdata(dg, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new AnimInterface.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  _num_frames = scan.get_int32();
+  manager->read_cdata(scan, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::CData::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+AnimInterface::CData::
+CData() :
   _frame_rate(0.0),
-  _num_frames(0),
   _play_mode(PM_pose),
   _start_time(0.0),
   _start_frame(0.0),
@@ -44,14 +141,13 @@ AnimInterface() :
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::Copy Constructor
+//     Function: AnimInterface::CData::Copy Constructor
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-AnimInterface::
-AnimInterface(const AnimInterface &copy) :
+AnimInterface::CData::
+CData(const AnimInterface::CData &copy) :
   _frame_rate(copy._frame_rate),
-  _num_frames(copy._num_frames),
   _play_mode(copy._play_mode),
   _start_time(copy._start_time),
   _start_frame(copy._start_frame),
@@ -66,17 +162,60 @@ AnimInterface(const AnimInterface &copy) :
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::Destructor
-//       Access: Published, Virtual
+//     Function: AnimInterface::CData::make_copy
+//       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-AnimInterface::
-~AnimInterface() {
+CycleData *AnimInterface::CData::
+make_copy() const {
+  return new CData(*this);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::play
-//       Access: Published
+//     Function: AnimInterface::CData::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::CData::
+write_datagram(BamWriter *, Datagram &dg) const {
+  dg.add_float32(_frame_rate);
+  dg.add_uint8(_play_mode);
+  dg.add_float32(_start_time);
+  dg.add_float32(_start_frame);
+  dg.add_float32(_play_frames);
+  dg.add_float32(_from_frame);
+  dg.add_float32(_to_frame);
+  dg.add_float32(_play_rate);
+  dg.add_bool(_paused);
+  dg.add_float32(_paused_f);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::CData::fillin
+//       Access: Public, Virtual
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new AnimInterface.
+////////////////////////////////////////////////////////////////////
+void AnimInterface::CData::
+fillin(DatagramIterator &scan, BamReader *) {
+  _frame_rate = scan.get_float32();
+  _play_mode = (PlayMode)scan.get_uint8();
+  _start_time = scan.get_float32();
+  _start_frame = scan.get_float32();
+  _play_frames = scan.get_float32();
+  _from_frame = scan.get_float32();
+  _to_frame = scan.get_float32();
+  _play_rate = scan.get_float32();
+  _effective_frame_rate = _frame_rate * _play_rate;
+  _paused = scan.get_bool();
+  _paused_f = scan.get_float32();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::CData::play
+//       Access: Public
 //  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
@@ -87,7 +226,7 @@ AnimInterface::
 //               get_num_frames() * 2) will play the animation twice
 //               and then stop.
 ////////////////////////////////////////////////////////////////////
-void AnimInterface::
+void AnimInterface::CData::
 play(double from, double to) {
   if (from >= to) {
     pose((int)from);
@@ -106,20 +245,18 @@ play(double from, double to) {
     // If we'll be playing backward, start at the end.
     _start_time -= _play_frames / _effective_frame_rate;
   }
-
-  animation_activated();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::loop
-//       Access: Published
+//     Function: AnimInterface::CData::loop
+//       Access: Public
 //  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.
 ////////////////////////////////////////////////////////////////////
-void AnimInterface::
+void AnimInterface::CData::
 loop(bool restart, double from, double to) {
   if (from >= to) {
     pose((int)from);
@@ -143,18 +280,16 @@ loop(bool restart, double from, double to) {
       _start_time -= fframe / _effective_frame_rate;
     }
   }
-
-  animation_activated();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::pingpong
-//       Access: Published
+//     Function: AnimInterface::CData::pingpong
+//       Access: Public
 //  Description: Loops the animation from the frame "from" to and
 //               including the frame "to", and then back in the
 //               opposite direction, indefinitely.
 ////////////////////////////////////////////////////////////////////
-void AnimInterface::
+void AnimInterface::CData::
 pingpong(bool restart, double from, double to) {
   if (from >= to) {
     pose((int)from);
@@ -178,17 +313,15 @@ pingpong(bool restart, double from, double to) {
       _start_time -= fframe / _effective_frame_rate;
     }
   }
-
-  animation_activated();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::pose
-//       Access: Published
+//     Function: AnimInterface::CData::pose
+//       Access: Public
 //  Description: Sets the animation to the indicated frame and holds
 //               it there.
 ////////////////////////////////////////////////////////////////////
-void AnimInterface::
+void AnimInterface::CData::
 pose(int frame) {
   _play_mode = PM_pose;
   _start_time = ClockObject::get_global_clock()->get_frame_time();
@@ -197,13 +330,11 @@ pose(int frame) {
   _from_frame = frame;
   _to_frame = frame;
   _paused_f = 0.0;
-
-  animation_activated();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::get_full_frame
-//       Access: Published
+//     Function: AnimInterface::CData::get_full_frame
+//       Access: Public
 //  Description: Returns the current integer frame number.
 //
 //               Unlike the value returned by get_frame(), this frame
@@ -215,7 +346,7 @@ pose(int frame) {
 //               return value will never exceed the value passed to
 //               to_frame in the play() method.
 ////////////////////////////////////////////////////////////////////
-int AnimInterface::
+int AnimInterface::CData::
 get_full_frame() const {
   int frame = (int)floor(get_full_fframe());
   if (_play_mode == PM_play) {
@@ -227,8 +358,8 @@ get_full_frame() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::get_full_fframe
-//       Access: Published
+//     Function: AnimInterface::CData::get_full_fframe
+//       Access: Public
 //  Description: Returns the current floating-point frame number.
 //
 //               Unlike the value returned by get_frame(), this frame
@@ -242,7 +373,7 @@ get_full_frame() const {
 //               this case the return value of get_full_frame() will
 //               be to_frame, not (to_frame + 1).
 ////////////////////////////////////////////////////////////////////
-double AnimInterface::
+double AnimInterface::CData::
 get_full_fframe() const {
   switch (_play_mode) {
   case PM_pose:
@@ -271,14 +402,14 @@ get_full_fframe() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::is_playing
-//       Access: Published
+//     Function: AnimInterface::CData::is_playing
+//       Access: Public
 //  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).
 ////////////////////////////////////////////////////////////////////
-bool AnimInterface::
+bool AnimInterface::CData::
 is_playing() const {
   switch (_play_mode) {
   case PM_pose:
@@ -296,69 +427,39 @@ is_playing() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::output
-//       Access: Published, Virtual
+//     Function: AnimInterface::CData::output
+//       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-void AnimInterface::
+void AnimInterface::CData::
 output(ostream &out) const {
   switch (_play_mode) {
   case PM_pose:
-    out << "pose, frame " << get_frame();
+    out << "pose, frame " << get_full_frame();
     return;
 
   case PM_play:
-    out << "play, frame " << get_frame();
+    out << "play, frame " << get_full_frame();
     return;
 
   case PM_loop:
-    out << "loop, frame " << get_frame();
+    out << "loop, frame " << get_full_frame();
     return;
 
   case PM_pingpong:
-    out << "pingpong, frame " << get_frame();
+    out << "pingpong, frame " << get_full_frame();
     return;
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::animation_activated
-//       Access: Protected, Virtual
-//  Description: This is provided as a callback method for when the
-//               user calls one of the play/loop/pose type methods to
-//               start the animation playing.
-////////////////////////////////////////////////////////////////////
-void AnimInterface::
-animation_activated() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::get_f
-//       Access: Private
-//  Description: Returns the current floating-point frame number,
-//               elapsed since _start_frame.
-////////////////////////////////////////////////////////////////////
-double AnimInterface::
-get_f() const {
-  if (_paused) {
-    return _paused_f;
-
-  } else {
-    double now = ClockObject::get_global_clock()->get_frame_time();
-    double elapsed = now - _start_time;
-    return (elapsed * _effective_frame_rate);
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimInterface::internal_set_rate
-//       Access: Private
+//     Function: AnimInterface::CData::internal_set_rate
+//       Access: Public
 //  Description: Called internally to adjust either or both of the
 //               frame_rate or play_rate without changing the current
 //               frame number if the animation is already playing.
 ////////////////////////////////////////////////////////////////////
-void AnimInterface::
+void AnimInterface::CData::
 internal_set_rate(double frame_rate, double play_rate) {
   double f = get_f();
   
@@ -379,3 +480,21 @@ internal_set_rate(double frame_rate, double play_rate) {
     _paused = false;
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimInterface::CData::get_f
+//       Access: Public
+//  Description: Returns the current floating-point frame number,
+//               elapsed since _start_frame.
+////////////////////////////////////////////////////////////////////
+double AnimInterface::CData::
+get_f() const {
+  if (_paused) {
+    return _paused_f;
+
+  } else {
+    double now = ClockObject::get_global_clock()->get_frame_time();
+    double elapsed = now - _start_time;
+    return (elapsed * _effective_frame_rate);
+  }
+}

+ 66 - 24
panda/src/putil/animInterface.h

@@ -22,6 +22,15 @@
 #include "pandabase.h"
 #include "typeHandle.h"
 #include "register_type.h"
+#include "cycleData.h"
+#include "cycleDataReader.h"
+#include "cycleDataWriter.h"
+#include "pipelineCycler.h"
+
+class BamWriter;
+class BamReader;
+class Datagram;
+class DatagramIterator;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : AnimInterface
@@ -39,24 +48,24 @@ protected:
 PUBLISHED:
   virtual ~AnimInterface();
   INLINE void play();
-  void play(double from, double to);
+  INLINE void play(double from, double to);
   INLINE void loop(bool restart);
-  void loop(bool restart, double from, double to);
+  INLINE void loop(bool restart, double from, double to);
   INLINE void pingpong(bool restart);
-  void pingpong(bool restart, double from, double to);
+  INLINE void pingpong(bool restart, double from, double to);
   INLINE void stop();
-  void pose(int frame);
+  INLINE void pose(int frame);
 
   INLINE void set_play_rate(double play_rate);
   INLINE double get_play_rate() const;
   INLINE double get_frame_rate() const;
-  INLINE int get_num_frames() const;
+  virtual int get_num_frames() const;
 
   INLINE int get_frame() const;
   INLINE double get_frac() const;
-  int get_full_frame() const;
-  double get_full_fframe() const;
-  bool is_playing() const;
+  INLINE int get_full_frame() const;
+  INLINE double get_full_fframe() const;
+  INLINE bool is_playing() const;
 
   virtual void output(ostream &out) const;
 
@@ -65,10 +74,6 @@ protected:
   INLINE void set_num_frames(int num_frames);
   virtual void animation_activated();
 
-private:
-  double get_f() const;
-  void internal_set_rate(double frame_rate, double play_rate);
-
 private:
   enum PlayMode {
     PM_pose,
@@ -77,20 +82,57 @@ private:
     PM_pingpong,
   };
 
-  double _frame_rate;
+  // This data is not cycled, because it is a semi-permanent part of
+  // the interface.  Also, some derivatives of AnimInterface don't
+  // even use it.
   int _num_frames;
 
-  PlayMode _play_mode;
-  double _start_time;
-  double _start_frame;
-  double _play_frames;
-  int _from_frame;
-  int _to_frame;
-
-  double _play_rate;
-  double _effective_frame_rate;
-  bool _paused;
-  double _paused_f;
+  // This is the data that must be cycled between pipeline stages.
+  class EXPCL_PANDA CData : public CycleData {
+  public:
+    CData();
+    CData(const CData &copy);
+    virtual CycleData *make_copy() const;
+    virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
+    virtual void fillin(DatagramIterator &scan, BamReader *manager);
+
+    void play(double from, double to);
+    void loop(bool restart, double from, double to);
+    void pingpong(bool restart, double from, double to);
+    void pose(int frame);
+
+    INLINE double get_frac() const;
+    int get_full_frame() const;
+    double get_full_fframe() const;
+    bool is_playing() const;
+
+    virtual void output(ostream &out) const;
+
+    void internal_set_rate(double frame_rate, double play_rate);
+    double get_f() const;
+
+    double _frame_rate;
+
+    PlayMode _play_mode;
+    double _start_time;
+    double _start_frame;
+    double _play_frames;
+    int _from_frame;
+    int _to_frame;
+    
+    double _play_rate;
+    double _effective_frame_rate;
+    bool _paused;
+    double _paused_f;
+  };
+
+  PipelineCycler<CData> _cycler;
+  typedef CycleDataReader<CData> CDReader;
+  typedef CycleDataWriter<CData> CDWriter;
+
+protected:
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  void fillin(DatagramIterator &scan, BamReader *manager);
 
 public:
   static TypeHandle get_class_type() {

+ 2 - 1
panda/src/putil/bam.h

@@ -35,10 +35,11 @@ static const unsigned short _bam_major_ver = 5;
 // Bumped to major version 4 on 4/10/02 to store new scene graph.
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 
-static const unsigned short _bam_minor_ver = 3;
+static const unsigned short _bam_minor_ver = 4;
 // Bumped to minor version 1 on 7/14/05 to add TextureStage::_saved_result.
 // Bumped to minor version 2 on 7/21/05 to add TransformState::is_2d.
 // Bumped to minor version 3 on 8/25/05 to add ModelNode::_preserve_attributes.
+// Bumped to minor version 4 on 9/27/05 to make SequenceNode inherit from AnimInterface.
 
 
 #endif