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()."));
56 _anim_preload = copy._anim_preload;
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;
72 PartBundle(
const string &name) :
92 if (other->_anim_preload ==
nullptr ||
93 _anim_preload == other->_anim_preload) {
98 if (_anim_preload ==
nullptr) {
100 _anim_preload = other->_anim_preload;
106 anim_preload->add_anims_from(other->_anim_preload.get_read_pointer());
123 nassertv(Thread::get_current_pipeline_stage() == 0);
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;
130 if (!anim_blend_flag && cdataw->_blend.size() > 1) {
135 nassertv(cdataw->_last_control_set !=
nullptr);
136 clear_and_stop_intersecting(cdataw->_last_control_set, cdataw);
139 cdataw->_anim_changed =
true;
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()) {
166 new_bundle->xform(transform->
get_mat());
168 if (ati != _applied_transforms.end()) {
170 (*ati).first.refresh();
171 (*ati).second = new_bundle;
174 bool inserted = _applied_transforms.insert(AppliedTransforms::value_type(transform, new_bundle)).second;
175 nassertr(inserted, new_bundle);
180 new_bundle->force_update();
198 nassertv(Thread::get_current_pipeline_stage() == 0);
201 if (!cdata->_blend.empty()) {
203 cdataw->_blend.clear();
204 cdataw->_net_blend = 0.0f;
205 cdataw->_anim_changed =
true;
215 out << get_type() <<
" " << get_name();
222 write(ostream &out,
int indent_level)
const {
224 << get_type() <<
" " << get_name() <<
" {\n";
225 write_descendants(out, indent_level + 2);
226 indent(out, indent_level) <<
"}\n";
248 bind_anim(
AnimBundle *anim,
int hierarchy_match_flags,
251 if (
do_bind_anim(control, anim, hierarchy_match_flags, subset)) {
281 int hierarchy_match_flags,
const PartSubset &subset,
283 nassertr(loader !=
nullptr,
nullptr);
286 LoaderOptions::LF_report_errors |
287 LoaderOptions::LF_convert_anim);
292 if (anim_preload !=
nullptr) {
293 anim_index = anim_preload->find_anim(basename);
296 if (anim_index < 0 || !allow_async || !Thread::is_threading_supported()) {
300 PT(
PandaNode) model = loader->load_sync(filename, anim_options);
301 if (model ==
nullptr) {
306 if (anim ==
nullptr) {
310 PT(
AnimControl) control = bind_anim(anim, hierarchy_match_flags, subset);
311 if (control ==
nullptr) {
315 control->set_anim_model(model);
321 PN_stdfloat frame_rate = anim_preload->get_base_frame_rate(anim_index);
322 int num_frames = anim_preload->get_num_frames(anim_index);
324 new AnimControl(basename,
this, frame_rate, num_frames);
330 find_bound_joints(joint_index,
false, bound_joints, subset);
331 control->set_bound_joints(bound_joints);
336 filename, anim_options, loader, control,
337 hierarchy_match_flags, subset);
339 loader->load_async(request);
351 ChannelBlend::const_iterator cbi;
352 for (cbi = cdata->_blend.begin();
353 cbi != cdata->_blend.end();
356 PN_stdfloat effect = (*cbi).second;
357 if (effect != 0.0f) {
374 if (child ==
nullptr) {
379 cdata->_anim_changed =
true;
393 freeze_joint(
const string &joint_name,
const LVecBase3 &pos,
const LVecBase3 &hpr,
const LVecBase3 &scale) {
395 if (child ==
nullptr) {
400 cdata->_anim_changed =
true;
416 if (child ==
nullptr) {
421 cdata->_anim_changed =
true;
438 if (child ==
nullptr) {
443 cdata->_anim_changed =
true;
459 if (child ==
nullptr) {
464 cdata->_anim_changed =
true;
478 Thread *current_thread = Thread::get_current_thread();
479 CDWriter cdata(_cycler,
false, current_thread);
480 bool any_changed =
false;
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;
487 any_changed =
do_update(
this, cdata,
nullptr,
false, anim_changed,
491 ChannelBlend::const_iterator cbi;
492 for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
497 cdata->_anim_changed =
false;
498 cdata->_last_update = now;
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);
515 ChannelBlend::const_iterator cbi;
516 for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
521 cdata->_anim_changed =
false;
534 nassertv(Thread::get_current_pipeline_stage() == 0);
535 nassertv(control->
get_part() ==
this);
541 if (!cdata->_anim_blend_flag) {
543 do_set_control_effect(control, 1.0f, cdataw);
553 nassertv(control->
get_part() ==
this);
555 OPEN_ITERATE_ALL_STAGES(_cycler) {
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;
565 if (pipeline_stage == 0) {
570 CLOSE_ITERATE_ALL_STAGES(_cycler);
580 int hierarchy_match_flags,
const PartSubset &subset) {
581 nassertr(Thread::get_current_pipeline_stage() == 0,
false);
587 if ((hierarchy_match_flags & HMF_ok_wrong_root_name) == 0) {
589 if (get_name() != ptanim->get_name()) {
590 if (chan_cat.is_error()) {
592 <<
"Root name of part (" << get_name()
593 <<
") does not match that of anim (" << ptanim->get_name()
605 int channel_index = 0;
606 pick_channel_index(holes, channel_index);
608 if (!holes.empty()) {
609 channel_index = holes.front();
617 bind_hierarchy(ptanim, channel_index, joint_index,
619 control->
setup_anim(
this, anim, channel_index, bound_joints);
634 nassertv(find(_nodes.begin(), _nodes.end(), node) == _nodes.end());
635 _nodes.push_back(node);
645 Nodes::iterator ni = find(_nodes.begin(), _nodes.end(), node);
646 nassertv(ni != _nodes.end());
654 do_set_control_effect(
AnimControl *control, PN_stdfloat effect, CData *cdata) {
655 nassertv(control->
get_part() ==
this);
657 if (effect == 0.0f) {
659 ChannelBlend::iterator cbi = cdata->_blend.find(control);
660 if (cbi != cdata->_blend.end()) {
661 cdata->_blend.erase(cbi);
662 cdata->_anim_changed =
true;
670 if (!cdata->_anim_blend_flag) {
671 clear_and_stop_intersecting(control, cdata);
674 if (do_get_control_effect(control, cdata) != effect) {
675 cdata->_blend[control] = effect;
676 cdata->_anim_changed =
true;
678 cdata->_last_control_set = control;
681 recompute_net_blend(cdata);
687 PN_stdfloat PartBundle::
688 do_get_control_effect(
AnimControl *control,
const CData *cdata)
const {
689 nassertr(control->
get_part() ==
this, 0.0f);
691 ChannelBlend::const_iterator cbi = cdata->_blend.find(control);
692 if (cbi == cdata->_blend.end()) {
696 return (*cbi).second;
707 recompute_net_blend(CData *cdata) {
708 cdata->_net_blend = 0.0f;
710 ChannelBlend::const_iterator bti;
711 for (bti = cdata->_blend.begin(); bti != cdata->_blend.end(); ++bti) {
712 cdata->_net_blend += (*bti).second;
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;
729 ChannelBlend::iterator cbi;
730 for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
736 new_blend.insert(new_blend.end(), (*cbi));
737 new_net_blend += (*cbi).second;
746 cdata->_net_blend = new_net_blend;
747 cdata->_blend.swap(new_blend);
748 cdata->_anim_changed =
true;
760 Thread *current_thread = Thread::get_current_thread();
762 do_update(
this, cdata,
nullptr,
true,
true, current_thread);
772 manager->
write_pointer(dg, _anim_preload.get_read_pointer());
801 me->fillin(scan, manager);
812 PartGroup::fillin(scan, manager);
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;
844 _anim_changed =
false;
852 CData(
const PartBundle::CData ©) :
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),
859 _net_blend(copy._net_blend),
860 _anim_changed(copy._anim_changed),
861 _last_update(copy._last_update)
873 return new CData(*
this);
880 void PartBundle::CData::
885 _root_xform.write_datagram(dg);
894 void PartBundle::CData::
896 _blend_type = (BlendType)scan.
get_uint8();
898 _frame_blend_flag = scan.
get_bool();
899 _root_xform.read_datagram(scan);
906 operator << (ostream &out, PartBundle::BlendType blend_type) {
907 switch (blend_type) {
908 case PartBundle::BT_linear:
909 return out <<
"linear";
911 case PartBundle::BT_normalized_linear:
912 return out <<
"normalized_linear";
914 case PartBundle::BT_componentwise:
915 return out <<
"componentwise";
917 case PartBundle::BT_componentwise_quat:
918 return out <<
"componentwise_quat";
922 <<
"Invalid BlendType value: " << (int)blend_type <<
"\n";
923 nassertr(
false, out);
931 operator >> (istream &in, PartBundle::BlendType &blend_type) {
935 if (cmp_nocase_uh(word,
"linear") == 0) {
936 blend_type = PartBundle::BT_linear;
938 }
else if (cmp_nocase_uh(word,
"normalized_linear") == 0) {
939 blend_type = PartBundle::BT_normalized_linear;
941 }
else if (cmp_nocase_uh(word,
"componentwise") == 0) {
942 blend_type = PartBundle::BT_componentwise;
944 }
else if (cmp_nocase_uh(word,
"componentwise_quat") == 0) {
945 blend_type = PartBundle::BT_componentwise_quat;
949 <<
"Invalid BlendType string: " << word <<
"\n";
950 blend_type = PartBundle::BT_linear;
bool is_include_empty() const
Returns true if the include list is completely empty, false otherwise.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A basic node of the scene graph or data graph.
PT(PartBundle) PartBundle
Returns a PartBundle that is a duplicate of this one, but with the indicated transform applied.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This table records data about a list of animations for a particular model, such as number of frames a...
bool get_bool()
Extracts a boolean value.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
virtual void output(std::ostream &out) const
Writes a one-line description of the bundle.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
static BitArray all_on()
Returns a BitArray with an infinite array of bits, all on.
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const BitArray & get_bound_joints() const
Returns the subset of joints controlled by this AnimControl.
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.
Specifies parameters that may be passed to the loader.
This is the root of an AnimChannel hierarchy.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
A single page of data maintained by a PipelineCycler.
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Base class for objects that can be written to and read from Bam files.
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
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.
set_priority
Specifies a priority value for this task.
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
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 ...
static void register_with_read_factory()
Factory method to generate a PartBundle object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
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 ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PartBundle * get_part() const
Returns the PartBundle bound in with this AnimControl.
void clear_control_effects()
Sets the control effect of all AnimControls to zero (but does not "stop" the AnimControls).
A dynamic array with an unlimited number of bits.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PartGroup * find_child(const std::string &name) const
Returns the first descendant found with the indicated name, or NULL if no such descendant exists.
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the bundle and all of its descendants.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
The name of a file, such as a texture file or an Egg file.
virtual void determine_effective_channels(const CycleData *root_cdata)
Should be called whenever the ChannelBlend values have changed, this recursively updates the _effecti...
This is a node that contains a pointer to an PartBundle.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
void control_removed(AnimControl *control)
Called by the AnimControl when it destructs.
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.
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().
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.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
This class specializes ConfigVariable as an enumerated type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool do_bind_anim(AnimControl *control, AnimBundle *anim, int hierarchy_match_flags, const PartSubset &subset)
The internal implementation of bind_anim(), this receives a pointer to an uninitialized AnimControl a...
virtual bool apply_control(PandaNode *node)
Specifies a node to influence this particular joint so that it will always hold the node's transform.
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index, const BitArray &bound_joints)
This can only be called once for a given AnimControl.
void wait_pending()
Blocks the current thread until the AnimControl has finished loading and is fully bound.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is used to define a subset of part names to apply to the PartBundle::bind_anim() operation...
This class object manages an asynchronous load-and-bind animation request, as issued through PartBund...
std::string get_basename() const
Returns the basename part of the filename.
set_anim_blend_flag
Defines the way the character responds to multiple calls to set_control_effect()).
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void control_activated(AnimControl *control)
Called by the AnimControl whenever it starts an animation.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
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...
A thread; that is, a lightweight process.
This is the root of a MovingPart hierarchy.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
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...
bool update()
Updates all the parts in the bundle to reflect the data for the current frame (as set in each of the ...
Controls the timing of a character animation.
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
virtual PartGroup * make_copy() const
Allocates and returns a new copy of the node.
void mark_channels(bool frame_blend_flag)
Marks this point as the point of reference for the next call to channel_has_changed().
PartGroup * copy_subgraph() const
Allocates and returns a new copy of this node and of all of its children.
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
void wait_pending()
Blocks the current thread until all currently-pending AnimControls, with a nonzero control effect,...
void merge_anim_preloads(const PartBundle *other)
Copies the contents of the other PartBundle's preload table into this one.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
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...
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 bool apply_freeze_scalar(PN_stdfloat value)
Freezes this particular joint so that it will always hold the specified transform.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the base class for PartRoot and MovingPart.