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