diff --git a/direct/src/interval/IntervalManager.py b/direct/src/interval/IntervalManager.py index 944a7abe06..1fd186d0ef 100644 --- a/direct/src/interval/IntervalManager.py +++ b/direct/src/interval/IntervalManager.py @@ -1,5 +1,6 @@ from PandaModules import * from DirectNotifyGlobal import * +import EventManager import Interval import types @@ -24,6 +25,12 @@ class IntervalManager(CIntervalManager): else: CIntervalManager.__init__(self) + # Set up a custom event queue for handling C++ events from + # intervals. + self.eventQueue = EventQueue() + self.eventManager = EventManager.EventManager(self.eventQueue) + self.setEventQueue(self.eventQueue) + self.ivals = [] self.removedIvals = {} @@ -46,9 +53,26 @@ class IntervalManager(CIntervalManager): return None def step(self): - # Call C++ step, then do all the required Python post-processing. + # This method should be called once per frame to perform all + # of the per-frame processing on the active intervals. + + # Call C++ step, then do the Python stuff. CIntervalManager.step(self) + self.__doPythonCallbacks() + def interrupt(self): + # This method should be called during an emergency cleanup + # operation, to automatically pause or finish all active + # intervals tagged with autoPause or autoFinish set true. + + # Call C++ interrupt, then do the Python stuff. + CIntervalManager.interrupt(self) + self.__doPythonCallbacks() + + def __doPythonCallbacks(self): + # This method does all of the required Python post-processing + # after performing some C++-level action. + # It is important to call all of the python callbacks on the # just-removed intervals before we call any of the callbacks # on the still-running intervals. @@ -67,6 +91,13 @@ class IntervalManager(CIntervalManager): self.ivals[index].privPostEvent() index = self.getNextEvent() + # Finally, throw all the events on the custom event queue. + # These are the done events that may have been generated in + # C++. We use a custom event queue so we can service all of + # these immediately, rather than waiting for the global event + # queue to be serviced (which might not be till next frame). + self.eventManager.doEvents() + def __storeInterval(self, interval, index): while index >= len(self.ivals): diff --git a/direct/src/interval/MetaInterval.py b/direct/src/interval/MetaInterval.py index 8cf0b4e7f2..6f453fe409 100644 --- a/direct/src/interval/MetaInterval.py +++ b/direct/src/interval/MetaInterval.py @@ -32,10 +32,22 @@ class MetaInterval(CMetaInterval): name = kw['name'] del kw['name'] - interruptible = 0 - if kw.has_key('interruptible'): - interruptible = kw['interruptible'] - del kw['interruptible'] + # If the keyword "autoPause" or "autoFinish" is defined to + # non-zero, it means the interval may be automatically paused + # or finished when CIntervalManager::interrupt() is called. + # This is generally called only on a catastrophic situation + # (for instance, the connection to the server being lost) when + # we have to exit right away; these keywords indicate + # intervals that might not be cleaned up by their owners. + + autoPause = 0 + autoFinish = 0 + if kw.has_key('autoPause'): + autoPause = kw['autoPause'] + del kw['autoPause'] + if kw.has_key('autoFinish'): + autoFinish = kw['autoFinish'] + del kw['autoFinish'] # A duration keyword specifies the duration the interval will # appear to have for the purposes of computing the start time @@ -71,7 +83,8 @@ class MetaInterval(CMetaInterval): CMetaInterval.__init__(self, name) self.__manager = ivalMgr - self.setInterruptible(interruptible) + self.setAutoPause(autoPause) + self.setAutoFinish(autoFinish) self.pythonIvals = [] diff --git a/direct/src/interval/cInterval.I b/direct/src/interval/cInterval.I index 94624d5636..efa523d4f0 100644 --- a/direct/src/interval/cInterval.I +++ b/direct/src/interval/cInterval.I @@ -117,30 +117,57 @@ get_t() const { } //////////////////////////////////////////////////////////////////// -// Function: CInterval::set_interruptible +// Function: CInterval::set_auto_pause // Access: Published -// Description: Changes the state of the 'interruptible' flag. If +// Description: Changes the state of the 'auto_pause' flag. If // this is true, the interval may be arbitrarily // interrupted when the system needs to reset due to // some external event by calling -// CIntervalManager::pause_all_interruptible(). If this +// CIntervalManager::interrupt(). If this // is false (the default), the interval must always be // explicitly finished or paused. //////////////////////////////////////////////////////////////////// INLINE void CInterval:: -set_interruptible(bool interruptible) { - _interruptible = interruptible; +set_auto_pause(bool auto_pause) { + _auto_pause = auto_pause; } //////////////////////////////////////////////////////////////////// -// Function: CInterval::get_interruptible +// Function: CInterval::get_auto_pause // Access: Published -// Description: Returns the state of the 'interruptible' flag. See -// set_interruptible(). +// Description: Returns the state of the 'auto_pause' flag. See +// set_auto_pause(). //////////////////////////////////////////////////////////////////// INLINE bool CInterval:: -get_interruptible() const { - return _interruptible; +get_auto_pause() const { + return _auto_pause; +} + +//////////////////////////////////////////////////////////////////// +// Function: CInterval::set_auto_finish +// Access: Published +// Description: Changes the state of the 'auto_finish' flag. If +// this is true, the interval may be arbitrarily +// finished when the system needs to reset due to +// some external event by calling +// CIntervalManager::interrupt(). If this +// is false (the default), the interval must always be +// explicitly finished or paused. +//////////////////////////////////////////////////////////////////// +INLINE void CInterval:: +set_auto_finish(bool auto_finish) { + _auto_finish = auto_finish; +} + +//////////////////////////////////////////////////////////////////// +// Function: CInterval::get_auto_finish +// Access: Published +// Description: Returns the state of the 'auto_finish' flag. See +// set_auto_finish(). +//////////////////////////////////////////////////////////////////// +INLINE bool CInterval:: +get_auto_finish() const { + return _auto_finish; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/interval/cInterval.cxx b/direct/src/interval/cInterval.cxx index d477f3d00f..c0884774ea 100644 --- a/direct/src/interval/cInterval.cxx +++ b/direct/src/interval/cInterval.cxx @@ -20,7 +20,8 @@ #include "cIntervalManager.h" #include "indent.h" #include "clockObject.h" -#include "throw_event.h" +#include "event.h" +#include "eventQueue.h" #include TypeHandle CInterval::_type_handle; @@ -39,7 +40,8 @@ CInterval(const string &name, double duration, bool open_ended) : _open_ended(open_ended), _dirty(false) { - _interruptible = false; + _auto_pause = false; + _auto_finish = false; _wants_t_callback = false; _last_t_callback = -1.0; _manager = CIntervalManager::get_global_ptr(); @@ -610,7 +612,7 @@ mark_dirty() { void CInterval:: interval_done() { if (!_done_event.empty()) { - throw_event(_done_event); + _manager->get_event_queue()->queue_event(new Event(_done_event)); } } diff --git a/direct/src/interval/cInterval.h b/direct/src/interval/cInterval.h index 4599aa75ac..14922ce2c1 100644 --- a/direct/src/interval/cInterval.h +++ b/direct/src/interval/cInterval.h @@ -75,8 +75,10 @@ PUBLISHED: void set_t(double t); INLINE double get_t() const; - INLINE void set_interruptible(bool interruptible); - INLINE bool get_interruptible() const; + INLINE void set_auto_pause(bool auto_pause); + INLINE bool get_auto_pause() const; + INLINE void set_auto_finish(bool auto_finish); + INLINE bool get_auto_finish() const; INLINE void set_wants_t_callback(bool wants_t_callback); INLINE bool get_wants_t_callback() const; @@ -136,7 +138,8 @@ protected: string _done_event; double _duration; - bool _interruptible; + bool _auto_pause; + bool _auto_finish; bool _wants_t_callback; double _last_t_callback; CIntervalManager *_manager; diff --git a/direct/src/interval/cIntervalManager.I b/direct/src/interval/cIntervalManager.I index 610797ef62..1932bf3963 100644 --- a/direct/src/interval/cIntervalManager.I +++ b/direct/src/interval/cIntervalManager.I @@ -17,6 +17,35 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: CIntervalManager::set_event_queue +// Access: Published +// Description: Specifies a custom event queue to be used for +// throwing done events from intervals as they finish. +// If this is not specified, the global event queue is +// used. +// +// The caller maintains ownership of the EventQueue +// object; it is the caller's responsibility to ensure +// that the supplied EventQueue does not destruct during +// the lifetime of the CIntervalManager. +//////////////////////////////////////////////////////////////////// +INLINE void CIntervalManager:: +set_event_queue(EventQueue *event_queue) { + _event_queue = event_queue; +} + +//////////////////////////////////////////////////////////////////// +// Function: CIntervalManager::get_event_queue +// Access: Published +// Description: Returns the custom event queue to be used for +// throwing done events from intervals as they finish. +//////////////////////////////////////////////////////////////////// +INLINE EventQueue *CIntervalManager:: +get_event_queue() const { + return _event_queue; +} + INLINE ostream & operator << (ostream &out, const CIntervalManager &ival_mgr) { ival_mgr.output(out); diff --git a/direct/src/interval/cIntervalManager.cxx b/direct/src/interval/cIntervalManager.cxx index b5246d88b1..7d650de10b 100644 --- a/direct/src/interval/cIntervalManager.cxx +++ b/direct/src/interval/cIntervalManager.cxx @@ -19,6 +19,7 @@ #include "cIntervalManager.h" #include "cMetaInterval.h" #include "dcast.h" +#include "eventQueue.h" CIntervalManager *CIntervalManager::_global_ptr; @@ -31,6 +32,7 @@ CIntervalManager:: CIntervalManager() { _first_slot = 0; _next_event_index = 0; + _event_queue = EventQueue::get_global_event_queue(); } //////////////////////////////////////////////////////////////////// @@ -164,18 +166,18 @@ remove_c_interval(int index) { } //////////////////////////////////////////////////////////////////// -// Function: CIntervalManager::pause_all_interruptible +// Function: CIntervalManager::interrupt // Access: Published -// Description: Pauses (removes from the active queue) all intervals -// tagged as "interruptible". These are intervals that -// someone fired up but won't necessarily expect to -// clean up; they can be interrupted at will when -// necessary. +// Description: Pauses or finishes (removes from the active queue) +// all intervals tagged with auto_pause or auto_finish +// set to true. These are intervals that someone fired +// up but won't necessarily expect to clean up; they can +// be interrupted at will when necessary. // // Returns the number of intervals affected. //////////////////////////////////////////////////////////////////// int CIntervalManager:: -pause_all_interruptible() { +interrupt() { int num_paused = 0; NameIndex::iterator ni; @@ -184,11 +186,38 @@ pause_all_interruptible() { int index = (*ni).second; const IntervalDef &def = _intervals[index]; nassertr(def._interval != (CInterval *)NULL, num_paused); - if (def._interval->get_interruptible()) { + if (def._interval->get_auto_pause() || def._interval->get_auto_finish()) { // This interval may be interrupted. - if (def._interval->get_state() == CInterval::S_started) { - def._interval->priv_interrupt(); + if (def._interval->get_auto_pause()) { + // It may be interrupted simply by pausing it. + if (interval_cat.is_debug()) { + interval_cat.debug() + << "Auto-pausing " << def._interval->get_name() << "\n"; + } + if (def._interval->get_state() == CInterval::S_started) { + def._interval->priv_interrupt(); + } + + } else { + // It should be interrupted by finishing it. + if (interval_cat.is_debug()) { + interval_cat.debug() + << "Auto-finishing " << def._interval->get_name() << "\n"; + } + switch (def._interval->get_state()) { + case CInterval::S_initial: + def._interval->priv_instant(); + break; + + case CInterval::S_final: + break; + + default: + def._interval->priv_finalize(); + } } + + // Now carefully remove it from the active list. NameIndex::iterator prev; prev = ni; ++ni; diff --git a/direct/src/interval/cIntervalManager.h b/direct/src/interval/cIntervalManager.h index 8f9b60816e..64ef55aed5 100644 --- a/direct/src/interval/cIntervalManager.h +++ b/direct/src/interval/cIntervalManager.h @@ -26,6 +26,8 @@ #include "pmap.h" #include "vector_int.h" +class EventQueue; + //////////////////////////////////////////////////////////////////// // Class : CIntervalManager // Description : This object holds a number of currently-playing @@ -46,13 +48,16 @@ PUBLISHED: CIntervalManager(); ~CIntervalManager(); + INLINE void set_event_queue(EventQueue *event_queue); + INLINE EventQueue *get_event_queue() const; + int add_c_interval(CInterval *interval, bool external); int find_c_interval(const string &name) const; CInterval *get_c_interval(int index) const; void remove_c_interval(int index); - int pause_all_interruptible(); + int interrupt(); int get_num_intervals() const; void step(); @@ -84,6 +89,7 @@ private: NameIndex _name_index; typedef vector_int Removed; Removed _removed; + EventQueue *_event_queue; int _first_slot; int _next_event_index;