Panda3D
animChannelMatrixXfmTable.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 animChannelMatrixXfmTable.cxx
10  * @author drose
11  * @date 1999-02-20
12  */
13 
15 #include "animBundle.h"
16 #include "config_chan.h"
17 
18 #include "compose_matrix.h"
19 #include "indent.h"
20 #include "datagram.h"
21 #include "datagramIterator.h"
22 #include "bamReader.h"
23 #include "bamWriter.h"
24 #include "fftCompressor.h"
25 #include "config_linmath.h"
26 
27 TypeHandle AnimChannelMatrixXfmTable::_type_handle;
28 
29 /**
30  * Used only for bam loader.
31  */
32 AnimChannelMatrixXfmTable::
33 AnimChannelMatrixXfmTable() {
34  for (int i = 0; i < num_matrix_components; i++) {
35  _tables[i] = CPTA_stdfloat(get_class_type());
36  }
37 }
38 
39 /**
40  * Creates a new AnimChannelMatrixXfmTable, just like this one, without
41  * copying any children. The new copy is added to the indicated parent.
42  * Intended to be called by make_copy() only.
43  */
44 AnimChannelMatrixXfmTable::
45 AnimChannelMatrixXfmTable(AnimGroup *parent, const AnimChannelMatrixXfmTable &copy) :
46  AnimChannelMatrix(parent, copy)
47 {
48  for (int i = 0; i < num_matrix_components; i++) {
49  _tables[i] = copy._tables[i];
50  }
51 }
52 
53 /**
54  *
55  */
56 AnimChannelMatrixXfmTable::
57 AnimChannelMatrixXfmTable(AnimGroup *parent, const std::string &name)
58  : AnimChannelMatrix(parent, name)
59 {
60  for (int i = 0; i < num_matrix_components; i++) {
61  _tables[i] = CPTA_stdfloat(get_class_type());
62  }
63 }
64 
65 /**
66  *
67  */
68 AnimChannelMatrixXfmTable::
69 ~AnimChannelMatrixXfmTable() {
70 }
71 
72 
73 /**
74  * Returns true if the value has changed since the last call to has_changed().
75  * last_frame is the frame number of the last call; this_frame is the current
76  * frame number.
77  */
79 has_changed(int last_frame, double last_frac,
80  int this_frame, double this_frac) {
81  if (last_frame != this_frame) {
82  for (int i = 0; i < num_matrix_components; i++) {
83  if (_tables[i].size() > 1) {
84  if (_tables[i][last_frame % _tables[i].size()] !=
85  _tables[i][this_frame % _tables[i].size()]) {
86  return true;
87  }
88  }
89  }
90  }
91 
92  if (last_frac != this_frac) {
93  // If we have some fractional changes, also check the next subsequent
94  // frame (since we'll be blending with that).
95  for (int i = 0; i < num_matrix_components; i++) {
96  if (_tables[i].size() > 1) {
97  if (_tables[i][last_frame % _tables[i].size()] !=
98  _tables[i][(this_frame + 1) % _tables[i].size()]) {
99  return true;
100  }
101  }
102  }
103  }
104 
105  return false;
106 }
107 
108 /**
109  * Gets the value of the channel at the indicated frame.
110  */
112 get_value(int frame, LMatrix4 &mat) {
113  PN_stdfloat components[num_matrix_components];
114 
115  for (int i = 0; i < num_matrix_components; i++) {
116  if (_tables[i].empty()) {
117  components[i] = get_default_value(i);
118  } else {
119  components[i] = _tables[i][frame % _tables[i].size()];
120  }
121  }
122 
123  compose_matrix(mat, components);
124 }
125 
126 /**
127  * Gets the value of the channel at the indicated frame, without any scale or
128  * shear information.
129  */
131 get_value_no_scale_shear(int frame, LMatrix4 &mat) {
132  PN_stdfloat components[num_matrix_components];
133  components[0] = 1.0f;
134  components[1] = 1.0f;
135  components[2] = 1.0f;
136  components[3] = 0.0f;
137  components[4] = 0.0f;
138  components[5] = 0.0f;
139 
140  for (int i = 6; i < num_matrix_components; i++) {
141  if (_tables[i].empty()) {
142  components[i] = get_default_value(i);
143  } else {
144  components[i] = _tables[i][frame % _tables[i].size()];
145  }
146  }
147 
148  compose_matrix(mat, components);
149 }
150 
151 /**
152  * Gets the scale value at the indicated frame.
153  */
155 get_scale(int frame, LVecBase3 &scale) {
156  for (int i = 0; i < 3; i++) {
157  if (_tables[i].empty()) {
158  scale[i] = 1.0f;
159  } else {
160  scale[i] = _tables[i][frame % _tables[i].size()];
161  }
162  }
163 }
164 
165 /**
166  * Returns the h, p, and r components associated with the current frame. As
167  * above, this only makes sense for a matrix-type channel.
168  */
170 get_hpr(int frame, LVecBase3 &hpr) {
171  for (int i = 0; i < 3; i++) {
172  if (_tables[i + 6].empty()) {
173  hpr[i] = 0.0f;
174  } else {
175  hpr[i] = _tables[i + 6][frame % _tables[i + 6].size()];
176  }
177  }
178 }
179 
180 /**
181  * Returns the rotation component associated with the current frame, expressed
182  * as a quaternion. As above, this only makes sense for a matrix-type
183  * channel.
184  */
186 get_quat(int frame, LQuaternion &quat) {
187  LVecBase3 hpr;
188  for (int i = 0; i < 3; i++) {
189  if (_tables[i + 6].empty()) {
190  hpr[i] = 0.0f;
191  } else {
192  hpr[i] = _tables[i + 6][frame % _tables[i + 6].size()];
193  }
194  }
195 
196  quat.set_hpr(hpr);
197 }
198 
199 /**
200  * Returns the x, y, and z translation components associated with the current
201  * frame. As above, this only makes sense for a matrix-type channel.
202  */
204 get_pos(int frame, LVecBase3 &pos) {
205  for (int i = 0; i < 3; i++) {
206  if (_tables[i + 9].empty()) {
207  pos[i] = 0.0f;
208  } else {
209  pos[i] = _tables[i + 9][frame % _tables[i + 9].size()];
210  }
211  }
212 }
213 
214 /**
215  * Returns the a, b, and c shear components associated with the current frame.
216  * As above, this only makes sense for a matrix-type channel.
217  */
219 get_shear(int frame, LVecBase3 &shear) {
220  for (int i = 0; i < 3; i++) {
221  if (_tables[i + 3].empty()) {
222  shear[i] = 0.0f;
223  } else {
224  shear[i] = _tables[i + 3][frame % _tables[i + 3].size()];
225  }
226  }
227 }
228 
229 /**
230  * Assigns the indicated table. table_id is one of 'i', 'j', 'k', for scale,
231  * 'a', 'b', 'c' for shear, 'h', 'p', 'r', for rotation, and 'x', 'y', 'z',
232  * for translation. The new table must have either zero, one, or
233  * get_num_frames() frames.
234  */
236 set_table(char table_id, const CPTA_stdfloat &table) {
237  int num_frames = _root->get_num_frames();
238 
239  if (table.size() > 1 && (int)table.size() < num_frames) {
240  // The new table has an invalid number of frames--it doesn't match the
241  // bundle's requirement.
242  nassert_raise("mismatched number of frames");
243  return;
244  }
245 
246  int i = get_table_index(table_id);
247  if (i < 0) {
248  return;
249  }
250 
251  _tables[i] = table;
252 }
253 
254 
255 /**
256  * Removes all the tables from the channel, and resets it to its initial
257  * state.
258  */
261  for (int i = 0; i < num_matrix_components; i++) {
262  _tables[i] = CPTA_stdfloat(get_class_type());
263  }
264 }
265 
266 /**
267  * Writes a brief description of the table and all of its descendants.
268  */
270 write(std::ostream &out, int indent_level) const {
271  indent(out, indent_level)
272  << get_type() << " " << get_name() << " ";
273 
274  // Write a list of all the sub-tables that have data.
275  bool found_any = false;
276  for (int i = 0; i < num_matrix_components; i++) {
277  if (!_tables[i].empty()) {
278  out << get_table_id(i) << _tables[i].size();
279  found_any = true;
280  }
281  }
282 
283  if (!found_any) {
284  out << "(no data)";
285  }
286 
287  if (!_children.empty()) {
288  out << " {\n";
289  write_descendants(out, indent_level + 2);
290  indent(out, indent_level) << "}";
291  }
292 
293  out << "\n";
294 }
295 
296 /**
297  * Returns a copy of this object, and attaches it to the indicated parent
298  * (which may be NULL only if this is an AnimBundle). Intended to be called
299  * by copy_subtree() only.
300  */
301 AnimGroup *AnimChannelMatrixXfmTable::
302 make_copy(AnimGroup *parent) const {
303  return new AnimChannelMatrixXfmTable(parent, *this);
304 }
305 
306 /**
307  * Returns the table index number, a value between 0 and
308  * num_matrix_components, that corresponds to the indicated table id. Returns
309  * -1 if the table id is invalid.
310  */
311 int AnimChannelMatrixXfmTable::
312 get_table_index(char table_id) {
313  for (int i = 0; i < num_matrix_components; i++) {
314  if (table_id == get_table_id(i)) {
315  return i;
316  }
317  }
318 
319  return -1;
320 }
321 
322 /**
323  * Function to write the important information in the particular object to a
324  * Datagram
325  */
329 
330  if (compress_channels) {
331  chan_cat.warning()
332  << "FFT compression of animations is deprecated. For compatibility "
333  "with future versions of Panda3D, set compress-channels to false.\n";
334 
336  chan_cat.error()
337  << "Compression is not available; writing uncompressed channels.\n";
338  compress_channels = false;
339  }
340  }
341 
342  me.add_bool(compress_channels);
343 
344  // We now always use the new HPR conventions.
345  me.add_bool(true);
346 
347  if (!compress_channels) {
348  // Write out everything uncompressed, as a stream of floats.
349  for (int i = 0; i < num_matrix_components; i++) {
350  me.add_uint16(_tables[i].size());
351  for(int j = 0; j < (int)_tables[i].size(); j++) {
352  me.add_stdfloat(_tables[i][j]);
353  }
354  }
355 
356  } else {
357  // Write out everything using lossy compression.
358  FFTCompressor compressor;
359  compressor.set_quality(compress_chan_quality);
360  compressor.set_use_error_threshold(true);
361  compressor.write_header(me);
362 
363  // First, write out the scales and shears.
364  int i;
365  for (i = 0; i < 6; i++) {
366  compressor.write_reals(me, _tables[i], _tables[i].size());
367  }
368 
369  // Now, write out the joint angles. For these we need to build up a HPR
370  // array.
371  pvector<LVecBase3> hprs;
372  int hprs_length = std::max(std::max(_tables[6].size(), _tables[7].size()), _tables[8].size());
373  hprs.reserve(hprs_length);
374  for (i = 0; i < hprs_length; i++) {
375  PN_stdfloat h = _tables[6].empty() ? 0.0f : _tables[6][i % _tables[6].size()];
376  PN_stdfloat p = _tables[7].empty() ? 0.0f : _tables[7][i % _tables[7].size()];
377  PN_stdfloat r = _tables[8].empty() ? 0.0f : _tables[8][i % _tables[8].size()];
378  hprs.push_back(LVecBase3(h, p, r));
379  }
380  const LVecBase3 *hprs_array = nullptr;
381  if (hprs_length != 0) {
382  hprs_array = &hprs[0];
383  }
384  compressor.write_hprs(me, hprs_array, hprs_length);
385 
386  // And now the translations.
387  for(i = 9; i < num_matrix_components; i++) {
388  compressor.write_reals(me, _tables[i], _tables[i].size());
389  }
390  }
391 }
392 
393 /**
394  * Function that reads out of the datagram (or asks manager to read) all of
395  * the data that is needed to re-create this object and stores it in the
396  * appropiate place
397  */
398 void AnimChannelMatrixXfmTable::
399 fillin(DatagramIterator &scan, BamReader *manager) {
400  AnimChannelMatrix::fillin(scan, manager);
401 
402  bool wrote_compressed = scan.get_bool();
403 
404  // If this is false, the file still uses the old HPR conventions, and we'll
405  // have to convert the HPR values to the new convention.
406  bool new_hpr = scan.get_bool();
407 
408  if (!wrote_compressed) {
409  // Regular floats.
410 
411  for (int i = 0; i < num_matrix_components; i++) {
412  int size = scan.get_uint16();
413  PTA_stdfloat ind_table(get_class_type());
414  for (int j = 0; j < size; j++) {
415  ind_table.push_back(scan.get_stdfloat());
416  }
417  _tables[i] = ind_table;
418  }
419 
420  if (!new_hpr) {
421  // Convert between the old HPR form and the new HPR form.
422  size_t num_hprs = std::max(std::max(_tables[6].size(), _tables[7].size()),
423  _tables[8].size());
424 
425  LVecBase3 default_hpr(0.0, 0.0, 0.0);
426  if (!_tables[6].empty()) {
427  default_hpr[0] = _tables[6][0];
428  }
429  if (!_tables[7].empty()) {
430  default_hpr[1] = _tables[7][0];
431  }
432  if (!_tables[8].empty()) {
433  default_hpr[2] = _tables[8][0];
434  }
435 
436  PTA_stdfloat h_table = PTA_stdfloat::empty_array(num_hprs, get_class_type());
437  PTA_stdfloat p_table = PTA_stdfloat::empty_array(num_hprs, get_class_type());
438  PTA_stdfloat r_table = PTA_stdfloat::empty_array(num_hprs, get_class_type());
439 
440  for (size_t hi = 0; hi < num_hprs; hi++) {
441  PN_stdfloat h = (hi < _tables[6].size() ? _tables[6][hi] : default_hpr[0]);
442  PN_stdfloat p = (hi < _tables[7].size() ? _tables[7][hi] : default_hpr[1]);
443  PN_stdfloat r = (hi < _tables[8].size() ? _tables[8][hi] : default_hpr[2]);
444 
445  LVecBase3 hpr = old_to_new_hpr(LVecBase3(h, p, r));
446  h_table[hi] = hpr[0];
447  p_table[hi] = hpr[1];
448  r_table[hi] = hpr[2];
449  }
450  _tables[6] = h_table;
451  _tables[7] = p_table;
452  _tables[8] = r_table;
453  }
454 
455  } else {
456  // Compressed channels.
457  if (!read_compressed_channels) {
458  chan_cat.info()
459  << "Not reading compressed animation channels.\n";
461  return;
462  }
463 
464  FFTCompressor compressor;
465  compressor.read_header(scan, manager->get_file_minor_ver());
466 
467  int i;
468  // First, read in the scales and shears.
469  for (i = 0; i < 6; i++) {
470  PTA_stdfloat ind_table = PTA_stdfloat::empty_array(0, get_class_type());
471  compressor.read_reals(scan, ind_table.v());
472  _tables[i] = ind_table;
473  }
474 
475  // Read in the HPR array and store it back in the joint angles.
476  pvector<LVecBase3> hprs;
477  compressor.read_hprs(scan, hprs, new_hpr);
478  PTA_stdfloat h_table = PTA_stdfloat::empty_array(hprs.size(), get_class_type());
479  PTA_stdfloat p_table = PTA_stdfloat::empty_array(hprs.size(), get_class_type());
480  PTA_stdfloat r_table = PTA_stdfloat::empty_array(hprs.size(), get_class_type());
481 
482  for (i = 0; i < (int)hprs.size(); i++) {
483  if (!new_hpr) {
484  // Convert the old HPR form to the new HPR form.
485  LVecBase3 hpr = old_to_new_hpr(hprs[i]);
486  h_table[i] = hpr[0];
487  p_table[i] = hpr[1];
488  r_table[i] = hpr[2];
489 
490  } else {
491  // Store the HPR angle directly.
492  h_table[i] = hprs[i][0];
493  p_table[i] = hprs[i][1];
494  r_table[i] = hprs[i][2];
495  }
496  }
497  _tables[6] = h_table;
498  _tables[7] = p_table;
499  _tables[8] = r_table;
500 
501  // Now read in the translations.
502  for (i = 9; i < num_matrix_components; i++) {
503  PTA_stdfloat ind_table = PTA_stdfloat::empty_array(0, get_class_type());
504  compressor.read_reals(scan, ind_table.v());
505  _tables[i] = ind_table;
506  }
507  }
508 }
509 
510 /**
511  * Factory method to generate an AnimChannelMatrixXfmTable object.
512  */
516  DatagramIterator scan;
517  BamReader *manager;
518 
519  parse_params(params, scan, manager);
520  me->fillin(scan, manager);
521  return me;
522 }
523 
524 /**
525  * Factory method to generate an AnimChannelMatrixXfmTable object.
526  */
530 }
virtual void get_hpr(int frame, LVecBase3 &hpr)
Returns the h, p, and r components associated with the current frame.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool read_reals(DatagramIterator &di, vector_stdfloat &array)
Reads an array of floating-point numbers.
bool read_hprs(DatagramIterator &di, pvector< LVecBase3 > &array, bool new_hpr)
Reads an array of HPR angles.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
void set_quality(int quality)
Sets the quality factor for the compression.
bool get_bool()
Extracts a boolean value.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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_shear(int frame, LVecBase3 &shear)
Returns the a, b, and c shear components associated with the current frame.
bool read_header(DatagramIterator &di, int bam_minor_version)
Reads the compression header that was written previously.
virtual void get_pos(int frame, LVecBase3 &pos)
Returns the x, y, and z translation components associated with the current frame.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
virtual void get_scale(int frame, LVecBase3 &scale)
Gets the scale value at the indicated frame.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
This class manages a lossy compression and decompression of a stream of floating-point numbers to a d...
Definition: fftCompressor.h:40
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the table and all of its descendants.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
void clear_all_tables()
Removes all the tables from the channel, and resets it to its initial state.
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
Definition: datagram.I:133
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
This is the base class for AnimChannel and AnimBundle.
Definition: animGroup.h:33
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static TypedWritable * make_AnimChannelMatrixXfmTable(const FactoryParams &params)
Factory method to generate an AnimChannelMatrixXfmTable object.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
void write_header(Datagram &datagram)
Writes the compression parameters to the indicated datagram.
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.
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.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual void get_value(int frame, LMatrix4 &mat)
Gets the value of the channel at the indicated frame.
void write_reals(Datagram &datagram, const PN_stdfloat *array, int length)
Writes an array of floating-point numbers to the indicated datagram.
static void register_with_read_factory()
Factory method to generate an AnimChannelMatrixXfmTable object.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
set_table
Assigns the indicated table.
void write_hprs(Datagram &datagram, const LVecBase3 *array, int length)
Writes an array of HPR angles to the indicated datagram.
An animation channel that issues a matrix each frame, read from a table such as might have been read ...
virtual void get_quat(int frame, LQuaternion &quat)
Returns the rotation component associated with the current frame, expressed as a quaternion.
A class to retrieve the individual data elements previously stored in a Datagram.
void set_use_error_threshold(bool use_error_threshold)
Enables or disables the use of the error threshold measurement to put a cap on the amount of damage d...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool has_changed(int last_frame, double last_frac, int this_frame, double this_frac)
Returns true if the value has changed since the last call to has_changed().
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static bool is_compression_available()
Returns true if the FFTW library is compiled in, so that this class is actually capable of doing usef...
Similar to PointerToArray, except that its contents may not be modified.
virtual void get_value_no_scale_shear(int frame, LMatrix4 &value)
Gets the value of the channel at the indicated frame, without any scale or shear information.