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 }
AnimChannel::get_quat
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
movingPartMatrix.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MovingPartMatrix::apply_freeze_matrix
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.
Definition: movingPartMatrix.cxx:368
AnimChannelMatrixFixed
A specialization on AnimChannel to add all the special matrix component operations.
Definition: animChannelMatrixFixed.h:26
AnimChannel::get_scale
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
AnimChannel::get_pos
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
MovingPart< ACMatrixSwitchType >
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
MovingPartMatrix
This is a particular kind of MovingPart that accepts a matrix each frame.
Definition: movingPartMatrix.h:29
animChannelMatrixFixed.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MovingPartMatrix::make_default_channel
virtual AnimChannelBase * make_default_channel() const
Creates and returns a new AnimChannel that is not part of any hierarchy, but that returns the default...
Definition: movingPartMatrix.cxx:41
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
compose_matrix.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AnimInterface::get_next_frame
get_next_frame
Returns the current integer frame number + 1, constrained to the range 0 <= f < get_num_frames().
Definition: animInterface.h:71
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
AnimChannel::get_hpr
virtual void get_hpr(int frame, LVecBase3 &hpr)
Returns the h, p, and r components associated with the current frame.
Definition: animChannel.I:90
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
AnimChannelBase
Parent class for all animation channels.
Definition: animChannelBase.h:30
AnimInterface::get_frac
get_frac
Returns the fractional part of the current frame.
Definition: animInterface.h:72
MovingPartMatrix::make_MovingPartMatrix
static TypedWritable * make_MovingPartMatrix(const FactoryParams &params)
Factory method to generate a MovingPartMatrix object.
Definition: movingPartMatrix.cxx:391
AnimChannelMatrixDynamic
An animation channel that accepts a matrix each frame from some dynamic input provided by code.
Definition: animChannelMatrixDynamic.h:33
CycleDataReader
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
Definition: cycleDataReader.h:35
MovingPartMatrix::register_with_read_factory
static void register_with_read_factory()
Factory method to generate a MovingPartMatrix object.
Definition: movingPartMatrix.cxx:405
animChannelMatrixDynamic.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Factory::register_factory
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
AnimChannelMatrixDynamic::set_value_node
set_value_node
Specifies a node whose transform will be queried each frame to implicitly specify the transform of th...
Definition: animChannelMatrixDynamic.h:60
config_chan.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AnimChannel::get_value_no_scale_shear
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
MovingPartMatrix::get_blend_value
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...
Definition: movingPartMatrix.cxx:52
AnimControl::get_channel_index
int get_channel_index() const
Returns the particular channel index associated with this AnimControl.
Definition: animControl.I:52
AnimControl
Controls the timing of a character animation.
Definition: animControl.h:38
MovingPartMatrix::apply_control
virtual bool apply_control(PandaNode *node)
Specifies a node to influence this particular joint so that it will always hold the node's transform.
Definition: movingPartMatrix.cxx:380
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AnimChannel< ACMatrixSwitchType >
AnimChannel::get_shear
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
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
parse_params
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
PartBundle
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:46
AnimInterface::get_frame
get_frame
Returns the current integer frame number.
Definition: animInterface.h:70