Panda3D
Loading...
Searching...
No Matches
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
34using std::istream;
35using std::ostream;
36using std::string;
37
38TypeHandle PartBundle::_type_handle;
39
40
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 */
52PartBundle::
53PartBundle(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 */
71PartBundle::
72PartBundle(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 */
83make_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 */
91merge_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 */
121void PartBundle::
122set_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 */
148PT(PartBundle) PartBundle::
149apply_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 */
214output(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 */
222write(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 */
247PT(AnimControl) PartBundle::
248bind_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 */
279PT(AnimControl) PartBundle::
280load_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 */
349wait_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 */
372freeze_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 */
393freeze_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 */
414freeze_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 */
436control_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 */
457release_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 */
477update() {
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 */
509force_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 */
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 */
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 */
579do_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 */
632void PartBundle::
633add_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 */
643void PartBundle::
644remove_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 */
653void PartBundle::
654do_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 */
687PN_stdfloat PartBundle::
688do_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 */
706void PartBundle::
707recompute_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 */
723void PartBundle::
724clear_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 */
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 */
770write_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 */
781complete_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 */
794TypedWritable* PartBundle::
795make_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 */
810void PartBundle::
811fillin(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 */
836PartBundle::CData::
837CData() {
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 */
851PartBundle::CData::
852CData(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 */
871CycleData *PartBundle::CData::
872make_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 */
880void PartBundle::CData::
881write_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 */
894void PartBundle::CData::
895fillin(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 */
905ostream &
906operator << (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 */
930istream &
931operator >> (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.
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.
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...
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
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.
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.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
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.
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...
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:44
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.
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.
virtual void output(std::ostream &out) const
Writes a one-line description of the bundle.
virtual void control_activated(AnimControl *control)
Called by the AnimControl whenever it starts an animation.
bool update()
Updates all the parts in the bundle to reflect the data for the current frame (as set in each of the ...
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().
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void wait_pending()
Blocks the current thread until all currently-pending AnimControls, with a nonzero control effect,...
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...
void clear_control_effects()
Sets the control effect of all AnimControls to zero (but does not "stop" the AnimControls).
void merge_anim_preloads(const PartBundle *other)
Copies the contents of the other PartBundle's preload table into this one.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
void control_removed(AnimControl *control)
Called by the AnimControl when it destructs.
bool force_update()
Updates all the parts in the bundle to reflect the data for the current frame, whether we believe it ...
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.
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...
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...
virtual PartGroup * make_copy() const
Allocates and returns a new copy of the node.
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the bundle and all of its descendants.
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.
virtual bool apply_freeze_scalar(PN_stdfloat value)
Freezes this particular joint so that it will always hold the specified transform.
bool apply_freeze(const TransformState *transform)
Freezes this particular joint so that it will always hold the specified transform.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual bool apply_control(PandaNode *node)
Specifies a node to influence this particular joint so that it will always hold the node's transform.
virtual bool clear_forced_channel()
Undoes the effect of a previous call to apply_freeze() or apply_control().
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...
virtual void determine_effective_channels(const CycleData *root_cdata)
Should be called whenever the ChannelBlend values have changed, this recursively updates the _effecti...
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.
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.
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...
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.
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.
This is our own Panda specialization on the default STL list.
Definition plist.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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.