Panda3D
partBundle.cxx
Go to the documentation of this file.
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 partBundle.cxx
10  * @author drose
11  * @date 1999-02-22
12  */
13 
14 #include "partBundle.h"
15 #include "animBundle.h"
16 #include "animBundleNode.h"
17 #include "animControl.h"
18 #include "loader.h"
19 #include "animPreloadTable.h"
20 #include "config_chan.h"
21 #include "bitArray.h"
22 #include "string_utils.h"
23 #include "indent.h"
24 #include "datagram.h"
25 #include "datagramIterator.h"
26 #include "bamReader.h"
27 #include "bamWriter.h"
28 #include "configVariableEnum.h"
29 #include "loaderOptions.h"
30 #include "bindAnimRequest.h"
31 
32 #include <algorithm>
33 
34 using std::istream;
35 using std::ostream;
36 using std::string;
37 
38 TypeHandle PartBundle::_type_handle;
39 
40 
41 static ConfigVariableEnum<PartBundle::BlendType> anim_blend_type
42 ("anim-blend-type", PartBundle::BT_normalized_linear,
43  PRC_DESC("The default blend type to use for blending animations between "
44  "frames, or between multiple animations. See interpolate-frames, "
45  "and also PartBundle::set_anim_blend_flag() and "
46  "PartBundle::set_frame_blend_flag()."));
47 
48 
49 /**
50  * Normally, you'd use make_copy() or copy_subgraph() to make a copy of this.
51  */
52 PartBundle::
53 PartBundle(const PartBundle &copy) :
54  PartGroup(copy)
55 {
56  _anim_preload = copy._anim_preload;
57  _update_delay = 0.0;
58 
59  CDWriter cdata(_cycler, true);
60  CDReader cdata_from(copy._cycler);
61  cdata->_blend_type = cdata_from->_blend_type;
62  cdata->_anim_blend_flag = cdata_from->_anim_blend_flag;
63  cdata->_frame_blend_flag = cdata_from->_frame_blend_flag;
64  cdata->_root_xform = cdata_from->_root_xform;
65 }
66 
67 /**
68  * Normally, a PartBundle constructor should not be called directly--it will
69  * get created when a PartBundleNode is created.
70  */
71 PartBundle::
72 PartBundle(const string &name) :
73  PartGroup(name)
74 {
75  _update_delay = 0.0;
76 }
77 
78 /**
79  * Allocates and returns a new copy of the node. Children are not copied, but
80  * see copy_subgraph().
81  */
83 make_copy() const {
84  return new PartBundle(*this);
85 }
86 
87 /**
88  * Copies the contents of the other PartBundle's preload table into this one.
89  */
90 void PartBundle::
92  if (other->_anim_preload == nullptr ||
93  _anim_preload == other->_anim_preload) {
94  // No-op.
95  return;
96  }
97 
98  if (_anim_preload == nullptr) {
99  // Trivial case.
100  _anim_preload = other->_anim_preload;
101  return;
102  }
103 
104  // Copy-on-write.
105  PT(AnimPreloadTable) anim_preload = _anim_preload.get_write_pointer();
106  anim_preload->add_anims_from(other->_anim_preload.get_read_pointer());
107 }
108 
109 /**
110  * Defines the way the character responds to multiple calls to
111  * set_control_effect()). By default, this flag is set false, which disallows
112  * multiple animations. When this flag is false, it is not necessary to
113  * explicitly set the control_effect when starting an animation; starting the
114  * animation will implicitly remove the control_effect from the previous
115  * animation and set it on the current one.
116  *
117  * However, if this flag is set true, the control_effect must be explicitly
118  * set via set_control_effect() whenever an animation is to affect the
119  * character.
120  */
121 void PartBundle::
122 set_anim_blend_flag(bool anim_blend_flag) {
123  nassertv(Thread::get_current_pipeline_stage() == 0);
124 
125  CDLockedReader cdata(_cycler);
126  if (cdata->_anim_blend_flag != anim_blend_flag) {
127  CDWriter cdataw(_cycler, cdata);
128  cdataw->_anim_blend_flag = anim_blend_flag;
129 
130  if (!anim_blend_flag && cdataw->_blend.size() > 1) {
131  // If we just changed to disallow animation blending, we should
132  // eliminate all the AnimControls other than the most-recently-added
133  // one.
134 
135  nassertv(cdataw->_last_control_set != nullptr);
136  clear_and_stop_intersecting(cdataw->_last_control_set, cdataw);
137  }
138 
139  cdataw->_anim_changed = true;
140  }
141 }
142 
143 /**
144  * Returns a PartBundle that is a duplicate of this one, but with the
145  * indicated transform applied. If this is called multiple times with the
146  * same TransformState pointer, it returns the same PartBundle each time.
147  */
148 PT(PartBundle) PartBundle::
149 apply_transform(const TransformState *transform) {
150  if (transform->is_identity()) {
151  // Trivial no-op.
152  return this;
153  }
154 
155  AppliedTransforms::iterator ati = _applied_transforms.find(transform);
156  if (ati != _applied_transforms.end()) {
157  if ((*ati).first.is_valid_pointer()) {
158  if (auto new_bundle = (*ati).second.lock()) {
159  // Here's our cached result.
160  return new_bundle;
161  }
162  }
163  }
164 
165  PT(PartBundle) new_bundle = DCAST(PartBundle, copy_subgraph());
166  new_bundle->xform(transform->get_mat());
167 
168  if (ati != _applied_transforms.end()) {
169  // A stale pointer to a deleted result. Update it.
170  (*ati).first.refresh();
171  (*ati).second = new_bundle;
172  } else {
173  // No such result yet. Store it.
174  bool inserted = _applied_transforms.insert(AppliedTransforms::value_type(transform, new_bundle)).second;
175  nassertr(inserted, new_bundle);
176  }
177 
178  // Make sure the new transform gets immediately applied to all of the
179  // joints.
180  new_bundle->force_update();
181 
182  return new_bundle;
183 }
184 
185 /**
186  * Sets the control effect of all AnimControls to zero (but does not "stop"
187  * the AnimControls). The character will no longer be affected by any
188  * animation, and will return to its default pose (unless restore-initial-pose
189  * is false).
190  *
191  * The AnimControls which are no longer associated will not be using any CPU
192  * cycles, but they may still be in the "playing" state; if they are later
193  * reassociated with the PartBundle they will resume at their current frame as
194  * if they'd been running all along.
195  */
196 void PartBundle::
198  nassertv(Thread::get_current_pipeline_stage() == 0);
199 
200  CDLockedReader cdata(_cycler);
201  if (!cdata->_blend.empty()) {
202  CDWriter cdataw(_cycler, cdata);
203  cdataw->_blend.clear();
204  cdataw->_net_blend = 0.0f;
205  cdataw->_anim_changed = true;
207  }
208 }
209 
210 /**
211  * Writes a one-line description of the bundle.
212  */
213 void PartBundle::
214 output(ostream &out) const {
215  out << get_type() << " " << get_name();
216 }
217 
218 /**
219  * Writes a brief description of the bundle and all of its descendants.
220  */
221 void PartBundle::
222 write(ostream &out, int indent_level) const {
223  indent(out, indent_level)
224  << get_type() << " " << get_name() << " {\n";
225  write_descendants(out, indent_level + 2);
226  indent(out, indent_level) << "}\n";
227 }
228 
229 
230 /**
231  * Binds the animation to the bundle, if possible, and returns a new
232  * AnimControl that can be used to start and stop the animation. If the anim
233  * hierarchy does not match the part hierarchy, returns NULL.
234  *
235  * If hierarchy_match_flags is 0, only an exact match is accepted; otherwise,
236  * it may contain a union of PartGroup::HierarchyMatchFlags values indicating
237  * conditions that will be tolerated (but warnings will still be issued).
238  *
239  * If subset is specified, it restricts the binding only to the named subtree
240  * of joints.
241  *
242  * The AnimControl is not stored within the PartBundle; it is the user's
243  * responsibility to maintain the pointer. The animation will automatically
244  * unbind itself when the AnimControl destructs (i.e. its reference count
245  * goes to zero).
246  */
247 PT(AnimControl) PartBundle::
248 bind_anim(AnimBundle *anim, int hierarchy_match_flags,
249  const PartSubset &subset) {
250  PT(AnimControl) control = new AnimControl(anim->get_name(), this, 1.0f, 0);
251  if (do_bind_anim(control, anim, hierarchy_match_flags, subset)) {
252  return control;
253  }
254 
255  return nullptr;
256 }
257 
258 /**
259  * Binds an animation to the bundle. The animation is loaded from the disk
260  * via the indicated Loader object. In other respects, this behaves similarly
261  * to bind_anim(), with the addition of asynchronous support.
262  *
263  * If allow_aysnc is true, the load will be asynchronous if possible. This
264  * requires that the animation basename can be found in the PartBundle's
265  * preload table (see get_anim_preload()).
266  *
267  * In an asynchronous load, the animation file will be loaded and bound in a
268  * sub-thread. This means that the animation will not necessarily be
269  * available at the time this method returns. You may still use the returned
270  * AnimControl immediately, though, but no visible effect will occur until the
271  * animation eventually becomes available.
272  *
273  * You can test AnimControl::is_pending() to see if the animation has been
274  * loaded yet, or wait for it to finish with AnimControl::wait_pending() or
275  * even PartBundle::wait_pending(). You can also set an event to be triggered
276  * when the animation finishes loading with
277  * AnimControl::set_pending_done_event().
278  */
279 PT(AnimControl) PartBundle::
280 load_bind_anim(Loader *loader, const Filename &filename,
281  int hierarchy_match_flags, const PartSubset &subset,
282  bool allow_async) {
283  nassertr(loader != nullptr, nullptr);
284 
285  LoaderOptions anim_options(LoaderOptions::LF_search |
286  LoaderOptions::LF_report_errors |
287  LoaderOptions::LF_convert_anim);
288  string basename = filename.get_basename_wo_extension();
289 
290  int anim_index = -1;
291  CPT(AnimPreloadTable) anim_preload = _anim_preload.get_read_pointer();
292  if (anim_preload != nullptr) {
293  anim_index = anim_preload->find_anim(basename);
294  }
295 
296  if (anim_index < 0 || !allow_async || !Thread::is_threading_supported()) {
297  // The animation is not present in the table, or allow_async is false.
298  // Therefore, perform an ordinary synchronous load-and-bind.
299 
300  PT(PandaNode) model = loader->load_sync(filename, anim_options);
301  if (model == nullptr) {
302  // Couldn't load the file.
303  return nullptr;
304  }
306  if (anim == nullptr) {
307  // No anim bundle.
308  return nullptr;
309  }
310  PT(AnimControl) control = bind_anim(anim, hierarchy_match_flags, subset);
311  if (control == nullptr) {
312  // Couldn't bind.
313  return nullptr;
314  }
315  control->set_anim_model(model);
316  return control;
317  }
318 
319  // The animation is present in the table, so we can perform an asynchronous
320  // load-and-bind.
321  PN_stdfloat frame_rate = anim_preload->get_base_frame_rate(anim_index);
322  int num_frames = anim_preload->get_num_frames(anim_index);
323  PT(AnimControl) control =
324  new AnimControl(basename, this, frame_rate, num_frames);
325 
326  if (!subset.is_include_empty()) {
327  // Figure out the actual subset of joints to be bound.
328  int joint_index = 0;
329  BitArray bound_joints;
330  find_bound_joints(joint_index, false, bound_joints, subset);
331  control->set_bound_joints(bound_joints);
332  }
333 
334  PT(BindAnimRequest) request =
335  new BindAnimRequest(string("bind:") + filename.get_basename(),
336  filename, anim_options, loader, control,
337  hierarchy_match_flags, subset);
338  request->set_priority(async_bind_priority);
339  loader->load_async(request);
340 
341  return control;
342 }
343 
344 /**
345  * Blocks the current thread until all currently-pending AnimControls, with a
346  * nonzero control effect, have been loaded and are properly bound.
347  */
348 void PartBundle::
350  CDReader cdata(_cycler);
351  ChannelBlend::const_iterator cbi;
352  for (cbi = cdata->_blend.begin();
353  cbi != cdata->_blend.end();
354  ++cbi) {
355  AnimControl *control = (*cbi).first;
356  PN_stdfloat effect = (*cbi).second;
357  if (effect != 0.0f) {
358  control->wait_pending();
359  }
360  }
361 }
362 
363 /**
364  * Specifies that the joint with the indicated name should be frozen with the
365  * specified transform. It will henceforth always hold this fixed transform,
366  * regardless of any animations that may subsequently be bound to the joint.
367  *
368  * Returns true if the joint is successfully frozen, or false if the named
369  * child is not a joint (or slider) or does not exist.
370  */
371 bool PartBundle::
372 freeze_joint(const string &joint_name, const TransformState *transform) {
373  PartGroup *child = find_child(joint_name);
374  if (child == nullptr) {
375  return false;
376  }
377 
378  CDWriter cdata(_cycler, false);
379  cdata->_anim_changed = true;
380 
381  return child->apply_freeze(transform);
382 }
383 
384 /**
385  * Specifies that the joint with the indicated name should be frozen with the
386  * specified transform. It will henceforth always hold this fixed transform,
387  * regardless of any animations that may subsequently be bound to the joint.
388  *
389  * Returns true if the joint is successfully frozen, or false if the named
390  * child is not a joint (or slider) or does not exist.
391  */
392 bool PartBundle::
393 freeze_joint(const string &joint_name, const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale) {
394  PartGroup *child = find_child(joint_name);
395  if (child == nullptr) {
396  return false;
397  }
398 
399  CDWriter cdata(_cycler, false);
400  cdata->_anim_changed = true;
401 
402  return child->apply_freeze_matrix(pos, hpr, scale);
403 }
404 
405 /**
406  * Specifies that the joint with the indicated name should be frozen with the
407  * specified transform. It will henceforth always hold this fixed transform,
408  * regardless of any animations that may subsequently be bound to the joint.
409  *
410  * Returns true if the joint is successfully frozen, or false if the named
411  * child is not a joint (or slider) or does not exist.
412  */
413 bool PartBundle::
414 freeze_joint(const string &joint_name, PN_stdfloat value) {
415  PartGroup *child = find_child(joint_name);
416  if (child == nullptr) {
417  return false;
418  }
419 
420  CDWriter cdata(_cycler, false);
421  cdata->_anim_changed = true;
422 
423  return child->apply_freeze_scalar(value);
424 }
425 
426 /**
427  * Specifies that the joint with the indicated name should be animated with
428  * the transform on the indicated node. It will henceforth always follow the
429  * node's transform, regardless of any animations that may subsequently be
430  * bound to the joint.
431  *
432  * Returns true if the joint is successfully controlled, or false if the named
433  * child is not a joint (or slider) or does not exist.
434  */
435 bool PartBundle::
436 control_joint(const string &joint_name, PandaNode *node) {
437  PartGroup *child = find_child(joint_name);
438  if (child == nullptr) {
439  return false;
440  }
441 
442  CDWriter cdata(_cycler, false);
443  cdata->_anim_changed = true;
444 
445  return child->apply_control(node);
446 }
447 
448 /**
449  * Releases the named joint from the effects of a previous call to
450  * freeze_joint() or control_joint(). It will henceforth once again follow
451  * whatever transforms are dictated by the animation.
452  *
453  * Returns true if the joint is released, or false if the named child was not
454  * previously controlled or frozen, or it does not exist.
455  */
456 bool PartBundle::
457 release_joint(const string &joint_name) {
458  PartGroup *child = find_child(joint_name);
459  if (child == nullptr) {
460  return false;
461  }
462 
463  CDWriter cdata(_cycler, false);
464  cdata->_anim_changed = true;
465 
466  return child->clear_forced_channel();
467 }
468 
469 /**
470  * Updates all the parts in the bundle to reflect the data for the current
471  * frame (as set in each of the AnimControls).
472  *
473  * Returns true if any part has changed as a result of this, or false
474  * otherwise.
475  */
476 bool PartBundle::
478  Thread *current_thread = Thread::get_current_thread();
479  CDWriter cdata(_cycler, false, current_thread);
480  bool any_changed = false;
481 
482  double now = ClockObject::get_global_clock()->get_frame_time(current_thread);
483  if (now > cdata->_last_update + _update_delay || cdata->_anim_changed) {
484  bool anim_changed = cdata->_anim_changed;
485  bool frame_blend_flag = cdata->_frame_blend_flag;
486 
487  any_changed = do_update(this, cdata, nullptr, false, anim_changed,
488  current_thread);
489 
490  // Now update all the controls for next time.
491  ChannelBlend::const_iterator cbi;
492  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
493  AnimControl *control = (*cbi).first;
494  control->mark_channels(frame_blend_flag);
495  }
496 
497  cdata->_anim_changed = false;
498  cdata->_last_update = now;
499  }
500 
501  return any_changed;
502 }
503 
504 /**
505  * Updates all the parts in the bundle to reflect the data for the current
506  * frame, whether we believe it needs it or not.
507  */
508 bool PartBundle::
510  Thread *current_thread = Thread::get_current_thread();
511  CDWriter cdata(_cycler, false, current_thread);
512  bool any_changed = do_update(this, cdata, nullptr, true, true, current_thread);
513 
514  // Now update all the controls for next time.
515  ChannelBlend::const_iterator cbi;
516  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
517  AnimControl *control = (*cbi).first;
518  control->mark_channels(cdata->_frame_blend_flag);
519  }
520 
521  cdata->_anim_changed = false;
522 
523  return any_changed;
524 }
525 
526 
527 /**
528  * Called by the AnimControl whenever it starts an animation. This is just a
529  * hook so the bundle can do something, if necessary, before the animation
530  * starts.
531  */
532 void PartBundle::
534  nassertv(Thread::get_current_pipeline_stage() == 0);
535  nassertv(control->get_part() == this);
536 
537  CDLockedReader cdata(_cycler);
538 
539  // If (and only if) our anim_blend_flag is false, then starting an animation
540  // implicitly enables it.
541  if (!cdata->_anim_blend_flag) {
542  CDWriter cdataw(_cycler, cdata);
543  do_set_control_effect(control, 1.0f, cdataw);
544  }
545 }
546 
547 /**
548  * Called by the AnimControl when it destructs. This needs to remove the
549  * AnimControl pointer from all pipeline stages.
550  */
551 void PartBundle::
553  nassertv(control->get_part() == this);
554 
555  OPEN_ITERATE_ALL_STAGES(_cycler) {
556  CDStageWriter cdata(_cycler, pipeline_stage);
557  ChannelBlend::iterator cbi = cdata->_blend.find(control);
558  if (cbi != cdata->_blend.end()) {
559  cdata->_net_blend -= cbi->second;
560  cdata->_blend.erase(cbi);
561  cdata->_anim_changed = true;
562 
563  // We need to make sure that any _effective_channel pointers that point
564  // to this control are cleared.
565  if (pipeline_stage == 0) {
567  }
568  }
569  }
570  CLOSE_ITERATE_ALL_STAGES(_cycler);
571 }
572 
573 /**
574  * The internal implementation of bind_anim(), this receives a pointer to an
575  * uninitialized AnimControl and fills it in if the bind is successful.
576  * Returns true if successful, false otherwise.
577  */
578 bool PartBundle::
580  int hierarchy_match_flags, const PartSubset &subset) {
581  nassertr(Thread::get_current_pipeline_stage() == 0, false);
582 
583  // Make sure this pointer doesn't destruct during the lifetime of this
584  // method.
585  PT(AnimBundle) ptanim = anim;
586 
587  if ((hierarchy_match_flags & HMF_ok_wrong_root_name) == 0) {
588  // Make sure the root names match.
589  if (get_name() != ptanim->get_name()) {
590  if (chan_cat.is_error()) {
591  chan_cat.error()
592  << "Root name of part (" << get_name()
593  << ") does not match that of anim (" << ptanim->get_name()
594  << ")\n";
595  }
596  return false;
597  }
598  }
599 
600  if (!check_hierarchy(anim, nullptr, hierarchy_match_flags)) {
601  return false;
602  }
603 
604  plist<int> holes;
605  int channel_index = 0;
606  pick_channel_index(holes, channel_index);
607 
608  if (!holes.empty()) {
609  channel_index = holes.front();
610  }
611 
612  int joint_index = 0;
613  BitArray bound_joints;
614  if (subset.is_include_empty()) {
615  bound_joints = BitArray::all_on();
616  }
617  bind_hierarchy(ptanim, channel_index, joint_index,
618  subset.is_include_empty(), bound_joints, subset);
619  control->setup_anim(this, anim, channel_index, bound_joints);
620 
621  CDReader cdata(_cycler);
623 
624  return true;
625 }
626 
627 /**
628  * Adds the PartBundleNode pointer to the set of nodes associated with the
629  * PartBundle. Normally called only by the PartBundleNode itself, for
630  * instance when the bundle is flattened with another node.
631  */
632 void PartBundle::
633 add_node(PartBundleNode *node) {
634  nassertv(find(_nodes.begin(), _nodes.end(), node) == _nodes.end());
635  _nodes.push_back(node);
636 }
637 
638 /**
639  * Removes the PartBundleNode pointer from the set of nodes associated with
640  * the PartBundle. Normally called only by the PartBundleNode itself, for
641  * instance when the bundle is flattened with another node.
642  */
643 void PartBundle::
644 remove_node(PartBundleNode *node) {
645  Nodes::iterator ni = find(_nodes.begin(), _nodes.end(), node);
646  nassertv(ni != _nodes.end());
647  _nodes.erase(ni);
648 }
649 
650 /**
651  * The private implementation of set_control_effect().
652  */
653 void PartBundle::
654 do_set_control_effect(AnimControl *control, PN_stdfloat effect, CData *cdata) {
655  nassertv(control->get_part() == this);
656 
657  if (effect == 0.0f) {
658  // An effect of zero means to eliminate the control.
659  ChannelBlend::iterator cbi = cdata->_blend.find(control);
660  if (cbi != cdata->_blend.end()) {
661  cdata->_blend.erase(cbi);
662  cdata->_anim_changed = true;
663  }
664 
665  } else {
666  // Otherwise we define it.
667 
668  // If anim_blend_flag is false, we only allow one AnimControl at a time.
669  // Stop all of the other AnimControls.
670  if (!cdata->_anim_blend_flag) {
671  clear_and_stop_intersecting(control, cdata);
672  }
673 
674  if (do_get_control_effect(control, cdata) != effect) {
675  cdata->_blend[control] = effect;
676  cdata->_anim_changed = true;
677  }
678  cdata->_last_control_set = control;
679  }
680 
681  recompute_net_blend(cdata);
682 }
683 
684 /**
685  * The private implementation of get_control_effect().
686  */
687 PN_stdfloat PartBundle::
688 do_get_control_effect(AnimControl *control, const CData *cdata) const {
689  nassertr(control->get_part() == this, 0.0f);
690 
691  ChannelBlend::const_iterator cbi = cdata->_blend.find(control);
692  if (cbi == cdata->_blend.end()) {
693  // The control is not in effect.
694  return 0.0f;
695  } else {
696  return (*cbi).second;
697  }
698 }
699 
700 
701 /**
702  * Recomputes the total blending amount after a control effect has been
703  * adjusted. This value must be kept up-to-date so we can normalize the
704  * blending amounts.
705  */
706 void PartBundle::
707 recompute_net_blend(CData *cdata) {
708  cdata->_net_blend = 0.0f;
709 
710  ChannelBlend::const_iterator bti;
711  for (bti = cdata->_blend.begin(); bti != cdata->_blend.end(); ++bti) {
712  cdata->_net_blend += (*bti).second;
713  }
715 }
716 
717 /**
718  * Removes and stops all the currently activated AnimControls that animate
719  * some joints also animated by the indicated AnimControl. This is a special
720  * internal function that's only called when _anim_blend_flag is false, to
721  * automatically stop all the other currently-executing animations.
722  */
723 void PartBundle::
724 clear_and_stop_intersecting(AnimControl *control, CData *cdata) {
725  double new_net_blend = 0.0f;
726  ChannelBlend new_blend;
727  bool any_changed = false;
728 
729  ChannelBlend::iterator cbi;
730  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
731  AnimControl *ac = (*cbi).first;
732  if (ac == control ||
734  // Save this control--it's either the target control, or it has no
735  // joints in common with the target control.
736  new_blend.insert(new_blend.end(), (*cbi));
737  new_net_blend += (*cbi).second;
738  } else {
739  // Remove and stop this control.
740  ac->stop();
741  any_changed = true;
742  }
743  }
744 
745  if (any_changed) {
746  cdata->_net_blend = new_net_blend;
747  cdata->_blend.swap(new_blend);
748  cdata->_anim_changed = true;
750  }
751 }
752 
753 /**
754  * Called by the BamReader to perform any final actions needed for setting up
755  * the object after all objects have been read and all pointers have been
756  * completed.
757  */
758 void PartBundle::
760  Thread *current_thread = Thread::get_current_thread();
761  CDWriter cdata(_cycler, true);
762  do_update(this, cdata, nullptr, true, true, current_thread);
763 }
764 
765 /**
766  * Writes the contents of this object to the datagram for shipping out to a
767  * Bam file.
768  */
769 void PartBundle::
771  PartGroup::write_datagram(manager, dg);
772  manager->write_pointer(dg, _anim_preload.get_read_pointer());
773  manager->write_cdata(dg, _cycler);
774 }
775 
776 /**
777  * Takes in a vector of pointers to TypedWritable objects that correspond to
778  * all the requests for pointers that this object made to BamReader.
779  */
780 int PartBundle::
782  int pi = PartGroup::complete_pointers(p_list, manager);
783 
784  if (manager->get_file_minor_ver() >= 17) {
785  _anim_preload = DCAST(AnimPreloadTable, p_list[pi++]);
786  }
787 
788  return pi;
789 }
790 
791 /**
792  * Factory method to generate a PartBundle object
793  */
794 TypedWritable* PartBundle::
795 make_from_bam(const FactoryParams &params) {
796  PartBundle *me = new PartBundle;
797  DatagramIterator scan;
798  BamReader *manager;
799 
800  parse_params(params, scan, manager);
801  me->fillin(scan, manager);
802  manager->register_finalize(me);
803  return me;
804 }
805 
806 /**
807  * This internal function is called by make_from_bam to read in all of the
808  * relevant data from the BamFile for the new PartBundle.
809  */
810 void PartBundle::
811 fillin(DatagramIterator &scan, BamReader *manager) {
812  PartGroup::fillin(scan, manager);
813  if (manager->get_file_minor_ver() >= 17) {
814  manager->read_pointer(scan); // _anim_preload
815  }
816  if (manager->get_file_minor_ver() >= 10) {
817  manager->read_cdata(scan, _cycler);
818  }
819  if (manager->get_file_minor_ver() == 11) {
820  // No longer need the _modifies_anim_bundles flag
821  scan.get_bool();
822  }
823 }
824 
825 /**
826  * Factory method to generate a PartBundle object
827  */
828 void PartBundle::
830  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
831 }
832 
833 /**
834  *
835  */
836 PartBundle::CData::
837 CData() {
838  _blend_type = anim_blend_type;
839  _anim_blend_flag = false;
840  _frame_blend_flag = interpolate_frames;
841  _root_xform = LMatrix4::ident_mat();
842  _last_control_set = nullptr;
843  _net_blend = 0.0f;
844  _anim_changed = false;
845  _last_update = 0.0;
846 }
847 
848 /**
849  *
850  */
851 PartBundle::CData::
852 CData(const PartBundle::CData &copy) :
853  _blend_type(copy._blend_type),
854  _anim_blend_flag(copy._anim_blend_flag),
855  _frame_blend_flag(copy._frame_blend_flag),
856  _root_xform(copy._root_xform),
857  _last_control_set(copy._last_control_set),
858  _blend(copy._blend),
859  _net_blend(copy._net_blend),
860  _anim_changed(copy._anim_changed),
861  _last_update(copy._last_update)
862 {
863  // Note that this copy constructor is not used by the PartBundle copy
864  // constructor! Any elements that must be copied between PartBundles should
865  // also be explicitly copied there.
866 }
867 
868 /**
869  *
870  */
871 CycleData *PartBundle::CData::
872 make_copy() const {
873  return new CData(*this);
874 }
875 
876 /**
877  * Writes the contents of this object to the datagram for shipping out to a
878  * Bam file.
879  */
880 void PartBundle::CData::
881 write_datagram(BamWriter *manager, Datagram &dg) const {
882  dg.add_uint8(_blend_type);
883  dg.add_bool(_anim_blend_flag);
884  dg.add_bool(_frame_blend_flag);
885  _root_xform.write_datagram(dg);
886 
887  // The remaining members are strictly dynamic.
888 }
889 
890 /**
891  * This internal function is called by make_from_bam to read in all of the
892  * relevant data from the BamFile for the new PartBundle.
893  */
894 void PartBundle::CData::
895 fillin(DatagramIterator &scan, BamReader *manager) {
896  _blend_type = (BlendType)scan.get_uint8();
897  _anim_blend_flag = scan.get_bool();
898  _frame_blend_flag = scan.get_bool();
899  _root_xform.read_datagram(scan);
900 }
901 
902 /**
903  *
904  */
905 ostream &
906 operator << (ostream &out, PartBundle::BlendType blend_type) {
907  switch (blend_type) {
908  case PartBundle::BT_linear:
909  return out << "linear";
910 
911  case PartBundle::BT_normalized_linear:
912  return out << "normalized_linear";
913 
914  case PartBundle::BT_componentwise:
915  return out << "componentwise";
916 
917  case PartBundle::BT_componentwise_quat:
918  return out << "componentwise_quat";
919  }
920 
921  chan_cat->error()
922  << "Invalid BlendType value: " << (int)blend_type << "\n";
923  nassertr(false, out);
924  return out;
925 }
926 
927 /**
928  *
929  */
930 istream &
931 operator >> (istream &in, PartBundle::BlendType &blend_type) {
932  string word;
933  in >> word;
934 
935  if (cmp_nocase_uh(word, "linear") == 0) {
936  blend_type = PartBundle::BT_linear;
937 
938  } else if (cmp_nocase_uh(word, "normalized_linear") == 0) {
939  blend_type = PartBundle::BT_normalized_linear;
940 
941  } else if (cmp_nocase_uh(word, "componentwise") == 0) {
942  blend_type = PartBundle::BT_componentwise;
943 
944  } else if (cmp_nocase_uh(word, "componentwise_quat") == 0) {
945  blend_type = PartBundle::BT_componentwise_quat;
946 
947  } else {
948  chan_cat->error()
949  << "Invalid BlendType string: " << word << "\n";
950  blend_type = PartBundle::BT_linear;
951  }
952  return in;
953 }
bool is_include_empty() const
Returns true if the include list is completely empty, false otherwise.
Definition: partSubset.cxx:114
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
PT(PartBundle) PartBundle
Returns a PartBundle that is a duplicate of this one, but with the indicated transform applied.
Definition: partBundle.cxx:148
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This table records data about a list of animations for a particular model, such as number of frames a...
Indicates a coordinate-system transform on vertices.
bool get_bool()
Extracts a boolean value.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
virtual void output(std::ostream &out) const
Writes a one-line description of the bundle.
Definition: partBundle.cxx:214
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
static BitArray all_on()
Returns a BitArray with an infinite array of bits, all on.
Definition: bitArray.I:37
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const BitArray & get_bound_joints() const
Returns the subset of joints controlled by this AnimControl.
Definition: animControl.I:64
virtual bool do_update(PartBundle *root, const CycleData *root_cdata, PartGroup *parent, bool parent_changed, bool anim_changed, Thread *current_thread)
Recursively update this particular part and all of its descendents for the current frame.
Definition: partGroup.cxx:470
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:29
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: partBundle.cxx:770
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
bool has_bits_in_common(const BitArray &other) const
Returns true if this BitArray has any "one" bits in common with the other one, false otherwise.
Definition: bitArray.cxx:467
set_priority
Specifies a priority value for this task.
Definition: asyncTask.h:116
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
Definition: loader.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: partBundle.cxx:759
void stop()
Stops a currently playing or looping animation right where it is.
Definition: animInterface.I:91
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
static void register_with_read_factory()
Factory method to generate a PartBundle object.
Definition: partBundle.cxx:829
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_mat
Returns the matrix that describes the transform.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
bool force_update()
Updates all the parts in the bundle to reflect the data for the current frame, whether we believe it ...
Definition: partBundle.cxx:509
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PartBundle * get_part() const
Returns the PartBundle bound in with this AnimControl.
void clear_control_effects()
Sets the control effect of all AnimControls to zero (but does not "stop" the AnimControls).
Definition: partBundle.cxx:197
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PartGroup * find_child(const std::string &name) const
Returns the first descendant found with the indicated name, or NULL if no such descendant exists.
Definition: partGroup.cxx:136
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the bundle and all of its descendants.
Definition: partBundle.cxx:222
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
static AnimBundle * find_anim_bundle(PandaNode *root)
Recursively walks the scene graph beginning at the indicated node (which need not be an AnimBundleNod...
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
virtual void determine_effective_channels(const CycleData *root_cdata)
Should be called whenever the ChannelBlend values have changed, this recursively updates the _effecti...
Definition: partGroup.cxx:503
This is a node that contains a pointer to an PartBundle.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
void control_removed(AnimControl *control)
Called by the AnimControl when it destructs.
Definition: partBundle.cxx:552
virtual bool apply_freeze_matrix(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale)
Freezes this particular joint so that it will always hold the specified transform.
Definition: partGroup.cxx:198
bool release_joint(const std::string &joint_name)
Releases the named joint from the effects of a previous call to freeze_joint() or control_joint().
Definition: partBundle.cxx:457
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
bool apply_freeze(const TransformState *transform)
Freezes this particular joint so that it will always hold the specified transform.
Definition: partGroup.cxx:185
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
This class specializes ConfigVariable as an enumerated type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool do_bind_anim(AnimControl *control, AnimBundle *anim, int hierarchy_match_flags, const PartSubset &subset)
The internal implementation of bind_anim(), this receives a pointer to an uninitialized AnimControl a...
Definition: partBundle.cxx:579
virtual bool apply_control(PandaNode *node)
Specifies a node to influence this particular joint so that it will always hold the node's transform.
Definition: partGroup.cxx:225
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index, const BitArray &bound_joints)
This can only be called once for a given AnimControl.
Definition: animControl.cxx:56
void wait_pending()
Blocks the current thread until the AnimControl has finished loading and is fully bound.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is used to define a subset of part names to apply to the PartBundle::bind_anim() operation...
Definition: partSubset.h:25
This class object manages an asynchronous load-and-bind animation request, as issued through PartBund...
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
set_anim_blend_flag
Defines the way the character responds to multiple calls to set_control_effect()).
Definition: partBundle.h:117
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void control_activated(AnimControl *control)
Called by the AnimControl whenever it starts an animation.
Definition: partBundle.cxx:533
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Takes in a vector of pointers to TypedWritable objects that correspond to all the requests for pointe...
Definition: partBundle.cxx:781
A thread; that is, a lightweight process.
Definition: thread.h:46
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:46
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
virtual bool clear_forced_channel()
Undoes the effect of a previous call to apply_freeze() or apply_control().
Definition: partGroup.cxx:237
bool check_hierarchy(const AnimGroup *anim, const PartGroup *parent, int hierarchy_match_flags=0) const
Walks the part hierarchy in tandem with the indicated anim hierarchy, and returns true if the hierarc...
Definition: partGroup.cxx:294
bool update()
Updates all the parts in the bundle to reflect the data for the current frame (as set in each of the ...
Definition: partBundle.cxx:477
Controls the timing of a character animation.
Definition: animControl.h:38
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
virtual PartGroup * make_copy() const
Allocates and returns a new copy of the node.
Definition: partBundle.cxx:83
void mark_channels(bool frame_blend_flag)
Marks this point as the point of reference for the next call to channel_has_changed().
PartGroup * copy_subgraph() const
Allocates and returns a new copy of this node and of all of its children.
Definition: partGroup.cxx:75
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void wait_pending()
Blocks the current thread until all currently-pending AnimControls, with a nonzero control effect,...
Definition: partBundle.cxx:349
void merge_anim_preloads(const PartBundle *other)
Copies the contents of the other PartBundle's preload table into this one.
Definition: partBundle.cxx:91
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
Definition: partGroup.cxx:629
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
bool control_joint(const std::string &joint_name, PandaNode *node)
Specifies that the joint with the indicated name should be animated with the transform on the indicat...
Definition: partBundle.cxx:436
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Takes in a vector of pointers to TypedWritable objects that correspond to all the requests for pointe...
Definition: partGroup.cxx:666
virtual bool apply_freeze_scalar(PN_stdfloat value)
Freezes this particular joint so that it will always hold the specified transform.
Definition: partGroup.cxx:211
bool freeze_joint(const std::string &joint_name, const TransformState *transform)
Specifies that the joint with the indicated name should be frozen with the specified transform.
Definition: partBundle.cxx:372
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
This is the base class for PartRoot and MovingPart.
Definition: partGroup.h:43