Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
b1046f60ec
52 changed files with 1834 additions and 429 deletions
  1. 16 6
      pandatool/src/flt/Sources.pp
  2. 10 0
      pandatool/src/flt/config_flt.cxx
  3. 5 4
      pandatool/src/flt/fltBead.cxx
  4. 30 0
      pandatool/src/flt/fltCurve.I
  5. 88 0
      pandatool/src/flt/fltCurve.cxx
  6. 66 0
      pandatool/src/flt/fltCurve.h
  7. 1 1
      pandatool/src/flt/fltExternalReference.cxx
  8. 0 55
      pandatool/src/flt/fltFace.I
  9. 8 191
      pandatool/src/flt/fltFace.cxx
  10. 4 84
      pandatool/src/flt/fltFace.h
  11. 60 0
      pandatool/src/flt/fltGeometry.I
  12. 239 0
      pandatool/src/flt/fltGeometry.cxx
  13. 131 0
      pandatool/src/flt/fltGeometry.h
  14. 1 1
      pandatool/src/flt/fltGroup.cxx
  15. 52 12
      pandatool/src/flt/fltHeader.cxx
  16. 5 0
      pandatool/src/flt/fltHeader.h
  17. 1 1
      pandatool/src/flt/fltInstanceDefinition.cxx
  18. 1 1
      pandatool/src/flt/fltInstanceRef.cxx
  19. 1 1
      pandatool/src/flt/fltLOD.cxx
  20. 1 1
      pandatool/src/flt/fltLightSourceDefinition.cxx
  21. 4 0
      pandatool/src/flt/fltLocalVertexPool.I
  22. 235 0
      pandatool/src/flt/fltLocalVertexPool.cxx
  23. 72 0
      pandatool/src/flt/fltLocalVertexPool.h
  24. 1 1
      pandatool/src/flt/fltMaterial.cxx
  25. 4 0
      pandatool/src/flt/fltMesh.I
  26. 118 0
      pandatool/src/flt/fltMesh.cxx
  27. 56 0
      pandatool/src/flt/fltMesh.h
  28. 4 0
      pandatool/src/flt/fltMeshPrimitive.I
  29. 127 0
      pandatool/src/flt/fltMeshPrimitive.cxx
  30. 64 0
      pandatool/src/flt/fltMeshPrimitive.h
  31. 1 1
      pandatool/src/flt/fltObject.cxx
  32. 38 2
      pandatool/src/flt/fltOpcode.cxx
  33. 15 1
      pandatool/src/flt/fltOpcode.h
  34. 29 0
      pandatool/src/flt/fltPackedColor.I
  35. 3 0
      pandatool/src/flt/fltPackedColor.h
  36. 143 1
      pandatool/src/flt/fltRecord.cxx
  37. 9 0
      pandatool/src/flt/fltRecord.h
  38. 86 21
      pandatool/src/flt/fltRecordReader.cxx
  39. 6 0
      pandatool/src/flt/fltRecordReader.h
  40. 44 27
      pandatool/src/flt/fltRecordWriter.cxx
  41. 34 6
      pandatool/src/flt/fltTexture.cxx
  42. 10 0
      pandatool/src/flt/fltTexture.h
  43. 1 1
      pandatool/src/flt/fltTransformGeneralMatrix.cxx
  44. 1 1
      pandatool/src/flt/fltTransformPut.cxx
  45. 1 1
      pandatool/src/flt/fltTransformRotateAboutEdge.cxx
  46. 1 1
      pandatool/src/flt/fltTransformRotateAboutPoint.cxx
  47. 1 1
      pandatool/src/flt/fltTransformRotateScale.cxx
  48. 1 1
      pandatool/src/flt/fltTransformScale.cxx
  49. 1 1
      pandatool/src/flt/fltTransformTranslate.cxx
  50. 1 1
      pandatool/src/flt/fltVertex.cxx
  51. 1 1
      pandatool/src/flt/fltVertexList.cxx
  52. 2 2
      pandatool/src/flt/test_flt.cxx

+ 16 - 6
pandatool/src/flt/Sources.pp

@@ -8,13 +8,18 @@
 
   #define SOURCES \
     config_flt.cxx config_flt.h fltBead.cxx fltBead.h fltBeadID.cxx \
-    fltBeadID.h fltError.cxx fltError.h fltExternalReference.cxx \
+    fltBeadID.h fltCurve.I fltCurve.cxx fltCurve.h \
+    fltError.cxx fltError.h fltExternalReference.cxx \
     fltExternalReference.h fltEyepoint.cxx fltEyepoint.h fltFace.I \
-    fltFace.cxx fltFace.h fltGroup.cxx fltGroup.h fltHeader.cxx \
+    fltFace.cxx fltFace.h fltGeometry.I fltGeometry.cxx fltGeometry.h \
+    fltGroup.cxx fltGroup.h fltHeader.cxx \
     fltHeader.h fltInstanceDefinition.cxx fltInstanceDefinition.h \
     fltInstanceRef.cxx fltInstanceRef.h fltLOD.cxx fltLOD.h \
     fltLightSourceDefinition.cxx fltLightSourceDefinition.h \
-    fltMaterial.cxx fltMaterial.h fltObject.cxx fltObject.h \
+    fltLocalVertexPool.I fltLocalVertexPool.cxx fltLocalVertexPool.h \
+    fltMaterial.cxx fltMaterial.h fltMesh.I fltMesh.cxx fltMesh.h \
+    fltMeshPrimitive.I fltMeshPrimitive.cxx fltMeshPrimitive.h \
+    fltObject.cxx fltObject.h \
     fltOpcode.cxx fltOpcode.h fltPackedColor.I fltPackedColor.cxx \
     fltPackedColor.h fltRecord.I fltRecord.cxx fltRecord.h \
     fltRecordReader.cxx fltRecordReader.h fltRecordWriter.cxx \
@@ -31,10 +36,15 @@
     fltVertexList.cxx fltVertexList.h
 
   #define INSTALL_HEADERS \
-    fltBead.h fltBeadID.h fltError.h fltExternalReference.h \
-    fltEyepoint.h fltFace.I fltFace.h fltGroup.h fltHeader.h \
+    fltBead.h fltBeadID.h fltCurve.I fltCurve.h \
+    fltError.h fltExternalReference.h \
+    fltEyepoint.h fltFace.I fltFace.h fltGeometry.I fltGeometry.h \
+    fltGroup.h fltHeader.h \
     fltInstanceDefinition.h fltInstanceRef.h fltLOD.h \
-    fltLightSourceDefinition.h fltMaterial.h fltObject.h fltOpcode.h \
+    fltLightSourceDefinition.h fltLocalVertexPool.I fltLocalVertexPool.h \
+    fltMaterial.h fltMesh.I fltMesh.h \
+    fltMeshPrimitive.I fltMeshPrimitive.h \
+    fltObject.h fltOpcode.h \
     fltPackedColor.I fltPackedColor.h fltRecord.I fltRecord.h \
     fltRecordReader.h fltRecordWriter.h fltTexture.h fltTrackplane.h \
     fltTransformGeneralMatrix.h fltTransformPut.h fltTransformRecord.h \

+ 10 - 0
pandatool/src/flt/config_flt.cxx

@@ -9,7 +9,12 @@
 #include "fltBeadID.h"
 #include "fltGroup.h"
 #include "fltObject.h"
+#include "fltGeometry.h"
 #include "fltFace.h"
+#include "fltCurve.h"
+#include "fltMesh.h"
+#include "fltLocalVertexPool.h"
+#include "fltMeshPrimitive.h"
 #include "fltVertexList.h"
 #include "fltLOD.h"
 #include "fltInstanceDefinition.h"
@@ -48,7 +53,12 @@ ConfigureFn(config_flt) {
   FltBeadID::init_type();
   FltGroup::init_type();
   FltObject::init_type();
+  FltGeometry::init_type();
   FltFace::init_type();
+  FltCurve::init_type();
+  FltMesh::init_type();
+  FltLocalVertexPool::init_type();
+  FltMeshPrimitive::init_type();
   FltVertexList::init_type();
   FltLOD::init_type();
   FltInstanceDefinition::init_type();

+ 5 - 4
pandatool/src/flt/fltBead.cxx

@@ -229,7 +229,9 @@ extract_ancillary(FltRecordReader &reader) {
 
   // A transform step.
   nassertr(step != (FltTransformRecord *)NULL, false);
-  step->extract_record(reader);
+  if (!step->extract_record(reader)) {
+    return false;
+  }
   _transform_steps.push_back(DCAST(FltTransformRecord, step));
 
   /*
@@ -305,7 +307,7 @@ extract_transform_matrix(FltRecordReader &reader) {
       matrix(r, c) = iterator.get_be_float32();
     }
   }
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
 
   _transform_steps.clear();
   _has_transform = true;
@@ -327,8 +329,7 @@ extract_replicate_count(FltRecordReader &reader) {
   _replicate_count = iterator.get_be_int16();
   iterator.skip_bytes(2);
 
-  nassertr(iterator.get_remaining_size() == 0, true);
-
+  check_remaining_size(iterator);
   return true;
 }
 

+ 30 - 0
pandatool/src/flt/fltCurve.I

@@ -0,0 +1,30 @@
+// Filename: fltCurve.I
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltCurve::get_num_control_points
+//       Access: Public
+//  Description: Returns the number of control points assigned to the
+//               curve.
+////////////////////////////////////////////////////////////////////
+INLINE int FltCurve::
+get_num_control_points() const {
+  return _control_points.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltCurve::get_control_point
+//       Access: Public
+//  Description: Returns the nth control point assigned to the curve.
+////////////////////////////////////////////////////////////////////
+INLINE const LPoint3d &FltCurve::
+get_control_point(int n) const {
+#ifndef NDEBUG
+  static LPoint3d bogus(0.0, 0.0, 0.0);
+  nassertr(n >= 0 && n < (int)_control_points.size(), bogus);
+#endif
+  return _control_points[n];
+}

+ 88 - 0
pandatool/src/flt/fltCurve.cxx

@@ -0,0 +1,88 @@
+// Filename: fltCurve.cxx
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "fltCurve.h"
+#include "fltRecordReader.h"
+#include "fltRecordWriter.h"
+#include "fltHeader.h"
+#include "fltMaterial.h"
+
+TypeHandle FltCurve::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltCurve::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltCurve::
+FltCurve(FltHeader *header) : FltBeadID(header) {
+  _curve_type = CT_b_spline;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltCurve::extract_record
+//       Access: Protected, Virtual
+//  Description: Fills in the information in this bead based on the
+//               information given in the indicated datagram, whose
+//               opcode has already been read.  Returns true on
+//               success, false if the datagram is invalid.
+////////////////////////////////////////////////////////////////////
+bool FltCurve::
+extract_record(FltRecordReader &reader) {
+  if (!FltBeadID::extract_record(reader)) {
+    return false;
+  }
+
+  nassertr(reader.get_opcode() == FO_curve, false);
+  DatagramIterator &iterator = reader.get_iterator();
+
+  iterator.skip_bytes(4);
+  _curve_type = (CurveType)iterator.get_be_int32();
+
+  int num_control_points = iterator.get_be_int32();
+  iterator.skip_bytes(8);
+  for (int i = 0; i < num_control_points; i++) {
+    double x = iterator.get_be_float64();
+    double y = iterator.get_be_float64();
+    double z = iterator.get_be_float64();
+    _control_points.push_back(LPoint3d(x, y, z));
+  }
+
+  check_remaining_size(iterator);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltCurve::build_record
+//       Access: Protected, Virtual
+//  Description: Fills up the current record on the FltRecordWriter with
+//               data for this record, but does not advance the
+//               writer.  Returns true on success, false if there is
+//               some error.
+////////////////////////////////////////////////////////////////////
+bool FltCurve::
+build_record(FltRecordWriter &writer) const {
+  if (!FltBeadID::build_record(writer)) {
+    return false;
+  }
+
+  writer.set_opcode(FO_curve);
+  Datagram &datagram = writer.update_datagram();
+
+  datagram.pad_bytes(4);
+  datagram.add_be_int32(_curve_type);
+  datagram.add_be_int32(_control_points.size());
+  datagram.pad_bytes(8);
+
+  ControlPoints::const_iterator ci;
+  for (ci = _control_points.begin(); ci != _control_points.end(); ++ci) {
+    const LPoint3d &p = (*ci);
+    datagram.add_be_float64(p[0]);
+    datagram.add_be_float64(p[1]);
+    datagram.add_be_float64(p[2]);
+  }
+
+  return true;
+}

+ 66 - 0
pandatool/src/flt/fltCurve.h

@@ -0,0 +1,66 @@
+// Filename: fltCurve.h
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLTCURVE_H
+#define FLTCURVE_H
+
+#include <pandatoolbase.h>
+
+#include "fltBeadID.h"
+#include "fltHeader.h"
+
+#include <luse.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : FltCurve
+// Description : A single curve, like a Bezier or B-Spline.
+////////////////////////////////////////////////////////////////////
+class FltCurve : public FltBeadID {
+public:
+  FltCurve(FltHeader *header);
+
+  enum CurveType {
+    CT_b_spline            = 4,
+    CT_cardinal            = 5,
+    CT_bezier              = 6
+  };
+
+  typedef vector<LPoint3d> ControlPoints;
+
+  CurveType _curve_type;
+  ControlPoints _control_points;
+
+public:
+  INLINE int get_num_control_points() const;
+  INLINE const LPoint3d &get_control_point(int n) const;
+
+
+protected:
+  virtual bool extract_record(FltRecordReader &reader);
+  virtual bool build_record(FltRecordWriter &writer) const;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    FltBeadID::init_type();
+    register_type(_type_handle, "FltCurve",
+		  FltBeadID::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "fltCurve.I"
+
+#endif
+
+

+ 1 - 1
pandatool/src/flt/fltExternalReference.cxx

@@ -86,7 +86,7 @@ extract_record(FltRecordReader &reader) {
     }
   }
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 0 - 55
pandatool/src/flt/fltFace.I

@@ -3,58 +3,3 @@
 // 
 ////////////////////////////////////////////////////////////////////
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::has_texture
-//       Access: Public
-//  Description: Returns true if the face has a texture applied, false
-//               otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool FltFace::
-has_texture() const {
-  return (_texture_index >= 0 && _header->has_texture(_texture_index));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::get_texture
-//       Access: Public
-//  Description: Returns the texture applied to this face, or NULL if
-//               no texture was applied.
-////////////////////////////////////////////////////////////////////
-INLINE FltTexture *FltFace::
-get_texture() const {
-  return _header->get_texture(_texture_index);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::has_material
-//       Access: Public
-//  Description: Returns true if the face has a material applied, false
-//               otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool FltFace::
-has_material() const {
-  return (_material_index >= 0 && _header->has_material(_material_index));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::get_material
-//       Access: Public
-//  Description: Returns the material applied to this face, or NULL if
-//               no material was applied.
-////////////////////////////////////////////////////////////////////
-INLINE FltMaterial *FltFace::
-get_material() const {
-  return _header->get_material(_material_index);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::has_color
-//       Access: Public
-//  Description: Returns true if the face has a primary color
-//               indicated, false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool FltFace::
-has_color() const {
-  return ((_flags & F_no_color) == 0) || has_material();
-}

+ 8 - 191
pandatool/src/flt/fltFace.cxx

@@ -17,125 +17,7 @@ TypeHandle FltFace::_type_handle;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 FltFace::
-FltFace(FltHeader *header) : FltBeadID(header) {
-  _ir_color = 0;
-  _relative_priority = 0;
-  _draw_type = DT_solid_backface;
-  _texwhite = false;
-  _color_name_index = 0;
-  _alt_color_name_index = 0;
-  _billboard_type = BT_none;
-  _detail_texture_index = -1;
-  _texture_index = -1;
-  _material_index = -1;
-  _dfad_material_code = 0;
-  _dfad_feature_id = 0;
-  _ir_material_code = 0;
-  _transparency = 0;
-  _lod_generation_control = 0;
-  _line_style_index = 0;
-  _flags = 0;
-  _light_mode = LM_face_no_normal;
-  _texture_mapping_index = 0;
-  _color_index = 0;
-  _alt_color_index = 0;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::get_color
-//       Access: Public
-//  Description: If has_color() indicates true, returns the primary
-//               color of the face, as a four-component value
-//               (including alpha as the transparency channel).
-////////////////////////////////////////////////////////////////////
-Colorf FltFace::
-get_color() const {
-  nassertr(has_color(), Colorf(0.0, 0.0, 0.0, 0.0));
-
-  if (_texwhite && has_texture()) {
-    // Force this one white.
-    return Colorf(1.0, 1.0, 1.0, 1.0 - (_transparency / 65535.0));
-  }
-
-  if (has_material()) {
-    // If we have a material, that replaces the color.
-    FltMaterial *material = get_material();
-    return Colorf(material->_diffuse[0],
-		  material->_diffuse[1],
-		  material->_diffuse[2],
-		  1.0 - (_transparency / 65535.0));
-  }
-
-  return _header->get_color(_color_index, (_flags & F_packed_color) != 0,
-			    _packed_color, _transparency);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::get_rgb
-//       Access: Public
-//  Description: If has_color() indicates true, returns the primary
-//               color of the face, as a three-component value
-//               ignoring transparency.
-////////////////////////////////////////////////////////////////////
-RGBColorf FltFace::
-get_rgb() const {
-  nassertr(has_color(), RGBColorf(0.0, 0.0, 0.0));
-
-  if (_texwhite && has_texture()) {
-    // Force this one white.
-    return RGBColorf(1.0, 1.0, 1.0);
-  }
-
-  if (has_material()) {
-    // If we have a material, that replaces the color.
-    FltMaterial *material = get_material();
-    return material->_diffuse;
-  }
-
-  return _header->get_rgb(_color_index, (_flags & F_packed_color) != 0,
-			  _packed_color);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::has_alt_color
-//       Access: Public
-//  Description: Returns true if the face has an alternate color
-//               indicated, false otherwise.
-////////////////////////////////////////////////////////////////////
-bool FltFace::
-has_alt_color() const {
-  return (_flags & F_no_alt_color) == 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::get_alt_color
-//       Access: Public
-//  Description: If has_alt_color() indicates true, returns the alternate
-//               color of the face, as a four-component value
-//               (including alpha as the transparency channel).
-////////////////////////////////////////////////////////////////////
-Colorf FltFace::
-get_alt_color() const {
-  nassertr(has_alt_color(), Colorf(0.0, 0.0, 0.0, 0.0));
-
-  return _header->get_color(_alt_color_index, (_flags & F_packed_color) != 0,
-			    _alt_packed_color, _transparency);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltFace::get_alt_rgb
-//       Access: Public
-//  Description: If has_alt_color() indicates true, returns the alternate
-//               color of the face, as a three-component value
-//               ignoring transparency.
-////////////////////////////////////////////////////////////////////
-RGBColorf FltFace::
-get_alt_rgb() const {
-  nassertr(has_alt_color(), RGBColorf(0.0, 0.0, 0.0));
-
-  return _header->get_rgb(_alt_color_index, (_flags & F_packed_color) != 0,
-			  _alt_packed_color);
+FltFace(FltHeader *header) : FltGeometry(header) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -151,46 +33,14 @@ extract_record(FltRecordReader &reader) {
   if (!FltBeadID::extract_record(reader)) {
     return false;
   }
-
-  nassertr(reader.get_opcode() == FO_face, false);
-  DatagramIterator &iterator = reader.get_iterator();
-
-  _ir_color = iterator.get_be_int32();
-  _relative_priority = iterator.get_be_int16();
-  _draw_type = (DrawType)iterator.get_int8();
-  _texwhite = (iterator.get_int8() != 0);
-  _color_name_index = iterator.get_be_int16();
-  _alt_color_name_index = iterator.get_be_int16();
-  iterator.skip_bytes(1);
-  _billboard_type = (BillboardType)iterator.get_int8();
-  _detail_texture_index = iterator.get_be_int16();
-  _texture_index = iterator.get_be_int16();
-  _material_index = iterator.get_be_int16();
-  _dfad_material_code = iterator.get_be_int16();
-  _dfad_feature_id = iterator.get_be_int16();
-  _ir_material_code = iterator.get_be_int32();
-  _transparency = iterator.get_be_uint16();
-  _lod_generation_control = iterator.get_uint8();
-  _line_style_index = iterator.get_uint8();
-  _flags = iterator.get_be_uint32();
-  _light_mode = (LightMode)iterator.get_uint8();
-  iterator.skip_bytes(1 + 4);
-  iterator.skip_bytes(2); // Undocumented padding.
-  
-  if (!_packed_color.extract_record(reader)) {
-    return false;
-  }
-  if (!_alt_packed_color.extract_record(reader)) {
+  if (!FltGeometry::extract_record(reader)) {
     return false;
   }
-  
-  _texture_mapping_index = iterator.get_be_int16();
-  iterator.skip_bytes(2);
-  _color_index = iterator.get_be_uint32();
-  _alt_color_index = iterator.get_be_uint32();
-  iterator.skip_bytes(2 + 2);
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  nassertr(reader.get_opcode() == FO_face, false);
+
+  DatagramIterator &iterator = reader.get_iterator();
+  check_remaining_size(iterator);
   return true;
 }
 
@@ -207,44 +57,11 @@ build_record(FltRecordWriter &writer) const {
   if (!FltBeadID::build_record(writer)) {
     return false;
   }
-
-  writer.set_opcode(FO_face);
-  Datagram &datagram = writer.update_datagram();
-
-  datagram.add_be_int32(_ir_color);
-  datagram.add_be_int16(_relative_priority);
-  datagram.add_int8(_draw_type);
-  datagram.add_int8(_texwhite);
-  datagram.add_be_uint16(_color_name_index);
-  datagram.add_be_uint16(_alt_color_name_index);
-  datagram.pad_bytes(1);
-  datagram.add_int8(_billboard_type);
-  datagram.add_be_int16(_detail_texture_index);
-  datagram.add_be_int16(_texture_index);
-  datagram.add_be_int16(_material_index);
-  datagram.add_be_int16(_dfad_material_code);
-  datagram.add_be_int16(_dfad_feature_id);
-  datagram.add_be_int32(_ir_material_code);
-  datagram.add_be_uint16(_transparency);
-  datagram.add_uint8(_lod_generation_control);
-  datagram.add_uint8(_line_style_index);
-  datagram.add_be_uint32(_flags);
-  datagram.add_uint8(_light_mode);
-  datagram.pad_bytes(1 + 4);
-  datagram.pad_bytes(2); // Undocumented padding.
-
-  if (!_packed_color.build_record(writer)) {
-    return false;
-  }
-  if (!_alt_packed_color.build_record(writer)) {
+  if (!FltGeometry::build_record(writer)) {
     return false;
   }
 
-  datagram.add_be_int16(_texture_mapping_index);
-  datagram.pad_bytes(2);
-  datagram.add_be_uint32(_color_index);
-  datagram.add_be_uint32(_alt_color_index);
-  datagram.pad_bytes(2 + 2);
+  writer.set_opcode(FO_face);
 
   return true;
 }

+ 4 - 84
pandatool/src/flt/fltFace.h

@@ -8,96 +8,16 @@
 
 #include <pandatoolbase.h>
 
-#include "fltBeadID.h"
-#include "fltPackedColor.h"
-#include "fltHeader.h"
-
-#include <luse.h>
-
-class FltTexture;
-class FltMaterial;
+#include "fltGeometry.h"
 
 ////////////////////////////////////////////////////////////////////
 // 	 Class : FltFace
 // Description : A single face bead, e.g. a polygon.
 ////////////////////////////////////////////////////////////////////
-class FltFace : public FltBeadID {
+class FltFace : public FltGeometry {
 public:
   FltFace(FltHeader *header);
 
-  enum DrawType {
-    DT_solid_backface      = 0,
-    DT_solid_no_backface   = 1,
-    DT_wireframe           = 2,
-    DT_wireframe_close     = 3,
-    DT_wireframe_highlight = 4,
-    DT_omni_light          = 5,
-    DT_uni_light           = 6,
-    DT_bi_light            = 7
-  };
-
-  enum BillboardType {
-    BT_none                = 0,
-    BT_fixed               = 1,
-    BT_axial               = 2,
-    BT_point               = 4
-  };
-
-  enum Flags {
-    F_terrain              = 0x80000000,
-    F_no_color             = 0x40000000,
-    F_no_alt_color         = 0x20000000,
-    F_packed_color         = 0x10000000,
-    F_terrain_footprint    = 0x08000000,
-    F_hidden               = 0x04000000
-  };
-
-  enum LightMode {
-    LM_face_no_normal      = 0,
-    LM_vertex_no_normal    = 1,
-    LM_face_with_normal    = 2,
-    LM_vertex_with_normal  = 3
-  };
-
-  int _ir_color;
-  int _relative_priority;
-  DrawType _draw_type;
-  bool _texwhite;
-  int _color_name_index;
-  int _alt_color_name_index;
-  BillboardType _billboard_type;
-  int _detail_texture_index;
-  int _texture_index;
-  int _material_index;
-  int _dfad_material_code;
-  int _dfad_feature_id;
-  int _ir_material_code;
-  int _transparency;
-  int _lod_generation_control;
-  int _line_style_index;
-  unsigned int _flags;
-  LightMode _light_mode;
-  FltPackedColor _packed_color;
-  FltPackedColor _alt_packed_color;
-  int _texture_mapping_index;
-  unsigned int _color_index;
-  unsigned int _alt_color_index;
-
-public:
-  INLINE bool has_texture() const;
-  INLINE FltTexture *get_texture() const;
-
-  INLINE bool has_material() const;
-  INLINE FltMaterial *get_material() const;
-
-  INLINE bool has_color() const;
-  Colorf get_color() const;
-  RGBColorf get_rgb() const;
-
-  bool has_alt_color() const;
-  Colorf get_alt_color() const;
-  RGBColorf get_alt_rgb() const;
-
 
 protected:
   virtual bool extract_record(FltRecordReader &reader);
@@ -112,9 +32,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    FltBeadID::init_type();
+    FltGeometry::init_type();
     register_type(_type_handle, "FltFace",
-		  FltBeadID::get_class_type());
+		  FltGeometry::get_class_type());
   }
 
 private:

+ 60 - 0
pandatool/src/flt/fltGeometry.I

@@ -0,0 +1,60 @@
+// Filename: fltGeometry.I
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::has_texture
+//       Access: Public
+//  Description: Returns true if the face has a texture applied, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool FltGeometry::
+has_texture() const {
+  return (_texture_index >= 0 && _header->has_texture(_texture_index));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::get_texture
+//       Access: Public
+//  Description: Returns the texture applied to this face, or NULL if
+//               no texture was applied.
+////////////////////////////////////////////////////////////////////
+INLINE FltTexture *FltGeometry::
+get_texture() const {
+  return _header->get_texture(_texture_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::has_material
+//       Access: Public
+//  Description: Returns true if the face has a material applied, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool FltGeometry::
+has_material() const {
+  return (_material_index >= 0 && _header->has_material(_material_index));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::get_material
+//       Access: Public
+//  Description: Returns the material applied to this face, or NULL if
+//               no material was applied.
+////////////////////////////////////////////////////////////////////
+INLINE FltMaterial *FltGeometry::
+get_material() const {
+  return _header->get_material(_material_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::has_color
+//       Access: Public
+//  Description: Returns true if the face has a primary color
+//               indicated, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool FltGeometry::
+has_color() const {
+  return ((_flags & F_no_color) == 0) || has_material();
+}

+ 239 - 0
pandatool/src/flt/fltGeometry.cxx

@@ -0,0 +1,239 @@
+// Filename: fltGeometry.cxx
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "fltGeometry.h"
+#include "fltRecordReader.h"
+#include "fltRecordWriter.h"
+#include "fltHeader.h"
+#include "fltMaterial.h"
+
+TypeHandle FltGeometry::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltGeometry::
+FltGeometry(FltHeader *header) : FltBeadID(header) {
+  _ir_color = 0;
+  _relative_priority = 0;
+  _draw_type = DT_solid_backface;
+  _texwhite = false;
+  _color_name_index = 0;
+  _alt_color_name_index = 0;
+  _billboard_type = BT_none;
+  _detail_texture_index = -1;
+  _texture_index = -1;
+  _material_index = -1;
+  _dfad_material_code = 0;
+  _dfad_feature_id = 0;
+  _ir_material_code = 0;
+  _transparency = 0;
+  _lod_generation_control = 0;
+  _line_style_index = 0;
+  _flags = 0;
+  _light_mode = LM_face_no_normal;
+  _texture_mapping_index = 0;
+  _color_index = 0;
+  _alt_color_index = 0;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::get_color
+//       Access: Public
+//  Description: If has_color() indicates true, returns the primary
+//               color of the face, as a four-component value
+//               (including alpha as the transparency channel).
+////////////////////////////////////////////////////////////////////
+Colorf FltGeometry::
+get_color() const {
+  nassertr(has_color(), Colorf(0.0, 0.0, 0.0, 0.0));
+
+  if (_texwhite && has_texture()) {
+    // Force this one white.
+    return Colorf(1.0, 1.0, 1.0, 1.0 - (_transparency / 65535.0));
+  }
+
+  if (has_material()) {
+    // If we have a material, that replaces the color.
+    FltMaterial *material = get_material();
+    return Colorf(material->_diffuse[0],
+		  material->_diffuse[1],
+		  material->_diffuse[2],
+		  1.0 - (_transparency / 65535.0));
+  }
+
+  return _header->get_color(_color_index, (_flags & F_packed_color) != 0,
+			    _packed_color, _transparency);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::get_rgb
+//       Access: Public
+//  Description: If has_color() indicates true, returns the primary
+//               color of the face, as a three-component value
+//               ignoring transparency.
+////////////////////////////////////////////////////////////////////
+RGBColorf FltGeometry::
+get_rgb() const {
+  nassertr(has_color(), RGBColorf(0.0, 0.0, 0.0));
+
+  if (_texwhite && has_texture()) {
+    // Force this one white.
+    return RGBColorf(1.0, 1.0, 1.0);
+  }
+
+  if (has_material()) {
+    // If we have a material, that replaces the color.
+    FltMaterial *material = get_material();
+    return material->_diffuse;
+  }
+
+  return _header->get_rgb(_color_index, (_flags & F_packed_color) != 0,
+			  _packed_color);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::has_alt_color
+//       Access: Public
+//  Description: Returns true if the face has an alternate color
+//               indicated, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool FltGeometry::
+has_alt_color() const {
+  return (_flags & F_no_alt_color) == 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::get_alt_color
+//       Access: Public
+//  Description: If has_alt_color() indicates true, returns the alternate
+//               color of the face, as a four-component value
+//               (including alpha as the transparency channel).
+////////////////////////////////////////////////////////////////////
+Colorf FltGeometry::
+get_alt_color() const {
+  nassertr(has_alt_color(), Colorf(0.0, 0.0, 0.0, 0.0));
+
+  return _header->get_color(_alt_color_index, (_flags & F_packed_color) != 0,
+			    _alt_packed_color, _transparency);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::get_alt_rgb
+//       Access: Public
+//  Description: If has_alt_color() indicates true, returns the alternate
+//               color of the face, as a three-component value
+//               ignoring transparency.
+////////////////////////////////////////////////////////////////////
+RGBColorf FltGeometry::
+get_alt_rgb() const {
+  nassertr(has_alt_color(), RGBColorf(0.0, 0.0, 0.0));
+
+  return _header->get_rgb(_alt_color_index, (_flags & F_packed_color) != 0,
+			  _alt_packed_color);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::extract_record
+//       Access: Protected, Virtual
+//  Description: Fills in the information in this bead based on the
+//               information given in the indicated datagram, whose
+//               opcode has already been read.  Returns true on
+//               success, false if the datagram is invalid.
+////////////////////////////////////////////////////////////////////
+bool FltGeometry::
+extract_record(FltRecordReader &reader) {
+  DatagramIterator &iterator = reader.get_iterator();
+
+  _ir_color = iterator.get_be_int32();
+  _relative_priority = iterator.get_be_int16();
+  _draw_type = (DrawType)iterator.get_int8();
+  _texwhite = (iterator.get_int8() != 0);
+  _color_name_index = iterator.get_be_int16();
+  _alt_color_name_index = iterator.get_be_int16();
+  iterator.skip_bytes(1);
+  _billboard_type = (BillboardType)iterator.get_int8();
+  _detail_texture_index = iterator.get_be_int16();
+  _texture_index = iterator.get_be_int16();
+  _material_index = iterator.get_be_int16();
+  _dfad_material_code = iterator.get_be_int16();
+  _dfad_feature_id = iterator.get_be_int16();
+  _ir_material_code = iterator.get_be_int32();
+  _transparency = iterator.get_be_uint16();
+  _lod_generation_control = iterator.get_uint8();
+  _line_style_index = iterator.get_uint8();
+  _flags = iterator.get_be_uint32();
+  _light_mode = (LightMode)iterator.get_uint8();
+  iterator.skip_bytes(1 + 4);
+  iterator.skip_bytes(2); // Undocumented padding.
+  
+  if (!_packed_color.extract_record(reader)) {
+    return false;
+  }
+  if (!_alt_packed_color.extract_record(reader)) {
+    return false;
+  }
+  
+  _texture_mapping_index = iterator.get_be_int16();
+  iterator.skip_bytes(2);
+  _color_index = iterator.get_be_uint32();
+  _alt_color_index = iterator.get_be_uint32();
+  iterator.skip_bytes(2 + 2);
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::build_record
+//       Access: Protected, Virtual
+//  Description: Fills up the current record on the FltRecordWriter with
+//               data for this record, but does not advance the
+//               writer.  Returns true on success, false if there is
+//               some error.
+////////////////////////////////////////////////////////////////////
+bool FltGeometry::
+build_record(FltRecordWriter &writer) const {
+  Datagram &datagram = writer.update_datagram();
+
+  datagram.add_be_int32(_ir_color);
+  datagram.add_be_int16(_relative_priority);
+  datagram.add_int8(_draw_type);
+  datagram.add_int8(_texwhite);
+  datagram.add_be_uint16(_color_name_index);
+  datagram.add_be_uint16(_alt_color_name_index);
+  datagram.pad_bytes(1);
+  datagram.add_int8(_billboard_type);
+  datagram.add_be_int16(_detail_texture_index);
+  datagram.add_be_int16(_texture_index);
+  datagram.add_be_int16(_material_index);
+  datagram.add_be_int16(_dfad_material_code);
+  datagram.add_be_int16(_dfad_feature_id);
+  datagram.add_be_int32(_ir_material_code);
+  datagram.add_be_uint16(_transparency);
+  datagram.add_uint8(_lod_generation_control);
+  datagram.add_uint8(_line_style_index);
+  datagram.add_be_uint32(_flags);
+  datagram.add_uint8(_light_mode);
+  datagram.pad_bytes(1 + 4);
+  datagram.pad_bytes(2); // Undocumented padding.
+
+  if (!_packed_color.build_record(writer)) {
+    return false;
+  }
+  if (!_alt_packed_color.build_record(writer)) {
+    return false;
+  }
+
+  datagram.add_be_int16(_texture_mapping_index);
+  datagram.pad_bytes(2);
+  datagram.add_be_uint32(_color_index);
+  datagram.add_be_uint32(_alt_color_index);
+  datagram.pad_bytes(2 + 2);
+
+  return true;
+}

+ 131 - 0
pandatool/src/flt/fltGeometry.h

@@ -0,0 +1,131 @@
+// Filename: fltGeometry.h
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLTGEOMETRY_H
+#define FLTGEOMETRY_H
+
+#include <pandatoolbase.h>
+
+#include "fltBeadID.h"
+#include "fltPackedColor.h"
+#include "fltHeader.h"
+
+#include <luse.h>
+
+class FltTexture;
+class FltMaterial;
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : FltGeometry
+// Description : This is a base class for both FltFace and FltMesh,
+//               which are two different kinds of geometric primitives
+//               that might be encountered in a MultiGen file.  They
+//               have similar properties.
+////////////////////////////////////////////////////////////////////
+class FltGeometry : public FltBeadID {
+public:
+  FltGeometry(FltHeader *header);
+
+  enum DrawType {
+    DT_solid_backface      = 0,
+    DT_solid_no_backface   = 1,
+    DT_wireframe           = 2,
+    DT_wireframe_close     = 3,
+    DT_wireframe_highlight = 4,
+    DT_omni_light          = 5,
+    DT_uni_light           = 6,
+    DT_bi_light            = 7
+  };
+
+  enum BillboardType {
+    BT_none                = 0,
+    BT_fixed               = 1,
+    BT_axial               = 2,
+    BT_point               = 4
+  };
+
+  enum Flags {
+    F_terrain              = 0x80000000,
+    F_no_color             = 0x40000000,
+    F_no_alt_color         = 0x20000000,
+    F_packed_color         = 0x10000000,
+    F_terrain_footprint    = 0x08000000,
+    F_hidden               = 0x04000000
+  };
+
+  enum LightMode {
+    LM_face_no_normal      = 0,
+    LM_vertex_no_normal    = 1,
+    LM_face_with_normal    = 2,
+    LM_vertex_with_normal  = 3
+  };
+
+  int _ir_color;
+  int _relative_priority;
+  DrawType _draw_type;
+  bool _texwhite;
+  int _color_name_index;
+  int _alt_color_name_index;
+  BillboardType _billboard_type;
+  int _detail_texture_index;
+  int _texture_index;
+  int _material_index;
+  int _dfad_material_code;
+  int _dfad_feature_id;
+  int _ir_material_code;
+  int _transparency;
+  int _lod_generation_control;
+  int _line_style_index;
+  unsigned int _flags;
+  LightMode _light_mode;
+  FltPackedColor _packed_color;
+  FltPackedColor _alt_packed_color;
+  int _texture_mapping_index;
+  unsigned int _color_index;
+  unsigned int _alt_color_index;
+
+public:
+  INLINE bool has_texture() const;
+  INLINE FltTexture *get_texture() const;
+
+  INLINE bool has_material() const;
+  INLINE FltMaterial *get_material() const;
+
+  INLINE bool has_color() const;
+  Colorf get_color() const;
+  RGBColorf get_rgb() const;
+
+  bool has_alt_color() const;
+  Colorf get_alt_color() const;
+  RGBColorf get_alt_rgb() const;
+
+
+protected:
+  virtual bool extract_record(FltRecordReader &reader);
+  virtual bool build_record(FltRecordWriter &writer) const;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    FltBeadID::init_type();
+    register_type(_type_handle, "FltGeometry",
+		  FltBeadID::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "fltGeometry.I"
+
+#endif
+
+

+ 1 - 1
pandatool/src/flt/fltGroup.cxx

@@ -50,7 +50,7 @@ extract_record(FltRecordReader &reader) {
   _layer_id = iterator.get_int8();
   iterator.skip_bytes(5);
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 52 - 12
pandatool/src/flt/fltHeader.cxx

@@ -20,8 +20,8 @@ TypeHandle FltHeader::_type_handle;
 ////////////////////////////////////////////////////////////////////
 FltHeader::
 FltHeader() : FltBeadID(this) {
-  _format_revision_level = 1520;
-  _edit_revision_level = 1520;
+  _format_revision_level = 1570;
+  _edit_revision_level = 1570;
   _next_group_id = 1;
   _next_lod_id = 1;
   _next_object_id = 1;
@@ -57,6 +57,15 @@ FltHeader() : FltBeadID(this) {
   _next_cat_id = 1;
   _earth_model = EM_wgs84;
 
+  // New with 15.6
+  _next_adaptive_id = 0;
+  _next_curve_id = 0;
+
+  // New with 15.7
+  _delta_z = 0.0;
+  _radius = 0.0;
+  _next_mesh_id = 0;
+
   _vertex_lookups_stale = false;
   _current_vertex_offset = 0;
   _got_color_palette = false;
@@ -239,15 +248,15 @@ min_flt_version() {
 ////////////////////////////////////////////////////////////////////
 double FltHeader::
 max_flt_version() {
-  return 15.2;
+  return 15.7;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: FltHeader::check_version
 //       Access: Public
 //  Description: Verifies that the version number read from the header
-//               is an understand version number, and prints a warning
-//               to the user if this is not so--the reading may or may
+//               is an understood version number, and prints a warning
+//               to the user if this is not so--the read may or may
 //               not succeed.  Returns true if the version number is
 //               acceptable (and no warning is printed), or false if
 //               it is questionable (and a warning is printed).
@@ -593,7 +602,7 @@ get_closest_color(Colorf color) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: FltHeader::get_closest_color
+//     Function: FltHeader::get_closest_rgb
 //       Access: Public
 //  Description: Returns the color index of the nearest color in the
 //               palette that matches the given three-component color,
@@ -1144,10 +1153,26 @@ extract_record(FltRecordReader &reader) {
   iterator.skip_bytes(2 + 2 + 2 + 2);
   _earth_model = (EarthModel)iterator.get_be_int32();
 
-  // Undocumented additional padding.
+  // Undocumented padding.
   iterator.skip_bytes(4);
 
-  //  nassertr(iterator.get_remaining_size() == 0, true);
+  if (get_flt_version() >= 15.6 && iterator.get_remaining_size() > 0) {
+    _next_adaptive_id = iterator.get_be_int16();
+    _next_curve_id = iterator.get_be_int16();
+    iterator.skip_bytes(4);
+    
+    if (get_flt_version() >= 15.7 && iterator.get_remaining_size() > 0) {
+      _delta_z = iterator.get_be_float64();
+      _radius = iterator.get_be_float64();
+      _next_mesh_id = iterator.get_be_int16();
+      iterator.skip_bytes(2);
+
+      // Undocumented padding.
+      iterator.skip_bytes(4);
+    }
+  }
+
+  check_remaining_size(iterator);
   return true;
 }
 
@@ -1260,8 +1285,23 @@ build_record(FltRecordWriter &writer) const {
   datagram.pad_bytes(2 + 2 + 2 + 2);
   datagram.add_be_int32(_earth_model);
 
-  // Undocumented additional padding.
-  datagram.pad_bytes(4);
+  datagram.pad_bytes(4);    
+
+  if (get_flt_version() >= 15.6) {
+    // New with 15.6
+    datagram.add_be_int16(_next_adaptive_id);
+    datagram.add_be_int16(_next_curve_id);
+    datagram.pad_bytes(4);
+
+    if (get_flt_version() >= 15.7) {
+      // New with 15.7
+      datagram.add_be_float64(_delta_z);
+      datagram.add_be_float64(_radius);
+      datagram.add_be_int16(_next_mesh_id);
+      datagram.pad_bytes(2);
+      datagram.pad_bytes(4);
+    }
+  }
 
   return true;
 }
@@ -1377,7 +1417,7 @@ extract_color_palette(FltRecordReader &reader) {
     _color_names[color_index] = iterator.get_fixed_string(name_length);
   }
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 
@@ -1479,7 +1519,7 @@ extract_eyepoint_palette(FltRecordReader &reader) {
   }
 
   _got_eyepoint_trackplane_palette = true;
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 5 - 0
pandatool/src/flt/fltHeader.h

@@ -120,6 +120,11 @@ public:
   int _next_road_id;
   int _next_cat_id;
   EarthModel _earth_model;
+  int _next_adaptive_id;
+  int _next_curve_id;
+  double _delta_z;
+  double _radius;
+  int _next_mesh_id;
 
 public:
   double get_flt_version() const;

+ 1 - 1
pandatool/src/flt/fltInstanceDefinition.cxx

@@ -39,7 +39,7 @@ extract_record(FltRecordReader &reader) {
   iterator.skip_bytes(2);
   _instance_index = iterator.get_be_int16();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltInstanceRef.cxx

@@ -61,7 +61,7 @@ extract_record(FltRecordReader &reader) {
   iterator.skip_bytes(2);
   _instance_index = iterator.get_be_int16();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltLOD.cxx

@@ -55,7 +55,7 @@ extract_record(FltRecordReader &reader) {
   _center_z = iterator.get_be_float64();
   _transition_range = iterator.get_be_float64();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltLightSourceDefinition.cxx

@@ -76,7 +76,7 @@ extract_record(FltRecordReader &reader) {
   _modeling_light = (iterator.get_be_int32() != 0);
   iterator.skip_bytes(4*19);
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 4 - 0
pandatool/src/flt/fltLocalVertexPool.I

@@ -0,0 +1,4 @@
+// Filename: fltLocalVertexPool.I
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////

+ 235 - 0
pandatool/src/flt/fltLocalVertexPool.cxx

@@ -0,0 +1,235 @@
+// Filename: fltLocalVertexPool.cxx
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "fltLocalVertexPool.h"
+#include "fltRecordReader.h"
+#include "fltRecordWriter.h"
+#include "fltHeader.h"
+#include "fltMaterial.h"
+
+TypeHandle FltLocalVertexPool::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltLocalVertexPool::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltLocalVertexPool::
+FltLocalVertexPool(FltHeader *header) : FltRecord(header) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltLocalVertexPool::extract_record
+//       Access: Protected, Virtual
+//  Description: Fills in the information in this bead based on the
+//               information given in the indicated datagram, whose
+//               opcode has already been read.  Returns true on
+//               success, false if the datagram is invalid.
+////////////////////////////////////////////////////////////////////
+bool FltLocalVertexPool::
+extract_record(FltRecordReader &reader) {
+  if (!FltRecord::extract_record(reader)) {
+    return false;
+  }
+
+  nassertr(reader.get_opcode() == FO_local_vertex_pool, false);
+  DatagramIterator &iterator = reader.get_iterator();
+
+  int num_vertices = iterator.get_be_int32();
+  int attributes = iterator.get_be_int32();
+
+  for (int i = 0; i < num_vertices; i++) {
+    FltVertex *vertex = new FltVertex(_header);
+    _vertices.push_back(vertex);
+
+    if ((attributes & AM_has_position) != 0) {
+      vertex->_pos[0] = iterator.get_be_float64();
+      vertex->_pos[1] = iterator.get_be_float64();
+      vertex->_pos[2] = iterator.get_be_float64();
+    }
+
+    if ((attributes & AM_has_color_index) != 0) {
+      vertex->_color_index = iterator.get_be_int32();
+
+    } else if ((attributes & AM_has_packed_color) != 0) {
+      if (!vertex->_packed_color.extract_record(reader)) {
+	return false;
+      }
+      vertex->_flags |= FltVertex::F_packed_color;
+
+    } else {
+      vertex->_flags |= FltVertex::F_no_color;
+    }
+
+    if ((attributes & AM_has_normal) != 0) {
+      vertex->_normal[0] = iterator.get_be_float32();
+      vertex->_normal[1] = iterator.get_be_float32();
+      vertex->_normal[2] = iterator.get_be_float32();
+      vertex->_has_normal = true;
+    }
+
+    if ((attributes & AM_has_base_uv) != 0) {
+      vertex->_uv[0] = iterator.get_be_float32();
+      vertex->_uv[1] = iterator.get_be_float32();
+      vertex->_has_uv = true;
+    }
+
+    if ((attributes & AM_has_uv_1) != 0) {
+      iterator.get_be_float32();
+      iterator.get_be_float32();
+    }
+
+    if ((attributes & AM_has_uv_2) != 0) {
+      iterator.get_be_float32();
+      iterator.get_be_float32();
+    }
+
+    if ((attributes & AM_has_uv_3) != 0) {
+      iterator.get_be_float32();
+      iterator.get_be_float32();
+    }
+
+    if ((attributes & AM_has_uv_4) != 0) {
+      iterator.get_be_float32();
+      iterator.get_be_float32();
+    }
+
+    if ((attributes & AM_has_uv_5) != 0) {
+      iterator.get_be_float32();
+      iterator.get_be_float32();
+    }
+
+    if ((attributes & AM_has_uv_6) != 0) {
+      iterator.get_be_float32();
+      iterator.get_be_float32();
+    }
+
+    if ((attributes & AM_has_uv_7) != 0) {
+      iterator.get_be_float32();
+      iterator.get_be_float32();
+    }
+  }
+
+  check_remaining_size(iterator);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltLocalVertexPool::build_record
+//       Access: Protected, Virtual
+//  Description: Fills up the current record on the FltRecordWriter with
+//               data for this record, but does not advance the
+//               writer.  Returns true on success, false if there is
+//               some error.
+////////////////////////////////////////////////////////////////////
+bool FltLocalVertexPool::
+build_record(FltRecordWriter &writer) const {
+  if (!FltRecord::build_record(writer)) {
+    return false;
+  }
+
+  writer.set_opcode(FO_local_vertex_pool);
+  Datagram &datagram = writer.update_datagram();
+
+  // Determine what kind of vertices we have.
+  int attributes = AM_has_position;
+
+  Vertices::const_iterator vi;
+  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
+    FltVertex *vertex = (*vi);
+    if ((vertex->_flags & FltVertex::F_no_color) != 0) {
+      // No color.
+
+    } else if ((vertex->_flags & FltVertex::F_packed_color) != 0) {
+      // Packed color.
+      attributes |= AM_has_packed_color;
+
+    } else {
+      // Indexed color.
+      attributes |= AM_has_color_index;
+    }
+
+    if (vertex->_has_normal) {
+      attributes |= AM_has_normal;
+    }
+
+    if (vertex->_has_uv) {
+      attributes |= AM_has_base_uv;
+    }
+  }
+
+  if ((attributes & AM_has_packed_color) != 0 &&
+      (attributes & AM_has_color_index) != 0) {
+    // We cannot have both a packed color and a color index.  If we
+    // want both, used packed color.
+    attributes &= ~AM_has_color_index;
+  }
+
+  datagram.add_be_int32(_vertices.size());
+  datagram.add_be_int32(attributes);
+
+  // Now write out each vertex.
+  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
+    FltVertex *vertex = (*vi);
+
+    if ((attributes & AM_has_position) != 0) {
+      datagram.add_be_float64(vertex->_pos[0]);
+      datagram.add_be_float64(vertex->_pos[1]);
+      datagram.add_be_float64(vertex->_pos[2]);
+    }
+
+    if ((attributes & AM_has_color_index) != 0) {
+      if ((vertex->_flags & (FltVertex::F_no_color | FltVertex::F_packed_color)) != 0) {
+	// This particular vertex does not have a color index.
+	// Make it white.
+	datagram.add_be_int32(_header->get_closest_rgb(RGBColorf(1.0, 1.0, 1.0)));
+      } else {
+	datagram.add_be_int32(vertex->_color_index);
+      }
+
+    } else if ((attributes & AM_has_packed_color) != 0) {
+      // We extract our own FltPackedColor instead of writing out the
+      // vertex's _packed_color directly, just in case the vertex is
+      // actually index colored.  This bit of code will work
+      // regardless of the kind of color the vertex has.
+
+      FltPackedColor color;
+      if (vertex->has_color()) {
+	color.set_color(vertex->get_color());
+      } else {
+	// An uncolored vertex.  Make it white.
+	color.set_color(Colorf(1.0, 1.0, 1.0, 1.0));
+      }
+
+      if (!color.build_record(writer)) {
+	return false;
+      }
+    }
+
+    if ((attributes & AM_has_normal) != 0) {
+      if (!vertex->_has_normal) {
+	datagram.add_be_float32(0.0);
+	datagram.add_be_float32(0.0);
+	datagram.add_be_float32(0.0);
+      } else {
+	datagram.add_be_float32(vertex->_normal[0]);
+	datagram.add_be_float32(vertex->_normal[1]);
+	datagram.add_be_float32(vertex->_normal[2]);
+      }
+    }
+
+    if ((attributes & AM_has_base_uv) != 0) {
+      if (!vertex->_has_uv) {
+	datagram.add_be_float32(0.0);
+	datagram.add_be_float32(0.0);
+      } else {
+	datagram.add_be_float32(vertex->_uv[0]);
+	datagram.add_be_float32(vertex->_uv[1]);
+      }
+    }
+  }
+
+  return true;
+}

+ 72 - 0
pandatool/src/flt/fltLocalVertexPool.h

@@ -0,0 +1,72 @@
+// Filename: fltLocalVertexPool.h
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLTLOCALVERTEXPOOL_H
+#define FLTLOCALVERTEXPOOL_H
+
+#include <pandatoolbase.h>
+
+#include "fltRecord.h"
+#include "fltHeader.h"
+#include "fltVertex.h"
+
+#include <pointerTo.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : FltLocalVertexPool
+// Description : A local vertex pool, as might appear in the middle of
+//               the hierarchy, for instance for a mesh.
+////////////////////////////////////////////////////////////////////
+class FltLocalVertexPool : public FltRecord {
+public:
+  FltLocalVertexPool(FltHeader *header);
+
+  // These bits are not stored in the vertex pool, but are read from
+  // the .flt file and used immediately.
+  enum AttributeMask {
+    AM_has_position      = 0x80000000,
+    AM_has_color_index   = 0x40000000,
+    AM_has_packed_color  = 0x20000000,
+    AM_has_normal        = 0x10000000,
+    AM_has_base_uv       = 0x08000000,
+    AM_has_uv_1          = 0x04000000,
+    AM_has_uv_2          = 0x02000000,
+    AM_has_uv_3          = 0x01000000,
+    AM_has_uv_4          = 0x00800000,
+    AM_has_uv_5          = 0x00400000,
+    AM_has_uv_6          = 0x00200000,
+    AM_has_uv_7          = 0x00100000
+  };
+
+  typedef vector<PT(FltVertex)> Vertices;
+  Vertices _vertices;
+
+public:
+  virtual bool extract_record(FltRecordReader &reader);
+  virtual bool build_record(FltRecordWriter &writer) const;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    FltRecord::init_type();
+    register_type(_type_handle, "FltLocalVertexPool",
+		  FltRecord::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "fltLocalVertexPool.I"
+
+#endif
+
+

+ 1 - 1
pandatool/src/flt/fltMaterial.cxx

@@ -62,7 +62,7 @@ extract_record(FltRecordReader &reader) {
   _alpha = iterator.get_be_float32();
   iterator.skip_bytes(4);
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 4 - 0
pandatool/src/flt/fltMesh.I

@@ -0,0 +1,4 @@
+// Filename: fltMesh.I
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////

+ 118 - 0
pandatool/src/flt/fltMesh.cxx

@@ -0,0 +1,118 @@
+// Filename: fltMesh.cxx
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "fltMesh.h"
+#include "fltRecordReader.h"
+#include "fltRecordWriter.h"
+#include "fltHeader.h"
+#include "fltMaterial.h"
+#include "config_flt.h"
+
+TypeHandle FltMesh::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMesh::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltMesh::
+FltMesh(FltHeader *header) : FltGeometry(header) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMesh::extract_record
+//       Access: Protected, Virtual
+//  Description: Fills in the information in this bead based on the
+//               information given in the indicated datagram, whose
+//               opcode has already been read.  Returns true on
+//               success, false if the datagram is invalid.
+////////////////////////////////////////////////////////////////////
+bool FltMesh::
+extract_record(FltRecordReader &reader) {
+  if (!FltBeadID::extract_record(reader)) {
+    return false;
+  }
+
+  DatagramIterator &iterator = reader.get_iterator();
+  iterator.skip_bytes(4); // Undocumented padding.
+
+  if (!FltGeometry::extract_record(reader)) {
+    return false;
+  }
+
+  nassertr(reader.get_opcode() == FO_mesh, false);
+
+  check_remaining_size(iterator);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMesh::extract_ancillary
+//       Access: Protected, Virtual
+//  Description: Checks whether the given bead, which follows this
+//               bead sequentially in the file, is an ancillary record
+//               of this bead.  If it is, extracts the relevant
+//               information and returns true; otherwise, leaves it
+//               alone and returns false.
+////////////////////////////////////////////////////////////////////
+bool FltMesh::
+extract_ancillary(FltRecordReader &reader) {
+  if (reader.get_opcode() == FO_local_vertex_pool) {
+    _vpool = new FltLocalVertexPool(_header);
+    return _vpool->extract_record(reader);
+  }
+
+  return FltBeadID::extract_ancillary(reader);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMesh::build_record
+//       Access: Protected, Virtual
+//  Description: Fills up the current record on the FltRecordWriter with
+//               data for this record, but does not advance the
+//               writer.  Returns true on success, false if there is
+//               some error.
+////////////////////////////////////////////////////////////////////
+bool FltMesh::
+build_record(FltRecordWriter &writer) const {
+  if (!FltBeadID::build_record(writer)) {
+    return false;
+  }
+
+  Datagram &datagram = writer.update_datagram();
+  datagram.pad_bytes(4); // Undocumented padding.
+
+  if (!FltGeometry::build_record(writer)) {
+    return false;
+  }
+
+  writer.set_opcode(FO_mesh);
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMesh::write_ancillary
+//       Access: Protected, Virtual
+//  Description: Writes whatever ancillary records are required for
+//               this record.  Returns FE_ok on success, or something
+//               else if there is some error.
+////////////////////////////////////////////////////////////////////
+FltError FltMesh::
+write_ancillary(FltRecordWriter &writer) const {
+  if (_vpool != (FltLocalVertexPool *)NULL) {
+    if (!_vpool->build_record(writer)) {
+      assert(!flt_error_abort);
+      return FE_bad_data;
+    }
+    FltError result = writer.advance();
+    if (result != FE_ok) {
+      return result;
+    }
+  }
+  
+  return FltBeadID::write_ancillary(writer);
+}
+

+ 56 - 0
pandatool/src/flt/fltMesh.h

@@ -0,0 +1,56 @@
+// Filename: fltMesh.h
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLTMESH_H
+#define FLTMESH_H
+
+#include <pandatoolbase.h>
+
+#include "fltGeometry.h"
+#include "fltLocalVertexPool.h"
+
+#include <pointerTo.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : FltMesh
+// Description : A mesh of connected polygons and tristrips, etc.,
+//               with a local vertex pool.
+////////////////////////////////////////////////////////////////////
+class FltMesh : public FltGeometry {
+public:
+  FltMesh(FltHeader *header);
+
+  PT(FltLocalVertexPool) _vpool;
+
+protected:
+  virtual bool extract_record(FltRecordReader &reader);
+  virtual bool extract_ancillary(FltRecordReader &reader);
+
+  virtual bool build_record(FltRecordWriter &writer) const;
+  virtual FltError write_ancillary(FltRecordWriter &writer) const;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    FltGeometry::init_type();
+    register_type(_type_handle, "FltMesh",
+		  FltGeometry::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "fltMesh.I"
+
+#endif
+
+

+ 4 - 0
pandatool/src/flt/fltMeshPrimitive.I

@@ -0,0 +1,4 @@
+// Filename: fltMeshPrimitive.I
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////

+ 127 - 0
pandatool/src/flt/fltMeshPrimitive.cxx

@@ -0,0 +1,127 @@
+// Filename: fltMeshPrimitive.cxx
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "fltMeshPrimitive.h"
+#include "fltRecordReader.h"
+#include "fltRecordWriter.h"
+#include "fltHeader.h"
+#include "fltMaterial.h"
+
+TypeHandle FltMeshPrimitive::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMeshPrimitive::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltMeshPrimitive::
+FltMeshPrimitive(FltHeader *header) : FltBead(header) {
+  _primitive_type = PT_tristrip;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMeshPrimitive::extract_record
+//       Access: Protected, Virtual
+//  Description: Fills in the information in this bead based on the
+//               information given in the indicated datagram, whose
+//               opcode has already been read.  Returns true on
+//               success, false if the datagram is invalid.
+////////////////////////////////////////////////////////////////////
+bool FltMeshPrimitive::
+extract_record(FltRecordReader &reader) {
+  if (!FltBead::extract_record(reader)) {
+    return false;
+  }
+
+  nassertr(reader.get_opcode() == FO_mesh_primitive, false);
+  DatagramIterator &iterator = reader.get_iterator();
+
+  _primitive_type = (PrimitiveType)iterator.get_be_int16();
+
+  int vertex_width = iterator.get_be_int16();
+  int num_vertices = iterator.get_be_int32();
+
+  if (vertex_width == 1) {
+    for (int i = 0; i < num_vertices; i++) {
+      _vertices.push_back(iterator.get_uint8());
+    }
+
+  } else if (vertex_width == 2) {
+    for (int i = 0; i < num_vertices; i++) {
+      _vertices.push_back(iterator.get_be_uint16());
+    }
+
+  } else if (vertex_width == 4) {
+    for (int i = 0; i < num_vertices; i++) {
+      _vertices.push_back(iterator.get_be_int32());
+    }
+
+  } else {
+    nout << "Invalid vertex width in mesh primitive: " << vertex_width
+	 << "\n";
+    return false;
+  }
+
+  check_remaining_size(iterator);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltMeshPrimitive::build_record
+//       Access: Protected, Virtual
+//  Description: Fills up the current record on the FltRecordWriter with
+//               data for this record, but does not advance the
+//               writer.  Returns true on success, false if there is
+//               some error.
+////////////////////////////////////////////////////////////////////
+bool FltMeshPrimitive::
+build_record(FltRecordWriter &writer) const {
+  if (!FltBead::build_record(writer)) {
+    return false;
+  }
+
+  writer.set_opcode(FO_mesh_primitive);
+  Datagram &datagram = writer.update_datagram();
+
+  datagram.add_be_int16(_primitive_type);
+
+  // Determine the optimum index width, based on the largest vertex
+  // index.
+  int max_index = 0;
+  Vertices::const_iterator vi;
+  for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
+    max_index = max(max_index, (*vi));
+  }
+
+  int vertex_width;
+  if (max_index < 0x100) {
+    vertex_width = 1;
+  } else if (max_index < 0x10000) {
+    vertex_width = 2;
+  } else {
+    vertex_width = 4;
+  }
+
+  datagram.add_be_int16(vertex_width);
+  datagram.add_be_int32(_vertices.size());
+
+  if (vertex_width == 1) {
+    for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
+      datagram.add_uint8(*vi);
+    }
+
+  } else if (vertex_width == 2) {
+    for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
+      datagram.add_be_uint16(*vi);
+    }
+
+  } else {
+    for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
+      datagram.add_be_int32(*vi);
+    }
+  }
+
+  return true;
+}

+ 64 - 0
pandatool/src/flt/fltMeshPrimitive.h

@@ -0,0 +1,64 @@
+// Filename: fltMeshPrimitive.h
+// Created by:  drose (28Feb01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLTMESHPRIMITIVE_H
+#define FLTMESHPRIMITIVE_H
+
+#include <pandatoolbase.h>
+
+#include "fltBead.h"
+#include "fltHeader.h"
+
+#include <luse.h>
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : FltMeshPrimitive
+// Description : A single primitive of a mesh, like a triangle strip
+//               or fan.
+////////////////////////////////////////////////////////////////////
+class FltMeshPrimitive : public FltBead {
+public:
+  FltMeshPrimitive(FltHeader *header);
+
+  enum PrimitiveType {
+    PT_tristrip            = 1,
+    PT_trifan              = 2,
+    PT_quadstrip           = 3,
+    PT_polygon             = 4,
+  };
+
+  typedef vector<int> Vertices;
+
+  PrimitiveType _primitive_type;
+  Vertices _vertices;
+
+
+protected:
+  virtual bool extract_record(FltRecordReader &reader);
+  virtual bool build_record(FltRecordWriter &writer) const;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    FltBead::init_type();
+    register_type(_type_handle, "FltMeshPrimitive",
+		  FltBead::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "fltMeshPrimitive.I"
+
+#endif
+
+

+ 1 - 1
pandatool/src/flt/fltObject.cxx

@@ -43,7 +43,7 @@ extract_record(FltRecordReader &reader) {
   _significance = iterator.get_be_int16();
   iterator.skip_bytes(2);
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 38 - 2
pandatool/src/flt/fltOpcode.cxx

@@ -69,6 +69,15 @@ operator << (ostream &out, FltOpcode opcode) {
   case FO_pop_face:
     return out << "pop subface";
 
+  case FO_push_extension:
+    return out << "push extension";
+
+  case FO_pop_extension:
+    return out << "pop extension";
+
+  case FO_continuation:
+    return out << "continuation";
+
   case FO_comment:
     return out << "comment";
 
@@ -103,6 +112,12 @@ operator << (ostream &out, FltOpcode opcode) {
   case FO_vector:
     return out << "vector";
 
+  case FO_multitexture:
+    return out << "multitexture";
+
+  case FO_uv_list:
+    return out << "UV list";
+
   case FO_bsp:
     return out << "BSP";
 
@@ -172,6 +187,15 @@ operator << (ostream &out, FltOpcode opcode) {
   case FO_eyepoint_palette:
     return out << "eyepoint palette";
 
+  case FO_mesh:
+    return out << "mesh";
+
+  case FO_local_vertex_pool:
+    return out << "local vertex pool";
+
+  case FO_mesh_primitive:
+    return out << "mesh primitive";
+
   case FO_road_segment:
     return out << "road segment";
 
@@ -226,14 +250,17 @@ operator << (ostream &out, FltOpcode opcode) {
   case FO_bv_orientation:
     return out << "bounding volume orientation";
 
+  case FO_light_point:
+    return out << "light point";
+
   case FO_texture_map_palette:
     return out << "texture mapping palette";
 
   case FO_15_material:
     return out << "material";
 
-  case FO_color_name_palette:
-    return out << "color name palette";
+  case FO_name_table:
+    return out << "name table";
 
   case FO_cat:
     return out << "continuously adaptive terrain";
@@ -247,6 +274,15 @@ operator << (ostream &out, FltOpcode opcode) {
   case FO_pop_attribute:
     return out << "pop attribute";
 
+  case FO_adaptive_attribute:
+    return out << "adaptive attribute";
+
+  case FO_curve:
+    return out << "curve";
+
+  case FO_road_construction:
+    return out << "road construction";
+
   default:
     return out << "unknown opcode " << (int)opcode;
   }

+ 15 - 1
pandatool/src/flt/fltOpcode.h

@@ -29,6 +29,10 @@ enum FltOpcode {
   FO_OB_instance         = 17,   // obsolete
   FO_push_face           = 19,
   FO_pop_face            = 20,
+  FO_push_extension      = 21,
+  FO_pop_extension       = 22,
+  FO_continuation        = 23,
+
   FO_comment             = 31,
   FO_color_palette       = 32,
   FO_long_id             = 33,
@@ -44,6 +48,8 @@ enum FltOpcode {
   FO_transform_matrix    = 49,
   FO_vector              = 50,
   FO_OB_bounding_box     = 51,   // obsolete
+  FO_multitexture        = 52,
+  FO_uv_list             = 53,
   FO_bsp                 = 55,
   FO_replicate           = 60,
   FO_instance_ref        = 61,
@@ -68,6 +74,9 @@ enum FltOpcode {
   FO_rotate_and_scale    = 81,
   FO_put                 = 82,
   FO_eyepoint_palette    = 83,
+  FO_mesh                = 84,
+  FO_local_vertex_pool   = 85,
+  FO_mesh_primitive      = 86,
   FO_road_segment        = 87,
   FO_road_zone           = 88,
   FO_morph_list          = 89,
@@ -80,19 +89,24 @@ enum FltOpcode {
   FO_switch              = 96,
   FO_line_style          = 97,
   FO_clip_region         = 98,
+  FO_extension           = 100,
   FO_light_source        = 101,
   FO_light_definition    = 102,
   FO_bounding_sphere     = 105,
   FO_bounding_cylinder   = 106,
   FO_bv_center           = 108,
   FO_bv_orientation      = 109,
+  FO_light_point         = 111,
   FO_texture_map_palette = 112,
   FO_15_material         = 113,
-  FO_color_name_palette  = 114,
+  FO_name_table          = 114,
   FO_cat                 = 115,
   FO_cat_data            = 116,
   FO_push_attribute      = 122,
   FO_pop_attribute       = 123,
+  FO_adaptive_attribute  = 125,
+  FO_curve               = 126,
+  FO_road_construction   = 127
 };
 
 ostream &operator << (ostream &out, FltOpcode opcode);

+ 29 - 0
pandatool/src/flt/fltPackedColor.I

@@ -45,3 +45,32 @@ INLINE RGBColorf FltPackedColor::
 get_rgb() const {
   return RGBColorf(_r / 255.0, _g / 255.0, _b / 255.0);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltPackedColor::set_color
+//       Access: Public
+//  Description: Sets the color according to the indicated
+//               four-component Colorf value (including alpha).
+////////////////////////////////////////////////////////////////////
+INLINE void FltPackedColor::
+set_color(const Colorf &color) {
+  _r = (int)floor(color[0] * 255.0);
+  _g = (int)floor(color[0] * 255.0);
+  _b = (int)floor(color[0] * 255.0);
+  _a = (int)floor(color[0] * 255.0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltPackedColor::set_rgb
+//       Access: Public
+//  Description: Sets the color according to the indicated
+//               three-component RGBColorf value, and set the alpha to
+//               1.0.
+////////////////////////////////////////////////////////////////////
+INLINE void FltPackedColor::
+set_rgb(const RGBColorf &color) {
+  _r = (int)floor(color[0] * 255.0);
+  _g = (int)floor(color[0] * 255.0);
+  _b = (int)floor(color[0] * 255.0);
+  _a = 255;
+}

+ 3 - 0
pandatool/src/flt/fltPackedColor.h

@@ -9,6 +9,7 @@
 #include <pandatoolbase.h>
 
 #include <luse.h>
+#include <math.h>
 
 class FltRecordReader;
 class FltRecordWriter;
@@ -24,6 +25,8 @@ public:
 
   INLINE Colorf get_color() const;
   INLINE RGBColorf get_rgb() const;
+  INLINE void set_color(const Colorf &color);
+  INLINE void set_rgb(const RGBColorf &rgb);
 
   void output(ostream &out) const;
   bool extract_record(FltRecordReader &reader);

+ 143 - 1
pandatool/src/flt/fltRecord.cxx

@@ -10,6 +10,10 @@
 #include "fltGroup.h"
 #include "fltObject.h"
 #include "fltFace.h"
+#include "fltCurve.h"
+#include "fltMesh.h"
+#include "fltLocalVertexPool.h"
+#include "fltMeshPrimitive.h"
 #include "fltVertexList.h"
 #include "fltLOD.h"
 #include "fltInstanceDefinition.h"
@@ -19,6 +23,7 @@
 #include "config_flt.h"
 
 #include <indent.h>
+#include <datagramIterator.h>
 
 #include <assert.h>
 
@@ -132,6 +137,52 @@ add_subface(FltRecord *subface) {
   _subfaces.push_back(subface);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltRecord::get_num_extensions
+//       Access: Public
+//  Description: Returns the number of extension attribute records for
+//               this object.  These are auxiliary nodes, presumably
+//               of type FO_extension, that have some local meaning to
+//               the object.
+////////////////////////////////////////////////////////////////////
+int FltRecord::
+get_num_extensions() const {
+  return _extensions.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltRecord::get_extension
+//       Access: Public
+//  Description: Returns the nth extension of this record.
+////////////////////////////////////////////////////////////////////
+FltRecord *FltRecord::
+get_extension(int n) const {
+  nassertr(n >= 0 && n < (int)_extensions.size(), (FltRecord *)NULL);
+  return _extensions[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltRecord::clear_extensions
+//       Access: Public
+//  Description: Removes all extensions from this record.
+////////////////////////////////////////////////////////////////////
+void FltRecord::
+clear_extensions() {
+  _extensions.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltRecord::add_extension
+//       Access: Public
+//  Description: Adds a new extension to the end of the list of
+//               extensions for this record.  This should be a record
+//               of type FO_extension.
+////////////////////////////////////////////////////////////////////
+void FltRecord::
+add_extension(FltRecord *extension) {
+  _extensions.push_back(extension);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltRecord::get_num_ancillary
 //       Access: Public
@@ -233,6 +284,31 @@ set_comment(const string &comment) {
   _comment = comment;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltRecord::check_remaining_size
+//       Access: Public
+//  Description: Checks that the iterator has no bytes left, as it
+//               should at the end of a successfully read record.  If
+//               there *are* remaining bytes, print a warning message
+//               but otherwise don't worry about it.
+//
+//               If we are attempting to read a flt file whose version
+//               is newer than the newest this program understands,
+//               don't even print a warning message, since this is
+//               exactly the sort of thing we expect.
+////////////////////////////////////////////////////////////////////
+void FltRecord::
+check_remaining_size(const DatagramIterator &iterator) const {
+  if (iterator.get_remaining_size() == 0) {
+    return;
+  }
+
+  if (_header->get_flt_version() <= _header->max_flt_version()) {
+    nout << "Warning!  Ignoring extra " << iterator.get_remaining_size()
+	 << " bytes at the end of a " << get_type() << " record.\n";
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltRecord::output
 //       Access: Public
@@ -272,6 +348,9 @@ write_children(ostream &out, int indent_level) const {
   if (!_ancillary.empty()) {
     out << " + " << _ancillary.size() << " ancillary";
   }
+  if (!_extensions.empty()) {
+    out << " + " << _extensions.size() << " extensions";
+  }
   if (!_subfaces.empty()) {
     out << " [";
     Records::const_iterator ci;
@@ -313,6 +392,8 @@ is_ancillary(FltOpcode opcode) {
   switch (opcode) {
   case FO_comment:
   case FO_long_id:
+  case FO_multitexture:
+  case FO_uv_list:
   case FO_replicate:
   case FO_road_zone:
   case FO_transform_matrix:
@@ -329,13 +410,16 @@ is_ancillary(FltOpcode opcode) {
   case FO_bounding_cylinder:
   case FO_bv_center:
   case FO_bv_orientation:
+  case FO_local_vertex_pool:
+  case FO_cat_data:
+
   case FO_vertex_palette:
   case FO_vertex_c:
   case FO_vertex_cn:
   case FO_vertex_cnu:
   case FO_vertex_cu:
   case FO_color_palette:
-  case FO_color_name_palette:
+  case FO_name_table:
   case FO_15_material:
   case FO_texture:
   case FO_eyepoint_palette:
@@ -344,9 +428,12 @@ is_ancillary(FltOpcode opcode) {
     return true;
 
   case FO_header:
+  case FO_mesh:
+  case FO_mesh_primitive:
   case FO_group:
   case FO_object:
   case FO_face:
+  case FO_light_point:
   case FO_dof:
   case FO_vertex_list:
   case FO_morph_list:
@@ -356,10 +443,14 @@ is_ancillary(FltOpcode opcode) {
   case FO_sound:
   case FO_light_source:
   case FO_road_segment:
+  case FO_road_construction:
   case FO_road_path:
   case FO_clip_region:
   case FO_text:
   case FO_switch:
+  case FO_cat:
+  case FO_extension:
+  case FO_curve:
     return false;
 
   case FO_push:
@@ -368,6 +459,8 @@ is_ancillary(FltOpcode opcode) {
   case FO_pop_face:
   case FO_push_attribute:
   case FO_pop_attribute:
+  case FO_push_extension:
+  case FO_pop_extension:
   case FO_instance:
   case FO_instance_ref:
     return false;
@@ -397,6 +490,18 @@ create_new_record(FltOpcode opcode) const {
   case FO_face:
     return new FltFace(_header);
 
+  case FO_curve:
+    return new FltCurve(_header);
+
+  case FO_mesh:
+    return new FltMesh(_header);
+
+  case FO_local_vertex_pool:
+    return new FltLocalVertexPool(_header);
+
+  case FO_mesh_primitive:
+    return new FltMeshPrimitive(_header);
+
   case FO_vertex_list:
     return new FltVertexList(_header);
 
@@ -497,6 +602,26 @@ read_record_and_children(FltRecordReader &reader) {
 	}
       }
 
+    } else if (reader.get_opcode() == FO_push_extension) {
+      // A push extension begins a new list of extensions.
+      result = reader.advance();
+      if (result != FE_ok) {
+	return result;
+      }
+      
+      while (reader.get_opcode() != FO_pop_extension) {
+	PT(FltRecord) extension = create_new_record(reader.get_opcode());
+	FltError result = extension->read_record_and_children(reader);
+	if (result != FE_ok) {
+	  return result;
+	}
+	add_extension(extension);
+	if (reader.eof() || reader.error()) {
+	  assert(!flt_error_abort);
+	  return FE_end_of_file;
+	}
+      }
+
     } else if (is_ancillary(reader.get_opcode())) {
       // An unsupported ancillary record.  Skip it.
       PT(FltRecord) ancillary = create_new_record(reader.get_opcode());
@@ -602,6 +727,23 @@ write_record_and_children(FltRecordWriter &writer) const {
     }
   }
 
+  // Any extensions?
+  if (!_extensions.empty()) {
+    result = writer.write_record(FO_push_face);
+    if (result != FE_ok) {
+      return result;
+    }
+
+    for (ci = _extensions.begin(); ci != _extensions.end(); ++ci) {
+      (*ci)->write_record_and_children(writer);
+    }
+
+    result = writer.write_record(FO_pop_face);
+    if (result != FE_ok) {
+      return result;
+    }
+  }
+
   // Finally, write all the children.
   if (!_children.empty()) {
     result = writer.write_record(FO_push);

+ 9 - 0
pandatool/src/flt/fltRecord.h

@@ -18,6 +18,7 @@
 class FltHeader;
 class FltRecordReader;
 class FltRecordWriter;
+class DatagramIterator;
 
 ////////////////////////////////////////////////////////////////////
 // 	 Class : FltRecord
@@ -42,6 +43,11 @@ public:
   void clear_subfaces();
   void add_subface(FltRecord *subface);
 
+  int get_num_extensions() const;
+  FltRecord *get_extension(int n) const;
+  void clear_extensions();
+  void add_extension(FltRecord *extension);
+
   int get_num_ancillary() const;
   FltRecord *get_ancillary(int n) const;
   void clear_ancillary();
@@ -52,6 +58,8 @@ public:
   void clear_comment();
   void set_comment(const string &comment);
 
+  void check_remaining_size(const DatagramIterator &iterator) const;
+
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 
@@ -76,6 +84,7 @@ private:
   typedef vector<PT(FltRecord)> Records;
   Records _children;
   Records _subfaces;
+  Records _extensions;
   Records _ancillary;
 
   string _comment;

+ 86 - 21
pandatool/src/flt/fltRecordReader.cxx

@@ -10,6 +10,8 @@
 
 #include <assert.h>
 
+static const int header_size = 4;
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltRecordReader::Constructor
 //       Access: Public
@@ -23,6 +25,12 @@ FltRecordReader(istream &in) :
   _record_length = 0;
   _iterator = (DatagramIterator *)NULL;
   _state = S_begin;
+  _next_error = FE_ok;
+  _next_opcode = FO_none;
+  _next_record_length = 0;
+
+  // Read the first header to get us going.
+  read_next_header();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -110,13 +118,7 @@ advance(bool ok_eof) {
     _iterator = (DatagramIterator *)NULL;
   }
 
-  // Get the first four bytes of the record.  This will be the opcode
-  // and length.
-  static const int header_size = 4;
-  char bytes[header_size];
-  _in.read(bytes, header_size);
-
-  if (_in.eof()) {
+  if (_next_error == FE_end_of_file) {
     _state = S_eof;
     if (ok_eof) {
       return FE_ok;
@@ -124,30 +126,23 @@ advance(bool ok_eof) {
     assert(!flt_error_abort);
     return FE_end_of_file;
 
-  } else if (_in.fail()) {
+  } else if (_next_error != FE_ok) {
     _state = S_error;
     assert(!flt_error_abort);
-    return FE_read_error;
+    return _next_error;
   }
 
-  // Now extract out the opcode and length.
-  Datagram dg(bytes, header_size);
-  DatagramIterator dgi(dg);
-  _opcode = (FltOpcode)dgi.get_be_int16();
-  _record_length = dgi.get_be_uint16();
-
-  if (_record_length < header_size) {
-    assert(!flt_error_abort);
-    return FE_invalid_record;
-  }
+  _opcode = _next_opcode;
+  _record_length = _next_record_length;
 
   if (flt_cat.is_debug()) {
     flt_cat.debug()
-      << "Reading " << _opcode << " of length " << _record_length << "\n";
+      << "Reading " << _opcode 
+      << " of length " << _record_length << "\n"; 
   }
 
   // And now read the full record based on the length.
-  int length = _record_length - header_size;
+  int length = _next_record_length - header_size;
   char *buffer = new char[length];
   if (length > 0) {
     _in.read(buffer, length);
@@ -167,6 +162,40 @@ advance(bool ok_eof) {
     return FE_read_error;
   }
 
+  // Check out the next header in case it's a continuation.
+  read_next_header();
+  while (_next_error == FE_ok && _next_opcode == FO_continuation) {
+    if (flt_cat.is_debug()) {
+      flt_cat.debug()
+	<< "Reading continuation of length " << _next_record_length << "\n";
+    }
+
+    // Read the continuation and tack it on.
+    _record_length += _next_record_length;
+    length = _next_record_length - header_size;
+
+    buffer = new char[length];
+    if (length > 0) {
+      _in.read(buffer, length);
+    }
+    _datagram.append_data(buffer, length);
+    delete[] buffer;
+    
+    if (_in.eof()) {
+      _state = S_eof;
+      assert(!flt_error_abort);
+      return FE_end_of_file;
+    }
+
+    if (_in.fail()) {
+      _state = S_error;
+      assert(!flt_error_abort);
+      return FE_read_error;
+    }
+
+    read_next_header();
+  }
+
   // Finally, create a new iterator to read this record.
   _iterator = new DatagramIterator(_datagram);
   _state = S_normal;
@@ -196,3 +225,39 @@ error() const {
   return _state == S_error;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltRecordReader::read_next_header
+//       Access: Private
+//  Description: Reads the four-byte header for the next record, which
+//               contains the next opcode and record length.
+//
+//               We need read the next header in advance so we can
+//               check to see if it happens to be a continuation
+//               record.  If it is, we will need to concatenate the
+//               records together before returning.
+////////////////////////////////////////////////////////////////////
+void FltRecordReader::
+read_next_header() {
+  char bytes[header_size];
+  _in.read(bytes, header_size);
+
+  if (_in.eof()) {
+    _next_error = FE_end_of_file;
+    return;
+
+  } else if (_in.fail()) {
+    _next_error = FE_read_error;
+    return;
+  }
+
+  // Now extract out the opcode and length.
+  Datagram dg(bytes, header_size);
+  DatagramIterator dgi(dg);
+  _next_opcode = (FltOpcode)dgi.get_be_int16();
+  _next_record_length = dgi.get_be_uint16();
+
+  if (_next_record_length < header_size) {
+    _next_error = FE_invalid_record;
+    return;
+  }
+}

+ 6 - 0
pandatool/src/flt/fltRecordReader.h

@@ -38,11 +38,17 @@ public:
   bool error() const;
 
 private:
+  void read_next_header();
+
   istream &_in;
   Datagram _datagram;
   FltOpcode _opcode;
   int _record_length;
   DatagramIterator *_iterator;
+  
+  FltError _next_error;
+  FltOpcode _next_opcode;
+  int _next_record_length;
 
   enum State {
     S_begin,

+ 44 - 27
pandatool/src/flt/fltRecordWriter.cxx

@@ -12,6 +12,13 @@
 
 #include <assert.h>
 
+static const int header_size = 4;
+
+// Don't attempt to write more than this number of bytes in one
+// record.  If the record requires more than this, use continuation
+// records.
+static const int max_write_length = 65532;
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltRecordWriter::Constructor
 //       Access: Public
@@ -76,33 +83,43 @@ update_datagram() {
 ////////////////////////////////////////////////////////////////////
 FltError FltRecordWriter::
 advance() {
-  if (flt_cat.is_debug()) {
-    flt_cat.debug()
-      << "Writing " << _opcode << " of length "
-      << _datagram.get_length() << "\n";
-  }
-
-  // Build a mini-datagram to write the header.
-  static const int header_size = 4;
-
-  Datagram dg;
-  dg.add_be_int16(_opcode);
-  dg.add_be_int16(_datagram.get_length() + header_size);
-
-  nassertr((int)dg.get_length() == header_size, FE_internal);
-
-  _out.write(dg.get_message().data(), dg.get_length());
-  if (_out.fail()) {
-    assert(!flt_error_abort);
-    return FE_write_error;
-  }
-
-  // Now write the rest of the record.
-  _out.write(_datagram.get_message().data(), _datagram.get_length());
-  if (_out.fail()) {
-    assert(!flt_error_abort);
-    return FE_write_error;
-  }
+  int start_byte = 0;
+  int write_length = 
+    min((int)_datagram.get_length() - start_byte, max_write_length - header_size);
+  FltOpcode opcode = _opcode;
+
+  do {
+    if (flt_cat.is_debug()) {
+      flt_cat.debug()
+	<< "Writing " << opcode << " of length "
+	<< write_length + header_size << "\n";
+    }
+
+    // Build a mini-datagram to write the header.
+    Datagram dg;
+    dg.add_be_int16(opcode);
+    dg.add_be_int16(write_length + header_size);
+
+    nassertr((int)dg.get_length() == header_size, FE_internal);
+
+    _out.write((const char *)dg.get_data(), dg.get_length());
+    if (_out.fail()) {
+      assert(!flt_error_abort);
+      return FE_write_error;
+    }
+
+    // Now write the rest of the record.
+    _out.write((const char *)_datagram.get_data() + start_byte, write_length);
+    if (_out.fail()) {
+      assert(!flt_error_abort);
+      return FE_write_error;
+    }
+
+    start_byte += write_length;
+    write_length = 
+      min((int)_datagram.get_length() - start_byte, max_write_length - header_size);
+    opcode = FO_continuation;
+  } while (write_length > 0);
 
   _datagram.clear();
   _opcode = FO_none;

+ 34 - 6
pandatool/src/flt/fltTexture.cxx

@@ -214,7 +214,7 @@ extract_record(FltRecordReader &reader) {
     nout << "Unable to read attribute file " << get_attr_filename() << "\n";
   }
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 
@@ -343,7 +343,19 @@ unpack_attr(const Datagram &datagram) {
     }
   }
 
-  nassertr(iterator.get_remaining_size() == 0, FE_ok);
+  if (iterator.get_remaining_size() != 0) {
+    int num_defs = iterator.get_be_int32();
+    while (num_defs > 0) {
+      SubtextureDef def;
+      def._name = iterator.get_fixed_string(32);
+      def._left = iterator.get_be_int32();
+      def._bottom = iterator.get_be_int32();
+      def._right = iterator.get_be_int32();
+      def._top = iterator.get_be_int32();
+    }
+  }
+
+  check_remaining_size(iterator);
   return FE_ok;
 }
 
@@ -430,12 +442,28 @@ pack_attr(Datagram &datagram) const {
     for (pi = _geospecific_control_points.begin();
 	 pi != _geospecific_control_points.end();
 	 ++pi) {
-      datagram.add_be_float64((*pi)._uv[0]);
-      datagram.add_be_float64((*pi)._uv[1]);
-      datagram.add_be_float64((*pi)._real_earth[0]);
-      datagram.add_be_float64((*pi)._real_earth[1]);
+      const GeospecificControlPoint &gcp = (*pi);
+      datagram.add_be_float64(gcp._uv[0]);
+      datagram.add_be_float64(gcp._uv[1]);
+      datagram.add_be_float64(gcp._real_earth[0]);
+      datagram.add_be_float64(gcp._real_earth[1]);
     }
   }
 
+  // Also write out the subtexture definitions.
+  datagram.add_be_int32(_subtexture_defs.size());
+  SubtextureDefs::const_iterator di;
+  for (di = _subtexture_defs.begin();
+       di != _subtexture_defs.end();
+       ++di) {
+    const SubtextureDef &def = (*di);
+    datagram.add_fixed_string(def._name, 31);
+    datagram.add_int8(0);
+    datagram.add_be_int32(def._left);
+    datagram.add_be_int32(def._bottom);
+    datagram.add_be_int32(def._right);
+    datagram.add_be_int32(def._top);
+  }
+
   return FE_ok;
 }

+ 10 - 0
pandatool/src/flt/fltTexture.h

@@ -145,6 +145,15 @@ public:
 
   typedef vector<GeospecificControlPoint> GeospecificControlPoints;
 
+  struct SubtextureDef {
+    string _name;
+    int _left;
+    int _bottom;
+    int _right;
+    int _top;
+  };
+  typedef vector<SubtextureDef> SubtextureDefs;
+
   int _num_texels_u;
   int _num_texels_v;
   int _real_world_size_u;
@@ -199,6 +208,7 @@ public:
   string _comment;
   int _file_version;
   GeospecificControlPoints _geospecific_control_points;
+  SubtextureDefs _subtexture_defs;
 
 protected:
   virtual bool extract_record(FltRecordReader &reader);

+ 1 - 1
pandatool/src/flt/fltTransformGeneralMatrix.cxx

@@ -61,7 +61,7 @@ extract_record(FltRecordReader &reader) {
     }
   }
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltTransformPut.cxx

@@ -166,7 +166,7 @@ extract_record(FltRecordReader &reader) {
 
   recompute_matrix();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltTransformRotateAboutEdge.cxx

@@ -117,7 +117,7 @@ extract_record(FltRecordReader &reader) {
 
   recompute_matrix();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltTransformRotateAboutPoint.cxx

@@ -116,7 +116,7 @@ extract_record(FltRecordReader &reader) {
 
   recompute_matrix();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltTransformRotateScale.cxx

@@ -187,7 +187,7 @@ extract_record(FltRecordReader &reader) {
 
   recompute_matrix();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltTransformScale.cxx

@@ -96,7 +96,7 @@ extract_record(FltRecordReader &reader) {
 
   recompute_matrix();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltTransformTranslate.cxx

@@ -95,7 +95,7 @@ extract_record(FltRecordReader &reader) {
 
   recompute_matrix();
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltVertex.cxx

@@ -179,7 +179,7 @@ extract_record(FltRecordReader &reader) {
     iterator.skip_bytes(4);
   }
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 1 - 1
pandatool/src/flt/fltVertexList.cxx

@@ -98,7 +98,7 @@ extract_record(FltRecordReader &reader) {
     _vertices.push_back(_header->get_vertex_by_offset(vertex_offset));
   }
 
-  nassertr(iterator.get_remaining_size() == 0, true);
+  check_remaining_size(iterator);
   return true;
 }
 

+ 2 - 2
pandatool/src/flt/test_flt.cxx

@@ -48,8 +48,8 @@ main(int argc, char *argv[]) {
   header->set_texture_path(texture_path);
 
   FltError result = header->read_flt(filename);
-  cerr << "Read result is " << result << "\n\n";
-  cerr << "Version is " << header->get_flt_version() << "\n";
+  cerr << "Read result is " << result << "\n"
+       << "Version is " << header->get_flt_version() << "\n";
   header->check_version();
 
   if (result == FE_ok) {