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