Panda3D

clockObject.cxx

00001 // Filename: clockObject.cxx
00002 // Created by:  drose (17Feb00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "clockObject.h"
00016 #include "config_util.h"
00017 #include "configVariableEnum.h"
00018 #include "string_utils.h"
00019 #include "thread.h"
00020 
00021 void (*ClockObject::_start_clock_wait)() = ClockObject::dummy_clock_wait;
00022 void (*ClockObject::_start_clock_busy_wait)() = ClockObject::dummy_clock_wait;
00023 void (*ClockObject::_stop_clock_wait)() = ClockObject::dummy_clock_wait;
00024 
00025 PT(ClockObject) ClockObject::_global_clock;
00026 TypeHandle ClockObject::_type_handle;
00027 
00028 ////////////////////////////////////////////////////////////////////
00029 //     Function: ClockObject::Constructor
00030 //       Access: Published
00031 //  Description:
00032 ////////////////////////////////////////////////////////////////////
00033 ClockObject::
00034 ClockObject() : _ticks(get_class_type()) {
00035   _true_clock = TrueClock::get_global_ptr();
00036 
00037   // Each clock except for the application global clock is created in
00038   // M_normal mode.  The application global clock is later reset to
00039   // respect clock_mode, which comes from the Config.prc file.
00040   _mode = M_normal;
00041 
00042   _start_short_time = _true_clock->get_short_time();
00043   _start_long_time = _true_clock->get_long_time();
00044   _actual_frame_time = 0.0;
00045 
00046   ConfigVariableDouble max_dt
00047     ("max-dt", -1.0,
00048      PRC_DESC("Sets a limit on the value returned by ClockObject::get_dt().  If "
00049               "this value is less than zero, no limit is imposed; "
00050               "otherwise, this is the maximum value that will ever "
00051               "be returned by get_dt(), regardless of how much time "
00052               "has actually elapsed between frames.  See ClockObject::set_dt()."));
00053   ConfigVariableDouble clock_frame_rate
00054     ("clock-frame-rate", 1.0,
00055      PRC_DESC("In non-real-time clock mode, sets the number of frames per "
00056               "second that we should appear to be running.  In forced "
00057               "mode or limited mode, sets our target frame rate.  In "
00058               "normal mode, this has no effect.  See ClockObject::set_frame_rate()."));
00059   ConfigVariableDouble clock_degrade_factor
00060     ("clock-degrade-factor", 1.0,
00061      PRC_DESC("In degrade clock mode, returns the ratio by which the "
00062               "performance is degraded.  A value of 2.0 causes the "
00063               "clock to be slowed down by a factor of two (reducing "
00064               "performance to 1/2 what would be otherwise).  See ClockObject::set_degrade_factor()."));
00065   ConfigVariableDouble average_frame_rate_interval
00066     ("average-frame-rate-interval", 1.0,
00067      PRC_DESC("See ClockObject::set_average_frame_rate_interval()."));
00068 
00069   _max_dt = max_dt;
00070   _user_frame_rate = clock_frame_rate;
00071   _degrade_factor = clock_degrade_factor;
00072   _average_frame_rate_interval = average_frame_rate_interval;
00073 
00074   _error_count = _true_clock->get_error_count();
00075 }
00076 
00077 ////////////////////////////////////////////////////////////////////
00078 //     Function: ClockObject::Copy Constructor
00079 //       Access: Published
00080 //  Description: 
00081 ////////////////////////////////////////////////////////////////////
00082 ClockObject::
00083 ClockObject(const ClockObject &copy) :
00084   _true_clock(copy._true_clock),
00085   _mode(copy._mode),
00086   _start_short_time(copy._start_short_time),
00087   _start_long_time(copy._start_long_time),
00088   _actual_frame_time(copy._actual_frame_time),
00089   _max_dt(copy._max_dt),
00090   _user_frame_rate(copy._user_frame_rate),
00091   _degrade_factor(copy._degrade_factor),
00092   _error_count(copy._error_count),
00093   _average_frame_rate_interval(copy._average_frame_rate_interval),
00094   _ticks(copy._ticks),
00095   _cycler(copy._cycler) 
00096 {
00097 }
00098 
00099 ////////////////////////////////////////////////////////////////////
00100 //     Function: ClockObject::set_mode
00101 //       Access: Published
00102 //  Description: Changes the mode of the clock.  Normally, the clock
00103 //               is in mode M_normal. In this mode, each call to
00104 //               tick() will set the value returned by
00105 //               get_frame_time() to the current real time; thus, the
00106 //               clock simply reports time advancing.
00107 //
00108 //               Other possible modes:
00109 //
00110 //               M_non_real_time - the clock ignores real time
00111 //               completely; at each call to tick(), it pretends that
00112 //               exactly dt seconds have elapsed since the last call
00113 //               to tick().  You may set the value of dt with
00114 //               set_dt() or set_frame_rate().
00115 //
00116 //               M_limited - the clock will run as fast as it can, as
00117 //               in M_normal, but will not run faster than the rate
00118 //               specified by set_frame_rate().  If the application
00119 //               would run faster than this rate, the clock will slow
00120 //               down the application.
00121 //
00122 //               M_integer - the clock will run as fast as it can, but
00123 //               the rate will be constrained to be an integer
00124 //               multiple or divisor of the rate specified by
00125 //               set_frame_rate().  The clock will slow down the
00126 //               application a bit to guarantee this.
00127 //
00128 //               M_integer_limited - a combination of M_limited and
00129 //               M_integer; the clock will not run faster than
00130 //               set_frame_rate(), and if it runs slower, it will run
00131 //               at a integer divisor of that rate.
00132 //
00133 //               M_forced - the clock forces the application to run at
00134 //               the rate specified by set_frame_rate().  If the
00135 //               application would run faster than this rate, the
00136 //               clock will slow down the application; if the
00137 //               application would run slower than this rate, the
00138 //               clock slows down time so that the application
00139 //               believes it is running at the given rate.
00140 //
00141 //               M_degrade - the clock runs at real time, but the
00142 //               application is slowed down by a set factor of its
00143 //               frame rate, specified by set_degrade_factor().
00144 //
00145 //               M_slave - the clock does not advance, but relies on
00146 //               the user to call set_frame_time() and/or
00147 //               set_frame_count() each frame.
00148 ////////////////////////////////////////////////////////////////////
00149 void ClockObject::
00150 set_mode(ClockObject::Mode mode) {
00151   Thread *current_thread = Thread::get_current_thread();
00152   nassertv(current_thread->get_pipeline_stage() == 0);
00153   CDWriter cdata(_cycler, current_thread);
00154 
00155   _mode = mode;
00156 
00157   // In case we have set the clock to one of the modes that uses
00158   // _reported_frame_time_epoch, recompute the epoch.
00159   switch (_mode) {
00160   case M_non_real_time:
00161   case M_forced:
00162     cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
00163       cdata->_frame_count / _user_frame_rate;
00164     cdata->_dt = 1.0 / _user_frame_rate;
00165 
00166   default:
00167     break;
00168   }
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: ClockObject::set_real_time
00173 //       Access: Published
00174 //  Description: Resets the clock to the indicated time.  This
00175 //               changes only the real time of the clock as reported
00176 //               by get_real_time(), but does not immediately change
00177 //               the time reported by get_frame_time()--that will
00178 //               change after the next call to tick().  Also see
00179 //               reset(), set_frame_time(), and set_frame_count().
00180 ////////////////////////////////////////////////////////////////////
00181 void ClockObject::
00182 set_real_time(double time) {
00183 #ifdef NOTIFY_DEBUG
00184   // This is only a debug message, since it happens during normal
00185   // development, particularly at startup, or whenever you break into
00186   // the task loop.
00187   if (util_cat.is_debug() && this == _global_clock) {
00188     util_cat.debug()
00189       << "Adjusting global clock's real time by " << time - get_real_time()
00190       << " seconds.\n";
00191   }
00192 #endif  // NOTIFY_DEBUG
00193   _start_short_time = _true_clock->get_short_time() - time;
00194   _start_long_time = _true_clock->get_long_time() - time;
00195 }
00196 
00197 ////////////////////////////////////////////////////////////////////
00198 //     Function: ClockObject::set_frame_time
00199 //       Access: Published
00200 //  Description: Changes the time as reported for the current frame to
00201 //               the indicated time.  Normally, the way to adjust the
00202 //               frame time is via tick(); this function is provided
00203 //               only for occasional special adjustments.
00204 ////////////////////////////////////////////////////////////////////
00205 void ClockObject::
00206 set_frame_time(double time, Thread *current_thread) {
00207   nassertv(current_thread->get_pipeline_stage() == 0);
00208 #ifdef NOTIFY_DEBUG
00209   if (this == _global_clock && _mode != M_slave) {
00210     util_cat.warning()
00211       << "Adjusting global clock's frame time by " << time - get_frame_time()
00212       << " seconds.\n";
00213   }
00214 #endif  // NOTIFY_DEBUG
00215   CDWriter cdata(_cycler, current_thread);
00216   _actual_frame_time = time;
00217   cdata->_reported_frame_time = time;
00218 
00219   // Recompute the epoch in case we are in a mode that relies on this.
00220   cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
00221     cdata->_frame_count / _user_frame_rate;
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: ClockObject::set_frame_count
00226 //       Access: Published
00227 //  Description: Resets the number of frames counted to the indicated
00228 //               number.  Also see reset(), set_real_time(), and
00229 //               set_frame_time().
00230 ////////////////////////////////////////////////////////////////////
00231 void ClockObject::
00232 set_frame_count(int frame_count, Thread *current_thread) {
00233   nassertv(current_thread->get_pipeline_stage() == 0);
00234 #ifdef NOTIFY_DEBUG
00235   if (this == _global_clock && _mode != M_slave) {
00236     util_cat.warning()
00237       << "Adjusting global clock's frame count by " 
00238       << frame_count - get_frame_count() << " frames.\n";
00239   }
00240 #endif  // NOTIFY_DEBUG
00241   CDWriter cdata(_cycler, current_thread);
00242   cdata->_frame_count = frame_count;
00243 
00244   // Recompute the epoch in case we are in a mode that relies on this.
00245   cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
00246     cdata->_frame_count / _user_frame_rate;
00247 }
00248 
00249 ////////////////////////////////////////////////////////////////////
00250 //     Function: ClockObject::set_dt
00251 //       Access: Published
00252 //  Description: In non-real-time mode, sets the number of seconds
00253 //               that should appear to elapse between frames.  In
00254 //               forced mode or limited mode, sets our target dt.  In
00255 //               normal mode, this has no effect.  
00256 //
00257 //               Also see set_frame_rate(), which is a different way
00258 //               to specify the same quantity.
00259 ////////////////////////////////////////////////////////////////////
00260 void ClockObject::
00261 set_dt(double dt) {
00262   if (_mode == M_slave) {
00263     // In M_slave mode, we can set any dt we like.
00264     CDWriter cdata(_cycler, Thread::get_current_thread());
00265     cdata->_dt = dt;
00266     if (dt != 0.0) {
00267       set_frame_rate(1.0 / dt);
00268     }
00269 
00270   } else {
00271     // In any other mode, we can only set non-zero dt.
00272     nassertv(dt != 0.0);
00273     set_frame_rate(1.0 / dt);
00274   }
00275 }
00276 
00277 ////////////////////////////////////////////////////////////////////
00278 //     Function: ClockObject::set_frame_rate
00279 //       Access: Published
00280 //  Description: In non-real-time mode, sets the number of frames per
00281 //               second that we should appear to be running.  In forced
00282 //               mode or limited mode, sets our target frame rate.  In
00283 //               normal mode, this has no effect.
00284 //
00285 //               Also see set_dt(), which is a different way to
00286 //               specify the same quantity.
00287 ////////////////////////////////////////////////////////////////////
00288 void ClockObject::
00289 set_frame_rate(double frame_rate) {
00290   nassertv(frame_rate != 0.0);
00291 
00292   Thread *current_thread = Thread::get_current_thread();
00293   nassertv(current_thread->get_pipeline_stage() == 0);
00294 
00295   CDWriter cdata(_cycler, current_thread);
00296   _user_frame_rate = frame_rate;
00297 
00298   switch (_mode) {
00299   case M_non_real_time:
00300   case M_forced:
00301     cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
00302       cdata->_frame_count / _user_frame_rate;
00303     cdata->_dt = 1.0 / _user_frame_rate;
00304 
00305   default:
00306     break;
00307   }
00308 }
00309 
00310 ////////////////////////////////////////////////////////////////////
00311 //     Function: ClockObject::get_average_frame_rate
00312 //       Access: Published
00313 //  Description: Returns the average frame rate in number of frames
00314 //               per second over the last
00315 //               get_average_frame_rate_interval() seconds.  This
00316 //               measures the virtual frame rate if the clock is in
00317 //               M_non_real_time mode.
00318 ////////////////////////////////////////////////////////////////////
00319 double ClockObject::
00320 get_average_frame_rate(Thread *current_thread) const {
00321   CDStageReader cdata(_cycler, 0, current_thread);
00322   if (_ticks.size() <= 1) {
00323     return 0.0;
00324   } else {
00325     return _ticks.size() / (cdata->_reported_frame_time - _ticks.front());
00326   }
00327 }
00328 
00329 ////////////////////////////////////////////////////////////////////
00330 //     Function: ClockObject::get_max_frame_duration
00331 //       Access: Published
00332 //  Description: Returns the maximum frame duration over the last
00333 //               get_average_frame_rate_interval() seconds.
00334 ////////////////////////////////////////////////////////////////////
00335 double ClockObject::
00336 get_max_frame_duration(Thread *current_thread) const {
00337   CDStageReader cdata(_cycler, 0, current_thread);
00338   double max_duration = 0.0;
00339   double cur_duration = 0.0;
00340   size_t i;
00341   for (i = 0; i < _ticks.size() - 1; i++) {
00342     cur_duration = _ticks[i + 1] - _ticks[i];
00343     if (cur_duration > max_duration) {
00344       max_duration = cur_duration;
00345     }
00346   }
00347   return max_duration;
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: ClockObject::calc_frame_time_deviation
00352 //       Access: Published
00353 //  Description: Returns the standard deviation of the frame times of
00354 //               the frames rendered over the past
00355 //               get_average_frame_rate_interval() seconds.  This
00356 //               number gives an estimate of the chugginess of the
00357 //               frame rate; if it is large, there is a large
00358 //               variation in the frame rate; if is small, all of the
00359 //               frames are consistent in length.
00360 //
00361 //               A large value might also represent just a recent
00362 //               change in frame rate, for instance, because the
00363 //               camera has just rotated from looking at a simple
00364 //               scene to looking at a more complex scene.
00365 ////////////////////////////////////////////////////////////////////
00366 double ClockObject::
00367 calc_frame_rate_deviation(Thread *current_thread) const {
00368   CDStageReader cdata(_cycler, 0, current_thread);
00369   if (_ticks.size() <= 1) {
00370     return 0.0;
00371   } else {
00372     double mean = (_ticks.back() - _ticks.front()) / (_ticks.size() - 1);
00373     size_t i;
00374     double sum_squares = 0.0;
00375     for (i = 0; i < _ticks.size() - 1; ++i) {
00376       double delta = _ticks[i + 1] - _ticks[i];
00377       double diff = (delta - mean);
00378       sum_squares += (diff * diff);
00379     }
00380     double deviation_2 = sum_squares / (_ticks.size() - 1);
00381     return sqrt(deviation_2);
00382   }
00383 }
00384 
00385 ////////////////////////////////////////////////////////////////////
00386 //     Function: ClockObject::tick
00387 //       Access: Published
00388 //  Description: Instructs the clock that a new frame has just begun.
00389 //               In normal, real-time mode, get_frame_time() will
00390 //               henceforth report the time as of this instant as the
00391 //               current start-of-frame time.  In non-real-time mode,
00392 //               get_frame_time() will be incremented by the value of
00393 //               dt.
00394 ////////////////////////////////////////////////////////////////////
00395 void ClockObject::
00396 tick(Thread *current_thread) {
00397   nassertv(current_thread->get_pipeline_stage() == 0);
00398   CDWriter cdata(_cycler, current_thread);
00399   double old_reported_time = cdata->_reported_frame_time;
00400 
00401   if (_mode != M_slave) {
00402     double old_time = _actual_frame_time;
00403     _actual_frame_time = get_real_time();
00404 
00405     // In case someone munged the clock last frame and sent us
00406     // backward in time, clamp the previous time to the current time
00407     // to make sure we don't report anything strange (or wait
00408     // interminably).
00409     old_time = min(old_time, _actual_frame_time);
00410 
00411     ++cdata->_frame_count;
00412     
00413     switch (_mode) {
00414     case M_normal:
00415       // Time runs as it will; we simply report time elapsing.
00416       cdata->_dt = _actual_frame_time - old_time;
00417       cdata->_reported_frame_time = _actual_frame_time;
00418       break;
00419       
00420     case M_non_real_time:
00421       // Ignore real time.  We always report the same interval having
00422       // elapsed each frame.
00423       cdata->_reported_frame_time = cdata->_reported_frame_time_epoch +
00424         cdata->_frame_count / _user_frame_rate;
00425       break;
00426       
00427     case M_limited:
00428       // If we are running faster than the desired interval, slow down.
00429       {
00430         double wait_until_time = old_time + 1.0 / _user_frame_rate;
00431         wait_until(wait_until_time);
00432         cdata->_dt = _actual_frame_time - old_time;
00433         cdata->_reported_frame_time = max(_actual_frame_time, wait_until_time);
00434       }
00435       break;
00436 
00437     case M_integer:
00438       {
00439         double dt = _actual_frame_time - old_time;
00440         double target_dt = 1.0 / _user_frame_rate;
00441         if (dt < target_dt) {
00442           // We're running faster than the desired interval, so slow
00443           // down to the next integer multiple of the frame rate.
00444           target_dt = target_dt / floor(target_dt / dt);
00445         } else {
00446           // We're running slower than the desired interval, so slow
00447           // down to the next integer divisor of the frame rate.
00448           target_dt = target_dt * ceil(dt / target_dt);
00449         }
00450         double wait_until_time = old_time + target_dt;
00451         wait_until(wait_until_time);
00452         cdata->_dt = target_dt;
00453         cdata->_reported_frame_time = wait_until_time;
00454       }
00455       break;
00456 
00457     case M_integer_limited:
00458       {
00459         double dt = _actual_frame_time - old_time;
00460         double target_dt = 1.0 / _user_frame_rate;
00461         if (dt < target_dt) {
00462           // We're running faster than the desired interval, so slow
00463           // down to the target frame rate.
00464 
00465         } else {
00466           // We're running slower than the desired interval, so slow
00467           // down to the next integer divisor of the frame rate.
00468           target_dt = target_dt * ceil(dt / target_dt);
00469         }
00470         double wait_until_time = old_time + target_dt;
00471         wait_until(wait_until_time);
00472         cdata->_dt = target_dt;
00473         cdata->_reported_frame_time = wait_until_time;
00474       }
00475       break;
00476       
00477     case M_forced:
00478       // If we are running faster than the desired interval, slow down.
00479       // If we are running slower than the desired interval, ignore that
00480       // and pretend we're running at the specified rate.
00481       wait_until(old_time + 1.0 / _user_frame_rate);
00482       cdata->_reported_frame_time = cdata->_reported_frame_time_epoch +
00483         cdata->_frame_count / _user_frame_rate;
00484       break;
00485       
00486     case M_degrade:
00487       // Each frame, wait a certain fraction of the previous frame's
00488       // time to degrade performance uniformly.
00489       cdata->_dt = (_actual_frame_time - old_time) * _degrade_factor;
00490       
00491       if (_degrade_factor < 1.0) {
00492         // If the degrade_factor is less than one, we want to simulate a
00493         // higher frame rate by incrementing the clock more slowly.
00494         cdata->_reported_frame_time += cdata->_dt;
00495         
00496       } else {
00497         // Otherwise, we simulate a lower frame rate by waiting until
00498         // the appropriate time has elapsed.
00499         wait_until(old_time + cdata->_dt);
00500         cdata->_reported_frame_time = _actual_frame_time;
00501       }
00502       
00503       break;
00504 
00505     case M_slave:
00506       // Handled above.
00507       break;
00508     }
00509   }
00510 
00511   if (_average_frame_rate_interval > 0.0) {
00512     _ticks.push_back(old_reported_time);
00513     while (_ticks.size() > 2 && 
00514            cdata->_reported_frame_time - _ticks.front() > _average_frame_rate_interval) {
00515       _ticks.pop_front();
00516     }
00517   }
00518 }
00519 
00520 ////////////////////////////////////////////////////////////////////
00521 //     Function: ClockObject::sync_frame_time
00522 //       Access: Published
00523 //  Description: Resets the frame time to the current real time.  This
00524 //               is similar to tick(), except that it does not advance
00525 //               the frame counter and does not affect dt.  This is
00526 //               intended to be used in the middle of a particularly
00527 //               long frame to compensate for the time that has
00528 //               already elapsed.
00529 //
00530 //               In non-real-time mode, this function has no effect
00531 //               (because in this mode all frames take the same length
00532 //               of time).
00533 ////////////////////////////////////////////////////////////////////
00534 void ClockObject::
00535 sync_frame_time(Thread *current_thread) {
00536   if (_mode == M_normal) {
00537     CDWriter cdata(_cycler, current_thread);
00538     cdata->_reported_frame_time = get_real_time();
00539   }
00540 }
00541 
00542 ////////////////////////////////////////////////////////////////////
00543 //     Function: ClockObject::wait_until
00544 //       Access: Private
00545 //  Description: Waits at the end of a frame until the indicated time
00546 //               has arrived.  This is used to implement M_forced and
00547 //               M_degrade.
00548 ////////////////////////////////////////////////////////////////////
00549 void ClockObject::
00550 wait_until(double want_time) {
00551   if (want_time <= _actual_frame_time) {
00552     return;
00553   }
00554 
00555 #ifdef DO_PSTATS
00556   (*_start_clock_wait)();
00557 #endif
00558 
00559   double wait_interval = (want_time - _actual_frame_time) - sleep_precision;
00560     
00561   if (wait_interval > 0.0) {
00562     Thread::sleep(wait_interval);
00563   }
00564 
00565 #ifdef DO_PSTATS
00566   (*_start_clock_busy_wait)();
00567 #endif
00568   
00569   // Now busy-wait until the actual time elapses.
00570   while (_actual_frame_time < want_time) {
00571     _actual_frame_time = get_real_time();
00572   }
00573 
00574 #ifdef DO_PSTATS
00575   (*_stop_clock_wait)();
00576 #endif
00577 }
00578 
00579 ////////////////////////////////////////////////////////////////////
00580 //     Function: ClockObject::make_global_clock
00581 //       Access: Private, Static
00582 //  Description: Called once per application to create the global
00583 //               clock object.
00584 ////////////////////////////////////////////////////////////////////
00585 void ClockObject::
00586 make_global_clock() {
00587   nassertv(_global_clock == (ClockObject *)NULL);
00588 
00589   ConfigVariableEnum<ClockObject::Mode> clock_mode
00590     ("clock-mode", ClockObject::M_normal,
00591      PRC_DESC("Specifies the mode of the global clock.  The default mode, normal, "
00592               "is a real-time clock; other modes allow non-real-time special "
00593               "effects like simulated reduced frame rate.  See "
00594               "ClockObject::set_mode()."));
00595 
00596   _global_clock = new ClockObject;
00597   _global_clock->set_mode(clock_mode);
00598 }
00599 
00600 ////////////////////////////////////////////////////////////////////
00601 //     Function: ClockObject::dummy_clock_wait
00602 //       Access: Private, Static
00603 //  Description: This no-op function is assigned as the initial
00604 //               pointer for _start_clock_wait and _stop_clock_wait,
00605 //               until the PStatClient comes along and replaces it.
00606 ////////////////////////////////////////////////////////////////////
00607 void ClockObject::
00608 dummy_clock_wait() {
00609 }
00610 
00611 ////////////////////////////////////////////////////////////////////
00612 //     Function: ClockObject::CData::Constructor
00613 //       Access: Public
00614 //  Description:
00615 ////////////////////////////////////////////////////////////////////
00616 ClockObject::CData::
00617 CData() {
00618   _frame_count = 0;
00619   _reported_frame_time = 0.0;
00620   _reported_frame_time_epoch = 0.0;
00621   _dt = 0.0;
00622 }
00623 
00624 ////////////////////////////////////////////////////////////////////
00625 //     Function: ClockObject::CData::make_copy
00626 //       Access: Public, Virtual
00627 //  Description:
00628 ////////////////////////////////////////////////////////////////////
00629 CycleData *ClockObject::CData::
00630 make_copy() const {
00631   return new CData(*this);
00632 }
00633 
00634 ////////////////////////////////////////////////////////////////////
00635 //     Function: ClockObject::Mode ostream operator
00636 //  Description:
00637 ////////////////////////////////////////////////////////////////////
00638 ostream &
00639 operator << (ostream &out, ClockObject::Mode mode) {
00640   switch (mode) {
00641   case ClockObject::M_normal:
00642     return out << "normal";
00643 
00644   case ClockObject::M_non_real_time:
00645     return out << "non-real-time";
00646 
00647   case ClockObject::M_limited:
00648     return out << "limited";
00649 
00650   case ClockObject::M_integer:
00651     return out << "integer";
00652 
00653   case ClockObject::M_integer_limited:
00654     return out << "integer_limited";
00655 
00656   case ClockObject::M_forced:
00657     return out << "forced";
00658 
00659   case ClockObject::M_degrade:
00660     return out << "degrade";
00661 
00662   case ClockObject::M_slave:
00663     return out << "slave";
00664   };
00665 
00666   return out << "**invalid ClockObject::Mode(" << (int)mode << ")**";
00667 }
00668 
00669 ////////////////////////////////////////////////////////////////////
00670 //     Function: ClockObject::Mode istream operator
00671 //  Description:
00672 ////////////////////////////////////////////////////////////////////
00673 istream &
00674 operator >> (istream &in, ClockObject::Mode &mode) {
00675   string word;
00676   in >> word;
00677 
00678   if (cmp_nocase_uh(word, "normal") == 0) {
00679     mode = ClockObject::M_normal;
00680   } else if (cmp_nocase_uh(word, "non-real-time") == 0) {
00681     mode = ClockObject::M_non_real_time;
00682   } else if (cmp_nocase_uh(word, "limited") == 0) {
00683     mode = ClockObject::M_limited;
00684   } else if (cmp_nocase_uh(word, "integer") == 0) {
00685     mode = ClockObject::M_integer;
00686   } else if (cmp_nocase_uh(word, "integer_limited") == 0) {
00687     mode = ClockObject::M_integer_limited;
00688   } else if (cmp_nocase_uh(word, "forced") == 0) {
00689     mode = ClockObject::M_forced;
00690   } else if (cmp_nocase_uh(word, "degrade") == 0) {
00691     mode = ClockObject::M_degrade;
00692   } else if (cmp_nocase_uh(word, "slave") == 0) {
00693     mode = ClockObject::M_slave;
00694   } else {
00695     util_cat->error()
00696       << "Invalid ClockObject::Mode: " << word << "\n";
00697     mode = ClockObject::M_normal;
00698   }
00699 
00700   return in;
00701 }
 All Classes Functions Variables Enumerations