Panda3D
animChannelMatrixXfmTable.cxx
1 // Filename: animChannelMatrixXfmTable.cxx
2 // Created by: drose (20Feb99)
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 "animChannelMatrixXfmTable.h"
17 #include "animBundle.h"
18 #include "config_chan.h"
19 
20 #include "compose_matrix.h"
21 #include "indent.h"
22 #include "datagram.h"
23 #include "datagramIterator.h"
24 #include "bamReader.h"
25 #include "bamWriter.h"
26 #include "fftCompressor.h"
27 #include "config_linmath.h"
28 
29 TypeHandle AnimChannelMatrixXfmTable::_type_handle;
30 
31 ////////////////////////////////////////////////////////////////////
32 // Function: AnimChannelMatrixXfmTable::Constructor
33 // Access: Protected
34 // Description: Used only for bam loader.
35 /////////////////////////////////////////////////////////////
36 AnimChannelMatrixXfmTable::
37 AnimChannelMatrixXfmTable() {
38  for (int i = 0; i < num_matrix_components; i++) {
39  _tables[i] = CPTA_stdfloat(get_class_type());
40  }
41 }
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: AnimChannelMatrixXfmTable::Copy Constructor
45 // Access: Protected
46 // Description: Creates a new AnimChannelMatrixXfmTable, just like
47 // this one, without copying any children. The new copy
48 // is added to the indicated parent. Intended to be
49 // called by make_copy() only.
50 ////////////////////////////////////////////////////////////////////
51 AnimChannelMatrixXfmTable::
52 AnimChannelMatrixXfmTable(AnimGroup *parent, const AnimChannelMatrixXfmTable &copy) :
53  AnimChannelMatrix(parent, copy)
54 {
55  for (int i = 0; i < num_matrix_components; i++) {
56  _tables[i] = copy._tables[i];
57  }
58 }
59 
60 ////////////////////////////////////////////////////////////////////
61 // Function: AnimChannelMatrixXfmTable::Constructor
62 // Access: Public
63 // Description:
64 ////////////////////////////////////////////////////////////////////
65 AnimChannelMatrixXfmTable::
66 AnimChannelMatrixXfmTable(AnimGroup *parent, const string &name)
67  : AnimChannelMatrix(parent, name)
68 {
69  for (int i = 0; i < num_matrix_components; i++) {
70  _tables[i] = CPTA_stdfloat(get_class_type());
71  }
72 }
73 
74 ////////////////////////////////////////////////////////////////////
75 // Function: AnimChannelMatrixXfmTable::Destructor
76 // Access: Public, Virtual
77 // Description:
78 /////////////////////////////////////////////////////////////
79 AnimChannelMatrixXfmTable::
80 ~AnimChannelMatrixXfmTable() {
81 }
82 
83 
84 ////////////////////////////////////////////////////////////////////
85 // Function: AnimChannelMatrixXfmTable::has_changed
86 // Access: Public, Virtual
87 // Description: Returns true if the value has changed since the last
88 // call to has_changed(). last_frame is the frame
89 // number of the last call; this_frame is the current
90 // frame number.
91 ////////////////////////////////////////////////////////////////////
93 has_changed(int last_frame, double last_frac,
94  int this_frame, double this_frac) {
95  if (last_frame != this_frame) {
96  for (int i = 0; i < num_matrix_components; i++) {
97  if (_tables[i].size() > 1) {
98  if (_tables[i][last_frame % _tables[i].size()] !=
99  _tables[i][this_frame % _tables[i].size()]) {
100  return true;
101  }
102  }
103  }
104  }
105 
106  if (last_frac != this_frac) {
107  // If we have some fractional changes, also check the next
108  // subsequent frame (since we'll be blending with that).
109  for (int i = 0; i < num_matrix_components; i++) {
110  if (_tables[i].size() > 1) {
111  if (_tables[i][last_frame % _tables[i].size()] !=
112  _tables[i][(this_frame + 1) % _tables[i].size()]) {
113  return true;
114  }
115  }
116  }
117  }
118 
119  return false;
120 }
121 
122 ////////////////////////////////////////////////////////////////////
123 // Function: AnimChannelMatrixXfmTable::get_value
124 // Access: Public, Virtual
125 // Description: Gets the value of the channel at the indicated frame.
126 ////////////////////////////////////////////////////////////////////
128 get_value(int frame, LMatrix4 &mat) {
129  PN_stdfloat components[num_matrix_components];
130 
131  for (int i = 0; i < num_matrix_components; i++) {
132  if (_tables[i].empty()) {
133  components[i] = get_default_value(i);
134  } else {
135  components[i] = _tables[i][frame % _tables[i].size()];
136  }
137  }
138 
139  compose_matrix(mat, components);
140 }
141 
142 ////////////////////////////////////////////////////////////////////
143 // Function: AnimChannelMatrixXfmTable::get_value_no_scale_shear
144 // Access: Public, Virtual
145 // Description: Gets the value of the channel at the indicated frame,
146 // without any scale or shear information.
147 ////////////////////////////////////////////////////////////////////
150  PN_stdfloat components[num_matrix_components];
151  components[0] = 1.0f;
152  components[1] = 1.0f;
153  components[2] = 1.0f;
154  components[3] = 0.0f;
155  components[4] = 0.0f;
156  components[5] = 0.0f;
157 
158  for (int i = 6; i < num_matrix_components; i++) {
159  if (_tables[i].empty()) {
160  components[i] = get_default_value(i);
161  } else {
162  components[i] = _tables[i][frame % _tables[i].size()];
163  }
164  }
165 
166  compose_matrix(mat, components);
167 }
168 
169 ////////////////////////////////////////////////////////////////////
170 // Function: AnimChannelMatrixXfmTable::get_scale
171 // Access: Public, Virtual
172 // Description: Gets the scale value at the indicated frame.
173 ////////////////////////////////////////////////////////////////////
175 get_scale(int frame, LVecBase3 &scale) {
176  for (int i = 0; i < 3; i++) {
177  if (_tables[i].empty()) {
178  scale[i] = 1.0f;
179  } else {
180  scale[i] = _tables[i][frame % _tables[i].size()];
181  }
182  }
183 }
184 
185 ////////////////////////////////////////////////////////////////////
186 // Function: AnimChannelMatrixXfmTable::get_hpr
187 // Access: Public, Virtual
188 // Description: Returns the h, p, and r components associated
189 // with the current frame. As above, this only makes
190 // sense for a matrix-type channel.
191 ////////////////////////////////////////////////////////////////////
193 get_hpr(int frame, LVecBase3 &hpr) {
194  for (int i = 0; i < 3; i++) {
195  if (_tables[i + 6].empty()) {
196  hpr[i] = 0.0f;
197  } else {
198  hpr[i] = _tables[i + 6][frame % _tables[i + 6].size()];
199  }
200  }
201 }
202 
203 ////////////////////////////////////////////////////////////////////
204 // Function: AnimChannelMatrixXfmTable::get_quat
205 // Access: Public, Virtual
206 // Description: Returns the rotation component associated with the
207 // current frame, expressed as a quaternion. As above,
208 // this only makes sense for a matrix-type channel.
209 ////////////////////////////////////////////////////////////////////
211 get_quat(int frame, LQuaternion &quat) {
212  LVecBase3 hpr;
213  for (int i = 0; i < 3; i++) {
214  if (_tables[i + 6].empty()) {
215  hpr[i] = 0.0f;
216  } else {
217  hpr[i] = _tables[i + 6][frame % _tables[i + 6].size()];
218  }
219  }
220 
221  quat.set_hpr(hpr);
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: AnimChannelMatrixXfmTable::get_pos
226 // Access: Public, Virtual
227 // Description: Returns the x, y, and z translation components
228 // associated with the current frame. As above, this
229 // only makes sense for a matrix-type channel.
230 ////////////////////////////////////////////////////////////////////
232 get_pos(int frame, LVecBase3 &pos) {
233  for (int i = 0; i < 3; i++) {
234  if (_tables[i + 9].empty()) {
235  pos[i] = 0.0f;
236  } else {
237  pos[i] = _tables[i + 9][frame % _tables[i + 9].size()];
238  }
239  }
240 }
241 
242 ////////////////////////////////////////////////////////////////////
243 // Function: AnimChannelMatrixXfmTable::get_shear
244 // Access: Public, Virtual
245 // Description: Returns the a, b, and c shear components associated
246 // with the current frame. As above, this only makes
247 // sense for a matrix-type channel.
248 ////////////////////////////////////////////////////////////////////
250 get_shear(int frame, LVecBase3 &shear) {
251  for (int i = 0; i < 3; i++) {
252  if (_tables[i + 3].empty()) {
253  shear[i] = 0.0f;
254  } else {
255  shear[i] = _tables[i + 3][frame % _tables[i + 3].size()];
256  }
257  }
258 }
259 
260 ////////////////////////////////////////////////////////////////////
261 // Function: AnimChannelMatrixXfmTable::set_table
262 // Access: Public
263 // Description: Assigns the indicated table. table_id is one of 'i',
264 // 'j', 'k', for scale, 'a', 'b', 'c' for shear, 'h',
265 // 'p', 'r', for rotation, and 'x', 'y', 'z', for
266 // translation. The new table must have either zero,
267 // one, or get_num_frames() frames.
268 ////////////////////////////////////////////////////////////////////
270 set_table(char table_id, const CPTA_stdfloat &table) {
271  int num_frames = _root->get_num_frames();
272 
273  if (table.size() > 1 && (int)table.size() < num_frames) {
274  // The new table has an invalid number of frames--it doesn't match
275  // the bundle's requirement.
276  nassertv(false);
277  return;
278  }
279 
280  int i = get_table_index(table_id);
281  if (i < 0) {
282  return;
283  }
284 
285  _tables[i] = table;
286 }
287 
288 
289 ////////////////////////////////////////////////////////////////////
290 // Function: AnimChannelMatrixXfmTable::clear_all_tables
291 // Access: Published
292 // Description: Removes all the tables from the channel, and resets
293 // it to its initial state.
294 ////////////////////////////////////////////////////////////////////
297  for (int i = 0; i < num_matrix_components; i++) {
298  _tables[i] = CPTA_stdfloat(get_class_type());
299  }
300 }
301 
302 ////////////////////////////////////////////////////////////////////
303 // Function: AnimChannelMatrixXfmTable::write
304 // Access: Public, Virtual
305 // Description: Writes a brief description of the table and all of
306 // its descendants.
307 ////////////////////////////////////////////////////////////////////
309 write(ostream &out, int indent_level) const {
310  indent(out, indent_level)
311  << get_type() << " " << get_name() << " ";
312 
313  // Write a list of all the sub-tables that have data.
314  bool found_any = false;
315  for (int i = 0; i < num_matrix_components; i++) {
316  if (!_tables[i].empty()) {
317  out << get_table_id(i) << _tables[i].size();
318  found_any = true;
319  }
320  }
321 
322  if (!found_any) {
323  out << "(no data)";
324  }
325 
326  if (!_children.empty()) {
327  out << " {\n";
328  write_descendants(out, indent_level + 2);
329  indent(out, indent_level) << "}";
330  }
331 
332  out << "\n";
333 }
334 
335 ////////////////////////////////////////////////////////////////////
336 // Function: AnimChannelMatrixXfmTable::make_copy
337 // Access: Protected, Virtual
338 // Description: Returns a copy of this object, and attaches it to the
339 // indicated parent (which may be NULL only if this is
340 // an AnimBundle). Intended to be called by
341 // copy_subtree() only.
342 ////////////////////////////////////////////////////////////////////
343 AnimGroup *AnimChannelMatrixXfmTable::
344 make_copy(AnimGroup *parent) const {
345  return new AnimChannelMatrixXfmTable(parent, *this);
346 }
347 
348 ////////////////////////////////////////////////////////////////////
349 // Function: AnimChannelMatrixXfmTable::get_table_index
350 // Access: Protected, Static
351 // Description: Returns the table index number, a value between 0 and
352 // num_matrix_components, that corresponds to the
353 // indicated table id. Returns -1 if the table id is
354 // invalid.
355 ////////////////////////////////////////////////////////////////////
356 int AnimChannelMatrixXfmTable::
357 get_table_index(char table_id) {
358  for (int i = 0; i < num_matrix_components; i++) {
359  if (table_id == get_table_id(i)) {
360  return i;
361  }
362  }
363 
364  return -1;
365 }
366 
367 ////////////////////////////////////////////////////////////////////
368 // Function: AnimChannelMatrixXfmTable::write_datagram
369 // Access: Public
370 // Description: Function to write the important information in
371 // the particular object to a Datagram
372 ////////////////////////////////////////////////////////////////////
376 
377  if (compress_channels && !FFTCompressor::is_compression_available()) {
378  chan_cat.error()
379  << "Compression is not available; writing uncompressed channels.\n";
380  compress_channels = false;
381  }
382 
383  me.add_bool(compress_channels);
384  me.add_bool(temp_hpr_fix);
385 
386  if (!compress_channels) {
387  // Write out everything uncompressed, as a stream of floats.
388  for (int i = 0; i < num_matrix_components; i++) {
389  me.add_uint16(_tables[i].size());
390  for(int j = 0; j < (int)_tables[i].size(); j++) {
391  me.add_stdfloat(_tables[i][j]);
392  }
393  }
394 
395  } else {
396  // Write out everything using lossy compression.
397  FFTCompressor compressor;
398  compressor.set_quality(compress_chan_quality);
399  compressor.set_use_error_threshold(true);
400  compressor.write_header(me);
401 
402  // First, write out the scales and shears.
403  int i;
404  for (i = 0; i < 6; i++) {
405  compressor.write_reals(me, _tables[i], _tables[i].size());
406  }
407 
408  // Now, write out the joint angles. For these we need to build up
409  // a HPR array.
410  pvector<LVecBase3> hprs;
411  int hprs_length = max(max(_tables[6].size(), _tables[7].size()), _tables[8].size());
412  hprs.reserve(hprs_length);
413  for (i = 0; i < hprs_length; i++) {
414  PN_stdfloat h = _tables[6].empty() ? 0.0f : _tables[6][i % _tables[6].size()];
415  PN_stdfloat p = _tables[7].empty() ? 0.0f : _tables[7][i % _tables[7].size()];
416  PN_stdfloat r = _tables[8].empty() ? 0.0f : _tables[8][i % _tables[8].size()];
417  hprs.push_back(LVecBase3(h, p, r));
418  }
419  const LVecBase3 *hprs_array = NULL;
420  if (hprs_length != 0) {
421  hprs_array = &hprs[0];
422  }
423  compressor.write_hprs(me, hprs_array, hprs_length);
424 
425  // And now the translations.
426  for(i = 9; i < num_matrix_components; i++) {
427  compressor.write_reals(me, _tables[i], _tables[i].size());
428  }
429  }
430 }
431 
432 ////////////////////////////////////////////////////////////////////
433 // Function: AnimChannelMatrixXfmTable::fillin
434 // Access: Protected
435 // Description: Function that reads out of the datagram (or asks
436 // manager to read) all of the data that is needed to
437 // re-create this object and stores it in the appropiate
438 // place
439 ////////////////////////////////////////////////////////////////////
440 void AnimChannelMatrixXfmTable::
441 fillin(DatagramIterator &scan, BamReader *manager) {
442  AnimChannelMatrix::fillin(scan, manager);
443 
444  bool wrote_compressed = scan.get_bool();
445 
446  bool new_hpr = scan.get_bool();
447 
448  if (!wrote_compressed) {
449  // Regular floats.
450 
451  for (int i = 0; i < num_matrix_components; i++) {
452  int size = scan.get_uint16();
453  PTA_stdfloat ind_table(get_class_type());
454  for (int j = 0; j < size; j++) {
455  ind_table.push_back(scan.get_stdfloat());
456  }
457  _tables[i] = ind_table;
458  }
459 
460  if ((!new_hpr && temp_hpr_fix) || (new_hpr && !temp_hpr_fix)) {
461  // Convert between the old HPR form and the new HPR form.
462  size_t num_hprs = max(max(_tables[6].size(), _tables[7].size()),
463  _tables[8].size());
464 
465  LVecBase3 default_hpr(0.0, 0.0, 0.0);
466  if (!_tables[6].empty()) {
467  default_hpr[0] = _tables[6][0];
468  }
469  if (!_tables[7].empty()) {
470  default_hpr[1] = _tables[7][0];
471  }
472  if (!_tables[8].empty()) {
473  default_hpr[2] = _tables[8][0];
474  }
475 
476  PTA_stdfloat h_table = PTA_stdfloat::empty_array(num_hprs, get_class_type());
477  PTA_stdfloat p_table = PTA_stdfloat::empty_array(num_hprs, get_class_type());
478  PTA_stdfloat r_table = PTA_stdfloat::empty_array(num_hprs, get_class_type());
479 
480  for (size_t hi = 0; hi < num_hprs; hi++) {
481  PN_stdfloat h = (hi < _tables[6].size() ? _tables[6][hi] : default_hpr[0]);
482  PN_stdfloat p = (hi < _tables[7].size() ? _tables[7][hi] : default_hpr[1]);
483  PN_stdfloat r = (hi < _tables[8].size() ? _tables[8][hi] : default_hpr[2]);
484 
485  LVecBase3 hpr;
486  if (temp_hpr_fix) {
487  hpr = old_to_new_hpr(LVecBase3(h, p, r));
488  } else {
489  hpr = new_to_old_hpr(LVecBase3(h, p, r));
490  }
491  h_table[hi] = hpr[0];
492  p_table[hi] = hpr[1];
493  r_table[hi] = hpr[2];
494  }
495  _tables[6] = h_table;
496  _tables[7] = p_table;
497  _tables[8] = r_table;
498  }
499 
500  } else {
501  // Compressed channels.
502  if (!read_compressed_channels) {
503  chan_cat.info()
504  << "Not reading compressed animation channels.\n";
506  return;
507  }
508 
509  FFTCompressor compressor;
510  compressor.read_header(scan, manager->get_file_minor_ver());
511 
512  int i;
513  // First, read in the scales and shears.
514  for (i = 0; i < 6; i++) {
515  PTA_stdfloat ind_table = PTA_stdfloat::empty_array(0, get_class_type());
516  compressor.read_reals(scan, ind_table.v());
517  _tables[i] = ind_table;
518  }
519 
520  // Read in the HPR array and store it back in the joint angles.
521  pvector<LVecBase3> hprs;
522  compressor.read_hprs(scan, hprs, new_hpr);
523  PTA_stdfloat h_table = PTA_stdfloat::empty_array(hprs.size(), get_class_type());
524  PTA_stdfloat p_table = PTA_stdfloat::empty_array(hprs.size(), get_class_type());
525  PTA_stdfloat r_table = PTA_stdfloat::empty_array(hprs.size(), get_class_type());
526 
527  for (i = 0; i < (int)hprs.size(); i++) {
528  if (!new_hpr && temp_hpr_fix) {
529  // Convert the old HPR form to the new HPR form.
530  LVecBase3 hpr = old_to_new_hpr(hprs[i]);
531  h_table[i] = hpr[0];
532  p_table[i] = hpr[1];
533  r_table[i] = hpr[2];
534 
535  } else if (new_hpr && !temp_hpr_fix) {
536  // Convert the new HPR form to the old HPR form.
537  LVecBase3 hpr = new_to_old_hpr(hprs[i]);
538  h_table[i] = hpr[0];
539  p_table[i] = hpr[1];
540  r_table[i] = hpr[2];
541 
542  } else {
543  // Store the HPR angle directly.
544  h_table[i] = hprs[i][0];
545  p_table[i] = hprs[i][1];
546  r_table[i] = hprs[i][2];
547  }
548  }
549  _tables[6] = h_table;
550  _tables[7] = p_table;
551  _tables[8] = r_table;
552 
553  // Now read in the translations.
554  for (i = 9; i < num_matrix_components; i++) {
555  PTA_stdfloat ind_table = PTA_stdfloat::empty_array(0, get_class_type());
556  compressor.read_reals(scan, ind_table.v());
557  _tables[i] = ind_table;
558  }
559  }
560 }
561 
562 ////////////////////////////////////////////////////////////////////
563 // Function: AnimChannelMatrixXfmTable::make_AnimChannelMatrixXfmTable
564 // Access: Protected
565 // Description: Factory method to generate an
566 // AnimChannelMatrixXfmTable object.
567 ////////////////////////////////////////////////////////////////////
571  DatagramIterator scan;
572  BamReader *manager;
573 
574  parse_params(params, scan, manager);
575  me->fillin(scan, manager);
576  return me;
577 }
578 
579 ////////////////////////////////////////////////////////////////////
580 // Function: AnimChannelMatrixXfmTable::register_with_factory
581 // Access: Public, Static
582 // Description: Factory method to generate an
583 // AnimChannelMatrixXfmTable object.
584 ////////////////////////////////////////////////////////////////////
588 }
589 
590 
virtual void get_hpr(int frame, LVecBase3 &hpr)
Returns the h, p, and r components associated with the current frame.
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
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...
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_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:37
virtual void get_scale(int frame, LVecBase3 &scale)
Gets the scale value at the indicated frame.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
This class manages a lossy compression and decompression of a stream of floating-point numbers to a d...
Definition: fftCompressor.h:45
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:105
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
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:240
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
This is the base class for AnimChannel and AnimBundle.
Definition: animGroup.h:36
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
static TypedWritable * make_AnimChannelMatrixXfmTable(const FactoryParams &params)
Factory method to generate an AnimChannelMatrixXfmTable object.
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:40
void set_table(char table_id, const CPTA_stdfloat &table)
Assigns the indicated table.
void set_hpr(const LVecBase3f &hpr, CoordinateSystem cs=CS_default)
Sets the quaternion as the unit quaternion that is equivalent to these Euler angles.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
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:213
This is the base quaternion class.
Definition: lquaternion.h:96
virtual void write(ostream &out, int indent_level) const
Writes a brief description of the table and all of its descendants.
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:85
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:43
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.