Panda3D
animChannelScalarTable.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 animChannelScalarTable.cxx
10 * @author drose
11 * @date 1999-02-22
12 */
13
15#include "animBundle.h"
16#include "config_chan.h"
17
18#include "indent.h"
19#include "datagram.h"
20#include "datagramIterator.h"
21#include "bamReader.h"
22#include "bamWriter.h"
23#include "fftCompressor.h"
24
25TypeHandle AnimChannelScalarTable::_type_handle;
26
27/**
28 *
29 */
30AnimChannelScalarTable::
31AnimChannelScalarTable() : _table(get_class_type()) {
32}
33
34/**
35 * Creates a new AnimChannelScalarTable, just like this one, without copying
36 * any children. The new copy is added to the indicated parent. Intended to
37 * be called by make_copy() only.
38 */
39AnimChannelScalarTable::
40AnimChannelScalarTable(AnimGroup *parent, const AnimChannelScalarTable &copy) :
41 AnimChannelScalar(parent, copy),
42 _table(copy._table)
43{
44}
45
46/**
47 *
48 */
49AnimChannelScalarTable::
50AnimChannelScalarTable(AnimGroup *parent, const std::string &name) :
51 AnimChannelScalar(parent, name),
52 _table(get_class_type())
53{
54}
55
56/**
57 * Returns true if the value has changed since the last call to has_changed().
58 * last_frame is the frame number of the last call; this_frame is the current
59 * frame number.
60 */
62has_changed(int last_frame, double last_frac,
63 int this_frame, double this_frac) {
64 if (_table.size() > 1) {
65 if (last_frame != this_frame) {
66 if (_table[last_frame % _table.size()] !=
67 _table[this_frame % _table.size()]) {
68 return true;
69 }
70 }
71 if (last_frac != this_frac) {
72 // If we have some fractional changes, also check the next subsequent
73 // frame (since we'll be blending with that).
74 if (_table[last_frame % _table.size()] !=
75 _table[(this_frame + 1) % _table.size()]) {
76 return true;
77 }
78 }
79 }
80
81 return false;
82}
83
84/**
85 * Gets the value of the channel at the indicated frame.
86 */
88get_value(int frame, PN_stdfloat &value) {
89 if (_table.empty()) {
90 value = 0.0f;
91 } else {
92 value = _table[frame % _table.size()];
93 }
94}
95
96
97/**
98 * Assigns the data table.
99 */
101set_table(const CPTA_stdfloat &table) {
102 int num_frames = _root->get_num_frames();
103
104 if (table.size() > 1 && (int)table.size() < num_frames) {
105 // The new table has an invalid number of frames--it doesn't match the
106 // bundle's requirement.
107 nassert_raise("mismatched number of frames");
108 return;
109 }
110
111 _table = table;
112}
113
114/**
115 * Writes a brief description of the table and all of its descendants.
116 */
118write(std::ostream &out, int indent_level) const {
119 indent(out, indent_level)
120 << get_type() << " " << get_name() << " " << _table.size();
121
122 if (!_children.empty()) {
123 out << " {\n";
124 write_descendants(out, indent_level + 2);
125 indent(out, indent_level) << "}";
126 }
127
128 out << "\n";
129}
130
131/**
132 * Returns a copy of this object, and attaches it to the indicated parent
133 * (which may be NULL only if this is an AnimBundle). Intended to be called
134 * by copy_subtree() only.
135 */
136AnimGroup *AnimChannelScalarTable::
137make_copy(AnimGroup *parent) const {
138 return new AnimChannelScalarTable(parent, *this);
139}
140
141/**
142 * Function to write the important information in the particular object to a
143 * Datagram
144 */
146write_datagram(BamWriter *manager, Datagram &me) {
148
149 if (compress_channels) {
150 chan_cat.warning()
151 << "FFT compression of animations is deprecated. For compatibility "
152 "with future versions of Panda3D, set compress-channels to false.\n";
153
155 chan_cat.error()
156 << "Compression is not available; writing uncompressed channels.\n";
157 compress_channels = false;
158 }
159 }
160
161 me.add_bool(compress_channels);
162 if (!compress_channels) {
163 // Write out everything the old way, as floats.
164 me.add_uint16(_table.size());
165 for(int i = 0; i < (int)_table.size(); i++) {
166 me.add_stdfloat(_table[i]);
167 }
168
169 } else {
170 // Some channels, particularly blink channels, may involve only a small
171 // number of discrete values. If we come across one of those, write it
172 // out losslessly, since the lossy compression could damage it
173 // significantly (and we can achieve better compression directly anyway).
174 // We consider the channel value only to the nearest 1000th for this
175 // purpose, because floats aren't very good at being precisely equal to
176 // each other.
177 static const int max_values = 16;
178 static const PN_stdfloat scale = 1000.0f;
179
180 pmap<int, int> index;
181 int i;
182 for (i = 0;
183 i < (int)_table.size() && (int)index.size() <= max_values;
184 i++) {
185 int value = (int)cfloor(_table[i] * scale + 0.5f);
186 index.insert(pmap<int, int>::value_type(value, index.size()));
187 }
188 int index_length = index.size();
189 if (index_length <= max_values) {
190 // All right, here's a blink channel. Now we write out the index table,
191 // and then a table of all the index values, two per byte.
192 me.add_uint8(index_length);
193
194 if (index_length > 0) {
195 // We need to write the index in order by its index number; for this,
196 // we need to invert the index.
197 vector_stdfloat reverse_index(index_length);
199 for (mi = index.begin(); mi != index.end(); ++mi) {
200 PN_stdfloat f = (PN_stdfloat)(*mi).first / scale;
201 int i = (*mi).second;
202 nassertv(i >= 0 && i < (int)reverse_index.size());
203 reverse_index[i] = f;
204 }
205
206 for (i = 0; i < index_length; i++) {
207 me.add_stdfloat(reverse_index[i]);
208 }
209
210 // Now write out the actual channels. We write these two at a time,
211 // in the high and low nibbles of each byte.
212 int table_length = _table.size();
213 me.add_uint16(table_length);
214
215 if (index_length == 1) {
216 // In fact, we don't even need to write the channels at all, if
217 // there weren't at least two different values.
218
219 } else {
220 for (i = 0; i < table_length - 1; i+= 2) {
221 int value1 = (int)cfloor(_table[i] * scale + 0.5f);
222 int value2 = (int)cfloor(_table[i + 1] * scale + 0.5f);
223 int i1 = index[value1];
224 int i2 = index[value2];
225
226 me.add_uint8((i1 << 4) | i2);
227 }
228
229 // There might be one odd value.
230 if (i < table_length) {
231 int value1 = (int)cfloor(_table[i] * scale + 0.5f);
232 int i1 = index[value1];
233
234 me.add_uint8(i1 << 4);
235 }
236 }
237 }
238
239 } else {
240 // No, we have continuous channels. Write them out using lossy
241 // compression.
242 me.add_uint8(0xff);
243
244 FFTCompressor compressor;
245 compressor.set_quality(compress_chan_quality);
246 compressor.set_use_error_threshold(true);
247 compressor.write_header(me);
248
249 compressor.write_reals(me, _table, _table.size());
250 }
251 }
252}
253
254/**
255 * Function that reads out of the datagram (or asks manager to read) all of
256 * the data that is needed to re-create this object and stores it in the
257 * appropiate place
258 */
259void AnimChannelScalarTable::
260fillin(DatagramIterator& scan, BamReader* manager) {
261 AnimChannelScalar::fillin(scan, manager);
262
263 bool wrote_compressed = scan.get_bool();
264
265 PTA_stdfloat temp_table = PTA_stdfloat::empty_array(0, get_class_type());
266
267 if (!wrote_compressed) {
268 // Regular floats.
269 int size = scan.get_uint16();
270 for(int i = 0; i < size; i++) {
271 temp_table.push_back(scan.get_stdfloat());
272 }
273
274 } else {
275 // Compressed channels. Did we write them as discrete or continuous
276 // channel values?
277 int index_length = scan.get_uint8();
278
279 if (index_length < 0xff) {
280 // Discrete. Read in the index.
281 if (index_length > 0) {
282 PN_stdfloat *index = (PN_stdfloat *)alloca(index_length * sizeof(PN_stdfloat));
283
284 int i;
285 for (i = 0; i < index_length; i++) {
286 index[i] = scan.get_stdfloat();
287 }
288
289 // Now read in the channel values.
290 int table_length = scan.get_uint16();
291 if (index_length == 1) {
292 // With only one index value, we can infer the table.
293 for (i = 0; i < table_length; i++) {
294 temp_table.push_back(index[0]);
295 }
296 } else {
297 // Otherwise, we must read it.
298 for (i = 0; i < table_length - 1; i+= 2) {
299 int num = scan.get_uint8();
300 int i1 = (num >> 4) & 0xf;
301 int i2 = num & 0xf;
302 temp_table.push_back(index[i1]);
303 temp_table.push_back(index[i2]);
304 }
305 // There might be one odd value.
306 if (i < table_length) {
307 int num = scan.get_uint8();
308 int i1 = (num >> 4) & 0xf;
309 temp_table.push_back(index[i1]);
310 }
311 }
312 }
313 } else {
314 // Continuous channels.
315 FFTCompressor compressor;
316 compressor.read_header(scan, manager->get_file_minor_ver());
317 compressor.read_reals(scan, temp_table.v());
318 }
319 }
320
321 _table = temp_table;
322}
323
324/**
325 * Factory method to generate a AnimChannelScalarTable object
326 */
330 DatagramIterator scan;
331 BamReader *manager;
332
333 parse_params(params, scan, manager);
334 me->fillin(scan, manager);
335 return me;
336}
337
338/**
339 * Factory method to generate a AnimChannelScalarTable object
340 */
344}
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 scalar each frame, read from a table such as might have been read ...
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 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, PN_stdfloat &value)
Gets the value of the channel at the indicated frame.
set_table
Assigns the data table.
static void register_with_read_factory()
Factory method to generate a AnimChannelScalarTable object.
static TypedWritable * make_AnimChannelScalarTable(const FactoryParams &params)
Factory method to generate a AnimChannelScalarTable object.
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the table and all of its descendants.
This template class is the parent class for all kinds of AnimChannels that return different values.
Definition: animChannel.h:28
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.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
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_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
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...
Definition: fftCompressor.h:40
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...
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.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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.
Definition: typedWritable.h:35
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: dcindent.cxx:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.