32 CMetaInterval(
const string &name) :
35 _precision = interval_precision;
36 _current_nesting_level = 0;
37 _next_event_index = 0;
38 _processing_events =
false;
56 bool lost_events =
false;
57 if (!_event_queue.empty()) {
58 interval_cat.warning()
59 <<
"Losing outstanding events for " << *
this <<
"\n";
69 for (di = _defs.begin(); di != _defs.end(); ++di) {
70 IntervalDef &def = (*di);
71 if (def._c_interval !=
nullptr) {
72 CInterval::Parents::iterator pi =
73 find(def._c_interval->_parents.begin(),
74 def._c_interval->_parents.end(),
76 nassertv(pi != def._c_interval->_parents.end());
77 def._c_interval->_parents.erase(pi);
82 _current_nesting_level = 0;
83 _next_event_index = 0;
86 if (verify_intervals) {
87 nassertv(!lost_events);
101 push_level(
const string &name,
double rel_time, RelativeStart rel_to) {
102 nassertr(_event_queue.empty() && !_processing_events, -1);
104 _defs.push_back(IntervalDef());
105 IntervalDef &def = _defs.back();
106 def._type = DT_push_level;
107 def._ext_name = name;
108 def._rel_time = rel_time;
109 def._rel_to = rel_to;
110 _current_nesting_level++;
113 return (
int)_defs.size() - 1;
125 double rel_time, RelativeStart rel_to) {
126 nassertr(_event_queue.empty() && !_processing_events, -1);
127 nassertr(c_interval !=
nullptr, -1);
129 c_interval->_parents.push_back(
this);
130 c_interval->_ival_pcollector =
PStatCollector(_ival_pcollector, c_interval->_pname);
131 _defs.push_back(IntervalDef());
132 IntervalDef &def = _defs.back();
133 def._type = DT_c_interval;
134 def._c_interval = c_interval;
135 def._rel_time = rel_time;
136 def._rel_to = rel_to;
139 return (
int)_defs.size() - 1;
161 double rel_time, RelativeStart rel_to) {
162 nassertr(_event_queue.empty() && !_processing_events, -1);
164 _defs.push_back(IntervalDef());
165 IntervalDef &def = _defs.back();
166 def._type = DT_ext_index;
167 def._ext_index = ext_index;
168 def._ext_name = name;
169 def._ext_duration = duration;
170 def._ext_open_ended = open_ended;
171 def._rel_time = rel_time;
172 def._rel_to = rel_to;
175 return (
int)_defs.size() - 1;
188 nassertr(_event_queue.empty() && !_processing_events, -1);
189 nassertr(_current_nesting_level > 0, -1);
191 _defs.push_back(IntervalDef());
192 IntervalDef &def = _defs.back();
193 def._type = DT_pop_level;
194 def._ext_duration = duration;
195 _current_nesting_level--;
198 return (
int)_defs.size() - 1;
212 CMetaInterval::RelativeStart rel_to) {
213 nassertr(_event_queue.empty() && !_processing_events,
false);
215 for (di = _defs.begin(); di != _defs.end(); ++di) {
216 IntervalDef &def = (*di);
221 match = (def._c_interval->get_name() == name);
225 match = (def._ext_name == name);
233 def._rel_time = rel_time;
234 def._rel_to = rel_to;
251 Defs::const_iterator di;
252 for (di = _defs.begin(); di != _defs.end(); ++di) {
253 const IntervalDef &def = (*di);
258 match = (def._c_interval->get_name() == name);
262 match = (def._ext_name == name);
270 return int_to_double_time(def._actual_begin_time);
285 Defs::const_iterator di;
286 for (di = _defs.begin(); di != _defs.end(); ++di) {
287 const IntervalDef &def = (*di);
290 double duration = 0.0;
293 duration = def._c_interval->get_duration();
294 match = (def._c_interval->get_name() == name);
298 duration = def._ext_duration;
299 match = (def._ext_name == name);
307 return int_to_double_time(def._actual_begin_time) + duration;
321 if (_processing_events) {
322 enqueue_self_event(ET_initialize, t);
326 check_stopped(get_class_type(),
"priv_initialize");
332 _next_event_index = 0;
335 int now = double_to_int_time(t);
348 _processing_events =
true;
350 while (_next_event_index < _events.size() &&
351 _events[_next_event_index]->_time <= now) {
352 PlaybackEvent *
event = _events[_next_event_index];
356 do_event_forward(event, new_active,
true);
358 finish_events_forward(now, new_active);
359 _processing_events =
false;
372 if (_processing_events) {
373 enqueue_self_event(ET_instant);
377 check_stopped(get_class_type(),
"priv_instant");
383 _processing_events =
true;
384 PlaybackEvents::iterator ei;
385 for (ei = _events.begin(); ei != _events.end(); ++ei) {
386 PlaybackEvent *
event = (*ei);
387 if (event->_type != PET_begin) {
388 enqueue_event(event->_n, ET_instant,
true, 0);
391 _processing_events =
false;
393 _next_event_index = _events.size();
397 if (_event_queue.empty()) {
400 enqueue_done_event();
411 if (_processing_events) {
412 enqueue_self_event(ET_step, t);
416 check_started(get_class_type(),
"priv_step");
417 int now = double_to_int_time(t);
431 _processing_events =
true;
432 if (_next_event_index < _events.size() &&
433 _events[_next_event_index]->_time <= now) {
436 while (_next_event_index < _events.size() &&
437 _events[_next_event_index]->_time <= now) {
438 PlaybackEvent *
event = _events[_next_event_index];
442 do_event_forward(event, new_active,
false);
445 finish_events_forward(now, new_active);
450 while (_next_event_index > 0 &&
451 _events[_next_event_index - 1]->_time > now) {
453 PlaybackEvent *
event = _events[_next_event_index];
455 do_event_reverse(event, new_active,
false);
458 finish_events_reverse(now, new_active);
460 _processing_events =
false;
473 if (_processing_events) {
474 enqueue_self_event(ET_finalize);
479 if (_state == S_initial) {
484 _processing_events =
true;
486 while (_next_event_index < _events.size()) {
487 PlaybackEvent *
event = _events[_next_event_index];
491 do_event_forward(event, new_active,
true);
493 finish_events_forward(double_to_int_time(duration), new_active);
494 _processing_events =
false;
499 if (_event_queue.empty()) {
502 enqueue_done_event();
513 if (_processing_events) {
514 enqueue_self_event(ET_reverse_initialize, t);
518 check_stopped(get_class_type(),
"priv_reverse_initialize");
524 _next_event_index = _events.size();
527 int now = double_to_int_time(t);
540 _processing_events =
true;
542 while (_next_event_index > 0 &&
543 _events[_next_event_index - 1]->_time > now) {
545 PlaybackEvent *
event = _events[_next_event_index];
548 do_event_reverse(event, new_active,
true);
550 finish_events_reverse(now, new_active);
551 _processing_events =
false;
565 if (_processing_events) {
566 enqueue_self_event(ET_reverse_instant);
570 check_stopped(get_class_type(),
"priv_reverse_instant");
576 _processing_events =
true;
577 PlaybackEvents::reverse_iterator ei;
578 for (ei = _events.rbegin(); ei != _events.rend(); ++ei) {
579 PlaybackEvent *
event = (*ei);
580 if (event->_type != PET_begin) {
581 enqueue_event(event->_n, ET_reverse_instant,
true, 0);
584 _processing_events =
false;
586 _next_event_index = 0;
597 if (_processing_events) {
598 enqueue_self_event(ET_reverse_finalize);
602 if (_state == S_initial) {
607 _processing_events =
true;
610 while (_next_event_index > 0) {
612 PlaybackEvent *
event = _events[_next_event_index];
614 do_event_reverse(event, new_active,
true);
616 finish_events_reverse(0, new_active);
617 _processing_events =
false;
635 if (_processing_events) {
636 enqueue_self_event(ET_interrupt);
640 _processing_events =
true;
641 ActiveEvents::iterator ai;
642 for (ai = _active.begin(); ai != _active.end(); ++ai) {
643 PlaybackEvent *
event = (*ai);
644 enqueue_event(event->_n, ET_interrupt,
false);
646 _processing_events =
false;
648 if (_state == S_started) {
662 nassertv(!_event_queue.empty());
663 const EventQueueEntry &entry = _event_queue.front();
664 const IntervalDef &def = _defs[entry._n];
665 nassertv(def._type == DT_ext_index);
667 _event_queue.pop_front();
674 write(std::ostream &out,
int indent_level)
const {
678 int num_decimals = (int)ceil(log10(_precision));
679 int total_digits = num_decimals + 4;
680 static const int max_digits = 32;
681 nassertv(total_digits <= max_digits);
683 sprintf(format_str,
"%%%d.%df", total_digits, num_decimals);
685 indent(out, indent_level) << get_name() <<
":\n";
687 int extra_indent_level = 1;
688 Defs::const_iterator di;
689 for (di = _defs.begin(); di != _defs.end(); ++di) {
690 const IntervalDef &def = (*di);
691 char time_str[max_digits + 1];
692 sprintf(time_str, format_str, int_to_double_time(def._actual_begin_time));
693 indent(out, indent_level) << time_str;
695 write_event_desc(out, def, extra_indent_level);
707 int num_decimals = (int)ceil(log10(_precision));
708 int total_digits = num_decimals + 4;
709 static const int max_digits = 32;
710 nassertv(total_digits <= max_digits);
712 sprintf(format_str,
"%%%d.%df", total_digits, num_decimals);
714 int extra_indent_level = 0;
715 PlaybackEvents::const_iterator ei;
716 for (ei = _events.begin(); ei != _events.end(); ++ei) {
717 const PlaybackEvent *
event = (*ei);
719 char time_str[max_digits + 1];
720 sprintf(time_str, format_str, int_to_double_time(event->_time));
723 switch (event->_type) {
736 nassertv(n >= 0 && n < (
int)_defs.size());
737 const IntervalDef &def = _defs[n];
739 write_event_desc(out, def, extra_indent_level);
752 int n = recompute_level(0, 0, _end_time);
754 if (n != (
int)_defs.size()) {
755 interval_cat.warning()
756 <<
"CMetaInterval pushes don't match pops.\n";
762 _duration = int_to_double_time(_end_time);
770 PlaybackEvents::iterator ei;
771 for (ei = _events.begin(); ei != _events.end(); ++ei) {
772 PlaybackEvent *
event = (*ei);
788 do_event_forward(CMetaInterval::PlaybackEvent *event,
790 switch (event->_type) {
792 nassertv(event->_begin_event == event);
793 new_active.push_back(event);
800 ActiveEvents::iterator ai;
801 ai = find(new_active.begin(), new_active.end(),
event->_begin_event);
802 if (ai != new_active.end()) {
803 new_active.erase(ai);
806 enqueue_event(event->_n, ET_instant, is_initial);
809 ai = find(_active.begin(), _active.end(),
event->_begin_event);
810 if (ai != _active.end()) {
812 enqueue_event(event->_n, ET_finalize, is_initial);
818 <<
"Event " <<
event->_begin_event->_n <<
" not on active list.\n";
826 nassertv(event->_begin_event == event);
827 enqueue_event(event->_n, ET_instant, is_initial);
841 ActiveEvents::iterator ai;
842 for (ai = _active.begin(); ai != _active.end(); ++ai) {
843 PlaybackEvent *
event = (*ai);
844 enqueue_event(event->_n, ET_step,
false, now - event->_time);
848 for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
849 PlaybackEvent *
event = (*ai);
850 enqueue_event(event->_n, ET_initialize,
false, now - event->_time);
851 _active.push_back(event);
865 do_event_reverse(CMetaInterval::PlaybackEvent *event,
868 switch (event->_type) {
871 nassertv(event->_begin_event == event);
874 ActiveEvents::iterator ai;
875 ai = find(new_active.begin(), new_active.end(), event);
876 if (ai != new_active.end()) {
877 new_active.erase(ai);
879 enqueue_event(event->_n, ET_reverse_instant, is_initial);
882 ai = find(_active.begin(), _active.end(), event);
883 if (ai != _active.end()) {
885 enqueue_event(event->_n, ET_reverse_finalize, is_initial);
891 <<
"Event " <<
event->_n <<
" not on active list.\n";
899 new_active.push_front(event->_begin_event);
903 nassertv(event->_begin_event == event);
904 enqueue_event(event->_n, ET_reverse_instant, is_initial);
918 ActiveEvents::iterator ai;
919 for (ai = _active.begin(); ai != _active.end(); ++ai) {
920 PlaybackEvent *
event = (*ai);
921 enqueue_event(event->_n, ET_step,
false, now - event->_time);
925 for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
926 PlaybackEvent *
event = (*ai);
927 enqueue_event(event->_n, ET_reverse_initialize,
false, now - event->_time);
928 _active.push_front(event);
945 enqueue_event(
int n, CInterval::EventType event_type,
bool is_initial,
int time) {
946 nassertv(n >= 0 && n < (
int)_defs.size());
947 const IntervalDef &def = _defs[n];
951 (event_type == ET_instant || event_type == ET_reverse_instant) &&
952 !def._c_interval->get_open_ended()) {
957 if (_event_queue.empty()) {
961 def._c_interval->priv_do_event(int_to_double_time(time), event_type);
969 (event_type == ET_instant || event_type == ET_reverse_instant) &&
970 !def._ext_open_ended) {
982 _event_queue.push_back(EventQueueEntry(n, event_type, time));
994 enqueue_self_event(CInterval::EventType event_type,
double t) {
996 <<
"Recursive reentry detected into " << *
this <<
"\n";
997 int time = double_to_int_time(t);
998 _event_queue.push_back(EventQueueEntry(-1, event_type, time));
1005 void CMetaInterval::
1006 enqueue_done_event() {
1007 _event_queue.push_back(EventQueueEntry(-2, ET_finalize, 0));
1017 bool CMetaInterval::
1018 service_event_queue() {
1019 while (!_event_queue.empty()) {
1020 nassertr(!_processing_events,
true);
1021 const EventQueueEntry &entry = _event_queue.front();
1022 if (entry._n == -1) {
1024 priv_do_event(int_to_double_time(entry._time), entry._event_type);
1026 }
else if (entry._n == -2) {
1032 nassertr(entry._n >= 0 && entry._n < (
int)_defs.size(),
false);
1033 const IntervalDef &def = _defs[entry._n];
1034 switch (def._type) {
1037 def._c_interval->priv_do_event(int_to_double_time(entry._time), entry._event_type);
1045 nassertr(
false,
false);
1049 _event_queue.pop_front();
1053 nassertr(!_processing_events,
false);
1069 recompute_level(
int n,
int level_begin,
int &level_end) {
1070 level_end = level_begin;
1071 int previous_begin = level_begin;
1072 int previous_end = level_begin;
1074 while (n < (
int)_defs.size() && _defs[n]._type != DT_pop_level) {
1075 IntervalDef &def = _defs[n];
1076 int begin_time = previous_begin;
1077 int end_time = previous_end;
1078 switch (def._type) {
1080 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
1081 def._actual_begin_time = begin_time;
1082 end_time = begin_time + double_to_int_time(def._c_interval->get_duration());
1084 if (def._c_interval->is_exact_type(WaitInterval::get_class_type())) {
1089 if (begin_time == end_time) {
1090 _events.push_back(
new PlaybackEvent(begin_time, n, PET_instant));
1092 PlaybackEvent *begin =
new PlaybackEvent(begin_time, n, PET_begin);
1093 PlaybackEvent *end =
new PlaybackEvent(end_time, n, PET_end);
1094 end->_begin_event = begin;
1095 _events.push_back(begin);
1096 _events.push_back(end);
1102 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
1103 def._actual_begin_time = begin_time;
1104 end_time = begin_time + double_to_int_time(def._ext_duration);
1105 if (begin_time == end_time) {
1106 _events.push_back(
new PlaybackEvent(begin_time, n, PET_instant));
1108 PlaybackEvent *begin =
new PlaybackEvent(begin_time, n, PET_begin);
1109 PlaybackEvent *end =
new PlaybackEvent(end_time, n, PET_end);
1110 end->_begin_event = begin;
1111 _events.push_back(begin);
1112 _events.push_back(end);
1117 begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
1118 def._actual_begin_time = begin_time;
1119 n = recompute_level(n + 1, begin_time, end_time);
1123 nassertr(
false, _defs.size());
1127 previous_begin = begin_time;
1128 previous_end = end_time;
1129 level_end = std::max(level_end, end_time);
1133 if (n < (
int)_defs.size()) {
1134 IntervalDef &def = _defs[n];
1136 if (def._ext_duration >= 0.0) {
1137 level_end = level_begin + double_to_int_time(def._ext_duration);
1142 def._actual_begin_time = level_end;
1153 get_begin_time(
const CMetaInterval::IntervalDef &def,
int level_begin,
1154 int previous_begin,
int previous_end) {
1155 switch (def._rel_to) {
1156 case RS_previous_end:
1157 return previous_end + double_to_int_time(def._rel_time);
1159 case RS_previous_begin:
1160 return previous_begin + double_to_int_time(def._rel_time);
1162 case RS_level_begin:
1163 return level_begin + double_to_int_time(def._rel_time);
1166 nassertr(
false, previous_end);
1167 return previous_end;
1173 void CMetaInterval::
1174 write_event_desc(std::ostream &out,
const CMetaInterval::IntervalDef &def,
1175 int &extra_indent_level)
const {
1176 switch (def._type) {
1178 indent(out, extra_indent_level)
1179 << *def._c_interval;
1180 if (!def._c_interval->get_open_ended()) {
1187 indent(out, extra_indent_level)
1188 <<
"*" << def._ext_name;
1189 if (def._ext_duration != 0.0) {
1190 out <<
" dur " << def._ext_duration;
1192 if (!def._ext_open_ended) {
1199 indent(out, extra_indent_level)
1200 << def._ext_name <<
" {\n";
1201 extra_indent_level += 2;
1205 extra_indent_level -= 2;
1206 indent(out, extra_indent_level)
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_duration
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.