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)
The base class for timeline components.
This is our own Panda specialization on the default STL list.
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...
const string & get_name() const
Returns the interval's name.
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.