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

direct/src/interval/cMetaInterval.cxx

Go to the documentation of this file.
00001 // Filename: cMetaInterval.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 "cMetaInterval.h"
00020 #include "waitInterval.h"
00021 #include "config_interval.h"
00022 #include "indirectLess.h"
00023 #include "indent.h"
00024 
00025 #include <algorithm>
00026 #include <math.h>   // for log10()
00027 #include <stdio.h>  // for sprintf()
00028 
00029 TypeHandle CMetaInterval::_type_handle;
00030 
00031 ////////////////////////////////////////////////////////////////////
00032 //     Function: CMetaInterval::Constructor
00033 //       Access: Published
00034 //  Description: 
00035 ////////////////////////////////////////////////////////////////////
00036 CMetaInterval::
00037 CMetaInterval(const string &name) :
00038   CInterval(name, 0.0, true)
00039 {
00040   _precision = interval_precision;
00041   _current_nesting_level = 0;
00042   _next_event_index = 0;
00043   _processing_events = false;
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: CMetaInterval::Destructor
00048 //       Access: Published, Virtual
00049 //  Description: 
00050 ////////////////////////////////////////////////////////////////////
00051 CMetaInterval::
00052 ~CMetaInterval() {
00053   clear_intervals();
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: CMetaInterval::clear_intervals
00058 //       Access: Published
00059 //  Description: Resets the list of intervals and prepares for
00060 //               receiving a new list.
00061 ////////////////////////////////////////////////////////////////////
00062 void CMetaInterval::
00063 clear_intervals() {
00064   // Better not do this unless you have serviced all of the
00065   // outstanding events!
00066   bool lost_events = false;
00067   if (!_event_queue.empty()) {
00068     interval_cat.warning()
00069       << "Losing outstanding events for " << *this << "\n";
00070     _event_queue.clear();
00071     lost_events = true;
00072   }
00073 
00074   clear_events();
00075 
00076   // Go through all of our nested intervals and remove ourselves as
00077   // their parent.
00078   Defs::iterator di;
00079   for (di = _defs.begin(); di != _defs.end(); ++di) {
00080     IntervalDef &def = (*di);
00081     if (def._c_interval != (CInterval *)NULL) {
00082       CInterval::Parents::iterator pi = 
00083         find(def._c_interval->_parents.begin(),
00084              def._c_interval->_parents.end(),
00085              this);
00086       nassertv(pi != def._c_interval->_parents.end());
00087       def._c_interval->_parents.erase(pi);
00088     }
00089   }
00090   _defs.clear();
00091 
00092   _current_nesting_level = 0;
00093   _next_event_index = 0;
00094 
00095 #ifndef NDEBUG
00096   if (verify_intervals) {
00097     nassertv(!lost_events);
00098   }
00099 #endif
00100 }
00101 
00102 ////////////////////////////////////////////////////////////////////
00103 //     Function: CMetaInterval::push_level
00104 //       Access: Published
00105 //  Description: Marks the beginning of a nested level of child
00106 //               intervals.  Within the nested level, a RelativeStart
00107 //               time of RS_level_begin refers to the start of the
00108 //               level, and the first interval added within the level
00109 //               is always relative to the start of the level.
00110 //
00111 //               The return value is the index of the def entry
00112 //               created by this push.
00113 ////////////////////////////////////////////////////////////////////
00114 int CMetaInterval::
00115 push_level(const string &name, double rel_time, RelativeStart rel_to) {
00116   nassertr(_event_queue.empty() && !_processing_events, -1);
00117 
00118   _defs.push_back(IntervalDef());
00119   IntervalDef &def = _defs.back();
00120   def._type = DT_push_level;
00121   def._ext_name = name;
00122   def._rel_time = rel_time;
00123   def._rel_to = rel_to;
00124   _current_nesting_level++;
00125   mark_dirty();
00126 
00127   return (int)_defs.size() - 1;
00128 }
00129 
00130 ////////////////////////////////////////////////////////////////////
00131 //     Function: CMetaInterval::add_c_interval
00132 //       Access: Published
00133 //  Description: Adds a new CInterval to the list.  The interval will
00134 //               be played when the indicated time (relative to the
00135 //               given point) has been reached.
00136 //
00137 //               The return value is the index of the def entry
00138 //               representing the new interval.
00139 ////////////////////////////////////////////////////////////////////
00140 int CMetaInterval::
00141 add_c_interval(CInterval *c_interval, 
00142                double rel_time, RelativeStart rel_to) {
00143   nassertr(_event_queue.empty() && !_processing_events, -1);
00144   nassertr(c_interval != (CInterval *)NULL, -1);
00145 
00146   c_interval->_parents.push_back(this);
00147   _defs.push_back(IntervalDef());
00148   IntervalDef &def = _defs.back();
00149   def._type = DT_c_interval;
00150   def._c_interval = c_interval;
00151   def._rel_time = rel_time;
00152   def._rel_to = rel_to;
00153   mark_dirty();
00154 
00155   return (int)_defs.size() - 1;
00156 }
00157 
00158 ////////////////////////////////////////////////////////////////////
00159 //     Function: CMetaInterval::add_ext_index
00160 //       Access: Published
00161 //  Description: Adds a new external interval to the list.  This
00162 //               represents some object in the external scripting
00163 //               language that has properties similar to a CInterval
00164 //               (for instance, a Python Interval object).
00165 //
00166 //               The CMetaInterval object cannot play this external
00167 //               interval directly, but it records a placeholder for
00168 //               it and will ask the scripting language to play it
00169 //               when it is time, via is_event_ready() and related
00170 //               methods.
00171 //
00172 //               The ext_index number itself is simply a handle that
00173 //               the scripting language makes up and associates with
00174 //               its interval object somehow.  The CMetaInterval
00175 //               object does not attempt to interpret this value.
00176 //
00177 //               The return value is the index of the def entry
00178 //               representing the new interval.
00179 ////////////////////////////////////////////////////////////////////
00180 int CMetaInterval::
00181 add_ext_index(int ext_index, const string &name, double duration,
00182               bool open_ended,
00183               double rel_time, RelativeStart rel_to) {
00184   nassertr(_event_queue.empty() && !_processing_events, -1);
00185 
00186   _defs.push_back(IntervalDef());
00187   IntervalDef &def = _defs.back();
00188   def._type = DT_ext_index;
00189   def._ext_index = ext_index;
00190   def._ext_name = name;
00191   def._ext_duration = duration;
00192   def._ext_open_ended = open_ended;
00193   def._rel_time = rel_time;
00194   def._rel_to = rel_to;
00195   mark_dirty();
00196 
00197   return (int)_defs.size() - 1;
00198 }
00199 
00200 ////////////////////////////////////////////////////////////////////
00201 //     Function: CMetaInterval::pop_level
00202 //       Access: Published
00203 //  Description: Finishes a level marked by a previous call to
00204 //               push_level(), and returns to the previous level.
00205 //
00206 //               If the duration is not negative, it represents a
00207 //               phony duration to assign to the level, for the
00208 //               purposes of sequencing later intervals.  Otherwise,
00209 //               the level's duration is computed based on the
00210 //               intervals within the level.
00211 ////////////////////////////////////////////////////////////////////
00212 int CMetaInterval::
00213 pop_level(double duration) {
00214   nassertr(_event_queue.empty() && !_processing_events, -1);
00215   nassertr(_current_nesting_level > 0, -1);
00216 
00217   _defs.push_back(IntervalDef());
00218   IntervalDef &def = _defs.back();
00219   def._type = DT_pop_level;
00220   def._ext_duration = duration;
00221   _current_nesting_level--;
00222   mark_dirty();
00223 
00224   return (int)_defs.size() - 1;
00225 }
00226 
00227 ////////////////////////////////////////////////////////////////////
00228 //     Function: CMetaInterval::set_interval_start_time
00229 //       Access: Published
00230 //  Description: Adjusts the start time of the child interval with the
00231 //               given name, if found.  This may be either a C++
00232 //               interval added via add_c_interval(), or an external
00233 //               interval added via add_ext_index(); the name must
00234 //               match exactly.
00235 //
00236 //               If the interval is found, its start time is adjusted,
00237 //               and all subsequent intervals are adjusting
00238 //               accordingly, and true is returned.  If a matching
00239 //               interval is not found, nothing is changed and false
00240 //               is returned.
00241 ////////////////////////////////////////////////////////////////////
00242 bool CMetaInterval::
00243 set_interval_start_time(const string &name, double rel_time,
00244                         CMetaInterval::RelativeStart rel_to) {
00245   nassertr(_event_queue.empty() && !_processing_events, false);
00246   Defs::iterator di;
00247   for (di = _defs.begin(); di != _defs.end(); ++di) {
00248     IntervalDef &def = (*di);
00249 
00250     bool match = false;
00251     switch (def._type) {
00252     case DT_c_interval:
00253       match = (def._c_interval->get_name() == name);
00254       break;
00255 
00256     case DT_ext_index:
00257       match = (def._ext_name == name);
00258       break;
00259 
00260     default:
00261       break;
00262     }
00263     if (match) {
00264       // Here's the interval.
00265       def._rel_time = rel_time;
00266       def._rel_to = rel_to;
00267       mark_dirty();
00268       return true;
00269     }
00270   }
00271 
00272   return false;
00273 }
00274 
00275 ////////////////////////////////////////////////////////////////////
00276 //     Function: CMetaInterval::get_interval_start_time
00277 //       Access: Published
00278 //  Description: Returns the actual start time, relative to the
00279 //               beginning of the interval, of the child interval with
00280 //               the given name, if found, or -1 if the interval is
00281 //               not found.
00282 ////////////////////////////////////////////////////////////////////
00283 double CMetaInterval::
00284 get_interval_start_time(const string &name) const {
00285   recompute();
00286   Defs::const_iterator di;
00287   for (di = _defs.begin(); di != _defs.end(); ++di) {
00288     const IntervalDef &def = (*di);
00289 
00290     bool match = false;
00291     switch (def._type) {
00292     case DT_c_interval:
00293       match = (def._c_interval->get_name() == name);
00294       break;
00295 
00296     case DT_ext_index:
00297       match = (def._ext_name == name);
00298       break;
00299 
00300     default:
00301       break;
00302     }
00303     if (match) {
00304       // Here's the interval.
00305       return int_to_double_time(def._actual_begin_time);
00306     }
00307   }
00308 
00309   return -1.0;
00310 }
00311 
00312 ////////////////////////////////////////////////////////////////////
00313 //     Function: CMetaInterval::get_interval_end_time
00314 //       Access: Published
00315 //  Description: Returns the actual end time, relative to the
00316 //               beginning of the interval, of the child interval with
00317 //               the given name, if found, or -1 if the interval is
00318 //               not found.
00319 ////////////////////////////////////////////////////////////////////
00320 double CMetaInterval::
00321 get_interval_end_time(const string &name) const {
00322   recompute();
00323   Defs::const_iterator di;
00324   for (di = _defs.begin(); di != _defs.end(); ++di) {
00325     const IntervalDef &def = (*di);
00326 
00327     bool match = false;
00328     double duration = 0.0;
00329     switch (def._type) {
00330     case DT_c_interval:
00331       duration = def._c_interval->get_duration();
00332       match = (def._c_interval->get_name() == name);
00333       break;
00334 
00335     case DT_ext_index:
00336       duration = def._ext_duration;
00337       match = (def._ext_name == name);
00338       break;
00339 
00340     default:
00341       break;
00342     }
00343     if (match) {
00344       // Here's the interval.
00345       return int_to_double_time(def._actual_begin_time) + duration;
00346     }
00347   }
00348 
00349   return -1.0;
00350 }
00351 
00352 ////////////////////////////////////////////////////////////////////
00353 //     Function: CMetaInterval::initialize
00354 //       Access: Published, Virtual
00355 //  Description: This replaces the first call to priv_step(), and indicates
00356 //               that the interval has just begun.  This may be
00357 //               overridden by derived classes that need to do some
00358 //               explicit initialization on the first call.
00359 ////////////////////////////////////////////////////////////////////
00360 void CMetaInterval::
00361 priv_initialize(double t) {
00362   if (_processing_events) {
00363     enqueue_self_event(ET_initialize, t);
00364     return;
00365   }
00366 
00367   check_stopped(get_class_type(), "priv_initialize");
00368   // It may be tempting to flush the event_queue here, but don't do
00369   // it.  Those are events that must still be serviced from some
00370   // previous interval operation.  Throwing them away would be a
00371   // mistake.
00372 
00373   recompute();
00374   _next_event_index = 0;
00375   _active.clear();
00376 
00377   int now = double_to_int_time(t);
00378 
00379   /*
00380   // One special case: if we step to t == 0.0, it really means to the
00381   // very beginning of the interval, *before* any events that occurred
00382   // at time 0.  (Most of the time, stepping to a particular time
00383   // means *after* any events that occurred at that time.)
00384   if (t == 0.0) {
00385     now = -1;
00386   }
00387   */
00388 
00389   // Now look for events from the beginning up to the current time.
00390   _processing_events = true;
00391   ActiveEvents new_active;
00392   while (_next_event_index < _events.size() &&
00393          _events[_next_event_index]->_time <= now) {
00394     PlaybackEvent *event = _events[_next_event_index];
00395     _next_event_index++;
00396     
00397     // Do the indicated event.
00398     do_event_forward(event, new_active, true);
00399   }
00400   finish_events_forward(now, new_active);
00401   _processing_events = false;
00402 
00403   _curr_t = t;
00404   _state = S_started;
00405 }
00406 
00407 ////////////////////////////////////////////////////////////////////
00408 //     Function: CMetaInterval::instant
00409 //       Access: Published, Virtual
00410 //  Description: This is called in lieu of priv_initialize() .. priv_step()
00411 //               .. priv_finalize(), when everything is to happen within
00412 //               one frame.  The interval should initialize itself,
00413 //               then leave itself in the final state.
00414 ////////////////////////////////////////////////////////////////////
00415 void CMetaInterval::
00416 priv_instant() {
00417   if (_processing_events) {
00418     enqueue_self_event(ET_instant);
00419     return;
00420   }
00421 
00422   check_stopped(get_class_type(), "priv_instant");
00423   recompute();
00424   _active.clear();
00425 
00426   // Apply all of the events.  This just means we invoke "instant" for
00427   // any end or instant event, ignoring the begin events.
00428   _processing_events = true;
00429   PlaybackEvents::iterator ei;
00430   for (ei = _events.begin(); ei != _events.end(); ++ei) {
00431     PlaybackEvent *event = (*ei);
00432     if (event->_type != PET_begin) {
00433       enqueue_event(event->_n, ET_instant, true, 0);
00434     }
00435   }
00436   _processing_events = false;
00437 
00438   _next_event_index = _events.size();
00439   _curr_t = get_duration();
00440   _state = S_final;
00441 
00442   if (_event_queue.empty()) {
00443     interval_done();
00444   } else {
00445     enqueue_done_event();
00446   }
00447 }
00448 
00449 ////////////////////////////////////////////////////////////////////
00450 //     Function: CMetaInterval::step
00451 //       Access: Published, Virtual
00452 //  Description: Advances the time on the interval.  The time may
00453 //               either increase (the normal case) or decrease
00454 //               (e.g. if the interval is being played by a slider).
00455 ////////////////////////////////////////////////////////////////////
00456 void CMetaInterval::
00457 priv_step(double t) {
00458   if (_processing_events) {
00459     enqueue_self_event(ET_step, t);
00460     return;
00461   }
00462 
00463   check_started(get_class_type(), "priv_step");
00464   int now = double_to_int_time(t);
00465 
00466   /*
00467   // One special case: if we step to t == 0.0, it really means to the
00468   // very beginning of the interval, *before* any events that occurred
00469   // at time 0.  (Most of the time, stepping to a particular time
00470   // means *after* any events that occurred at that time.)
00471   if (t == 0.0) {
00472     now = -1;
00473   }
00474   */
00475 
00476   // Now look for events between the last time we ran and the current
00477   // time.
00478 
00479   _processing_events = true;
00480   if (_next_event_index < _events.size() &&
00481       _events[_next_event_index]->_time <= now) {
00482     // The normal case: time is increasing.
00483     ActiveEvents new_active;
00484     while (_next_event_index < _events.size() &&
00485            _events[_next_event_index]->_time <= now) {
00486       PlaybackEvent *event = _events[_next_event_index];
00487       _next_event_index++;
00488 
00489       // Do the indicated event.
00490       do_event_forward(event, new_active, false);
00491     }
00492 
00493     finish_events_forward(now, new_active);
00494 
00495   } else {
00496     // A less usual case: time is decreasing.
00497     ActiveEvents new_active;
00498     while (_next_event_index > 0 && 
00499            _events[_next_event_index - 1]->_time > now) {
00500       _next_event_index--;
00501       PlaybackEvent *event = _events[_next_event_index];
00502 
00503       do_event_reverse(event, new_active, false);
00504     }
00505 
00506     finish_events_reverse(now, new_active);
00507   }
00508   _processing_events = false;
00509 
00510   _curr_t = t;
00511   _state = S_started;
00512 }
00513 
00514 ////////////////////////////////////////////////////////////////////
00515 //     Function: CMetaInterval::finalize
00516 //       Access: Published, Virtual
00517 //  Description: This is called when an interval is interrupted.  It
00518 //               should advance the time as if priv_step() were called, and
00519 //               also perform whatever cleanup might be required.
00520 ////////////////////////////////////////////////////////////////////
00521 void CMetaInterval::
00522 priv_finalize() {
00523   if (_processing_events) {
00524     enqueue_self_event(ET_finalize);
00525     return;
00526   }
00527 
00528   double duration = get_duration();
00529   if (_state == S_initial) {
00530     priv_initialize(duration);
00531   }
00532 
00533   // Do all remaining events.
00534   _processing_events = true;
00535   ActiveEvents new_active;
00536   while (_next_event_index < _events.size()) {
00537     PlaybackEvent *event = _events[_next_event_index];
00538     _next_event_index++;
00539 
00540     // Do the indicated event.
00541     do_event_forward(event, new_active, true);
00542   }
00543   finish_events_forward(double_to_int_time(duration), new_active);
00544   _processing_events = false;
00545 
00546   _curr_t = duration;
00547   _state = S_final;
00548 
00549   if (_event_queue.empty()) {
00550     interval_done();
00551   } else {
00552     enqueue_done_event();
00553   }
00554 }
00555 
00556 ////////////////////////////////////////////////////////////////////
00557 //     Function: CMetaInterval::reverse_initialize
00558 //       Access: Published, Virtual
00559 //  Description: Similar to priv_initialize(), but this is called when the
00560 //               interval is being played backwards; it indicates that
00561 //               the interval should start at the finishing state and
00562 //               undo any intervening intervals.
00563 ////////////////////////////////////////////////////////////////////
00564 void CMetaInterval::
00565 priv_reverse_initialize(double t) {
00566   if (_processing_events) {
00567     enqueue_self_event(ET_reverse_initialize, t);
00568     return;
00569   }
00570 
00571   check_stopped(get_class_type(), "priv_reverse_initialize");
00572   // It may be tempting to flush the event_queue here, but don't do
00573   // it.  Those are events that must still be serviced from some
00574   // previous interval operation.  Throwing them away would be a
00575   // mistake.
00576 
00577   recompute();
00578   _next_event_index = _events.size();
00579   _active.clear();
00580 
00581   int now = double_to_int_time(t);
00582 
00583   /*
00584   // One special case: if we step to t == 0.0, it really means to the
00585   // very beginning of the interval, *before* any events that occurred
00586   // at time 0.  (Most of the time, stepping to a particular time
00587   // means *after* any events that occurred at that time.)
00588   if (t == 0.0) {
00589     now = -1;
00590   }
00591   */
00592 
00593   // Now look for events from the end down to the current time.
00594   _processing_events = true;
00595   ActiveEvents new_active;
00596   while (_next_event_index > 0 && 
00597          _events[_next_event_index - 1]->_time > now) {
00598     _next_event_index--;
00599     PlaybackEvent *event = _events[_next_event_index];
00600     
00601     // Do the indicated event.
00602     do_event_reverse(event, new_active, true);
00603   }
00604   finish_events_reverse(now, new_active);
00605   _processing_events = false;
00606 
00607   _curr_t = t;
00608   _state = S_started;
00609 }
00610 
00611 ////////////////////////////////////////////////////////////////////
00612 //     Function: CMetaInterval::reverse_instant
00613 //       Access: Published, Virtual
00614 //  Description: This is called in lieu of priv_reverse_initialize()
00615 //               .. priv_step() .. priv_reverse_finalize(), when everything is
00616 //               to happen within one frame.  The interval should
00617 //               initialize itself, then leave itself in the initial
00618 //               state.
00619 ////////////////////////////////////////////////////////////////////
00620 void CMetaInterval::
00621 priv_reverse_instant() {
00622   if (_processing_events) {
00623     enqueue_self_event(ET_reverse_instant);
00624     return;
00625   }
00626 
00627   check_stopped(get_class_type(), "priv_reverse_instant");
00628   recompute();
00629   _active.clear();
00630 
00631   // Apply all of the events.  This just means we invoke "instant" for
00632   // any end or instant event, ignoring the begin events.
00633   _processing_events = true;
00634   PlaybackEvents::reverse_iterator ei;
00635   for (ei = _events.rbegin(); ei != _events.rend(); ++ei) {
00636     PlaybackEvent *event = (*ei);
00637     if (event->_type != PET_begin) {
00638       enqueue_event(event->_n, ET_reverse_instant, true, 0);
00639     }
00640   }
00641   _processing_events = false;
00642 
00643   _next_event_index = 0;
00644   _curr_t = 0.0;
00645   _state = S_initial;
00646 }
00647 
00648 ////////////////////////////////////////////////////////////////////
00649 //     Function: CMetaInterval::reverse_finalize
00650 //       Access: Published, Virtual
00651 //  Description: Called generally following a priv_reverse_initialize(),
00652 //               this indicates the interval should set itself to the
00653 //               initial state.
00654 ////////////////////////////////////////////////////////////////////
00655 void CMetaInterval::
00656 priv_reverse_finalize() {
00657   if (_processing_events) {
00658     enqueue_self_event(ET_reverse_finalize);
00659     return;
00660   }
00661 
00662   if (_state == S_initial) {
00663     priv_initialize(0.0);
00664   }
00665 
00666   // Do all remaining events at the beginning.
00667   _processing_events = true;
00668   ActiveEvents new_active;
00669 
00670   while (_next_event_index > 0) {
00671     _next_event_index--;
00672     PlaybackEvent *event = _events[_next_event_index];
00673 
00674     do_event_reverse(event, new_active, true);
00675   }
00676   finish_events_reverse(0, new_active);
00677   _processing_events = false;
00678 
00679   _curr_t = 0.0;
00680   _state = S_initial;
00681 }
00682 
00683 ////////////////////////////////////////////////////////////////////
00684 //     Function: CMetaInterval::interrupt
00685 //       Access: Published, Virtual
00686 //  Description: This is called while the interval is playing to
00687 //               indicate that it is about to be interrupted; that is,
00688 //               priv_step() will not be called for a length of time.  But
00689 //               the interval should remain in its current state in
00690 //               anticipation of being eventually restarted when the
00691 //               calls to priv_step() eventually resume.
00692 //
00693 //               The purpose of this function is to allow self-running
00694 //               intervals like sound intervals to stop the actual
00695 //               sound playback during the pause.
00696 ////////////////////////////////////////////////////////////////////
00697 void CMetaInterval::
00698 priv_interrupt() {
00699   if (_processing_events) {
00700     enqueue_self_event(ET_interrupt);
00701     return;
00702   }
00703 
00704   _processing_events = true;
00705   ActiveEvents::iterator ai;
00706   for (ai = _active.begin(); ai != _active.end(); ++ai) {
00707     PlaybackEvent *event = (*ai);
00708     enqueue_event(event->_n, ET_interrupt, false);
00709   }
00710   _processing_events = false;
00711 
00712   if (_state == S_started) {
00713     _state = S_paused;
00714   }
00715 }
00716 
00717 ////////////////////////////////////////////////////////////////////
00718 //     Function: CMetaInterval::pop_event
00719 //       Access: Published
00720 //  Description: Acknowledges that the external interval on the top of
00721 //               the queue has been extracted, and is about to be
00722 //               serviced by the scripting language.  This prepares
00723 //               the interval so the next call to is_event_ready()
00724 //               will return information about the next external
00725 //               interval on the queue, if any.
00726 ////////////////////////////////////////////////////////////////////
00727 void CMetaInterval::
00728 pop_event() {
00729 #ifndef NDEBUG
00730   nassertv(!_event_queue.empty());
00731   const EventQueueEntry &entry = _event_queue.front();
00732   const IntervalDef &def = _defs[entry._n];
00733   nassertv(def._type == DT_ext_index);
00734 #endif
00735   _event_queue.pop_front();
00736 }
00737 
00738 ////////////////////////////////////////////////////////////////////
00739 //     Function: CMetaInterval::write
00740 //       Access: Published, Virtual
00741 //  Description: 
00742 ////////////////////////////////////////////////////////////////////
00743 void CMetaInterval::
00744 write(ostream &out, int indent_level) const {
00745   recompute();
00746 
00747   // How many digits of precision should we output for time?
00748   int num_decimals = (int)ceil(log10(_precision));
00749   int total_digits = num_decimals + 4;
00750   static const int max_digits = 32;  // totally arbitrary
00751   nassertv(total_digits <= max_digits);
00752   char format_str[12];
00753   sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
00754 
00755   indent(out, indent_level) << get_name() << ":\n";
00756 
00757   int extra_indent_level = 1;
00758   Defs::const_iterator di;
00759   for (di = _defs.begin(); di != _defs.end(); ++di) {
00760     const IntervalDef &def = (*di);
00761     char time_str[max_digits + 1];
00762     sprintf(time_str, format_str, int_to_double_time(def._actual_begin_time));
00763     indent(out, indent_level) << time_str;
00764 
00765     write_event_desc(out, def, extra_indent_level);
00766   }
00767 }
00768 
00769 ////////////////////////////////////////////////////////////////////
00770 //     Function: CMetaInterval::timeline
00771 //       Access: Published
00772 //  Description: Outputs a list of all events in the order in which
00773 //               they occur.
00774 ////////////////////////////////////////////////////////////////////
00775 void CMetaInterval::
00776 timeline(ostream &out) const {
00777   recompute();
00778 
00779   // How many digits of precision should we output for time?
00780   int num_decimals = (int)ceil(log10(_precision));
00781   int total_digits = num_decimals + 4;
00782   static const int max_digits = 32;  // totally arbitrary
00783   nassertv(total_digits <= max_digits);
00784   char format_str[12];
00785   sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
00786 
00787   int extra_indent_level = 0;
00788   PlaybackEvents::const_iterator ei;
00789   for (ei = _events.begin(); ei != _events.end(); ++ei) {
00790     const PlaybackEvent *event = (*ei);
00791 
00792     char time_str[max_digits + 1];
00793     sprintf(time_str, format_str, int_to_double_time(event->_time));
00794     out << time_str;
00795 
00796     switch (event->_type) {
00797     case PET_begin:
00798       out << " begin   ";
00799       break;
00800     case PET_end:
00801       out << " end     ";
00802       break;
00803     case PET_instant:
00804       out << " instant ";
00805       break;
00806     }
00807 
00808     int n = event->_n;
00809     nassertv(n >= 0 && n < (int)_defs.size());
00810     const IntervalDef &def = _defs[n];
00811 
00812     write_event_desc(out, def, extra_indent_level);
00813   }
00814 }
00815 
00816 ////////////////////////////////////////////////////////////////////
00817 //     Function: CMetaInterval::do_recompute
00818 //       Access: Protected, Virtual
00819 //  Description: Recomputes all of the events (and the duration)
00820 //               according to the set of interval defs.
00821 ////////////////////////////////////////////////////////////////////
00822 void CMetaInterval::
00823 do_recompute() {
00824   _dirty = false;
00825   clear_events();
00826 
00827   int n = recompute_level(0, 0, _end_time);
00828 
00829   if (n != (int)_defs.size()) {
00830     interval_cat.warning()
00831       << "CMetaInterval pushes don't match pops.\n";
00832   }
00833 
00834   // We do a stable_sort() to guarantee ordering of events that have
00835   // the same start time.  These must be invoked in the order in which
00836   // they appear.
00837   stable_sort(_events.begin(), _events.end(), IndirectLess<PlaybackEvent>());
00838   _duration = int_to_double_time(_end_time);
00839 }
00840 
00841 ////////////////////////////////////////////////////////////////////
00842 //     Function: CMetaInterval::clear_events
00843 //       Access: Private
00844 //  Description: Removes all entries from the _events list.
00845 ////////////////////////////////////////////////////////////////////
00846 void CMetaInterval::
00847 clear_events() {
00848   PlaybackEvents::iterator ei;
00849   for (ei = _events.begin(); ei != _events.end(); ++ei) {
00850     PlaybackEvent *event = (*ei);
00851     delete event;
00852   }
00853   _events.clear();
00854   _active.clear();
00855 }
00856 
00857 ////////////////////////////////////////////////////////////////////
00858 //     Function: CMetaInterval::do_event_forward
00859 //       Access: Private
00860 //  Description: Process a single event in the interval, moving
00861 //               forwards in time.  If the event represents a new
00862 //               begin, adds it to the new_active list; if it is an
00863 //               end, finalizes it.
00864 //
00865 //               If is_initial is true, it is as if we are in
00866 //               initialize or finalize: instant events will be
00867 //               invoked only if they are marked open_ended.
00868 ////////////////////////////////////////////////////////////////////
00869 void CMetaInterval::
00870 do_event_forward(CMetaInterval::PlaybackEvent *event, 
00871                  CMetaInterval::ActiveEvents &new_active, bool is_initial) {
00872   switch (event->_type) {
00873   case PET_begin:
00874     nassertv(event->_begin_event == event);
00875     new_active.push_back(event);
00876     break;
00877     
00878   case PET_end:
00879     {
00880       // Erase the event from either the new active or the current
00881       // active lists.
00882       ActiveEvents::iterator ai;
00883       ai = find(new_active.begin(), new_active.end(), event->_begin_event);
00884       if (ai != new_active.end()) {
00885         new_active.erase(ai);
00886         // This interval was new this frame; we must invoke it as
00887         // an instant event.
00888         enqueue_event(event->_n, ET_instant, is_initial);
00889 
00890       } else {
00891         ai = find(_active.begin(), _active.end(), event->_begin_event);
00892         if (ai != _active.end()) {
00893           _active.erase(ai);
00894           enqueue_event(event->_n, ET_finalize, is_initial);
00895 
00896         } else {
00897           // Hmm, this event wasn't on either list.  Maybe there was a
00898           // start event on the list whose time was less than 0.
00899           interval_cat.error()
00900             << "Event " << event->_begin_event->_n << " not on active list.\n";
00901           nassertv(false);
00902         }
00903       }
00904     }
00905     break;
00906     
00907   case PET_instant:
00908     nassertv(event->_begin_event == event);
00909     enqueue_event(event->_n, ET_instant, is_initial);
00910     break;
00911   }
00912 }
00913 
00914 ////////////////////////////////////////////////////////////////////
00915 //     Function: CMetaInterval::finish_events_forward
00916 //       Access: Private
00917 //  Description: After walking through the event list and adding a
00918 //               bunch of new events to new_active, finished up by
00919 //               calling priv_step() on all of the events still in _active
00920 //               and priv_initialize() on all the events in new_active,
00921 //               then copying the events from new_active to active.
00922 ////////////////////////////////////////////////////////////////////
00923 void CMetaInterval::
00924 finish_events_forward(int now, CMetaInterval::ActiveEvents &new_active) {
00925   // Do whatever's still active.
00926   ActiveEvents::iterator ai;
00927   for (ai = _active.begin(); ai != _active.end(); ++ai) {
00928     PlaybackEvent *event = (*ai);
00929     enqueue_event(event->_n, ET_step, false, now - event->_time);
00930   }
00931   
00932   // Initialize whatever new intervals we came across.
00933   for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
00934     PlaybackEvent *event = (*ai);
00935     enqueue_event(event->_n, ET_initialize, false, now - event->_time);
00936     _active.push_back(event);
00937   }
00938 }
00939 
00940 ////////////////////////////////////////////////////////////////////
00941 //     Function: CMetaInterval::do_event_reverse
00942 //       Access: Private
00943 //  Description: Process a single event in the interval, moving
00944 //               backwards in time.  This undoes the indicated event.
00945 //               If the event represents a new begin, adds it to the
00946 //               new_active list; if it is an end, finalizes it.
00947 //
00948 //               If is_initial is true, it is as if we are in
00949 //               reverse_initialize or reverse_finalize: instant
00950 //               events will be invoked only if they are marked
00951 //               open_ended.
00952 ////////////////////////////////////////////////////////////////////
00953 void CMetaInterval::
00954 do_event_reverse(CMetaInterval::PlaybackEvent *event, 
00955                  CMetaInterval::ActiveEvents &new_active, bool is_initial) {
00956   // Undo the indicated event.
00957   switch (event->_type) {
00958   case PET_begin:
00959     {
00960       nassertv(event->_begin_event == event);
00961       // Erase the event from either the new active or the current
00962       // active lists.
00963       ActiveEvents::iterator ai;
00964       ai = find(new_active.begin(), new_active.end(), event);
00965       if (ai != new_active.end()) {
00966         new_active.erase(ai);
00967         // This interval was new this frame; we invoke it as an
00968         // instant event.
00969         enqueue_event(event->_n, ET_reverse_instant, is_initial);
00970 
00971       } else {
00972         ai = find(_active.begin(), _active.end(), event);
00973         if (ai != _active.end()) {
00974           _active.erase(ai);
00975           enqueue_event(event->_n, ET_reverse_finalize, is_initial);
00976 
00977         } else {
00978           // Hmm, this event wasn't on either list.  Maybe there was a
00979           // stop event on the list whose time was greater than the
00980           // total, somehow. 
00981           interval_cat.error()
00982             << "Event " << event->_n << " not on active list.\n";
00983           nassertv(false);
00984         }
00985       }
00986     }
00987     break;
00988     
00989   case PET_end:
00990     new_active.push_front(event->_begin_event);
00991     break;
00992     
00993   case PET_instant:
00994     nassertv(event->_begin_event == event);
00995     enqueue_event(event->_n, ET_reverse_instant, is_initial);
00996     break;
00997   }
00998 }
00999 
01000 ////////////////////////////////////////////////////////////////////
01001 //     Function: CMetaInterval::finish_events_reverse
01002 //       Access: Private
01003 //  Description: After walking through the event list and adding a
01004 //               bunch of new events to new_active, finishes up by
01005 //               calling priv_step() on all of the events still in _active
01006 //               and priv_reverse_initialize() on all the events in
01007 //               new_active, then copying the events from new_active
01008 //               to active.
01009 ////////////////////////////////////////////////////////////////////
01010 void CMetaInterval::
01011 finish_events_reverse(int now, CMetaInterval::ActiveEvents &new_active) {
01012   // Do whatever's still active.
01013   ActiveEvents::iterator ai;
01014   for (ai = _active.begin(); ai != _active.end(); ++ai) {
01015     PlaybackEvent *event = (*ai);
01016     enqueue_event(event->_n, ET_step, false, now - event->_time);
01017   }
01018   
01019   // Initialize whatever new intervals we came across.
01020   for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
01021     PlaybackEvent *event = (*ai);
01022     enqueue_event(event->_n, ET_reverse_initialize, false, now - event->_time);
01023     _active.push_front(event);
01024   }
01025 }
01026   
01027 ////////////////////////////////////////////////////////////////////
01028 //     Function: CMetaInterval::enqueue_event
01029 //       Access: Private
01030 //  Description: Enqueues the indicated interval for invocation after
01031 //               we have finished scanning for events that need
01032 //               processing this frame.
01033 //
01034 //               is_initial is only relevant for event types
01035 //               ET_instant or ET_reverse_instant, and indicates
01036 //               whether we are in the priv_initialize() (or
01037 //               priv_reverse_initialize()) call, and should therefore only
01038 //               invoke open-ended intervals.
01039 //
01040 //               time is only relevant for ET_initialize,
01041 //               ET_reverse_initialize, and ET_step.
01042 ////////////////////////////////////////////////////////////////////
01043 void CMetaInterval::
01044 enqueue_event(int n, CInterval::EventType event_type, bool is_initial, int time) {
01045   nassertv(n >= 0 && n < (int)_defs.size());
01046   const IntervalDef &def = _defs[n];
01047   switch (def._type) {
01048   case DT_c_interval:
01049     if (is_initial &&
01050         (event_type == ET_instant || event_type == ET_reverse_instant) &&
01051         !def._c_interval->get_open_ended()) {
01052       // Ignore a non-open-ended interval that we skipped completely
01053       // past on priv_initialize().
01054       return;
01055     } else {
01056       if (_event_queue.empty()) {
01057         // if the event queue is empty, we can process this C++
01058         // interval immediately.  We only need to defer it if there
01059         // are external (e.g. Python) intervals in the queue that need
01060         // to be processed first.
01061         def._c_interval->priv_do_event(int_to_double_time(time), event_type);
01062         return;
01063       }
01064     }
01065     break;
01066 
01067   case DT_ext_index:
01068     if (is_initial &&
01069         (event_type == ET_instant || event_type == ET_reverse_instant) &&
01070         !def._ext_open_ended) {
01071       // Ignore a non-open-ended interval that we skipped completely
01072       // past on priv_initialize().
01073       return;
01074     }
01075     break;
01076 
01077   default:
01078     nassertv(false);
01079     return;
01080   }
01081 
01082   _event_queue.push_back(EventQueueEntry(n, event_type, time));
01083 }
01084 
01085 ////////////////////////////////////////////////////////////////////
01086 //     Function: CMetaInterval::enqueue_self_event
01087 //       Access: Private
01088 //  Description: Enqueues a reference to *this* interval.  This is
01089 //               called only when the interval is recursively
01090 //               re-entered; the request will be serviced when the
01091 //               current request is done processing.
01092 //
01093 //               time is only relevant for ET_initialize,
01094 //               ET_reverse_initialize, and ET_step.
01095 ////////////////////////////////////////////////////////////////////
01096 void CMetaInterval::
01097 enqueue_self_event(CInterval::EventType event_type, double t) {
01098   interval_cat.info()
01099     << "Recursive reentry detected into " << *this << "\n";
01100   int time = double_to_int_time(t);
01101   _event_queue.push_back(EventQueueEntry(-1, event_type, time));
01102 }
01103 
01104 ////////////////////////////////////////////////////////////////////
01105 //     Function: CMetaInterval::enqueue_done_event
01106 //       Access: Private
01107 //  Description: Enqueues a special "event" that simply marks the end
01108 //               of processing of the interval; the interval's done
01109 //               event should be thrown now, if it is defined.
01110 ////////////////////////////////////////////////////////////////////
01111 void CMetaInterval::
01112 enqueue_done_event() {
01113   _event_queue.push_back(EventQueueEntry(-2, ET_finalize, 0));
01114 }
01115   
01116 ////////////////////////////////////////////////////////////////////
01117 //     Function: CMetaInterval::service_event_queue
01118 //       Access: Private
01119 //  Description: Invokes whatever C++ intervals might be at the head
01120 //               of the queue, and prepares for passing an external
01121 //               interval to the scripting language.
01122 //
01123 //               The return value is true if there remains at least
01124 //               one external event to be serviced, false if all
01125 //               events are handled.
01126 ////////////////////////////////////////////////////////////////////
01127 bool CMetaInterval::
01128 service_event_queue() {
01129   while (!_event_queue.empty()) {
01130     nassertr(!_processing_events, true);
01131     const EventQueueEntry &entry = _event_queue.front();
01132     if (entry._n == -1) {
01133       // Index -1 is a special code for *this* interval.
01134       priv_do_event(int_to_double_time(entry._time), entry._event_type);
01135 
01136     } else if (entry._n == -2) {
01137       // Index -2 is a special code to indicate the interval is now
01138       // done, and its done event should be thrown.
01139       interval_done();
01140 
01141     } else {
01142       nassertr(entry._n >= 0 && entry._n < (int)_defs.size(), false);
01143       const IntervalDef &def = _defs[entry._n];
01144       switch (def._type) {
01145       case DT_c_interval:
01146         // Handle the C++ event.
01147         def._c_interval->priv_do_event(int_to_double_time(entry._time), entry._event_type);
01148         break;
01149         
01150       case DT_ext_index:
01151         // Here's an external event; leave it there and return.
01152         return true;
01153         
01154       default:
01155         nassertr(false, false);
01156         return false;
01157       }
01158     }
01159     _event_queue.pop_front();
01160   }
01161 
01162   // No more events on the queue.
01163   nassertr(!_processing_events, false);
01164   return false;
01165 }
01166 
01167 ////////////////////////////////////////////////////////////////////
01168 //     Function: CMetaInterval::recompute_level
01169 //       Access: Private
01170 //  Description: Recursively recomputes a complete level (delimited by
01171 //               push/pop definitions).
01172 //
01173 //               The value n on entry refers to the first entry after
01174 //               the push; the return value will reference the
01175 //               matching pop, or an index greater than the last
01176 //               element in the array if there was no matching pop.
01177 //
01178 //               The level_begin value indicates the begin time of
01179 //               this level.  On return, level_end is filled with the
01180 //               end time of this level.
01181 ////////////////////////////////////////////////////////////////////
01182 int CMetaInterval::
01183 recompute_level(int n, int level_begin, int &level_end) {
01184   level_end = level_begin;
01185   int previous_begin = level_begin;
01186   int previous_end = level_begin;
01187 
01188   while (n < (int)_defs.size() && _defs[n]._type != DT_pop_level) {
01189     IntervalDef &def = _defs[n];
01190     int begin_time = previous_begin;
01191     int end_time = previous_end;
01192     switch (def._type) {
01193     case DT_c_interval:
01194       begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
01195       def._actual_begin_time = begin_time;
01196       end_time = begin_time + double_to_int_time(def._c_interval->get_duration());
01197 
01198       if (def._c_interval->is_exact_type(WaitInterval::get_class_type())) {
01199         // Don't bother enqueuing events for WaitIntervals; they're
01200         // just there to fill up time.
01201 
01202       } else {
01203         if (begin_time == end_time) {
01204           _events.push_back(new PlaybackEvent(begin_time, n, PET_instant));
01205         } else {
01206           PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin);
01207           PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end);
01208           end->_begin_event = begin;
01209           _events.push_back(begin);
01210           _events.push_back(end);
01211         }
01212       }
01213       break;
01214 
01215     case DT_ext_index:
01216       begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
01217       def._actual_begin_time = begin_time;
01218       end_time = begin_time + double_to_int_time(def._ext_duration);
01219       if (begin_time == end_time) {
01220         _events.push_back(new PlaybackEvent(begin_time, n, PET_instant));
01221       } else {
01222         PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin);
01223         PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end);
01224         end->_begin_event = begin;
01225         _events.push_back(begin);
01226         _events.push_back(end);
01227       }
01228       break;
01229 
01230     case DT_push_level:
01231       begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
01232       def._actual_begin_time = begin_time;
01233       n = recompute_level(n + 1, begin_time, end_time);
01234       break;
01235 
01236     case DT_pop_level:
01237       nassertr(false, _defs.size());
01238       break;
01239     }
01240 
01241     previous_begin = begin_time;
01242     previous_end = end_time;
01243     level_end = max(level_end, end_time);
01244     n++;
01245   }
01246 
01247   if (n < (int)_defs.size()) {
01248     IntervalDef &def = _defs[n];
01249     // If we have a pop record, check it for a phony duration.
01250     if (def._ext_duration >= 0.0) {
01251       level_end = level_begin + double_to_int_time(def._ext_duration);
01252     }
01253 
01254     // The final pop "begins" at the level end time, just for clarity
01255     // on output.
01256     def._actual_begin_time = level_end;
01257   }
01258 
01259   return n;
01260 }
01261 
01262 ////////////////////////////////////////////////////////////////////
01263 //     Function: CMetaInterval::get_begin_time
01264 //       Access: Private
01265 //  Description: Returns the integer begin time indicated by the given
01266 //               IntervalDef, given the indicated level begin,
01267 //               previous begin, and previous end times.
01268 ////////////////////////////////////////////////////////////////////
01269 int CMetaInterval::
01270 get_begin_time(const CMetaInterval::IntervalDef &def, int level_begin,
01271                int previous_begin, int previous_end) {
01272   switch (def._rel_to) {
01273   case RS_previous_end:
01274     return previous_end + double_to_int_time(def._rel_time);
01275 
01276   case RS_previous_begin:
01277     return previous_begin + double_to_int_time(def._rel_time);
01278 
01279   case RS_level_begin:
01280     return level_begin + double_to_int_time(def._rel_time);
01281   }
01282 
01283   nassertr(false, previous_end);
01284   return previous_end;
01285 }
01286 
01287 ////////////////////////////////////////////////////////////////////
01288 //     Function: CMetaInterval::write_event_desc
01289 //       Access: Private
01290 //  Description: Formats an event for output, for write() or
01291 //               timeline().
01292 ////////////////////////////////////////////////////////////////////
01293 void CMetaInterval::
01294 write_event_desc(ostream &out, const CMetaInterval::IntervalDef &def, 
01295                  int &extra_indent_level) const {
01296   switch (def._type) {
01297   case DT_c_interval:
01298     indent(out, extra_indent_level)
01299       << *def._c_interval;
01300     if (!def._c_interval->get_open_ended()) {
01301       out << " (!oe)";
01302     }
01303     out << "\n";
01304     break;
01305     
01306   case DT_ext_index:
01307     indent(out, extra_indent_level)
01308       << "*" << def._ext_name;
01309     if (def._ext_duration != 0.0) {
01310       out << " dur " << def._ext_duration;
01311     }
01312     if (!def._ext_open_ended) {
01313       out << " (!oe)";
01314     }
01315     out<< "\n";
01316     break;
01317     
01318   case DT_push_level:
01319     indent(out, extra_indent_level)
01320       << def._ext_name << " {\n";
01321     extra_indent_level += 2;
01322     break;
01323     
01324   case DT_pop_level:
01325     extra_indent_level -= 2;
01326     indent(out, extra_indent_level)
01327       << "}\n";
01328     break;
01329   }
01330 }

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