|
|
@@ -0,0 +1,417 @@
|
|
|
+// Filename: cIntervalManager.cxx
|
|
|
+// Created by: drose (10Sep02)
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+//
|
|
|
+// PANDA 3D SOFTWARE
|
|
|
+// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
|
|
|
+//
|
|
|
+// To contact the maintainers of this program write to
|
|
|
+// [email protected] .
|
|
|
+//
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#include "cIntervalManager.h"
|
|
|
+#include "cMetaInterval.h"
|
|
|
+#include "dcast.h"
|
|
|
+
|
|
|
+CIntervalManager *CIntervalManager::_global_ptr;
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::Constructor
|
|
|
+// Access: Published
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CIntervalManager::
|
|
|
+CIntervalManager() {
|
|
|
+ _first_slot = 0;
|
|
|
+ _next_event_index = 0;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::Destructor
|
|
|
+// Access: Published
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CIntervalManager::
|
|
|
+~CIntervalManager() {
|
|
|
+ nassertv(_name_index.empty());
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::add_c_interval
|
|
|
+// Access: Published
|
|
|
+// Description: Adds the interval to the manager, and returns a
|
|
|
+// unique index for the interval. This index will be
|
|
|
+// unique among all the currently added intervals, but
|
|
|
+// not unique across all intervals ever added to the
|
|
|
+// manager. The maximum index value will never exceed
|
|
|
+// the maximum number of intervals added at any given
|
|
|
+// time.
|
|
|
+//
|
|
|
+// If the external flag is true, the interval is
|
|
|
+// understood to also be stored in the scripting
|
|
|
+// language data structures. In this case, it will be
|
|
|
+// available for information returned by
|
|
|
+// get_next_event() and get_next_removal(). If external
|
|
|
+// is false, the interval's index will never be returned
|
|
|
+// by these two functions.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int CIntervalManager::
|
|
|
+add_c_interval(CInterval *interval, bool external) {
|
|
|
+ // First, check the name index. If we already have an interval by
|
|
|
+ // this name, it gets finished and removed.
|
|
|
+ NameIndex::iterator ni = _name_index.find(interval->get_name());
|
|
|
+ if (ni != _name_index.end()) {
|
|
|
+ int old_index = (*ni).second;
|
|
|
+ nassertr(old_index >= 0 && old_index < (int)_intervals.size(), -1)
|
|
|
+ CInterval *old_interval = _intervals[old_index]._interval;
|
|
|
+ if (old_interval == interval) {
|
|
|
+ // No, it's the same interval that was already here. In this
|
|
|
+ // case, don't finish the interval; just return it.
|
|
|
+ return old_index;
|
|
|
+ }
|
|
|
+ finish_interval(old_interval);
|
|
|
+ remove_index(old_index);
|
|
|
+ _name_index.erase(ni);
|
|
|
+ }
|
|
|
+
|
|
|
+ int slot;
|
|
|
+
|
|
|
+ if (_first_slot >= (int)_intervals.size()) {
|
|
|
+ // All the slots are filled; make a new slot.
|
|
|
+ nassertr(_first_slot == (int)_intervals.size(), -1);
|
|
|
+ slot = (int)_intervals.size();
|
|
|
+ _intervals.push_back(IntervalDef());
|
|
|
+ _first_slot = (int)_intervals.size();
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // Some slot is available; use it.
|
|
|
+ slot = _first_slot;
|
|
|
+ nassertr(slot >= 0 && slot < (int)_intervals.size(), -1);
|
|
|
+ _first_slot = _intervals[slot]._next_slot;
|
|
|
+ }
|
|
|
+
|
|
|
+ IntervalDef &def = _intervals[slot];
|
|
|
+ def._interval = interval;
|
|
|
+ def._flags = 0;
|
|
|
+ if (external) {
|
|
|
+ def._flags |= F_external;
|
|
|
+ }
|
|
|
+ if (interval->is_of_type(CMetaInterval::get_class_type())) {
|
|
|
+ def._flags |= F_meta_interval;
|
|
|
+ }
|
|
|
+ def._next_slot = -1;
|
|
|
+
|
|
|
+ _name_index[interval->get_name()] = slot;
|
|
|
+ nassertr(_first_slot >= 0, slot);
|
|
|
+ return slot;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::find_c_interval
|
|
|
+// Access: Published
|
|
|
+// Description: Returns the index associated with the named interval,
|
|
|
+// if there is such an interval, or -1 if there is not.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int CIntervalManager::
|
|
|
+find_c_interval(const string &name) const {
|
|
|
+ NameIndex::const_iterator ni = _name_index.find(name);
|
|
|
+ if (ni != _name_index.end()) {
|
|
|
+ return (*ni).second;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::get_c_interval
|
|
|
+// Access: Published
|
|
|
+// Description: Returns the interval associated with the given index.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CInterval *CIntervalManager::
|
|
|
+get_c_interval(int index) const {
|
|
|
+ nassertr(index >= 0 && index < (int)_intervals.size(), NULL);
|
|
|
+ return _intervals[index]._interval;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::remove_c_interval
|
|
|
+// Access: Published
|
|
|
+// Description: Removes the indicated interval from the queue
|
|
|
+// immediately. It will not be returned from
|
|
|
+// get_next_removal(), and none of its pending events,
|
|
|
+// if any, will be returned by get_next_event().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void CIntervalManager::
|
|
|
+remove_c_interval(int index) {
|
|
|
+ nassertv(index >= 0 && index < (int)_intervals.size());
|
|
|
+ IntervalDef &def = _intervals[index];
|
|
|
+ nassertv(def._interval != (CInterval *)NULL);
|
|
|
+
|
|
|
+ NameIndex::iterator ni = _name_index.find(def._interval->get_name());
|
|
|
+ nassertv(ni != _name_index.end());
|
|
|
+ nassertv((*ni).second == index);
|
|
|
+ _name_index.erase(ni);
|
|
|
+
|
|
|
+ def._interval = (CInterval *)NULL;
|
|
|
+ def._next_slot = _first_slot;
|
|
|
+ _first_slot = index;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::pause_all_interruptible
|
|
|
+// 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.
|
|
|
+//
|
|
|
+// Returns the number of intervals affected.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int CIntervalManager::
|
|
|
+pause_all_interruptible() {
|
|
|
+ int num_paused = 0;
|
|
|
+
|
|
|
+ NameIndex::iterator ni;
|
|
|
+ ni = _name_index.begin();
|
|
|
+ while (ni != _name_index.end()) {
|
|
|
+ int index = (*ni).second;
|
|
|
+ const IntervalDef &def = _intervals[index];
|
|
|
+ nassertr(def._interval != (CInterval *)NULL, num_paused);
|
|
|
+ if (!def._interval->get_interruptible()) {
|
|
|
+ // This interval may be interrupted.
|
|
|
+ if (def._interval->get_state() == CInterval::S_started) {
|
|
|
+ def._interval->priv_interrupt();
|
|
|
+ }
|
|
|
+ NameIndex::iterator prev;
|
|
|
+ prev = ni;
|
|
|
+ ++ni;
|
|
|
+ _name_index.erase(prev);
|
|
|
+ remove_index(index);
|
|
|
+ num_paused++;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // The interval should remain on the active list.
|
|
|
+ ++ni;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return num_paused;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::get_num_intervals
|
|
|
+// Access: Published
|
|
|
+// Description: Returns the number of currently active intervals.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int CIntervalManager::
|
|
|
+get_num_intervals() const {
|
|
|
+ return _name_index.size();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::step
|
|
|
+// Access: Published
|
|
|
+// Description: This should be called every frame to do the
|
|
|
+// processing for all the active intervals. It will
|
|
|
+// call step_play() for each interval that has been
|
|
|
+// added and that has not yet been removed.
|
|
|
+//
|
|
|
+// After each call to step(), the scripting language
|
|
|
+// should call get_next_event() and get_next_removal()
|
|
|
+// repeatedly to process all the high-level
|
|
|
+// (e.g. Python-interval-based) events and to manage the
|
|
|
+// high-level list of intervals.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void CIntervalManager::
|
|
|
+step() {
|
|
|
+ NameIndex::iterator ni;
|
|
|
+ ni = _name_index.begin();
|
|
|
+ while (ni != _name_index.end()) {
|
|
|
+ int index = (*ni).second;
|
|
|
+ const IntervalDef &def = _intervals[index];
|
|
|
+ nassertv(def._interval != (CInterval *)NULL);
|
|
|
+ if (!def._interval->step_play()) {
|
|
|
+ // This interval is finished and wants to be removed from the
|
|
|
+ // active list.
|
|
|
+ NameIndex::iterator prev;
|
|
|
+ prev = ni;
|
|
|
+ ++ni;
|
|
|
+ _name_index.erase(prev);
|
|
|
+ remove_index(index);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // The interval can remain on the active list.
|
|
|
+ ++ni;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _next_event_index = 0;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::get_next_event
|
|
|
+// Access: Published
|
|
|
+// Description: This should be called by the scripting language after
|
|
|
+// each call to step(). It returns the index number of
|
|
|
+// the next interval that has events requiring servicing
|
|
|
+// by the scripting language, or -1 if no more intervals
|
|
|
+// have any events pending.
|
|
|
+//
|
|
|
+// If this function returns something other than -1, it
|
|
|
+// is the scripting language's responsibility to query
|
|
|
+// the indicated interval for its next event via
|
|
|
+// get_event_index(), and eventually pop_event().
|
|
|
+//
|
|
|
+// Then get_next_event() should be called again until it
|
|
|
+// returns -1.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int CIntervalManager::
|
|
|
+get_next_event() {
|
|
|
+ while (_next_event_index < (int)_intervals.size()) {
|
|
|
+ IntervalDef &def = _intervals[_next_event_index];
|
|
|
+ if (def._interval != (CInterval *)NULL &&
|
|
|
+ (def._flags & F_meta_interval) != 0) {
|
|
|
+ CMetaInterval *meta_interval;
|
|
|
+ DCAST_INTO_R(meta_interval, def._interval, -1);
|
|
|
+ if (meta_interval->is_event_ready()) {
|
|
|
+ nassertr((def._flags & F_external) != 0, -1);
|
|
|
+ return _next_event_index;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _next_event_index++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::get_next_removal
|
|
|
+// Access: Published
|
|
|
+// Description: This should be called by the scripting language after
|
|
|
+// each call to step(). It returns the index number of
|
|
|
+// an interval that was recently removed, or -1 if no
|
|
|
+// intervals were removed.
|
|
|
+//
|
|
|
+// If this returns something other than -1, the
|
|
|
+// scripting language should clean up its own data
|
|
|
+// structures accordingly, and then call
|
|
|
+// get_next_removal() again.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+int CIntervalManager::
|
|
|
+get_next_removal() {
|
|
|
+ if (!_removed.empty()) {
|
|
|
+ int index = _removed.back();
|
|
|
+ _removed.pop_back();
|
|
|
+
|
|
|
+ nassertr(index >= 0 && index < (int)_intervals.size(), -1);
|
|
|
+ IntervalDef &def = _intervals[index];
|
|
|
+ def._interval = (CInterval *)NULL;
|
|
|
+ def._next_slot = _first_slot;
|
|
|
+ _first_slot = index;
|
|
|
+ return index;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::output
|
|
|
+// Access: Published
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void CIntervalManager::
|
|
|
+output(ostream &out) const {
|
|
|
+ out << "CIntervalManager, " << (int)_name_index.size() << " intervals.";
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::write
|
|
|
+// Access: Published
|
|
|
+// Description:
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void CIntervalManager::
|
|
|
+write(ostream &out) const {
|
|
|
+ NameIndex::const_iterator ni;
|
|
|
+ for (ni = _name_index.begin(); ni != _name_index.end(); ++ni) {
|
|
|
+ int index = (*ni).second;
|
|
|
+ nassertv(index >= 0 && index < (int)_intervals.size());
|
|
|
+ const IntervalDef &def = _intervals[index];
|
|
|
+ nassertv(def._interval != (CInterval *)NULL);
|
|
|
+ out << *def._interval << "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!_removed.empty()) {
|
|
|
+ out << "\nRemoved:\n";
|
|
|
+ Removed::const_iterator ri;
|
|
|
+ for (ri = _removed.begin(); ri != _removed.end(); ++ri) {
|
|
|
+ int index = (*ri);
|
|
|
+ nassertv(index >= 0 && index < (int)_intervals.size());
|
|
|
+ const IntervalDef &def = _intervals[index];
|
|
|
+ nassertv(def._interval != (CInterval *)NULL);
|
|
|
+ out << "(R)" << *def._interval << "\n";
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::get_global_ptr
|
|
|
+// Access: Published, Static
|
|
|
+// Description: Returns the pointer to the one global
|
|
|
+// CIntervalManager object.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+CIntervalManager *CIntervalManager::
|
|
|
+get_global_ptr() {
|
|
|
+ if (_global_ptr == (CIntervalManager *)NULL) {
|
|
|
+ _global_ptr = new CIntervalManager;
|
|
|
+ }
|
|
|
+ return _global_ptr;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::finish_interval
|
|
|
+// Access: Private
|
|
|
+// Description: Explicitly finishes the indicated interval in
|
|
|
+// preparation for moving it to the removed queue.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void CIntervalManager::
|
|
|
+finish_interval(CInterval *interval) {
|
|
|
+ switch (interval->get_state()) {
|
|
|
+ case CInterval::S_initial:
|
|
|
+ interval->priv_instant();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case CInterval::S_final:
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ interval->priv_finalize();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: CIntervalManager::remove_index
|
|
|
+// Access: Private
|
|
|
+// Description: Removes the indicated index number from the active
|
|
|
+// list, either by moving it to the removed queue if it
|
|
|
+// is flagged external, or by simply making the slot
|
|
|
+// available again if it is not.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void CIntervalManager::
|
|
|
+remove_index(int index) {
|
|
|
+ nassertv(index >= 0 && index < (int)_intervals.size());
|
|
|
+ IntervalDef &def = _intervals[index];
|
|
|
+ if ((def._flags & F_external) != 0) {
|
|
|
+ _removed.push_back(index);
|
|
|
+ } else {
|
|
|
+ def._interval = (CInterval *)NULL;
|
|
|
+ def._next_slot = _first_slot;
|
|
|
+ _first_slot = index;
|
|
|
+ }
|
|
|
+}
|