Panda3D
clockObject.cxx
1 // Filename: clockObject.cxx
2 // Created by: drose (17Feb00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "clockObject.h"
16 #include "config_util.h"
17 #include "configVariableEnum.h"
18 #include "string_utils.h"
19 #include "thread.h"
20 
21 void (*ClockObject::_start_clock_wait)() = ClockObject::dummy_clock_wait;
22 void (*ClockObject::_start_clock_busy_wait)() = ClockObject::dummy_clock_wait;
23 void (*ClockObject::_stop_clock_wait)() = ClockObject::dummy_clock_wait;
24 
25 ClockObject *ClockObject::_global_clock;
26 TypeHandle ClockObject::_type_handle;
27 
28 ////////////////////////////////////////////////////////////////////
29 // Function: ClockObject::Constructor
30 // Access: Published
31 // Description:
32 ////////////////////////////////////////////////////////////////////
33 ClockObject::
34 ClockObject() : _ticks(get_class_type()) {
35  _true_clock = TrueClock::get_global_ptr();
36 
37  // Each clock except for the application global clock is created in
38  // M_normal mode. The application global clock is later reset to
39  // respect clock_mode, which comes from the Config.prc file.
40  _mode = M_normal;
41 
42  _start_short_time = _true_clock->get_short_time();
43  _start_long_time = _true_clock->get_long_time();
44  _actual_frame_time = 0.0;
45 
47  ("max-dt", -1.0,
48  PRC_DESC("Sets a limit on the value returned by ClockObject::get_dt(). If "
49  "this value is less than zero, no limit is imposed; "
50  "otherwise, this is the maximum value that will ever "
51  "be returned by get_dt(), regardless of how much time "
52  "has actually elapsed between frames. See ClockObject::set_dt()."));
53  ConfigVariableDouble clock_frame_rate
54  ("clock-frame-rate", 1.0,
55  PRC_DESC("In non-real-time clock mode, sets the number of frames per "
56  "second that we should appear to be running. In forced "
57  "mode or limited mode, sets our target frame rate. In "
58  "normal mode, this has no effect. See ClockObject::set_frame_rate()."));
59  ConfigVariableDouble clock_degrade_factor
60  ("clock-degrade-factor", 1.0,
61  PRC_DESC("In degrade clock mode, returns the ratio by which the "
62  "performance is degraded. A value of 2.0 causes the "
63  "clock to be slowed down by a factor of two (reducing "
64  "performance to 1/2 what would be otherwise). See ClockObject::set_degrade_factor()."));
65  ConfigVariableDouble average_frame_rate_interval
66  ("average-frame-rate-interval", 1.0,
67  PRC_DESC("See ClockObject::set_average_frame_rate_interval()."));
68 
69  _max_dt = max_dt;
70  _user_frame_rate = clock_frame_rate;
71  _degrade_factor = clock_degrade_factor;
72  _average_frame_rate_interval = average_frame_rate_interval;
73 
74  _error_count = _true_clock->get_error_count();
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: ClockObject::Copy Constructor
79 // Access: Published
80 // Description:
81 ////////////////////////////////////////////////////////////////////
82 ClockObject::
83 ClockObject(const ClockObject &copy) :
84  _true_clock(copy._true_clock),
85  _mode(copy._mode),
86  _start_short_time(copy._start_short_time),
87  _start_long_time(copy._start_long_time),
88  _actual_frame_time(copy._actual_frame_time),
89  _max_dt(copy._max_dt),
90  _user_frame_rate(copy._user_frame_rate),
91  _degrade_factor(copy._degrade_factor),
92  _error_count(copy._error_count),
93  _average_frame_rate_interval(copy._average_frame_rate_interval),
94  _ticks(copy._ticks),
95  _cycler(copy._cycler)
96 {
97 }
98 
99 ////////////////////////////////////////////////////////////////////
100 // Function: ClockObject::set_mode
101 // Access: Published
102 // Description: Changes the mode of the clock. Normally, the clock
103 // is in mode M_normal. In this mode, each call to
104 // tick() will set the value returned by
105 // get_frame_time() to the current real time; thus, the
106 // clock simply reports time advancing.
107 //
108 // Other possible modes:
109 //
110 // M_non_real_time - the clock ignores real time
111 // completely; at each call to tick(), it pretends that
112 // exactly dt seconds have elapsed since the last call
113 // to tick(). You may set the value of dt with
114 // set_dt() or set_frame_rate().
115 //
116 // M_limited - the clock will run as fast as it can, as
117 // in M_normal, but will not run faster than the rate
118 // specified by set_frame_rate(). If the application
119 // would run faster than this rate, the clock will slow
120 // down the application.
121 //
122 // M_integer - the clock will run as fast as it can, but
123 // the rate will be constrained to be an integer
124 // multiple or divisor of the rate specified by
125 // set_frame_rate(). The clock will slow down the
126 // application a bit to guarantee this.
127 //
128 // M_integer_limited - a combination of M_limited and
129 // M_integer; the clock will not run faster than
130 // set_frame_rate(), and if it runs slower, it will run
131 // at a integer divisor of that rate.
132 //
133 // M_forced - the clock forces the application to run at
134 // the rate specified by set_frame_rate(). If the
135 // application would run faster than this rate, the
136 // clock will slow down the application; if the
137 // application would run slower than this rate, the
138 // clock slows down time so that the application
139 // believes it is running at the given rate.
140 //
141 // M_degrade - the clock runs at real time, but the
142 // application is slowed down by a set factor of its
143 // frame rate, specified by set_degrade_factor().
144 //
145 // M_slave - the clock does not advance, but relies on
146 // the user to call set_frame_time() and/or
147 // set_frame_count() each frame.
148 ////////////////////////////////////////////////////////////////////
149 void ClockObject::
150 set_mode(ClockObject::Mode mode) {
151  Thread *current_thread = Thread::get_current_thread();
152  nassertv(current_thread->get_pipeline_stage() == 0);
153  CDWriter cdata(_cycler, current_thread);
154 
155  _mode = mode;
156 
157  // In case we have set the clock to one of the modes that uses
158  // _reported_frame_time_epoch, recompute the epoch.
159  switch (_mode) {
160  case M_non_real_time:
161  case M_forced:
162  cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
163  cdata->_frame_count / _user_frame_rate;
164  cdata->_dt = 1.0 / _user_frame_rate;
165 
166  default:
167  break;
168  }
169 }
170 
171 ////////////////////////////////////////////////////////////////////
172 // Function: ClockObject::set_real_time
173 // Access: Published
174 // Description: Resets the clock to the indicated time. This
175 // changes only the real time of the clock as reported
176 // by get_real_time(), but does not immediately change
177 // the time reported by get_frame_time()--that will
178 // change after the next call to tick(). Also see
179 // reset(), set_frame_time(), and set_frame_count().
180 ////////////////////////////////////////////////////////////////////
181 void ClockObject::
182 set_real_time(double time) {
183 #ifdef NOTIFY_DEBUG
184  // This is only a debug message, since it happens during normal
185  // development, particularly at startup, or whenever you break into
186  // the task loop.
187  if (util_cat.is_debug() && this == _global_clock) {
188  util_cat.debug()
189  << "Adjusting global clock's real time by " << time - get_real_time()
190  << " seconds.\n";
191  }
192 #endif // NOTIFY_DEBUG
193  _start_short_time = _true_clock->get_short_time() - time;
194  _start_long_time = _true_clock->get_long_time() - time;
195 }
196 
197 ////////////////////////////////////////////////////////////////////
198 // Function: ClockObject::set_frame_time
199 // Access: Published
200 // Description: Changes the time as reported for the current frame to
201 // the indicated time. Normally, the way to adjust the
202 // frame time is via tick(); this function is provided
203 // only for occasional special adjustments.
204 ////////////////////////////////////////////////////////////////////
205 void ClockObject::
206 set_frame_time(double time, Thread *current_thread) {
207  nassertv(current_thread->get_pipeline_stage() == 0);
208 #ifdef NOTIFY_DEBUG
209  if (this == _global_clock && _mode != M_slave) {
210  util_cat.warning()
211  << "Adjusting global clock's frame time by " << time - get_frame_time()
212  << " seconds.\n";
213  }
214 #endif // NOTIFY_DEBUG
215  CDWriter cdata(_cycler, current_thread);
216  _actual_frame_time = time;
217  cdata->_reported_frame_time = time;
218 
219  // Recompute the epoch in case we are in a mode that relies on this.
220  cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
221  cdata->_frame_count / _user_frame_rate;
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: ClockObject::set_frame_count
226 // Access: Published
227 // Description: Resets the number of frames counted to the indicated
228 // number. Also see reset(), set_real_time(), and
229 // set_frame_time().
230 ////////////////////////////////////////////////////////////////////
231 void ClockObject::
232 set_frame_count(int frame_count, Thread *current_thread) {
233  nassertv(current_thread->get_pipeline_stage() == 0);
234 #ifdef NOTIFY_DEBUG
235  if (this == _global_clock && _mode != M_slave) {
236  util_cat.warning()
237  << "Adjusting global clock's frame count by "
238  << frame_count - get_frame_count() << " frames.\n";
239  }
240 #endif // NOTIFY_DEBUG
241  CDWriter cdata(_cycler, current_thread);
242  cdata->_frame_count = frame_count;
243 
244  // Recompute the epoch in case we are in a mode that relies on this.
245  cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
246  cdata->_frame_count / _user_frame_rate;
247 }
248 
249 ////////////////////////////////////////////////////////////////////
250 // Function: ClockObject::set_dt
251 // Access: Published
252 // Description: In non-real-time mode, sets the number of seconds
253 // that should appear to elapse between frames. In
254 // forced mode or limited mode, sets our target dt. In
255 // normal mode, this has no effect.
256 //
257 // Also see set_frame_rate(), which is a different way
258 // to specify the same quantity.
259 ////////////////////////////////////////////////////////////////////
260 void ClockObject::
261 set_dt(double dt) {
262  if (_mode == M_slave) {
263  // In M_slave mode, we can set any dt we like.
264  CDWriter cdata(_cycler, Thread::get_current_thread());
265  cdata->_dt = dt;
266  if (dt != 0.0) {
267  set_frame_rate(1.0 / dt);
268  }
269 
270  } else {
271  // In any other mode, we can only set non-zero dt.
272  nassertv(dt != 0.0);
273  set_frame_rate(1.0 / dt);
274  }
275 }
276 
277 ////////////////////////////////////////////////////////////////////
278 // Function: ClockObject::set_frame_rate
279 // Access: Published
280 // Description: In non-real-time mode, sets the number of frames per
281 // second that we should appear to be running. In forced
282 // mode or limited mode, sets our target frame rate. In
283 // normal mode, this has no effect.
284 //
285 // Also see set_dt(), which is a different way to
286 // specify the same quantity.
287 ////////////////////////////////////////////////////////////////////
288 void ClockObject::
289 set_frame_rate(double frame_rate) {
290  nassertv(frame_rate != 0.0);
291 
292  Thread *current_thread = Thread::get_current_thread();
293  nassertv(current_thread->get_pipeline_stage() == 0);
294 
295  CDWriter cdata(_cycler, current_thread);
296  _user_frame_rate = frame_rate;
297 
298  switch (_mode) {
299  case M_non_real_time:
300  case M_forced:
301  cdata->_reported_frame_time_epoch = cdata->_reported_frame_time -
302  cdata->_frame_count / _user_frame_rate;
303  cdata->_dt = 1.0 / _user_frame_rate;
304 
305  default:
306  break;
307  }
308 }
309 
310 ////////////////////////////////////////////////////////////////////
311 // Function: ClockObject::get_average_frame_rate
312 // Access: Published
313 // Description: Returns the average frame rate in number of frames
314 // per second over the last
315 // get_average_frame_rate_interval() seconds. This
316 // measures the virtual frame rate if the clock is in
317 // M_non_real_time mode.
318 ////////////////////////////////////////////////////////////////////
319 double ClockObject::
320 get_average_frame_rate(Thread *current_thread) const {
321  CDStageReader cdata(_cycler, 0, current_thread);
322  if (_ticks.size() <= 1) {
323  return 0.0;
324  } else {
325  return _ticks.size() / (cdata->_reported_frame_time - _ticks.front());
326  }
327 }
328 
329 ////////////////////////////////////////////////////////////////////
330 // Function: ClockObject::get_max_frame_duration
331 // Access: Published
332 // Description: Returns the maximum frame duration over the last
333 // get_average_frame_rate_interval() seconds.
334 ////////////////////////////////////////////////////////////////////
335 double ClockObject::
336 get_max_frame_duration(Thread *current_thread) const {
337  CDStageReader cdata(_cycler, 0, current_thread);
338  double max_duration = 0.0;
339  double cur_duration = 0.0;
340  size_t i;
341  for (i = 0; i < _ticks.size() - 1; i++) {
342  cur_duration = _ticks[i + 1] - _ticks[i];
343  if (cur_duration > max_duration) {
344  max_duration = cur_duration;
345  }
346  }
347  return max_duration;
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: ClockObject::calc_frame_time_deviation
352 // Access: Published
353 // Description: Returns the standard deviation of the frame times of
354 // the frames rendered over the past
355 // get_average_frame_rate_interval() seconds. This
356 // number gives an estimate of the chugginess of the
357 // frame rate; if it is large, there is a large
358 // variation in the frame rate; if is small, all of the
359 // frames are consistent in length.
360 //
361 // A large value might also represent just a recent
362 // change in frame rate, for instance, because the
363 // camera has just rotated from looking at a simple
364 // scene to looking at a more complex scene.
365 ////////////////////////////////////////////////////////////////////
366 double ClockObject::
367 calc_frame_rate_deviation(Thread *current_thread) const {
368  CDStageReader cdata(_cycler, 0, current_thread);
369  if (_ticks.size() <= 1) {
370  return 0.0;
371  } else {
372  double mean = (_ticks.back() - _ticks.front()) / (_ticks.size() - 1);
373  size_t i;
374  double sum_squares = 0.0;
375  for (i = 0; i < _ticks.size() - 1; ++i) {
376  double delta = _ticks[i + 1] - _ticks[i];
377  double diff = (delta - mean);
378  sum_squares += (diff * diff);
379  }
380  double deviation_2 = sum_squares / (_ticks.size() - 1);
381  return sqrt(deviation_2);
382  }
383 }
384 
385 ////////////////////////////////////////////////////////////////////
386 // Function: ClockObject::tick
387 // Access: Published
388 // Description: Instructs the clock that a new frame has just begun.
389 // In normal, real-time mode, get_frame_time() will
390 // henceforth report the time as of this instant as the
391 // current start-of-frame time. In non-real-time mode,
392 // get_frame_time() will be incremented by the value of
393 // dt.
394 ////////////////////////////////////////////////////////////////////
395 void ClockObject::
396 tick(Thread *current_thread) {
397  nassertv(current_thread->get_pipeline_stage() == 0);
398  CDWriter cdata(_cycler, current_thread);
399  double old_reported_time = cdata->_reported_frame_time;
400 
401  if (_mode != M_slave) {
402  double old_time = _actual_frame_time;
403  _actual_frame_time = get_real_time();
404 
405  // In case someone munged the clock last frame and sent us
406  // backward in time, clamp the previous time to the current time
407  // to make sure we don't report anything strange (or wait
408  // interminably).
409  old_time = min(old_time, _actual_frame_time);
410 
411  ++cdata->_frame_count;
412 
413  switch (_mode) {
414  case M_normal:
415  // Time runs as it will; we simply report time elapsing.
416  cdata->_dt = _actual_frame_time - old_time;
417  cdata->_reported_frame_time = _actual_frame_time;
418  break;
419 
420  case M_non_real_time:
421  // Ignore real time. We always report the same interval having
422  // elapsed each frame.
423  cdata->_reported_frame_time = cdata->_reported_frame_time_epoch +
424  cdata->_frame_count / _user_frame_rate;
425  break;
426 
427  case M_limited:
428  // If we are running faster than the desired interval, slow down.
429  {
430  double wait_until_time = old_time + 1.0 / _user_frame_rate;
431  wait_until(wait_until_time);
432  cdata->_dt = _actual_frame_time - old_time;
433  cdata->_reported_frame_time = max(_actual_frame_time, wait_until_time);
434  }
435  break;
436 
437  case M_integer:
438  {
439  double dt = _actual_frame_time - old_time;
440  double target_dt = 1.0 / _user_frame_rate;
441  if (dt < target_dt) {
442  // We're running faster than the desired interval, so slow
443  // down to the next integer multiple of the frame rate.
444  target_dt = target_dt / floor(target_dt / dt);
445  } else {
446  // We're running slower than the desired interval, so slow
447  // down to the next integer divisor of the frame rate.
448  target_dt = target_dt * ceil(dt / target_dt);
449  }
450  double wait_until_time = old_time + target_dt;
451  wait_until(wait_until_time);
452  cdata->_dt = target_dt;
453  cdata->_reported_frame_time = wait_until_time;
454  }
455  break;
456 
457  case M_integer_limited:
458  {
459  double dt = _actual_frame_time - old_time;
460  double target_dt = 1.0 / _user_frame_rate;
461  if (dt < target_dt) {
462  // We're running faster than the desired interval, so slow
463  // down to the target frame rate.
464 
465  } else {
466  // We're running slower than the desired interval, so slow
467  // down to the next integer divisor of the frame rate.
468  target_dt = target_dt * ceil(dt / target_dt);
469  }
470  double wait_until_time = old_time + target_dt;
471  wait_until(wait_until_time);
472  cdata->_dt = target_dt;
473  cdata->_reported_frame_time = wait_until_time;
474  }
475  break;
476 
477  case M_forced:
478  // If we are running faster than the desired interval, slow down.
479  // If we are running slower than the desired interval, ignore that
480  // and pretend we're running at the specified rate.
481  wait_until(old_time + 1.0 / _user_frame_rate);
482  cdata->_reported_frame_time = cdata->_reported_frame_time_epoch +
483  cdata->_frame_count / _user_frame_rate;
484  break;
485 
486  case M_degrade:
487  // Each frame, wait a certain fraction of the previous frame's
488  // time to degrade performance uniformly.
489  cdata->_dt = (_actual_frame_time - old_time) * _degrade_factor;
490 
491  if (_degrade_factor < 1.0) {
492  // If the degrade_factor is less than one, we want to simulate a
493  // higher frame rate by incrementing the clock more slowly.
494  cdata->_reported_frame_time += cdata->_dt;
495 
496  } else {
497  // Otherwise, we simulate a lower frame rate by waiting until
498  // the appropriate time has elapsed.
499  wait_until(old_time + cdata->_dt);
500  cdata->_reported_frame_time = _actual_frame_time;
501  }
502 
503  break;
504 
505  case M_slave:
506  // Handled above.
507  break;
508  }
509  }
510 
511  if (_average_frame_rate_interval > 0.0) {
512  _ticks.push_back(old_reported_time);
513  while (_ticks.size() > 2 &&
514  cdata->_reported_frame_time - _ticks.front() > _average_frame_rate_interval) {
515  _ticks.pop_front();
516  }
517  }
518 }
519 
520 ////////////////////////////////////////////////////////////////////
521 // Function: ClockObject::sync_frame_time
522 // Access: Published
523 // Description: Resets the frame time to the current real time. This
524 // is similar to tick(), except that it does not advance
525 // the frame counter and does not affect dt. This is
526 // intended to be used in the middle of a particularly
527 // long frame to compensate for the time that has
528 // already elapsed.
529 //
530 // In non-real-time mode, this function has no effect
531 // (because in this mode all frames take the same length
532 // of time).
533 ////////////////////////////////////////////////////////////////////
534 void ClockObject::
535 sync_frame_time(Thread *current_thread) {
536  if (_mode == M_normal) {
537  CDWriter cdata(_cycler, current_thread);
538  cdata->_reported_frame_time = get_real_time();
539  }
540 }
541 
542 ////////////////////////////////////////////////////////////////////
543 // Function: ClockObject::wait_until
544 // Access: Private
545 // Description: Waits at the end of a frame until the indicated time
546 // has arrived. This is used to implement M_forced and
547 // M_degrade.
548 ////////////////////////////////////////////////////////////////////
549 void ClockObject::
550 wait_until(double want_time) {
551  if (want_time <= _actual_frame_time) {
552  return;
553  }
554 
555 #ifdef DO_PSTATS
556  (*_start_clock_wait)();
557 #endif
558 
559  double wait_interval = (want_time - _actual_frame_time) - sleep_precision;
560 
561  if (wait_interval > 0.0) {
562  Thread::sleep(wait_interval);
563  }
564 
565 #ifdef DO_PSTATS
566  (*_start_clock_busy_wait)();
567 #endif
568 
569  // Now busy-wait until the actual time elapses.
570  while (_actual_frame_time < want_time) {
571  _actual_frame_time = get_real_time();
572  }
573 
574 #ifdef DO_PSTATS
575  (*_stop_clock_wait)();
576 #endif
577 }
578 
579 ////////////////////////////////////////////////////////////////////
580 // Function: ClockObject::make_global_clock
581 // Access: Private, Static
582 // Description: Called once per application to create the global
583 // clock object.
584 ////////////////////////////////////////////////////////////////////
585 void ClockObject::
586 make_global_clock() {
587  nassertv(_global_clock == (ClockObject *)NULL);
588 
590  ("clock-mode", ClockObject::M_normal,
591  PRC_DESC("Specifies the mode of the global clock. The default mode, normal, "
592  "is a real-time clock; other modes allow non-real-time special "
593  "effects like simulated reduced frame rate. See "
594  "ClockObject::set_mode()."));
595 
596  _global_clock = new ClockObject;
597  _global_clock->set_mode(clock_mode);
598  _global_clock->ref();
599 }
600 
601 ////////////////////////////////////////////////////////////////////
602 // Function: ClockObject::dummy_clock_wait
603 // Access: Private, Static
604 // Description: This no-op function is assigned as the initial
605 // pointer for _start_clock_wait and _stop_clock_wait,
606 // until the PStatClient comes along and replaces it.
607 ////////////////////////////////////////////////////////////////////
608 void ClockObject::
609 dummy_clock_wait() {
610 }
611 
612 ////////////////////////////////////////////////////////////////////
613 // Function: ClockObject::CData::Constructor
614 // Access: Public
615 // Description:
616 ////////////////////////////////////////////////////////////////////
617 ClockObject::CData::
618 CData() {
619  _frame_count = 0;
620  _reported_frame_time = 0.0;
621  _reported_frame_time_epoch = 0.0;
622  _dt = 0.0;
623 }
624 
625 ////////////////////////////////////////////////////////////////////
626 // Function: ClockObject::CData::make_copy
627 // Access: Public, Virtual
628 // Description:
629 ////////////////////////////////////////////////////////////////////
630 CycleData *ClockObject::CData::
631 make_copy() const {
632  return new CData(*this);
633 }
634 
635 ////////////////////////////////////////////////////////////////////
636 // Function: ClockObject::Mode ostream operator
637 // Description:
638 ////////////////////////////////////////////////////////////////////
639 ostream &
640 operator << (ostream &out, ClockObject::Mode mode) {
641  switch (mode) {
642  case ClockObject::M_normal:
643  return out << "normal";
644 
645  case ClockObject::M_non_real_time:
646  return out << "non-real-time";
647 
648  case ClockObject::M_limited:
649  return out << "limited";
650 
651  case ClockObject::M_integer:
652  return out << "integer";
653 
654  case ClockObject::M_integer_limited:
655  return out << "integer_limited";
656 
657  case ClockObject::M_forced:
658  return out << "forced";
659 
660  case ClockObject::M_degrade:
661  return out << "degrade";
662 
663  case ClockObject::M_slave:
664  return out << "slave";
665  };
666 
667  return out << "**invalid ClockObject::Mode(" << (int)mode << ")**";
668 }
669 
670 ////////////////////////////////////////////////////////////////////
671 // Function: ClockObject::Mode istream operator
672 // Description:
673 ////////////////////////////////////////////////////////////////////
674 istream &
675 operator >> (istream &in, ClockObject::Mode &mode) {
676  string word;
677  in >> word;
678 
679  if (cmp_nocase_uh(word, "normal") == 0) {
680  mode = ClockObject::M_normal;
681  } else if (cmp_nocase_uh(word, "non-real-time") == 0) {
682  mode = ClockObject::M_non_real_time;
683  } else if (cmp_nocase_uh(word, "limited") == 0) {
684  mode = ClockObject::M_limited;
685  } else if (cmp_nocase_uh(word, "integer") == 0) {
686  mode = ClockObject::M_integer;
687  } else if (cmp_nocase_uh(word, "integer_limited") == 0) {
688  mode = ClockObject::M_integer_limited;
689  } else if (cmp_nocase_uh(word, "forced") == 0) {
690  mode = ClockObject::M_forced;
691  } else if (cmp_nocase_uh(word, "degrade") == 0) {
692  mode = ClockObject::M_degrade;
693  } else if (cmp_nocase_uh(word, "slave") == 0) {
694  mode = ClockObject::M_slave;
695  } else {
696  util_cat->error()
697  << "Invalid ClockObject::Mode: " << word << "\n";
698  mode = ClockObject::M_normal;
699  }
700 
701  return in;
702 }
void tick(Thread *current_thread=Thread::get_current_thread())
Instructs the clock that a new frame has just begun.
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:81
void set_dt(double dt)
In non-real-time mode, sets the number of seconds that should appear to elapse between frames...
double get_max_frame_duration(Thread *current_thread=Thread::get_current_thread()) const
Returns the maximum frame duration over the last get_average_frame_rate_interval() seconds...
double calc_frame_rate_deviation(Thread *current_thread=Thread::get_current_thread()) const
Returns the standard deviation of the frame times of the frames rendered over the past get_average_fr...
int get_pipeline_stage() const
Returns the Pipeline stage number associated with this thread.
Definition: thread.I:84
void set_frame_time(double time, Thread *current_thread=Thread::get_current_thread())
Changes the time as reported for the current frame to the indicated time.
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
void set_frame_rate(double frame_rate)
In non-real-time mode, sets the number of frames per second that we should appear to be running...
double get_frame_time(Thread *current_thread=Thread::get_current_thread()) const
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.I:48
void sync_frame_time(Thread *current_thread=Thread::get_current_thread())
Resets the frame time to the current real time.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
This is a convenience class to specialize ConfigVariable as a floating-point type.
void set_real_time(double time)
Resets the clock to the indicated time.
int get_frame_count(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of times tick() has been called since the ClockObject was created, or since it was last reset.
Definition: clockObject.I:113
double get_average_frame_rate(Thread *current_thread=Thread::get_current_thread()) const
Returns the average frame rate in number of frames per second over the last get_average_frame_rate_in...
A ClockObject keeps track of elapsed real time and discrete time.
Definition: clockObject.h:66
double get_real_time() const
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
Definition: clockObject.I:68
This class specializes ConfigVariable as an enumerated type.
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
static void sleep(double seconds)
Suspends the current thread for at least the indicated amount of time.
Definition: thread.I:236
void ref() const
Explicitly increments the reference count.
void set_frame_count(int frame_count, Thread *current_thread=Thread::get_current_thread())
Resets the number of frames counted to the indicated number.
void set_mode(Mode mode)
Changes the mode of the clock.
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
A thread; that is, a lightweight process.
Definition: thread.h:51
int get_error_count() const
Returns the number of clock errors that have been detected.
Definition: trueClock.I:70
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85