00001 // Filename: cInterval.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 "cInterval.h" 00016 #include "cIntervalManager.h" 00017 #include "indent.h" 00018 #include "clockObject.h" 00019 #include "event.h" 00020 #include "eventQueue.h" 00021 #include "pStatTimer.h" 00022 00023 PStatCollector CInterval::_root_pcollector("App:Show code:ivalLoop"); 00024 TypeHandle CInterval::_type_handle; 00025 00026 static inline string 00027 get_pstats_name(const string &name) { 00028 string pname = name; 00029 size_t hyphen = pname.find('-'); 00030 if (hyphen != string::npos) { 00031 pname = pname.substr(0, hyphen); 00032 } 00033 return pname; 00034 } 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: CInterval::Constructor 00038 // Access: Public 00039 // Description: 00040 //////////////////////////////////////////////////////////////////// 00041 CInterval:: 00042 CInterval(const string &name, double duration, bool open_ended) : 00043 _state(S_initial), 00044 _curr_t(0.0), 00045 _name(name), 00046 _pname(get_pstats_name(name)), 00047 _duration(max(duration, 0.0)), 00048 _open_ended(open_ended), 00049 _dirty(false), 00050 _ival_pcollector(_root_pcollector, _pname) 00051 { 00052 _auto_pause = false; 00053 _auto_finish = false; 00054 _wants_t_callback = false; 00055 _last_t_callback = -1.0; 00056 _manager = CIntervalManager::get_global_ptr(); 00057 _clock_start = 0.0; 00058 _start_t = 0.0; 00059 _end_t = _duration; 00060 _start_t_at_start = true; 00061 _end_t_at_end = true; 00062 _play_rate = 1.0; 00063 _do_loop = false; 00064 _loop_count = 0; 00065 00066 if (interval_cat.is_spam()) { 00067 interval_cat.spam() 00068 << "Constructing interval " << (void *)this << ", duration = " 00069 << _duration << "\n"; 00070 } 00071 } 00072 00073 //////////////////////////////////////////////////////////////////// 00074 // Function: CInterval::Destructor 00075 // Access: Public, Virtual 00076 // Description: 00077 //////////////////////////////////////////////////////////////////// 00078 CInterval:: 00079 ~CInterval() { 00080 if (interval_cat.is_spam()) { 00081 interval_cat.spam() 00082 << "Destructing interval " << (void *)this << "\n"; 00083 } 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 // Function: CInterval::set_t 00088 // Access: Published 00089 // Description: Explicitly sets the time within the interval. 00090 // Normally, you would use start() .. finish() to let 00091 // the time play normally, but this may be used to set 00092 // the time to some particular value. 00093 //////////////////////////////////////////////////////////////////// 00094 void CInterval:: 00095 set_t(double t) { 00096 // There doesn't seem to be any reason to clamp this, and it 00097 // breaks looping intervals. The interval code should properly 00098 // handle t values outside the proper range. 00099 //t = min(max(t, 0.0), get_duration()); 00100 00101 switch (get_state()) { 00102 case S_initial: 00103 priv_initialize(t); 00104 if (is_playing()) { 00105 setup_resume(); 00106 } else { 00107 priv_interrupt(); 00108 } 00109 break; 00110 00111 case S_started: 00112 // Support modifying t while the interval is playing. We assume 00113 // is_playing() will be true in this state. 00114 nassertv(is_playing()); 00115 priv_interrupt(); 00116 priv_step(t); 00117 setup_resume(); 00118 break; 00119 00120 case S_paused: 00121 // Support modifying t while the interval is paused. In this 00122 // case, we simply step to the new value of t; but this will 00123 // change the state to S_started, so we must then change it back 00124 // to S_paused by hand (because we're still paused). 00125 priv_step(t); 00126 priv_interrupt(); 00127 break; 00128 00129 case S_final: 00130 priv_reverse_initialize(t); 00131 if (is_playing()) { 00132 setup_resume(); 00133 } else { 00134 priv_interrupt(); 00135 } 00136 break; 00137 } 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: CInterval::start 00142 // Access: Published 00143 // Description: Starts the interval playing by registering it with 00144 // the current CIntervalManager. The interval will 00145 // play to the end and stop. 00146 // 00147 // If end_t is less than zero, it indicates the end of 00148 // the interval. 00149 //////////////////////////////////////////////////////////////////// 00150 void CInterval:: 00151 start(double start_t, double end_t, double play_rate) { 00152 setup_play(start_t, end_t, play_rate, false); 00153 _manager->add_c_interval(this, false); 00154 } 00155 00156 //////////////////////////////////////////////////////////////////// 00157 // Function: CInterval::loop 00158 // Access: Published 00159 // Description: Starts the interval playing by registering it with 00160 // the current CIntervalManager. The interval will 00161 // play until it is interrupted with finish() or 00162 // pause(), looping back to start_t when it reaches 00163 // end_t. 00164 // 00165 // If end_t is less than zero, it indicates the end of 00166 // the interval. 00167 //////////////////////////////////////////////////////////////////// 00168 void CInterval:: 00169 loop(double start_t, double end_t, double play_rate) { 00170 setup_play(start_t, end_t, play_rate, true); 00171 _manager->add_c_interval(this, false); 00172 } 00173 00174 //////////////////////////////////////////////////////////////////// 00175 // Function: CInterval::pause 00176 // Access: Published 00177 // Description: Stops the interval from playing but leaves it in its 00178 // current state. It may later be resumed from this 00179 // point by calling resume(). 00180 //////////////////////////////////////////////////////////////////// 00181 double CInterval:: 00182 pause() { 00183 if (get_state() == S_started) { 00184 priv_interrupt(); 00185 } 00186 int index = _manager->find_c_interval(this->get_name()); 00187 if (index >= 0) { 00188 _manager->remove_c_interval(index); 00189 } 00190 return get_t(); 00191 } 00192 00193 //////////////////////////////////////////////////////////////////// 00194 // Function: CInterval::resume 00195 // Access: Published 00196 // Description: Restarts the interval from its current point after a 00197 // previous call to pause(). 00198 //////////////////////////////////////////////////////////////////// 00199 void CInterval:: 00200 resume() { 00201 setup_resume(); 00202 _manager->add_c_interval(this, false); 00203 } 00204 00205 //////////////////////////////////////////////////////////////////// 00206 // Function: CInterval::resume 00207 // Access: Published 00208 // Description: Restarts the interval from the indicated point after a 00209 // previous call to pause(). 00210 //////////////////////////////////////////////////////////////////// 00211 void CInterval:: 00212 resume(double start_t) { 00213 set_t(start_t); 00214 setup_resume(); 00215 _manager->add_c_interval(this, false); 00216 } 00217 00218 //////////////////////////////////////////////////////////////////// 00219 // Function: CInterval::resume_until 00220 // Access: Published 00221 // Description: Restarts the interval from the current point after a 00222 // previous call to pause() (or a previous 00223 // play-to-point-and-stop), to play until the indicated 00224 // point and then stop. 00225 //////////////////////////////////////////////////////////////////// 00226 void CInterval:: 00227 resume_until(double end_t) { 00228 setup_resume_until(end_t); 00229 _manager->add_c_interval(this, false); 00230 } 00231 00232 //////////////////////////////////////////////////////////////////// 00233 // Function: CInterval::finish 00234 // Access: Published 00235 // Description: Stops the interval from playing and sets it to its 00236 // final state. 00237 //////////////////////////////////////////////////////////////////// 00238 void CInterval:: 00239 finish() { 00240 switch (get_state()) { 00241 case S_initial: 00242 priv_instant(); 00243 break; 00244 00245 case S_final: 00246 break; 00247 00248 default: 00249 priv_finalize(); 00250 } 00251 00252 int index = _manager->find_c_interval(this->get_name()); 00253 if (index >= 0) { 00254 _manager->remove_c_interval(index); 00255 } 00256 } 00257 00258 //////////////////////////////////////////////////////////////////// 00259 // Function: CInterval::clear_to_initial 00260 // Access: Published 00261 // Description: Pauses the interval, if it is playing, and resets its 00262 // state to its initial state, abandoning any state 00263 // changes already in progress in the middle of the 00264 // interval. Calling this is like pausing the interval 00265 // and discarding it, creating a new one in its place. 00266 //////////////////////////////////////////////////////////////////// 00267 void CInterval:: 00268 clear_to_initial() { 00269 pause(); 00270 00271 _state = S_initial; 00272 _curr_t = 0.0; 00273 } 00274 00275 //////////////////////////////////////////////////////////////////// 00276 // Function: CInterval::is_playing 00277 // Access: Published 00278 // Description: Returns true if the interval is currently playing, 00279 // false otherwise. 00280 //////////////////////////////////////////////////////////////////// 00281 bool CInterval:: 00282 is_playing() const { 00283 int index = _manager->find_c_interval(this->get_name()); 00284 return (index >= 0); 00285 } 00286 00287 //////////////////////////////////////////////////////////////////// 00288 // Function: CInterval::get_play_rate 00289 // Access: Published 00290 // Description: Returns the play rate as set by the last call to 00291 // start(), loop(), or set_play_rate(). 00292 //////////////////////////////////////////////////////////////////// 00293 double CInterval:: 00294 get_play_rate() const { 00295 return _play_rate; 00296 } 00297 00298 //////////////////////////////////////////////////////////////////// 00299 // Function: CInterval::set_play_rate 00300 // Access: Published 00301 // Description: Changes the play rate of the interval. If the 00302 // interval is already started, this changes its speed 00303 // on-the-fly. Note that since play_rate is a parameter 00304 // to start() and loop(), the next call to start() or 00305 // loop() will reset this parameter. 00306 //////////////////////////////////////////////////////////////////// 00307 void CInterval:: 00308 set_play_rate(double play_rate) { 00309 if (is_playing()) { 00310 pause(); 00311 _play_rate = play_rate; 00312 resume(); 00313 } else { 00314 _play_rate = play_rate; 00315 } 00316 } 00317 00318 //////////////////////////////////////////////////////////////////// 00319 // Function: CInterval::priv_do_event 00320 // Access: Published 00321 // Description: Calls the appropriate event function indicated by the 00322 // EventType. 00323 //////////////////////////////////////////////////////////////////// 00324 void CInterval:: 00325 priv_do_event(double t, EventType event) { 00326 PStatTimer timer(_ival_pcollector); 00327 switch (event) { 00328 case ET_initialize: 00329 priv_initialize(t); 00330 return; 00331 00332 case ET_instant: 00333 priv_instant(); 00334 return; 00335 00336 case ET_step: 00337 priv_step(t); 00338 return; 00339 00340 case ET_finalize: 00341 priv_finalize(); 00342 return; 00343 00344 case ET_reverse_initialize: 00345 priv_reverse_initialize(t); 00346 return; 00347 00348 case ET_reverse_instant: 00349 priv_reverse_instant(); 00350 return; 00351 00352 case ET_reverse_finalize: 00353 priv_reverse_finalize(); 00354 return; 00355 00356 case ET_interrupt: 00357 priv_interrupt(); 00358 return; 00359 } 00360 00361 interval_cat.warning() 00362 << "Invalid event type: " << (int)event << "\n"; 00363 } 00364 00365 //////////////////////////////////////////////////////////////////// 00366 // Function: CInterval::priv_initialize 00367 // Access: Published, Virtual 00368 // Description: This replaces the first call to priv_step(), and indicates 00369 // that the interval has just begun. This may be 00370 // overridden by derived classes that need to do some 00371 // explicit initialization on the first call. 00372 //////////////////////////////////////////////////////////////////// 00373 void CInterval:: 00374 priv_initialize(double t) { 00375 check_stopped(get_class_type(), "priv_initialize"); 00376 recompute(); 00377 _state = S_started; 00378 priv_step(t); 00379 } 00380 00381 //////////////////////////////////////////////////////////////////// 00382 // Function: CInterval::priv_instant 00383 // Access: Published, Virtual 00384 // Description: This is called in lieu of priv_initialize() .. priv_step() 00385 // .. priv_finalize(), when everything is to happen within 00386 // one frame. The interval should initialize itself, 00387 // then leave itself in the final state. 00388 //////////////////////////////////////////////////////////////////// 00389 void CInterval:: 00390 priv_instant() { 00391 check_stopped(get_class_type(), "priv_instant"); 00392 recompute(); 00393 _state = S_started; 00394 priv_step(get_duration()); 00395 _state = S_final; 00396 interval_done(); 00397 } 00398 00399 //////////////////////////////////////////////////////////////////// 00400 // Function: CInterval::priv_step 00401 // Access: Published, Virtual 00402 // Description: Advances the time on the interval. The time may 00403 // either increase (the normal case) or decrease 00404 // (e.g. if the interval is being played by a slider). 00405 //////////////////////////////////////////////////////////////////// 00406 void CInterval:: 00407 priv_step(double t) { 00408 check_started(get_class_type(), "priv_step"); 00409 _state = S_started; 00410 _curr_t = t; 00411 } 00412 00413 //////////////////////////////////////////////////////////////////// 00414 // Function: CInterval::priv_finalize 00415 // Access: Published, Virtual 00416 // Description: This is called to stop an interval, forcing it to 00417 // whatever state it would be after it played all the 00418 // way through. It's generally invoked by 00419 // set_final_t(). 00420 //////////////////////////////////////////////////////////////////// 00421 void CInterval:: 00422 priv_finalize() { 00423 check_started(get_class_type(), "priv_finalize"); 00424 double duration = get_duration(); 00425 priv_step(duration); 00426 _state = S_final; 00427 interval_done(); 00428 } 00429 00430 //////////////////////////////////////////////////////////////////// 00431 // Function: CInterval::reverse_initialize 00432 // Access: Published, Virtual 00433 // Description: Similar to priv_initialize(), but this is called when the 00434 // interval is being played backwards; it indicates that 00435 // the interval should start at the finishing state and 00436 // undo any intervening intervals. 00437 //////////////////////////////////////////////////////////////////// 00438 void CInterval:: 00439 priv_reverse_initialize(double t) { 00440 check_stopped(get_class_type(), "priv_reverse_initialize"); 00441 recompute(); 00442 _state = S_started; 00443 priv_step(t); 00444 } 00445 00446 //////////////////////////////////////////////////////////////////// 00447 // Function: CInterval::reverse_instant 00448 // Access: Published, Virtual 00449 // Description: This is called in lieu of priv_reverse_initialize() 00450 // .. priv_step() .. priv_reverse_finalize(), when everything is 00451 // to happen within one frame. The interval should 00452 // initialize itself, then leave itself in the initial 00453 // state. 00454 //////////////////////////////////////////////////////////////////// 00455 void CInterval:: 00456 priv_reverse_instant() { 00457 check_stopped(get_class_type(), "priv_reverse_instant"); 00458 recompute(); 00459 _state = S_started; 00460 priv_step(0.0); 00461 _state = S_initial; 00462 } 00463 00464 //////////////////////////////////////////////////////////////////// 00465 // Function: CInterval::reverse_finalize 00466 // Access: Published, Virtual 00467 // Description: Called generally following a priv_reverse_initialize(), 00468 // this indicates the interval should set itself to the 00469 // initial state. 00470 //////////////////////////////////////////////////////////////////// 00471 void CInterval:: 00472 priv_reverse_finalize() { 00473 check_started(get_class_type(), "priv_reverse_finalize"); 00474 priv_step(0.0); 00475 _state = S_initial; 00476 } 00477 00478 //////////////////////////////////////////////////////////////////// 00479 // Function: CInterval::priv_interrupt 00480 // Access: Published, Virtual 00481 // Description: This is called while the interval is playing to 00482 // indicate that it is about to be interrupted; that is, 00483 // priv_step() will not be called for a length of time. But 00484 // the interval should remain in its current state in 00485 // anticipation of being eventually restarted when the 00486 // calls to priv_step() eventually resume. 00487 // 00488 // The purpose of this function is to allow self-running 00489 // intervals like sound intervals to stop the actual 00490 // sound playback during the pause. 00491 //////////////////////////////////////////////////////////////////// 00492 void CInterval:: 00493 priv_interrupt() { 00494 check_started(get_class_type(), "priv_interrupt"); 00495 _state = S_paused; 00496 } 00497 00498 //////////////////////////////////////////////////////////////////// 00499 // Function: CInterval::output 00500 // Access: Published, Virtual 00501 // Description: 00502 //////////////////////////////////////////////////////////////////// 00503 void CInterval:: 00504 output(ostream &out) const { 00505 out << get_name(); 00506 if (get_duration() != 0.0) { 00507 out << " dur " << get_duration(); 00508 } 00509 } 00510 00511 //////////////////////////////////////////////////////////////////// 00512 // Function: CInterval::write 00513 // Access: Published, Virtual 00514 // Description: 00515 //////////////////////////////////////////////////////////////////// 00516 void CInterval:: 00517 write(ostream &out, int indent_level) const { 00518 indent(out, indent_level) << *this << "\n"; 00519 } 00520 00521 //////////////////////////////////////////////////////////////////// 00522 // Function: CInterval::setup_play 00523 // Access: Published 00524 // Description: Called to prepare the interval for automatic timed 00525 // playback, e.g. via a Python task. The interval will 00526 // be played from start_t to end_t, at a time factor 00527 // specified by play_rate. start_t must always be less 00528 // than end_t (except for the exception for end_t == -1, 00529 // below), but if play_rate is negative the interval 00530 // will be played backwards. 00531 // 00532 // Specify end_t of -1 to play the entire interval from 00533 // start_t. 00534 // 00535 // Call step_play() repeatedly to execute the interval. 00536 //////////////////////////////////////////////////////////////////// 00537 void CInterval:: 00538 setup_play(double start_t, double end_t, double play_rate, bool do_loop) { 00539 nassertv(start_t < end_t || end_t < 0.0); 00540 nassertv(play_rate != 0.0); 00541 PStatTimer timer(_ival_pcollector); 00542 00543 double duration = get_duration(); 00544 00545 if (start_t <= 0.0) { 00546 _start_t = 0.0; 00547 _start_t_at_start = true; 00548 } else if (start_t > duration) { 00549 _start_t = duration; 00550 _start_t_at_start = false; 00551 } else { 00552 _start_t = start_t; 00553 _start_t_at_start = false; 00554 } 00555 if (end_t < 0.0 || end_t >= duration) { 00556 _end_t = duration; 00557 _end_t_at_end = true; 00558 } else { 00559 _end_t = end_t; 00560 _end_t_at_end = false; 00561 } 00562 00563 _clock_start = ClockObject::get_global_clock()->get_frame_time(); 00564 _play_rate = play_rate; 00565 _do_loop = do_loop; 00566 _loop_count = 0; 00567 } 00568 00569 //////////////////////////////////////////////////////////////////// 00570 // Function: CInterval::setup_resume 00571 // Access: Published 00572 // Description: Called to prepare the interval for restarting at the 00573 // current point within the interval after an 00574 // interruption. 00575 //////////////////////////////////////////////////////////////////// 00576 void CInterval:: 00577 setup_resume() { 00578 double now = ClockObject::get_global_clock()->get_frame_time(); 00579 if (_play_rate > 0.0) { 00580 _clock_start = now - ((get_t() - _start_t) / _play_rate); 00581 00582 } else if (_play_rate < 0.0) { 00583 _clock_start = now - ((get_t() - _end_t) / _play_rate); 00584 } 00585 _loop_count = 0; 00586 } 00587 00588 //////////////////////////////////////////////////////////////////// 00589 // Function: CInterval::setup_resume_until 00590 // Access: Published 00591 // Description: Called to prepare the interval for restarting from 00592 // the current point after a previous call to pause() 00593 // (or a previous play-to-point-and-stop), to play until 00594 // the indicated point and then stop. 00595 //////////////////////////////////////////////////////////////////// 00596 void CInterval:: 00597 setup_resume_until(double end_t) { 00598 double duration = get_duration(); 00599 00600 if (end_t < 0.0 || end_t >= duration) { 00601 _end_t = duration; 00602 _end_t_at_end = true; 00603 } else { 00604 _end_t = end_t; 00605 _end_t_at_end = false; 00606 } 00607 00608 setup_resume(); 00609 } 00610 00611 //////////////////////////////////////////////////////////////////// 00612 // Function: CInterval::step_play 00613 // Access: Published 00614 // Description: Should be called once per frame to execute the 00615 // automatic timed playback begun with setup_play(). 00616 // 00617 // Returns true if the interval should continue, false 00618 // if it is done and should stop. 00619 //////////////////////////////////////////////////////////////////// 00620 bool CInterval:: 00621 step_play() { 00622 PStatTimer timer(_ival_pcollector); 00623 double now = ClockObject::get_global_clock()->get_frame_time(); 00624 00625 if (_play_rate >= 0.0) { 00626 double t = (now - _clock_start) * _play_rate + _start_t; 00627 00628 if (_end_t_at_end) { 00629 _end_t = get_duration(); 00630 } 00631 00632 if (t < _end_t) { 00633 // In the middle of the interval, not a problem. 00634 if (is_stopped()) { 00635 priv_initialize(t); 00636 } else { 00637 priv_step(t); 00638 } 00639 00640 } else { 00641 // Past the ending point; time to finalize. 00642 if (_end_t_at_end) { 00643 // Only finalize if the playback cycle includes the whole 00644 // interval. 00645 if (is_stopped()) { 00646 if (get_open_ended() || _loop_count != 0) { 00647 priv_instant(); 00648 } 00649 } else { 00650 priv_finalize(); 00651 } 00652 } else { 00653 if (is_stopped()) { 00654 priv_initialize(_end_t); 00655 } else { 00656 priv_step(_end_t); 00657 } 00658 } 00659 00660 // Advance the clock for the next loop cycle. We might have to 00661 // advance multiple times if we skipped several cycles in the past 00662 // frame. 00663 00664 if (_end_t == _start_t) { 00665 // If the interval has no length, we loop exactly once each 00666 // time. 00667 _loop_count++; 00668 00669 } else { 00670 // Otherwise, figure out how many loops we need to skip. 00671 double time_per_loop = (_end_t - _start_t) / _play_rate; 00672 double num_loops = floor((now - _clock_start) / time_per_loop); 00673 _loop_count += (int)num_loops; 00674 _clock_start += num_loops * time_per_loop; 00675 } 00676 } 00677 00678 } else { 00679 // Playing backwards. 00680 double t = (now - _clock_start) * _play_rate + _end_t; 00681 00682 if (t >= _start_t) { 00683 // In the middle of the interval, not a problem. 00684 if (is_stopped()) { 00685 priv_reverse_initialize(t); 00686 } else { 00687 priv_step(t); 00688 } 00689 00690 } else { 00691 // Past the ending point; time to finalize. 00692 if (_start_t_at_start) { 00693 // Only finalize if the playback cycle includes the whole 00694 // interval. 00695 if (is_stopped()) { 00696 if (get_open_ended() || _loop_count != 0) { 00697 priv_reverse_instant(); 00698 } 00699 } else { 00700 priv_reverse_finalize(); 00701 } 00702 } else { 00703 if (is_stopped()) { 00704 priv_reverse_initialize(_start_t); 00705 } else { 00706 priv_step(_start_t); 00707 } 00708 } 00709 00710 // Advance the clock for the next loop cycle. We might have to 00711 // advance multiple times if we skipped several cycles in the past 00712 // frame. 00713 00714 if (_end_t == _start_t) { 00715 // If the interval has no length, we loop exactly once each 00716 // time. 00717 _loop_count++; 00718 00719 } else { 00720 // Otherwise, figure out how many loops we need to skip. 00721 double time_per_loop = (_end_t - _start_t) / -_play_rate; 00722 double num_loops = floor((now - _clock_start) / time_per_loop); 00723 _loop_count += (int)num_loops; 00724 _clock_start += num_loops * time_per_loop; 00725 } 00726 } 00727 } 00728 00729 bool should_continue = (_loop_count == 0 || _do_loop); 00730 00731 if (!should_continue && _state == S_started) { 00732 priv_interrupt(); 00733 } 00734 00735 return should_continue; 00736 } 00737 00738 //////////////////////////////////////////////////////////////////// 00739 // Function: CInterval::mark_dirty 00740 // Access: Public 00741 // Description: Called by a derived class to indicate the interval has 00742 // been changed internally and must be recomputed before 00743 // its duration may be returned. 00744 //////////////////////////////////////////////////////////////////// 00745 void CInterval:: 00746 mark_dirty() { 00747 if (!_dirty) { 00748 _dirty = true; 00749 Parents::iterator pi; 00750 for (pi = _parents.begin(); pi != _parents.end(); ++pi) { 00751 (*pi)->mark_dirty(); 00752 } 00753 } 00754 } 00755 00756 //////////////////////////////////////////////////////////////////// 00757 // Function: CInterval::interval_done 00758 // Access: Protected 00759 // Description: Called internally whenever the interval reaches its 00760 // final state. 00761 //////////////////////////////////////////////////////////////////// 00762 void CInterval:: 00763 interval_done() { 00764 if (!_done_event.empty()) { 00765 _manager->get_event_queue()->queue_event(new Event(_done_event)); 00766 } 00767 } 00768 00769 //////////////////////////////////////////////////////////////////// 00770 // Function: CInterval::do_recompute 00771 // Access: Protected, Virtual 00772 // Description: Does whatever processing is necessary to recompute 00773 // the interval after a call to mark_dirty() has 00774 // indicated a recomputation is necessary. 00775 //////////////////////////////////////////////////////////////////// 00776 void CInterval:: 00777 do_recompute() { 00778 _dirty = false; 00779 } 00780 00781 ostream & 00782 operator << (ostream &out, CInterval::State state) { 00783 switch (state) { 00784 case CInterval::S_initial: 00785 return out << "initial"; 00786 00787 case CInterval::S_started: 00788 return out << "started"; 00789 00790 case CInterval::S_paused: 00791 return out << "paused"; 00792 00793 case CInterval::S_final: 00794 return out << "final"; 00795 } 00796 00797 return out << "**invalid state(" << (int)state << ")**"; 00798 } 00799