Panda3D

cIntervalManager.cxx

00001 // Filename: cIntervalManager.cxx
00002 // Created by:  drose (10Sep02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "cIntervalManager.h"
00016 #include "cMetaInterval.h"
00017 #include "dcast.h"
00018 #include "eventQueue.h"
00019 #include "mutexHolder.h"
00020 
00021 CIntervalManager *CIntervalManager::_global_ptr;
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: CIntervalManager::Constructor
00025 //       Access: Published
00026 //  Description: 
00027 ////////////////////////////////////////////////////////////////////
00028 CIntervalManager::
00029 CIntervalManager() {
00030   _first_slot = 0;
00031   _next_event_index = 0;
00032   _event_queue = EventQueue::get_global_event_queue();
00033 }
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: CIntervalManager::Destructor
00037 //       Access: Published
00038 //  Description: 
00039 ////////////////////////////////////////////////////////////////////
00040 CIntervalManager::
00041 ~CIntervalManager() {
00042   nassertv(_name_index.empty());
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: CIntervalManager::add_c_interval
00047 //       Access: Published
00048 //  Description: Adds the interval to the manager, and returns a
00049 //               unique index for the interval.  This index will be
00050 //               unique among all the currently added intervals, but
00051 //               not unique across all intervals ever added to the
00052 //               manager.  The maximum index value will never exceed
00053 //               the maximum number of intervals added at any given
00054 //               time.
00055 //
00056 //               If the external flag is true, the interval is
00057 //               understood to also be stored in the scripting
00058 //               language data structures.  In this case, it will be
00059 //               available for information returned by
00060 //               get_next_event() and get_next_removal().  If external
00061 //               is false, the interval's index will never be returned
00062 //               by these two functions.
00063 ////////////////////////////////////////////////////////////////////
00064 int CIntervalManager::
00065 add_c_interval(CInterval *interval, bool external) {
00066   MutexHolder holder(_lock);
00067 
00068   // First, check the name index.  If we already have an interval by
00069   // this name, it gets finished and removed.
00070   NameIndex::iterator ni = _name_index.find(interval->get_name());
00071   if (ni != _name_index.end()) {
00072     int old_index = (*ni).second;
00073     nassertr(old_index >= 0 && old_index < (int)_intervals.size(), -1)
00074     CInterval *old_interval = _intervals[old_index]._interval;
00075     if (old_interval == interval) {
00076       // No, it's the same interval that was already here.  In this
00077       // case, don't finish the interval; just return it.
00078       return old_index;
00079     }
00080     finish_interval(old_interval);
00081     remove_index(old_index);
00082     _name_index.erase(ni);
00083   }
00084 
00085   int slot;
00086 
00087   if (_first_slot >= (int)_intervals.size()) {
00088     // All the slots are filled; make a new slot.
00089     nassertr(_first_slot == (int)_intervals.size(), -1);
00090     slot = (int)_intervals.size();
00091     _intervals.push_back(IntervalDef());
00092     _first_slot = (int)_intervals.size();
00093 
00094   } else {
00095     // Some slot is available; use it.
00096     slot = _first_slot;
00097     nassertr(slot >= 0 && slot < (int)_intervals.size(), -1);
00098     _first_slot = _intervals[slot]._next_slot;
00099   }
00100 
00101   IntervalDef &def = _intervals[slot];
00102   def._interval = interval;
00103   def._flags = 0;
00104   if (external) {
00105     def._flags |= F_external;
00106   }
00107   if (interval->is_of_type(CMetaInterval::get_class_type())) {
00108     def._flags |= F_meta_interval;
00109   }
00110   def._next_slot = -1;
00111     
00112   _name_index[interval->get_name()] = slot;
00113   nassertr(_first_slot >= 0, slot);
00114   return slot;
00115 }
00116 
00117 ////////////////////////////////////////////////////////////////////
00118 //     Function: CIntervalManager::find_c_interval
00119 //       Access: Published
00120 //  Description: Returns the index associated with the named interval,
00121 //               if there is such an interval, or -1 if there is not.
00122 ////////////////////////////////////////////////////////////////////
00123 int CIntervalManager::
00124 find_c_interval(const string &name) const {
00125   MutexHolder holder(_lock);
00126 
00127   NameIndex::const_iterator ni = _name_index.find(name);
00128   if (ni != _name_index.end()) {
00129     return (*ni).second;
00130   }
00131   return -1;
00132 }
00133 
00134 ////////////////////////////////////////////////////////////////////
00135 //     Function: CIntervalManager::get_c_interval
00136 //       Access: Published
00137 //  Description: Returns the interval associated with the given index.
00138 ////////////////////////////////////////////////////////////////////
00139 CInterval *CIntervalManager::
00140 get_c_interval(int index) const {
00141   MutexHolder holder(_lock);
00142 
00143   nassertr(index >= 0 && index < (int)_intervals.size(), NULL);
00144   return _intervals[index]._interval;
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: CIntervalManager::remove_c_interval
00149 //       Access: Published
00150 //  Description: Removes the indicated interval from the queue
00151 //               immediately.  It will not be returned from
00152 //               get_next_removal(), and none of its pending events,
00153 //               if any, will be returned by get_next_event().
00154 ////////////////////////////////////////////////////////////////////
00155 void CIntervalManager::
00156 remove_c_interval(int index) {
00157   MutexHolder holder(_lock);
00158 
00159   nassertv(index >= 0 && index < (int)_intervals.size());
00160   IntervalDef &def = _intervals[index];
00161   nassertv(def._interval != (CInterval *)NULL);
00162 
00163   NameIndex::iterator ni = _name_index.find(def._interval->get_name());
00164   nassertv(ni != _name_index.end());
00165   nassertv((*ni).second == index);
00166   _name_index.erase(ni);
00167 
00168   def._interval = (CInterval *)NULL;
00169   def._next_slot = _first_slot;
00170   _first_slot = index;
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: CIntervalManager::interrupt
00175 //       Access: Published
00176 //  Description: Pauses or finishes (removes from the active queue)
00177 //               all intervals tagged with auto_pause or auto_finish
00178 //               set to true.  These are intervals that someone fired
00179 //               up but won't necessarily expect to clean up; they can
00180 //               be interrupted at will when necessary.
00181 //
00182 //               Returns the number of intervals affected.
00183 ////////////////////////////////////////////////////////////////////
00184 int CIntervalManager::
00185 interrupt() {
00186   MutexHolder holder(_lock);
00187 
00188   int num_paused = 0;
00189 
00190   NameIndex::iterator ni;
00191   ni = _name_index.begin();
00192   while (ni != _name_index.end()) {
00193     int index = (*ni).second;
00194     const IntervalDef &def = _intervals[index];
00195     nassertr(def._interval != (CInterval *)NULL, num_paused);
00196     if (def._interval->get_auto_pause() || def._interval->get_auto_finish()) {
00197       // This interval may be interrupted.
00198       if (def._interval->get_auto_pause()) {
00199         // It may be interrupted simply by pausing it.
00200         if (interval_cat.is_debug()) {
00201           interval_cat.debug()
00202             << "Auto-pausing " << def._interval->get_name() << "\n";
00203         }
00204         if (def._interval->get_state() == CInterval::S_started) {
00205           def._interval->priv_interrupt();
00206         }
00207 
00208       } else {
00209         // It should be interrupted by finishing it.
00210         if (interval_cat.is_debug()) {
00211           interval_cat.debug()
00212             << "Auto-finishing " << def._interval->get_name() << "\n";
00213         }
00214         switch (def._interval->get_state()) {
00215         case CInterval::S_initial:
00216           def._interval->priv_instant();
00217           break;
00218           
00219         case CInterval::S_final:
00220           break;
00221           
00222         default:
00223           def._interval->priv_finalize();
00224         }
00225       }
00226 
00227       // Now carefully remove it from the active list.
00228       NameIndex::iterator prev;
00229       prev = ni;
00230       ++ni;
00231       _name_index.erase(prev);
00232       remove_index(index);
00233       num_paused++;
00234 
00235     } else {
00236       // The interval should remain on the active list.
00237       ++ni;
00238     }
00239   }
00240 
00241   return num_paused;
00242 }
00243 
00244 ////////////////////////////////////////////////////////////////////
00245 //     Function: CIntervalManager::get_num_intervals
00246 //       Access: Published
00247 //  Description: Returns the number of currently active intervals.
00248 ////////////////////////////////////////////////////////////////////
00249 int CIntervalManager::
00250 get_num_intervals() const {
00251   MutexHolder holder(_lock);
00252 
00253   return _name_index.size();
00254 }
00255 
00256 ////////////////////////////////////////////////////////////////////
00257 //     Function: CIntervalManager::get_max_index
00258 //       Access: Published
00259 //  Description: Returns one more than the largest interval index
00260 //               number in the manager.  If you walk through all the
00261 //               values between (0, get_max_index()] and call
00262 //               get_c_interval() on each number, you will retrieve
00263 //               all of the managed intervals (and possibly a number
00264 //               of NULL pointers as well).
00265 ////////////////////////////////////////////////////////////////////
00266 int CIntervalManager::
00267 get_max_index() const {
00268   MutexHolder holder(_lock);
00269 
00270   return _intervals.size();
00271 }
00272 
00273 ////////////////////////////////////////////////////////////////////
00274 //     Function: CIntervalManager::step
00275 //       Access: Published
00276 //  Description: This should be called every frame to do the
00277 //               processing for all the active intervals.  It will
00278 //               call step_play() for each interval that has been
00279 //               added and that has not yet been removed.
00280 //
00281 //               After each call to step(), the scripting language
00282 //               should call get_next_event() and get_next_removal()
00283 //               repeatedly to process all the high-level
00284 //               (e.g. Python-interval-based) events and to manage the
00285 //               high-level list of intervals.
00286 ////////////////////////////////////////////////////////////////////
00287 void CIntervalManager::
00288 step() {
00289   MutexHolder holder(_lock);
00290 
00291   NameIndex::iterator ni;
00292   ni = _name_index.begin();
00293   while (ni != _name_index.end()) {
00294     int index = (*ni).second;
00295     const IntervalDef &def = _intervals[index];
00296     nassertv(def._interval != (CInterval *)NULL);
00297     if (!def._interval->step_play()) {
00298       // This interval is finished and wants to be removed from the
00299       // active list.
00300       NameIndex::iterator prev;
00301       prev = ni;
00302       ++ni;
00303       _name_index.erase(prev);
00304       remove_index(index);
00305 
00306     } else {
00307       // The interval can remain on the active list.
00308       ++ni;
00309     }
00310   }
00311 
00312   _next_event_index = 0;
00313 }
00314 
00315 ////////////////////////////////////////////////////////////////////
00316 //     Function: CIntervalManager::get_next_event
00317 //       Access: Published
00318 //  Description: This should be called by the scripting language after
00319 //               each call to step().  It returns the index number of
00320 //               the next interval that has events requiring servicing
00321 //               by the scripting language, or -1 if no more intervals
00322 //               have any events pending.
00323 //
00324 //               If this function returns something other than -1, it
00325 //               is the scripting language's responsibility to query
00326 //               the indicated interval for its next event via
00327 //               get_event_index(), and eventually pop_event().
00328 //
00329 //               Then get_next_event() should be called again until it
00330 //               returns -1.
00331 ////////////////////////////////////////////////////////////////////
00332 int CIntervalManager::
00333 get_next_event() {
00334   MutexHolder holder(_lock);
00335 
00336   while (_next_event_index < (int)_intervals.size()) {
00337     IntervalDef &def = _intervals[_next_event_index];
00338     if (def._interval != (CInterval *)NULL) {
00339       if ((def._flags & F_external) != 0 && 
00340           def._interval->check_t_callback()) {
00341         return _next_event_index;
00342       }
00343       if ((def._flags & F_meta_interval) != 0) {
00344         CMetaInterval *meta_interval;
00345         DCAST_INTO_R(meta_interval, def._interval, -1);
00346         if (meta_interval->is_event_ready()) {
00347           nassertr((def._flags & F_external) != 0, -1);
00348           return _next_event_index;
00349         }
00350       }
00351     }
00352     _next_event_index++;
00353   }
00354 
00355   return -1;
00356 }
00357 
00358 ////////////////////////////////////////////////////////////////////
00359 //     Function: CIntervalManager::get_next_removal
00360 //       Access: Published
00361 //  Description: This should be called by the scripting language after
00362 //               each call to step().  It returns the index number of
00363 //               an interval that was recently removed, or -1 if no
00364 //               intervals were removed.
00365 //
00366 //               If this returns something other than -1, the
00367 //               scripting language should clean up its own data
00368 //               structures accordingly, and then call
00369 //               get_next_removal() again.
00370 ////////////////////////////////////////////////////////////////////
00371 int CIntervalManager::
00372 get_next_removal() {
00373   MutexHolder holder(_lock);
00374 
00375   if (!_removed.empty()) {
00376     int index = _removed.back();
00377     _removed.pop_back();
00378 
00379     nassertr(index >= 0 && index < (int)_intervals.size(), -1);
00380     IntervalDef &def = _intervals[index];
00381     def._interval = (CInterval *)NULL;
00382     def._next_slot = _first_slot;
00383     _first_slot = index;
00384     return index;
00385   }
00386 
00387   return -1;
00388 }
00389 
00390 ////////////////////////////////////////////////////////////////////
00391 //     Function: CIntervalManager::output
00392 //       Access: Published
00393 //  Description: 
00394 ////////////////////////////////////////////////////////////////////
00395 void CIntervalManager::
00396 output(ostream &out) const {
00397   MutexHolder holder(_lock);
00398 
00399   out << "CIntervalManager, " << (int)_name_index.size() << " intervals.";
00400 }
00401 
00402 ////////////////////////////////////////////////////////////////////
00403 //     Function: CIntervalManager::write
00404 //       Access: Published
00405 //  Description: 
00406 ////////////////////////////////////////////////////////////////////
00407 void CIntervalManager::
00408 write(ostream &out) const {
00409   MutexHolder holder(_lock);
00410 
00411   // We need to write this line so that it's clear what's going on
00412   // when there are no intervals in the list.
00413   out << (int)_name_index.size() << " intervals.\n";
00414 
00415   NameIndex::const_iterator ni;
00416   for (ni = _name_index.begin(); ni != _name_index.end(); ++ni) {
00417     int index = (*ni).second;
00418     nassertv(index >= 0 && index < (int)_intervals.size());
00419     const IntervalDef &def = _intervals[index];
00420     nassertv(def._interval != (CInterval *)NULL);
00421     out << *def._interval << "\n";
00422   }
00423 
00424   if (!_removed.empty()) {
00425     out << "\nRemoved:\n";
00426     Removed::const_iterator ri;
00427     for (ri = _removed.begin(); ri != _removed.end(); ++ri) {
00428       int index = (*ri);
00429       nassertv(index >= 0 && index < (int)_intervals.size());
00430       const IntervalDef &def = _intervals[index];
00431       nassertv(def._interval != (CInterval *)NULL);
00432       out << "(R)" << *def._interval << "\n";
00433     }
00434   }
00435 }
00436 
00437 ////////////////////////////////////////////////////////////////////
00438 //     Function: CIntervalManager::get_global_ptr
00439 //       Access: Published, Static
00440 //  Description: Returns the pointer to the one global
00441 //               CIntervalManager object.
00442 ////////////////////////////////////////////////////////////////////
00443 CIntervalManager *CIntervalManager::
00444 get_global_ptr() {
00445   if (_global_ptr == (CIntervalManager *)NULL) {
00446     _global_ptr = new CIntervalManager;
00447   }
00448   return _global_ptr;
00449 }
00450 
00451 ////////////////////////////////////////////////////////////////////
00452 //     Function: CIntervalManager::finish_interval
00453 //       Access: Private
00454 //  Description: Explicitly finishes the indicated interval in
00455 //               preparation for moving it to the removed queue.
00456 ////////////////////////////////////////////////////////////////////
00457 void CIntervalManager::
00458 finish_interval(CInterval *interval) {
00459   switch (interval->get_state()) {
00460   case CInterval::S_initial:
00461     interval->priv_instant();
00462     break;
00463 
00464   case CInterval::S_final:
00465     break;
00466 
00467   default:
00468     interval->priv_finalize();
00469   }
00470 }
00471 
00472 ////////////////////////////////////////////////////////////////////
00473 //     Function: CIntervalManager::remove_index
00474 //       Access: Private
00475 //  Description: Removes the indicated index number from the active
00476 //               list, either by moving it to the removed queue if it
00477 //               is flagged external, or by simply making the slot
00478 //               available again if it is not.  Assumes the lock is
00479 //               already held.
00480 ////////////////////////////////////////////////////////////////////
00481 void CIntervalManager::
00482 remove_index(int index) {
00483   nassertv(_lock.debug_is_locked());
00484   nassertv(index >= 0 && index < (int)_intervals.size());
00485   IntervalDef &def = _intervals[index];
00486   if ((def._flags & F_external) != 0) {
00487     _removed.push_back(index);
00488   } else {
00489     def._interval = (CInterval *)NULL;
00490     def._next_slot = _first_slot;
00491     _first_slot = index;
00492   }    
00493 }
 All Classes Functions Variables Enumerations