Panda3D
movingPartMatrix.cxx
1 // Filename: movingPartMatrix.cxx
2 // Created by: drose (23Feb99)
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 
16 #include "movingPartMatrix.h"
17 #include "animChannelMatrixDynamic.h"
18 #include "animChannelMatrixFixed.h"
19 #include "compose_matrix.h"
20 #include "datagram.h"
21 #include "datagramIterator.h"
22 #include "bamReader.h"
23 #include "bamWriter.h"
24 #include "config_chan.h"
25 
26 // Tell GCC that we'll take care of the instantiation explicitly here.
27 #ifdef __GNUC__
28 #pragma implementation
29 #endif
30 
31 TypeHandle MovingPartMatrix::_type_handle;
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: MovingPartMatrix::Destructor
35 // Access: Public, Virtual
36 // Description:
37 ////////////////////////////////////////////////////////////////////
38 MovingPartMatrix::
39 ~MovingPartMatrix() {
40 }
41 
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: MovingPartMatrix::make_default_channel
45 // Access: Public, Virtual
46 // Description: Creates and returns a new AnimChannel that is not
47 // part of any hierarchy, but that returns the default
48 // value associated with this part.
49 ////////////////////////////////////////////////////////////////////
52  LVecBase3 pos, hpr, scale, shear;
53  decompose_matrix(_default_value, pos, hpr, scale, shear);
54  return new AnimChannelMatrixFixed(get_name(), pos, hpr, scale);
55 }
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: MovingPartMatrix::get_blend_value
59 // Access: Public
60 // Description: Attempts to blend the various matrix values
61 // indicated, and sets the _value member to the
62 // resulting matrix.
63 ////////////////////////////////////////////////////////////////////
66  // If a forced channel is set on this particular joint, we always
67  // return that value instead of performing the blend. Furthermore,
68  // the frame number is always 0 for the forced channel.
69  if (_forced_channel != (AnimChannelBase *)NULL) {
70  ChannelType *channel = DCAST(ChannelType, _forced_channel);
71  channel->get_value(0, _value);
72  return;
73  }
74 
75  PartBundle::CDReader cdata(root->_cycler);
76 
77  if (cdata->_blend.empty()) {
78  // No channel is bound; supply the default value.
79  if (restore_initial_pose) {
80  _value = _default_value;
81  }
82 
83  } else if (_effective_control != (AnimControl *)NULL &&
84  !cdata->_frame_blend_flag) {
85  // A single value, the normal case.
86  ChannelType *channel = DCAST(ChannelType, _effective_channel);
87  channel->get_value(_effective_control->get_frame(), _value);
88 
89  } else {
90  // A blend of two or more values, either between multiple
91  // different animations, or between consecutive frames of the same
92  // animation (or both).
93  switch (cdata->_blend_type) {
94  case PartBundle::BT_linear:
95  {
96  // An ordinary, linear blend.
97  LMatrix4 net_value = LMatrix4::zeros_mat();
98  PN_stdfloat net_effect = 0.0f;
99 
100  PartBundle::ChannelBlend::const_iterator cbi;
101  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
102  AnimControl *control = (*cbi).first;
103  PN_stdfloat effect = (*cbi).second;
104  nassertv(effect != 0.0f);
105 
106  int channel_index = control->get_channel_index();
107  nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
108  ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
109  if (channel != (ChannelType *)NULL) {
110  ValueType v;
111  channel->get_value(control->get_frame(), v);
112 
113  if (!cdata->_frame_blend_flag) {
114  // Hold the current frame until the next one is ready.
115  net_value += v * effect;
116  } else {
117  // Blend between successive frames.
118  PN_stdfloat frac = (PN_stdfloat)control->get_frac();
119  net_value += v * (effect * (1.0f - frac));
120 
121  channel->get_value(control->get_next_frame(), v);
122  net_value += v * (effect * frac);
123  }
124  net_effect += effect;
125  }
126  }
127 
128  if (net_effect == 0.0f) {
129  if (restore_initial_pose) {
130  _value = _default_value;
131  }
132  } else {
133  _value = net_value / net_effect;
134  }
135  }
136  break;
137 
138  case PartBundle::BT_normalized_linear:
139  {
140  // A normalized linear blend. This means we do a linear blend
141  // without scales or shears, normalize the scale and shear
142  // components of the resulting matrix to eliminate
143  // artificially-introduced scales, and then reapply the
144  // scales and shears.
145 
146  LMatrix4 net_value = LMatrix4::zeros_mat();
147  LVecBase3 scale(0.0f, 0.0f, 0.0f);
148  LVecBase3 shear(0.0f, 0.0f, 0.0f);
149  PN_stdfloat net_effect = 0.0f;
150 
151  PartBundle::ChannelBlend::const_iterator cbi;
152  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
153  AnimControl *control = (*cbi).first;
154  PN_stdfloat effect = (*cbi).second;
155  nassertv(effect != 0.0f);
156 
157  ChannelType *channel = NULL;
158  int channel_index = control->get_channel_index();
159  if (channel_index >= 0 && channel_index < (int)_channels.size()) {
160  channel = DCAST(ChannelType, _channels[channel_index]);
161  }
162  if (channel != (ChannelType *)NULL) {
163  int frame = control->get_frame();
164  ValueType v;
165  LVecBase3 iscale, ishear;
166  channel->get_value_no_scale_shear(frame, v);
167  channel->get_scale(frame, iscale);
168  channel->get_shear(frame, ishear);
169 
170  if (!cdata->_frame_blend_flag) {
171  // Hold the current frame until the next one is ready.
172  net_value += v * effect;
173  scale += iscale * effect;
174  shear += ishear * effect;
175  } else {
176  // Blend between successive frames.
177  PN_stdfloat frac = (PN_stdfloat)control->get_frac();
178  PN_stdfloat e0 = effect * (1.0f - frac);
179  net_value += v * e0;
180  scale += iscale * e0;
181  shear += ishear * e0;
182 
183  int next_frame = control->get_next_frame();
184  channel->get_value_no_scale_shear(next_frame, v);
185  channel->get_scale(next_frame, iscale);
186  channel->get_shear(next_frame, ishear);
187  PN_stdfloat e1 = effect * frac;
188  net_value += v * e1;
189  scale += iscale * e1;
190  shear += ishear * e1;
191  }
192  net_effect += effect;
193  }
194  }
195 
196  if (net_effect == 0.0f) {
197  if (restore_initial_pose) {
198  _value = _default_value;
199  }
200 
201  } else {
202  net_value /= net_effect;
203  scale /= net_effect;
204  shear /= net_effect;
205 
206  // Now rebuild the matrix with the correct scale values.
207 
208  LVector3 false_scale, false_shear, hpr, translate;
209  decompose_matrix(net_value, false_scale, false_shear, hpr, translate);
210  compose_matrix(_value, scale, shear, hpr, translate);
211  }
212  }
213  break;
214 
215  case PartBundle::BT_componentwise:
216  {
217  // Componentwise linear, including componentwise H, P, and R.
218  LVecBase3 scale(0.0f, 0.0f, 0.0f);
219  LVecBase3 hpr(0.0f, 0.0f, 0.0f);
220  LVecBase3 pos(0.0f, 0.0f, 0.0f);
221  LVecBase3 shear(0.0f, 0.0f, 0.0f);
222  PN_stdfloat net_effect = 0.0f;
223 
224  PartBundle::ChannelBlend::const_iterator cbi;
225  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
226  AnimControl *control = (*cbi).first;
227  PN_stdfloat effect = (*cbi).second;
228  nassertv(effect != 0.0f);
229 
230  ChannelType *channel = NULL;
231  int channel_index = control->get_channel_index();
232  if (channel_index >= 0 && channel_index < (int)_channels.size()) {
233  channel = DCAST(ChannelType, _channels[channel_index]);
234  }
235  if (channel != (ChannelType *)NULL) {
236  int frame = control->get_frame();
237  LVecBase3 iscale, ihpr, ipos, ishear;
238  channel->get_scale(frame, iscale);
239  channel->get_hpr(frame, ihpr);
240  channel->get_pos(frame, ipos);
241  channel->get_shear(frame, ishear);
242 
243  if (!cdata->_frame_blend_flag) {
244  // Hold the current frame until the next one is ready.
245  scale += iscale * effect;
246  hpr += ihpr * effect;
247  pos += ipos * effect;
248  shear += ishear * effect;
249  } else {
250  // Blend between successive frames.
251  PN_stdfloat frac = (PN_stdfloat)control->get_frac();
252  PN_stdfloat e0 = effect * (1.0f - frac);
253 
254  scale += iscale * e0;
255  hpr += ihpr * e0;
256  pos += ipos * e0;
257  shear += ishear * e0;
258 
259  int next_frame = control->get_next_frame();
260  channel->get_scale(next_frame, iscale);
261  channel->get_hpr(next_frame, ihpr);
262  channel->get_pos(next_frame, ipos);
263  channel->get_shear(next_frame, ishear);
264  PN_stdfloat e1 = effect * frac;
265 
266  scale += iscale * e1;
267  hpr += ihpr * e1;
268  pos += ipos * e1;
269  shear += ishear * e1;
270  }
271  net_effect += effect;
272  }
273  }
274 
275  if (net_effect == 0.0f) {
276  if (restore_initial_pose) {
277  _value = _default_value;
278  }
279 
280  } else {
281  scale /= net_effect;
282  hpr /= net_effect;
283  pos /= net_effect;
284  shear /= net_effect;
285 
286  compose_matrix(_value, scale, shear, hpr, pos);
287  }
288  }
289  break;
290 
291  case PartBundle::BT_componentwise_quat:
292  {
293  // Componentwise linear, except for rotation, which is a
294  // quaternion.
295  LVecBase3 scale(0.0f, 0.0f, 0.0f);
296  LQuaternion quat(0.0f, 0.0f, 0.0f, 0.0f);
297  LVecBase3 pos(0.0f, 0.0f, 0.0f);
298  LVecBase3 shear(0.0f, 0.0f, 0.0f);
299  PN_stdfloat net_effect = 0.0f;
300 
301  PartBundle::ChannelBlend::const_iterator cbi;
302  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
303  AnimControl *control = (*cbi).first;
304  PN_stdfloat effect = (*cbi).second;
305  nassertv(effect != 0.0f);
306 
307  ChannelType *channel = NULL;
308  int channel_index = control->get_channel_index();
309  if (channel_index >= 0 && channel_index < (int)_channels.size()) {
310  channel = DCAST(ChannelType, _channels[channel_index]);
311  }
312  if (channel != (ChannelType *)NULL) {
313  int frame = control->get_frame();
314  LVecBase3 iscale, ipos, ishear;
315  LQuaternion iquat;
316  channel->get_scale(frame, iscale);
317  channel->get_quat(frame, iquat);
318  channel->get_pos(frame, ipos);
319  channel->get_shear(frame, ishear);
320 
321  if (!cdata->_frame_blend_flag) {
322  // Hold the current frame until the next one is ready.
323  scale += iscale * effect;
324  quat += iquat * effect;
325  pos += ipos * effect;
326  shear += ishear * effect;
327 
328  } else {
329  // Blend between successive frames.
330  PN_stdfloat frac = (PN_stdfloat)control->get_frac();
331  PN_stdfloat e0 = effect * (1.0f - frac);
332 
333  scale += iscale * e0;
334  quat += iquat * e0;
335  pos += ipos * e0;
336  shear += ishear * e0;
337 
338  int next_frame = control->get_next_frame();
339  channel->get_scale(next_frame, iscale);
340  channel->get_quat(next_frame, iquat);
341  channel->get_pos(next_frame, ipos);
342  channel->get_shear(next_frame, ishear);
343  PN_stdfloat e1 = effect * frac;
344 
345  scale += iscale * e1;
346  quat += iquat * e1;
347  pos += ipos * e1;
348  shear += ishear * e1;
349  }
350  net_effect += effect;
351  }
352  }
353 
354  if (net_effect == 0.0f) {
355  if (restore_initial_pose) {
356  _value = _default_value;
357  }
358 
359  } else {
360  scale /= net_effect;
361  quat /= net_effect;
362  pos /= net_effect;
363  shear /= net_effect;
364 
365  // There should be no need to normalize the quaternion,
366  // assuming all of the input quaternions were already
367  // normalized.
368 
369  _value = LMatrix4::scale_shear_mat(scale, shear) * quat;
370  _value.set_row(3, pos);
371  }
372  }
373  break;
374  }
375  }
376 }
377 
378 ////////////////////////////////////////////////////////////////////
379 // Function: MovingPartMatrix::apply_freeze_matrix
380 // Access: Public, Virtual
381 // Description: Freezes this particular joint so that it will always
382 // hold the specified transform. Returns true if this
383 // is a joint that can be so frozen, false otherwise.
384 // This is called internally by
385 // PartBundle::freeze_joint().
386 ////////////////////////////////////////////////////////////////////
388 apply_freeze_matrix(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale) {
389  _forced_channel = new AnimChannelMatrixFixed(get_name(), pos, hpr, scale);
390  return true;
391 }
392 
393 ////////////////////////////////////////////////////////////////////
394 // Function: MovingPartMatrix::apply_control
395 // Access: Public, Virtual
396 // Description: Specifies a node to influence this particular joint
397 // so that it will always hold the node's transform.
398 // Returns true if this is a joint that can be so
399 // controlled, false otherwise. This is called
400 // internally by PartBundle::control_joint().
401 ////////////////////////////////////////////////////////////////////
404  AnimChannelMatrixDynamic *chan = new AnimChannelMatrixDynamic(get_name());
405  chan->set_value_node(node);
406  _forced_channel = chan;
407  return true;
408 }
409 
410 ////////////////////////////////////////////////////////////////////
411 // Function: MovingPartMatrix::make_MovingPartMatrix
412 // Access: Protected
413 // Description: Factory method to generate a MovingPartMatrix object
414 ////////////////////////////////////////////////////////////////////
418  DatagramIterator scan;
419  BamReader *manager;
420 
421  parse_params(params, scan, manager);
422  me->fillin(scan, manager);
423  return me;
424 }
425 
426 ////////////////////////////////////////////////////////////////////
427 // Function: MovingPartMatrix::register_with_factory
428 // Access: Public, Static
429 // Description: Factory method to generate a MovingPartMatrix object
430 ////////////////////////////////////////////////////////////////////
434 }
static void register_with_read_factory()
Factory method to generate a MovingPartMatrix object.
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
virtual void get_pos(int frame, LVecBase3 &pos)
Returns the x, y, and z translation components associated with the current frame. ...
Definition: animChannel.I:158
virtual void get_quat(int frame, LQuaternion &quat)
Returns the rotation component associated with the current frame, expressed as a quaternion.
Definition: animChannel.I:145
virtual void get_scale(int frame, LVecBase3 &scale)
Returns the x, y, and z scale components associated with the current frame.
Definition: animChannel.I:119
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
virtual void get_blend_value(const PartBundle *root)
Attempts to blend the various matrix values indicated, and sets the _value member to the resulting ma...
static LMatrix4f scale_shear_mat(const LVecBase3f &scale, const LVecBase3f &shear, CoordinateSystem cs=CS_default)
Returns a matrix that applies the indicated scale and shear.
Definition: lmatrix.h:2526
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
virtual bool apply_control(PandaNode *node)
Specifies a node to influence this particular joint so that it will always hold the node&#39;s transform...
void set_value_node(PandaNode *node)
Specifies a node whose transform will be queried each frame to implicitly specify the transform of th...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
virtual void get_hpr(int frame, LVecBase3 &hpr)
Returns the h, p, and r components associated with the current frame.
Definition: animChannel.I:132
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
Parent class for all animation channels.
An animation channel that accepts a matrix each frame from some dynamic input provided by code...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
virtual void get_value_no_scale_shear(int frame, ValueType &value)
Returns the value associated with the current frame, with no scale or share components.
Definition: animChannel.I:106
A specialization on AnimChannel to add all the special matrix component operations.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
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.
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
int get_next_frame() const
Returns the current integer frame number + 1, constrained to the range 0 <= f < get_num_frames().
static const LMatrix4f & zeros_mat()
Returns an matrix filled with zeros.
Definition: lmatrix.h:923
virtual AnimChannelBase * make_default_channel() const
Creates and returns a new AnimChannel that is not part of any hierarchy, but that returns the default...
This is a particular kind of MovingPart that accepts a matrix each frame.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
This is the base quaternion class.
Definition: lquaternion.h:96
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:49
int get_channel_index() const
Returns the particular channel index associated with this AnimControl.
Definition: animControl.I:67
Controls the timing of a character animation.
Definition: animControl.h:41
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
int get_frame() const
Returns the current integer frame number.
double get_frac() const
Returns the fractional part of the current frame.
virtual void get_shear(int frame, LVecBase3 &shear)
Returns the a, b, and c shear components associated with the current frame.
Definition: animChannel.I:171
static TypedWritable * make_MovingPartMatrix(const FactoryParams &params)
Factory method to generate a MovingPartMatrix object.