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