Panda3D
Loading...
Searching...
No Matches
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
27TypeHandle AnimChannelMatrixXfmTable::_type_handle;
28
29/**
30 * Used only for bam loader.
31 */
32AnimChannelMatrixXfmTable::
33AnimChannelMatrixXfmTable() {
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 */
44AnimChannelMatrixXfmTable::
45AnimChannelMatrixXfmTable(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 */
56AnimChannelMatrixXfmTable::
57AnimChannelMatrixXfmTable(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 */
68AnimChannelMatrixXfmTable::
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 */
79has_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 */
112get_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 */
131get_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 */
155get_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 */
170get_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 */
186get_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 */
204get_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 */
219get_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 */
236set_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 */
270write(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 */
301AnimGroup *AnimChannelMatrixXfmTable::
302make_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 */
311int AnimChannelMatrixXfmTable::
312get_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 */
327write_datagram(BamWriter *manager, Datagram &me) {
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.
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 */
398void AnimChannelMatrixXfmTable::
399fillin(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.
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 */
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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.
An animation channel that issues a matrix each frame, read from a table such as might have been read ...
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.
set_table
Assigns the indicated table.
static void register_with_read_factory()
Factory method to generate an AnimChannelMatrixXfmTable object.
virtual void get_quat(int frame, LQuaternion &quat)
Returns the rotation component associated with the current frame, expressed as a quaternion.
void clear_all_tables()
Removes all the tables from the channel, and resets it to its initial state.
static TypedWritable * make_AnimChannelMatrixXfmTable(const FactoryParams &params)
Factory method to generate an AnimChannelMatrixXfmTable object.
virtual void get_scale(int frame, LVecBase3 &scale)
Gets the scale value at the indicated frame.
virtual void get_hpr(int frame, LVecBase3 &hpr)
Returns the h, p, and r components associated with the current frame.
virtual void get_pos(int frame, LVecBase3 &pos)
Returns the x, y, and z translation components associated with the current frame.
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().
virtual void get_value(int frame, LMatrix4 &mat)
Gets the value of the channel at the indicated frame.
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the table and all of its descendants.
virtual void get_shear(int frame, LVecBase3 &shear)
Returns the a, b, and c shear components associated with the current frame.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
This is the base class for AnimChannel and AnimBundle.
Definition animGroup.h:33
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition bamReader.I:83
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
Similar to PointerToArray, except that its contents may not be modified.
A class to retrieve the individual data elements previously stored in a Datagram.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
bool get_bool()
Extracts a boolean value.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
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
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition datagram.I:34
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition datagram.I:85
This class manages a lossy compression and decompression of a stream of floating-point numbers to a d...
bool read_reals(DatagramIterator &di, vector_stdfloat &array)
Reads an array of floating-point numbers.
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...
bool read_hprs(DatagramIterator &di, pvector< LVecBase3 > &array, bool new_hpr)
Reads an array of HPR angles.
void set_quality(int quality)
Sets the quality factor for the compression.
bool read_header(DatagramIterator &di, int bam_minor_version)
Reads the compression header that was written previously.
static bool is_compression_available()
Returns true if the FFTW library is compiled in, so that this class is actually capable of doing usef...
void write_header(Datagram &datagram)
Writes the compression parameters to the indicated datagram.
void write_reals(Datagram &datagram, const PN_stdfloat *array, int length)
Writes an array of floating-point numbers to the indicated datagram.
void write_hprs(Datagram &datagram, const LVecBase3 *array, int length)
Writes an array of HPR angles to the indicated datagram.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
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
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.