00001 // Filename: cInterval.cxx 00002 // Created by: drose (27Aug02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "cInterval.h" 00020 #include "cIntervalManager.h" 00021 #include "indent.h" 00022 #include "clockObject.h" 00023 #include "event.h" 00024 #include "eventQueue.h" 00025 #include <math.h> 00026 00027 TypeHandle CInterval::_type_handle; 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // Function: CInterval::Constructor 00031 // Access: Public 00032 // Description: 00033 //////////////////////////////////////////////////////////////////// 00034 CInterval:: 00035 CInterval(const string &name, double duration, bool open_ended) : 00036 _state(S_initial), 00037 _curr_t(0.0), 00038 _name(name), 00039 _duration(duration), 00040 _open_ended(open_ended), 00041 _dirty(false) 00042 { 00043 _auto_pause = false; 00044 _auto_finish = false; 00045 _wants_t_callback = false; 00046 _last_t_callback = -1.0; 00047 _manager = CIntervalManager::get_global_ptr(); 00048 _clock_start = 0.0; 00049 _start_t = 0.0; 00050 _end_t = _duration; 00051 _start_t_at_start = true; 00052 _end_t_at_end = true; 00053 _play_rate = 1.0; 00054 _do_loop = false; 00055 _loop_count = 0; 00056 nassertv(_duration >= 0.0); 00057 } 00058 00059 //////////////////////////////////////////////////////////////////// 00060 // Function: CInterval::set_t 00061 // Access: Published 00062 // Description: Explicitly sets the time within the interval. 00063 // Normally, you would use start() .. finish() to let 00064 // the time play normally, but this may be used to set 00065 // the time to some particular value. 00066 //////////////////////////////////////////////////////////////////// 00067 void CInterval:: 00068 set_t(double t) { 00069 t = min(max(t, 0.0), get_duration()); 00070 switch (get_state()) { 00071 case S_initial: 00072 priv_initialize(t); 00073 break; 00074 00075 case S_final: 00076 priv_reverse_initialize(t); 00077 break; 00078 00079 default: 00080 priv_step(t); 00081 } 00082 } 00083 00084 //////////////////////////////////////////////////////////////////// 00085 // Function: CInterval::start 00086 // Access: Published 00087 // Description: Starts the interval playing by registering it with 00088 // the current CIntervalManager. The interval will 00089 // play to the end and stop. 00090 // 00091 // If end_t is less than zero, it indicates the end of 00092 // the interval. 00093 //////////////////////////////////////////////////////////////////// 00094 void CInterval:: 00095 start(double start_t, double end_t, double play_rate) { 00096 setup_play(start_t, end_t, play_rate, false); 00097 _manager->add_c_interval(this, false); 00098 } 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: CInterval::loop 00102 // Access: Published 00103 // Description: Starts the interval playing by registering it with 00104 // the current CIntervalManager. The interval will 00105 // play until it is interrupted with finish() or 00106 // pause(), looping back to start_t when it reaches 00107 // end_t. 00108 // 00109 // If end_t is less than zero, it indicates the end of 00110 // the interval. 00111 //////////////////////////////////////////////////////////////////// 00112 void CInterval:: 00113 loop(double start_t, double end_t, double play_rate) { 00114 setup_play(start_t, end_t, play_rate, true); 00115 _manager->add_c_interval(this, false); 00116 } 00117 00118 //////////////////////////////////////////////////////////////////// 00119 // Function: CInterval::pause 00120 // Access: Published 00121 // Description: Stops the interval from playing but leaves it in its 00122 // current state. It may later be resumed from this 00123 // point by calling resume(). 00124 //////////////////////////////////////////////////////////////////// 00125 double CInterval:: 00126 pause() { 00127 if (get_state() == S_started) { 00128 priv_interrupt(); 00129 } 00130 int index = _manager->find_c_interval(this->get_name()); 00131 if (index >= 0) { 00132 _manager->remove_c_interval(index); 00133 } 00134 return get_t(); 00135 } 00136 00137 //////////////////////////////////////////////////////////////////// 00138 // Function: CInterval::resume 00139 // Access: Published 00140 // Description: Restarts the interval from its current point after a 00141 // previous call to pause(). 00142 //////////////////////////////////////////////////////////////////// 00143 void CInterval:: 00144 resume() { 00145 setup_resume(); 00146 _manager->add_c_interval(this, false); 00147 } 00148 00149 //////////////////////////////////////////////////////////////////// 00150 // Function: CInterval::resume 00151 // Access: Published 00152 // Description: Restarts the interval from the indicated point after a 00153 // previous call to pause(). 00154 //////////////////////////////////////////////////////////////////// 00155 void CInterval:: 00156 resume(double start_t) { 00157 set_t(start_t); 00158 setup_resume(); 00159 _manager->add_c_interval(this, false); 00160 } 00161 00162 //////////////////////////////////////////////////////////////////// 00163 // Function: CInterval::finish 00164 // Access: Published 00165 // Description: Stops the interval from playing and sets it to its 00166 // final state. 00167 //////////////////////////////////////////////////////////////////// 00168 void CInterval:: 00169 finish() { 00170 switch (get_state()) { 00171 case S_initial: 00172 priv_instant(); 00173 break; 00174 00175 case S_final: 00176 break; 00177 00178 default: 00179 priv_finalize(); 00180 } 00181 00182 int index = _manager->find_c_interval(this->get_name()); 00183 if (index >= 0) { 00184 _manager->remove_c_interval(index); 00185 } 00186 } 00187 00188 //////////////////////////////////////////////////////////////////// 00189 // Function: CInterval::is_playing 00190 // Access: Published 00191 // Description: Returns true if the interval is currently playing, 00192 // false otherwise. 00193 //////////////////////////////////////////////////////////////////// 00194 bool CInterval:: 00195 is_playing() const { 00196 int index = _manager->find_c_interval(this->get_name()); 00197 return (index >= 0); 00198 } 00199 00200 //////////////////////////////////////////////////////////////////// 00201 // Function: CInterval::priv_do_event 00202 // Access: Published 00203 // Description: Calls the appropriate event function indicated by the 00204 // EventType. 00205 //////////////////////////////////////////////////////////////////// 00206 void CInterval:: 00207 priv_do_event(double t, EventType event) { 00208 switch (event) { 00209 case ET_initialize: 00210 priv_initialize(t); 00211 return; 00212 00213 case ET_instant: 00214 priv_instant(); 00215 return; 00216 00217 case ET_step: 00218 priv_step(t); 00219 return; 00220 00221 case ET_finalize: 00222 priv_finalize(); 00223 return; 00224 00225 case ET_reverse_initialize: 00226 priv_reverse_initialize(t); 00227 return; 00228 00229 case ET_reverse_instant: 00230 priv_reverse_instant(); 00231 return; 00232 00233 case ET_reverse_finalize: 00234 priv_reverse_finalize(); 00235 return; 00236 00237 case ET_interrupt: 00238 priv_interrupt(); 00239 return; 00240 } 00241 00242 interval_cat.warning() 00243 << "Invalid event type: " << (int)event << "\n"; 00244 } 00245 00246 //////////////////////////////////////////////////////////////////// 00247 // Function: CInterval::priv_initialize 00248 // Access: Published, Virtual 00249 // Description: This replaces the first call to priv_step(), and indicates 00250 // that the interval has just begun. This may be 00251 // overridden by derived classes that need to do some 00252 // explicit initialization on the first call. 00253 //////////////////////////////////////////////////////////////////// 00254 void CInterval:: 00255 priv_initialize(double t) { 00256 check_stopped(get_class_type(), "priv_initialize"); 00257 recompute(); 00258 _state = S_started; 00259 priv_step(t); 00260 } 00261 00262 //////////////////////////////////////////////////////////////////// 00263 // Function: CInterval::priv_instant 00264 // Access: Published, Virtual 00265 // Description: This is called in lieu of priv_initialize() .. priv_step() 00266 // .. priv_finalize(), when everything is to happen within 00267 // one frame. The interval should initialize itself, 00268 // then leave itself in the final state. 00269 //////////////////////////////////////////////////////////////////// 00270 void CInterval:: 00271 priv_instant() { 00272 check_stopped(get_class_type(), "priv_instant"); 00273 recompute(); 00274 _state = S_started; 00275 priv_step(get_duration()); 00276 _state = S_final; 00277 interval_done(); 00278 } 00279 00280 //////////////////////////////////////////////////////////////////// 00281 // Function: CInterval::priv_step 00282 // Access: Published, Virtual 00283 // Description: Advances the time on the interval. The time may 00284 // either increase (the normal case) or decrease 00285 // (e.g. if the interval is being played by a slider). 00286 //////////////////////////////////////////////////////////////////// 00287 void CInterval:: 00288 priv_step(double t) { 00289 check_started(get_class_type(), "priv_step"); 00290 _state = S_started; 00291 _curr_t = t; 00292 } 00293 00294 //////////////////////////////////////////////////////////////////// 00295 // Function: CInterval::priv_finalize 00296 // Access: Published, Virtual 00297 // Description: This is called to stop an interval, forcing it to 00298 // whatever state it would be after it played all the 00299 // way through. It's generally invoked by 00300 // set_final_t(). 00301 //////////////////////////////////////////////////////////////////// 00302 void CInterval:: 00303 priv_finalize() { 00304 check_started(get_class_type(), "priv_finalize"); 00305 double duration = get_duration(); 00306 priv_step(duration); 00307 _state = S_final; 00308 interval_done(); 00309 } 00310 00311 //////////////////////////////////////////////////////////////////// 00312 // Function: CInterval::reverse_initialize 00313 // Access: Published, Virtual 00314 // Description: Similar to priv_initialize(), but this is called when the 00315 // interval is being played backwards; it indicates that 00316 // the interval should start at the finishing state and 00317 // undo any intervening intervals. 00318 //////////////////////////////////////////////////////////////////// 00319 void CInterval:: 00320 priv_reverse_initialize(double t) { 00321 check_stopped(get_class_type(), "priv_reverse_initialize"); 00322 recompute(); 00323 _state = S_started; 00324 priv_step(t); 00325 } 00326 00327 //////////////////////////////////////////////////////////////////// 00328 // Function: CInterval::reverse_instant 00329 // Access: Published, Virtual 00330 // Description: This is called in lieu of priv_reverse_initialize() 00331 // .. priv_step() .. priv_reverse_finalize(), when everything is 00332 // to happen within one frame. The interval should 00333 // initialize itself, then leave itself in the initial 00334 // state. 00335 //////////////////////////////////////////////////////////////////// 00336 void CInterval:: 00337 priv_reverse_instant() { 00338 check_stopped(get_class_type(), "priv_reverse_instant"); 00339 recompute(); 00340 _state = S_started; 00341 priv_step(0.0); 00342 _state = S_initial; 00343 } 00344 00345 //////////////////////////////////////////////////////////////////// 00346 // Function: CInterval::reverse_finalize 00347 // Access: Published, Virtual 00348 // Description: Called generally following a priv_reverse_initialize(), 00349 // this indicates the interval should set itself to the 00350 // initial state. 00351 //////////////////////////////////////////////////////////////////// 00352 void CInterval:: 00353 priv_reverse_finalize() { 00354 check_started(get_class_type(), "priv_reverse_finalize"); 00355 priv_step(0.0); 00356 _state = S_initial; 00357 } 00358 00359 //////////////////////////////////////////////////////////////////// 00360 // Function: CInterval::priv_interrupt 00361 // Access: Published, Virtual 00362 // Description: This is called while the interval is playing to 00363 // indicate that it is about to be interrupted; that is, 00364 // priv_step() will not be called for a length of time. But 00365 // the interval should remain in its current state in 00366 // anticipation of being eventually restarted when the 00367 // calls to priv_step() eventually resume. 00368 // 00369 // The purpose of this function is to allow self-running 00370 // intervals like sound intervals to stop the actual 00371 // sound playback during the pause. 00372 //////////////////////////////////////////////////////////////////// 00373 void CInterval:: 00374 priv_interrupt() { 00375 check_started(get_class_type(), "priv_interrupt"); 00376 _state = S_paused; 00377 } 00378 00379 //////////////////////////////////////////////////////////////////// 00380 // Function: CInterval::output 00381 // Access: Published, Virtual 00382 // Description: 00383 //////////////////////////////////////////////////////////////////// 00384 void CInterval:: 00385 output(ostream &out) const { 00386 out << get_name(); 00387 if (get_duration() != 0.0) { 00388 out << " dur " << get_duration(); 00389 } 00390 } 00391 00392 //////////////////////////////////////////////////////////////////// 00393 // Function: CInterval::write 00394 // Access: Published, Virtual 00395 // Description: 00396 //////////////////////////////////////////////////////////////////// 00397 void CInterval:: 00398 write(ostream &out, int indent_level) const { 00399 indent(out, indent_level) << *this << "\n"; 00400 } 00401 00402 //////////////////////////////////////////////////////////////////// 00403 // Function: CInterval::setup_play 00404 // Access: Published 00405 // Description: Called to prepare the interval for automatic timed 00406 // playback, e.g. via a Python task. The interval will 00407 // be played from start_t to end_t, at a time factor 00408 // specified by play_rate. start_t must always be less 00409 // than end_t (except for the exception for end_t == -1, 00410 // below), but if play_rate is negative the interval 00411 // will be played backwards. 00412 // 00413 // Specify end_t of -1 to play the entire interval from 00414 // start_t. 00415 // 00416 // Call step_play() repeatedly to execute the interval. 00417 //////////////////////////////////////////////////////////////////// 00418 void CInterval:: 00419 setup_play(double start_t, double end_t, double play_rate, bool do_loop) { 00420 nassertv(start_t < end_t || end_t < 0.0); 00421 nassertv(play_rate != 0.0); 00422 00423 double duration = get_duration(); 00424 00425 if (start_t <= 0.0) { 00426 _start_t = 0.0; 00427 _start_t_at_start = true; 00428 } else if (start_t > duration) { 00429 _start_t = duration; 00430 _start_t_at_start = false; 00431 } else { 00432 _start_t = start_t; 00433 _start_t_at_start = false; 00434 } 00435 if (end_t < 0.0 || end_t >= duration) { 00436 _end_t = duration; 00437 _end_t_at_end = true; 00438 } else { 00439 _end_t = end_t; 00440 _end_t_at_end = false; 00441 } 00442 00443 _clock_start = ClockObject::get_global_clock()->get_frame_time(); 00444 _play_rate = play_rate; 00445 _do_loop = do_loop; 00446 _loop_count = 0; 00447 } 00448 00449 //////////////////////////////////////////////////////////////////// 00450 // Function: CInterval::setup_resume 00451 // Access: Published 00452 // Description: Called to prepare the interval for restarting at the 00453 // current point within the interval after an 00454 // interruption. 00455 //////////////////////////////////////////////////////////////////// 00456 void CInterval:: 00457 setup_resume() { 00458 double now = ClockObject::get_global_clock()->get_frame_time(); 00459 if (_play_rate > 0.0) { 00460 _clock_start = now - ((get_t() - _start_t) / _play_rate); 00461 00462 } else if (_play_rate < 0.0) { 00463 _clock_start = now - ((get_t() - _end_t) / _play_rate); 00464 } 00465 _loop_count = 0; 00466 } 00467 00468 //////////////////////////////////////////////////////////////////// 00469 // Function: CInterval::step_play 00470 // Access: Published 00471 // Description: Should be called once per frame to execute the 00472 // automatic timed playback begun with setup_play(). 00473 // 00474 // Returns true if the interval should continue, false 00475 // if it is done and should stop. 00476 //////////////////////////////////////////////////////////////////// 00477 bool CInterval:: 00478 step_play() { 00479 double now = ClockObject::get_global_clock()->get_frame_time(); 00480 00481 if (_play_rate >= 0.0) { 00482 double t = (now - _clock_start) * _play_rate + _start_t; 00483 00484 if (_end_t_at_end) { 00485 _end_t = get_duration(); 00486 } 00487 00488 if (t < _end_t) { 00489 // In the middle of the interval, not a problem. 00490 if (is_stopped()) { 00491 priv_initialize(t); 00492 } else { 00493 priv_step(t); 00494 } 00495 00496 } else { 00497 // Past the ending point; time to finalize. 00498 if (_end_t_at_end) { 00499 // Only finalize if the playback cycle includes the whole 00500 // interval. 00501 if (is_stopped()) { 00502 if (get_open_ended() || _loop_count != 0) { 00503 priv_instant(); 00504 } 00505 } else { 00506 priv_finalize(); 00507 } 00508 } else { 00509 if (is_stopped()) { 00510 priv_initialize(_end_t); 00511 } else { 00512 priv_step(_end_t); 00513 } 00514 } 00515 00516 // Advance the clock for the next loop cycle. We might have to 00517 // advance multiple times if we skipped several cycles in the past 00518 // frame. 00519 00520 if (_end_t == _start_t) { 00521 // If the interval has no length, we loop exactly once each 00522 // time. 00523 _loop_count++; 00524 00525 } else { 00526 // Otherwise, figure out how many loops we need to skip. 00527 double time_per_loop = (_end_t - _start_t) / _play_rate; 00528 double num_loops = floor((now - _clock_start) / time_per_loop); 00529 _loop_count += (int)num_loops; 00530 _clock_start += num_loops * time_per_loop; 00531 } 00532 } 00533 00534 } else { 00535 // Playing backwards. 00536 double t = (now - _clock_start) * _play_rate + _end_t; 00537 00538 if (t >= _start_t) { 00539 // In the middle of the interval, not a problem. 00540 if (is_stopped()) { 00541 priv_reverse_initialize(t); 00542 } else { 00543 priv_step(t); 00544 } 00545 00546 } else { 00547 // Past the ending point; time to finalize. 00548 if (_start_t_at_start) { 00549 // Only finalize if the playback cycle includes the whole 00550 // interval. 00551 if (is_stopped()) { 00552 if (get_open_ended() || _loop_count != 0) { 00553 priv_reverse_instant(); 00554 } 00555 } else { 00556 priv_reverse_finalize(); 00557 } 00558 } else { 00559 if (is_stopped()) { 00560 priv_reverse_initialize(_start_t); 00561 } else { 00562 priv_step(_start_t); 00563 } 00564 } 00565 00566 // Advance the clock for the next loop cycle. We might have to 00567 // advance multiple times if we skipped several cycles in the past 00568 // frame. 00569 00570 if (_end_t == _start_t) { 00571 // If the interval has no length, we loop exactly once each 00572 // time. 00573 _loop_count++; 00574 00575 } else { 00576 // Otherwise, figure out how many loops we need to skip. 00577 double time_per_loop = (_end_t - _start_t) / -_play_rate; 00578 double num_loops = floor((now - _clock_start) / time_per_loop); 00579 _loop_count += (int)num_loops; 00580 _clock_start += num_loops * time_per_loop; 00581 } 00582 } 00583 } 00584 00585 return (_loop_count == 0 || _do_loop); 00586 } 00587 00588 //////////////////////////////////////////////////////////////////// 00589 // Function: CInterval::mark_dirty 00590 // Access: Public 00591 // Description: Called by a derived class to indicate the interval has 00592 // been changed internally and must be recomputed before 00593 // its duration may be returned. 00594 //////////////////////////////////////////////////////////////////// 00595 void CInterval:: 00596 mark_dirty() { 00597 if (!_dirty) { 00598 _dirty = true; 00599 Parents::iterator pi; 00600 for (pi = _parents.begin(); pi != _parents.end(); ++pi) { 00601 (*pi)->mark_dirty(); 00602 } 00603 } 00604 } 00605 00606 //////////////////////////////////////////////////////////////////// 00607 // Function: CInterval::interval_done 00608 // Access: Protected 00609 // Description: Called internally whenever the interval reaches its 00610 // final state. 00611 //////////////////////////////////////////////////////////////////// 00612 void CInterval:: 00613 interval_done() { 00614 if (!_done_event.empty()) { 00615 _manager->get_event_queue()->queue_event(new Event(_done_event)); 00616 } 00617 } 00618 00619 //////////////////////////////////////////////////////////////////// 00620 // Function: CInterval::do_recompute 00621 // Access: Protected, Virtual 00622 // Description: Does whatever processing is necessary to recompute 00623 // the interval after a call to mark_dirty() has 00624 // indicated a recomputation is necessary. 00625 //////////////////////////////////////////////////////////////////// 00626 void CInterval:: 00627 do_recompute() { 00628 _dirty = false; 00629 } 00630 00631 ostream & 00632 operator << (ostream &out, CInterval::State state) { 00633 switch (state) { 00634 case CInterval::S_initial: 00635 return out << "initial"; 00636 00637 case CInterval::S_started: 00638 return out << "started"; 00639 00640 case CInterval::S_paused: 00641 return out << "paused"; 00642 00643 case CInterval::S_final: 00644 return out << "final"; 00645 } 00646 00647 return out << "**invalid state(" << (int)state << ")**"; 00648 } 00649