Panda3D

cInterval.cxx

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 
 All Classes Functions Variables Enumerations