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