Panda3D
fltBead.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 fltBead.cxx
10  * @author drose
11  * @date 2000-08-24
12  */
13 
14 #include "fltBead.h"
15 #include "fltRecordReader.h"
16 #include "fltRecordWriter.h"
18 #include "fltTransformPut.h"
21 #include "fltTransformScale.h"
22 #include "fltTransformTranslate.h"
24 #include "config_flt.h"
25 
26 #include "dcast.h"
27 
28 #include <assert.h>
29 
30 TypeHandle FltBead::_type_handle;
31 
32 /**
33  *
34  */
35 FltBead::
36 FltBead(FltHeader *header) : FltRecord(header) {
37  _has_transform = false;
38  _transform = LMatrix4d::ident_mat();
39  _replicate_count = 0;
40 }
41 
42 /**
43  * Returns true if the bead has been transformed, false otherwise. If this
44  * returns true, get_transform() will return the single-precision net
45  * transformation, and get_num_transform_steps() will return nonzero.
46  */
48 has_transform() const {
49  return _has_transform;
50 }
51 
52 /**
53  * Returns the single-precision 4x4 matrix that represents the transform
54  * applied to this bead, or the identity matrix if the bead has not been
55  * transformed.
56  */
57 const LMatrix4d &FltBead::
58 get_transform() const {
59  return _has_transform ? _transform : LMatrix4d::ident_mat();
60 }
61 
62 /**
63  * Replaces the transform matrix on this bead. This implicitly removes all of
64  * the transform steps added previously, and replaces them with a single 4x4
65  * general matrix transform step.
66  */
68 set_transform(const LMatrix4d &mat) {
71  step->set_matrix(mat);
72  add_transform_step(step);
73 }
74 
75 /**
76  * Removes any transform matrix and all transform steps on this bead.
77  */
80  _has_transform = false;
81  _transform = LMatrix4d::ident_mat();
82  _transform_steps.clear();
83 }
84 
85 /**
86  * Returns the number of individual steps that define the net transform on
87  * this bead as returned by set_transform(). Each step is a single
88  * transformation; the concatenation of all transformations will produce the
89  * matrix represented by set_transform().
90  */
93  return _transform_steps.size();
94 }
95 
96 /**
97  * Returns the nth individual step that defines the net transform on this
98  * bead. See get_num_transform_steps().
99  */
101 get_transform_step(int n) {
102  nassertr(n >= 0 && n < (int)_transform_steps.size(),
103  nullptr);
104  return _transform_steps[n];
105 }
106 
107 /**
108  * Returns the nth individual step that defines the net transform on this
109  * bead. See get_num_transform_steps().
110  */
112 get_transform_step(int n) const {
113  nassertr(n >= 0 && n < (int)_transform_steps.size(),
114  nullptr);
115  return _transform_steps[n];
116 }
117 
118 /**
119  * Applies the indicated transform step to the net transformation applied to
120  * the bead.
121  */
124  if (!_has_transform) {
125  _has_transform = true;
126  _transform = record->get_matrix();
127  } else {
128  _transform = record->get_matrix() * _transform;
129  }
130  _transform_steps.push_back(record);
131 }
132 
133 /**
134  * Returns the replicate count of this bead. If this is nonzero, it means
135  * that the bead is implicitly copied this number of additional times (for
136  * replicate_count + 1 total copies), applying the transform on this bead for
137  * each copy. In this case, the transform does *not* apply to the initial
138  * copy of the bead.
139  */
141 get_replicate_count() const {
142  return _replicate_count;
143 }
144 
145 /**
146  * Changes the replicate count of this bead. If you are setting the replicate
147  * count to some nonzero number, you must also set a transform on the bead.
148  * See set_replicate_count().
149  */
151 set_replicate_count(int count) {
152  _replicate_count = count;
153 }
154 
155 /**
156  * Fills in the information in this bead based on the information given in the
157  * indicated datagram, whose opcode has already been read. Returns true on
158  * success, false if the datagram is invalid.
159  */
160 bool FltBead::
161 extract_record(FltRecordReader &reader) {
162  if (!FltRecord::extract_record(reader)) {
163  return false;
164  }
165  return true;
166 }
167 
168 /**
169  * Checks whether the given bead, which follows this bead sequentially in the
170  * file, is an ancillary record of this bead. If it is, extracts the relevant
171  * information and returns true; otherwise, leaves it alone and returns false.
172  */
173 bool FltBead::
174 extract_ancillary(FltRecordReader &reader) {
175  FltTransformRecord *step = nullptr;
176 
177  switch (reader.get_opcode()) {
178  case FO_transform_matrix:
179  return extract_transform_matrix(reader);
180 
181  case FO_general_matrix:
182  step = new FltTransformGeneralMatrix(_header);
183  break;
184 
185  case FO_put:
186  step = new FltTransformPut(_header);
187  break;
188 
189  case FO_rotate_about_edge:
190  step = new FltTransformRotateAboutEdge(_header);
191  break;
192 
193  case FO_rotate_about_point:
194  step = new FltTransformRotateAboutPoint(_header);
195  break;
196 
197  case FO_scale:
198  step = new FltTransformScale(_header);
199  break;
200 
201  case FO_translate:
202  step = new FltTransformTranslate(_header);
203  break;
204 
205  case FO_rotate_and_scale:
206  step = new FltTransformRotateScale(_header);
207  break;
208 
209  case FO_replicate:
210  return extract_replicate_count(reader);
211 
212  default:
213  return FltRecord::extract_ancillary(reader);
214  }
215 
216  // A transform step.
217  nassertr(step != nullptr, false);
218  if (!step->extract_record(reader)) {
219  return false;
220  }
221  _transform_steps.push_back(DCAST(FltTransformRecord, step));
222 
223  return true;
224 }
225 
226 /**
227  * Fills up the current record on the FltRecordWriter with data for this
228  * record, but does not advance the writer. Returns true on success, false if
229  * there is some error.
230  */
231 bool FltBead::
232 build_record(FltRecordWriter &writer) const {
233  if (!FltRecord::build_record(writer)) {
234  return false;
235  }
236  return true;
237 }
238 
239 /**
240  * Writes whatever ancillary records are required for this record. Returns
241  * FE_ok on success, or something else if there is some error.
242  */
243 FltError FltBead::
244 write_ancillary(FltRecordWriter &writer) const {
245  if (_has_transform) {
246  FltError result = write_transform(writer);
247  if (result != FE_ok) {
248  return result;
249  }
250  }
251  if (_replicate_count != 0) {
252  FltError result = write_replicate_count(writer);
253  if (result != FE_ok) {
254  return result;
255  }
256  }
257 
258 
259  return FltRecord::write_ancillary(writer);
260 }
261 
262 /**
263  * Reads a transform matrix ancillary bead. This defines the net
264  * transformation that has been applied to the bead, and precedes the set of
265  * individual transform steps that define how this net transform was computed.
266  */
267 bool FltBead::
268 extract_transform_matrix(FltRecordReader &reader) {
269  nassertr(reader.get_opcode() == FO_transform_matrix, false);
270  DatagramIterator &iterator = reader.get_iterator();
271 
272  LMatrix4d matrix;
273  for (int r = 0; r < 4; r++) {
274  for (int c = 0; c < 4; c++) {
275  matrix(r, c) = iterator.get_be_float32();
276  }
277  }
278  check_remaining_size(iterator);
279 
280  _transform_steps.clear();
281  _has_transform = true;
282  _transform = matrix;
283 
284  return true;
285 }
286 
287 /**
288  * Reads a replicate count ancillary bead.
289  */
290 bool FltBead::
291 extract_replicate_count(FltRecordReader &reader) {
292  nassertr(reader.get_opcode() == FO_replicate, false);
293  DatagramIterator &iterator = reader.get_iterator();
294 
295  _replicate_count = iterator.get_be_int16();
296  iterator.skip_bytes(2);
297 
298  check_remaining_size(iterator);
299  return true;
300 }
301 
302 /**
303  * Writes out the transformation and all of its defining steps.
304  */
305 FltError FltBead::
306 write_transform(FltRecordWriter &writer) const {
307  // First, write out the initial transform indication.
308  writer.set_opcode(FO_transform_matrix);
309  Datagram &datagram = writer.update_datagram();
310 
311  for (int r = 0; r < 4; r++) {
312  for (int c = 0; c < 4; c++) {
313  datagram.add_be_float32(_transform(r, c));
314  }
315  }
316 
317  FltError result = writer.advance();
318  if (result != FE_ok) {
319  return result;
320  }
321 
322  // Now, write out each of the steps of the transform.
323  Transforms::const_iterator ti;
324  for (ti = _transform_steps.begin(); ti != _transform_steps.end(); ++ti) {
325  if (!(*ti)->build_record(writer)) {
326  assert(!flt_error_abort);
327  return FE_invalid_record;
328  }
329  FltError result = writer.advance();
330  if (result != FE_ok) {
331  return result;
332  }
333  }
334 
335  return FE_ok;
336 }
337 
338 /**
339  * Writes out the replicate count, if needed.
340  */
341 FltError FltBead::
342 write_replicate_count(FltRecordWriter &writer) const {
343  if (_replicate_count != 0) {
344  writer.set_opcode(FO_replicate);
345  Datagram &datagram = writer.update_datagram();
346 
347  datagram.add_be_int16(_replicate_count);
348  datagram.pad_bytes(2);
349 
350  FltError result = writer.advance();
351  if (result != FE_ok) {
352  return result;
353  }
354  }
355 
356  return FE_ok;
357 }
A class to retrieve the individual data elements previously stored in a Datagram.
void skip_bytes(size_t size)
Skips over the indicated number of bytes in the datagram.
PN_float32 get_be_float32()
Extracts a 32-bit big-endian single-precision floating-point number.
int16_t get_be_int16()
Extracts a signed 16-bit big-endian integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_be_float32(PN_float32 value)
Adds a 32-bit single-precision big-endian floating-point number to the datagram.
Definition: datagram.I:200
void add_be_int16(int16_t value)
Adds a signed 16-bit big-endian integer to the datagram.
Definition: datagram.I:145
void pad_bytes(size_t size)
Adds the indicated number of zero bytes to the datagram.
Definition: datagram.cxx:99
int get_num_transform_steps() const
Returns the number of individual steps that define the net transform on this bead as returned by set_...
Definition: fltBead.cxx:92
void clear_transform()
Removes any transform matrix and all transform steps on this bead.
Definition: fltBead.cxx:79
int get_replicate_count() const
Returns the replicate count of this bead.
Definition: fltBead.cxx:141
void add_transform_step(FltTransformRecord *record)
Applies the indicated transform step to the net transformation applied to the bead.
Definition: fltBead.cxx:123
FltTransformRecord * get_transform_step(int n)
Returns the nth individual step that defines the net transform on this bead.
Definition: fltBead.cxx:101
const LMatrix4d & get_transform() const
Returns the single-precision 4x4 matrix that represents the transform applied to this bead,...
Definition: fltBead.cxx:58
void set_transform(const LMatrix4d &mat)
Replaces the transform matrix on this bead.
Definition: fltBead.cxx:68
void set_replicate_count(int count)
Changes the replicate count of this bead.
Definition: fltBead.cxx:151
bool has_transform() const
Returns true if the bead has been transformed, false otherwise.
Definition: fltBead.cxx:48
This is the first bead in the file, the top of the bead hierarchy, and the primary interface to readi...
Definition: fltHeader.h:44
This class turns an istream into a sequence of FltRecords by reading a sequence of Datagrams and extr...
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
DatagramIterator & get_iterator()
Returns an iterator suitable for extracting data from the current record.
This class writes a sequence of FltRecords to an ostream, handling opcode and size counts properly.
void set_opcode(FltOpcode opcode)
Sets the opcode associated with the current record.
FltError advance()
Writes the current record to the flt file, and resets the current record to receive new data.
Datagram & update_datagram()
Returns a modifiable reference to the datagram associated with the current record.
The base class for all kinds of records in a MultiGen OpenFlight file.
Definition: fltRecord.h:36
void check_remaining_size(const DatagramIterator &di, const std::string &name=std::string()) const
Checks that the iterator has no bytes left, as it should at the end of a successfully read record.
Definition: fltRecord.cxx:254
void set_matrix(const LMatrix4d &matrix)
Directly sets the general matrix.
A "put", which is a MultiGen concept of defining a transformation by mapping three arbitrary points t...
A base class for a number of types of ancillary records that follow beads and indicate some kind of a...
A transformation that rotates about a particular axis in space, defined by two endpoints.
A transformation that rotates about a particular axis in space, defined by a point and vector.
A combination rotation and scale.
A transformation that applies a (possibly nonuniform) scale.
A transformation that applies a translation.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
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.
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.