Panda3D
Loading...
Searching...
No Matches
movingPartBase.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 movingPartBase.cxx
10 * @author drose
11 * @date 1999-02-22
12 */
13
14#include "movingPartBase.h"
15#include "animControl.h"
16#include "animChannelBase.h"
17#include "bitArray.h"
18#include "config_chan.h"
19#include "dcast.h"
20#include "indent.h"
21
22TypeHandle MovingPartBase::_type_handle;
23
24
25/**
26 *
27 */
28MovingPartBase::
29MovingPartBase(PartGroup *parent, const std::string &name) :
30 PartGroup(parent, name),
31 _num_effective_channels(0),
32 _effective_control(nullptr)
33{
34}
35
36/**
37 *
38 */
39MovingPartBase::
40MovingPartBase() :
41 _num_effective_channels(0),
42 _effective_control(nullptr)
43{
44}
45
46/**
47 * Undoes the effect of a previous call to apply_freeze() or apply_control().
48 * Returns true if the joint was modified, false otherwise.
49 */
52 if (_forced_channel != nullptr) {
53 _forced_channel.clear();
54 return true;
55 }
56 return false;
57}
58
59/**
60 * Returns the AnimChannelBase that has been forced to this joint by a
61 * previous call to apply_freeze() or apply_control(), or NULL if no such
62 * channel has been applied.
63 */
65get_forced_channel() const {
66 return _forced_channel;
67}
68
69/**
70 * Writes a brief description of the channel and all of its descendants.
71 */
73write(std::ostream &out, int indent_level) const {
74 indent(out, indent_level) << get_value_type() << " " << get_name();
75 if (_children.empty()) {
76 out << "\n";
77 } else {
78 out << " {\n";
79 write_descendants(out, indent_level + 2);
80 indent(out, indent_level) << "}\n";
81 }
82}
83
84/**
85 * Writes a brief description of the channel and all of its descendants, along
86 * with their values.
87 */
89write_with_value(std::ostream &out, int indent_level) const {
90 indent(out, indent_level) << get_value_type() << " " << get_name() << "\n";
91 indent(out, indent_level);
92 output_value(out);
93
94 if (_children.empty()) {
95 out << "\n";
96 } else {
97 out << " {\n";
98 write_descendants_with_value(out, indent_level + 2);
99 indent(out, indent_level) << "}\n";
100 }
101}
102
103/**
104 * Recursively update this particular part and all of its descendents for the
105 * current frame. This is not really public and is not intended to be called
106 * directly; it is called from the top of the tree by PartBundle::update().
107 *
108 * The return value is true if any part has changed, false otherwise.
109 */
111do_update(PartBundle *root, const CycleData *root_cdata, PartGroup *parent,
112 bool parent_changed, bool anim_changed,
113 Thread *current_thread) {
114 bool any_changed = false;
115 bool needs_update = anim_changed;
116
117 // See if any of the channel values have changed since last time.
118
119 if (!needs_update) {
120 if (_forced_channel != nullptr) {
121 needs_update = _forced_channel->has_changed(0, 0.0, 0, 0.0);
122
123 } else if (_effective_control != nullptr) {
124 const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
125 needs_update = _effective_control->channel_has_changed(_effective_channel, cdata->_frame_blend_flag);
126
127 } else {
128 const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
129 PartBundle::ChannelBlend::const_iterator bci;
130 for (bci = cdata->_blend.begin();
131 !needs_update && bci != cdata->_blend.end();
132 ++bci) {
133 AnimControl *control = (*bci).first;
134
135 AnimChannelBase *channel = nullptr;
136 int channel_index = control->get_channel_index();
137 if (channel_index >= 0 && channel_index < (int)_channels.size()) {
138 channel = _channels[channel_index];
139 }
140 if (channel != nullptr) {
141 needs_update = control->channel_has_changed(channel, cdata->_frame_blend_flag);
142 }
143 }
144 }
145 }
146
147 if (needs_update) {
148 // Ok, get the latest value.
149 get_blend_value(root);
150 }
151
152 if (parent_changed || needs_update) {
153 any_changed = update_internals(root, parent, needs_update, parent_changed,
154 current_thread);
155 }
156
157 // Now recurse.
158 Children::iterator ci;
159 for (ci = _children.begin(); ci != _children.end(); ++ci) {
160 if ((*ci)->do_update(root, root_cdata, this,
161 parent_changed || needs_update,
162 anim_changed, current_thread)) {
163 any_changed = true;
164 }
165 }
166
167 return any_changed;
168}
169
170
171/**
172 * This is called by do_update() whenever the part or some ancestor has
173 * changed values. It is a hook for derived classes to update whatever cache
174 * they may have that depends on these.
175 *
176 * The return value is true if the part has changed as a result of the update,
177 * or false otherwise.
178 */
180update_internals(PartBundle *, PartGroup *, bool, bool, Thread *) {
181 return true;
182}
183
184/**
185 * Walks the part hierarchy, looking for a suitable channel index number to
186 * use. Available index numbers are the elements of the holes set, as well as
187 * next to infinity.
188 */
189void MovingPartBase::
190pick_channel_index(plist<int> &holes, int &next) const {
191 // Verify each of the holes.
192
193 plist<int>::iterator ii, ii_next;
194 ii = holes.begin();
195 while (ii != holes.end()) {
196 ii_next = ii;
197 ++ii_next;
198
199 int hole = (*ii);
200 nassertv(hole >= 0 && hole < next);
201 if (hole < (int)_channels.size() ||
202 _channels[hole] != nullptr) {
203 // We can't accept this hole; we're using it!
204 holes.erase(ii);
205 }
206 ii = ii_next;
207 }
208
209 // Now do we have any more to restrict?
210 if (next < (int)_channels.size()) {
211 int i;
212 for (i = next; i < (int)_channels.size(); i++) {
213 if (_channels[i] == nullptr) {
214 // Here's a hole we do have.
215 holes.push_back(i);
216 }
217 }
218 next = _channels.size();
219 }
220
221 PartGroup::pick_channel_index(holes, next);
222}
223
224
225
226/**
227 * Binds the indicated anim hierarchy to the part hierarchy, at the given
228 * channel index number.
229 */
230void MovingPartBase::
231bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index,
232 bool is_included, BitArray &bound_joints,
233 const PartSubset &subset) {
234 if (subset.matches_include(get_name())) {
235 is_included = true;
236 } else if (subset.matches_exclude(get_name())) {
237 is_included = false;
238 }
239
240 if (chan_cat.is_debug()) {
241 if (anim == nullptr) {
242 chan_cat.debug()
243 << "binding " << *this << " to NULL, is_included = "
244 << is_included << "\n";
245 } else {
246 chan_cat.debug()
247 << "binding " << *this << " to " << *anim << ", is_included = "
248 << is_included << "\n";
249 }
250 }
251 while ((int)_channels.size() <= channel_index) {
252 _channels.push_back(nullptr);
253 }
254
255 nassertv(_channels[channel_index] == nullptr);
256
257 if (is_included) {
258 if (anim == nullptr) {
259 // If we're binding to the NULL anim, it means actually to create a
260 // default AnimChannel that just returns the part's initial value.
261 _channels[channel_index] = make_default_channel();
262 } else {
263 _channels[channel_index] = DCAST(AnimChannelBase, anim);
264 }
265
266 // Record that we have bound this joint in the bound_joints BitArray.
267 bound_joints.set_bit(joint_index);
268 } else {
269 // Record that we have *not* bound this particular joint.
270 bound_joints.clear_bit(joint_index);
271 }
272 ++joint_index;
273
274 PartGroup::bind_hierarchy(anim, channel_index, joint_index,
275 is_included, bound_joints, subset);
276}
277
278/**
279 * Similar to bind_hierarchy, but does not actually perform any binding. All
280 * it does is compute the BitArray bount_joints according to the specified
281 * subset. This is useful in preparation for asynchronous binding--in this
282 * case, we may need to know bound_joints immediately, without having to wait
283 * for the animation itself to load and bind.
284 */
285void MovingPartBase::
286find_bound_joints(int &joint_index, bool is_included, BitArray &bound_joints,
287 const PartSubset &subset) {
288 if (subset.matches_include(get_name())) {
289 is_included = true;
290 } else if (subset.matches_exclude(get_name())) {
291 is_included = false;
292 }
293
294 bound_joints.set_bit_to(joint_index, is_included);
295 ++joint_index;
296
297 PartGroup::find_bound_joints(joint_index, is_included, bound_joints, subset);
298}
299
300/**
301 * Should be called whenever the ChannelBlend values have changed, this
302 * recursively updates the _effective_channel member in each part.
303 */
304void MovingPartBase::
305determine_effective_channels(const CycleData *root_cdata) {
306 _effective_control = nullptr;
307 _effective_channel = nullptr;
308 _num_effective_channels = 0;
309
310 AnimControl *effective_control = nullptr;
311 AnimChannelBase *effective_channel = nullptr;
312 int num_effective_channels = 0;
313
314 const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
315 PartBundle::ChannelBlend::const_iterator cbi;
316 for (cbi = cdata->_blend.begin();
317 cbi != cdata->_blend.end();
318 ++cbi) {
319 AnimControl *control = (*cbi).first;
320 int channel_index = control->get_channel_index();
321 if (channel_index >= 0 && channel_index < (int)_channels.size()) {
322 if (_channels[channel_index] != nullptr) {
323 effective_control = control;
324 effective_channel = _channels[channel_index];
325 ++num_effective_channels;
326 }
327 }
328 }
329
330 _num_effective_channels = num_effective_channels;
331 if (num_effective_channels == 1) {
332 _effective_control = effective_control;
333 _effective_channel = effective_channel;
334 }
335
337}
338
339/**
340 * Writes the contents of this object to the datagram for shipping out to a
341 * Bam file.
342 */
344write_datagram(BamWriter *manager, Datagram &dg) {
345 PartGroup::write_datagram(manager, dg);
346
347 manager->write_pointer(dg, _forced_channel);
348}
349
350/**
351 * Receives an array of pointers, one for each time manager->read_pointer()
352 * was called in fillin(). Returns the number of pointers processed.
353 *
354 * This is the callback function that is made by the BamReader at some later
355 * point, after all of the required pointers have been filled in. It is
356 * necessary because there might be forward references in a bam file; when we
357 * call read_pointer() in fillin(), the object may not have been read from the
358 * file yet, so we do not have a pointer available at that time. Thus,
359 * instead of returning a pointer, read_pointer() simply reserves a later
360 * callback. This function provides that callback. The calling object is
361 * responsible for keeping track of the number of times it called
362 * read_pointer() and extracting the same number of pointers out of the
363 * supplied vector, and storing them appropriately within the object.
364 */
366complete_pointers(TypedWritable **p_list, BamReader *manager) {
367 int pi = PartGroup::complete_pointers(p_list, manager);
368
369 if (manager->get_file_minor_ver() >= 20) {
370 _forced_channel = DCAST(AnimChannelBase, p_list[pi++]);
371 }
372
373 return pi;
374}
375
376/**
377 * This internal function is called by make_from_bam to read in all of the
378 * relevant data from the BamFile for the new MovingPartBase.
379 */
380void MovingPartBase::
381fillin(DatagramIterator &scan, BamReader *manager) {
382 PartGroup::fillin(scan, manager);
383
384 if (manager->get_file_minor_ver() >= 20) {
385 manager->read_pointer(scan);
386 }
387}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Parent class for all animation channels.
Controls the timing of a character animation.
Definition animControl.h:38
bool channel_has_changed(AnimChannelBase *channel, bool frame_blend_flag) const
Returns true if the indicated channel value has changed since the last call to mark_channels().
int get_channel_index() const
Returns the particular channel index associated with this AnimControl.
Definition animControl.I:52
This is the base class for AnimChannel and AnimBundle.
Definition animGroup.h:33
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
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
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
A dynamic array with an unlimited number of bits.
Definition bitArray.h:40
void clear_bit(int index)
Sets the nth bit off.
Definition bitArray.I:133
void set_bit_to(int index, bool value)
Sets the nth bit either on or off, according to the indicated bool value.
Definition bitArray.I:150
void set_bit(int index)
Sets the nth bit on.
Definition bitArray.I:115
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.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
virtual TypeHandle get_value_type() const =0
Returns the TypeHandle associated with the ValueType we are concerned with.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual bool clear_forced_channel()
Undoes the effect of a previous call to apply_freeze() or apply_control().
virtual bool update_internals(PartBundle *root, PartGroup *parent, bool self_changed, bool parent_changed, Thread *current_thread)
This is called by do_update() whenever the part or some ancestor has changed values.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the channel and all of its descendants.
virtual void write_with_value(std::ostream &out, int indent_level) const
Writes a brief description of the channel and all of its descendants, along with their values.
virtual AnimChannelBase * get_forced_channel() const
Returns the AnimChannelBase that has been forced to this joint by a previous call to apply_freeze() o...
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.
This is the root of a MovingPart hierarchy.
Definition partBundle.h:46
This is the base class for PartRoot and MovingPart.
Definition partGroup.h:43
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual void determine_effective_channels(const CycleData *root_cdata)
Should be called whenever the ChannelBlend values have changed, this recursively updates the _effecti...
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 matches_exclude(const std::string &joint_name) const
Returns true if the indicated name matches a name on the exclude list, false otherwise.
bool matches_include(const std::string &joint_name) const
Returns true if the indicated name matches a name on the include list, false otherwise.
A thread; that is, a lightweight process.
Definition thread.h:46
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.
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.