diff --git a/direct/src/interval/Interval.py b/direct/src/interval/Interval.py index b77da2346d..c552f2158a 100644 --- a/direct/src/interval/Interval.py +++ b/direct/src/interval/Interval.py @@ -21,6 +21,7 @@ class Interval(DirectObject): self.duration = duration self.state = CInterval.SInitial self.currT = 0.0 + self.doneEvent = None self.setTHooks = [] self.__startT = 0 self.__startTAtStart = 1 @@ -56,6 +57,12 @@ class Interval(DirectObject): def getT(self): return self.currT + def setDoneEvent(self, event): + self.doneEvent = event + + def getDoneEvent(self): + return self.doneEvent + def privDoEvent(self, t, event): if event == CInterval.ETStep: self.privStep(t) @@ -87,6 +94,7 @@ class Interval(DirectObject): self.state = CInterval.SStarted self.privStep(self.getDuration()) self.state = CInterval.SFinal + self.intervalDone() def privStep(self, t): # Subclasses may redefine this function @@ -97,6 +105,7 @@ class Interval(DirectObject): # Subclasses may redefine this function self.privStep(self.getDuration()) self.state = CInterval.SFinal + self.intervalDone() def privReverseInitialize(self, t): # Subclasses may redefine this function @@ -118,6 +127,12 @@ class Interval(DirectObject): # Subclasses may redefine this function self.state = CInterval.SPaused + def intervalDone(self): + # Subclasses should call this when the interval transitions to + # its final state. + if self.doneEvent: + messenger.throw(self.doneEvent) + def setupPlay(self, startT, endT, playRate): duration = self.getDuration() diff --git a/direct/src/interval/cInterval.I b/direct/src/interval/cInterval.I index b65243aaeb..22b8d950fd 100644 --- a/direct/src/interval/cInterval.I +++ b/direct/src/interval/cInterval.I @@ -90,6 +90,32 @@ get_t() const { return _curr_t; } +//////////////////////////////////////////////////////////////////// +// Function: CInterval::set_done_event +// Access: Published +// Description: Sets the event that is generated whenever the +// interval reaches its final state, whether it is +// explicitly finished or whether it gets there on its +// own. +//////////////////////////////////////////////////////////////////// +INLINE void CInterval:: +set_done_event(const string &event) { + _done_event = event; +} + +//////////////////////////////////////////////////////////////////// +// Function: CInterval::get_done_event +// Access: Published +// Description: Returns the event that is generated whenever the +// interval reaches its final state, whether it is +// explicitly finished or whether it gets there on its +// own. +//////////////////////////////////////////////////////////////////// +INLINE const string &CInterval:: +get_done_event() const { + return _done_event; +} + //////////////////////////////////////////////////////////////////// // Function: CInterval::recompute // Access: Protected diff --git a/direct/src/interval/cInterval.cxx b/direct/src/interval/cInterval.cxx index 93d7121472..ea41c606e4 100644 --- a/direct/src/interval/cInterval.cxx +++ b/direct/src/interval/cInterval.cxx @@ -19,6 +19,7 @@ #include "cInterval.h" #include "indent.h" #include "clockObject.h" +#include "throw_event.h" #include TypeHandle CInterval::_type_handle; @@ -308,6 +309,7 @@ priv_instant() { _state = S_started; priv_step(get_duration()); _state = S_final; + interval_done(); } //////////////////////////////////////////////////////////////////// @@ -338,6 +340,7 @@ priv_finalize() { double duration = get_duration(); priv_step(duration); _state = S_final; + interval_done(); } //////////////////////////////////////////////////////////////////// @@ -449,6 +452,19 @@ mark_dirty() { } } +//////////////////////////////////////////////////////////////////// +// Function: CInterval::interval_done +// Access: Protected +// Description: Called internally whenever the interval reaches its +// final state. +//////////////////////////////////////////////////////////////////// +void CInterval:: +interval_done() { + if (!_done_event.empty()) { + throw_event(_done_event); + } +} + //////////////////////////////////////////////////////////////////// // Function: CInterval::do_recompute // Access: Protected, Virtual diff --git a/direct/src/interval/cInterval.h b/direct/src/interval/cInterval.h index 8cfe03f455..da27a8e9a0 100644 --- a/direct/src/interval/cInterval.h +++ b/direct/src/interval/cInterval.h @@ -68,6 +68,9 @@ PUBLISHED: INLINE bool is_stopped() const; INLINE double get_t() const; + INLINE void set_done_event(const string &event); + INLINE const string &get_done_event() const; + void setup_play(double start_time, double end_time, double play_rate); void setup_resume(); int step_play(); @@ -78,7 +81,7 @@ PUBLISHED: // interface. // These cannot be declared private because they must be accessible - // Python, but the method names are prefixed with priv_ to remind + // to Python, but the method names are prefixed with priv_ to remind // you that you probably don't want to be using them directly. void priv_do_event(double t, EventType event); virtual void priv_initialize(double t); @@ -97,6 +100,8 @@ public: void mark_dirty(); protected: + void interval_done(); + INLINE void recompute() const; virtual void do_recompute(); INLINE void check_stopped(const char *method_name) const; @@ -105,6 +110,7 @@ protected: State _state; double _curr_t; string _name; + string _done_event; double _duration; // For setup_play() and step_play(). diff --git a/direct/src/interval/cMetaInterval.I b/direct/src/interval/cMetaInterval.I index 81bbbb56a4..63d11069cc 100644 --- a/direct/src/interval/cMetaInterval.I +++ b/direct/src/interval/cMetaInterval.I @@ -155,27 +155,6 @@ get_event_type() const { return _event_queue.front()._event_type; } -//////////////////////////////////////////////////////////////////// -// Function: CMetaInterval::pop_event -// Access: Published -// Description: Acknowledges that the external interval on the top of -// the queue has been extracted, and is about to be -// serviced by the scripting language. This prepares -// the interval so the next call to is_event_ready() -// will return information about the next external -// interval on the queue, if any. -//////////////////////////////////////////////////////////////////// -INLINE void CMetaInterval:: -pop_event() { -#ifndef NDEBUG - nassertv(!_event_queue.empty()); - const EventQueueEntry &entry = _event_queue.front(); - const IntervalDef &def = _defs[entry._n]; - nassertv(def._type == DT_ext_index); -#endif - _event_queue.pop_front(); -} - //////////////////////////////////////////////////////////////////// // Function: CMetaInterval::double_to_int_time // Access: Private diff --git a/direct/src/interval/cMetaInterval.cxx b/direct/src/interval/cMetaInterval.cxx index 1b65e31ae7..ed630ab461 100644 --- a/direct/src/interval/cMetaInterval.cxx +++ b/direct/src/interval/cMetaInterval.cxx @@ -419,6 +419,10 @@ priv_instant() { _next_event_index = _events.size(); _curr_t = get_duration(); _state = S_final; + + if (_event_queue.empty()) { + interval_done(); + } } //////////////////////////////////////////////////////////////////// @@ -510,6 +514,10 @@ priv_finalize() { _curr_t = duration; _state = S_final; + + if (_event_queue.empty()) { + interval_done(); + } } //////////////////////////////////////////////////////////////////// @@ -663,6 +671,36 @@ priv_interrupt() { } } +//////////////////////////////////////////////////////////////////// +// Function: CMetaInterval::pop_event +// Access: Published +// Description: Acknowledges that the external interval on the top of +// the queue has been extracted, and is about to be +// serviced by the scripting language. This prepares +// the interval so the next call to is_event_ready() +// will return information about the next external +// interval on the queue, if any. +//////////////////////////////////////////////////////////////////// +void CMetaInterval:: +pop_event() { +#ifndef NDEBUG + nassertv(!_event_queue.empty()); + const EventQueueEntry &entry = _event_queue.front(); + const IntervalDef &def = _defs[entry._n]; + nassertv(def._type == DT_ext_index); +#endif + _event_queue.pop_front(); + + // Really, we should set a flag to call this at the next call to + // service_event_queue(), instead of calling it immediately, because + // the just-popped event probably hasn't been processed yet. But we + // can get away with calling this here for now because Python + // doesn't process C++ events immediately. + if (_state == S_final) { + interval_done(); + } +} + //////////////////////////////////////////////////////////////////// // Function: CMetaInterval::write // Access: Published, Virtual @@ -1017,6 +1055,13 @@ enqueue_self_event(CInterval::EventType event_type, double t) { //////////////////////////////////////////////////////////////////// bool CMetaInterval:: service_event_queue() { + if (_event_queue.empty()) { + // Return early if we're empty on entry, so we don't throw the + // done event more than once. + nassertr(!_processing_events, false); + return false; + } + while (!_event_queue.empty()) { nassertr(!_processing_events, true); const EventQueueEntry &entry = _event_queue.front(); @@ -1045,6 +1090,10 @@ service_event_queue() { _event_queue.pop_front(); } + if (_state == S_final) { + interval_done(); + } + // No more events on the queue. nassertr(!_processing_events, false); diff --git a/direct/src/interval/cMetaInterval.h b/direct/src/interval/cMetaInterval.h index a58fee9a8d..100cf48c48 100644 --- a/direct/src/interval/cMetaInterval.h +++ b/direct/src/interval/cMetaInterval.h @@ -87,7 +87,7 @@ PUBLISHED: INLINE int get_event_index() const; INLINE double get_event_t() const; INLINE EventType get_event_type() const; - INLINE void pop_event(); + void pop_event(); virtual void write(ostream &out, int indent_level) const;