15 #include "cMetaInterval.h"
16 #include "waitInterval.h"
17 #include "config_interval.h"
18 #include "indirectLess.h"
33 CMetaInterval(
const string &name) :
36 _precision = interval_precision;
37 _current_nesting_level = 0;
38 _next_event_index = 0;
39 _processing_events =
false;
62 bool lost_events =
false;
63 if (!_event_queue.empty()) {
64 interval_cat.warning()
65 <<
"Losing outstanding events for " << *
this <<
"\n";
75 for (di = _defs.begin(); di != _defs.end(); ++di) {
76 IntervalDef &def = (*di);
77 if (def._c_interval != (
CInterval *)NULL) {
78 CInterval::Parents::iterator pi =
79 find(def._c_interval->_parents.begin(),
80 def._c_interval->_parents.end(),
82 nassertv(pi != def._c_interval->_parents.end());
83 def._c_interval->_parents.erase(pi);
88 _current_nesting_level = 0;
89 _next_event_index = 0;
92 if (verify_intervals) {
93 nassertv(!lost_events);
111 push_level(
const string &name,
double rel_time, RelativeStart rel_to) {
112 nassertr(_event_queue.empty() && !_processing_events, -1);
114 _defs.push_back(IntervalDef());
115 IntervalDef &def = _defs.back();
116 def._type = DT_push_level;
117 def._ext_name = name;
118 def._rel_time = rel_time;
119 def._rel_to = rel_to;
120 _current_nesting_level++;
123 return (
int)_defs.size() - 1;
138 double rel_time, RelativeStart rel_to) {
139 nassertr(_event_queue.empty() && !_processing_events, -1);
140 nassertr(c_interval != (
CInterval *)NULL, -1);
142 c_interval->_parents.push_back(
this);
143 c_interval->_ival_pcollector =
PStatCollector(_ival_pcollector, c_interval->_pname);
144 _defs.push_back(IntervalDef());
145 IntervalDef &def = _defs.back();
146 def._type = DT_c_interval;
147 def._c_interval = c_interval;
148 def._rel_time = rel_time;
149 def._rel_to = rel_to;
152 return (
int)_defs.size() - 1;
180 double rel_time, RelativeStart rel_to) {
181 nassertr(_event_queue.empty() && !_processing_events, -1);
183 _defs.push_back(IntervalDef());
184 IntervalDef &def = _defs.back();
185 def._type = DT_ext_index;
186 def._ext_index = ext_index;
187 def._ext_name = name;
188 def._ext_duration = duration;
189 def._ext_open_ended = open_ended;
190 def._rel_time = rel_time;
191 def._rel_to = rel_to;
194 return (
int)_defs.size() - 1;
211 nassertr(_event_queue.empty() && !_processing_events, -1);
212 nassertr(_current_nesting_level > 0, -1);
214 _defs.push_back(IntervalDef());
215 IntervalDef &def = _defs.back();
216 def._type = DT_pop_level;
217 def._ext_duration = duration;
218 _current_nesting_level--;
221 return (
int)_defs.size() - 1;
241 CMetaInterval::RelativeStart rel_to) {
242 nassertr(_event_queue.empty() && !_processing_events,
false);
244 for (di = _defs.begin(); di != _defs.end(); ++di) {
245 IntervalDef &def = (*di);
250 match = (def._c_interval->get_name() == name);
254 match = (def._ext_name == name);
262 def._rel_time = rel_time;
263 def._rel_to = rel_to;
283 Defs::const_iterator di;
284 for (di = _defs.begin(); di != _defs.end(); ++di) {
285 const IntervalDef &def = (*di);
290 match = (def._c_interval->get_name() == name);
294 match = (def._ext_name == name);
302 return int_to_double_time(def._actual_begin_time);
320 Defs::const_iterator di;
321 for (di = _defs.begin(); di != _defs.end(); ++di) {
322 const IntervalDef &def = (*di);
325 double duration = 0.0;
328 duration = def._c_interval->get_duration();
329 match = (def._c_interval->get_name() == name);
333 duration = def._ext_duration;
334 match = (def._ext_name == name);
342 return int_to_double_time(def._actual_begin_time) + duration;
359 if (_processing_events) {
360 enqueue_self_event(ET_initialize, t);
364 check_stopped(get_class_type(),
"priv_initialize");
371 _next_event_index = 0;
374 int now = double_to_int_time(t);
387 _processing_events =
true;
389 while (_next_event_index < _events.size() &&
390 _events[_next_event_index]->_time <= now) {
391 PlaybackEvent *
event = _events[_next_event_index];
395 do_event_forward(event, new_active,
true);
397 finish_events_forward(now, new_active);
398 _processing_events =
false;
414 if (_processing_events) {
415 enqueue_self_event(ET_instant);
419 check_stopped(get_class_type(),
"priv_instant");
425 _processing_events =
true;
426 PlaybackEvents::iterator ei;
427 for (ei = _events.begin(); ei != _events.end(); ++ei) {
428 PlaybackEvent *
event = (*ei);
429 if (event->_type != PET_begin) {
430 enqueue_event(event->_n, ET_instant,
true, 0);
433 _processing_events =
false;
435 _next_event_index = _events.size();
439 if (_event_queue.empty()) {
442 enqueue_done_event();
455 if (_processing_events) {
456 enqueue_self_event(ET_step, t);
460 check_started(get_class_type(),
"priv_step");
461 int now = double_to_int_time(t);
476 _processing_events =
true;
477 if (_next_event_index < _events.size() &&
478 _events[_next_event_index]->_time <= now) {
481 while (_next_event_index < _events.size() &&
482 _events[_next_event_index]->_time <= now) {
483 PlaybackEvent *
event = _events[_next_event_index];
487 do_event_forward(event, new_active,
false);
490 finish_events_forward(now, new_active);
495 while (_next_event_index > 0 &&
496 _events[_next_event_index - 1]->_time > now) {
498 PlaybackEvent *
event = _events[_next_event_index];
500 do_event_reverse(event, new_active,
false);
503 finish_events_reverse(now, new_active);
505 _processing_events =
false;
520 if (_processing_events) {
521 enqueue_self_event(ET_finalize);
526 if (_state == S_initial) {
531 _processing_events =
true;
533 while (_next_event_index < _events.size()) {
534 PlaybackEvent *
event = _events[_next_event_index];
538 do_event_forward(event, new_active,
true);
540 finish_events_forward(double_to_int_time(duration), new_active);
541 _processing_events =
false;
546 if (_event_queue.empty()) {
549 enqueue_done_event();
563 if (_processing_events) {
564 enqueue_self_event(ET_reverse_initialize, t);
568 check_stopped(get_class_type(),
"priv_reverse_initialize");
575 _next_event_index = _events.size();
578 int now = double_to_int_time(t);
591 _processing_events =
true;
593 while (_next_event_index > 0 &&
594 _events[_next_event_index - 1]->_time > now) {
596 PlaybackEvent *
event = _events[_next_event_index];
599 do_event_reverse(event, new_active,
true);
601 finish_events_reverse(now, new_active);
602 _processing_events =
false;
619 if (_processing_events) {
620 enqueue_self_event(ET_reverse_instant);
624 check_stopped(get_class_type(),
"priv_reverse_instant");
630 _processing_events =
true;
631 PlaybackEvents::reverse_iterator ei;
632 for (ei = _events.rbegin(); ei != _events.rend(); ++ei) {
633 PlaybackEvent *
event = (*ei);
634 if (event->_type != PET_begin) {
635 enqueue_event(event->_n, ET_reverse_instant,
true, 0);
638 _processing_events =
false;
640 _next_event_index = 0;
654 if (_processing_events) {
655 enqueue_self_event(ET_reverse_finalize);
659 if (_state == S_initial) {
664 _processing_events =
true;
667 while (_next_event_index > 0) {
669 PlaybackEvent *
event = _events[_next_event_index];
671 do_event_reverse(event, new_active,
true);
673 finish_events_reverse(0, new_active);
674 _processing_events =
false;
696 if (_processing_events) {
697 enqueue_self_event(ET_interrupt);
701 _processing_events =
true;
702 ActiveEvents::iterator ai;
703 for (ai = _active.begin(); ai != _active.end(); ++ai) {
704 PlaybackEvent *
event = (*ai);
705 enqueue_event(event->_n, ET_interrupt,
false);
707 _processing_events =
false;
709 if (_state == S_started) {
727 nassertv(!_event_queue.empty());
728 const EventQueueEntry &entry = _event_queue.front();
729 const IntervalDef &def = _defs[entry._n];
730 nassertv(def._type == DT_ext_index);
732 _event_queue.pop_front();
741 write(ostream &out,
int indent_level)
const {
745 int num_decimals = (int)ceil(log10(_precision));
746 int total_digits = num_decimals + 4;
747 static const int max_digits = 32;
748 nassertv(total_digits <= max_digits);
750 sprintf(format_str,
"%%%d.%df", total_digits, num_decimals);
752 indent(out, indent_level) <<
get_name() <<
":\n";
754 int extra_indent_level = 1;
755 Defs::const_iterator di;
756 for (di = _defs.begin(); di != _defs.end(); ++di) {
757 const IntervalDef &def = (*di);
758 char time_str[max_digits + 1];
759 sprintf(time_str, format_str, int_to_double_time(def._actual_begin_time));
760 indent(out, indent_level) << time_str;
762 write_event_desc(out, def, extra_indent_level);
777 int num_decimals = (int)ceil(log10(_precision));
778 int total_digits = num_decimals + 4;
779 static const int max_digits = 32;
780 nassertv(total_digits <= max_digits);
782 sprintf(format_str,
"%%%d.%df", total_digits, num_decimals);
784 int extra_indent_level = 0;
785 PlaybackEvents::const_iterator ei;
786 for (ei = _events.begin(); ei != _events.end(); ++ei) {
787 const PlaybackEvent *
event = (*ei);
789 char time_str[max_digits + 1];
790 sprintf(time_str, format_str, int_to_double_time(event->_time));
793 switch (event->_type) {
806 nassertv(n >= 0 && n < (
int)_defs.size());
807 const IntervalDef &def = _defs[n];
809 write_event_desc(out, def, extra_indent_level);
824 int n = recompute_level(0, 0, _end_time);
826 if (n != (
int)_defs.size()) {
827 interval_cat.warning()
828 <<
"CMetaInterval pushes don't match pops.\n";
835 _duration = int_to_double_time(_end_time);
845 PlaybackEvents::iterator ei;
846 for (ei = _events.begin(); ei != _events.end(); ++ei) {
847 PlaybackEvent *
event = (*ei);
867 do_event_forward(CMetaInterval::PlaybackEvent *event,
869 switch (event->_type) {
871 nassertv(event->_begin_event == event);
872 new_active.push_back(event);
879 ActiveEvents::iterator ai;
880 ai = find(new_active.begin(), new_active.end(),
event->_begin_event);
881 if (ai != new_active.end()) {
882 new_active.erase(ai);
885 enqueue_event(event->_n, ET_instant, is_initial);
888 ai = find(_active.begin(), _active.end(),
event->_begin_event);
889 if (ai != _active.end()) {
891 enqueue_event(event->_n, ET_finalize, is_initial);
897 <<
"Event " <<
event->_begin_event->_n <<
" not on active list.\n";
905 nassertv(event->_begin_event == event);
906 enqueue_event(event->_n, ET_instant, is_initial);
923 ActiveEvents::iterator ai;
924 for (ai = _active.begin(); ai != _active.end(); ++ai) {
925 PlaybackEvent *
event = (*ai);
926 enqueue_event(event->_n, ET_step,
false, now - event->_time);
930 for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
931 PlaybackEvent *
event = (*ai);
932 enqueue_event(event->_n, ET_initialize,
false, now - event->_time);
933 _active.push_back(event);
951 do_event_reverse(CMetaInterval::PlaybackEvent *event,
954 switch (event->_type) {
957 nassertv(event->_begin_event == event);
960 ActiveEvents::iterator ai;
961 ai = find(new_active.begin(), new_active.end(), event);
962 if (ai != new_active.end()) {
963 new_active.erase(ai);
966 enqueue_event(event->_n, ET_reverse_instant, is_initial);
969 ai = find(_active.begin(), _active.end(), event);
970 if (ai != _active.end()) {
972 enqueue_event(event->_n, ET_reverse_finalize, is_initial);
979 <<
"Event " <<
event->_n <<
" not on active list.\n";
987 new_active.push_front(event->_begin_event);
991 nassertv(event->_begin_event == event);
992 enqueue_event(event->_n, ET_reverse_instant, is_initial);
1007 void CMetaInterval::
1010 ActiveEvents::iterator ai;
1011 for (ai = _active.begin(); ai != _active.end(); ++ai) {
1012 PlaybackEvent *
event = (*ai);
1013 enqueue_event(event->_n, ET_step,
false, now - event->_time);
1017 for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
1018 PlaybackEvent *
event = (*ai);
1019 enqueue_event(event->_n, ET_reverse_initialize,
false, now - event->_time);
1020 _active.push_front(event);
1040 void CMetaInterval::
1041 enqueue_event(
int n, CInterval::EventType event_type,
bool is_initial,
int time) {
1042 nassertv(n >= 0 && n < (
int)_defs.size());
1043 const IntervalDef &def = _defs[n];
1044 switch (def._type) {
1047 (event_type == ET_instant || event_type == ET_reverse_instant) &&
1048 !def._c_interval->get_open_ended()) {
1053 if (_event_queue.empty()) {
1058 def._c_interval->priv_do_event(int_to_double_time(time), event_type);
1066 (event_type == ET_instant || event_type == ET_reverse_instant) &&
1067 !def._ext_open_ended) {
1079 _event_queue.push_back(EventQueueEntry(n, event_type, time));
1093 void CMetaInterval::
1094 enqueue_self_event(CInterval::EventType event_type,
double t) {
1096 <<
"Recursive reentry detected into " << *
this <<
"\n";
1097 int time = double_to_int_time(t);
1098 _event_queue.push_back(EventQueueEntry(-1, event_type, time));
1108 void CMetaInterval::
1109 enqueue_done_event() {
1110 _event_queue.push_back(EventQueueEntry(-2, ET_finalize, 0));
1124 bool CMetaInterval::
1125 service_event_queue() {
1126 while (!_event_queue.empty()) {
1127 nassertr(!_processing_events,
true);
1128 const EventQueueEntry &entry = _event_queue.front();
1129 if (entry._n == -1) {
1131 priv_do_event(int_to_double_time(entry._time), entry._event_type);
1133 }
else if (entry._n == -2) {
1139 nassertr(entry._n >= 0 && entry._n < (
int)_defs.size(),
false);
1140 const IntervalDef &def = _defs[entry._n];
1141 switch (def._type) {
1144 def._c_interval->priv_do_event(int_to_double_time(entry._time), entry._event_type);
1152 nassertr(
false,
false);
1156 _event_queue.pop_front();
1160 nassertr(!_processing_events,
false);
1180 recompute_level(
int n,
int level_begin,
int &level_end) {
1181 level_end = level_begin;
1182 int previous_begin = level_begin;
1183 int previous_end = level_begin;
1185 while (n < (
int)_defs.size() && _defs[n]._type != DT_pop_level) {
1186 IntervalDef &def = _defs[n];
1187 int begin_time = previous_begin;
1188 int end_time = previous_end;
1189 switch (def._type) {
1191 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
1192 def._actual_begin_time = begin_time;
1193 end_time = begin_time + double_to_int_time(def._c_interval->get_duration());
1195 if (def._c_interval->is_exact_type(WaitInterval::get_class_type())) {
1200 if (begin_time == end_time) {
1201 _events.push_back(
new PlaybackEvent(begin_time, n, PET_instant));
1203 PlaybackEvent *begin =
new PlaybackEvent(begin_time, n, PET_begin);
1204 PlaybackEvent *end =
new PlaybackEvent(end_time, n, PET_end);
1205 end->_begin_event = begin;
1206 _events.push_back(begin);
1207 _events.push_back(end);
1213 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
1214 def._actual_begin_time = begin_time;
1215 end_time = begin_time + double_to_int_time(def._ext_duration);
1216 if (begin_time == end_time) {
1217 _events.push_back(
new PlaybackEvent(begin_time, n, PET_instant));
1219 PlaybackEvent *begin =
new PlaybackEvent(begin_time, n, PET_begin);
1220 PlaybackEvent *end =
new PlaybackEvent(end_time, n, PET_end);
1221 end->_begin_event = begin;
1222 _events.push_back(begin);
1223 _events.push_back(end);
1228 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
1229 def._actual_begin_time = begin_time;
1230 n = recompute_level(n + 1, begin_time, end_time);
1234 nassertr(
false, _defs.size());
1238 previous_begin = begin_time;
1239 previous_end = end_time;
1240 level_end = max(level_end, end_time);
1244 if (n < (
int)_defs.size()) {
1245 IntervalDef &def = _defs[n];
1247 if (def._ext_duration >= 0.0) {
1248 level_end = level_begin + double_to_int_time(def._ext_duration);
1253 def._actual_begin_time = level_end;
1267 get_begin_time(
const CMetaInterval::IntervalDef &def,
int level_begin,
1268 int previous_begin,
int previous_end) {
1269 switch (def._rel_to) {
1270 case RS_previous_end:
1271 return previous_end + double_to_int_time(def._rel_time);
1273 case RS_previous_begin:
1274 return previous_begin + double_to_int_time(def._rel_time);
1276 case RS_level_begin:
1277 return level_begin + double_to_int_time(def._rel_time);
1280 nassertr(
false, previous_end);
1281 return previous_end;
1290 void CMetaInterval::
1291 write_event_desc(ostream &out,
const CMetaInterval::IntervalDef &def,
1292 int &extra_indent_level)
const {
1293 switch (def._type) {
1295 indent(out, extra_indent_level)
1296 << *def._c_interval;
1297 if (!def._c_interval->get_open_ended()) {
1304 indent(out, extra_indent_level)
1305 <<
"*" << def._ext_name;
1306 if (def._ext_duration != 0.0) {
1307 out <<
" dur " << def._ext_duration;
1309 if (!def._ext_open_ended) {
1316 indent(out, extra_indent_level)
1317 << def._ext_name <<
" {\n";
1318 extra_indent_level += 2;
1322 extra_indent_level -= 2;
1323 indent(out, extra_indent_level)
const string & get_name() const
Returns the interval's name.
The base class for timeline components.
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
A lightweight class that represents a single element that may be timed and/or counted via stats...
double get_duration() const
Returns the duration of the interval in seconds.
void priv_do_event(double t, EventType event)
Calls the appropriate event function indicated by the EventType.
void mark_dirty()
Called by a derived class to indicate the interval has been changed internally and must be recomputed...
TypeHandle is the identifier used to differentiate C++ class types.