|
@@ -17,6 +17,7 @@
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include "cInterval.h"
|
|
#include "cInterval.h"
|
|
|
|
|
+#include "cIntervalManager.h"
|
|
|
#include "indent.h"
|
|
#include "indent.h"
|
|
|
#include "clockObject.h"
|
|
#include "clockObject.h"
|
|
|
#include "throw_event.h"
|
|
#include "throw_event.h"
|
|
@@ -38,198 +39,157 @@ CInterval(const string &name, double duration, bool open_ended) :
|
|
|
_open_ended(open_ended),
|
|
_open_ended(open_ended),
|
|
|
_dirty(false)
|
|
_dirty(false)
|
|
|
{
|
|
{
|
|
|
|
|
+ _interruptible = false;
|
|
|
|
|
+ _manager = CIntervalManager::get_global_ptr();
|
|
|
_clock_start = 0.0;
|
|
_clock_start = 0.0;
|
|
|
_start_t = 0.0;
|
|
_start_t = 0.0;
|
|
|
_end_t = _duration;
|
|
_end_t = _duration;
|
|
|
_start_t_at_start = true;
|
|
_start_t_at_start = true;
|
|
|
_end_t_at_end = true;
|
|
_end_t_at_end = true;
|
|
|
_play_rate = 1.0;
|
|
_play_rate = 1.0;
|
|
|
|
|
+ _do_loop = false;
|
|
|
_loop_count = 0;
|
|
_loop_count = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: CInterval::setup_play
|
|
|
|
|
|
|
+// Function: CInterval::set_t
|
|
|
// Access: Published
|
|
// Access: Published
|
|
|
-// Description: Called to prepare the interval for automatic timed
|
|
|
|
|
-// playback, e.g. via a Python task. The interval will
|
|
|
|
|
-// be played from start_t to end_t, at a time factor
|
|
|
|
|
-// specified by play_rate. start_t must always be less
|
|
|
|
|
-// than end_t (except for the exception for end_t == -1,
|
|
|
|
|
-// below), but if play_rate is negative the interval
|
|
|
|
|
-// will be played backwards.
|
|
|
|
|
-//
|
|
|
|
|
-// Specify end_t of -1 to play the entire interval from
|
|
|
|
|
-// start_t.
|
|
|
|
|
-//
|
|
|
|
|
-// Call step_play() repeatedly to execute the interval.
|
|
|
|
|
|
|
+// Description: Explicitly sets the time within the interval.
|
|
|
|
|
+// Normally, you would use start() .. finish() to let
|
|
|
|
|
+// the time play normally, but this may be used to set
|
|
|
|
|
+// the time to some particular value.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void CInterval::
|
|
void CInterval::
|
|
|
-setup_play(double start_t, double end_t, double play_rate) {
|
|
|
|
|
- nassertv(start_t < end_t || end_t < 0.0);
|
|
|
|
|
- nassertv(play_rate != 0.0);
|
|
|
|
|
|
|
+set_t(double t) {
|
|
|
|
|
+ t = min(max(t, 0.0), get_duration());
|
|
|
|
|
+ switch (get_state()) {
|
|
|
|
|
+ case S_initial:
|
|
|
|
|
+ priv_initialize(t);
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- double duration = get_duration();
|
|
|
|
|
|
|
+ case S_final:
|
|
|
|
|
+ priv_reverse_initialize(t);
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- if (start_t <= 0.0) {
|
|
|
|
|
- _start_t = 0.0;
|
|
|
|
|
- _start_t_at_start = true;
|
|
|
|
|
- } else if (start_t > duration) {
|
|
|
|
|
- _start_t = duration;
|
|
|
|
|
- _start_t_at_start = false;
|
|
|
|
|
- } else {
|
|
|
|
|
- _start_t = start_t;
|
|
|
|
|
- _start_t_at_start = false;
|
|
|
|
|
- }
|
|
|
|
|
- if (end_t < 0.0 || end_t >= duration) {
|
|
|
|
|
- _end_t = duration;
|
|
|
|
|
- _end_t_at_end = true;
|
|
|
|
|
- } else {
|
|
|
|
|
- _end_t = end_t;
|
|
|
|
|
- _end_t_at_end = false;
|
|
|
|
|
|
|
+ default:
|
|
|
|
|
+ priv_step(t);
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- _clock_start = ClockObject::get_global_clock()->get_frame_time();
|
|
|
|
|
- _play_rate = play_rate;
|
|
|
|
|
- _loop_count = 0;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::start
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Starts the interval playing by registering it with
|
|
|
|
|
+// the current CIntervalManager. The interval will
|
|
|
|
|
+// play to the end and stop.
|
|
|
|
|
+//
|
|
|
|
|
+// If end_t is less than zero, it indicates the end of
|
|
|
|
|
+// the interval.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CInterval::
|
|
|
|
|
+start(double start_t, double end_t, double play_rate) {
|
|
|
|
|
+ setup_play(start_t, end_t, play_rate, false);
|
|
|
|
|
+ _manager->add_c_interval(this, false);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: CInterval::setup_resume
|
|
|
|
|
|
|
+// Function: CInterval::loop
|
|
|
// Access: Published
|
|
// Access: Published
|
|
|
-// Description: Called to prepare the interval for restarting at the
|
|
|
|
|
-// current point within the interval after an
|
|
|
|
|
-// interruption.
|
|
|
|
|
|
|
+// Description: Starts the interval playing by registering it with
|
|
|
|
|
+// the current CIntervalManager. The interval will
|
|
|
|
|
+// play until it is interrupted with finish() or
|
|
|
|
|
+// pause(), looping back to start_t when it reaches
|
|
|
|
|
+// end_t.
|
|
|
|
|
+//
|
|
|
|
|
+// If end_t is less than zero, it indicates the end of
|
|
|
|
|
+// the interval.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void CInterval::
|
|
void CInterval::
|
|
|
-setup_resume() {
|
|
|
|
|
- double now = ClockObject::get_global_clock()->get_frame_time();
|
|
|
|
|
- if (_play_rate > 0.0) {
|
|
|
|
|
- _clock_start = now - ((get_t() - _start_t) / _play_rate);
|
|
|
|
|
|
|
+loop(double start_t, double end_t, double play_rate) {
|
|
|
|
|
+ setup_play(start_t, end_t, play_rate, true);
|
|
|
|
|
+ _manager->add_c_interval(this, false);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- } else if (_play_rate < 0.0) {
|
|
|
|
|
- _clock_start = now - ((get_t() - _end_t) / _play_rate);
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::pause
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Stops the interval from playing but leaves it in its
|
|
|
|
|
+// current state. It may later be resumed from this
|
|
|
|
|
+// point by calling resume().
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+double CInterval::
|
|
|
|
|
+pause() {
|
|
|
|
|
+ if (get_state() == S_started) {
|
|
|
|
|
+ priv_interrupt();
|
|
|
}
|
|
}
|
|
|
- _loop_count = 0;
|
|
|
|
|
|
|
+ int index = _manager->find_c_interval(this->get_name());
|
|
|
|
|
+ if (index >= 0) {
|
|
|
|
|
+ _manager->remove_c_interval(index);
|
|
|
|
|
+ }
|
|
|
|
|
+ return get_t();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: CInterval::step_play
|
|
|
|
|
|
|
+// Function: CInterval::resume
|
|
|
// Access: Published
|
|
// Access: Published
|
|
|
-// Description: Should be called once per frame to execute the
|
|
|
|
|
-// automatic timed playback begun with setup_play().
|
|
|
|
|
-// The return value is the number of times the interval
|
|
|
|
|
-// is about to repeat; stop when this reaches one to
|
|
|
|
|
-// play the interval through exactly once.
|
|
|
|
|
|
|
+// Description: Restarts the interval from its current point after a
|
|
|
|
|
+// previous call to pause().
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-int CInterval::
|
|
|
|
|
-step_play() {
|
|
|
|
|
- double now = ClockObject::get_global_clock()->get_frame_time();
|
|
|
|
|
|
|
+void CInterval::
|
|
|
|
|
+resume() {
|
|
|
|
|
+ setup_resume();
|
|
|
|
|
+ _manager->add_c_interval(this, false);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if (_play_rate >= 0.0) {
|
|
|
|
|
- double t = (now - _clock_start) * _play_rate + _start_t;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::resume
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Restarts the interval from the indicated point after a
|
|
|
|
|
+// previous call to pause().
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CInterval::
|
|
|
|
|
+resume(double start_t) {
|
|
|
|
|
+ set_t(start_t);
|
|
|
|
|
+ setup_resume();
|
|
|
|
|
+ _manager->add_c_interval(this, false);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if (_end_t_at_end) {
|
|
|
|
|
- _end_t = get_duration();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (t < _end_t) {
|
|
|
|
|
- // In the middle of the interval, not a problem.
|
|
|
|
|
- if (is_stopped()) {
|
|
|
|
|
- priv_initialize(t);
|
|
|
|
|
- } else {
|
|
|
|
|
- priv_step(t);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // Past the ending point; time to finalize.
|
|
|
|
|
- if (_end_t_at_end) {
|
|
|
|
|
- // Only finalize if the playback cycle includes the whole
|
|
|
|
|
- // interval.
|
|
|
|
|
- if (is_stopped()) {
|
|
|
|
|
- if (get_open_ended() || _loop_count != 0) {
|
|
|
|
|
- priv_instant();
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- priv_finalize();
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if (is_stopped()) {
|
|
|
|
|
- priv_initialize(_end_t);
|
|
|
|
|
- } else {
|
|
|
|
|
- priv_step(_end_t);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Advance the clock for the next loop cycle. We might have to
|
|
|
|
|
- // advance multiple times if we skipped several cycles in the past
|
|
|
|
|
- // frame.
|
|
|
|
|
-
|
|
|
|
|
- if (_end_t == _start_t) {
|
|
|
|
|
- // If the interval has no length, we loop exactly once each
|
|
|
|
|
- // time.
|
|
|
|
|
- _loop_count++;
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // Otherwise, figure out how many loops we need to skip.
|
|
|
|
|
- double time_per_loop = (_end_t - _start_t) / _play_rate;
|
|
|
|
|
- double num_loops = floor((now - _clock_start) / time_per_loop);
|
|
|
|
|
- _loop_count += (int)num_loops;
|
|
|
|
|
- _clock_start += num_loops * time_per_loop;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::finish
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Stops the interval from playing and sets it to its
|
|
|
|
|
+// final state.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CInterval::
|
|
|
|
|
+finish() {
|
|
|
|
|
+ switch (get_state()) {
|
|
|
|
|
+ case S_initial:
|
|
|
|
|
+ priv_instant();
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- } else {
|
|
|
|
|
- // Playing backwards.
|
|
|
|
|
- double t = (now - _clock_start) * _play_rate + _end_t;
|
|
|
|
|
-
|
|
|
|
|
- if (t >= _start_t) {
|
|
|
|
|
- // In the middle of the interval, not a problem.
|
|
|
|
|
- if (is_stopped()) {
|
|
|
|
|
- priv_reverse_initialize(t);
|
|
|
|
|
- } else {
|
|
|
|
|
- priv_step(t);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // Past the ending point; time to finalize.
|
|
|
|
|
- if (_start_t_at_start) {
|
|
|
|
|
- // Only finalize if the playback cycle includes the whole
|
|
|
|
|
- // interval.
|
|
|
|
|
- if (is_stopped()) {
|
|
|
|
|
- if (get_open_ended() || _loop_count != 0) {
|
|
|
|
|
- priv_reverse_instant();
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- priv_reverse_finalize();
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if (is_stopped()) {
|
|
|
|
|
- priv_reverse_initialize(_start_t);
|
|
|
|
|
- } else {
|
|
|
|
|
- priv_step(_start_t);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Advance the clock for the next loop cycle. We might have to
|
|
|
|
|
- // advance multiple times if we skipped several cycles in the past
|
|
|
|
|
- // frame.
|
|
|
|
|
-
|
|
|
|
|
- if (_end_t == _start_t) {
|
|
|
|
|
- // If the interval has no length, we loop exactly once each
|
|
|
|
|
- // time.
|
|
|
|
|
- _loop_count++;
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // Otherwise, figure out how many loops we need to skip.
|
|
|
|
|
- double time_per_loop = (_end_t - _start_t) / -_play_rate;
|
|
|
|
|
- double num_loops = floor((now - _clock_start) / time_per_loop);
|
|
|
|
|
- _loop_count += (int)num_loops;
|
|
|
|
|
- _clock_start += num_loops * time_per_loop;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ case S_final:
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ priv_finalize();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int index = _manager->find_c_interval(this->get_name());
|
|
|
|
|
+ if (index >= 0) {
|
|
|
|
|
+ _manager->remove_c_interval(index);
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- return _loop_count;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::is_playing
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Returns true if the interval is currently playing,
|
|
|
|
|
+// false otherwise.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+bool CInterval::
|
|
|
|
|
+is_playing() const {
|
|
|
|
|
+ int index = _manager->find_c_interval(this->get_name());
|
|
|
|
|
+ return (index >= 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
@@ -434,6 +394,192 @@ write(ostream &out, int indent_level) const {
|
|
|
indent(out, indent_level) << *this << "\n";
|
|
indent(out, indent_level) << *this << "\n";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::setup_play
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Called to prepare the interval for automatic timed
|
|
|
|
|
+// playback, e.g. via a Python task. The interval will
|
|
|
|
|
+// be played from start_t to end_t, at a time factor
|
|
|
|
|
+// specified by play_rate. start_t must always be less
|
|
|
|
|
+// than end_t (except for the exception for end_t == -1,
|
|
|
|
|
+// below), but if play_rate is negative the interval
|
|
|
|
|
+// will be played backwards.
|
|
|
|
|
+//
|
|
|
|
|
+// Specify end_t of -1 to play the entire interval from
|
|
|
|
|
+// start_t.
|
|
|
|
|
+//
|
|
|
|
|
+// Call step_play() repeatedly to execute the interval.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CInterval::
|
|
|
|
|
+setup_play(double start_t, double end_t, double play_rate, bool do_loop) {
|
|
|
|
|
+ nassertv(start_t < end_t || end_t < 0.0);
|
|
|
|
|
+ nassertv(play_rate != 0.0);
|
|
|
|
|
+
|
|
|
|
|
+ double duration = get_duration();
|
|
|
|
|
+
|
|
|
|
|
+ if (start_t <= 0.0) {
|
|
|
|
|
+ _start_t = 0.0;
|
|
|
|
|
+ _start_t_at_start = true;
|
|
|
|
|
+ } else if (start_t > duration) {
|
|
|
|
|
+ _start_t = duration;
|
|
|
|
|
+ _start_t_at_start = false;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _start_t = start_t;
|
|
|
|
|
+ _start_t_at_start = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (end_t < 0.0 || end_t >= duration) {
|
|
|
|
|
+ _end_t = duration;
|
|
|
|
|
+ _end_t_at_end = true;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _end_t = end_t;
|
|
|
|
|
+ _end_t_at_end = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _clock_start = ClockObject::get_global_clock()->get_frame_time();
|
|
|
|
|
+ _play_rate = play_rate;
|
|
|
|
|
+ _do_loop = do_loop;
|
|
|
|
|
+ _loop_count = 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::setup_resume
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Called to prepare the interval for restarting at the
|
|
|
|
|
+// current point within the interval after an
|
|
|
|
|
+// interruption.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CInterval::
|
|
|
|
|
+setup_resume() {
|
|
|
|
|
+ double now = ClockObject::get_global_clock()->get_frame_time();
|
|
|
|
|
+ if (_play_rate > 0.0) {
|
|
|
|
|
+ _clock_start = now - ((get_t() - _start_t) / _play_rate);
|
|
|
|
|
+
|
|
|
|
|
+ } else if (_play_rate < 0.0) {
|
|
|
|
|
+ _clock_start = now - ((get_t() - _end_t) / _play_rate);
|
|
|
|
|
+ }
|
|
|
|
|
+ _loop_count = 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: CInterval::step_play
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Should be called once per frame to execute the
|
|
|
|
|
+// automatic timed playback begun with setup_play().
|
|
|
|
|
+//
|
|
|
|
|
+// Returns true if the interval should continue, false
|
|
|
|
|
+// if it is done and should stop.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+bool CInterval::
|
|
|
|
|
+step_play() {
|
|
|
|
|
+ double now = ClockObject::get_global_clock()->get_frame_time();
|
|
|
|
|
+
|
|
|
|
|
+ if (_play_rate >= 0.0) {
|
|
|
|
|
+ double t = (now - _clock_start) * _play_rate + _start_t;
|
|
|
|
|
+
|
|
|
|
|
+ if (_end_t_at_end) {
|
|
|
|
|
+ _end_t = get_duration();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (t < _end_t) {
|
|
|
|
|
+ // In the middle of the interval, not a problem.
|
|
|
|
|
+ if (is_stopped()) {
|
|
|
|
|
+ priv_initialize(t);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ priv_step(t);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Past the ending point; time to finalize.
|
|
|
|
|
+ if (_end_t_at_end) {
|
|
|
|
|
+ // Only finalize if the playback cycle includes the whole
|
|
|
|
|
+ // interval.
|
|
|
|
|
+ if (is_stopped()) {
|
|
|
|
|
+ if (get_open_ended() || _loop_count != 0) {
|
|
|
|
|
+ priv_instant();
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ priv_finalize();
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (is_stopped()) {
|
|
|
|
|
+ priv_initialize(_end_t);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ priv_step(_end_t);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Advance the clock for the next loop cycle. We might have to
|
|
|
|
|
+ // advance multiple times if we skipped several cycles in the past
|
|
|
|
|
+ // frame.
|
|
|
|
|
+
|
|
|
|
|
+ if (_end_t == _start_t) {
|
|
|
|
|
+ // If the interval has no length, we loop exactly once each
|
|
|
|
|
+ // time.
|
|
|
|
|
+ _loop_count++;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Otherwise, figure out how many loops we need to skip.
|
|
|
|
|
+ double time_per_loop = (_end_t - _start_t) / _play_rate;
|
|
|
|
|
+ double num_loops = floor((now - _clock_start) / time_per_loop);
|
|
|
|
|
+ _loop_count += (int)num_loops;
|
|
|
|
|
+ _clock_start += num_loops * time_per_loop;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Playing backwards.
|
|
|
|
|
+ double t = (now - _clock_start) * _play_rate + _end_t;
|
|
|
|
|
+
|
|
|
|
|
+ if (t >= _start_t) {
|
|
|
|
|
+ // In the middle of the interval, not a problem.
|
|
|
|
|
+ if (is_stopped()) {
|
|
|
|
|
+ priv_reverse_initialize(t);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ priv_step(t);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Past the ending point; time to finalize.
|
|
|
|
|
+ if (_start_t_at_start) {
|
|
|
|
|
+ // Only finalize if the playback cycle includes the whole
|
|
|
|
|
+ // interval.
|
|
|
|
|
+ if (is_stopped()) {
|
|
|
|
|
+ if (get_open_ended() || _loop_count != 0) {
|
|
|
|
|
+ priv_reverse_instant();
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ priv_reverse_finalize();
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (is_stopped()) {
|
|
|
|
|
+ priv_reverse_initialize(_start_t);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ priv_step(_start_t);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Advance the clock for the next loop cycle. We might have to
|
|
|
|
|
+ // advance multiple times if we skipped several cycles in the past
|
|
|
|
|
+ // frame.
|
|
|
|
|
+
|
|
|
|
|
+ if (_end_t == _start_t) {
|
|
|
|
|
+ // If the interval has no length, we loop exactly once each
|
|
|
|
|
+ // time.
|
|
|
|
|
+ _loop_count++;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Otherwise, figure out how many loops we need to skip.
|
|
|
|
|
+ double time_per_loop = (_end_t - _start_t) / -_play_rate;
|
|
|
|
|
+ double num_loops = floor((now - _clock_start) / time_per_loop);
|
|
|
|
|
+ _loop_count += (int)num_loops;
|
|
|
|
|
+ _clock_start += num_loops * time_per_loop;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return (_loop_count == 0 || _do_loop);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: CInterval::mark_dirty
|
|
// Function: CInterval::mark_dirty
|
|
|
// Access: Public
|
|
// Access: Public
|