cMetaInterval.cxx 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file cMetaInterval.cxx
  10. * @author drose
  11. * @date 2002-08-27
  12. */
  13. #include "cMetaInterval.h"
  14. #include "waitInterval.h"
  15. #include "config_interval.h"
  16. #include "indirectLess.h"
  17. #include "indent.h"
  18. #include <algorithm>
  19. #include <math.h> // for log10()
  20. #include <stdio.h> // for sprintf()
  21. using std::string;
  22. TypeHandle CMetaInterval::_type_handle;
  23. /**
  24. *
  25. */
  26. CMetaInterval::
  27. CMetaInterval(const string &name) :
  28. CInterval(name, 0.0, true)
  29. {
  30. _precision = interval_precision;
  31. _current_nesting_level = 0;
  32. _next_event_index = 0;
  33. _processing_events = false;
  34. }
  35. /**
  36. *
  37. */
  38. CMetaInterval::
  39. ~CMetaInterval() {
  40. clear_intervals();
  41. }
  42. /**
  43. * Resets the list of intervals and prepares for receiving a new list.
  44. */
  45. void CMetaInterval::
  46. clear_intervals() {
  47. // Better not do this unless you have serviced all of the outstanding
  48. // events!
  49. bool lost_events = false;
  50. if (!_event_queue.empty()) {
  51. interval_cat.warning()
  52. << "Losing outstanding events for " << *this << "\n";
  53. _event_queue.clear();
  54. lost_events = true;
  55. }
  56. clear_events();
  57. // Go through all of our nested intervals and remove ourselves as their
  58. // parent.
  59. Defs::iterator di;
  60. for (di = _defs.begin(); di != _defs.end(); ++di) {
  61. IntervalDef &def = (*di);
  62. if (def._c_interval != nullptr) {
  63. CInterval::Parents::iterator pi =
  64. std::find(def._c_interval->_parents.begin(),
  65. def._c_interval->_parents.end(),
  66. this);
  67. nassertv(pi != def._c_interval->_parents.end());
  68. def._c_interval->_parents.erase(pi);
  69. }
  70. }
  71. _defs.clear();
  72. _current_nesting_level = 0;
  73. _next_event_index = 0;
  74. #ifndef NDEBUG
  75. if (verify_intervals) {
  76. nassertv(!lost_events);
  77. }
  78. #endif
  79. }
  80. /**
  81. * Marks the beginning of a nested level of child intervals. Within the
  82. * nested level, a RelativeStart time of RS_level_begin refers to the start of
  83. * the level, and the first interval added within the level is always relative
  84. * to the start of the level.
  85. *
  86. * The return value is the index of the def entry created by this push.
  87. */
  88. int CMetaInterval::
  89. push_level(const string &name, double rel_time, RelativeStart rel_to) {
  90. nassertr(_event_queue.empty() && !_processing_events, -1);
  91. _defs.push_back(IntervalDef());
  92. IntervalDef &def = _defs.back();
  93. def._type = DT_push_level;
  94. def._ext_name = name;
  95. def._rel_time = rel_time;
  96. def._rel_to = rel_to;
  97. _current_nesting_level++;
  98. mark_dirty();
  99. return (int)_defs.size() - 1;
  100. }
  101. /**
  102. * Adds a new CInterval to the list. The interval will be played when the
  103. * indicated time (relative to the given point) has been reached.
  104. *
  105. * The return value is the index of the def entry representing the new
  106. * interval.
  107. */
  108. int CMetaInterval::
  109. add_c_interval(CInterval *c_interval,
  110. double rel_time, RelativeStart rel_to) {
  111. nassertr(_event_queue.empty() && !_processing_events, -1);
  112. nassertr(c_interval != nullptr, -1);
  113. c_interval->_parents.push_back(this);
  114. c_interval->_ival_pcollector = PStatCollector(_ival_pcollector, c_interval->_pname);
  115. _defs.push_back(IntervalDef());
  116. IntervalDef &def = _defs.back();
  117. def._type = DT_c_interval;
  118. def._c_interval = c_interval;
  119. def._rel_time = rel_time;
  120. def._rel_to = rel_to;
  121. mark_dirty();
  122. return (int)_defs.size() - 1;
  123. }
  124. /**
  125. * Adds a new external interval to the list. This represents some object in
  126. * the external scripting language that has properties similar to a CInterval
  127. * (for instance, a Python Interval object).
  128. *
  129. * The CMetaInterval object cannot play this external interval directly, but
  130. * it records a placeholder for it and will ask the scripting language to play
  131. * it when it is time, via is_event_ready() and related methods.
  132. *
  133. * The ext_index number itself is simply a handle that the scripting language
  134. * makes up and associates with its interval object somehow. The
  135. * CMetaInterval object does not attempt to interpret this value.
  136. *
  137. * The return value is the index of the def entry representing the new
  138. * interval.
  139. */
  140. int CMetaInterval::
  141. add_ext_index(int ext_index, const string &name, double duration,
  142. bool open_ended,
  143. double rel_time, RelativeStart rel_to) {
  144. nassertr(_event_queue.empty() && !_processing_events, -1);
  145. _defs.push_back(IntervalDef());
  146. IntervalDef &def = _defs.back();
  147. def._type = DT_ext_index;
  148. def._ext_index = ext_index;
  149. def._ext_name = name;
  150. def._ext_duration = duration;
  151. def._ext_open_ended = open_ended;
  152. def._rel_time = rel_time;
  153. def._rel_to = rel_to;
  154. mark_dirty();
  155. return (int)_defs.size() - 1;
  156. }
  157. /**
  158. * Finishes a level marked by a previous call to push_level(), and returns to
  159. * the previous level.
  160. *
  161. * If the duration is not negative, it represents a phony duration to assign
  162. * to the level, for the purposes of sequencing later intervals. Otherwise,
  163. * the level's duration is computed based on the intervals within the level.
  164. */
  165. int CMetaInterval::
  166. pop_level(double duration) {
  167. nassertr(_event_queue.empty() && !_processing_events, -1);
  168. nassertr(_current_nesting_level > 0, -1);
  169. _defs.push_back(IntervalDef());
  170. IntervalDef &def = _defs.back();
  171. def._type = DT_pop_level;
  172. def._ext_duration = duration;
  173. _current_nesting_level--;
  174. mark_dirty();
  175. return (int)_defs.size() - 1;
  176. }
  177. /**
  178. * Adjusts the start time of the child interval with the given name, if found.
  179. * This may be either a C++ interval added via add_c_interval(), or an
  180. * external interval added via add_ext_index(); the name must match exactly.
  181. *
  182. * If the interval is found, its start time is adjusted, and all subsequent
  183. * intervals are adjusting accordingly, and true is returned. If a matching
  184. * interval is not found, nothing is changed and false is returned.
  185. */
  186. bool CMetaInterval::
  187. set_interval_start_time(const string &name, double rel_time,
  188. CMetaInterval::RelativeStart rel_to) {
  189. nassertr(_event_queue.empty() && !_processing_events, false);
  190. Defs::iterator di;
  191. for (di = _defs.begin(); di != _defs.end(); ++di) {
  192. IntervalDef &def = (*di);
  193. bool match = false;
  194. switch (def._type) {
  195. case DT_c_interval:
  196. match = (def._c_interval->get_name() == name);
  197. break;
  198. case DT_ext_index:
  199. match = (def._ext_name == name);
  200. break;
  201. default:
  202. break;
  203. }
  204. if (match) {
  205. // Here's the interval.
  206. def._rel_time = rel_time;
  207. def._rel_to = rel_to;
  208. mark_dirty();
  209. return true;
  210. }
  211. }
  212. return false;
  213. }
  214. /**
  215. * Returns the actual start time, relative to the beginning of the interval,
  216. * of the child interval with the given name, if found, or -1 if the interval
  217. * is not found.
  218. */
  219. double CMetaInterval::
  220. get_interval_start_time(const string &name) const {
  221. recompute();
  222. Defs::const_iterator di;
  223. for (di = _defs.begin(); di != _defs.end(); ++di) {
  224. const IntervalDef &def = (*di);
  225. bool match = false;
  226. switch (def._type) {
  227. case DT_c_interval:
  228. match = (def._c_interval->get_name() == name);
  229. break;
  230. case DT_ext_index:
  231. match = (def._ext_name == name);
  232. break;
  233. default:
  234. break;
  235. }
  236. if (match) {
  237. // Here's the interval.
  238. return int_to_double_time(def._actual_begin_time);
  239. }
  240. }
  241. return -1.0;
  242. }
  243. /**
  244. * Returns the actual end time, relative to the beginning of the interval, of
  245. * the child interval with the given name, if found, or -1 if the interval is
  246. * not found.
  247. */
  248. double CMetaInterval::
  249. get_interval_end_time(const string &name) const {
  250. recompute();
  251. Defs::const_iterator di;
  252. for (di = _defs.begin(); di != _defs.end(); ++di) {
  253. const IntervalDef &def = (*di);
  254. bool match = false;
  255. double duration = 0.0;
  256. switch (def._type) {
  257. case DT_c_interval:
  258. duration = def._c_interval->get_duration();
  259. match = (def._c_interval->get_name() == name);
  260. break;
  261. case DT_ext_index:
  262. duration = def._ext_duration;
  263. match = (def._ext_name == name);
  264. break;
  265. default:
  266. break;
  267. }
  268. if (match) {
  269. // Here's the interval.
  270. return int_to_double_time(def._actual_begin_time) + duration;
  271. }
  272. }
  273. return -1.0;
  274. }
  275. /**
  276. * This replaces the first call to priv_step(), and indicates that the
  277. * interval has just begun. This may be overridden by derived classes that
  278. * need to do some explicit initialization on the first call.
  279. */
  280. void CMetaInterval::
  281. priv_initialize(double t) {
  282. if (_processing_events) {
  283. enqueue_self_event(ET_initialize, t);
  284. return;
  285. }
  286. check_stopped(get_class_type(), "priv_initialize");
  287. // It may be tempting to flush the event_queue here, but don't do it. Those
  288. // are events that must still be serviced from some previous interval
  289. // operation. Throwing them away would be a mistake.
  290. recompute();
  291. _next_event_index = 0;
  292. _active.clear();
  293. int now = double_to_int_time(t);
  294. /*
  295. // One special case: if we step to t == 0.0, it really means to the very
  296. // beginning of the interval, *before* any events that occurred at time 0.
  297. // (Most of the time, stepping to a particular time means *after* any events
  298. // that occurred at that time.)
  299. if (t == 0.0) {
  300. now = -1;
  301. }
  302. */
  303. // Now look for events from the beginning up to the current time.
  304. _processing_events = true;
  305. ActiveEvents new_active;
  306. while (_next_event_index < _events.size() &&
  307. _events[_next_event_index]->_time <= now) {
  308. PlaybackEvent *event = _events[_next_event_index];
  309. _next_event_index++;
  310. // Do the indicated event.
  311. do_event_forward(event, new_active, true);
  312. }
  313. finish_events_forward(now, new_active);
  314. _processing_events = false;
  315. _curr_t = t;
  316. _state = S_started;
  317. }
  318. /**
  319. * This is called in lieu of priv_initialize() .. priv_step() ..
  320. * priv_finalize(), when everything is to happen within one frame. The
  321. * interval should initialize itself, then leave itself in the final state.
  322. */
  323. void CMetaInterval::
  324. priv_instant() {
  325. if (_processing_events) {
  326. enqueue_self_event(ET_instant);
  327. return;
  328. }
  329. check_stopped(get_class_type(), "priv_instant");
  330. recompute();
  331. _active.clear();
  332. // Apply all of the events. This just means we invoke "instant" for any end
  333. // or instant event, ignoring the begin events.
  334. _processing_events = true;
  335. PlaybackEvents::iterator ei;
  336. for (ei = _events.begin(); ei != _events.end(); ++ei) {
  337. PlaybackEvent *event = (*ei);
  338. if (event->_type != PET_begin) {
  339. enqueue_event(event->_n, ET_instant, true, 0);
  340. }
  341. }
  342. _processing_events = false;
  343. _next_event_index = _events.size();
  344. _curr_t = get_duration();
  345. _state = S_final;
  346. if (_event_queue.empty()) {
  347. interval_done();
  348. } else {
  349. enqueue_done_event();
  350. }
  351. }
  352. /**
  353. * Advances the time on the interval. The time may either increase (the
  354. * normal case) or decrease (e.g. if the interval is being played by a
  355. * slider).
  356. */
  357. void CMetaInterval::
  358. priv_step(double t) {
  359. if (_processing_events) {
  360. enqueue_self_event(ET_step, t);
  361. return;
  362. }
  363. check_started(get_class_type(), "priv_step");
  364. int now = double_to_int_time(t);
  365. /*
  366. // One special case: if we step to t == 0.0, it really means to the very
  367. // beginning of the interval, *before* any events that occurred at time 0.
  368. // (Most of the time, stepping to a particular time means *after* any events
  369. // that occurred at that time.)
  370. if (t == 0.0) {
  371. now = -1;
  372. }
  373. */
  374. // Now look for events between the last time we ran and the current time.
  375. _processing_events = true;
  376. if (_next_event_index < _events.size() &&
  377. _events[_next_event_index]->_time <= now) {
  378. // The normal case: time is increasing.
  379. ActiveEvents new_active;
  380. while (_next_event_index < _events.size() &&
  381. _events[_next_event_index]->_time <= now) {
  382. PlaybackEvent *event = _events[_next_event_index];
  383. _next_event_index++;
  384. // Do the indicated event.
  385. do_event_forward(event, new_active, false);
  386. }
  387. finish_events_forward(now, new_active);
  388. } else {
  389. // A less usual case: time is decreasing.
  390. ActiveEvents new_active;
  391. while (_next_event_index > 0 &&
  392. _events[_next_event_index - 1]->_time > now) {
  393. _next_event_index--;
  394. PlaybackEvent *event = _events[_next_event_index];
  395. do_event_reverse(event, new_active, false);
  396. }
  397. finish_events_reverse(now, new_active);
  398. }
  399. _processing_events = false;
  400. _curr_t = t;
  401. _state = S_started;
  402. }
  403. /**
  404. * This is called when an interval is interrupted. It should advance the time
  405. * as if priv_step() were called, and also perform whatever cleanup might be
  406. * required.
  407. */
  408. void CMetaInterval::
  409. priv_finalize() {
  410. if (_processing_events) {
  411. enqueue_self_event(ET_finalize);
  412. return;
  413. }
  414. double duration = get_duration();
  415. if (_state == S_initial) {
  416. priv_initialize(duration);
  417. }
  418. // Do all remaining events.
  419. _processing_events = true;
  420. ActiveEvents new_active;
  421. while (_next_event_index < _events.size()) {
  422. PlaybackEvent *event = _events[_next_event_index];
  423. _next_event_index++;
  424. // Do the indicated event.
  425. do_event_forward(event, new_active, true);
  426. }
  427. finish_events_forward(double_to_int_time(duration), new_active);
  428. _processing_events = false;
  429. _curr_t = duration;
  430. _state = S_final;
  431. if (_event_queue.empty()) {
  432. interval_done();
  433. } else {
  434. enqueue_done_event();
  435. }
  436. }
  437. /**
  438. * Similar to priv_initialize(), but this is called when the interval is being
  439. * played backwards; it indicates that the interval should start at the
  440. * finishing state and undo any intervening intervals.
  441. */
  442. void CMetaInterval::
  443. priv_reverse_initialize(double t) {
  444. if (_processing_events) {
  445. enqueue_self_event(ET_reverse_initialize, t);
  446. return;
  447. }
  448. check_stopped(get_class_type(), "priv_reverse_initialize");
  449. // It may be tempting to flush the event_queue here, but don't do it. Those
  450. // are events that must still be serviced from some previous interval
  451. // operation. Throwing them away would be a mistake.
  452. recompute();
  453. _next_event_index = _events.size();
  454. _active.clear();
  455. int now = double_to_int_time(t);
  456. /*
  457. // One special case: if we step to t == 0.0, it really means to the very
  458. // beginning of the interval, *before* any events that occurred at time 0.
  459. // (Most of the time, stepping to a particular time means *after* any events
  460. // that occurred at that time.)
  461. if (t == 0.0) {
  462. now = -1;
  463. }
  464. */
  465. // Now look for events from the end down to the current time.
  466. _processing_events = true;
  467. ActiveEvents new_active;
  468. while (_next_event_index > 0 &&
  469. _events[_next_event_index - 1]->_time > now) {
  470. _next_event_index--;
  471. PlaybackEvent *event = _events[_next_event_index];
  472. // Do the indicated event.
  473. do_event_reverse(event, new_active, true);
  474. }
  475. finish_events_reverse(now, new_active);
  476. _processing_events = false;
  477. _curr_t = t;
  478. _state = S_started;
  479. }
  480. /**
  481. * This is called in lieu of priv_reverse_initialize() .. priv_step() ..
  482. * priv_reverse_finalize(), when everything is to happen within one frame.
  483. * The interval should initialize itself, then leave itself in the initial
  484. * state.
  485. */
  486. void CMetaInterval::
  487. priv_reverse_instant() {
  488. if (_processing_events) {
  489. enqueue_self_event(ET_reverse_instant);
  490. return;
  491. }
  492. check_stopped(get_class_type(), "priv_reverse_instant");
  493. recompute();
  494. _active.clear();
  495. // Apply all of the events. This just means we invoke "instant" for any end
  496. // or instant event, ignoring the begin events.
  497. _processing_events = true;
  498. PlaybackEvents::reverse_iterator ei;
  499. for (ei = _events.rbegin(); ei != _events.rend(); ++ei) {
  500. PlaybackEvent *event = (*ei);
  501. if (event->_type != PET_begin) {
  502. enqueue_event(event->_n, ET_reverse_instant, true, 0);
  503. }
  504. }
  505. _processing_events = false;
  506. _next_event_index = 0;
  507. _curr_t = 0.0;
  508. _state = S_initial;
  509. }
  510. /**
  511. * Called generally following a priv_reverse_initialize(), this indicates the
  512. * interval should set itself to the initial state.
  513. */
  514. void CMetaInterval::
  515. priv_reverse_finalize() {
  516. if (_processing_events) {
  517. enqueue_self_event(ET_reverse_finalize);
  518. return;
  519. }
  520. if (_state == S_initial) {
  521. priv_initialize(0.0);
  522. }
  523. // Do all remaining events at the beginning.
  524. _processing_events = true;
  525. ActiveEvents new_active;
  526. while (_next_event_index > 0) {
  527. _next_event_index--;
  528. PlaybackEvent *event = _events[_next_event_index];
  529. do_event_reverse(event, new_active, true);
  530. }
  531. finish_events_reverse(0, new_active);
  532. _processing_events = false;
  533. _curr_t = 0.0;
  534. _state = S_initial;
  535. }
  536. /**
  537. * This is called while the interval is playing to indicate that it is about
  538. * to be interrupted; that is, priv_step() will not be called for a length of
  539. * time. But the interval should remain in its current state in anticipation
  540. * of being eventually restarted when the calls to priv_step() eventually
  541. * resume.
  542. *
  543. * The purpose of this function is to allow self-running intervals like sound
  544. * intervals to stop the actual sound playback during the pause.
  545. */
  546. void CMetaInterval::
  547. priv_interrupt() {
  548. if (_processing_events) {
  549. enqueue_self_event(ET_interrupt);
  550. return;
  551. }
  552. _processing_events = true;
  553. ActiveEvents::iterator ai;
  554. for (ai = _active.begin(); ai != _active.end(); ++ai) {
  555. PlaybackEvent *event = (*ai);
  556. enqueue_event(event->_n, ET_interrupt, false);
  557. }
  558. _processing_events = false;
  559. if (_state == S_started) {
  560. _state = S_paused;
  561. }
  562. }
  563. /**
  564. * Acknowledges that the external interval on the top of the queue has been
  565. * extracted, and is about to be serviced by the scripting language. This
  566. * prepares the interval so the next call to is_event_ready() will return
  567. * information about the next external interval on the queue, if any.
  568. */
  569. void CMetaInterval::
  570. pop_event() {
  571. #ifndef NDEBUG
  572. nassertv(!_event_queue.empty());
  573. const EventQueueEntry &entry = _event_queue.front();
  574. const IntervalDef &def = _defs[entry._n];
  575. nassertv(def._type == DT_ext_index);
  576. #endif
  577. _event_queue.pop_front();
  578. }
  579. /**
  580. *
  581. */
  582. void CMetaInterval::
  583. write(std::ostream &out, int indent_level) const {
  584. recompute();
  585. // How many digits of precision should we output for time?
  586. int num_decimals = (int)ceil(log10(_precision));
  587. int total_digits = num_decimals + 4;
  588. static const int max_digits = 32; // totally arbitrary
  589. nassertv(total_digits <= max_digits);
  590. char format_str[26];
  591. sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
  592. indent(out, indent_level) << get_name() << ":\n";
  593. int extra_indent_level = 1;
  594. Defs::const_iterator di;
  595. for (di = _defs.begin(); di != _defs.end(); ++di) {
  596. const IntervalDef &def = (*di);
  597. char time_str[max_digits + 1];
  598. sprintf(time_str, format_str, int_to_double_time(def._actual_begin_time));
  599. indent(out, indent_level) << time_str;
  600. write_event_desc(out, def, extra_indent_level);
  601. }
  602. }
  603. /**
  604. * Outputs a list of all events in the order in which they occur.
  605. */
  606. void CMetaInterval::
  607. timeline(std::ostream &out) const {
  608. recompute();
  609. // How many digits of precision should we output for time?
  610. int num_decimals = (int)ceil(log10(_precision));
  611. int total_digits = num_decimals + 4;
  612. static const int max_digits = 32; // totally arbitrary
  613. nassertv(total_digits <= max_digits);
  614. char format_str[26];
  615. sprintf(format_str, "%%%d.%df", total_digits, num_decimals);
  616. int extra_indent_level = 0;
  617. PlaybackEvents::const_iterator ei;
  618. for (ei = _events.begin(); ei != _events.end(); ++ei) {
  619. const PlaybackEvent *event = (*ei);
  620. char time_str[max_digits + 1];
  621. sprintf(time_str, format_str, int_to_double_time(event->_time));
  622. out << time_str;
  623. switch (event->_type) {
  624. case PET_begin:
  625. out << " begin ";
  626. break;
  627. case PET_end:
  628. out << " end ";
  629. break;
  630. case PET_instant:
  631. out << " instant ";
  632. break;
  633. }
  634. int n = event->_n;
  635. nassertv(n >= 0 && n < (int)_defs.size());
  636. const IntervalDef &def = _defs[n];
  637. write_event_desc(out, def, extra_indent_level);
  638. }
  639. }
  640. /**
  641. * Recomputes all of the events (and the duration) according to the set of
  642. * interval defs.
  643. */
  644. void CMetaInterval::
  645. do_recompute() {
  646. _dirty = false;
  647. clear_events();
  648. int n = recompute_level(0, 0, _end_time);
  649. if (n != (int)_defs.size()) {
  650. interval_cat.warning()
  651. << "CMetaInterval pushes don't match pops.\n";
  652. }
  653. // We do a stable_sort() to guarantee ordering of events that have the same
  654. // start time. These must be invoked in the order in which they appear.
  655. std::stable_sort(_events.begin(), _events.end(), IndirectLess<PlaybackEvent>());
  656. _duration = int_to_double_time(_end_time);
  657. }
  658. /**
  659. * Removes all entries from the _events list.
  660. */
  661. void CMetaInterval::
  662. clear_events() {
  663. PlaybackEvents::iterator ei;
  664. for (ei = _events.begin(); ei != _events.end(); ++ei) {
  665. PlaybackEvent *event = (*ei);
  666. delete event;
  667. }
  668. _events.clear();
  669. _active.clear();
  670. }
  671. /**
  672. * Process a single event in the interval, moving forwards in time. If the
  673. * event represents a new begin, adds it to the new_active list; if it is an
  674. * end, finalizes it.
  675. *
  676. * If is_initial is true, it is as if we are in initialize or finalize:
  677. * instant events will be invoked only if they are marked open_ended.
  678. */
  679. void CMetaInterval::
  680. do_event_forward(CMetaInterval::PlaybackEvent *event,
  681. CMetaInterval::ActiveEvents &new_active, bool is_initial) {
  682. switch (event->_type) {
  683. case PET_begin:
  684. nassertv(event->_begin_event == event);
  685. new_active.push_back(event);
  686. break;
  687. case PET_end:
  688. {
  689. // Erase the event from either the new active or the current active
  690. // lists.
  691. ActiveEvents::iterator ai;
  692. ai = std::find(new_active.begin(), new_active.end(), event->_begin_event);
  693. if (ai != new_active.end()) {
  694. new_active.erase(ai);
  695. // This interval was new this frame; we must invoke it as an instant
  696. // event.
  697. enqueue_event(event->_n, ET_instant, is_initial);
  698. } else {
  699. ai = std::find(_active.begin(), _active.end(), event->_begin_event);
  700. if (ai != _active.end()) {
  701. _active.erase(ai);
  702. enqueue_event(event->_n, ET_finalize, is_initial);
  703. } else {
  704. // Hmm, this event wasn't on either list. Maybe there was a start
  705. // event on the list whose time was less than 0.
  706. interval_cat.error()
  707. << "Event " << event->_begin_event->_n << " not on active list.\n";
  708. nassertv(false);
  709. }
  710. }
  711. }
  712. break;
  713. case PET_instant:
  714. nassertv(event->_begin_event == event);
  715. enqueue_event(event->_n, ET_instant, is_initial);
  716. break;
  717. }
  718. }
  719. /**
  720. * After walking through the event list and adding a bunch of new events to
  721. * new_active, finished up by calling priv_step() on all of the events still
  722. * in _active and priv_initialize() on all the events in new_active, then
  723. * copying the events from new_active to active.
  724. */
  725. void CMetaInterval::
  726. finish_events_forward(int now, CMetaInterval::ActiveEvents &new_active) {
  727. // Do whatever's still active.
  728. ActiveEvents::iterator ai;
  729. for (ai = _active.begin(); ai != _active.end(); ++ai) {
  730. PlaybackEvent *event = (*ai);
  731. enqueue_event(event->_n, ET_step, false, now - event->_time);
  732. }
  733. // Initialize whatever new intervals we came across.
  734. for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
  735. PlaybackEvent *event = (*ai);
  736. enqueue_event(event->_n, ET_initialize, false, now - event->_time);
  737. _active.push_back(event);
  738. }
  739. }
  740. /**
  741. * Process a single event in the interval, moving backwards in time. This
  742. * undoes the indicated event. If the event represents a new begin, adds it
  743. * to the new_active list; if it is an end, finalizes it.
  744. *
  745. * If is_initial is true, it is as if we are in reverse_initialize or
  746. * reverse_finalize: instant events will be invoked only if they are marked
  747. * open_ended.
  748. */
  749. void CMetaInterval::
  750. do_event_reverse(CMetaInterval::PlaybackEvent *event,
  751. CMetaInterval::ActiveEvents &new_active, bool is_initial) {
  752. // Undo the indicated event.
  753. switch (event->_type) {
  754. case PET_begin:
  755. {
  756. nassertv(event->_begin_event == event);
  757. // Erase the event from either the new active or the current active
  758. // lists.
  759. ActiveEvents::iterator ai;
  760. ai = std::find(new_active.begin(), new_active.end(), event);
  761. if (ai != new_active.end()) {
  762. new_active.erase(ai);
  763. // This interval was new this frame; we invoke it as an instant event.
  764. enqueue_event(event->_n, ET_reverse_instant, is_initial);
  765. } else {
  766. ai = std::find(_active.begin(), _active.end(), event);
  767. if (ai != _active.end()) {
  768. _active.erase(ai);
  769. enqueue_event(event->_n, ET_reverse_finalize, is_initial);
  770. } else {
  771. // Hmm, this event wasn't on either list. Maybe there was a stop
  772. // event on the list whose time was greater than the total, somehow.
  773. interval_cat.error()
  774. << "Event " << event->_n << " not on active list.\n";
  775. nassertv(false);
  776. }
  777. }
  778. }
  779. break;
  780. case PET_end:
  781. new_active.push_front(event->_begin_event);
  782. break;
  783. case PET_instant:
  784. nassertv(event->_begin_event == event);
  785. enqueue_event(event->_n, ET_reverse_instant, is_initial);
  786. break;
  787. }
  788. }
  789. /**
  790. * After walking through the event list and adding a bunch of new events to
  791. * new_active, finishes up by calling priv_step() on all of the events still
  792. * in _active and priv_reverse_initialize() on all the events in new_active,
  793. * then copying the events from new_active to active.
  794. */
  795. void CMetaInterval::
  796. finish_events_reverse(int now, CMetaInterval::ActiveEvents &new_active) {
  797. // Do whatever's still active.
  798. ActiveEvents::iterator ai;
  799. for (ai = _active.begin(); ai != _active.end(); ++ai) {
  800. PlaybackEvent *event = (*ai);
  801. enqueue_event(event->_n, ET_step, false, now - event->_time);
  802. }
  803. // Initialize whatever new intervals we came across.
  804. for (ai = new_active.begin(); ai != new_active.end(); ++ai) {
  805. PlaybackEvent *event = (*ai);
  806. enqueue_event(event->_n, ET_reverse_initialize, false, now - event->_time);
  807. _active.push_front(event);
  808. }
  809. }
  810. /**
  811. * Enqueues the indicated interval for invocation after we have finished
  812. * scanning for events that need processing this frame.
  813. *
  814. * is_initial is only relevant for event types ET_instant or
  815. * ET_reverse_instant, and indicates whether we are in the priv_initialize()
  816. * (or priv_reverse_initialize()) call, and should therefore only invoke open-
  817. * ended intervals.
  818. *
  819. * time is only relevant for ET_initialize, ET_reverse_initialize, and
  820. * ET_step.
  821. */
  822. void CMetaInterval::
  823. enqueue_event(int n, CInterval::EventType event_type, bool is_initial, int time) {
  824. nassertv(n >= 0 && n < (int)_defs.size());
  825. const IntervalDef &def = _defs[n];
  826. switch (def._type) {
  827. case DT_c_interval:
  828. if (is_initial &&
  829. (event_type == ET_instant || event_type == ET_reverse_instant) &&
  830. !def._c_interval->get_open_ended()) {
  831. // Ignore a non-open-ended interval that we skipped completely past on
  832. // priv_initialize().
  833. return;
  834. } else {
  835. if (_event_queue.empty()) {
  836. // if the event queue is empty, we can process this C++ interval
  837. // immediately. We only need to defer it if there are external (e.g.
  838. // Python) intervals in the queue that need to be processed first.
  839. def._c_interval->priv_do_event(int_to_double_time(time), event_type);
  840. return;
  841. }
  842. }
  843. break;
  844. case DT_ext_index:
  845. if (is_initial &&
  846. (event_type == ET_instant || event_type == ET_reverse_instant) &&
  847. !def._ext_open_ended) {
  848. // Ignore a non-open-ended interval that we skipped completely past on
  849. // priv_initialize().
  850. return;
  851. }
  852. break;
  853. default:
  854. nassertv(false);
  855. return;
  856. }
  857. _event_queue.push_back(EventQueueEntry(n, event_type, time));
  858. }
  859. /**
  860. * Enqueues a reference to *this* interval. This is called only when the
  861. * interval is recursively re-entered; the request will be serviced when the
  862. * current request is done processing.
  863. *
  864. * time is only relevant for ET_initialize, ET_reverse_initialize, and
  865. * ET_step.
  866. */
  867. void CMetaInterval::
  868. enqueue_self_event(CInterval::EventType event_type, double t) {
  869. interval_cat.info()
  870. << "Recursive reentry detected into " << *this << "\n";
  871. int time = double_to_int_time(t);
  872. _event_queue.push_back(EventQueueEntry(-1, event_type, time));
  873. }
  874. /**
  875. * Enqueues a special "event" that simply marks the end of processing of the
  876. * interval; the interval's done event should be thrown now, if it is defined.
  877. */
  878. void CMetaInterval::
  879. enqueue_done_event() {
  880. _event_queue.push_back(EventQueueEntry(-2, ET_finalize, 0));
  881. }
  882. /**
  883. * Invokes whatever C++ intervals might be at the head of the queue, and
  884. * prepares for passing an external interval to the scripting language.
  885. *
  886. * The return value is true if there remains at least one external event to be
  887. * serviced, false if all events are handled.
  888. */
  889. bool CMetaInterval::
  890. service_event_queue() {
  891. while (!_event_queue.empty()) {
  892. nassertr(!_processing_events, true);
  893. const EventQueueEntry &entry = _event_queue.front();
  894. if (entry._n == -1) {
  895. // Index -1 is a special code for *this* interval.
  896. priv_do_event(int_to_double_time(entry._time), entry._event_type);
  897. } else if (entry._n == -2) {
  898. // Index -2 is a special code to indicate the interval is now done, and
  899. // its done event should be thrown.
  900. interval_done();
  901. } else {
  902. nassertr(entry._n >= 0 && entry._n < (int)_defs.size(), false);
  903. const IntervalDef &def = _defs[entry._n];
  904. switch (def._type) {
  905. case DT_c_interval:
  906. // Handle the C++ event.
  907. def._c_interval->priv_do_event(int_to_double_time(entry._time), entry._event_type);
  908. break;
  909. case DT_ext_index:
  910. // Here's an external event; leave it there and return.
  911. return true;
  912. default:
  913. nassertr(false, false);
  914. return false;
  915. }
  916. }
  917. _event_queue.pop_front();
  918. }
  919. // No more events on the queue.
  920. nassertr(!_processing_events, false);
  921. return false;
  922. }
  923. /**
  924. * Recursively recomputes a complete level (delimited by push/pop
  925. * definitions).
  926. *
  927. * The value n on entry refers to the first entry after the push; the return
  928. * value will reference the matching pop, or an index greater than the last
  929. * element in the array if there was no matching pop.
  930. *
  931. * The level_begin value indicates the begin time of this level. On return,
  932. * level_end is filled with the end time of this level.
  933. */
  934. int CMetaInterval::
  935. recompute_level(int n, int level_begin, int &level_end) {
  936. level_end = level_begin;
  937. int previous_begin = level_begin;
  938. int previous_end = level_begin;
  939. while (n < (int)_defs.size() && _defs[n]._type != DT_pop_level) {
  940. IntervalDef &def = _defs[n];
  941. int begin_time = previous_begin;
  942. int end_time = previous_end;
  943. switch (def._type) {
  944. case DT_c_interval:
  945. begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
  946. def._actual_begin_time = begin_time;
  947. end_time = begin_time + double_to_int_time(def._c_interval->get_duration());
  948. if (def._c_interval->is_exact_type(WaitInterval::get_class_type())) {
  949. // Don't bother enqueuing events for WaitIntervals; they're just there
  950. // to fill up time.
  951. } else {
  952. if (begin_time == end_time) {
  953. _events.push_back(new PlaybackEvent(begin_time, n, PET_instant));
  954. } else {
  955. PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin);
  956. PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end);
  957. end->_begin_event = begin;
  958. _events.push_back(begin);
  959. _events.push_back(end);
  960. }
  961. }
  962. break;
  963. case DT_ext_index:
  964. begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
  965. def._actual_begin_time = begin_time;
  966. end_time = begin_time + double_to_int_time(def._ext_duration);
  967. if (begin_time == end_time) {
  968. _events.push_back(new PlaybackEvent(begin_time, n, PET_instant));
  969. } else {
  970. PlaybackEvent *begin = new PlaybackEvent(begin_time, n, PET_begin);
  971. PlaybackEvent *end = new PlaybackEvent(end_time, n, PET_end);
  972. end->_begin_event = begin;
  973. _events.push_back(begin);
  974. _events.push_back(end);
  975. }
  976. break;
  977. case DT_push_level:
  978. begin_time = get_begin_time(def, level_begin, previous_begin, previous_end);
  979. def._actual_begin_time = begin_time;
  980. n = recompute_level(n + 1, begin_time, end_time);
  981. break;
  982. case DT_pop_level:
  983. nassertr(false, _defs.size());
  984. break;
  985. }
  986. previous_begin = begin_time;
  987. previous_end = end_time;
  988. level_end = std::max(level_end, end_time);
  989. n++;
  990. }
  991. if (n < (int)_defs.size()) {
  992. IntervalDef &def = _defs[n];
  993. // If we have a pop record, check it for a phony duration.
  994. if (def._ext_duration >= 0.0) {
  995. level_end = level_begin + double_to_int_time(def._ext_duration);
  996. }
  997. // The final pop "begins" at the level end time, just for clarity on
  998. // output.
  999. def._actual_begin_time = level_end;
  1000. }
  1001. return n;
  1002. }
  1003. /**
  1004. * Returns the integer begin time indicated by the given IntervalDef, given
  1005. * the indicated level begin, previous begin, and previous end times.
  1006. */
  1007. int CMetaInterval::
  1008. get_begin_time(const CMetaInterval::IntervalDef &def, int level_begin,
  1009. int previous_begin, int previous_end) {
  1010. switch (def._rel_to) {
  1011. case RS_previous_end:
  1012. return previous_end + double_to_int_time(def._rel_time);
  1013. case RS_previous_begin:
  1014. return previous_begin + double_to_int_time(def._rel_time);
  1015. case RS_level_begin:
  1016. return level_begin + double_to_int_time(def._rel_time);
  1017. }
  1018. nassertr(false, previous_end);
  1019. return previous_end;
  1020. }
  1021. /**
  1022. * Formats an event for output, for write() or timeline().
  1023. */
  1024. void CMetaInterval::
  1025. write_event_desc(std::ostream &out, const CMetaInterval::IntervalDef &def,
  1026. int &extra_indent_level) const {
  1027. switch (def._type) {
  1028. case DT_c_interval:
  1029. indent(out, extra_indent_level)
  1030. << *def._c_interval;
  1031. if (!def._c_interval->get_open_ended()) {
  1032. out << " (!oe)";
  1033. }
  1034. out << "\n";
  1035. break;
  1036. case DT_ext_index:
  1037. indent(out, extra_indent_level)
  1038. << "*" << def._ext_name;
  1039. if (def._ext_duration != 0.0) {
  1040. out << " dur " << def._ext_duration;
  1041. }
  1042. if (!def._ext_open_ended) {
  1043. out << " (!oe)";
  1044. }
  1045. out<< "\n";
  1046. break;
  1047. case DT_push_level:
  1048. indent(out, extra_indent_level)
  1049. << def._ext_name << " {\n";
  1050. extra_indent_level += 2;
  1051. break;
  1052. case DT_pop_level:
  1053. extra_indent_level -= 2;
  1054. indent(out, extra_indent_level)
  1055. << "}\n";
  1056. break;
  1057. }
  1058. }