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());
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();
201 if (!cdata->_blend.empty()) {
203 cdataw->_blend.clear();
204 cdataw->_net_blend = 0.0f;
205 cdataw->_anim_changed =
true;
214 output(ostream &out)
const {
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);
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);
338 request->set_priority(async_bind_priority);
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;
414 freeze_joint(
const string &joint_name, PN_stdfloat value) {
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;
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;
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;
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) {
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;
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;
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 ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
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.
Controls the timing of a character animation.
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.
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...
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.
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.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
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.
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.
static BitArray all_on()
Returns a BitArray with an infinite array of bits, all on.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
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.
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 ...
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
void add_bool(bool value)
Adds a boolean value to the datagram.
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.
The name of a file, such as a texture file or an Egg file.
std::string get_basename() const
Returns the basename part of the filename.
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
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...
A basic node of the scene graph or data graph.
This is a node that contains a pointer to an PartBundle.
This is the root of a MovingPart hierarchy.
set_anim_blend_flag
Defines the way the character responds to multiple calls to set_control_effect()).
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.
PartGroup * copy_subgraph() const
Allocates and returns a new copy of this node and of all of its children.
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...
bool is_include_empty() const
Returns true if the include list is completely empty, false otherwise.
A thread; that is, a lightweight process.
is_threading_supported
Returns true if threading support has been compiled in and enabled, or false if no threading is avail...
get_current_pipeline_stage
Returns the integer pipeline stage associated with the current thread.
get_current_thread
Returns a pointer to the currently-executing Thread object.
TypeHandle is the identifier used to differentiate C++ class types.
Base class for objects that can be written to and read from Bam files.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(PartBundle) PartBundle
Returns a PartBundle that is a duplicate of this one, but with the indicated transform applied.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.