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  */
91 merge_anim_preloads(const PartBundle *other) {
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  */
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  */
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  */
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  */
349 wait_pending() {
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  */
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  */
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  */
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  */
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  */
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  */
477 update() {
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  */
509 force_update() {
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  */
533 control_activated(AnimControl *control) {
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  */
552 control_removed(AnimControl *control) {
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  */
579 do_bind_anim(AnimControl *control, AnimBundle *anim,
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  */
759 finalize(BamReader *) {
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  */
770 write_datagram(BamWriter *manager, Datagram &dg) {
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  */
781 complete_pointers(TypedWritable **p_list, BamReader *manager) {
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  */
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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static AnimBundle * find_anim_bundle(PandaNode *root)
Recursively walks the scene graph beginning at the indicated node (which need not be an AnimBundleNod...
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:29
Controls the timing of a character animation.
Definition: animControl.h:38
void mark_channels(bool frame_blend_flag)
Marks this point as the point of reference for the next call to channel_has_changed().
const BitArray & get_bound_joints() const
Returns the subset of joints controlled by this AnimControl.
Definition: animControl.I:64
void wait_pending()
Blocks the current thread until the AnimControl has finished loading and is fully bound.
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
PartBundle * get_part() const
Returns the PartBundle bound in with this AnimControl.
void stop()
Stops a currently playing or looping animation right where it is.
Definition: animInterface.I:91
This table records data about a list of animations for a particular model, such as number of frames a...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
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
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
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
This class object manages an asynchronous load-and-bind animation request, as issued through PartBund...
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:40
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
static BitArray all_on()
Returns a BitArray with an infinite array of bits, all on.
Definition: bitArray.I:37
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
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
This class specializes ConfigVariable as an enumerated type.
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
bool get_bool()
Extracts a boolean value.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
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
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
This is a node that contains a pointer to an PartBundle.
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:46
set_anim_blend_flag
Defines the way the character responds to multiple calls to set_control_effect()).
Definition: partBundle.h:117
static void register_with_read_factory()
Factory method to generate a PartBundle object.
Definition: partBundle.cxx:829
virtual void output(std::ostream &out) const
Writes a one-line description of the bundle.
Definition: partBundle.cxx:214
virtual void control_activated(AnimControl *control)
Called by the AnimControl whenever it starts an animation.
Definition: partBundle.cxx:533
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
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
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
void wait_pending()
Blocks the current thread until all currently-pending AnimControls, with a nonzero control effect,...
Definition: partBundle.cxx:349
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
void clear_control_effects()
Sets the control effect of all AnimControls to zero (but does not "stop" the AnimControls).
Definition: partBundle.cxx:197
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 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 control_removed(AnimControl *control)
Called by the AnimControl when it destructs.
Definition: partBundle.cxx:552
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
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
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 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
virtual PartGroup * make_copy() const
Allocates and returns a new copy of the node.
Definition: partBundle.cxx:83
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
This is the base class for PartRoot and MovingPart.
Definition: partGroup.h:43
PartGroup * copy_subgraph() const
Allocates and returns a new copy of this node and of all of its children.
Definition: partGroup.cxx:75
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 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 apply_freeze(const TransformState *transform)
Freezes this particular joint so that it will always hold the specified transform.
Definition: partGroup.cxx:185
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
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
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
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
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
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
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
This class is used to define a subset of part names to apply to the PartBundle::bind_anim() operation...
Definition: partSubset.h:25
bool is_include_empty() const
Returns true if the include list is completely empty, false otherwise.
Definition: partSubset.cxx:114
A thread; that is, a lightweight process.
Definition: thread.h:46
is_threading_supported
Returns true if threading support has been compiled in and enabled, or false if no threading is avail...
Definition: thread.h:112
get_current_pipeline_stage
Returns the integer pipeline stage associated with the current thread.
Definition: thread.h:110
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
Indicates a coordinate-system transform on vertices.
get_mat
Returns the matrix that describes the transform.
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.