Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

direct/src/interval/cIntervalManager.cxx

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

Generated on Fri May 2 01:37:39 2003 for Direct by doxygen1.3