Panda3D
fltRecord.cxx
1 // Filename: fltRecord.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 "fltRecord.h"
16 #include "fltRecordReader.h"
17 #include "fltRecordWriter.h"
18 #include "fltHeader.h"
19 #include "fltGroup.h"
20 #include "fltObject.h"
21 #include "fltFace.h"
22 #include "fltCurve.h"
23 #include "fltMesh.h"
24 #include "fltLocalVertexPool.h"
25 #include "fltMeshPrimitive.h"
26 #include "fltVertexList.h"
27 #include "fltLOD.h"
28 #include "fltInstanceDefinition.h"
29 #include "fltInstanceRef.h"
30 #include "fltUnsupportedRecord.h"
31 #include "fltExternalReference.h"
32 #include "fltVectorRecord.h"
33 #include "config_flt.h"
34 
35 #include "dcast.h"
36 #include "indent.h"
37 #include "datagramIterator.h"
38 
39 #include <assert.h>
40 
41 TypeHandle FltRecord::_type_handle;
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: FltRecord::Constructor
45 // Access: Public
46 // Description:
47 ////////////////////////////////////////////////////////////////////
48 FltRecord::
49 FltRecord(FltHeader *header) :
50  _header(header)
51 {
52 }
53 
54 ////////////////////////////////////////////////////////////////////
55 // Function: FltRecord::Destructor
56 // Access: Public, Virtual
57 // Description:
58 ////////////////////////////////////////////////////////////////////
59 FltRecord::
60 ~FltRecord() {
61 }
62 
63 ////////////////////////////////////////////////////////////////////
64 // Function: FltRecord::get_num_children
65 // Access: Public
66 // Description: Returns the number of child records of this record.
67 // This reflects the normal scene graph hierarchy.
68 ////////////////////////////////////////////////////////////////////
69 int FltRecord::
71  return _children.size();
72 }
73 
74 ////////////////////////////////////////////////////////////////////
75 // Function: FltRecord::get_child
76 // Access: Public
77 // Description: Returns the nth child of this record.
78 ////////////////////////////////////////////////////////////////////
80 get_child(int n) const {
81  nassertr(n >= 0 && n < (int)_children.size(), (FltRecord *)NULL);
82  return _children[n];
83 }
84 
85 ////////////////////////////////////////////////////////////////////
86 // Function: FltRecord::clear_children
87 // Access: Public
88 // Description: Removes all children from this record.
89 ////////////////////////////////////////////////////////////////////
90 void FltRecord::
92  _children.clear();
93 }
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: FltRecord::add_child
97 // Access: Public
98 // Description: Adds a new child to the end of the list of children
99 // for this record.
100 ////////////////////////////////////////////////////////////////////
101 void FltRecord::
103  _children.push_back(child);
104 }
105 
106 ////////////////////////////////////////////////////////////////////
107 // Function: FltRecord::get_num_subfaces
108 // Access: Public
109 // Description: Returns the number of subface records of this record.
110 // Normally, subfaces will only be present on object
111 // records, although it is logically possible for them to
112 // appear anywhere.
113 ////////////////////////////////////////////////////////////////////
114 int FltRecord::
116  return _subfaces.size();
117 }
118 
119 ////////////////////////////////////////////////////////////////////
120 // Function: FltRecord::get_subface
121 // Access: Public
122 // Description: Returns the nth subface of this record.
123 ////////////////////////////////////////////////////////////////////
125 get_subface(int n) const {
126  nassertr(n >= 0 && n < (int)_subfaces.size(), (FltRecord *)NULL);
127  return _subfaces[n];
128 }
129 
130 ////////////////////////////////////////////////////////////////////
131 // Function: FltRecord::clear_subfaces
132 // Access: Public
133 // Description: Removes all subfaces from this record.
134 ////////////////////////////////////////////////////////////////////
135 void FltRecord::
137  _subfaces.clear();
138 }
139 
140 ////////////////////////////////////////////////////////////////////
141 // Function: FltRecord::add_subface
142 // Access: Public
143 // Description: Adds a new subface to the end of the list of subfaces
144 // for this record.
145 ////////////////////////////////////////////////////////////////////
146 void FltRecord::
148  _subfaces.push_back(subface);
149 }
150 
151 ////////////////////////////////////////////////////////////////////
152 // Function: FltRecord::get_num_extensions
153 // Access: Public
154 // Description: Returns the number of extension attribute records for
155 // this object. These are auxiliary nodes, presumably
156 // of type FO_extension, that have some local meaning to
157 // the object.
158 ////////////////////////////////////////////////////////////////////
159 int FltRecord::
161  return _extensions.size();
162 }
163 
164 ////////////////////////////////////////////////////////////////////
165 // Function: FltRecord::get_extension
166 // Access: Public
167 // Description: Returns the nth extension of this record.
168 ////////////////////////////////////////////////////////////////////
170 get_extension(int n) const {
171  nassertr(n >= 0 && n < (int)_extensions.size(), (FltRecord *)NULL);
172  return _extensions[n];
173 }
174 
175 ////////////////////////////////////////////////////////////////////
176 // Function: FltRecord::clear_extensions
177 // Access: Public
178 // Description: Removes all extensions from this record.
179 ////////////////////////////////////////////////////////////////////
180 void FltRecord::
182  _extensions.clear();
183 }
184 
185 ////////////////////////////////////////////////////////////////////
186 // Function: FltRecord::add_extension
187 // Access: Public
188 // Description: Adds a new extension to the end of the list of
189 // extensions for this record. This should be a record
190 // of type FO_extension.
191 ////////////////////////////////////////////////////////////////////
192 void FltRecord::
194  _extensions.push_back(extension);
195 }
196 
197 ////////////////////////////////////////////////////////////////////
198 // Function: FltRecord::get_num_ancillary
199 // Access: Public
200 // Description: Returns the number of unsupported ancillary records
201 // of this record. These are ancillary records that
202 // appeared following this record in the flt file but that
203 // aren't directly understood by the flt
204 // loader--normally, an ancillary record is examined and
205 // decoded on the spot, and no pointer to it is kept.
206 ////////////////////////////////////////////////////////////////////
207 int FltRecord::
209  return _ancillary.size();
210 }
211 
212 ////////////////////////////////////////////////////////////////////
213 // Function: FltRecord::get_ancillary
214 // Access: Public
215 // Description: Returns the nth unsupported ancillary record of this
216 // record. See get_num_ancillary().
217 ////////////////////////////////////////////////////////////////////
219 get_ancillary(int n) const {
220  nassertr(n >= 0 && n < (int)_ancillary.size(), (FltRecord *)NULL);
221  return _ancillary[n];
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: FltRecord::clear_ancillary
226 // Access: Public
227 // Description: Removes all unsupported ancillary records from this
228 // record. See get_num_ancillary().
229 ////////////////////////////////////////////////////////////////////
230 void FltRecord::
232  _ancillary.clear();
233 }
234 
235 ////////////////////////////////////////////////////////////////////
236 // Function: FltRecord::add_ancillary
237 // Access: Public
238 // Description: Adds a new unsupported ancillary record to the end of
239 // the list of ancillary records for this record. This
240 // record will be written to the flt file following this
241 // record, without attempting to understand what is in it.
242 //
243 // Normally, there is no reason to use this function; if
244 // the data stored in the FltRecord requires one or more
245 // ancillary record, the appropriate records will
246 // automatically be generated when the record is written.
247 // This function is only required to output a record
248 // whose type is not supported by the flt loader. But
249 // it would be better to extend the flt loader to know
250 // about this new kind of data record.
251 ////////////////////////////////////////////////////////////////////
252 void FltRecord::
254  _ancillary.push_back(ancillary);
255 }
256 
257 ////////////////////////////////////////////////////////////////////
258 // Function: FltRecord::has_comment
259 // Access: Public
260 // Description: Returns true if this record has a nonempty comment,
261 // false otherwise.
262 ////////////////////////////////////////////////////////////////////
263 bool FltRecord::
264 has_comment() const {
265  return !_comment.empty();
266 }
267 
268 ////////////////////////////////////////////////////////////////////
269 // Function: FltRecord::get_comment
270 // Access: Public
271 // Description: Retrieves the comment for this record, or empty
272 // string if the record has no comment.
273 ////////////////////////////////////////////////////////////////////
274 const string &FltRecord::
275 get_comment() const {
276  return _comment;
277 }
278 
279 ////////////////////////////////////////////////////////////////////
280 // Function: FltRecord::clear_comment
281 // Access: Public
282 // Description: Removes the comment for this record.
283 ////////////////////////////////////////////////////////////////////
284 void FltRecord::
286  _comment = "";
287 }
288 
289 ////////////////////////////////////////////////////////////////////
290 // Function: FltRecord::set_comment
291 // Access: Public
292 // Description: Changes the comment for this record.
293 ////////////////////////////////////////////////////////////////////
294 void FltRecord::
295 set_comment(const string &comment) {
296  _comment = comment;
297 }
298 
299 ////////////////////////////////////////////////////////////////////
300 // Function: FltRecord::check_remaining_size
301 // Access: Public
302 // Description: Checks that the iterator has no bytes left, as it
303 // should at the end of a successfully read record. If
304 // there *are* remaining bytes, print a warning message
305 // but otherwise don't worry about it.
306 //
307 // If we are attempting to read a flt file whose version
308 // is newer than the newest this program understands,
309 // don't even print a warning message, since this is
310 // exactly the sort of thing we expect.
311 ////////////////////////////////////////////////////////////////////
312 void FltRecord::
313 check_remaining_size(const DatagramIterator &di, const string &name) const {
314  if (di.get_remaining_size() == 0) {
315  return;
316  }
317 
318  if (_header->get_flt_version() <= _header->max_flt_version()) {
319  nout << "Warning! Ignoring extra " << di.get_remaining_size()
320  << " bytes at the end of a ";
321  if (name.empty()) {
322  nout << get_type();
323  } else {
324  nout << name;
325  }
326  nout << " record.\n";
327  }
328 }
329 
330 ////////////////////////////////////////////////////////////////////
331 // Function: FltRecord::apply_converted_filenames
332 // Access: Public, Virtual
333 // Description: Walks the hierarchy at this record and below and
334 // copies the _converted_filename record into the
335 // _orig_filename record, so the flt file will be
336 // written out with the converted filename instead of
337 // what was originally read in.
338 ////////////////////////////////////////////////////////////////////
339 void FltRecord::
341  Records::const_iterator ci;
342  for (ci = _subfaces.begin(); ci != _subfaces.end(); ++ci) {
343  (*ci)->apply_converted_filenames();
344  }
345  for (ci = _children.begin(); ci != _children.end(); ++ci) {
346  (*ci)->apply_converted_filenames();
347  }
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: FltRecord::output
352 // Access: Public
353 // Description: Writes a quick one-line description of the record, but
354 // not its children. This is a human-readable
355 // description, primarily for debugging; to write a flt
356 // file, use FltHeader::write_flt().
357 ////////////////////////////////////////////////////////////////////
358 void FltRecord::
359 output(ostream &out) const {
360  out << get_type();
361 }
362 
363 ////////////////////////////////////////////////////////////////////
364 // Function: FltRecord::write
365 // Access: Public
366 // Description: Writes a multiple-line description of the record and
367 // all of its children. This is a human-readable
368 // description, primarily for debugging; to write a flt
369 // file, use FltHeader::write_flt().
370 ////////////////////////////////////////////////////////////////////
371 void FltRecord::
372 write(ostream &out, int indent_level) const {
373  indent(out, indent_level) << *this;
374  write_children(out, indent_level);
375 }
376 
377 ////////////////////////////////////////////////////////////////////
378 // Function: FltRecord::write_children
379 // Access: Protected
380 // Description: Assuming the current write position has been left at
381 // the end of the last line of the record description,
382 // writes out the list of children.
383 ////////////////////////////////////////////////////////////////////
384 void FltRecord::
385 write_children(ostream &out, int indent_level) const {
386  if (!_ancillary.empty()) {
387  out << " + " << _ancillary.size() << " ancillary";
388  }
389  if (!_extensions.empty()) {
390  out << " + " << _extensions.size() << " extensions";
391  }
392  if (!_subfaces.empty()) {
393  out << " [";
394  Records::const_iterator ci;
395  for (ci = _subfaces.begin(); ci != _subfaces.end(); ++ci) {
396  out << " " << *(*ci);
397  }
398  out << " ]";
399  }
400  if (!_children.empty()) {
401  out << " {\n";
402  Records::const_iterator ci;
403  for (ci = _children.begin(); ci != _children.end(); ++ci) {
404  (*ci)->write(out, indent_level + 2);
405  }
406  indent(out, indent_level) << "}\n";
407  } else {
408  out << "\n";
409  }
410 }
411 
412  /*
413  virtual void write(ostream &out) const;
414  virtual void build_record(Datagram &datagram) const;
415  */
416 
417 ////////////////////////////////////////////////////////////////////
418 // Function: FltRecord::is_ancillary
419 // Access: Protected, Static
420 // Description: Returns true if the indicated opcode corresponds to
421 // an ancillary record type, false otherwise. In
422 // general, this function is used to identify ancillary
423 // records that are not presently supported by the
424 // FltReader; these will be ignored. Normally,
425 // ancillary records will be detected and processed by
426 // extract_ancillary().
427 ////////////////////////////////////////////////////////////////////
428 bool FltRecord::
429 is_ancillary(FltOpcode opcode) {
430  switch (opcode) {
431  case FO_comment:
432  case FO_long_id:
433  case FO_multitexture:
434  case FO_uv_list:
435  case FO_replicate:
436  case FO_road_zone:
437  case FO_transform_matrix:
438  case FO_rotate_about_edge:
439  case FO_translate:
440  case FO_scale:
441  case FO_rotate_about_point:
442  case FO_rotate_and_scale:
443  case FO_put:
444  case FO_general_matrix:
445  case FO_vector:
446  case FO_bounding_box:
447  case FO_bounding_sphere:
448  case FO_bounding_cylinder:
449  case FO_bv_center:
450  case FO_bv_orientation:
451  case FO_local_vertex_pool:
452  case FO_cat_data:
453 
454  case FO_14_material_palette:
455  case FO_vertex_palette:
456  case FO_vertex_c:
457  case FO_vertex_cn:
458  case FO_vertex_cnu:
459  case FO_vertex_cu:
460  case FO_color_palette:
461  case FO_name_table:
462  case FO_15_material:
463  case FO_texture:
464  case FO_eyepoint_palette:
465  case FO_light_definition:
466  case FO_texture_map_palette:
467  return true;
468 
469  case FO_header:
470  case FO_mesh:
471  case FO_mesh_primitive:
472  case FO_group:
473  case FO_object:
474  case FO_face:
475  case FO_light_point:
476  case FO_dof:
477  case FO_vertex_list:
478  case FO_morph_list:
479  case FO_bsp:
480  case FO_external_ref:
481  case FO_lod:
482  case FO_sound:
483  case FO_light_source:
484  case FO_road_segment:
485  case FO_road_construction:
486  case FO_road_path:
487  case FO_clip_region:
488  case FO_text:
489  case FO_switch:
490  case FO_cat:
491  case FO_extension:
492  case FO_curve:
493  return false;
494 
495  case FO_push:
496  case FO_pop:
497  case FO_push_face:
498  case FO_pop_face:
499  case FO_push_attribute:
500  case FO_pop_attribute:
501  case FO_push_extension:
502  case FO_pop_extension:
503  case FO_instance:
504  case FO_instance_ref:
505  return false;
506 
507  default:
508  nout << "Don't know whether " << opcode << " is ancillary.\n";
509  return false;
510  }
511 }
512 
513 ////////////////////////////////////////////////////////////////////
514 // Function: FltRecord::create_new_record
515 // Access: Protected
516 // Description: Creates a new FltRecord corresponding to the opcode.
517 // If the opcode is unknown, creates a
518 // FltUnsupportedRecord.
519 ////////////////////////////////////////////////////////////////////
520 FltRecord *FltRecord::
521 create_new_record(FltOpcode opcode) const {
522  switch (opcode) {
523  case FO_group:
524  return new FltGroup(_header);
525 
526  case FO_object:
527  return new FltObject(_header);
528 
529  case FO_face:
530  return new FltFace(_header);
531 
532  case FO_curve:
533  return new FltCurve(_header);
534 
535  case FO_mesh:
536  return new FltMesh(_header);
537 
538  case FO_local_vertex_pool:
539  return new FltLocalVertexPool(_header);
540 
541  case FO_mesh_primitive:
542  return new FltMeshPrimitive(_header);
543 
544  case FO_vertex_list:
545  return new FltVertexList(_header);
546 
547  case FO_lod:
548  return new FltLOD(_header);
549 
550  case FO_instance:
551  return new FltInstanceDefinition(_header);
552 
553  case FO_instance_ref:
554  return new FltInstanceRef(_header);
555 
556  case FO_external_ref:
557  return new FltExternalReference(_header);
558 
559  case FO_vector:
560  return new FltVectorRecord(_header);
561 
562  default:
563  nout << "Ignoring unsupported record " << opcode << "\n";
564  return new FltUnsupportedRecord(_header);
565  }
566 }
567 
568 ////////////////////////////////////////////////////////////////////
569 // Function: FltRecord::read_record_and_children
570 // Access: Protected
571 // Description: Extracts this record information from the current
572 // record presented in the reader, then advances the
573 // reader and continues to read any children, if
574 // present. On return, the reader is position on the
575 // next sibling record to this record.
576 //
577 // Returns FE_ok if successful, otherwise on error.
578 ////////////////////////////////////////////////////////////////////
579 FltError FltRecord::
580 read_record_and_children(FltRecordReader &reader) {
581  if (!extract_record(reader)) {
582  nout << "Could not extract record for " << *this << "\n";
583  assert(!flt_error_abort);
584  return FE_invalid_record;
585  }
586  FltError result = reader.advance();
587  if (result == FE_end_of_file) {
588  return FE_ok;
589  } else if (result != FE_ok) {
590  return result;
591  }
592 
593  while (true) {
594  if (extract_ancillary(reader)) {
595  // Ok, a known ancillary record. Fine.
596 
597  } else if (reader.get_opcode() == FO_push) {
598  // A push begins a new list of children.
599  result = reader.advance();
600  if (result != FE_ok) {
601  return result;
602  }
603 
604  while (reader.get_opcode() != FO_pop) {
605  PT(FltRecord) child = create_new_record(reader.get_opcode());
606  FltError result = child->read_record_and_children(reader);
607  if (result != FE_ok) {
608  return result;
609  }
610 
611  if (child->is_of_type(FltInstanceDefinition::get_class_type())) {
612  // A special case for an instance definition. These
613  // shouldn't appear in the hierarchy, but should instead be
614  // added directly to the header.
615  _header->add_instance(DCAST(FltInstanceDefinition, child));
616 
617  } else {
618  add_child(child);
619  }
620 
621  if (reader.eof() || reader.error()) {
622  assert(!flt_error_abort);
623  return FE_end_of_file;
624  }
625  }
626 
627  } else if (reader.get_opcode() == FO_push_face) {
628  // A push subface begins a new list of subfaces.
629  result = reader.advance();
630  if (result != FE_ok) {
631  return result;
632  }
633 
634  while (reader.get_opcode() != FO_pop_face) {
635  PT(FltRecord) subface = create_new_record(reader.get_opcode());
636  FltError result = subface->read_record_and_children(reader);
637  if (result != FE_ok) {
638  return result;
639  }
640  add_subface(subface);
641  if (reader.eof() || reader.error()) {
642  assert(!flt_error_abort);
643  return FE_end_of_file;
644  }
645  }
646 
647  } else if (reader.get_opcode() == FO_push_extension) {
648  // A push extension begins a new list of extensions.
649  result = reader.advance();
650  if (result != FE_ok) {
651  return result;
652  }
653 
654  while (reader.get_opcode() != FO_pop_extension) {
655  PT(FltRecord) extension = create_new_record(reader.get_opcode());
656  FltError result = extension->read_record_and_children(reader);
657  if (result != FE_ok) {
658  return result;
659  }
660  add_extension(extension);
661  if (reader.eof() || reader.error()) {
662  assert(!flt_error_abort);
663  return FE_end_of_file;
664  }
665  }
666 
667  } else if (is_ancillary(reader.get_opcode())) {
668  // An unsupported ancillary record. Skip it.
669  PT(FltRecord) ancillary = create_new_record(reader.get_opcode());
670  ancillary->extract_record(reader);
671  _ancillary.push_back(ancillary);
672 
673  } else {
674  // None of the above: we're done.
675  return FE_ok;
676  }
677 
678  // Skip to the next record. If that's the end, fine.
679  result = reader.advance(true);
680  if (reader.eof() || result != FE_ok) {
681  return result;
682  }
683  }
684 }
685 
686 ////////////////////////////////////////////////////////////////////
687 // Function: FltRecord::extract_record
688 // Access: Protected, Virtual
689 // Description: Fills in the information in this record based on the
690 // information given in the indicated datagram, whose
691 // opcode has already been read. Returns true on
692 // success, false if the datagram is invalid.
693 ////////////////////////////////////////////////////////////////////
694 bool FltRecord::
695 extract_record(FltRecordReader &) {
696  return true;
697 }
698 
699 ////////////////////////////////////////////////////////////////////
700 // Function: FltRecord::extract_ancillary
701 // Access: Protected, Virtual
702 // Description: Checks whether the given record, which follows this
703 // record sequentially in the file, is an ancillary record
704 // of this record. If it is, extracts the relevant
705 // information and returns true; otherwise, leaves it
706 // alone and returns false.
707 ////////////////////////////////////////////////////////////////////
708 bool FltRecord::
709 extract_ancillary(FltRecordReader &reader) {
710  if (reader.get_opcode() == FO_comment) {
711  _comment = reader.get_iterator().get_remaining_bytes();
712  return true;
713  }
714 
715  return false;
716 }
717 
718 ////////////////////////////////////////////////////////////////////
719 // Function: FltRecord::write_record_and_children
720 // Access: Protected, Virtual
721 // Description: Writes this record out to the flt file, along with all
722 // of its ancillary records and children records. Returns
723 // FE_ok on success, or something else on error.
724 ////////////////////////////////////////////////////////////////////
725 FltError FltRecord::
726 write_record_and_children(FltRecordWriter &writer) const {
727  // First, write the record.
728  if (!build_record(writer)) {
729  assert(!flt_error_abort);
730  return FE_bad_data;
731  }
732 
733  FltError result = writer.advance();
734  if (result != FE_ok) {
735  return result;
736  }
737 
738  // Then the ancillary data.
739  result = write_ancillary(writer);
740  if (result != FE_ok) {
741  return result;
742  }
743  Records::const_iterator ci;
744  for (ci = _ancillary.begin(); ci != _ancillary.end(); ++ci) {
745  if (!(*ci)->build_record(writer)) {
746  assert(!flt_error_abort);
747  return FE_bad_data;
748  }
749  result = writer.advance();
750  if (result != FE_ok) {
751  return result;
752  }
753  }
754 
755  // Any extensions?
756  if (!_extensions.empty()) {
757  result = writer.write_record(FO_push_face);
758  if (result != FE_ok) {
759  return result;
760  }
761 
762  for (ci = _extensions.begin(); ci != _extensions.end(); ++ci) {
763  (*ci)->write_record_and_children(writer);
764  }
765 
766  result = writer.write_record(FO_pop_face);
767  if (result != FE_ok) {
768  return result;
769  }
770  }
771 
772  // Finally, write all the children.
773  if (!_children.empty()) {
774  result = writer.write_record(FO_push);
775  if (result != FE_ok) {
776  return result;
777  }
778 
779  for (ci = _children.begin(); ci != _children.end(); ++ci) {
780  (*ci)->write_record_and_children(writer);
781  }
782 
783  result = writer.write_record(FO_pop);
784  if (result != FE_ok) {
785  return result;
786  }
787  }
788 
789  // We must write subfaces *after* the list of children, or Creator
790  // will crash trying to load the file.
791  if (!_subfaces.empty()) {
792  result = writer.write_record(FO_push_face);
793  if (result != FE_ok) {
794  return result;
795  }
796 
797  for (ci = _subfaces.begin(); ci != _subfaces.end(); ++ci) {
798  (*ci)->write_record_and_children(writer);
799  }
800 
801  result = writer.write_record(FO_pop_face);
802  if (result != FE_ok) {
803  return result;
804  }
805  }
806 
807  return FE_ok;
808 }
809 
810 ////////////////////////////////////////////////////////////////////
811 // Function: FltRecord::build_record
812 // Access: Protected, Virtual
813 // Description: Fills up the current record on the FltRecordWriter with
814 // data for this record, but does not advance the
815 // writer. Returns true on success, false if there is
816 // some error.
817 ////////////////////////////////////////////////////////////////////
818 bool FltRecord::
819 build_record(FltRecordWriter &) const {
820  return true;
821 }
822 
823 ////////////////////////////////////////////////////////////////////
824 // Function: FltRecord::write_ancillary
825 // Access: Protected, Virtual
826 // Description: Writes whatever ancillary records are required for
827 // this record. Returns FE_ok on success, or something
828 // else if there is some error.
829 ////////////////////////////////////////////////////////////////////
830 FltError FltRecord::
831 write_ancillary(FltRecordWriter &writer) const {
832  if (!_comment.empty()) {
833  Datagram dc(_comment);
834  FltError result = writer.write_record(FO_comment, dc);
835  if (result != FE_ok) {
836  return result;
837  }
838  }
839  return FE_ok;
840 }
void clear_comment()
Removes the comment for this record.
Definition: fltRecord.cxx:285
int get_flt_version() const
Returns the version number of the flt file as reported in the header, times 100.
Definition: fltHeader.cxx:359
This class writes a sequence of FltRecords to an ostream, handling opcode and size counts properly...
void clear_ancillary()
Removes all unsupported ancillary records from this record.
Definition: fltRecord.cxx:231
void clear_extensions()
Removes all extensions from this record.
Definition: fltRecord.cxx:181
This class turns an istream into a sequence of FltRecords by reading a sequence of Datagrams and extr...
void set_comment(const string &comment)
Changes the comment for this record.
Definition: fltRecord.cxx:295
FltRecord * get_ancillary(int n) const
Returns the nth unsupported ancillary record of this record.
Definition: fltRecord.cxx:219
int get_num_children() const
Returns the number of child records of this record.
Definition: fltRecord.cxx:70
static int max_flt_version()
Returns the latest flt version number that this codebase is known to support (times 100)...
Definition: fltHeader.cxx:403
FltRecord * get_extension(int n) const
Returns the nth extension of this record.
Definition: fltRecord.cxx:170
The main grouping bead of the flt file.
Definition: fltGroup.h:26
virtual void apply_converted_filenames()
Walks the hierarchy at this record and below and copies the _converted_filename record into the _orig...
Definition: fltRecord.cxx:340
bool error() const
Returns true if some error has been encountered while reading (for instance, a truncated file)...
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
A single primitive of a mesh, like a triangle strip or fan.
A single face bead, e.g.
Definition: fltFace.h:26
DatagramIterator & get_iterator()
Returns an iterator suitable for extracting data from the current record.
void add_child(FltRecord *child)
Adds a new child to the end of the list of children for this record.
Definition: fltRecord.cxx:102
This is the first bead in the file, the top of the bead hierarchy, and the primary interface to readi...
Definition: fltHeader.h:48
bool has_comment() const
Returns true if this record has a nonempty comment, false otherwise.
Definition: fltRecord.cxx:264
A local vertex pool, as might appear in the middle of the hierarchy, for instance for a mesh...
FltRecord * get_subface(int n) const
Returns the nth subface of this record.
Definition: fltRecord.cxx:125
A mesh of connected polygons and tristrips, etc., with a local vertex pool.
Definition: fltMesh.h:30
virtual void output(ostream &out) const
Writes a quick one-line description of the record, but not its children.
Definition: fltRecord.cxx:359
A list of vertices, typically added as a child of a face bead.
Definition: fltVertexList.h:31
const string & get_comment() const
Retrieves the comment for this record, or empty string if the record has no comment.
Definition: fltRecord.cxx:275
int get_remaining_size() const
Return the bytes left in the datagram.
The base class for all kinds of records in a MultiGen OpenFlight file.
Definition: fltRecord.h:40
This bead appears in the hierarchy to refer to a FltInstanceDefinition node defined elsewhere...
An external reference to another flt file (possibly to a specific bead within the flt file)...
FltError advance()
Writes the current record to the flt file, and resets the current record to receive new data...
The main objecting bead of the flt file.
Definition: fltObject.h:26
FltRecord * get_child(int n) const
Returns the nth child of this record.
Definition: fltRecord.cxx:80
void add_extension(FltRecord *extension)
Adds a new extension to the end of the list of extensions for this record.
Definition: fltRecord.cxx:193
void add_subface(FltRecord *subface)
Adds a new subface to the end of the list of subfaces for this record.
Definition: fltRecord.cxx:147
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
void add_instance(FltInstanceDefinition *instance)
Defines a new instance subtree.
Definition: fltHeader.cxx:520
A class to retrieve the individual data elements previously stored in a Datagram. ...
void add_ancillary(FltRecord *ancillary)
Adds a new unsupported ancillary record to the end of the list of ancillary records for this record...
Definition: fltRecord.cxx:253
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
string get_remaining_bytes() const
Returns the remaining bytes in the datagram as a string, but does not extract them from the iterator...
A single curve, like a Bezier or B-Spline.
Definition: fltCurve.h:29
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
A Level-of-Detail record.
Definition: fltLOD.h:26
FltError advance(bool ok_eof=false)
Extracts the next record from the file.
int get_num_ancillary() const
Returns the number of unsupported ancillary records of this record.
Definition: fltRecord.cxx:208
void clear_children()
Removes all children from this record.
Definition: fltRecord.cxx:91
void clear_subfaces()
Removes all subfaces from this record.
Definition: fltRecord.cxx:136
This special kind of record marks the top node of an instance subtree.
This is an ancillary record of the old (pre-15.4) face node.
int get_num_subfaces() const
Returns the number of subface records of this record.
Definition: fltRecord.cxx:115
virtual void write(ostream &out, int indent_level=0) const
Writes a multiple-line description of the record and all of its children.
Definition: fltRecord.cxx:372
int get_num_extensions() const
Returns the number of extension attribute records for this object.
Definition: fltRecord.cxx:160
bool eof() const
Returns true if end-of-file has been reached without error.
FltError write_record(FltOpcode opcode, const Datagram &datagram=Datagram())
A convenience function to quickly write a simple record that consists of an opcode and possibly a dat...