Browse Source

define start()/finish(), put more assertion checks in for state

David Rose 23 năm trước cách đây
mục cha
commit
c1b2fc4652

+ 13 - 9
direct/src/extensions/CInterval-extensions.py

@@ -4,11 +4,9 @@
     of the CInterval class
     """
 
-    def play(self, t0 = 0.0, duration = None, scale = 1.0):
-        """ play(t0, duration)
-        """
+    def start(self, t0 = 0.0, duration = None, scale = 1.0):
         if self.isPlaying():
-            self.stop()
+            self.finish()
         if duration:  # None or 0 implies full length
             self.setupPlay(t0, t0 + duration, scale)
         else:
@@ -17,7 +15,7 @@
         self.resume()
 
     def loop(self, t0 = 0.0, duration = None, scale = 1.0):
-        self.play(t0, duration, scale)
+        self.start(t0, duration, scale)
         self.__loop = 1
         return
 
@@ -31,8 +29,8 @@
         # Spawn task
         taskMgr.add(self.__playTask, self.getName() + '-play')
     
-    def stop(self):
-        # Nowadays, stop() will implicitly set the interval to its
+    def finish(self):
+        # Nowadays, finish() will implicitly set the interval to its
         # terminal state, like setFinalT() used to.  Use pause()
         # instead if you just want to leave the interval in its
         # current state, whatever that may be.
@@ -42,8 +40,14 @@
             for func in self.setTHooks:
                 func(self.getT())
 
+    def play(self, *args, **kw):
+        self.start(*args, **kw)
+
+    def stop(self):
+        self.finish()
+
     def setFinalT(self):
-        self.stop()
+        self.finish()
 
     def setT(self, t, event = ETStep):
         # Overridden from the C++ layer.  We rename the C++ function
@@ -115,7 +119,7 @@
                       command = lambda s=self: s.pause())
         play = Button(
             bf, text = 'Play',
-            command = lambda s=self, es=es: s.play(es.get()))
+            command = lambda s=self, es=es: s.start(es.get()))
         jumpToEnd = Button(bf, text = '>>', command = toEnd)
         jumpToStart.pack(side = LEFT, expand = 1, fill = X)
         play.pack(side = LEFT, expand = 1, fill = X)

+ 17 - 11
direct/src/interval/Interval.py

@@ -75,22 +75,22 @@ class Interval(DirectObject):
         # Used by control panel to update scale
         pass
 
-    def play(self, t0=0.0, duration=0.0, scale=1.0):
-        """ play(t0, duration)
-        """
+    def start(self, t0=0.0, duration=0.0, scale=1.0):
+        # Starts playing the interval from the beginning, or at the
+        # indicated time if specified.
+        
         # Make sure the start time is sensible.
         if t0 > self.duration:
             t0 = self.duration
 
         # Kill ongoing play task
         if self.isPlaying():
-            self.stop()
+            self.finish()
         # Start new one
         self.offset = t0
         self.startT = globalClock.getFrameTime()
         assert(scale > 0.0)
         self.scale = scale
-        self.vernier = 0.0
         self.firstTime = 1
         if (duration == 0.0):
             # If no play duration specified, use duration of Interval
@@ -105,7 +105,7 @@ class Interval(DirectObject):
     def loop(self, t0=0.0, duration=0.0, scale=1.0):
         self.accept(self.name + '-loop', self.play,
                     extraArgs=[t0, duration, scale])
-        self.play(t0, duration, scale)
+        self.start(t0, duration, scale)
         return
 
     def pause(self):
@@ -121,16 +121,22 @@ class Interval(DirectObject):
         # Spawn task
         taskMgr.add(self.__playTask, self.getName() + '-play')
 
-    def stop(self):
-        # Nowadays, stop() will implicitly set the interval to its
+    def finish(self):
+        # Nowadays, finish() will implicitly set the interval to its
         # terminal state, like setFinalT() used to.  Use pause()
         # instead if you just want to leave the interval in its
         # current state, whatever that may be.
         self.pause()
         self.setT(self.getDuration(), IVAL_DONE)
 
+    def play(self, *args, **kw):
+        self.start(*args, **kw)
+        
+    def stop(self):
+        self.finish()
+
     def setFinalT(self):
-        self.stop()
+        self.finish()
 
     def isPlaying(self):
         return taskMgr.hasTaskNamed(self.name + '-play')
@@ -139,7 +145,7 @@ class Interval(DirectObject):
         """ __playTask(task)
         """
         t = globalClock.getFrameTime()
-        te = self.offset + ((t - self.startT) * self.scale + self.vernier)
+        te = self.offset + ((t - self.startT) * self.scale)
         if (te < self.endTime):
             if (self.firstTime):
                 # If first call, init intervals
@@ -215,7 +221,7 @@ class Interval(DirectObject):
                       command = lambda s=self: s.pause())
         play = Button(
             bf, text = 'Play',
-            command = lambda s=self, es=es: s.play(es.get()))
+            command = lambda s=self, es=es: s.start(es.get()))
         jumpToEnd = Button(bf, text = '>>', command = toEnd)
         jumpToStart.pack(side = LEFT, expand = 1, fill = X)
         play.pack(side = LEFT, expand = 1, fill = X)

+ 4 - 4
direct/src/interval/MetaInterval.py

@@ -319,11 +319,11 @@ class MetaInterval(CMetaInterval):
         CMetaInterval.interrupt(self)
         self.__doPythonCallbacks()
 
-    def stop(self):
+    def finish(self):
         # This function overrides from the parent level to check for Python
         # callbacks afterwards.
         self.__updateIvals()
-        CMetaInterval.stop(self)
+        CMetaInterval.finish(self)
         self.__doPythonCallbacks()
 
     def setFinalT(self):
@@ -360,12 +360,12 @@ class MetaInterval(CMetaInterval):
         self.__updateIvals()
         return CMetaInterval.getDuration(self)
 
-    def play(self, *args, **kw):
+    def start(self, *args, **kw):
         # This function overrides from the parent level to force it to
         # update the interval list first, if necessary.
 
         self.__updateIvals()
-        return CMetaInterval.play(self, *args, **kw)
+        return CMetaInterval.start(self, *args, **kw)
 
     def loop(self, *args, **kw):
         # This function overrides from the parent level to force it to

+ 44 - 0
direct/src/interval/cInterval.I

@@ -54,6 +54,18 @@ get_open_ended() const {
   return _open_ended;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CInterval::get_state
+//       Access: Published
+//  Description: Indicates the state the interval believes it is in:
+//               whether it has been started, is currently in the
+//               middle, or has been finalized.
+////////////////////////////////////////////////////////////////////
+INLINE CInterval::State CInterval::
+get_state() const {
+  return _state;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CInterval::set_t
 //       Access: Published
@@ -123,6 +135,38 @@ recompute() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CInterval::check_stopped
+//       Access: Protected
+//  Description: Issues a warning if our internal state is not in
+//               one of the stopped states.
+////////////////////////////////////////////////////////////////////
+INLINE void CInterval::
+check_stopped(const char *method_name) const {
+  if (_state != S_initial && _state != S_final) {
+    interval_cat.warning()
+      << get_name() << "." << method_name << "() called in state "
+      << _state << ".\n";
+    nassertv(!verify_intervals);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CInterval::check_started
+//       Access: Protected
+//  Description: Issues a warning if our internal state is not in
+//               one of the started states.
+////////////////////////////////////////////////////////////////////
+INLINE void CInterval::
+check_started(const char *method_name) const {
+  if (_state != S_started && _state != S_paused) {
+    interval_cat.warning()
+      << get_name() << "." << method_name << "() called in state "
+      << _state << ".\n";
+    nassertv(!verify_intervals);
+  }
+}
+
 INLINE ostream &
 operator << (ostream &out, const CInterval &ival) {
   ival.output(out);

+ 48 - 1
direct/src/interval/cInterval.cxx

@@ -30,6 +30,7 @@ TypeHandle CInterval::_type_handle;
 ////////////////////////////////////////////////////////////////////
 CInterval::
 CInterval(const string &name, double duration, bool open_ended) :
+  _state(S_initial),
   _curr_t(0.0),
   _name(name),
   _duration(duration),
@@ -225,7 +226,9 @@ step_play() {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 initialize(double t) {
+  check_stopped("initialize");
   recompute();
+  _state = S_started;
   step(t);
 }
 
@@ -239,8 +242,11 @@ initialize(double t) {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 instant() {
+  check_stopped("instant");
   recompute();
+  _state = S_started;
   step(get_duration());
+  _state = S_final;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -252,6 +258,8 @@ instant() {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 step(double t) {
+  check_started("step");
+  _state = S_started;
   _curr_t = t;
 }
 
@@ -265,7 +273,13 @@ step(double t) {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 finalize() {
-  step(get_duration());
+  double duration = get_duration();
+  if (_state == S_initial) {
+    initialize(duration);
+  }
+
+  step(duration);
+  _state = S_final;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -278,7 +292,9 @@ finalize() {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 reverse_initialize(double t) {
+  check_stopped("reverse_initialize");
   recompute();
+  _state = S_started;
   step(t);
 }
 
@@ -293,8 +309,11 @@ reverse_initialize(double t) {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 reverse_instant() {
+  check_stopped("reverse_instant");
   recompute();
+  _state = S_started;
   step(0.0);
+  _state = S_initial;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -306,7 +325,12 @@ reverse_instant() {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 reverse_finalize() {
+  if (_state == S_initial) {
+    initialize(0.0);
+  }
+
   step(0.0);
+  _state = S_initial;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -325,6 +349,9 @@ reverse_finalize() {
 ////////////////////////////////////////////////////////////////////
 void CInterval::
 interrupt() {
+  if (_state == S_started) {
+    _state = S_paused;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -379,3 +406,23 @@ void CInterval::
 do_recompute() {
   _dirty = false;
 }
+
+ostream &
+operator << (ostream &out, CInterval::State state) {
+  switch (state) {
+  case CInterval::S_initial:
+    return out << "initial";
+
+  case CInterval::S_started:
+    return out << "started";
+
+  case CInterval::S_paused:
+    return out << "paused";
+
+  case CInterval::S_final:
+    return out << "final";
+  }
+
+  return out << "**invalid state(" << (int)state << ")**";
+}
+

+ 17 - 0
direct/src/interval/cInterval.h

@@ -22,6 +22,7 @@
 #include "directbase.h"
 #include "typedReferenceCount.h"
 #include "pvector.h"
+#include "config_interval.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : CInterval
@@ -56,6 +57,15 @@ PUBLISHED:
     ET_interrupt
   };
 
+  enum State {
+    S_initial,
+    S_started,
+    S_paused,
+    S_final
+  };
+
+  INLINE State get_state() const;
+
   INLINE void set_t(double t, EventType event = ET_step);
   INLINE double get_t() const;
 
@@ -63,6 +73,9 @@ PUBLISHED:
   int step_play();
 
   // These functions control the actual playback of the interval.
+  // Don't call them directly; they're intended to be called from a
+  // supervising object, e.g. the Python start() .. finish()
+  // interface.
   virtual void initialize(double t);
   virtual void instant();
   virtual void step(double t);
@@ -81,7 +94,10 @@ public:
 protected:
   INLINE void recompute() const;
   virtual void do_recompute();
+  INLINE void check_stopped(const char *method_name) const;
+  INLINE void check_started(const char *method_name) const;
 
+  State _state;
   double _curr_t;
   string _name;
   double _duration;
@@ -128,6 +144,7 @@ private:
 };
 
 INLINE ostream &operator << (ostream &out, const CInterval &ival);
+ostream &operator << (ostream &out, CInterval::State state);
 
 #include "cInterval.I"
 

+ 2 - 0
direct/src/interval/cLerpAnimEffectInterval.cxx

@@ -31,6 +31,8 @@ TypeHandle CLerpAnimEffectInterval::_type_handle;
 ////////////////////////////////////////////////////////////////////
 void CLerpAnimEffectInterval::
 step(double t) {
+  check_started("step");
+  _state = S_started;
   double d = compute_delta(t);
 
   Controls::iterator ci;

+ 12 - 0
direct/src/interval/cLerpNodePathInterval.cxx

@@ -64,8 +64,10 @@ CLerpNodePathInterval(const string &name, double duration,
 ////////////////////////////////////////////////////////////////////
 void CLerpNodePathInterval::
 initialize(double t) {
+  check_stopped("initialize");
   recompute();
   _prev_d = 0.0;
+  _state = S_started;
   step(t);
 }
 
@@ -79,9 +81,12 @@ initialize(double t) {
 ////////////////////////////////////////////////////////////////////
 void CLerpNodePathInterval::
 instant() {
+  check_stopped("instant");
   recompute();
   _prev_d = 0.0;
+  _state = S_started;
   step(get_duration());
+  _state = S_final;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -93,6 +98,8 @@ instant() {
 ////////////////////////////////////////////////////////////////////
 void CLerpNodePathInterval::
 step(double t) {
+  check_started("step");
+  _state = S_started;
   double d = compute_delta(t);
 
   if ((_flags & (F_end_pos | F_end_hpr | F_end_scale)) != 0) {
@@ -278,7 +285,9 @@ step(double t) {
 ////////////////////////////////////////////////////////////////////
 void CLerpNodePathInterval::
 reverse_initialize(double t) {
+  check_stopped("reverse_initialize");
   recompute();
+  _state = S_started;
   _prev_d = 1.0;
   step(t);
 }
@@ -294,9 +303,12 @@ reverse_initialize(double t) {
 ////////////////////////////////////////////////////////////////////
 void CLerpNodePathInterval::
 reverse_instant() {
+  check_stopped("reverse_initialize");
   recompute();
+  _state = S_started;
   _prev_d = 1.0;
   step(0.0);
+  _state = S_initial;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 26 - 2
direct/src/interval/cMetaInterval.cxx

@@ -330,6 +330,7 @@ get_interval_end_time(const string &name) const {
 ////////////////////////////////////////////////////////////////////
 void CMetaInterval::
 initialize(double t) {
+  check_stopped("initialize");
   // It may be tempting to flush the event_queue here, but don't do
   // it.  Those are events that must still be serviced from some
   // previous interval operation.  Throwing them away would be a
@@ -354,6 +355,7 @@ initialize(double t) {
   finish_events_forward(now, new_active);
 
   _curr_t = t;
+  _state = S_started;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -366,6 +368,7 @@ initialize(double t) {
 ////////////////////////////////////////////////////////////////////
 void CMetaInterval::
 instant() {
+  check_stopped("instant");
   recompute();
   _active.clear();
 
@@ -381,6 +384,7 @@ instant() {
 
   _next_event_index = _events.size();
   _curr_t = get_duration();
+  _state = S_final;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -392,6 +396,7 @@ instant() {
 ////////////////////////////////////////////////////////////////////
 void CMetaInterval::
 step(double t) {
+  check_started("step");
   int now = double_to_int_time(t);
 
   // Now look for events between the last time we ran and the current
@@ -426,6 +431,7 @@ step(double t) {
   }
 
   _curr_t = t;
+  _state = S_started;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -437,6 +443,11 @@ step(double t) {
 ////////////////////////////////////////////////////////////////////
 void CMetaInterval::
 finalize() {
+  double duration = get_duration();
+  if (_state == S_initial) {
+    initialize(duration);
+  }
+
   // Do all remaining events.
   ActiveEvents new_active;
   while (_next_event_index < _events.size()) {
@@ -446,8 +457,9 @@ finalize() {
     _next_event_index++;
   }
 
-  _curr_t = get_duration();
-  finish_events_forward(double_to_int_time(_curr_t), new_active);
+  finish_events_forward(double_to_int_time(duration), new_active);
+  _curr_t = duration;
+  _state = S_final;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -460,6 +472,7 @@ finalize() {
 ////////////////////////////////////////////////////////////////////
 void CMetaInterval::
 reverse_initialize(double t) {
+  check_stopped("reverse_initialize");
   // It may be tempting to flush the event_queue here, but don't do
   // it.  Those are events that must still be serviced from some
   // previous interval operation.  Throwing them away would be a
@@ -484,6 +497,7 @@ reverse_initialize(double t) {
   finish_events_reverse(now, new_active);
 
   _curr_t = t;
+  _state = S_started;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -497,6 +511,7 @@ reverse_initialize(double t) {
 ////////////////////////////////////////////////////////////////////
 void CMetaInterval::
 reverse_instant() {
+  check_stopped("reverse_instant");
   recompute();
   _active.clear();
 
@@ -512,6 +527,7 @@ reverse_instant() {
 
   _next_event_index = 0;
   _curr_t = 0.0;
+  _state = S_initial;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -523,6 +539,10 @@ reverse_instant() {
 ////////////////////////////////////////////////////////////////////
 void CMetaInterval::
 reverse_finalize() {
+  if (_state == S_initial) {
+    initialize(0.0);
+  }
+
   // Do all remaining events at the beginning.
   ActiveEvents new_active;
 
@@ -534,6 +554,7 @@ reverse_finalize() {
 
   finish_events_reverse(0, new_active);
   _curr_t = 0.0;
+  _state = S_initial;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -557,6 +578,9 @@ interrupt() {
     PlaybackEvent *event = (*ai);
     enqueue_event(event->_n, ET_interrupt, false);
   }
+  if (_state == S_started) {
+    _state = S_paused;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 0
direct/src/interval/config_interval.cxx

@@ -38,6 +38,10 @@ ConfigureFn(config_interval) {
 // CMetaInterval created.
 const double interval_precision = config_interval.GetDouble("interval-precision", 1000.0);
 
+// Set this true to generate an assertion failure if interval
+// functions are called out-of-order.
+const bool verify_intervals = config_interval.GetBool("verify-intervals", false);
+
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libinterval
 //  Description: Initializes the library.  This must be called at

+ 1 - 0
direct/src/interval/config_interval.h

@@ -26,6 +26,7 @@
 NotifyCategoryDecl(interval, EXPCL_DIRECT, EXPTP_DIRECT);
 
 extern const double interval_precision;
+extern const bool verify_intervals;
 
 extern EXPCL_DIRECT void init_libinterval();
 

+ 4 - 0
direct/src/interval/showInterval.cxx

@@ -50,7 +50,9 @@ ShowInterval(const NodePath &node, const string &name) :
 ////////////////////////////////////////////////////////////////////
 void ShowInterval::
 instant() {
+  check_stopped("instant");
   _node.show();
+  _state = S_final;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -64,5 +66,7 @@ instant() {
 ////////////////////////////////////////////////////////////////////
 void ShowInterval::
 reverse_instant() {
+  check_stopped("instant");
   _node.hide();
+  _state = S_initial;
 }