Panda3D
|
00001 // Filename: cMetaInterval.cxx 00002 // Created by: drose (27Aug02) 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 "cMetaInterval.h" 00016 #include "waitInterval.h" 00017 #include "config_interval.h" 00018 #include "indirectLess.h" 00019 #include "indent.h" 00020 00021 #include <algorithm> 00022 #include <math.h> // for log10() 00023 #include <stdio.h> // for sprintf() 00024 00025 TypeHandle CMetaInterval::_type_handle; 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: CMetaInterval::Constructor 00029 // Access: Published 00030 // Description: 00031 //////////////////////////////////////////////////////////////////// 00032 CMetaInterval:: 00033 CMetaInterval(const string &name) : 00034 CInterval(name, 0.0, true) 00035 { 00036 _precision = interval_precision; 00037 _current_nesting_level = 0; 00038 _next_event_index = 0; 00039 _processing_events = false; 00040 } 00041 00042 //////////////////////////////////////////////////////////////////// 00043 // Function: CMetaInterval::Destructor 00044 // Access: Published, Virtual 00045 // Description: 00046 //////////////////////////////////////////////////////////////////// 00047 CMetaInterval:: 00048 ~CMetaInterval() { 00049 clear_intervals(); 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: CMetaInterval::clear_intervals 00054 // Access: Published 00055 // Description: Resets the list of intervals and prepares for 00056 // receiving a new list. 00057 //////////////////////////////////////////////////////////////////// 00058 void CMetaInterval:: 00059 clear_intervals() { 00060 // Better not do this unless you have serviced all of the 00061 // outstanding events! 00062 bool lost_events = false; 00063 if (!_event_queue.empty()) { 00064 interval_cat.warning() 00065 << "Losing outstanding events for " << *this << "\n"; 00066 _event_queue.clear(); 00067 lost_events = true; 00068 } 00069 00070 clear_events(); 00071 00072 // Go through all of our nested intervals and remove ourselves as 00073 // their parent. 00074 Defs::iterator di; 00075 for (di = _defs.begin(); di != _defs.end(); ++di) { 00076 IntervalDef &def = (*di); 00077 if (def._c_interval != (CInterval *)NULL) { 00078 CInterval::Parents::iterator pi = 00079 find(def._c_interval->_parents.begin(), 00080 def._c_interval->_parents.end(), 00081 this); 00082 nassertv(pi != def._c_interval->_parents.end()); 00083 def._c_interval->_parents.erase(pi); 00084 } 00085 } 00086 _defs.clear(); 00087 00088 _current_nesting_level = 0; 00089 _next_event_index = 0; 00090 00091 #ifndef NDEBUG 00092 if (verify_intervals) { 00093 nassertv(!lost_events); 00094 } 00095 #endif 00096 } 00097 00098 //////////////////////////////////////////////////////////////////// 00099 // Function: CMetaInterval::push_level 00100 // Access: Published 00101 // Description: Marks the beginning of a nested level of child 00102 // intervals. Within the nested level, a RelativeStart 00103 // time of RS_level_begin refers to the start of the 00104 // level, and the first interval added within the level 00105 // is always relative to the start of the level. 00106 // 00107 // The return value is the index of the def entry 00108 // created by this push. 00109 //////////////////////////////////////////////////////////////////// 00110 int CMetaInterval:: 00111 push_level(const string &name, double rel_time, RelativeStart rel_to) { 00112 nassertr(_event_queue.empty() && !_processing_events, -1); 00113 00114 _defs.push_back(IntervalDef()); 00115 IntervalDef &def = _defs.back(); 00116 def._type = DT_push_level; 00117 def._ext_name = name; 00118 def._rel_time = rel_time; 00119 def._rel_to = rel_to; 00120 _current_nesting_level++; 00121 mark_dirty(); 00122 00123 return (int)_defs.size() - 1; 00124 } 00125 00126 //////////////////////////////////////////////////////////////////// 00127 // Function: CMetaInterval::add_c_interval 00128 // Access: Published 00129 // Description: Adds a new CInterval to the list. The interval will 00130 // be played when the indicated time (relative to the 00131 // given point) has been reached. 00132 // 00133 // The return value is the index of the def entry 00134 // representing the new interval. 00135 //////////////////////////////////////////////////////////////////// 00136 int CMetaInterval:: 00137 add_c_interval(CInterval *c_interval, 00138 double rel_time, RelativeStart rel_to) { 00139 nassertr(_event_queue.empty() && !_processing_events, -1); 00140 nassertr(c_interval != (CInterval *)NULL, -1); 00141 00142 c_interval->_parents.push_back(this); 00143 c_interval->_ival_pcollector = PStatCollector(_ival_pcollector, c_interval->_pname); 00144 _defs.push_back(IntervalDef()); 00145 IntervalDef &def = _defs.back(); 00146 def._type = DT_c_interval; 00147 def._c_interval = c_interval; 00148 def._rel_time = rel_time; 00149 def._rel_to = rel_to; 00150 mark_dirty(); 00151 00152 return (int)_defs.size() - 1; 00153 } 00154 00155 //////////////////////////////////////////////////////////////////// 00156 // Function: CMetaInterval::add_ext_index 00157 // Access: Published 00158 // Description: Adds a new external interval to the list. This 00159 // represents some object in the external scripting 00160 // language that has properties similar to a CInterval 00161 // (for instance, a Python Interval object). 00162 // 00163 // The CMetaInterval object cannot play this external 00164 // interval directly, but it records a placeholder for 00165 // it and will ask the scripting language to play it 00166 // when it is time, via is_event_ready() and related 00167 // methods. 00168 // 00169 // The ext_index number itself is simply a handle that 00170 // the scripting language makes up and associates with 00171 // its interval object somehow. The CMetaInterval 00172 // object does not attempt to interpret this value. 00173 // 00174 // The return value is the index of the def entry 00175 // representing the new interval. 00176 //////////////////////////////////////////////////////////////////// 00177 int CMetaInterval:: 00178 add_ext_index(int ext_index, const string &name, double duration, 00179 bool open_ended, 00180 double rel_time, RelativeStart rel_to) { 00181 nassertr(_event_queue.empty() && !_processing_events, -1); 00182 00183 _defs.push_back(IntervalDef()); 00184 IntervalDef &def = _defs.back(); 00185 def._type = DT_ext_index; 00186 def._ext_index = ext_index; 00187 def._ext_name = name; 00188 def._ext_duration = duration; 00189 def._ext_open_ended = open_ended; 00190 def._rel_time = rel_time; 00191 def._rel_to = rel_to; 00192 mark_dirty(); 00193 00194 return (int)_defs.size() - 1; 00195 } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: CMetaInterval::pop_level 00199 // Access: Published 00200 // Description: Finishes a level marked by a previous call to 00201 // push_level(), and returns to the previous level. 00202 // 00203 // If the duration is not negative, it represents a 00204 // phony duration to assign to the level, for the 00205 // purposes of sequencing later intervals. Otherwise, 00206 // the level's duration is computed based on the 00207 // intervals within the level. 00208 //////////////////////////////////////////////////////////////////// 00209 int CMetaInterval:: 00210 pop_level(double duration) { 00211 nassertr(_event_queue.empty() && !_processing_events, -1); 00212 nassertr(_current_nesting_level > 0, -1); 00213 00214 _defs.push_back(IntervalDef()); 00215 IntervalDef &def = _defs.back(); 00216 def._type = DT_pop_level; 00217 def._ext_duration = duration; 00218 _current_nesting_level--; 00219 mark_dirty(); 00220 00221 return (int)_defs.size() - 1; 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: CMetaInterval::set_interval_start_time 00226 // Access: Published 00227 // Description: Adjusts the start time of the child interval with the 00228 // given name, if found. This may be either a C++ 00229 // interval added via add_c_interval(), or an external 00230 // interval added via add_ext_index(); the name must 00231 // match exactly. 00232 // 00233 // If the interval is found, its start time is adjusted, 00234 // and all subsequent intervals are adjusting 00235 // accordingly, and true is returned. If a matching 00236 // interval is not found, nothing is changed and false 00237 // is returned. 00238 //////////////////////////////////////////////////////////////////// 00239 bool CMetaInterval:: 00240 set_interval_start_time(const string &name, double rel_time, 00241 CMetaInterval::RelativeStart rel_to) { 00242 nassertr(_event_queue.empty() && !_processing_events, false); 00243 Defs::iterator di; 00244 for (di = _defs.begin(); di != _defs.end(); ++di) { 00245 IntervalDef &def = (*di); 00246 00247 bool match = false; 00248 switch (def._type) { 00249 case DT_c_interval: 00250 match = (def._c_interval->get_name() == name); 00251 break; 00252 00253 case DT_ext_index: 00254 match = (def._ext_name == name); 00255 break; 00256 00257 default: 00258 break; 00259 } 00260 if (match) { 00261 // Here's the interval. 00262 def._rel_time = rel_time; 00263 def._rel_to = rel_to; 00264 mark_dirty(); 00265 return true; 00266 } 00267 } 00268 00269 return false; 00270 } 00271 00272 //////////////////////////////////////////////////////////////////// 00273 // Function: CMetaInterval::get_interval_start_time 00274 // Access: Published 00275 // Description: Returns the actual start time, relative to the 00276 // beginning of the interval, of the child interval with 00277 // the given name, if found, or -1 if the interval is 00278 // not found. 00279 //////////////////////////////////////////////////////////////////// 00280 double CMetaInterval:: 00281 get_interval_start_time(const string &name) const { 00282 recompute(); 00283 Defs::const_iterator di; 00284 for (di = _defs.begin(); di != _defs.end(); ++di) { 00285 const IntervalDef &def = (*di); 00286 00287 bool match = false; 00288 switch (def._type) { 00289 case DT_c_interval: 00290 match = (def._c_interval->get_name() == name); 00291 break; 00292 00293 case DT_ext_index: 00294 match = (def._ext_name == name); 00295 break; 00296 00297 default: 00298 break; 00299 } 00300 if (match) { 00301 // Here's the interval. 00302 return int_to_double_time(def._actual_begin_time); 00303 } 00304 } 00305 00306 return -1.0; 00307 } 00308 00309 //////////////////////////////////////////////////////////////////// 00310 // Function: CMetaInterval::get_interval_end_time 00311 // Access: Published 00312 // Description: Returns the actual end time, relative to the 00313 // beginning of the interval, of the child interval with 00314 // the given name, if found, or -1 if the interval is 00315 // not found. 00316 //////////////////////////////////////////////////////////////////// 00317 double CMetaInterval:: 00318 get_interval_end_time(const string &name) const { 00319 recompute(); 00320 Defs::const_iterator di; 00321 for (di = _defs.begin(); di != _defs.end(); ++di) { 00322 const IntervalDef &def = (*di); 00323 00324 bool match = false; 00325 double duration = 0.0; 00326 switch (def._type) { 00327 case DT_c_interval: 00328 duration = def._c_interval->get_duration(); 00329 match = (def._c_interval->get_name() == name); 00330 break; 00331 00332 case DT_ext_index: 00333 duration = def._ext_duration; 00334 match = (def._ext_name == name); 00335 break; 00336 00337 default: 00338 break; 00339 } 00340 if (match) { 00341 // Here's the interval. 00342 return int_to_double_time(def._actual_begin_time) + duration; 00343 } 00344 } 00345 00346 return -1.0; 00347 } 00348 00349 //////////////////////////////////////////////////////////////////// 00350 // Function: CMetaInterval::initialize 00351 // Access: Published, Virtual 00352 // Description: This replaces the first call to priv_step(), and indicates 00353 // that the interval has just begun. This may be 00354 // overridden by derived classes that need to do some 00355 // explicit initialization on the first call. 00356 //////////////////////////////////////////////////////////////////// 00357 void CMetaInterval:: 00358 priv_initialize(double t) { 00359 if (_processing_events) { 00360 enqueue_self_event(ET_initialize, t); 00361 return; 00362 } 00363 00364 check_stopped(get_class_type(), "priv_initialize"); 00365 // It may be tempting to flush the event_queue here, but don't do 00366 // it. Those are events that must still be serviced from some 00367 // previous interval operation. Throwing them away would be a 00368 // mistake. 00369 00370 recompute(); 00371 _next_event_index = 0; 00372 _active.clear(); 00373 00374 int now = double_to_int_time(t); 00375 00376 /* 00377 // One special case: if we step to t == 0.0, it really means to the 00378 // very beginning of the interval, *before* any events that occurred 00379 // at time 0. (Most of the time, stepping to a particular time 00380 // means *after* any events that occurred at that time.) 00381 if (t == 0.0) { 00382 now = -1; 00383 } 00384 */ 00385 00386 // Now look for events from the beginning up to the current time. 00387 _processing_events = true; 00388 ActiveEvents new_active; 00389 while (_next_event_index < _events.size() && 00390 _events[_next_event_index]->_time <= now) { 00391 PlaybackEvent *event = _events[_next_event_index]; 00392 _next_event_index++; 00393 00394 // Do the indicated event. 00395 do_event_forward(event, new_active, true); 00396 } 00397 finish_events_forward(now, new_active); 00398 _processing_events = false; 00399 00400 _curr_t = t; 00401 _state = S_started; 00402 } 00403 00404 //////////////////////////////////////////////////////////////////// 00405 // Function: CMetaInterval::instant 00406 // Access: Published, Virtual 00407 // Description: This is called in lieu of priv_initialize() .. priv_step() 00408 // .. priv_finalize(), when everything is to happen within 00409 // one frame. The interval should initialize itself, 00410 // then leave itself in the final state. 00411 //////////////////////////////////////////////////////////////////// 00412 void CMetaInterval:: 00413 priv_instant() { 00414 if (_processing_events) { 00415 enqueue_self_event(ET_instant); 00416 return; 00417 } 00418 00419 check_stopped(get_class_type(), "priv_instant"); 00420 recompute(); 00421 _active.clear(); 00422 00423 // Apply all of the events. This just means we invoke "instant" for 00424 // any end or instant event, ignoring the begin events. 00425 _processing_events = true; 00426 PlaybackEvents::iterator ei; 00427 for (ei = _events.begin(); ei != _events.end(); ++ei) { 00428 PlaybackEvent *event = (*ei); 00429 if (event->_type != PET_begin) { 00430 enqueue_event(event->_n, ET_instant, true, 0); 00431 } 00432 } 00433 _processing_events = false; 00434 00435 _next_event_index = _events.size(); 00436 _curr_t = get_duration(); 00437 _state = S_final; 00438 00439 if (_event_queue.empty()) { 00440 interval_done(); 00441 } else { 00442 enqueue_done_event(); 00443 } 00444 } 00445 00446 //////////////////////////////////////////////////////////////////// 00447 // Function: CMetaInterval::step 00448 // Access: Published, Virtual 00449 // Description: Advances the time on the interval. The time may 00450 // either increase (the normal case) or decrease 00451 // (e.g. if the interval is being played by a slider). 00452 //////////////////////////////////////////////////////////////////// 00453 void CMetaInterval:: 00454 priv_step(double t) { 00455 if (_processing_events) { 00456 enqueue_self_event(ET_step, t); 00457 return; 00458 } 00459 00460 check_started(get_class_type(), "priv_step"); 00461 int now = double_to_int_time(t); 00462 00463 /* 00464 // One special case: if we step to t == 0.0, it really means to the 00465 // very beginning of the interval, *before* any events that occurred 00466 // at time 0. (Most of the time, stepping to a particular time 00467 // means *after* any events that occurred at that time.) 00468 if (t == 0.0) { 00469 now = -1; 00470 } 00471 */ 00472 00473 // Now look for events between the last time we ran and the current 00474 // time. 00475 00476 _processing_events = true; 00477 if (_next_event_index < _events.size() && 00478 _events[_next_event_index]->_time <= now) { 00479 // The normal case: time is increasing. 00480 ActiveEvents new_active; 00481 while (_next_event_index < _events.size() && 00482 _events[_next_event_index]->_time <= now) { 00483 PlaybackEvent *event = _events[_next_event_index]; 00484 _next_event_index++; 00485 00486 // Do the indicated event. 00487 do_event_forward(event, new_active, false); 00488 } 00489 00490 finish_events_forward(now, new_active); 00491 00492 } else { 00493 // A less usual case: time is decreasing. 00494 ActiveEvents new_active; 00495 while (_next_event_index > 0 && 00496 _events[_next_event_index - 1]->_time > now) { 00497 _next_event_index--; 00498 PlaybackEvent *event = _events[_next_event_index]; 00499 00500 do_event_reverse(event, new_active, false); 00501 } 00502 00503 finish_events_reverse(now, new_active); 00504 } 00505 _processing_events = false; 00506 00507 _curr_t = t; 00508 _state = S_started; 00509 } 00510 00511 //////////////////////////////////////////////////////////////////// 00512 // Function: CMetaInterval::finalize 00513 // Access: Published, Virtual 00514 // Description: This is called when an interval is interrupted. It 00515 // should advance the time as if priv_step() were called, and 00516 // also perform whatever cleanup might be required. 00517 //////////////////////////////////////////////////////////////////// 00518 void CMetaInterval:: 00519 priv_finalize() { 00520 if (_processing_events) { 00521 enqueue_self_event(ET_finalize); 00522 return; 00523 } 00524 00525 double duration = get_duration(); 00526 if (_state == S_initial) { 00527 priv_initialize(duration); 00528 } 00529 00530 // Do all remaining events. 00531 _processing_events = true; 00532 ActiveEvents new_active; 00533 while (_next_event_index < _events.size()) { 00534 PlaybackEvent *event = _events[_next_event_index]; 00535 _next_event_index++; 00536 00537 // Do the indicated event. 00538 do_event_forward(event, new_active, true); 00539 } 00540 finish_events_forward(double_to_int_time(duration), new_active); 00541 _processing_events = false; 00542 00543 _curr_t = duration; 00544 _state = S_final; 00545 00546 if (_event_queue.empty()) { 00547 interval_done(); 00548 } else { 00549 enqueue_done_event(); 00550 } 00551 } 00552 00553 //////////////////////////////////////////////////////////////////// 00554 // Function: CMetaInterval::reverse_initialize 00555 // Access: Published, Virtual 00556 // Description: Similar to priv_initialize(), but this is called when the 00557 // interval is being played backwards; it indicates that 00558 // the interval should start at the finishing state and 00559 // undo any intervening intervals. 00560 //////////////////////////////////////////////////////////////////// 00561 void CMetaInterval:: 00562 priv_reverse_initialize(double t) { 00563 if (_processing_events) { 00564 enqueue_self_event(ET_reverse_initialize, t); 00565 return; 00566 } 00567 00568 check_stopped(get_class_type(), "priv_reverse_initialize"); 00569 // It may be tempting to flush the event_queue here, but don't do 00570 // it. Those are events that must still be serviced from some 00571 // previous interval operation. Throwing them away would be a 00572 // mistake. 00573 00574 recompute(); 00575 _next_event_index = _events.size(); 00576 _active.clear(); 00577 00578 int now = double_to_int_time(t); 00579 00580 /* 00581 // One special case: if we step to t == 0.0, it really means to the 00582 // very beginning of the interval, *before* any events that occurred 00583 // at time 0. (Most of the time, stepping to a particular time 00584 // means *after* any events that occurred at that time.) 00585 if (t == 0.0) { 00586 now = -1; 00587 } 00588 */ 00589 00590 // Now look for events from the end down to the current time. 00591 _processing_events = true; 00592 ActiveEvents new_active; 00593 while (_next_event_index > 0 && 00594 _events[_next_event_index - 1]->_time > now) { 00595 _next_event_index--; 00596 PlaybackEvent *event = _events[_next_event_index]; 00597 00598 // Do the indicated event. 00599 do_event_reverse(event, new_active, true); 00600 } 00601 finish_events_reverse(now, new_active); 00602 _processing_events = false; 00603 00604 _curr_t = t; 00605 _state = S_started; 00606 } 00607 00608 //////////////////////////////////////////////////////////////////// 00609 // Function: CMetaInterval::reverse_instant 00610 // Access: Published, Virtual 00611 // Description: This is called in lieu of priv_reverse_initialize() 00612 // .. priv_step() .. priv_reverse_finalize(), when everything is 00613 // to happen within one frame. The interval should 00614 // initialize itself, then leave itself in the initial 00615 // state. 00616 //////////////////////////////////////////////////////////////////// 00617 void CMetaInterval:: 00618 priv_reverse_instant() { 00619 if (_processing_events) { 00620 enqueue_self_event(ET_reverse_instant); 00621 return; 00622 } 00623 00624 check_stopped(get_class_type(), "priv_reverse_instant"); 00625 recompute(); 00626 _active.clear(); 00627 00628 // Apply all of the events. This just means we invoke "instant" for 00629 // any end or instant event, ignoring the begin events. 00630 _processing_events = true; 00631 PlaybackEvents::reverse_iterator ei; 00632 for (ei = _events.rbegin(); ei != _events.rend(); ++ei) { 00633 PlaybackEvent *event = (*ei); 00634 if (event->_type != PET_begin) { 00635 enqueue_event(event->_n, ET_reverse_instant, true, 0); 00636 } 00637 } 00638 _processing_events = false; 00639 00640 _next_event_index = 0; 00641 _curr_t = 0.0; 00642 _state = S_initial; 00643 } 00644 00645 //////////////////////////////////////////////////////////////////// 00646 // Function: CMetaInterval::reverse_finalize 00647 // Access: Published, Virtual 00648 // Description: Called generally following a priv_reverse_initialize(), 00649 // this indicates the interval should set itself to the 00650 // initial state. 00651 //////////////////////////////////////////////////////////////////// 00652 void CMetaInterval:: 00653 priv_reverse_finalize() { 00654 if (_processing_events) { 00655 enqueue_self_event(ET_reverse_finalize); 00656 return; 00657 } 00658 00659 if (_state == S_initial) { 00660 priv_initialize(0.0); 00661 } 00662 00663 // Do all remaining events at the beginning. 00664 _processing_events = true; 00665 ActiveEvents new_active; 00666 00667 while (_next_event_index > 0) { 00668 _next_event_index--; 00669 PlaybackEvent *event = _events[_next_event_index]; 00670 00671 do_event_reverse(event, new_active, true); 00672 } 00673 finish_events_reverse(0, new_active); 00674 _processing_events = false; 00675 00676 _curr_t = 0.0; 00677 _state = S_initial; 00678 } 00679 00680 //////////////////////////////////////////////////////////////////// 00681 // Function: CMetaInterval::interrupt 00682 // Access: Published, Virtual 00683 // Description: This is called while the interval is playing to 00684 // indicate that it is about to be interrupted; that is, 00685 // priv_step() will not be called for a length of time. But 00686 // the interval should remain in its current state in 00687 // anticipation of being eventually restarted when the 00688 // calls to priv_step() eventually resume. 00689 // 00690 // The purpose of this function is to allow self-running 00691 // intervals like sound intervals to stop the actual 00692 // sound playback during the pause. 00693 //////////////////////////////////////////////////////////////////// 00694 void CMetaInterval:: 00695 priv_interrupt() { 00696 if (_processing_events) { 00697 enqueue_self_event(ET_interrupt); 00698 return; 00699 } 00700 00701 _processing_events = true; 00702 ActiveEvents::iterator ai; 00703 for (ai = _active.begin(); ai != _active.end(); ++ai) { 00704 PlaybackEvent *event = (*ai); 00705 enqueue_event(event->_n, ET_interrupt, false); 00706 } 00707 _processing_events = false; 00708 00709 if (_state == S_started) { 00710 _state = S_paused; 00711 } 00712 } 00713 00714 //////////////////////////////////////////////////////////////////// 00715 // Function: CMetaInterval::pop_event 00716 // Access: Published 00717 // Description: Acknowledges that the external interval on the top of 00718 // the queue has been extracted, and is about to be 00719 // serviced by the scripting language. This prepares 00720 // the interval so the next call to is_event_ready() 00721 // will return information about the next external 00722 // interval on the queue, if any. 00723 //////////////////////////////////////////////////////////////////// 00724 void CMetaInterval:: 00725 pop_event() { 00726 #ifndef NDEBUG 00727 nassertv(!_event_queue.empty()); 00728 const EventQueueEntry &entry = _event_queue.front(); 00729 const IntervalDef &def = _defs[entry._n]; 00730 nassertv(def._type == DT_ext_index); 00731 #endif 00732 _event_queue.pop_front(); 00733 } 00734 00735 //////////////////////////////////////////////////////////////////// 00736 // Function: CMetaInterval::write 00737 // Access: Published, Virtual 00738 // Description: 00739 //////////////////////////////////////////////////////////////////// 00740 void CMetaInterval:: 00741 write(ostream &out, int indent_level) const { 00742 recompute(); 00743 00744 // How many digits of precision should we output for time? 00745 int num_decimals = (int)ceil(log10(_precision)); 00746 int total_digits = num_decimals + 4; 00747 static const int max_digits = 32; // totally arbitrary 00748 nassertv(total_digits <= max_digits); 00749 char format_str[12]; 00750 sprintf(format_str, "%%%d.%df", total_digits, num_decimals); 00751 00752 indent(out, indent_level) << get_name() << ":\n"; 00753 00754 int extra_indent_level = 1; 00755 Defs::const_iterator di; 00756 for (di = _defs.begin(); di != _defs.end(); ++di) { 00757 const IntervalDef &def = (*di); 00758 char time_str[max_digits + 1]; 00759 sprintf(time_str, format_str, int_to_double_time(def._actual_begin_time)); 00760 indent(out, indent_level) << time_str; 00761 00762 write_event_desc(out, def, extra_indent_level); 00763 } 00764 } 00765 00766 //////////////////////////////////////////////////////////////////// 00767 // Function: CMetaInterval::timeline 00768 // Access: Published 00769 // Description: Outputs a list of all events in the order in which 00770 // they occur. 00771 //////////////////////////////////////////////////////////////////// 00772 void CMetaInterval:: 00773 timeline(ostream &out) const { 00774 recompute(); 00775 00776 // How many digits of precision should we output for time? 00777 int num_decimals = (int)ceil(log10(_precision)); 00778 int total_digits = num_decimals + 4; 00779 static const int max_digits = 32; // totally arbitrary 00780 nassertv(total_digits <= max_digits); 00781 char format_str[12]; 00782 sprintf(format_str, "%%%d.%df", total_digits, num_decimals); 00783 00784 int extra_indent_level = 0; 00785 PlaybackEvents::const_iterator ei; 00786 for (ei = _events.begin(); ei != _events.end(); ++ei) { 00787 const PlaybackEvent *event = (*ei); 00788 00789 char time_str[max_digits + 1]; 00790 sprintf(time_str, format_str, int_to_double_time(event->_time)); 00791 out << time_str; 00792 00793 switch (event->_type) { 00794 case PET_begin: 00795 out << " begin "; 00796 break; 00797 case PET_end: 00798 out << " end "; 00799 break; 00800 case PET_instant: 00801 out << " instant "; 00802 break; 00803 } 00804 00805 int n = event->_n; 00806 nassertv(n >= 0 && n < (int)_defs.size()); 00807 const IntervalDef &def = _defs[n]; 00808 00809 write_event_desc(out, def, extra_indent_level); 00810 } 00811 } 00812 00813 //////////////////////////////////////////////////////////////////// 00814 // Function: CMetaInterval::do_recompute 00815 // Access: Protected, Virtual 00816 // Description: Recomputes all of the events (and the duration) 00817 // according to the set of interval defs. 00818 //////////////////////////////////////////////////////////////////// 00819 void CMetaInterval:: 00820 do_recompute() { 00821 _dirty = false; 00822 clear_events(); 00823 00824 int n = recompute_level(0, 0, _end_time); 00825 00826 if (n != (int)_defs.size()) { 00827 interval_cat.warning() 00828 << "CMetaInterval pushes don't match pops.\n"; 00829 } 00830 00831 // We do a stable_sort() to guarantee ordering of events that have 00832 // the same start time. These must be invoked in the order in which 00833 // they appear. 00834 stable_sort(_events.begin(), _events.end(), IndirectLess<PlaybackEvent>()); 00835 _duration = int_to_double_time(_end_time); 00836 } 00837 00838 //////////////////////////////////////////////////////////////////// 00839 // Function: CMetaInterval::clear_events 00840 // Access: Private 00841 // Description: Removes all entries from the _events list. 00842 //////////////////////////////////////////////////////////////////// 00843 void CMetaInterval:: 00844 clear_events() { 00845 PlaybackEvents::iterator ei; 00846 for (ei = _events.begin(); ei != _events.end(); ++ei) { 00847 PlaybackEvent *event = (*ei); 00848 delete event; 00849 } 00850 _events.clear(); 00851 _active.clear(); 00852 } 00853 00854 //////////////////////////////////////////////////////////////////// 00855 // Function: CMetaInterval::do_event_forward 00856 // Access: Private 00857 // Description: Process a single event in the interval, moving 00858 // forwards in time. If the event represents a new 00859 // begin, adds it to the new_active list; if it is an 00860 // end, finalizes it. 00861 // 00862 // If is_initial is true, it is as if we are in 00863 // initialize or finalize: instant events will be 00864 // invoked only if they are marked open_ended. 00865 //////////////////////////////////////////////////////////////////// 00866 void CMetaInterval:: 00867 do_event_forward(CMetaInterval::PlaybackEvent *event, 00868 CMetaInterval::ActiveEvents &new_active, bool is_initial) { 00869 switch (event->_type) { 00870 case PET_begin: 00871 nassertv(event->_begin_event == event); 00872 new_active.push_back(event); 00873 break; 00874 00875 case PET_end: 00876 { 00877 // Erase the event from either the new active or the current 00878 // active lists. 00879 ActiveEvents::iterator ai; 00880 ai = find(new_active.begin(), new_active.end(), event->_begin_event); 00881 if (ai != new_active.end()) { 00882 new_active.erase(ai); 00883 // This interval was new this frame; we must invoke it as 00884 // an instant event. 00885 enqueue_event(event->_n, ET_instant, is_initial); 00886 00887 } else { 00888 ai = find(_active.begin(), _active.end(), event->_begin_event); 00889 if (ai != _active.end()) { 00890 _active.erase(ai); 00891 enqueue_event(event->_n, ET_finalize, is_initial); 00892 00893 } else { 00894 // Hmm, this event wasn't on either list. Maybe there was a 00895 // start event on the list whose time was less than 0. 00896 interval_cat.error() 00897 << "Event " << event->_begin_event->_n << " not on active list.\n"; 00898 nassertv(false); 00899 } 00900 } 00901 } 00902 break; 00903 00904 case PET_instant: 00905 nassertv(event->_begin_event == event); 00906 enqueue_event(event->_n, ET_instant, is_initial); 00907 break; 00908 } 00909 } 00910 00911 //////////////////////////////////////////////////////////////////// 00912 // Function: CMetaInterval::finish_events_forward 00913 // Access: Private 00914 // Description: After walking through the event list and adding a 00915 // bunch of new events to new_active, finished up by 00916 // calling priv_step() on all of the events still in _active 00917 // and priv_initialize() on all the events in new_active, 00918 // then copying the events from new_active to active. 00919 //////////////////////////////////////////////////////////////////// 00920 void CMetaInterval:: 00921 finish_events_forward(int now, CMetaInterval::ActiveEvents &new_active) { 00922 // Do whatever's still active. 00923 ActiveEvents::iterator ai; 00924 for (ai = _active.begin(); ai != _active.end(); ++ai) { 00925 PlaybackEvent *event = (*ai); 00926 enqueue_event(event->_n, ET_step, false, now - event->_time); 00927 } 00928 00929 // Initialize whatever new intervals we came across. 00930 for (ai = new_active.begin(); ai != new_active.end(); ++ai) { 00931 PlaybackEvent *event = (*ai); 00932 enqueue_event(event->_n, ET_initialize, false, now - event->_time); 00933 _active.push_back(event); 00934 } 00935 } 00936 00937 //////////////////////////////////////////////////////////////////// 00938 // Function: CMetaInterval::do_event_reverse 00939 // Access: Private 00940 // Description: Process a single event in the interval, moving 00941 // backwards in time. This undoes the indicated event. 00942 // If the event represents a new begin, adds it to the 00943 // new_active list; if it is an end, finalizes it. 00944 // 00945 // If is_initial is true, it is as if we are in 00946 // reverse_initialize or reverse_finalize: instant 00947 // events will be invoked only if they are marked 00948 // open_ended. 00949 //////////////////////////////////////////////////////////////////// 00950 void CMetaInterval:: 00951 do_event_reverse(CMetaInterval::PlaybackEvent *event, 00952 CMetaInterval::ActiveEvents &new_active, bool is_initial) { 00953 // Undo the indicated event. 00954 switch (event->_type) { 00955 case PET_begin: 00956 { 00957 nassertv(event->_begin_event == event); 00958 // Erase the event from either the new active or the current 00959 // active lists. 00960 ActiveEvents::iterator ai; 00961 ai = find(new_active.begin(), new_active.end(), event); 00962 if (ai != new_active.end()) { 00963 new_active.erase(ai); 00964 // This interval was new this frame; we invoke it as an 00965 // instant event. 00966 enqueue_event(event->_n, ET_reverse_instant, is_initial); 00967 00968 } else { 00969 ai = find(_active.begin(), _active.end(), event); 00970 if (ai != _active.end()) { 00971 _active.erase(ai); 00972 enqueue_event(event->_n, ET_reverse_finalize, is_initial); 00973 00974 } else { 00975 // Hmm, this event wasn't on either list. Maybe there was a 00976 // stop event on the list whose time was greater than the 00977 // total, somehow. 00978 interval_cat.error() 00979 << "Event " << event->_n << " not on active list.\n"; 00980 nassertv(false); 00981 } 00982 } 00983 } 00984 break; 00985 00986 case PET_end: 00987 new_active.push_front(event->_begin_event); 00988 break; 00989 00990 case PET_instant: 00991 nassertv(event->_begin_event == event); 00992 enqueue_event(event->_n, ET_reverse_instant, is_initial); 00993 break; 00994 } 00995 } 00996 00997 //////////////////////////////////////////////////////////////////// 00998 // Function: CMetaInterval::finish_events_reverse 00999 // Access: Private 01000 // Description: After walking through the event list and adding a 01001 // bunch of new events to new_active, finishes up by 01002 // calling priv_step() on all of the events still in _active 01003 // and priv_reverse_initialize() on all the events in 01004 // new_active, then copying the events from new_active 01005 // to active. 01006 //////////////////////////////////////////////////////////////////// 01007 void CMetaInterval:: 01008 finish_events_reverse(int now, CMetaInterval::ActiveEvents &new_active) { 01009 // Do whatever's still active. 01010 ActiveEvents::iterator ai; 01011 for (ai = _active.begin(); ai != _active.end(); ++ai) { 01012 PlaybackEvent *event = (*ai); 01013 enqueue_event(event->_n, ET_step, false, now - event->_time); 01014 } 01015 01016 // Initialize whatever new intervals we came across. 01017 for (ai = new_active.begin(); ai != new_active.end(); ++ai) { 01018 PlaybackEvent *event = (*ai); 01019 enqueue_event(event->_n, ET_reverse_initialize, false, now - event->_time); 01020 _active.push_front(event); 01021 } 01022 } 01023 01024 //////////////////////////////////////////////////////////////////// 01025 // Function: CMetaInterval::enqueue_event 01026 // Access: Private 01027 // Description: Enqueues the indicated interval for invocation after 01028 // we have finished scanning for events that need 01029 // processing this frame. 01030 // 01031 // is_initial is only relevant for event types 01032 // ET_instant or ET_reverse_instant, and indicates 01033 // whether we are in the priv_initialize() (or 01034 // priv_reverse_initialize()) call, and should therefore only 01035 // invoke open-ended intervals. 01036 // 01037 // time is only relevant for ET_initialize, 01038 // ET_reverse_initialize, and ET_step. 01039 //////////////////////////////////////////////////////////////////// 01040 void CMetaInterval:: 01041 enqueue_event(int n, CInterval::EventType event_type, bool is_initial, int time) { 01042 nassertv(n >= 0 && n < (int)_defs.size()); 01043 const IntervalDef &def = _defs[n]; 01044 switch (def._type) { 01045 case DT_c_interval: 01046 if (is_initial && 01047 (event_type == ET_instant || event_type == ET_reverse_instant) && 01048 !def._c_interval->get_open_ended()) { 01049 // Ignore a non-open-ended interval that we skipped completely 01050 // past on priv_initialize(). 01051 return; 01052 } else { 01053 if (_event_queue.empty()) { 01054 // if the event queue is empty, we can process this C++ 01055 // interval immediately. We only need to defer it if there 01056 // are external (e.g. Python) intervals in the queue that need 01057 // to be processed first. 01058 def._c_interval->priv_do_event(int_to_double_time(time), event_type); 01059 return; 01060 } 01061 } 01062 break; 01063 01064 case DT_ext_index: 01065 if (is_initial && 01066 (event_type == ET_instant || event_type == ET_reverse_instant) && 01067 !def._ext_open_ended) { 01068 // Ignore a non-open-ended interval that we skipped completely 01069 // past on priv_initialize(). 01070 return; 01071 } 01072 break; 01073 01074 default: 01075 nassertv(false); 01076 return; 01077 } 01078 01079 _event_queue.push_back(EventQueueEntry(n, event_type, time)); 01080 } 01081 01082 //////////////////////////////////////////////////////////////////// 01083 // Function: CMetaInterval::enqueue_self_event 01084 // Access: Private 01085 // Description: Enqueues a reference to *this* interval. This is 01086 // called only when the interval is recursively 01087 // re-entered; the request will be serviced when the 01088 // current request is done processing. 01089 // 01090 // time is only relevant for ET_initialize, 01091 // ET_reverse_initialize, and ET_step. 01092 //////////////////////////////////////////////////////////////////// 01093 void CMetaInterval:: 01094 enqueue_self_event(CInterval::EventType event_type, double t) { 01095 interval_cat.info() 01096 << "Recursive reentry detected into " << *this << "\n"; 01097 int time = double_to_int_time(t); 01098 _event_queue.push_back(EventQueueEntry(-1, event_type, time)); 01099 } 01100 01101 //////////////////////////////////////////////////////////////////// 01102 // Function: CMetaInterval::enqueue_done_event 01103 // Access: Private 01104 // Description: Enqueues a special "event" that simply marks the end 01105 // of processing of the interval; the interval's done 01106 // event should be thrown now, if it is defined. 01107 //////////////////////////////////////////////////////////////////// 01108 void CMetaInterval:: 01109 enqueue_done_event() { 01110 _event_queue.push_back(EventQueueEntry(-2, ET_finalize, 0)); 01111 } 01112 01113 //////////////////////////////////////////////////////////////////// 01114 // Function: CMetaInterval::service_event_queue 01115 // Access: Private 01116 // Description: Invokes whatever C++ intervals might be at the head 01117 // of the queue, and prepares for passing an external 01118 // interval to the scripting language. 01119 // 01120 // The return value is true if there remains at least 01121 // one external event to be serviced, false if all 01122 // events are handled. 01123 //////////////////////////////////////////////////////////////////// 01124 bool CMetaInterval:: 01125 service_event_queue() { 01126 while (!_event_queue.empty()) { 01127 nassertr(!_processing_events, true); 01128 const EventQueueEntry &entry = _event_queue.front(); 01129 if (entry._n == -1) { 01130 // Index -1 is a special code for *this* interval. 01131 priv_do_event(int_to_double_time(entry._time), entry._event_type); 01132 01133 } else if (entry._n == -2) { 01134 // Index -2 is a special code to indicate the interval is now 01135 // done, and its done event should be thrown. 01136 interval_done(); 01137 01138 } else { 01139 nassertr(entry._n >= 0 && entry._n < (int)_defs.size(), false); 01140 const IntervalDef &def = _defs[entry._n]; 01141 switch (def._type) { 01142 case DT_c_interval: 01143 // Handle the C++ event. 01144 def._c_interval->priv_do_event(int_to_double_time(entry._time), entry._event_type); 01145 break; 01146 01147 case DT_ext_index: 01148 // Here's an external event; leave it there and return. 01149 return true; 01150 01151 default: 01152 nassertr(false, false); 01153 return false; 01154 } 01155 } 01156 _event_queue.pop_front(); 01157 } 01158 01159 // No more events on the queue. 01160 nassertr(!_processing_events, false); 01161 return false; 01162 } 01163 01164 //////////////////////////////////////////////////////////////////// 01165 // Function: CMetaInterval::recompute_level 01166 // Access: Private 01167 // Description: Recursively recomputes a complete level (delimited by 01168 // push/pop definitions). 01169 // 01170 // The value n on entry refers to the first entry after 01171 // the push; the return value will reference the 01172 // matching pop, or an index greater than the last 01173 // element in the array if there was no matching pop. 01174 // 01175 // The level_begin value indicates the begin time of 01176 // this level. On return, level_end is filled with the 01177 // end time of this level. 01178 //////////////////////////////////////////////////////////////////// 01179 int CMetaInterval:: 01180 recompute_level(int n, int level_begin, int &level_end) { 01181 level_end = level_begin; 01182 int previous_begin = level_begin; 01183 int previous_end = level_begin; 01184 01185 while (n < (int)_defs.size() && _defs[n]._type != DT_pop_level) { 01186 IntervalDef &def = _defs[n]; 01187 int begin_time = previous_begin; 01188 int end_time = previous_end; 01189 switch (def._type) { 01190 case DT_c_interval: 01191 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end); 01192 def._actual_begin_time = begin_time; 01193 end_time = begin_time + double_to_int_time(def._c_interval->get_duration()); 01194 01195 if (def._c_interval->is_exact_type(WaitInterval::get_class_type())) { 01196 // Don't bother enqueuing events for WaitIntervals; they're 01197 // just there to fill up time. 01198 01199 } else { 01200 if (begin_time == end_time) { 01201 _events.push_back(new PlaybackEvent(begin_time, n, PET_instant)); 01202 } else { 01203 PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin); 01204 PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end); 01205 end->_begin_event = begin; 01206 _events.push_back(begin); 01207 _events.push_back(end); 01208 } 01209 } 01210 break; 01211 01212 case DT_ext_index: 01213 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end); 01214 def._actual_begin_time = begin_time; 01215 end_time = begin_time + double_to_int_time(def._ext_duration); 01216 if (begin_time == end_time) { 01217 _events.push_back(new PlaybackEvent(begin_time, n, PET_instant)); 01218 } else { 01219 PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin); 01220 PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end); 01221 end->_begin_event = begin; 01222 _events.push_back(begin); 01223 _events.push_back(end); 01224 } 01225 break; 01226 01227 case DT_push_level: 01228 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end); 01229 def._actual_begin_time = begin_time; 01230 n = recompute_level(n + 1, begin_time, end_time); 01231 break; 01232 01233 case DT_pop_level: 01234 nassertr(false, _defs.size()); 01235 break; 01236 } 01237 01238 previous_begin = begin_time; 01239 previous_end = end_time; 01240 level_end = max(level_end, end_time); 01241 n++; 01242 } 01243 01244 if (n < (int)_defs.size()) { 01245 IntervalDef &def = _defs[n]; 01246 // If we have a pop record, check it for a phony duration. 01247 if (def._ext_duration >= 0.0) { 01248 level_end = level_begin + double_to_int_time(def._ext_duration); 01249 } 01250 01251 // The final pop "begins" at the level end time, just for clarity 01252 // on output. 01253 def._actual_begin_time = level_end; 01254 } 01255 01256 return n; 01257 } 01258 01259 //////////////////////////////////////////////////////////////////// 01260 // Function: CMetaInterval::get_begin_time 01261 // Access: Private 01262 // Description: Returns the integer begin time indicated by the given 01263 // IntervalDef, given the indicated level begin, 01264 // previous begin, and previous end times. 01265 //////////////////////////////////////////////////////////////////// 01266 int CMetaInterval:: 01267 get_begin_time(const CMetaInterval::IntervalDef &def, int level_begin, 01268 int previous_begin, int previous_end) { 01269 switch (def._rel_to) { 01270 case RS_previous_end: 01271 return previous_end + double_to_int_time(def._rel_time); 01272 01273 case RS_previous_begin: 01274 return previous_begin + double_to_int_time(def._rel_time); 01275 01276 case RS_level_begin: 01277 return level_begin + double_to_int_time(def._rel_time); 01278 } 01279 01280 nassertr(false, previous_end); 01281 return previous_end; 01282 } 01283 01284 //////////////////////////////////////////////////////////////////// 01285 // Function: CMetaInterval::write_event_desc 01286 // Access: Private 01287 // Description: Formats an event for output, for write() or 01288 // timeline(). 01289 //////////////////////////////////////////////////////////////////// 01290 void CMetaInterval:: 01291 write_event_desc(ostream &out, const CMetaInterval::IntervalDef &def, 01292 int &extra_indent_level) const { 01293 switch (def._type) { 01294 case DT_c_interval: 01295 indent(out, extra_indent_level) 01296 << *def._c_interval; 01297 if (!def._c_interval->get_open_ended()) { 01298 out << " (!oe)"; 01299 } 01300 out << "\n"; 01301 break; 01302 01303 case DT_ext_index: 01304 indent(out, extra_indent_level) 01305 << "*" << def._ext_name; 01306 if (def._ext_duration != 0.0) { 01307 out << " dur " << def._ext_duration; 01308 } 01309 if (!def._ext_open_ended) { 01310 out << " (!oe)"; 01311 } 01312 out<< "\n"; 01313 break; 01314 01315 case DT_push_level: 01316 indent(out, extra_indent_level) 01317 << def._ext_name << " {\n"; 01318 extra_indent_level += 2; 01319 break; 01320 01321 case DT_pop_level: 01322 extra_indent_level -= 2; 01323 indent(out, extra_indent_level) 01324 << "}\n"; 01325 break; 01326 } 01327 }