Panda3D
 All Classes Functions Variables Enumerations
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
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
int get_num_ancillary() const
Returns the number of unsupported ancillary records of this record.
Definition: fltRecord.cxx:208
int get_num_subfaces() const
Returns the number of subface records of this record.
Definition: fltRecord.cxx:115
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
bool eof() const
Returns true if end-of-file has been reached without error.
int get_num_extensions() const
Returns the number of extension attribute records for this object.
Definition: fltRecord.cxx:160
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
A single primitive of a mesh, like a triangle strip or fan.
FltRecord * get_child(int n) const
Returns the nth child of this record.
Definition: fltRecord.cxx:80
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
virtual void output(ostream &out) const
Writes a quick one-line description of the record, but not its children.
Definition: fltRecord.cxx:359
A local vertex pool, as might appear in the middle of the hierarchy, for instance for a mesh...
int get_remaining_size() const
Return the bytes left in the datagram.
bool error() const
Returns true if some error has been encountered while reading (for instance, a truncated file)...
string get_remaining_bytes() const
Returns the remaining bytes in the datagram as a string, but does not extract them from the iterator...
A mesh of connected polygons and tristrips, etc., with a local vertex pool.
Definition: fltMesh.h:30
FltRecord * get_ancillary(int n) const
Returns the nth unsupported ancillary record of this record.
Definition: fltRecord.cxx:219
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
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)...
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
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
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 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
void add_subface(FltRecord *subface)
Adds a new subface to the end of the list of subfaces for this record.
Definition: fltRecord.cxx:147
bool has_comment() const
Returns true if this record has a nonempty comment, false otherwise.
Definition: fltRecord.cxx:264
FltRecord * get_subface(int n) const
Returns the nth subface of this record.
Definition: fltRecord.cxx:125
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
int get_num_children() const
Returns the number of child records of this record.
Definition: fltRecord.cxx:70
void add_instance(FltInstanceDefinition *instance)
Defines a new instance subtree.
Definition: fltHeader.cxx:520
int get_flt_version() const
Returns the version number of the flt file as reported in the header, times 100.
Definition: fltHeader.cxx:359
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
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.
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.
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...