Panda3D
|
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 }