Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

direct/src/interval/cInterval.cxx

Go to the documentation of this file.
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 

Generated on Fri May 2 01:37:33 2003 for Direct by doxygen1.3