Panda3D
|
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 ©) : 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 }