Browse Source

*** empty log message ***

David Rose 24 years ago
parent
commit
690b7776f4
88 changed files with 988 additions and 945 deletions
  1. 2 4
      panda/src/chan/animBundle.cxx
  2. 2 4
      panda/src/chan/animBundleNode.cxx
  3. 2 4
      panda/src/chan/animChannelMatrixXfmTable.cxx
  4. 2 4
      panda/src/chan/animChannelScalarTable.cxx
  5. 2 4
      panda/src/chan/animGroup.cxx
  6. 2 4
      panda/src/chan/movingPartMatrix.cxx
  7. 2 4
      panda/src/chan/movingPartScalar.cxx
  8. 2 4
      panda/src/chan/partBundle.cxx
  9. 2 4
      panda/src/chan/partGroup.cxx
  10. 2 4
      panda/src/char/character.cxx
  11. 2 4
      panda/src/char/characterJoint.cxx
  12. 2 4
      panda/src/char/characterJointBundle.cxx
  13. 2 4
      panda/src/char/characterSlider.cxx
  14. 2 4
      panda/src/char/computedVertices.cxx
  15. 2 4
      panda/src/collide/collisionNode.cxx
  16. 2 4
      panda/src/collide/collisionPlane.cxx
  17. 2 4
      panda/src/collide/collisionPolygon.cxx
  18. 2 4
      panda/src/collide/collisionSphere.cxx
  19. 2 4
      panda/src/cull/geomBinTransition.cxx
  20. 2 4
      panda/src/effects/lensFlareNode.cxx
  21. 4 2
      panda/src/express/Sources.pp
  22. 62 0
      panda/src/express/datagramIterator.I
  23. 72 62
      panda/src/express/datagramIterator.cxx
  24. 7 2
      panda/src/express/datagramIterator.h
  25. 2 4
      panda/src/gobj/geomLine.cxx
  26. 2 4
      panda/src/gobj/geomLinestrip.cxx
  27. 2 4
      panda/src/gobj/geomPoint.cxx
  28. 2 4
      panda/src/gobj/geomPolygon.cxx
  29. 2 4
      panda/src/gobj/geomQuad.cxx
  30. 4 4
      panda/src/gobj/geomSphere.cxx
  31. 2 4
      panda/src/gobj/geomSprite.cxx
  32. 2 4
      panda/src/gobj/geomTri.cxx
  33. 2 4
      panda/src/gobj/geomTrifan.cxx
  34. 2 4
      panda/src/gobj/geomTristrip.cxx
  35. 2 4
      panda/src/gobj/material.cxx
  36. 2 3
      panda/src/gobj/texture.cxx
  37. 2 4
      panda/src/graph/namedNode.cxx
  38. 3 4
      panda/src/graph/node.cxx
  39. 2 4
      panda/src/graph/nodeRelation.cxx
  40. 17 6
      panda/src/loader/bamFile.cxx
  41. 12 1
      panda/src/loader/bamFile.h
  42. 9 2
      panda/src/loader/loaderFileTypeBam.cxx
  43. 2 4
      panda/src/parametrics/classicNurbsCurve.cxx
  44. 2 4
      panda/src/parametrics/cubicCurveseg.cxx
  45. 2 4
      panda/src/parametrics/hermiteCurve.cxx
  46. 43 70
      panda/src/putil/bamReader.I
  47. 442 348
      panda/src/putil/bamReader.cxx
  48. 95 80
      panda/src/putil/bamReader.h
  49. 18 28
      panda/src/putil/bamReaderParam.I
  50. 7 11
      panda/src/putil/bamReaderParam.h
  51. 7 12
      panda/src/putil/test_bam.cxx
  52. 2 4
      panda/src/sgattrib/billboardTransition.cxx
  53. 2 4
      panda/src/sgattrib/colorMatrixTransition.cxx
  54. 2 4
      panda/src/sgattrib/cullFaceTransition.cxx
  55. 2 4
      panda/src/sgattrib/decalTransition.cxx
  56. 2 4
      panda/src/sgattrib/depthTestTransition.cxx
  57. 2 4
      panda/src/sgattrib/depthWriteTransition.cxx
  58. 2 4
      panda/src/sgattrib/materialTransition.cxx
  59. 2 4
      panda/src/sgattrib/pruneTransition.cxx
  60. 2 4
      panda/src/sgattrib/renderRelation.cxx
  61. 2 4
      panda/src/sgattrib/textureApplyTransition.cxx
  62. 2 4
      panda/src/sgattrib/textureTransition.cxx
  63. 2 4
      panda/src/sgattrib/transformTransition.cxx
  64. 2 4
      panda/src/sgattrib/transparencyTransition.cxx
  65. 2 4
      panda/src/sgraph/geomNode.cxx
  66. 2 4
      panda/src/sgraph/modelNode.cxx
  67. 2 4
      panda/src/sgraph/modelRoot.cxx
  68. 2 4
      panda/src/switchnode/LODNode.cxx
  69. 2 4
      panda/src/switchnode/sequenceNode.cxx
  70. 4 2
      pandatool/src/bam/bamInfo.cxx
  71. 2 4
      pandatool/src/egg-palettize/destTextureImage.cxx
  72. 2 4
      pandatool/src/egg-palettize/eggFile.cxx
  73. 2 4
      pandatool/src/egg-palettize/paletteGroup.cxx
  74. 2 4
      pandatool/src/egg-palettize/paletteGroups.cxx
  75. 2 4
      pandatool/src/egg-palettize/paletteImage.cxx
  76. 2 4
      pandatool/src/egg-palettize/palettePage.cxx
  77. 2 4
      pandatool/src/egg-palettize/palettizer.cxx
  78. 2 4
      pandatool/src/egg-palettize/sourceTextureImage.cxx
  79. 2 4
      pandatool/src/egg-palettize/textureImage.cxx
  80. 2 4
      pandatool/src/egg-palettize/texturePlacement.cxx
  81. 2 4
      pandatool/src/egg-palettize/texturePosition.cxx
  82. 2 4
      pandatool/src/egg-palettize/textureProperties.cxx
  83. 2 4
      pandatool/src/egg-palettize/textureReference.cxx
  84. 2 2
      pandatool/src/flt/fltGeometry.cxx
  85. 30 28
      pandatool/src/flt/fltHeader.cxx
  86. 4 4
      pandatool/src/flt/fltHeader.h
  87. 3 3
      pandatool/src/flt/fltVertex.cxx
  88. 9 7
      pandatool/src/fltprogs/fltTrans.cxx

+ 2 - 4
panda/src/chan/animBundle.cxx

@@ -63,12 +63,10 @@ TypedWriteable* AnimBundle::
 make_AnimBundle(const FactoryParams &params)
 {
   AnimBundle *me = new AnimBundle;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/chan/animBundleNode.cxx

@@ -77,12 +77,10 @@ TypedWriteable* AnimBundleNode::
 make_AnimBundleNode(const FactoryParams &params)
 {
   AnimBundleNode *me = new AnimBundleNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/chan/animChannelMatrixXfmTable.cxx

@@ -363,12 +363,10 @@ TypedWriteable* AnimChannelMatrixXfmTable::
 make_AnimChannelMatrixXfmTable(const FactoryParams &params)
 {
   AnimChannelMatrixXfmTable *me = new AnimChannelMatrixXfmTable;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/chan/animChannelScalarTable.cxx

@@ -307,12 +307,10 @@ TypedWriteable* AnimChannelScalarTable::
 make_AnimChannelScalarTable(const FactoryParams &params)
 {
   AnimChannelScalarTable *me = new AnimChannelScalarTable;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/chan/animGroup.cxx

@@ -234,12 +234,10 @@ TypedWriteable* AnimGroup::
 make_AnimGroup(const FactoryParams &params)
 {
   AnimGroup *me = new AnimGroup;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/chan/movingPartMatrix.cxx

@@ -126,12 +126,10 @@ TypedWriteable* MovingPartMatrix::
 make_MovingPartMatrix(const FactoryParams &params)
 {
   MovingPartMatrix *me = new MovingPartMatrix;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/chan/movingPartScalar.cxx

@@ -79,12 +79,10 @@ TypedWriteable* MovingPartScalar::
 make_MovingPartScalar(const FactoryParams &params)
 {
   MovingPartScalar *me = new MovingPartScalar;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/chan/partBundle.cxx

@@ -404,12 +404,10 @@ TypedWriteable* PartBundle::
 make_PartBundle(const FactoryParams &params)
 {
   PartBundle *me = new PartBundle;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   manager->register_finalize(me);
   return me;

+ 2 - 4
panda/src/chan/partGroup.cxx

@@ -510,12 +510,10 @@ TypedWriteable* PartGroup::
 make_PartGroup(const FactoryParams &params)
 {
   PartGroup *me = new PartGroup;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/char/character.cxx

@@ -470,12 +470,10 @@ TypedWriteable* Character::
 make_Character(const FactoryParams &params)
 {
   Character *me = new Character;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/char/characterJoint.cxx

@@ -327,12 +327,10 @@ TypedWriteable* CharacterJoint::
 make_CharacterJoint(const FactoryParams &params)
 {
   CharacterJoint *me = new CharacterJoint;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/char/characterJointBundle.cxx

@@ -41,12 +41,10 @@ TypedWriteable* CharacterJointBundle::
 make_CharacterJointBundle(const FactoryParams &params)
 {
   CharacterJointBundle *me = new CharacterJointBundle;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   manager->register_finalize(me);
   return me;

+ 2 - 4
panda/src/char/characterSlider.cxx

@@ -61,12 +61,10 @@ TypedWriteable* CharacterSlider::
 make_CharacterSlider(const FactoryParams &params)
 {
   CharacterSlider *me = new CharacterSlider;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/char/computedVertices.cxx

@@ -407,12 +407,10 @@ TypedWriteable* ComputedVertices::
 make_ComputedVertices(const FactoryParams &params)
 {
   ComputedVertices *me = new ComputedVertices;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/collide/collisionNode.cxx

@@ -255,12 +255,10 @@ TypedWriteable* CollisionNode::
 make_CollisionNode(const FactoryParams &params)
 {
   CollisionNode *me = new CollisionNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/collide/collisionPlane.cxx

@@ -285,12 +285,10 @@ TypedWriteable* CollisionPlane::
 make_CollisionPlane(const FactoryParams &params)
 {
   CollisionPlane *me = new CollisionPlane;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/collide/collisionPolygon.cxx

@@ -773,12 +773,10 @@ TypedWriteable* CollisionPolygon::
 make_CollisionPolygon(const FactoryParams &params)
 {
   CollisionPolygon *me = new CollisionPolygon;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/collide/collisionSphere.cxx

@@ -370,12 +370,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable *CollisionSphere::
 make_CollisionSphere(const FactoryParams &params) {
   CollisionSphere *me = new CollisionSphere;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/cull/geomBinTransition.cxx

@@ -115,12 +115,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable *GeomBinTransition::
 make_GeomBinTransition(const FactoryParams &params) {
   GeomBinTransition *me = new GeomBinTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/effects/lensFlareNode.cxx

@@ -532,12 +532,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager)
 TypedWriteable *LensFlareNode::
 make_LensFlareNode(const FactoryParams &params) {
   LensFlareNode *me = new LensFlareNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 4 - 2
panda/src/express/Sources.pp

@@ -14,7 +14,8 @@
     clockObject.h config_express.cxx config_express.h datagram.I	\
     datagram.cxx datagram.h datagramGenerator.I datagramGenerator.cxx	\
     datagramGenerator.h datagramInputFile.I datagramInputFile.h		\
-    datagramInputFile.cxx datagramIterator.cxx datagramIterator.h	\
+    datagramInputFile.cxx datagramIterator.I \
+    datagramIterator.cxx datagramIterator.h	\
     datagramOutputFile.I datagramOutputFile.h datagramOutputFile.cxx	\
     datagramSink.I datagramSink.cxx datagramSink.h			\
     get_config_path.cxx get_config_path.h				\
@@ -38,7 +39,8 @@
     bigEndian.I bigEndian.h buffer.I buffer.h circBuffer.I		\
     circBuffer.h clockObject.I clockObject.h config_express.h		\
     datagram.I datagram.h datagramInputFile.I datagramInputFile.h	\
-    datagramIterator.h datagramOutputFile.I datagramOutputFile.h	\
+    datagramIterator.I datagramIterator.h \
+    datagramOutputFile.I datagramOutputFile.h	\
     datagramSink.I datagramSink.h datagramGenerator.I			\
     datagramGenerator.h get_config_path.h				\
     hashVal.I hashVal.h \

+ 62 - 0
panda/src/express/datagramIterator.I

@@ -0,0 +1,62 @@
+// Filename: datagramIterator.I
+// Created by:  drose (08May01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramIterator::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE DatagramIterator::
+DatagramIterator() :
+  _datagram((Datagram *)NULL),
+  _current_index(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramIterator::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE DatagramIterator::
+DatagramIterator(const Datagram &datagram, size_t offset) :
+  _datagram(&datagram),
+  _current_index(offset)
+{
+  nassertv(_current_index <= _datagram->get_length());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramIterator::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE DatagramIterator::
+DatagramIterator(const DatagramIterator &copy) :
+  _datagram(copy._datagram),
+  _current_index(copy._current_index)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramIterator::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void DatagramIterator::
+operator = (const DatagramIterator &copy) {
+  _datagram = copy._datagram;
+  _current_index = copy._current_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramIterator::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE DatagramIterator::
+~DatagramIterator() {
+}

+ 72 - 62
panda/src/express/datagramIterator.cxx

@@ -8,19 +8,6 @@
 
 #include <notify.h>
 
-////////////////////////////////////////////////////////////////////
-//     Function: DatagramIterator::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-DatagramIterator::
-DatagramIterator(const Datagram &datagram, size_t offset) :
-  _datagram(datagram),
-  _current_index(offset)
-{
-  nassertv(_current_index <= _datagram.get_length());
-}
-
 // Various ways to get data and increment the iterator...
 // Cut-and-paste-orama
 
@@ -31,11 +18,12 @@ DatagramIterator(const Datagram &datagram, size_t offset) :
 ////////////////////////////////////////////////////////////////////
 bool DatagramIterator::
 get_bool() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint8 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -51,11 +39,12 @@ get_bool() {
 ////////////////////////////////////////////////////////////////////
 PN_int8 DatagramIterator::
 get_int8() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_int8 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -71,11 +60,12 @@ get_int8() {
 ////////////////////////////////////////////////////////////////////
 PN_uint8 DatagramIterator::
 get_uint8() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint8 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -91,11 +81,12 @@ get_uint8() {
 ////////////////////////////////////////////////////////////////////
 PN_int16 DatagramIterator::
 get_int16() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_int16 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -111,11 +102,12 @@ get_int16() {
 ////////////////////////////////////////////////////////////////////
 PN_int32 DatagramIterator::
 get_int32() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_int32 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -131,11 +123,12 @@ get_int32() {
 ////////////////////////////////////////////////////////////////////
 PN_int64 DatagramIterator::
 get_int64() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_int64 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -151,11 +144,12 @@ get_int64() {
 ////////////////////////////////////////////////////////////////////
 PN_uint16 DatagramIterator::
 get_uint16() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint16 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -171,11 +165,12 @@ get_uint16() {
 ////////////////////////////////////////////////////////////////////
 PN_uint32 DatagramIterator::
 get_uint32() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint32 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -191,11 +186,12 @@ get_uint32() {
 ////////////////////////////////////////////////////////////////////
 PN_uint64 DatagramIterator::
 get_uint64() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint64 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -218,11 +214,12 @@ get_float32() {
   // architectures we are concerned with.  If we come across one that
   // is different, we will have to convert.
   nassertr(sizeof(float) == 4, 0.0);
-  nassertr(_current_index < _datagram.get_length(), 0.0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0.0);
 
   float tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0.0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -238,11 +235,12 @@ get_float32() {
 ////////////////////////////////////////////////////////////////////
 PN_float64 DatagramIterator::
 get_float64() {
-  nassertr(_current_index < _datagram.get_length(), 0.0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0.0);
 
   PN_float64 tempvar;
   LittleEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0.0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -258,11 +256,12 @@ get_float64() {
 ////////////////////////////////////////////////////////////////////
 PN_int16 DatagramIterator::
 get_be_int16() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_int16 tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -278,11 +277,12 @@ get_be_int16() {
 ////////////////////////////////////////////////////////////////////
 PN_int32 DatagramIterator::
 get_be_int32() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_int32 tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -298,11 +298,12 @@ get_be_int32() {
 ////////////////////////////////////////////////////////////////////
 PN_int64 DatagramIterator::
 get_be_int64() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_int64 tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -318,11 +319,12 @@ get_be_int64() {
 ////////////////////////////////////////////////////////////////////
 PN_uint16 DatagramIterator::
 get_be_uint16() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint16 tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -338,11 +340,12 @@ get_be_uint16() {
 ////////////////////////////////////////////////////////////////////
 PN_uint32 DatagramIterator::
 get_be_uint32() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint32 tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -358,11 +361,12 @@ get_be_uint32() {
 ////////////////////////////////////////////////////////////////////
 PN_uint64 DatagramIterator::
 get_be_uint64() {
-  nassertr(_current_index < _datagram.get_length(), 0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0);
 
   PN_uint64 tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -385,11 +389,12 @@ get_be_float32() {
   // architectures we are concerned with.  If we come across one that
   // is different, we will have to convert.
   nassertr(sizeof(float) == 4, 0.0);
-  nassertr(_current_index < _datagram.get_length(), 0.0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0.0);
 
   float tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0.0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -405,11 +410,12 @@ get_be_float32() {
 ////////////////////////////////////////////////////////////////////
 PN_float64 DatagramIterator::
 get_be_float64() {
-  nassertr(_current_index < _datagram.get_length(), 0.0);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index < _datagram->get_length(), 0.0);
 
   PN_float64 tempvar;
   BigEndian s = 
-    _datagram.get_message().substr(_current_index, sizeof(tempvar));
+    _datagram->get_message().substr(_current_index, sizeof(tempvar));
 
   nassertr(s.length() == sizeof(tempvar), 0.0);
   memcpy((void *)&tempvar, (void *)s.data(), sizeof(tempvar));
@@ -428,10 +434,11 @@ get_string() {
   // First, get the length of the string
   PN_uint16 s_len = get_uint16();
 
-  nassertr(_current_index + s_len <= _datagram.get_length(), "");
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index + s_len <= _datagram->get_length(), "");
 
   string s = 
-    _datagram.get_message().substr(_current_index, s_len);
+    _datagram->get_message().substr(_current_index, s_len);
 
   nassertr(s.length() == s_len, "");
   _current_index += s_len;
@@ -448,10 +455,11 @@ get_string() {
 ////////////////////////////////////////////////////////////////////
 string DatagramIterator::
 get_fixed_string(size_t size) {
-  nassertr(_current_index + size <= _datagram.get_length(), "");
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index + size <= _datagram->get_length(), "");
 
   string s = 
-    _datagram.get_message().substr(_current_index, size);
+    _datagram->get_message().substr(_current_index, size);
   _current_index += size;
 
   size_t zero_byte = s.find('\0');
@@ -467,7 +475,7 @@ get_fixed_string(size_t size) {
 void DatagramIterator::
 skip_bytes(size_t size) {
   nassertv((int)size >= 0);
-  nassertv(_current_index + size <= _datagram.get_length());
+  nassertv(_current_index + size <= _datagram->get_length());
   _current_index += size;
 }
 
@@ -480,11 +488,12 @@ skip_bytes(size_t size) {
 string DatagramIterator::
 extract_bytes(size_t size) {
   nassertr((int)size >= 0, "");
-  nassertr(_current_index + size <= _datagram.get_length(), "");
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index + size <= _datagram->get_length(), "");
   int start = _current_index;
 
   _current_index += size;
-  return _datagram.get_message().substr(start, size);
+  return _datagram->get_message().substr(start, size);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -495,8 +504,9 @@ extract_bytes(size_t size) {
 ////////////////////////////////////////////////////////////////////
 string DatagramIterator::
 get_remaining_bytes() const {
-  nassertr(_current_index <= _datagram.get_length(), "");
-  return _datagram.get_message().substr(_current_index);
+  nassertr(_datagram != (const Datagram *)NULL &&
+	   _current_index <= _datagram->get_length(), "");
+  return _datagram->get_message().substr(_current_index);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -506,7 +516,7 @@ get_remaining_bytes() const {
 ////////////////////////////////////////////////////////////////////
 int DatagramIterator::
 get_remaining_size() const {
-  return _datagram.get_length() - _current_index;
+  return _datagram->get_length() - _current_index;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -516,7 +526,7 @@ get_remaining_size() const {
 ////////////////////////////////////////////////////////////////////
 const Datagram &DatagramIterator::
 get_datagram() const {
-  return _datagram;
+  return *_datagram;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 7 - 2
panda/src/express/datagramIterator.h

@@ -19,7 +19,11 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDAEXPRESS DatagramIterator {
 PUBLISHED:
-  DatagramIterator(const Datagram &datagram, size_t offset = 0);
+  INLINE DatagramIterator();
+  INLINE DatagramIterator(const Datagram &datagram, size_t offset = 0);
+  INLINE DatagramIterator(const DatagramIterator &copy);
+  INLINE void operator = (const DatagramIterator &copy);
+  INLINE ~DatagramIterator();
 
   bool get_bool();
   PN_int8 get_int8();
@@ -56,9 +60,10 @@ PUBLISHED:
   size_t get_current_index() const;
  
 private:
-  const Datagram &_datagram;
+  const Datagram *_datagram;
   size_t _current_index;
 };
  
+#include "datagramIterator.I"
 
 #endif

+ 2 - 4
panda/src/gobj/geomLine.cxx

@@ -60,12 +60,10 @@ write_datagram(BamWriter *manager, Datagram &me)
 TypedWriteable* GeomLine::
 make_GeomLine(const FactoryParams &params) {
   GeomLine *me = new GeomLine;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/geomLinestrip.cxx

@@ -72,12 +72,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable* GeomLinestrip::
 make_GeomLinestrip(const FactoryParams &params) {
   GeomLinestrip *me = new GeomLinestrip;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/geomPoint.cxx

@@ -68,12 +68,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable* GeomPoint::
 make_GeomPoint(const FactoryParams &params) {
   GeomPoint *me = new GeomPoint;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/geomPolygon.cxx

@@ -56,12 +56,10 @@ draw_immediate(GraphicsStateGuardianBase *gsg) const {
 TypedWriteable* GeomPolygon::
 make_GeomPolygon(const FactoryParams &params) {
   GeomPolygon *me = new GeomPolygon;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/geomQuad.cxx

@@ -107,12 +107,10 @@ get_tris() const {
 TypedWriteable* GeomQuad::
 make_GeomQuad(const FactoryParams &params) {
   GeomQuad *me = new GeomQuad;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 4 - 4
panda/src/gobj/geomSphere.cxx

@@ -40,13 +40,13 @@ TypedWriteable* GeomSphere::
 make_GeomSphere(const FactoryParams &params)
 {
   GeomSphere *me = new GeomSphere;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
+  me->make_dirty();
+  me->config();
   return me;
 }
 

+ 2 - 4
panda/src/gobj/geomSprite.cxx

@@ -91,12 +91,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable* GeomSprite::
 make_GeomSprite(const FactoryParams &params) {
   GeomSprite *me = new GeomSprite;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/geomTri.cxx

@@ -221,12 +221,10 @@ get_tris() const {
 TypedWriteable* GeomTri::
 make_GeomTri(const FactoryParams &params) {
   GeomTri *me = new GeomTri;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/geomTrifan.cxx

@@ -385,12 +385,10 @@ get_tris() const {
 TypedWriteable* GeomTrifan::
 make_GeomTrifan(const FactoryParams &params) {
   GeomTrifan *me = new GeomTrifan;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/geomTristrip.cxx

@@ -496,12 +496,10 @@ get_tris() const {
 TypedWriteable* GeomTristrip::
 make_GeomTristrip(const FactoryParams &params) {
   GeomTristrip *me = new GeomTristrip;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   me->make_dirty();
   me->config();

+ 2 - 4
panda/src/gobj/material.cxx

@@ -157,12 +157,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable *Material::
 make_Material(const FactoryParams &params) {
   Material *me = new Material;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 3
panda/src/gobj/texture.cxx

@@ -500,11 +500,10 @@ make_Texture(const FactoryParams &params)
   //be done through calls to TexturePool, which ensures
   //that any loads of the same Texture, refer to the
   //same memory
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
 
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
+  parse_params(params, scan, manager);
 
   string name = scan.get_string();
   string alpha_name = scan.get_string();

+ 2 - 4
panda/src/graph/namedNode.cxx

@@ -61,12 +61,10 @@ TypedWriteable* NamedNode::
 make_NamedNode(const FactoryParams &params)
 {
   NamedNode *me = new NamedNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 3 - 4
panda/src/graph/node.cxx

@@ -78,6 +78,7 @@ Node::
     DownRelationPointers::iterator drpi;
     for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
       NodeRelation *arc = (*drpi);
+      nassertv(arc != (NodeRelation *)NULL);
 
       // This deletes the arc and anything below it through the magic
       // of reference-counting.
@@ -504,12 +505,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* Node::
 make_Node(const FactoryParams &params) {
   Node *me = new Node;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/graph/nodeRelation.cxx

@@ -944,12 +944,10 @@ TypedWriteable* NodeRelation::
 make_NodeRelation(const FactoryParams &params)
 {
   NodeRelation *me = new NodeRelation(get_class_type());
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 17 - 6
panda/src/loader/bamFile.cxx

@@ -84,10 +84,8 @@ open_read(const Filename &filename, bool report_errors) {
 //       Access: Public
 //  Description: Reads and returns the next object from the Bam file,
 //               or NULL if the end of the file has been reached, or
-//               if there is an error condition.
-//
-//               Note that there is presently no way to differentiate
-//               a normal end-of-file from an error.
+//               if there is an error condition.  Use is_eof() to
+//               differentiate these two cases.
 //
 //               The pointers returned by this method will not be
 //               valid for use until resolve() is subsequently called.
@@ -101,6 +99,18 @@ read_object() {
   return _reader->read_object();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BamFile::is_eof
+//       Access: Public
+//  Description: Returns true if the reader has reached end-of-file,
+//               false otherwise.  This call is only valid after a
+//               call to read_object().
+////////////////////////////////////////////////////////////////////
+bool BamFile::
+is_eof() const {
+  return _reader != (BamReader *)NULL && _reader->is_eof();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BamFile::resolve
 //       Access: Public
@@ -108,8 +118,9 @@ read_object() {
 //               been read via calls to read_object() in order to
 //               resolve all internal pointer references in the
 //               objects read and make all the pointers valid.  It
-//               returns true if successful, false if there is some
-//               error.
+//               returns true if all objects are successfully
+//               resolved, or false if some have not been (in which
+//               case you must call resolve() again later).
 ////////////////////////////////////////////////////////////////////
 bool BamFile::
 resolve() {

+ 12 - 1
panda/src/loader/bamFile.h

@@ -19,7 +19,17 @@ class Filename;
 ////////////////////////////////////////////////////////////////////
 // 	 Class : BamFile
 // Description : The principle public interface to reading and writing
-//               Bam disk files.
+//               Bam disk files.  See also BamReader and BamWriter,
+//               the more general implementation of this class.
+//
+//               Bam files are most often used to store scene graphs
+//               or subgraphs, and by convention they are given
+//               filenames ending in the extension ".bam" when they
+//               are used for this purpose.  However, a Bam file may
+//               store any arbitrary list of TypedWriteable objects;
+//               in this more general usage, they are given filenames
+//               ending in ".boo" to differentiate them from the more
+//               common scene graph files.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA BamFile {
 public:
@@ -28,6 +38,7 @@ public:
 
   bool open_read(const Filename &filename, bool report_errors = true);
   TypedWriteable *read_object();
+  bool is_eof() const;
   bool resolve();
 
   bool open_write(const Filename &filename, bool report_errors = true);

+ 9 - 2
panda/src/loader/loaderFileTypeBam.cxx

@@ -89,14 +89,21 @@ load_file(const Filename &path, bool report_errors) const
     result = DCAST(Node, object);
     
     if (report_errors) {
-      if (bam_file.read_object() != TypedWriteable::Null) {
+      bam_file.read_object();
+      if (!bam_file.is_eof()) {
 	loader_cat.warning()
 	  << "Ignoring extra objects in " << path << "\n";
       }
     }
   }
     
-  bam_file.resolve();
+  if (!bam_file.resolve()) {
+    if (report_errors) {
+      loader_cat.error() 
+	<< "Unable to resolve Bam file.\n";
+      result = (Node *)NULL;
+    }
+  }    
 
   return result;
 }

+ 2 - 4
panda/src/parametrics/classicNurbsCurve.cxx

@@ -556,12 +556,10 @@ register_with_read_factory() {
 TypedWriteable *ClassicNurbsCurve::
 make_ClassicNurbsCurve(const FactoryParams &params) {
   ClassicNurbsCurve *me = new ClassicNurbsCurve;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/parametrics/cubicCurveseg.cxx

@@ -563,12 +563,10 @@ register_with_read_factory() {
 TypedWriteable *CubicCurveseg::
 make_CubicCurveseg(const FactoryParams &params) {
   CubicCurveseg *me = new CubicCurveseg;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/parametrics/hermiteCurve.cxx

@@ -914,12 +914,10 @@ register_with_read_factory() {
 TypedWriteable *HermiteCurve::
 make_HermiteCurve(const FactoryParams &params) {
   HermiteCurve *me = new HermiteCurve;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 43 - 70
panda/src/putil/bamReader.I

@@ -2,111 +2,89 @@
 // Created by:  jason (12Jun00)
 //
 
-#include <algorithm>
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::Constructor
+//     Function: BamReader::is_eof
 //       Access: Public
-//  Description: 
+//  Description: Returns true if the reader has reached end-of-file,
+//               false otherwise.  This call is only valid after a
+//               call to read_object().
 ////////////////////////////////////////////////////////////////////
-INLINE BamReader::
-BamReader(DatagramGenerator *generator) 
-  : _source(generator)
-{
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamReader::create_factory
-//       Access: Private, Static
-//  Description: Creates a new WriteableFactory for generating
-//               TypedWriteable objects
-////////////////////////////////////////////////////////////////////
-INLINE void BamReader::
-create_factory(void)
-{
-  _factory = new WriteableFactory;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamReader::get_factory
-//       Access: Public, Static
-//  Description: Returns the global WriteableFactory for generating
-//               TypedWriteable objects
-////////////////////////////////////////////////////////////////////
-INLINE WriteableFactory* BamReader::
-get_factory(void)
-{
-  if (_factory == NullFactory)
-    create_factory();
-  return _factory;
+INLINE bool BamReader::
+is_eof() const {
+  return _source->is_eof();
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::get_file_major_ver
 //       Access: Public
-//  Description: 
+//  Description: Returns the major version number of the Bam file
+//               currently being read.
 ////////////////////////////////////////////////////////////////////
 INLINE int BamReader::
-get_file_major_ver(void)
-{
+get_file_major_ver() const {
   return _file_major;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::get_file_minor_ver
 //       Access: Public
-//  Description: 
+//  Description: Returns the minor version number of the Bam file
+//               currently being read.
 ////////////////////////////////////////////////////////////////////
 INLINE int BamReader::
-get_file_minor_ver(void)
-{
+get_file_minor_ver() const {
   return _file_minor;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::get_current_major_ver
 //       Access: Public
-//  Description: 
+//  Description: Returns the major version number of Bam files
+//               supported by the current code base.  This must match
+//               get_file_major_ver() in order to successfully read a
+//               file.
 ////////////////////////////////////////////////////////////////////
 INLINE int BamReader::
-get_current_major_ver(void)
-{
+get_current_major_ver() const {
   return _cur_major;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::get_current_minor_ver
 //       Access: Public
-//  Description: 
+//  Description: Returns the minor version number of Bam files
+//               supported by the current code base.  This must match
+//               or exceed get_file_minor_ver() in order to
+//               successfully read a file.
 ////////////////////////////////////////////////////////////////////
 INLINE int BamReader::
-get_current_minor_ver(void)
-{
+get_current_minor_ver() const {
   return _cur_minor;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::queue
-//       Access: Private
-//  Description: queues the objId of the object needing to be created
+//     Function: BamReader::get_factory
+//       Access: Public, Static
+//  Description: Returns the global WriteableFactory for generating
+//               TypedWriteable objects
 ////////////////////////////////////////////////////////////////////
-INLINE void BamReader::
-queue(PN_uint16 objId)
-{
-  if (!binary_search(_deferred_reads.begin(), _deferred_reads.end(), objId))
-      _deferred_reads.push_back(objId);
+INLINE WriteableFactory* BamReader::
+get_factory() {
+  if (_factory == NullFactory)
+    create_factory();
+  return _factory;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::clear_queue
-//       Access: Private
-//  Description: Clears all pending object reads
+//     Function: BamReader::create_factory
+//       Access: Private, Static
+//  Description: Creates a new WriteableFactory for generating
+//               TypedWriteable objects
 ////////////////////////////////////////////////////////////////////
 INLINE void BamReader::
-clear_queue(void)
-{ 
-  _deferred_reads.clear();
+create_factory() {
+  _factory = new WriteableFactory;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -119,15 +97,10 @@ clear_queue(void)
 //               managing BamReader object 
 ////////////////////////////////////////////////////////////////////
 INLINE void
-parse_params(const FactoryParams &params, BamReader* &manager, Datagram &packet)
-{
-  WriteableParam *datagram_param = DCAST(WriteableParam, params.get_param(0));
-  BamReaderParam *manager_param = DCAST(BamReaderParam, params.get_param(1));
-
-  Datagram temp_packet = datagram_param->get_datagram();
-  DatagramIterator scan(temp_packet);
-  string mesg = scan.get_remaining_bytes();
-  packet.append_data(mesg.data(), mesg.size());
+parse_params(const FactoryParams &params,	
+	     DatagramIterator &scan, BamReader *&manager) {
+  BamReaderParam *param = DCAST(BamReaderParam, params.get_param(0));
 
-  manager = manager_param->get_manager();
+  scan = param->get_iterator();
+  manager = param->get_manager();
 }

+ 442 - 348
panda/src/putil/bamReader.cxx

@@ -11,45 +11,50 @@
 #include "config_util.h"
 
 WriteableFactory *BamReader::_factory = (WriteableFactory*)0L;
-BamReader* const BamReader::Null = (BamReader*)0L;
-WriteableFactory* const BamReader::NullFactory = (WriteableFactory*)0L;
+BamReader *const BamReader::Null = (BamReader*)0L;
+WriteableFactory *const BamReader::NullFactory = (WriteableFactory*)0L;
 
 const int BamReader::_cur_major = _bam_major_ver;
 const int BamReader::_cur_minor = _bam_minor_ver;
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::Destructor
+//     Function: BamReader::Constructor
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 BamReader::
-~BamReader(void)
+BamReader(DatagramGenerator *generator) 
+  : _source(generator)
 {
+  _num_extra_objects = 0;
+  _pta_id = -1;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamReader::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+BamReader::
+~BamReader() {
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::init
 //       Access: Public
-//  Description: Does all initialization necessary for BamReader to work
-//               Current this means reading in the Type Map stored as
-//               the header of the file.  This TypeMap contains the 
-//               name of all types written out and their type indeces
-//               as set when the file was created.  This map is used
-//               for later determing the current TypeHandle for each
-//               object written.  Each Object is identified in the file
-//               with the old index for space reason.
+//  Description: Initializes the BamReader prior to reading any
+//               objects from its source.
 //
 //               This returns true if the BamReader successfully
 //               initialized, false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool BamReader::
-init(void)
-{
+init() {
   Datagram header;
 
-  if (_source->is_error())
-  {
+  if (_source->is_error()) {
     return false;
   }
 
@@ -66,8 +71,7 @@ init(void)
 
   // If the major version is different, or the minor version is
   // *newer*, we can't safely load the file.
-  if (_file_major != _bam_major_ver || _file_minor > _bam_minor_ver)
-  {
+  if (_file_major != _bam_major_ver || _file_minor > _bam_minor_ver) {
     bam_cat.error()
       << "Bam file is version " << _file_major << "." << _file_minor
       << ".\n";
@@ -103,189 +107,264 @@ init(void)
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::read_handle
+//     Function: BamReader::read_object
 //       Access: Public
-//  Description: Reads a TypeHandle out of the Datagram.  If the Type
-//               has not been registered yet, BamReader will register
-//               the Type with TypeRegistry
+//  Description: Reads a single object from the Bam file.  If the
+//               object type is known, a new object of the appropriate
+//               type is created and returned; otherwise, NULL is
+//               returned.  NULL is also returned when the end of the
+//               file is reached.  is_eof() may be called to
+//               differentiate between these two cases.
+//
+//               This may be called repeatedly to extract out all the
+//               objects in the Bam file, but typically (especially
+//               for scene graph files, indicated with the .bam
+//               extension), only one object is retrieved directly
+//               from the Bam file: the root of the scene graph.  The
+//               remaining objects will all be retrieved recursively
+//               by the first object.
+//
+//               Note that the object returned may not yet be
+//               complete.  In particular, some of its pointers may
+//               not be filled in; you must call resolve() to fill in
+//               all the available pointers before you can safely use
+//               any objects returned by read_object().
 ////////////////////////////////////////////////////////////////////
-TypeHandle BamReader::
-read_handle(DatagramIterator& scan)
-{
-  int id = scan.get_uint16();
-  
-  if (id == 0)
-  {
-    //This indicates an object that should have already been read in,
-    //so return TypeHandle::none() to indicate this.
+TypedWriteable *BamReader::
+read_object() {
+  nassertr(_num_extra_objects == 0, (TypedWriteable *)NULL);
+
+  // First, read the base object.
+  int object_id = p_read_object();
+
+  // Now that object might have included some pointers to other
+  // objects, which may still need to be read.  And those objects
+  // might in turn require reading additional objects.  Read all the
+  // remaining objects.
+  while (_num_extra_objects > 0) {
+    p_read_object();
+    _num_extra_objects--;
+  }
+
+  // Now look up the pointer of the object we read first.  It should
+  // be available now.
+  if (object_id == 0) {
 #ifndef NDEBUG
     if (bam_cat.is_spam()) {
       bam_cat.spam()
-	<< "Reading previously read TypeHandle.\n";
+	<< "Returning NULL\n";
     }
 #endif
-    return TypeHandle::none();
+    return (TypedWriteable *)NULL;
   }
 
-  if (_index_map.find(id) == _index_map.end())
-  {
-    //Have not loaded this type before
-    string name = scan.get_string();
-    TypeHandle type = TypeRegistry::ptr()->find_type(name);
-    bool new_type = false;
-   
-    if (type == TypeHandle::none())
-    {
-      //This is a new type we've never heard of before so register it
-      //with the type registry
-      type = TypeRegistry::ptr()->register_dynamic_type(name);
-      bam_cat.warning()
-	<< "Bam file contains objects of unknown type: " << type << "\n";
-      new_type = true;
+  CreatedObjs::iterator oi = _created_objs.find(object_id);
+    
+  if (oi == _created_objs.end()) {
+    bam_cat.error() 
+      << "Undefined object encountered!\n";
+    return (TypedWriteable *)NULL;
+
+  } else {
+    TypedWriteable *object = (*oi).second;
+
+#ifndef NDEBUG
+    if (bam_cat.is_spam()) {
+      if (object != (TypedWriteable *)NULL) {
+	bam_cat.spam()
+	  << "Returning object of type " << object->get_type() << "\n";
+      }
     }
-    _index_map[id] = type;
-
-    // Now pick up the derivation information.
-    int num_parent_classes = scan.get_uint8();
-    for (int i = 0; i < num_parent_classes; i++) {
-      TypeHandle parent_type = read_handle(scan);
-      if (new_type) {
-	TypeRegistry::ptr()->record_derivation(type, parent_type);
+#endif
+    
+    return object;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamReader::resolve
+//       Access: Public
+//  Description: This may be called at any time during processing of
+//               the Bam file to resolve all the known pointers so
+//               far.  It is usually called at the end of the
+//               processing, after all objects have been read, which
+//               is generally the best time to call it.
+//
+//               This must be called at least once after reading a
+//               particular object via get_object() in order to
+//               validate that object.
+//
+//               The return value is true if all objects have been
+//               resolved, or false if some objects are still
+//               outstanding (in which case you will need to call
+//               resolve() again later).
+////////////////////////////////////////////////////////////////////
+bool BamReader::
+resolve() {
+  bool all_completed = true;
+
+  // Walk through all the objects that still have outstanding pointers.
+  Requests::iterator ri;
+  ri = _deferred_pointers.begin(); 
+  while (ri != _deferred_pointers.end()) {
+    TypedWriteable *whom = (*ri).first;
+    const vector_ushort &pointers = (*ri).second;
+
+    // Now make sure we have all of the pointers this object is
+    // waiting for.  If any of the pointers has not yet been read in,
+    // we can't resolve this object--we can't do anything for a given
+    // object until we have *all* outstanding pointers for that
+    // object.
+
+    bool is_complete = true;
+    vector_typedWriteable references;
+
+    vector_ushort::const_iterator pi;
+    for (pi = pointers.begin(); pi != pointers.end() && is_complete; ++pi) {
+      int object_id = (*pi);
+
+      if (object_id == 0) {
+	// A NULL pointer is a NULL pointer.
+	references.push_back((TypedWriteable *)NULL);
+
       } else {
-	if (type.get_parent_towards(parent_type) != parent_type) {
-	  bam_cat.warning()
-	    << "Bam file indicates a derivation of " << type 
-	    << " from " << parent_type << " which is no longer true.\n";
+	// See if we have the pointer available now.
+	CreatedObjs::const_iterator oi = _created_objs.find(object_id);
+	if (oi == _created_objs.end()) {
+	  // No, too bad.
+	  is_complete = false;
+
+	} else {
+	  // Yes, it's ready.
+	  references.push_back((*oi).second);
 	}
       }
     }
-    
+
+    if (is_complete) {
+      // Okay, here's the complete list of pointers for you!
+      whom->complete_pointers(references, this);
+
+      // Now remove this object from the list of things that need
+      // completion.  We have to be a bit careful when deleting things
+      // from the STL container while we are traversing it.
+      Requests::iterator old = ri;
+      ++ri;
+      _deferred_pointers.erase(old);
+
+    } else {
+      // Couldn't complete this object yet; it'll wait for next time.
+      bam_cat.warning()
+	<< "Unable to complete " << whom->get_type() << "\n";
+      ++ri;
+      all_completed = false;
+    }
   }
 
-#ifndef NDEBUG
-  if (bam_cat.is_spam()) {
-    bam_cat.spam()
-      << "Reading TypeHandle for " << _index_map[id] << ".\n";
+  if (all_completed) {
+    finalize();
   }
-#endif
 
-  return _index_map[id];
+  return all_completed;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::read_object
+//     Function: BamReader::read_handle
 //       Access: Public
-//  Description: Reads an object definition from the DatagramGenerator
-//               and generates an object of the correct type, and returns
-//               a pointer to that object.
+//  Description: Reads a TypeHandle out of the Datagram.
 ////////////////////////////////////////////////////////////////////
-TypedWriteable* BamReader::
-read_object(void)
-{
-  Datagram packet, body;
-
-  //if (_source->empty())  //If the source is empty, then we merely have
-  //{                      //back reference read's queue, so clear the queue
-  //  clear_queue();
-  //  return TypedWriteable::Null;
-  //}
+TypeHandle BamReader::
+read_handle(DatagramIterator &scan) {
+  // We encode TypeHandles within the Bam file by writing a unique
+  // index number for each one to the file.  When we write a
+  // particular TypeHandle for the first type, we assign it a new
+  // index number and then immediately follow it by its definition;
+  // when we write the same TypeHandle on subsequent times we only
+  // write the index number.
+
+  // Thus, to read a TypeHandle, we first read the index number.  If
+  // it is a number we have not yet encountered, we must then read the
+  // definition.
+
+  // Here's the index number.
+  int id = scan.get_uint16();
+  
+  if (id == 0) {
+    // Index number 0 is always, by convention, TypeHandle::none().
 
-  if (_source->is_error())
-  {
-    return TypedWriteable::Null;
+    // This indicates an object that should have already been read in,
+    // so return TypeHandle::none() to indicate this.
+#ifndef NDEBUG
+    if (bam_cat.is_spam()) {
+      bam_cat.spam()
+	<< "Read TypeHandle::none().\n";
+    }
+#endif
+    return TypeHandle::none();
   }
 
-  if (!_source->get_datagram(packet)) {
-    // The datagram source is empty.
+  IndexMap::const_iterator mi = _index_map.find(id);
+  if (mi != _index_map.end()) {
+    // We've encountered this index number before, so there should be
+    // no type definition following the id.  Simply return the
+    // TypeHandle we previously associated with the id.
+    TypeHandle type = (*mi).second;
 
 #ifndef NDEBUG
-    if (bam_cat.is_debug()) {
-      bam_cat.debug()
-	<< "Reached end of bam source.\n";
+    if (bam_cat.is_spam()) {
+      bam_cat.spam()
+	<< "Read TypeHandle for " << type << ".\n";
     }
 #endif
-    return TypedWriteable::Null;
+    return type;
   }
 
-  //Now pull out the type ID and Object ID from the
-  //datagram and pass the remaining data in that 
-  //datagram, the body to the WriteableParam for 
-  //creation of the object
-  DatagramIterator scan(packet);
-  TypeHandle type = read_handle(scan);
-  PN_uint16 objId = scan.get_uint16();
-
-  //Before anything else, check to see if type is none
-  //If that is the case, then we SHOULD have already read
-  //in and created the object (although pointers in that object
-  //may not be fully instanciated yet), so just return a pointer
-  //to that already created obj and don't try to re-create it
-  if (type != TypeHandle::none())
-  {
-    string message = scan.get_remaining_bytes();
-    body.append_data(message.data(), message.size());
-    
-    //Generate FactoryParams object to pass to the factory for
-    //creating the object
-    FactoryParams list;
-    list.add_param(new WriteableParam(body));
-    list.add_param(new BamReaderParam(this));
-
-    //Due to the recursive nature of reading in objects (and their pointers)
-    //this line is to ensure that objId gets into the map _created_objs
-    //before we call make_instance.   It works due to the nature of map.
-    //What happens is that a pair consistenting of objId and some random
-    //pointer is put into the map.  But this is okay, since in the 
-    //recursion we only refer to this objId for purposes of whether
-    //it is there or not and we immediately override it with a good
-    //value otherwise
-    _created_objs[objId];
-    _created_objs[objId] = _factory->make_instance_more_general(type, list);
+  // We haven't encountered this index number before.  This means it
+  // will be immediately followed by the type definition.  This
+  // consists of the string name, followed by the list of parent
+  // TypeHandles for this type.
 
-    //Just some sanity checks
-    if (_created_objs[objId] == (TypedWriteable *)NULL) {
-      bam_cat.error() 
-	<< "Unable to create an object of type " << type << endl;
+  string name = scan.get_string();
+  bool new_type = false;
 
-    } else if (_created_objs[objId]->get_type() != type) {
-      bam_cat.warning()
-	<< "Attempted to create a " << type.get_name() \
-	<< " but a " << _created_objs[objId]->get_type() \
-	<< " was created instead." << endl;
+  TypeHandle type = TypeRegistry::ptr()->find_type(name);
+  if (type == TypeHandle::none()) {
+    // We've never heard of this type before!  This is really an error
+    // condition, but we'll do the best we can and declare it
+    // on-the-fly.
 
+    type = TypeRegistry::ptr()->register_dynamic_type(name);
+    bam_cat.warning()
+      << "Bam file contains objects of unknown type: " << type << "\n";
+    new_type = true;
+  }
+
+  // Now pick up the derivation information.
+  int num_parent_classes = scan.get_uint8();
+  for (int i = 0; i < num_parent_classes; i++) {
+    TypeHandle parent_type = read_handle(scan);
+    if (new_type) {
+      TypeRegistry::ptr()->record_derivation(type, parent_type);
     } else {
-#ifndef NDEBUG
-      if (bam_cat.is_spam()) {
-	bam_cat.spam()
-	  << "Read a " << _created_objs[objId]->get_type() << "\n";
+      if (type.get_parent_towards(parent_type) != parent_type) {
+	bam_cat.warning()
+	  << "Bam file indicates a derivation of " << type 
+	  << " from " << parent_type << " which is no longer true.\n";
       }
-#endif
     }
   }
+  
+  bool inserted = _index_map.insert(IndexMap::value_type(id, type)).second;
+  nassertr(inserted, type);
 
 #ifndef NDEBUG
   if (bam_cat.is_spam()) {
     bam_cat.spam()
-      << "Emptying queue.\n";
+      << "Read TypeHandle for " << type << ".\n";
   }
 #endif
-  empty_queue();
 
-  TypedWriteable *object = _created_objs[objId];
-
-#ifndef NDEBUG
-  if (bam_cat.is_spam()) {
-    if (object == (TypedWriteable *)NULL) {
-      bam_cat.spam()
-	<< "Returning NULL\n";
-    } else {
-      bam_cat.spam()
-	<< "Returning object of type " << object->get_type() << "\n";
-    }
-  }
-#endif
-
-  return object;
+  return type;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -310,22 +389,21 @@ read_object(void)
 //               object properly.
 ////////////////////////////////////////////////////////////////////
 void BamReader::
-read_pointer(DatagramIterator& scan, TypedWriteable* forWhom)
-{
-  PN_uint16 objId = scan.get_uint16();
-  _deferred_pointers[forWhom].push_back(objId);
-  // This is safe since we have already read the full datagram for the
-  // object requesting this object.  So there can be no collision on
-  // that front.
-
-  // IMPORTANT NOTE: This does make the assumption that objects are
-  // requested by other objects in the same order that they wrote them
-  // originally.
-
-  // Don't queue a read of a null pointer or if the object has already
-  // been read
-  if ((objId != 0) && (_created_objs.find(objId) == _created_objs.end()))
-    queue(objId);
+read_pointer(DatagramIterator &scan, TypedWriteable *for_whom) {
+  // Read the object ID, and associate it with the requesting object.
+  int object_id = scan.get_uint16();
+  _deferred_pointers[for_whom].push_back(object_id);
+
+  // If the object ID is zero (which indicates a NULL pointer), we
+  // don't have to do anything else.
+  if (object_id != 0) {
+    if (_created_objs.count(object_id) == 0) {
+      // If we don't already have an entry in the map for this object
+      // ID (that is, we haven't encountered this object before), we
+      // must remember to read the object definition later.
+      _num_extra_objects++;
+    }
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -336,9 +414,9 @@ read_pointer(DatagramIterator& scan, TypedWriteable* forWhom)
 //               read_pointer() count times.
 ////////////////////////////////////////////////////////////////////
 void BamReader::
-read_pointers(DatagramIterator &scan, TypedWriteable *forWhom, int count) {
+read_pointers(DatagramIterator &scan, TypedWriteable *for_whom, int count) {
   for (int i = 0; i < count; i++) {
-    read_pointer(scan, forWhom);
+    read_pointer(scan, for_whom);
   }
 }
 
@@ -358,13 +436,20 @@ skip_pointer(DatagramIterator &scan) {
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::register_finalize
 //       Access: Public
-//  Description: Register for later finalization
+//  Description: Should be called by an object reading itself from the
+//               Bam file to indicate that this particular object
+//               would like to receive the finalize() callback when
+//               all the objects and pointers in the Bam file are
+//               completely read.
+//
+//               This provides a hook for objects (like Characters)
+//               that need to do any additional finalization work
+//               after all of their related pointers are guaranteed to
+//               be filled in.
 ////////////////////////////////////////////////////////////////////
 void BamReader::
-register_finalize(TypedWriteable *whom)
-{
-  if (whom == TypedWriteable::Null)
-  {
+register_finalize(TypedWriteable *whom) {
+  if (whom == TypedWriteable::Null) {
     bam_cat.error() << "Can't register a null pointer to finalize!" << endl;
     return;
   }
@@ -374,211 +459,220 @@ register_finalize(TypedWriteable *whom)
 ////////////////////////////////////////////////////////////////////
 //     Function: BamReader::finalize_now
 //       Access: Public
-//  Description: Force finalization of a particular object
+//  Description: Forces the finalization of a particular object.  This
+//               may be called by any of the objects during
+//               finalization, to guarantee finalization ordering
+//               where it is important.
 ////////////////////////////////////////////////////////////////////
 void BamReader::
-finalize_now(TypedWriteable *whom)
-{
-  if (whom == TypedWriteable::Null)
-  {
-    bam_cat.error() << "Can't finalize null pointer!" << endl;
-    return;
-  }
-  if (_finalize_list.find(whom) != _finalize_list.end())
-  {
+finalize_now(TypedWriteable *whom) {
+  nassertv(whom != (TypedWriteable *)NULL);
+  
+  Finalize::iterator fi = _finalize_list.find(whom);
+  if (fi != _finalize_list.end()) {
+    _finalize_list.erase(fi);
     whom->finalize();
-    _finalize_list.erase(whom);
-  }
-  else
-  {
-    bam_cat.warning() << "Request to finalize object of type " 
-			<< whom->get_type().get_name() << " failed" 
-			<< endl;
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::empty_queue
-//       Access: Private
-//  Description: For every objId in the queue, reads an object
-//               from the datagram source
+//     Function: BamReader::get_pta
+//       Access: Public
+//  Description: This function works in conjection with
+//               register_pta(), below, to read a PointerToArray (PTA)
+//               from the Bam file, and unify references to the same
+//               PTA.
+//
+//               The first time get_pta() encounters a particular PTA,
+//               it will return NULL.  This is the indication that the
+//               caller should then read in the data associated with
+//               the PTA, and subsequently call register_pta() with
+//               the address of the filled-in array.
+//
+//               The next time (and all subsequent times) that
+//               get_pta() encounters this same PTA, it will return
+//               the pointer that was passed with register_pta().
+//
+//               Also see the READ_PTA() macro, which consolidates all
+//               the work that must be done to read a PTA.
 ////////////////////////////////////////////////////////////////////
-void BamReader::
-empty_queue(void) {
-  size_t num_reads = _deferred_reads.size();
-  _deferred_reads.clear();
+void *BamReader::
+get_pta(DatagramIterator &scan) {
+  nassertr(_pta_id == -1, (void *)NULL);
+  int id = scan.get_uint16();
+
+  if (id == 0) {
+    // As always, a 0 ID indicates a NULL pointer.  The caller will
+    // not be able to differentiate this case from that of a
+    // previously-read pointer, but that's OK because the next data in
+    // the Bam file is the length of the array, which will be
+    // zero--indicating an empty or NULL array.
+    return (void *)NULL;
+  }
 
-  while (num_reads > 0) {
-    read_object();
-    num_reads--;
+  PTAMap::iterator pi = _ptamap.find(id);
+  if (pi == _ptamap.end()) {
+    // This is the first time we've encountered this particular ID,
+    // meaning we need to read the data now and register it.
+    _pta_id = id;
+    return (void *)NULL;
   }
+
+  return (*pi).second;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::finalize_this
-//       Access: Private
-//  Description: 
+//     Function: BamReader::register_pta
+//       Access: Public
+//  Description: The second part of read_pta(), this should be called
+//               with the pointer to the array that was read in after
+//               read_pta() returned NULL.  This associates the
+//               pointer with the ID that was previously read, so that
+//               future calls to read_pta() will return the same
+//               pointer.
+//
+//               Also see the READ_PTA() macro, which consolidates all
+//               the work that must be done to read a PTA.
 ////////////////////////////////////////////////////////////////////
 void BamReader::
-finalize_this(TypedWriteable *whom)
-{
-  whom->finalize();
-  _finalize_list.erase(whom);
+register_pta(void *ptr) {
+  if (_pta_id != -1) {
+    bool inserted = _ptamap.insert(PTAMap::value_type(_pta_id, ptr)).second;
+    _pta_id = -1;
+    nassertv(inserted);
+  }
 }
 
+
+
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::finalize
+//     Function: BamReader::p_read_object
 //       Access: Private
-//  Description: Call finalize_this on all objects stored
+//  Description: The private implementation of read_object(), this
+//               reads an object from the file and returns its object
+//               ID.
 ////////////////////////////////////////////////////////////////////
-void BamReader::
-finalize(void)
-{
-#ifndef NDEBUG
-  if (bam_cat.is_debug()) {
-    bam_cat.debug()
-      << "Finalizing bam source\n";
+int BamReader::
+p_read_object() {
+  Datagram packet;
+
+  if (_source->is_error()) {
+    return 0;
   }
-#endif
 
-  Finalize::iterator fi = _finalize_list.begin();
-  while(fi != _finalize_list.end())
-  {
-    if (*fi == TypedWriteable::Null)
-    {
-      bam_cat.error() << "Spun off into the weeds. "
-		       << "somehow a null was registered to be "
-		       << "finalized." << endl;
-      _finalize_list.erase(fi);
-    }
-    else
-    {
-      finalize_this(*fi);
+  // First, read a datagram for the object.
+  if (!_source->get_datagram(packet)) {
+    // When we run out of datagrams, we're at the end of the file.
+
+#ifndef NDEBUG
+    if (bam_cat.is_debug()) {
+      bam_cat.debug()
+	<< "Reached end of bam source.\n";
     }
-    fi = _finalize_list.begin();
+#endif
+    return 0;
   }
-}
 
-////////////////////////////////////////////////////////////////////
-//     Function: BamReader::get_pta
-//       Access: Public
-//  Description: Requests an already read PTA from BamReader.  If
-//               the PTA has not already been read and registered, 
-//               returns a NULL
-////////////////////////////////////////////////////////////////////
-void* BamReader::
-get_pta(DatagramIterator &scan)
-{
-  int _id = scan.get_uint16();
+  // Now extract the object definition from the datagram.
+  DatagramIterator scan(packet);
 
-  if (_id == 0)
-  {
-    _pta_id = -1;
-    return (void*)NULL;
-  }
+  // An object definition in a Bam file consists of a TypeHandle
+  // definition, defining the object's type, followed by an object ID
+  // index, defining the particular instance (e.g. pointer) of this
+  // object.
 
-  if (_ptamap.find(_id) == _ptamap.end())
-  {
-    _pta_id = _id;
-    return (void*)NULL;
-  }
-  else
-  {
-    //Just to enforce that register_pta should do nothing if
-    //get_pta returns a good value or a NULL was what was
-    //actually written
-    _pta_id = -1;
+  TypeHandle type = read_handle(scan);
+  int object_id = scan.get_uint16();
+
+  // There are two cases.  Either this is a new object definition, or
+  // this is a reference to an object that was previously defined.
+
+  // We use the TypeHandle to differentiate these two cases.  By
+  // convention, we write a TypeHandle::none() to the Bam file when we
+  // are writing a reference to a previously-defined object, but we
+  // write the object's actual type when we are writing its definition
+  // right now.
+
+  // Therefore, if the type is TypeHandle::none(), then we must have
+  // already read in and created the object (although its pointers may
+  // not be fully instantiated yet).  On the other hand, if the type
+  // is anything else, then we must read the definition to follow.
+
+  if (type != TypeHandle::none()) {
+    // Now we are going to read and create a new object.
+
+    // Defined the parameters for passing to the object factory.
+    FactoryParams fparams;
+    fparams.add_param(new BamReaderParam(scan, this));
+
+    // First, we must add an entry into the map for this object ID, so
+    // that in case this function is called recursively during the
+    // object's factory constructor, we will have some definition for
+    // the object.  It doesn't matter yet what the pointer is.
+    CreatedObjs::iterator oi = 
+      _created_objs.insert(CreatedObjs::value_type(object_id, NULL)).first;
+
+    // Now we can call the factory to create the object.
+    TypedWriteable *object = 
+      _factory->make_instance_more_general(type, fparams);
+
+    // And now we can store the new object pointer in the map.
+    (*oi).second = object;
+
+    //Just some sanity checks
+    if (object == (TypedWriteable *)NULL) {
+      bam_cat.error() 
+	<< "Unable to create an object of type " << type << endl;
+
+    } else if (object->get_type() != type) {
+      bam_cat.warning()
+	<< "Attempted to create a " << type.get_name() \
+	<< " but a " << object->get_type() \
+	<< " was created instead." << endl;
+
+    } else {
+#ifndef NDEBUG
+      if (bam_cat.is_spam()) {
+	bam_cat.spam()
+	  << "Read a " << object->get_type() << "\n";
+      }
+#endif
+    }
   }
-  
-  return _ptamap[_id];
-}
 
-////////////////////////////////////////////////////////////////////
-//     Function: BamReader::register_pta
-//       Access: Public
-//  Description: Utility function to be called by the objects reading
-//               themselves from a Datagram. Registers a PTA with 
-//               BamReader, so that if there are any shared ptr references,
-//               BamReader can detect and resolve those.  To be used
-//               in conjunction with get_pta
-////////////////////////////////////////////////////////////////////
-void BamReader::
-register_pta(void *ptr)
-{
-  //Just a sanity check to make sure that register_pta
-  //does nothing if get_pta has not been called first
-  if (_pta_id != -1)
-  {
-    _ptamap[_pta_id] = ptr;
+#ifndef NDEBUG
+  if (bam_cat.is_spam()) {
+    bam_cat.spam()
+      << "Emptying queue.\n";
   }
-  _pta_id = -1;
+#endif
+
+  return object_id;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReader::resolve
-//       Access: Public
-//  Description: Calling this function, asks BamReader to go ahead
-//               and resolve all pointer requests that can be resolved
+//     Function: BamReader::finalize
+//       Access: Private
+//  Description: Should be called after all objects have been read,
+//               this will finalize all the objects that registered
+//               themselves for the finalize callback.
 ////////////////////////////////////////////////////////////////////
-bool BamReader::
-resolve(void)
-{
-  Requests::iterator whom, old;
-  vector_ushort::iterator request;
-  bool objReferencesComplete;
-  vector_typedWriteable references;
-
-  //Loop through the list of all objects who registered themselves as wanting
-  //a pointer to another object to be completed
-  whom = _deferred_pointers.begin(); 
-  while(whom != _deferred_pointers.end())
-  {
-    //For each of those objects, loop through its list of objects that it is
-    //interested in.  If any one of those is not complete, then do nothing
-    //for that object, as when it is passed the list of pointers, it will
-    //expect them in a certain order and in totality.
-    objReferencesComplete = true;
-    references.clear();
-    for(request = (*whom).second.begin(); request != (*whom).second.end(); request++)
-    {
-      //Check and see if the request was for a null pointer
-      if (*request == 0)
-      {
-	references.push_back(TypedWriteable::Null);      
-      }
-      else
-      {
-	//Test to see if the object requested has been created or not yet
-	if (_created_objs.find((*request)) == _created_objs.end())
-	{
-	  objReferencesComplete = false;
-	  break;
-	}
-       	references.push_back(_created_objs[(*request)]);
-      }
-    }
-    if (objReferencesComplete)
-    {
-      (*whom).first->complete_pointers(references, this);
-      //The request list has been completed, so delete the 
-      //list froms storage
-      //Annoying STL design flaw forces this delete trick
-      old = whom;
-      whom++;
-      _deferred_pointers.erase(old);
-    }
-    else
-    {
-      // nassertv(objReferencesComplete);
-      bam_cat.warning()
-	<< "Unable to complete " << (*whom).first->get_type() << "\n";
-      whom++;
-    }
+void BamReader::
+finalize() {
+#ifndef NDEBUG
+  if (bam_cat.is_debug()) {
+    bam_cat.debug()
+      << "Finalizing bam source\n";
   }
+#endif
 
-  finalize();
+  Finalize::iterator fi = _finalize_list.begin();
+  while (fi != _finalize_list.end()) {
+    TypedWriteable *object = (*fi);
+    nassertv(object != (TypedWriteable *)NULL);
+    _finalize_list.erase(fi);
+    object->finalize();
 
-  return true;
+    fi = _finalize_list.begin();
+  }
 }
-
-

+ 95 - 80
panda/src/putil/bamReader.h

@@ -11,11 +11,12 @@
 #include "typedWriteable.h"
 #include "datagramGenerator.h"
 #include "datagramIterator.h"
-#include "writeableParam.h"
 #include "bamReaderParam.h"
 #include "factory.h"
 #include "vector_ushort.h"
-#include <deque>
+
+#include <algorithm>
+
 
 //Useful define for reading pta's
 #define READ_PTA(Manager, source, Read_func, array)   \
@@ -34,55 +35,68 @@
 
 ////////////////////////////////////////////////////////////////////
 // 	 Class : BamReader
-// Description : This class manages all aspects of reading the data
-//               structure from a DatagramGenerator  Requests are made to
-//               read an object out of the source.  This class will then
-//               read in all the necessary data and pass that data into
-//               a factory object for creating TypedWriteable objects.
-//               The factory, will call the particular "make" function
-//               of the class of the object being created.
-//               If that object has pointers to any objects that are
-//               also stored in the binary source, then that object will
-//               make a request to BamReader for that object to be
-//               read and register itself with BamReader.  Once BamReader
-//               has read in the objects requested, resolve can be called
-//               to go back and complete the pointer requests.  BamReader's
-//               interface back into the functions is complete_pointers, 
-//               which is defined in TypedWriteable
+// Description : This is the fundamental interface for extracting
+//               binary objects from a Bam file, as generated by a
+//               BamWriter.
+//
+//               A Bam file can be thought of as a linear collection
+//               of objects.  Each object is an instance of a class
+//               that inherits, directly or indirectly, from
+//               TypedWriteable.  The objects may include pointers to
+//               other objects within the Bam file; the BamReader
+//               automatically manages these and restores the pointers
+//               correctly.
+//
+//               This is the abstract interface and does not
+//               specifically deal with disk files, but rather with a
+//               DatagramGenerator of some kind, which is simply a
+//               linear source of Datagrams.  It is probably from a
+//               disk file, but it might conceivably be streamed
+//               directly from a network or some such nonsense.
+//
+//               Bam files are most often used to store scene graphs
+//               or subgraphs, and by convention they are given
+//               filenames ending in the extension ".bam" when they
+//               are used for this purpose.  However, a Bam file may
+//               store any arbitrary list of TypedWriteable objects;
+//               in this more general usage, they are given filenames
+//               ending in ".boo" to differentiate them from the more
+//               common scene graph files.
+//
+//               See also BamFile, which defines a higher-level
+//               interface to read and write Bam files on disk.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA BamReader {
 public:
   typedef Factory<TypedWriteable> WriteableFactory;
-  static BamReader* const Null;
-  static WriteableFactory* const NullFactory;
-
-  INLINE BamReader(DatagramGenerator *generator);
-  ~BamReader(void);
-
-  bool init(void);
-  TypedWriteable* read_object(void);
-  //When a client class asks BamReader to read out an object that it
-  //points to, it needs to pass a reference to itself, that BamReader
-  //can register in itself for later "fixing"
-  void read_pointer(DatagramIterator &scan, TypedWriteable* forWhom);
-  void read_pointers(DatagramIterator &scan, TypedWriteable* forWhom, int count);
-  void skip_pointer(DatagramIterator &scan);
+  static BamReader *const Null;
+  static WriteableFactory *const NullFactory;
+
+  // The primary interface for a caller.
+
+  BamReader(DatagramGenerator *generator);
+  ~BamReader();
+
+  bool init();
+  TypedWriteable *read_object();
+  INLINE bool is_eof() const;
+  bool resolve();
+
+  INLINE int get_file_major_ver() const;
+  INLINE int get_file_minor_ver() const;
 
-  //At any time you can call this function to try and resolve all
-  //outstanding pointer requests.  Will resolve all requests that
-  //it can, and ignores those it can't.   This allows for immediate
-  //use of part of a full definition if that is wanted.
-  bool resolve(void);
+  INLINE int get_current_major_ver() const;
+  INLINE int get_current_minor_ver() const;
+
+public:
+  // Functions to support classes that read themselves from the Bam.
+
+  void read_pointer(DatagramIterator &scan, TypedWriteable *for_whom);
+  void read_pointers(DatagramIterator &scan, TypedWriteable *for_whom, int count);
+  void skip_pointer(DatagramIterator &scan);
 
-  //There are some classes that need to perform certain tasks before they 
-  //are useable, but those taks can not be performed before all pointer 
-  //references have been completed.  So this function is provided as an 
-  //interface to allow each class to register itself to be finalized
   void register_finalize(TypedWriteable *whom);
 
-  //Since there may be an ordering dependency on who gets finalized first,
-  //either the parent or the children.  So this function is provided as an
-  //interface to force finalization of an object
   void finalize_now(TypedWriteable *whom);
 
   void *get_pta(DatagramIterator &scan);
@@ -91,51 +105,50 @@ public:
   TypeHandle read_handle(DatagramIterator &scan);
   
 
-  //Version access functions
-  INLINE int get_file_major_ver(void);
-  INLINE int get_file_minor_ver(void);
-
-  INLINE int get_current_major_ver(void);
-  INLINE int get_current_minor_ver(void);
 public:
-  INLINE static WriteableFactory* get_factory(void);
+  INLINE static WriteableFactory *get_factory();
 private:
-  INLINE static void create_factory(void);
+  INLINE static void create_factory();
 
 private:
-  INLINE void queue(PN_uint16);
-  void empty_queue(void);
-  INLINE void clear_queue(void);
-  void finalize_this(TypedWriteable *whom);
-  void finalize(void);
+  int p_read_object();
+  void finalize();
 
 private:
-  typedef map<int, TypedWriteable*> Created;
-  typedef map<TypedWriteable*, vector_ushort> Requests;
-  typedef set<TypedWriteable*> Finalize;
-  typedef deque<PN_uint16> DeferredReads;
- 
   static WriteableFactory *_factory;
 
   DatagramGenerator *_source;
-  //Map of old TypeHandle index number to current TypeHandle
-  map<int, TypeHandle> _index_map;
-  //Map of unique object ID in Binary structure to created object
-  Created _created_objs;
-  //Map of Objects that need pointers completed, to the
-  //object ID of the objects they need
+
+  // This maps the type index numbers encountered within the Bam file
+  // to actual TypeHandles.
+  typedef map<int, TypeHandle> IndexMap;
+  IndexMap _index_map;
+
+  // This maps the object ID numbers encountered within the Bam file
+  // to the actual pointers of the corresponding generated objects.
+  typedef map<int, TypedWriteable *> CreatedObjs;
+  CreatedObjs _created_objs;
+
+  // This records all the objects that still need their pointers
+  // completed, along with the object ID's of the pointers they need,
+  // in the order in which read_pointer() was called.
+  typedef map<TypedWriteable *, vector_ushort> Requests;
   Requests _deferred_pointers;
-  DeferredReads _deferred_reads;
 
-  //Keep track of all objects needing to be finalized
-  Finalize _finalize_list;
+  // This is the number of extra objects that must still be read (and
+  // saved in the _created_objs map) before returning from
+  // read_object().
+  int _num_extra_objects;
 
-  //Map of unique PTA ID's to the PTA's
-  map<int, void*> _ptamap;
+  // This is the set of all objects that registered themselves for
+  // finalization.
+  typedef set<TypedWriteable *> Finalize;
+  Finalize _finalize_list;
 
-  //When register_pta is called, this is the unique
-  //PTA ID that was stored during the call to 
-  //get_pta that failed.  
+  // These are used by get_pta() and register_pta() to unify multiple
+  // references to the same PointerToArray.
+  typedef map<int, void *> PTAMap;
+  PTAMap _ptamap;
   int _pta_id;
 
   int _file_major, _file_minor;
@@ -145,11 +158,13 @@ private:
 
 typedef BamReader::WriteableFactory WriteableFactory;
 
-//Useful function for taking apart the Factory Params
-//in the static functions that need to be defined in each
-//writeable class that will be generated by a factory.  Sets a
-//datagram and a BamReader
-INLINE void parse_params(const FactoryParams &, BamReader* &, Datagram &);
+// Useful function for taking apart the Factory Params in the static
+// functions that need to be defined in each writeable class that will
+// be generated by a factory.  Sets the DatagramIterator and the
+// BamReader pointers.
+INLINE void
+parse_params(const FactoryParams &params,
+	     DatagramIterator &scan, BamReader *&manager);
 
 #include "bamReader.I"
 

+ 18 - 28
panda/src/putil/bamReaderParam.I

@@ -3,56 +3,46 @@
 // 
 ////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////////////////////////
-//     Function: BamReaderParam::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE BamReaderParam::
-BamReaderParam(BamReader *manager) :
-  _manager(manager)
-{
-}
+
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReaderParam::Copy Constructor
+//     Function: BamReaderParam::get_iterator
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-INLINE BamReaderParam::
-BamReaderParam(const BamReaderParam &copy) :
-  FactoryParam(copy),
-  _manager(copy._manager)
-{
+INLINE const DatagramIterator &BamReaderParam::
+get_iterator() {
+  return _iterator;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReaderParam::Copy Assignment Operator
+//     Function: BamReaderParam::get_manager
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-INLINE void BamReaderParam::
-operator = (const BamReaderParam &copy) {
-  FactoryParam::operator = (copy);
-  _manager = copy._manager;
+INLINE BamReader *BamReaderParam::
+get_manager() {
+  return _manager;
 }
 
+
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReaderParam::Destructor
+//     Function: BamReaderParam::Constructor
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE BamReaderParam::
-~BamReaderParam(void) {
+BamReaderParam(const DatagramIterator &dgi, BamReader *manager) :
+  _iterator(dgi),
+  _manager(manager)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamReaderParam::get_datagram
+//     Function: BamReaderParam::Destructor
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
-INLINE BamReader* BamReaderParam::
-get_manager(void) {
-  return _manager;
+INLINE BamReaderParam::
+~BamReaderParam() {
 }
-

+ 7 - 11
panda/src/putil/bamReaderParam.h

@@ -9,30 +9,26 @@
 #include <pandabase.h>
 
 #include "factoryParam.h"
-#include "datagram.h"
-
-#include <vector>
 
 class BamReader;
+class DatagramIterator;
 
 ////////////////////////////////////////////////////////////////////
 // 	 Class : BamReaderParam
-// Description : The specific derivation of FactoryParam that 
-//               contains the information needed by a TypedWriteable
-//               object.  Simply contains a pointer to the managing
-//               BamReader
+// Description : The parameters that are passed through the Factory to
+//               any object constructing itself from a Bam file.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA BamReaderParam : public FactoryParam {
 public:
-  INLINE BamReader *get_manager(void);
+  INLINE const DatagramIterator &get_iterator();
+  INLINE BamReader *get_manager();
 
 private:
+  const DatagramIterator &_iterator;
   BamReader *_manager;
 
 public:
-  INLINE BamReaderParam(BamReader *manager);
-  INLINE BamReaderParam(const BamReaderParam &other);
-  INLINE void operator = (const BamReaderParam &other);
+  INLINE BamReaderParam(const DatagramIterator &dgi, BamReader *manager);
   INLINE ~BamReaderParam();
 
 public:

+ 7 - 12
panda/src/putil/test_bam.cxx

@@ -50,12 +50,10 @@ TypedWriteable* Person::
 make_person(const FactoryParams &params)
 {
   Person *me = new Person;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(me, scan, manager);
   return me;
 }
@@ -98,12 +96,10 @@ TypedWriteable* Parent::
 make_parent(const FactoryParams &params)
 {
   Parent *me = new Parent;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(me, scan, manager);
   return me;
 }
@@ -158,12 +154,11 @@ TypedWriteable* Child::
 make_child(const FactoryParams &params)
 {
   Child *me = new Child;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
+  me->fillin(me, scan, manager);
   me->fillin(me, scan, manager);
 
   return me;

+ 2 - 4
panda/src/sgattrib/billboardTransition.cxx

@@ -205,12 +205,10 @@ TypedWriteable* BillboardTransition::
 make_BillboardTransition(const FactoryParams &params)
 {
   BillboardTransition *me = new BillboardTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/colorMatrixTransition.cxx

@@ -54,12 +54,10 @@ TypedWriteable* ColorMatrixTransition::
 make_ColorMatrixTransition(const FactoryParams &params)
 {
   ColorMatrixTransition *me = new ColorMatrixTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/cullFaceTransition.cxx

@@ -120,12 +120,10 @@ TypedWriteable* CullFaceTransition::
 make_CullFaceTransition(const FactoryParams &params)
 {
   CullFaceTransition *me = new CullFaceTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/decalTransition.cxx

@@ -55,12 +55,10 @@ TypedWriteable* DecalTransition::
 make_DecalTransition(const FactoryParams &params)
 {
   DecalTransition *me = new DecalTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/depthTestTransition.cxx

@@ -111,12 +111,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable* DepthTestTransition::
 make_DepthTestTransition(const FactoryParams &params) {
   DepthTestTransition *me = new DepthTestTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/depthWriteTransition.cxx

@@ -63,12 +63,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable *DepthWriteTransition::
 make_DepthWriteTransition(const FactoryParams &params) {
   DepthWriteTransition *me = new DepthWriteTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/materialTransition.cxx

@@ -140,12 +140,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *) {
 TypedWriteable* MaterialTransition::
 make_MaterialTransition(const FactoryParams &params) {
   MaterialTransition *me = new MaterialTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/pruneTransition.cxx

@@ -54,12 +54,10 @@ TypedWriteable* PruneTransition::
 make_PruneTransition(const FactoryParams &params)
 {
   PruneTransition *me = new PruneTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/renderRelation.cxx

@@ -78,12 +78,10 @@ TypedWriteable* RenderRelation::
 make_RenderRelation(const FactoryParams &params)
 {
   RenderRelation *me = new RenderRelation;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/textureApplyTransition.cxx

@@ -118,12 +118,10 @@ TypedWriteable* TextureApplyTransition::
 make_TextureApplyTransition(const FactoryParams &params)
 {
   TextureApplyTransition *me = new TextureApplyTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/textureTransition.cxx

@@ -141,12 +141,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *) {
 TypedWriteable* TextureTransition::
 make_TextureTransition(const FactoryParams &params) {
   TextureTransition *me = new TextureTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/transformTransition.cxx

@@ -54,12 +54,10 @@ TypedWriteable* TransformTransition::
 make_TransformTransition(const FactoryParams &params)
 {
   TransformTransition *me = new TransformTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgattrib/transparencyTransition.cxx

@@ -118,12 +118,10 @@ TypedWriteable* TransparencyTransition::
 make_TransparencyTransition(const FactoryParams &params)
 {
   TransparencyTransition *me = new TransparencyTransition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgraph/geomNode.cxx

@@ -285,12 +285,10 @@ TypedWriteable* GeomNode::
 make_GeomNode(const FactoryParams &params)
 {
   GeomNode *me = new GeomNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgraph/modelNode.cxx

@@ -70,12 +70,10 @@ register_with_read_factory() {
 TypedWriteable* ModelNode::
 make_ModelNode(const FactoryParams &params) {
   ModelNode *me = new ModelNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/sgraph/modelRoot.cxx

@@ -39,12 +39,10 @@ register_with_read_factory() {
 TypedWriteable* ModelRoot::
 make_ModelRoot(const FactoryParams &params) {
   ModelRoot *me = new ModelRoot;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/switchnode/LODNode.cxx

@@ -170,12 +170,10 @@ write_datagram(BamWriter *manager, Datagram &me) {
 TypedWriteable *LODNode::
 make_LODNode(const FactoryParams &params) {
   LODNode *me = new LODNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
panda/src/switchnode/sequenceNode.cxx

@@ -164,12 +164,10 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 TypedWriteable *SequenceNode::
 make_SequenceNode(const FactoryParams &params) {
   SequenceNode *me = new SequenceNode;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 4 - 2
pandatool/src/bam/bamInfo.cxx

@@ -116,8 +116,10 @@ get_info(const Filename &filename) {
   typedef vector<TypedWriteable *> Objects;
   Objects objects;
   TypedWriteable *object = bam_file.read_object();
-  while (object != (TypedWriteable *)NULL) {
-    objects.push_back(object);
+  while (!bam_file.is_eof()) {
+    if (object != (TypedWriteable *)NULL) {
+      objects.push_back(object);
+    }
     object = bam_file.read_object();
   }
   bam_file.resolve();

+ 2 - 4
pandatool/src/egg-palettize/destTextureImage.cxx

@@ -139,12 +139,10 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
 TypedWriteable* DestTextureImage::
 make_DestTextureImage(const FactoryParams &params) {
   DestTextureImage *me = new DestTextureImage;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/eggFile.cxx

@@ -571,12 +571,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* EggFile::
 make_EggFile(const FactoryParams &params) {
   EggFile *me = new EggFile;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/paletteGroup.cxx

@@ -648,12 +648,10 @@ finalize() {
 TypedWriteable *PaletteGroup::
 make_PaletteGroup(const FactoryParams &params) {
   PaletteGroup *me = new PaletteGroup;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   manager->register_finalize(me);
   return me;

+ 2 - 4
pandatool/src/egg-palettize/paletteGroups.cxx

@@ -305,12 +305,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* PaletteGroups::
 make_PaletteGroups(const FactoryParams &params) {
   PaletteGroups *me = new PaletteGroups;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/paletteImage.cxx

@@ -798,12 +798,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable *PaletteImage::
 make_PaletteImage(const FactoryParams &params) {
   PaletteImage *me = new PaletteImage;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/palettePage.cxx

@@ -312,12 +312,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* PalettePage::
 make_PalettePage(const FactoryParams &params) {
   PalettePage *me = new PalettePage;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/palettizer.cxx

@@ -927,12 +927,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* Palettizer::
 make_Palettizer(const FactoryParams &params) {
   Palettizer *me = new Palettizer;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/sourceTextureImage.cxx

@@ -206,12 +206,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable *SourceTextureImage::
 make_SourceTextureImage(const FactoryParams &params) {
   SourceTextureImage *me = new SourceTextureImage;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/textureImage.cxx

@@ -1131,12 +1131,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable *TextureImage::
 make_TextureImage(const FactoryParams &params) {
   TextureImage *me = new TextureImage;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/texturePlacement.cxx

@@ -977,12 +977,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* TexturePlacement::
 make_TexturePlacement(const FactoryParams &params) {
   TexturePlacement *me = new TexturePlacement;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/texturePosition.cxx

@@ -112,12 +112,10 @@ write_datagram(BamWriter *writer, Datagram &datagram) {
 TypedWriteable* TexturePosition::
 make_TexturePosition(const FactoryParams &params) {
   TexturePosition *me = new TexturePosition;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/textureProperties.cxx

@@ -591,12 +591,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* TextureProperties::
 make_TextureProperties(const FactoryParams &params) {
   TextureProperties *me = new TextureProperties;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

+ 2 - 4
pandatool/src/egg-palettize/textureReference.cxx

@@ -731,12 +731,10 @@ complete_pointers(vector_typedWriteable &plist, BamReader *manager) {
 TypedWriteable* TextureReference::
 make_TextureReference(const FactoryParams &params) {
   TextureReference *me = new TextureReference;
+  DatagramIterator scan;
   BamReader *manager;
-  Datagram packet;
-
-  parse_params(params, manager, packet);
-  DatagramIterator scan(packet);
 
+  parse_params(params, scan, manager);
   me->fillin(scan, manager);
   return me;
 }

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

@@ -186,7 +186,7 @@ extract_record(FltRecordReader &reader) {
     return false;
   }
 
-  if (_header->get_flt_version() >= 15.2) {
+  if (_header->get_flt_version() >= 1520) {
     _texture_mapping_index = iterator.get_be_int16();
     iterator.skip_bytes(2);
     _color_index = iterator.get_be_int32();
@@ -238,7 +238,7 @@ build_record(FltRecordWriter &writer) const {
     return false;
   }
 
-  if (_header->get_flt_version() >= 15.2) {
+  if (_header->get_flt_version() >= 1520) {
     // New with 15.2
     datagram.add_be_int16(_texture_mapping_index);
     datagram.pad_bytes(2);

+ 30 - 28
pandatool/src/flt/fltHeader.cxx

@@ -222,14 +222,15 @@ get_auto_attr_update() const {
 //     Function: FltHeader::get_flt_version
 //       Access: Public
 //  Description: Returns the version number of the flt file as
-//               reported in the header.
+//               reported in the header, times 100.  Divide by 100 to
+//               get the floating-point version number.
 ////////////////////////////////////////////////////////////////////
-double FltHeader::
+int FltHeader::
 get_flt_version() const {
   if (_format_revision_level < 1420) {
-    return _format_revision_level;
+    return _format_revision_level * 100;
   } else {
-    return _format_revision_level / 100.0;
+    return _format_revision_level;
   }
 }
 
@@ -237,14 +238,15 @@ get_flt_version() const {
 //     Function: FltHeader::set_flt_version
 //       Access: Public
 //  Description: Changes the version number of the flt file that will
-//               be reported in the header.
+//               be reported in the header.  Pass in the
+//               floating-point version number times 100.
 ////////////////////////////////////////////////////////////////////
 void FltHeader::
-set_flt_version(double version) {
+set_flt_version(int version) {
   if (version < 14.2) {
-    _format_revision_level = (int)floor(version + 0.5);
+    _format_revision_level = version / 100;
   } else {
-    _format_revision_level = (int)floor(version * 100.0 + 0.5);
+    _format_revision_level = version;
   }
 }
 
@@ -252,24 +254,24 @@ set_flt_version(double version) {
 //     Function: FltHeader::min_flt_version
 //       Access: Public, Static
 //  Description: Returns the earliest flt version number that this
-//               codebase supports.  Earlier versions will probably
-//               not work.
+//               codebase supports (times 100).  Earlier versions will
+//               probably not work.
 ////////////////////////////////////////////////////////////////////
-double FltHeader::
+int FltHeader::
 min_flt_version() {
-  return 14.2;
+  return 1420;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: FltHeader::max_flt_version
 //       Access: Public, Static
 //  Description: Returns the latest flt version number that this
-//               codebase is known to support.  Later versions might
-//               work, but then again they may not.
+//               codebase is known to support (times 100).  Later
+//               versions might work, but then again they may not.
 ////////////////////////////////////////////////////////////////////
-double FltHeader::
+int FltHeader::
 max_flt_version() {
-  return 15.7;
+  return 1570;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -284,20 +286,20 @@ max_flt_version() {
 ////////////////////////////////////////////////////////////////////
 bool FltHeader::
 check_version() const {
-  double version = get_flt_version();
+  int version = get_flt_version();
 
-  if (version < min_flt_version() && !IS_NEARLY_EQUAL(version, min_flt_version())) {
+  if (version < min_flt_version()) {
     nout << "Warning!  The version number of this file appears to be "
-	 << version << ", which is older than " << min_flt_version()
+	 << version << ", which is older than " << min_flt_version() / 100.0
 	 << ", the oldest OpenFlight version understood by this program.  "
       "It is unlikely that this program will be able to read the file "
       "correctly.\n";
     return false;
   }
   
-  if (version > max_flt_version() && !IS_NEARLY_EQUAL(version, max_flt_version())) {
+  if (version > max_flt_version()) {
     nout << "Warning!  The version number of this file appears to be "
-	 << version << ", which is newer than " << max_flt_version()
+	 << version << ", which is newer than " << max_flt_version() / 100.0
 	 << ", the newest OpenFlight version understood by this program.  "
       "Chances are good that the program will still be able to read it "
       "correctly, but any features in the file that are specific to "
@@ -1202,19 +1204,19 @@ extract_record(FltRecordReader &reader) {
   _next_road_id = iterator.get_be_int16();
   _next_cat_id = iterator.get_be_int16();
   
-  if (get_flt_version() >= 15.2 && iterator.get_remaining_size() > 0) {
+  if (get_flt_version() >= 1520 && iterator.get_remaining_size() > 0) {
     iterator.skip_bytes(2 + 2 + 2 + 2);
     _earth_model = (EarthModel)iterator.get_be_int32();
 
     // Undocumented padding.
     iterator.skip_bytes(4);
     
-    if (get_flt_version() >= 15.6 && iterator.get_remaining_size() > 0) {
+    if (get_flt_version() >= 1560 && 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) {
+      if (get_flt_version() >= 1570 && iterator.get_remaining_size() > 0) {
 	_delta_z = iterator.get_be_float64();
 	_radius = iterator.get_be_float64();
 	_next_mesh_id = iterator.get_be_int16();
@@ -1340,20 +1342,20 @@ build_record(FltRecordWriter &writer) const {
   datagram.add_be_int16(_next_road_id);
   datagram.add_be_int16(_next_cat_id);
 
-  if (get_flt_version() >= 15.2) {
+  if (get_flt_version() >= 1520) {
     // New with 15.2
     datagram.pad_bytes(2 + 2 + 2 + 2);
     datagram.add_be_int32(_earth_model);
 
     datagram.pad_bytes(4);    
 
-    if (get_flt_version() >= 15.6) {
+    if (get_flt_version() >= 1560) {
       // 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) {
+      if (get_flt_version() >= 1570) {
 	// New with 15.7
 	datagram.add_be_float64(_delta_z);
 	datagram.add_be_float64(_radius);
@@ -1714,7 +1716,7 @@ FltError FltHeader::
 write_material_palette(FltRecordWriter &writer) const {
   FltError result;
 
-  if (get_flt_version() >= 15.2) {
+  if (get_flt_version() >= 1520) {
     // Write a version 15 material palette.
     Materials::const_iterator mi;
     for (mi = _materials.begin(); mi != _materials.end(); ++mi) {

+ 4 - 4
pandatool/src/flt/fltHeader.h

@@ -128,10 +128,10 @@ public:
   int _next_mesh_id;
 
 public:
-  double get_flt_version() const;
-  void set_flt_version(double version);
-  static double min_flt_version();
-  static double max_flt_version();
+  int get_flt_version() const;
+  void set_flt_version(int version);
+  static int min_flt_version();
+  static int max_flt_version();
   bool check_version() const;
 
   DistanceUnit get_units() const;

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

@@ -59,7 +59,7 @@ get_opcode() const {
 ////////////////////////////////////////////////////////////////////
 int FltVertex::
 get_record_length() const {
-  if (_header->get_flt_version() < 15.2) {
+  if (_header->get_flt_version() < 1520) {
     // Version 14.2
     switch (get_opcode()) {
     case FO_vertex_c:
@@ -193,7 +193,7 @@ extract_record(FltRecordReader &reader) {
   if (!_packed_color.extract_record(reader)) {
     return false;
   }
-  if (_header->get_flt_version() >= 15.2) {
+  if (_header->get_flt_version() >= 1520) {
     _color_index = iterator.get_be_int32();
 
     if (_has_normal && iterator.get_remaining_size() > 0) {
@@ -244,7 +244,7 @@ build_record(FltRecordWriter &writer) const {
     return false;
   }
 
-  if (_header->get_flt_version() >= 15.2) {
+  if (_header->get_flt_version() >= 1520) {
     // New with 15.2
     datagram.add_be_uint32(_color_index);
 

+ 9 - 7
pandatool/src/fltprogs/fltTrans.cxx

@@ -59,12 +59,13 @@ FltTrans() :
 void FltTrans::
 run() {
   if (_got_new_version) {
-    if (_new_version < FltHeader::min_flt_version() ||
-	_new_version > FltHeader::max_flt_version()) {
-      nout << "Cannot write flt files of version " << _new_version
+    int new_version = (int)floor(_new_version * 100.0 + 0.5);
+    if (new_version < FltHeader::min_flt_version() ||
+	new_version > FltHeader::max_flt_version()) {
+      nout << "Cannot write flt files of version " << new_version / 100.0
 	   << ".  This program only understands how to write flt files between version " 
-	   << FltHeader::min_flt_version() << " and " 
-	   << FltHeader::max_flt_version() << ".\n";
+	   << FltHeader::min_flt_version() / 100.0 << " and " 
+	   << FltHeader::max_flt_version() / 100.0 << ".\n";
       exit(1);
     }
   }
@@ -80,11 +81,12 @@ run() {
   }
 
   if (header->check_version()) {
-    nout << "Version is " << header->get_flt_version() << "\n";
+    nout << "Version is " << header->get_flt_version() / 100.0 << "\n";
   }
   
   if (_got_new_version) {
-    header->set_flt_version(_new_version);
+    int new_version = (int)floor(_new_version * 100.0 + 0.5);
+    header->set_flt_version(new_version);
   }
   
   result = header->write_flt(get_output());