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
14 #include "animChannelScalarTable.h"
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
25 TypeHandle AnimChannelScalarTable::_type_handle;
26
27 /**
28 *
29 */
30 AnimChannelScalarTable::
31 AnimChannelScalarTable() : _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 */
39 AnimChannelScalarTable::
40 AnimChannelScalarTable(AnimGroup *parent, const AnimChannelScalarTable &copy) :
41 AnimChannelScalar(parent, copy),
42 _table(copy._table)
43 {
44 }
45
46 /**
47 *
48 */
49 AnimChannelScalarTable::
50 AnimChannelScalarTable(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 */
61 bool AnimChannelScalarTable::
62 has_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 */
87 void AnimChannelScalarTable::
88 get_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 */
100 void AnimChannelScalarTable::
101 set_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 */
117 void AnimChannelScalarTable::
118 write(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 */
136 AnimGroup *AnimChannelScalarTable::
137 make_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 */
145 void AnimChannelScalarTable::
146 write_datagram(BamWriter *manager, Datagram &me) {
147 AnimChannelScalar::write_datagram(manager, 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
154 if (!FFTCompressor::is_compression_available()) {
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);
198 pmap<int, int>::iterator mi;
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 */
259 void AnimChannelScalarTable::
260 fillin(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 */
327 TypedWritable* AnimChannelScalarTable::
328 make_AnimChannelScalarTable(const FactoryParams &params) {
329 AnimChannelScalarTable *me = new AnimChannelScalarTable;
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 */
341 void AnimChannelScalarTable::
342 register_with_read_factory() {
343 BamReader::get_factory()->register_factory(get_class_type(), make_AnimChannelScalarTable);
344 }
animBundle.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
animChannelScalarTable.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AnimChannelBase::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
Definition: animChannelBase.cxx:39
AnimChannelScalarTable
An animation channel that issues a scalar each frame, read from a table such as might have been read ...
Definition: animChannelScalarTable.h:28
AnimChannelScalarTable::has_changed
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().
Definition: animChannelScalarTable.cxx:62
AnimChannelScalarTable::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
Definition: animChannelScalarTable.cxx:146
AnimChannelScalarTable::get_value
virtual void get_value(int frame, PN_stdfloat &value)
Gets the value of the channel at the indicated frame.
Definition: animChannelScalarTable.cxx:88
AnimChannelScalarTable::set_table
set_table
Assigns the data table.
Definition: animChannelScalarTable.h:48
AnimChannelScalarTable::register_with_read_factory
static void register_with_read_factory()
Factory method to generate a AnimChannelScalarTable object.
Definition: animChannelScalarTable.cxx:342
AnimChannelScalarTable::make_AnimChannelScalarTable
static TypedWritable * make_AnimChannelScalarTable(const FactoryParams &params)
Factory method to generate a AnimChannelScalarTable object.
Definition: animChannelScalarTable.cxx:328
AnimChannelScalarTable::write
virtual void write(std::ostream &out, int indent_level) const
Writes a brief description of the table and all of its descendants.
Definition: animChannelScalarTable.cxx:118
AnimChannel
This template class is the parent class for all kinds of AnimChannels that return different values.
Definition: animChannel.h:28
AnimGroup
This is the base class for AnimChannel and AnimBundle.
Definition: animGroup.h:33
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
ConstPointerToArray
Similar to PointerToArray, except that its contents may not be modified.
Definition: pointerToArray.h:252
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
DatagramIterator::get_stdfloat
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
Definition: datagramIterator.I:242
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
DatagramIterator::get_bool
bool get_bool()
Extracts a boolean value.
Definition: datagramIterator.I:48
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
Datagram::add_stdfloat
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
Datagram::add_bool
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
FFTCompressor
This class manages a lossy compression and decompression of a stream of floating-point numbers to a d...
Definition: fftCompressor.h:40
FFTCompressor::read_reals
bool read_reals(DatagramIterator &di, vector_stdfloat &array)
Reads an array of floating-point numbers.
Definition: fftCompressor.cxx:576
FFTCompressor::set_use_error_threshold
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...
Definition: fftCompressor.cxx:152
FFTCompressor::set_quality
void set_quality(int quality)
Sets the quality factor for the compression.
Definition: fftCompressor.cxx:89
FFTCompressor::read_header
bool read_header(DatagramIterator &di, int bam_minor_version)
Reads the compression header that was written previously.
Definition: fftCompressor.cxx:541
FFTCompressor::is_compression_available
static bool is_compression_available()
Returns true if the FFTW library is compiled in, so that this class is actually capable of doing usef...
Definition: fftCompressor.cxx:64
FFTCompressor::write_header
void write_header(Datagram &datagram)
Writes the compression parameters to the indicated datagram.
Definition: fftCompressor.cxx:189
FFTCompressor::write_reals
void write_reals(Datagram &datagram, const PN_stdfloat *array, int length)
Writes an array of floating-point numbers to the indicated datagram.
Definition: fftCompressor.cxx:202
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
pmap< int, int >
config_chan.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
fftCompressor.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.