Преглед изворни кода

various pstats improvements; pstats use 32 bit headers; added "*" category; some minor fixes

David Rose пре 20 година
родитељ
комит
819355581e
47 измењених фајлова са 493 додато и 326 уклоњено
  1. 8 13
      panda/src/char/character.cxx
  2. 2 4
      panda/src/char/character.h
  3. 1 0
      panda/src/display/standardMunger.cxx
  4. 12 2
      panda/src/egg2pg/characterMaker.cxx
  5. 8 0
      panda/src/egg2pg/config_egg2pg.cxx
  6. 1 0
      panda/src/egg2pg/config_egg2pg.h
  7. 4 3
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  8. 1 1
      panda/src/gobj/qpgeomMunger.cxx
  9. 2 2
      panda/src/gobj/qpgeomPrimitive.cxx
  10. 0 52
      panda/src/gobj/qpgeomVertexData.I
  11. 130 124
      panda/src/gobj/qpgeomVertexData.cxx
  12. 7 12
      panda/src/gobj/qpgeomVertexData.h
  13. 62 12
      panda/src/gobj/qpgeomVertexFormat.cxx
  14. 4 0
      panda/src/gobj/qpgeomVertexFormat.h
  15. 1 1
      panda/src/grutil/frameRateMeter.cxx
  16. 4 4
      panda/src/net/connection.cxx
  17. 1 1
      panda/src/net/connection.h
  18. 36 7
      panda/src/net/connectionReader.cxx
  19. 4 0
      panda/src/net/connectionReader.h
  20. 29 3
      panda/src/net/connectionWriter.cxx
  21. 4 0
      panda/src/net/connectionWriter.h
  22. 0 12
      panda/src/net/datagramTCPHeader.I
  23. 62 18
      panda/src/net/datagramTCPHeader.cxx
  24. 6 5
      panda/src/net/datagramTCPHeader.h
  25. 1 1
      panda/src/parametrics/ropeNode.cxx
  26. 1 1
      panda/src/parametrics/sheetNode.cxx
  27. 1 0
      panda/src/pgraph/binCullHandler.cxx
  28. 10 0
      panda/src/pgraph/config_pgraph.cxx
  29. 1 0
      panda/src/pgraph/config_pgraph.h
  30. 10 6
      panda/src/pgraph/cullBinStateSorted.I
  31. 0 3
      panda/src/pgraph/cullTraverser.cxx
  32. 1 0
      panda/src/pgraph/cullTraverserData.cxx
  33. 2 2
      panda/src/pgraph/cullableObject.cxx
  34. 11 0
      panda/src/pgraph/geomTransformer.cxx
  35. 0 5
      panda/src/pgraph/polylightEffect.cxx
  36. 0 3
      panda/src/pgraph/polylightEffect.h
  37. 7 1
      panda/src/pgraph/renderState.cxx
  38. 2 0
      panda/src/pgraph/renderState.h
  39. 4 0
      panda/src/pgraph/sceneGraphReducer.I
  40. 7 0
      panda/src/pgraph/sceneGraphReducer.cxx
  41. 8 1
      panda/src/pgraph/sceneGraphReducer.h
  42. 17 15
      panda/src/pgraph/transformState.cxx
  43. 2 0
      panda/src/pgraph/transformState.h
  44. 1 1
      panda/src/pstatclient/pStatClient.cxx
  45. 2 0
      panda/src/pstatclient/pStatClientImpl.cxx
  46. 11 11
      panda/src/pstatclient/pStatProperties.cxx
  47. 5 0
      panda/src/text/textNode.cxx

+ 8 - 13
panda/src/char/character.cxx

@@ -33,8 +33,7 @@
 
 TypeHandle Character::_type_handle;
 
-PStatCollector Character::_app_animation_pcollector("App:Animation");
-PStatCollector Character::_cull_animation_pcollector("Cull:Animation");
+PStatCollector Character::_animation_pcollector("*:Animation");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Character::Copy Constructor
@@ -47,8 +46,7 @@ Character(const Character &copy) :
   _cv(DynamicVertices::deep_copy(copy._cv)),
   _computed_vertices(copy._computed_vertices),
   _parts(copy._parts),
-  _app_char_pcollector(copy._app_char_pcollector),
-  _cull_char_pcollector(copy._cull_char_pcollector)
+  _char_pcollector(copy._char_pcollector)
 {
   // Now make a copy of the joint/slider hierarchy.  We could just use
   // the copy_subgraph feature of the PartBundleNode's copy
@@ -66,8 +64,7 @@ Character(const Character &copy) :
 Character::
 Character(const string &name) :
   PartBundleNode(name, new CharacterJointBundle(name)),
-  _app_char_pcollector(PStatCollector(_app_animation_pcollector, name), "Joints"),
-  _cull_char_pcollector(PStatCollector(_cull_animation_pcollector, name), "Joints")
+  _char_pcollector(PStatCollector(_animation_pcollector, name), "Joints")
 {
 }
 
@@ -162,7 +159,7 @@ cull_callback(CullTraverser *, CullTraverserData &) {
   // optimization later, to handle characters that might animate
   // themselves in front of the view frustum.
 
-  PStatTimer timer(_cull_char_pcollector);
+  PStatTimer timer(_char_pcollector);
 
   double now = ClockObject::get_global_clock()->get_frame_time();
   get_bundle()->advance_time(now);
@@ -207,7 +204,7 @@ update_to_now() {
 ////////////////////////////////////////////////////////////////////
 void Character::
 update() {
-  PStatTimer timer(_app_char_pcollector);
+  PStatTimer timer(_char_pcollector);
   do_update();
 }
 
@@ -220,7 +217,7 @@ update() {
 void Character::
 force_update() {
   // Statistics
-  PStatTimer timer(_app_char_pcollector);
+  PStatTimer timer(_char_pcollector);
 
   // First, update all the joints and sliders.
   get_bundle()->force_update();
@@ -692,10 +689,8 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 #ifdef DO_PSTATS
   // Reinitialize our collectors with our name, now that we know it.
   if (has_name()) {
-    _app_char_pcollector = 
-      PStatCollector(PStatCollector(_app_animation_pcollector, get_name()), "Joints");
-    _cull_char_pcollector = 
-      PStatCollector(PStatCollector(_cull_animation_pcollector, get_name()), "Joints");
+    _char_pcollector = 
+      PStatCollector(PStatCollector(_animation_pcollector, get_name()), "Joints");
   }
 #endif
 }

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

@@ -105,10 +105,8 @@ private:
   Parts _parts;
 
   // Statistics
-  PStatCollector _app_char_pcollector;
-  PStatCollector _cull_char_pcollector;
-  static PStatCollector _app_animation_pcollector;
-  static PStatCollector _cull_animation_pcollector;
+  PStatCollector _char_pcollector;
+  static PStatCollector _animation_pcollector;
 
 public:
   static void register_with_read_factory();

+ 1 - 0
panda/src/display/standardMunger.cxx

@@ -95,6 +95,7 @@ munge_data_impl(const qpGeomVertexData *data) {
     // Maybe we can animate the vertices with hardware.
     const TransformBlendTable *table = new_data->get_transform_blend_table();
     if (table != (TransformBlendTable *)NULL &&
+        table->get_num_transforms() != 0 &&
         table->get_max_simultaneous_transforms() <= 
         _gsg->get_max_vertex_transforms()) {
       if (matrix_palette && 

+ 12 - 2
panda/src/egg2pg/characterMaker.cxx

@@ -587,6 +587,12 @@ determine_bin_home(EggBin *egg_bin) {
   // different joints, then the entire bin must be considered dynamic.
   // (We'll indicate a dynamic bin by returning NULL.)
 
+  if (!egg_rigid_geometry) {
+    // If we don't have egg-rigid-geometry enabled, then all geometry
+    // is considered dynamic.
+    return NULL;
+  }
+
   // We need to keep track of the one joint we've encountered so far,
   // to see if all the vertices are referenced by the same joint.
   EggGroupNode *home = NULL;
@@ -681,8 +687,12 @@ determine_bin_home(EggBin *egg_bin) {
       // putting an explicit "<DCS> { none }" entry in the joint.  In
       // this case, we return NULL to treat the geometry as dynamic
       // (and animate it by animating its vertices), but display lists
-      // and vertex buffers will perform better if as much geometry as
-      // possible is rigid.
+      // and vertex buffers will perform better if more geometry is
+      // rigid.  There's a tradeoff, though, since the cull traverser
+      // will have to do more work with additional transforms in the
+      // scene graph, and this may also break up the geometry into
+      // more individual pieces, which is the biggest limiting factor
+      // on modern PC graphics cards.
       return NULL;
     }
 

+ 8 - 0
panda/src/egg2pg/config_egg2pg.cxx

@@ -76,6 +76,14 @@ ConfigVariableBool egg_combine_geoms
           "when possible.  This usually shouldn't be necessary, since the "
           "egg loader does a pretty good job of combining these by itself."));
 
+ConfigVariableBool egg_rigid_geometry
+("egg-rigid-geometry", false,
+ PRC_DESC("Set this true to create rigid pieces of an animated character as "
+          "separate static nodes, or false to leave these in with the parent "
+          "node as vertex-animated geometry.  Setting this true means less "
+          "geometry has to be vertex-animated, but there will tend to be "
+          "more separate pieces."));
+
 ConfigVariableBool egg_show_collision_solids
 ("egg-show-collision-solids", false);
 

+ 1 - 0
panda/src/egg2pg/config_egg2pg.h

@@ -44,6 +44,7 @@ extern EXPCL_PANDAEGG ConfigVariableBool egg_flatten;
 extern EXPCL_PANDAEGG ConfigVariableBool egg_unify;
 extern EXPCL_PANDAEGG ConfigVariableDouble egg_flatten_radius;
 extern EXPCL_PANDAEGG ConfigVariableBool egg_combine_geoms;
+extern EXPCL_PANDAEGG ConfigVariableBool egg_rigid_geometry;
 extern EXPCL_PANDAEGG ConfigVariableBool egg_show_collision_solids;
 extern EXPCL_PANDAEGG ConfigVariableBool egg_load_old_curves;
 extern EXPCL_PANDAEGG ConfigVariableBool egg_load_classic_nurbs_curves;

+ 4 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2222,14 +2222,15 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
   }
 
   const qpGeomVertexAnimationSpec &animation = 
-    vertex_data->get_format()->get_animation();
+    _vertex_data->get_format()->get_animation();
   bool hardware_animation = (animation.get_animation_type() == qpGeom::AT_hardware);
   if (hardware_animation) {
     // Set up the transform matrices for vertex blending.
+    nassertr(_supports_vertex_blend, false);
     GLP(Enable)(GL_VERTEX_BLEND_ARB);
     _glVertexBlendARB(animation.get_num_transforms() - 1);
-    
-    const TransformTable *table = vertex_data->get_transform_table();
+
+    const TransformTable *table = _vertex_data->get_transform_table();
     if (table != (TransformTable *)NULL) {
       if (animation.get_indexed_transforms()) {
         // We are loading the indexed matrix palette.  The ARB decided

+ 1 - 1
panda/src/gobj/qpgeomMunger.cxx

@@ -24,7 +24,7 @@
 qpGeomMunger::Registry *qpGeomMunger::_registry = NULL;
 TypeHandle qpGeomMunger::_type_handle;
 
-PStatCollector qpGeomMunger::_munge_pcollector("Cull:Munge");
+PStatCollector qpGeomMunger::_munge_pcollector("*:Munge");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomMunger::Constructor

+ 2 - 2
panda/src/gobj/qpgeomPrimitive.cxx

@@ -32,8 +32,8 @@
 
 TypeHandle qpGeomPrimitive::_type_handle;
 
-PStatCollector qpGeomPrimitive::_decompose_pcollector("Cull:Munge:Decompose");
-PStatCollector qpGeomPrimitive::_rotate_pcollector("Cull:Munge:Rotate");
+PStatCollector qpGeomPrimitive::_decompose_pcollector("*:Munge:Decompose");
+PStatCollector qpGeomPrimitive::_rotate_pcollector("*:Munge:Rotate");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::Default Constructor

+ 0 - 52
panda/src/gobj/qpgeomVertexData.I

@@ -29,21 +29,6 @@ get_name() const {
   return _name;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexData::set_name
-//       Access: Published
-//  Description: Changes the name of the vertex data.  This name is
-//               reported on the PStats graph for vertex computations.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexData::
-set_name(const string &name) {
-  _name = name;
-  _app_char_pcollector = 
-    PStatCollector(PStatCollector(_app_animation_pcollector, name), "Vertices");
-  _cull_char_pcollector =
-    PStatCollector(PStatCollector(_cull_animation_pcollector, name), "Vertices");
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::get_format
 //       Access: Published
@@ -249,43 +234,6 @@ get_modified() const {
   return cdata->_modified;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexData::animate_vertices
-//       Access: Published
-//  Description: Returns a GeomVertexData that represents the results
-//               of computing the vertex animation on the CPU for this
-//               GeomVertexData.
-//
-//               If there is no CPU-defined vertex animation on this
-//               object, this just returns the original object.
-//
-//               If there is vertex animation, but the VertexTransform
-//               values have not changed since last time, this may
-//               return the same pointer it returned previously.  Even
-//               if the VertexTransform values have changed, it may
-//               still return the same pointer, but with its contents
-//               modified (this is preferred, since it allows the
-//               graphics backend to update vertex buffers optimally).
-////////////////////////////////////////////////////////////////////
-INLINE CPT(qpGeomVertexData) qpGeomVertexData::
-animate_vertices() const {
-  return do_animate_vertices(true);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexData::animate_vertices_cull
-//       Access: Public
-//  Description: Does exactly the same thing as animate_vertices(),
-//               but when PStats is enabled, it records the time spent
-//               as during the cull step instead of the app step.
-//               This is intended to be called from the cull callback,
-//               rather the called directly by the user.
-////////////////////////////////////////////////////////////////////
-INLINE CPT(qpGeomVertexData) qpGeomVertexData::
-animate_vertices_cull() const {
-  return do_animate_vertices(false);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::has_vertex
 //       Access: Public

+ 130 - 124
panda/src/gobj/qpgeomVertexData.cxx

@@ -28,11 +28,10 @@
 
 TypeHandle qpGeomVertexData::_type_handle;
 
-PStatCollector qpGeomVertexData::_convert_pcollector("Cull:Munge:Convert");
-PStatCollector qpGeomVertexData::_scale_color_pcollector("Cull:Munge:Scale color");
-PStatCollector qpGeomVertexData::_set_color_pcollector("Cull:Munge:Set color");
-PStatCollector qpGeomVertexData::_app_animation_pcollector("App:Animation");
-PStatCollector qpGeomVertexData::_cull_animation_pcollector("Cull:Animation");
+PStatCollector qpGeomVertexData::_convert_pcollector("*:Munge:Convert");
+PStatCollector qpGeomVertexData::_scale_color_pcollector("*:Munge:Scale color");
+PStatCollector qpGeomVertexData::_set_color_pcollector("*:Munge:Set color");
+PStatCollector qpGeomVertexData::_animation_pcollector("*:Animation");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::Default Constructor
@@ -42,8 +41,9 @@ PStatCollector qpGeomVertexData::_cull_animation_pcollector("Cull:Animation");
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexData::
 qpGeomVertexData() :
-  _app_char_pcollector(_app_animation_pcollector),
-  _cull_char_pcollector(_cull_animation_pcollector)
+  _char_pcollector(_animation_pcollector, "unnamed"),
+  _skinning_pcollector(_char_pcollector, "Skinning"),
+  _morphs_pcollector(_char_pcollector, "Morphs")
 {
 }
 
@@ -58,8 +58,9 @@ qpGeomVertexData(const string &name,
                  qpGeomVertexData::UsageHint usage_hint) :
   _name(name),
   _format(format),
-  _app_char_pcollector(PStatCollector(_app_animation_pcollector, name), "Vertices"),
-  _cull_char_pcollector(PStatCollector(_cull_animation_pcollector, name), "Vertices")
+  _char_pcollector(PStatCollector(_animation_pcollector, name)),
+  _skinning_pcollector(_char_pcollector, "Skinning"),
+  _morphs_pcollector(_char_pcollector, "Morphs")
 {
   nassertv(_format->is_registered());
 
@@ -87,8 +88,9 @@ qpGeomVertexData(const qpGeomVertexData &copy) :
   _name(copy._name),
   _format(copy._format),
   _cycler(copy._cycler),
-  _app_char_pcollector(copy._app_char_pcollector),
-  _cull_char_pcollector(copy._cull_char_pcollector)
+  _char_pcollector(copy._char_pcollector),
+  _skinning_pcollector(copy._skinning_pcollector),
+  _morphs_pcollector(copy._morphs_pcollector)
 {
 }
 
@@ -107,8 +109,9 @@ qpGeomVertexData(const qpGeomVertexData &copy,
   _name(copy._name),
   _format(format),
   _cycler(copy._cycler),
-  _app_char_pcollector(copy._app_char_pcollector),
-  _cull_char_pcollector(copy._cull_char_pcollector)
+  _char_pcollector(copy._char_pcollector),
+  _skinning_pcollector(copy._skinning_pcollector),
+  _morphs_pcollector(copy._morphs_pcollector)
 {
   nassertv(_format->is_registered());
 
@@ -136,8 +139,9 @@ operator = (const qpGeomVertexData &copy) {
   _name = copy._name;
   _format = copy._format;
   _cycler = copy._cycler;
-  _app_char_pcollector = copy._app_char_pcollector;
-  _cull_char_pcollector = copy._cull_char_pcollector;
+  _char_pcollector = copy._char_pcollector;
+  _skinning_pcollector = copy._skinning_pcollector;
+  _morphs_pcollector = copy._morphs_pcollector;
 
   CDWriter cdata(_cycler);
   clear_cache();
@@ -171,6 +175,20 @@ qpGeomVertexData::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::set_name
+//       Access: Published
+//  Description: Changes the name of the vertex data.  This name is
+//               reported on the PStats graph for vertex computations.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+set_name(const string &name) {
+  _name = name;
+  _char_pcollector = PStatCollector(_animation_pcollector, name);
+  _skinning_pcollector = PStatCollector(_char_pcollector, "Skinning");
+  _morphs_pcollector = PStatCollector(_char_pcollector, "Morphs");
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::set_usage_hint
 //       Access: Published
@@ -832,6 +850,96 @@ set_color(const Colorf &color, int num_components,
   return new_data;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::animate_vertices
+//       Access: Published
+//  Description: Returns a GeomVertexData that represents the results
+//               of computing the vertex animation on the CPU for this
+//               GeomVertexData.
+//
+//               If there is no CPU-defined vertex animation on this
+//               object, this just returns the original object.
+//
+//               If there is vertex animation, but the VertexTransform
+//               values have not changed since last time, this may
+//               return the same pointer it returned previously.  Even
+//               if the VertexTransform values have changed, it may
+//               still return the same pointer, but with its contents
+//               modified (this is preferred, since it allows the
+//               graphics backend to update vertex buffers optimally).
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexData) qpGeomVertexData::
+animate_vertices() const {
+  CDReader cdata(_cycler);
+
+  if (_format->get_animation().get_animation_type() != AT_panda) {
+    return this;
+  }
+
+  UpdateSeq modified;
+  if (cdata->_transform_blend_table != (TransformBlendTable *)NULL) {
+    if (cdata->_slider_table != (SliderTable *)NULL) {
+      modified = 
+        max(cdata->_transform_blend_table->get_modified(),
+            cdata->_slider_table->get_modified());
+    } else {
+      modified = cdata->_transform_blend_table->get_modified();
+    }
+
+  } else if (cdata->_slider_table != (SliderTable *)NULL) {
+    modified = cdata->_slider_table->get_modified();
+
+  } else {
+    // No transform blend table or slider table--ergo, no vertex
+    // animation.
+    return this;
+  }
+
+  if (cdata->_animated_vertices_modified == modified &&
+      cdata->_animated_vertices != (qpGeomVertexData *)NULL) {
+    // No changes.
+    return cdata->_animated_vertices;
+  }
+  CDWriter cdataw(((qpGeomVertexData *)this)->_cycler, cdata);
+  cdataw->_animated_vertices_modified = modified;
+  ((qpGeomVertexData *)this)->update_animated_vertices(cdataw);
+  return cdataw->_animated_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::bytewise_copy
+//       Access: Private, Static
+//  Description: Quickly copies data without the need to convert it.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+bytewise_copy(unsigned char *to, int to_stride,
+              const unsigned char *from, int from_stride,
+              const qpGeomVertexColumn *from_type,
+              int num_records) {
+  if (gobj_cat.is_debug()) {
+    gobj_cat.debug()
+      << "bytewise_copy(" << (void *)to << ", " << to_stride
+      << ", " << (const void *)from << ", " << from_stride
+      << ", " << *from_type << ", " << num_records << ")\n";
+  }
+  if (to_stride == from_type->get_total_bytes() && 
+      from_stride == from_type->get_total_bytes()) {
+    // Fantastic!  It's just a linear array of this one data type.
+    // Copy the whole thing all at once.
+    memcpy(to, from, num_records * from_type->get_total_bytes());
+
+  } else {
+    // Ok, it's interleaved in with other data.  Copy them one record
+    // at a time.
+    while (num_records > 0) {
+      memcpy(to, from, from_type->get_total_bytes());
+      to += to_stride;
+      from += from_stride;
+      num_records--;
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::replace_column
 //       Access: Published
@@ -1085,84 +1193,6 @@ get_color_info(const qpGeomVertexArrayData *&array_data,
   return false;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexData::do_animate_vertices
-//       Access: Private
-//  Description: This is the private implementation of
-//               animate_vertices() and animate_vertices_cull().
-////////////////////////////////////////////////////////////////////
-CPT(qpGeomVertexData) qpGeomVertexData::
-do_animate_vertices(bool from_app) const {
-  CDReader cdata(_cycler);
-
-  if (_format->get_animation().get_animation_type() != AT_panda) {
-    return this;
-  }
-
-  UpdateSeq modified;
-  if (cdata->_transform_blend_table != (TransformBlendTable *)NULL) {
-    if (cdata->_slider_table != (SliderTable *)NULL) {
-      modified = 
-        max(cdata->_transform_blend_table->get_modified(),
-            cdata->_slider_table->get_modified());
-    } else {
-      modified = cdata->_transform_blend_table->get_modified();
-    }
-
-  } else if (cdata->_slider_table != (SliderTable *)NULL) {
-    modified = cdata->_slider_table->get_modified();
-
-  } else {
-    // No transform blend table or slider table--ergo, no vertex
-    // animation.
-    return this;
-  }
-
-  if (cdata->_animated_vertices_modified == modified &&
-      cdata->_animated_vertices != (qpGeomVertexData *)NULL) {
-    // No changes.
-    return cdata->_animated_vertices;
-  }
-  CDWriter cdataw(((qpGeomVertexData *)this)->_cycler, cdata);
-  cdataw->_animated_vertices_modified = modified;
-  ((qpGeomVertexData *)this)->update_animated_vertices(cdataw, from_app);
-  return cdataw->_animated_vertices;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexData::bytewise_copy
-//       Access: Private, Static
-//  Description: Quickly copies data without the need to convert it.
-////////////////////////////////////////////////////////////////////
-void qpGeomVertexData::
-bytewise_copy(unsigned char *to, int to_stride,
-              const unsigned char *from, int from_stride,
-              const qpGeomVertexColumn *from_type,
-              int num_records) {
-  if (gobj_cat.is_debug()) {
-    gobj_cat.debug()
-      << "bytewise_copy(" << (void *)to << ", " << to_stride
-      << ", " << (const void *)from << ", " << from_stride
-      << ", " << *from_type << ", " << num_records << ")\n";
-  }
-  if (to_stride == from_type->get_total_bytes() && 
-      from_stride == from_type->get_total_bytes()) {
-    // Fantastic!  It's just a linear array of this one data type.
-    // Copy the whole thing all at once.
-    memcpy(to, from, num_records * from_type->get_total_bytes());
-
-  } else {
-    // Ok, it's interleaved in with other data.  Copy them one record
-    // at a time.
-    while (num_records > 0) {
-      memcpy(to, from, from_type->get_total_bytes());
-      to += to_stride;
-      from += from_stride;
-      num_records--;
-    }
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::packed_argb_to_uint8_rgba
 //       Access: Private, Static
@@ -1302,7 +1332,7 @@ do_set_num_rows(int n, qpGeomVertexData::CDWriter &cdata) {
 //               existing animated_vertices object.
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexData::
-update_animated_vertices(qpGeomVertexData::CDWriter &cdata, bool from_app) {
+update_animated_vertices(qpGeomVertexData::CDWriter &cdata) {
   int num_rows = get_num_rows();
 
   if (gobj_cat.is_debug()) {
@@ -1311,15 +1341,12 @@ update_animated_vertices(qpGeomVertexData::CDWriter &cdata, bool from_app) {
       << "\n";
   }
 
-#ifdef DO_PSTATS
-  PStatCollector &collector = from_app ? _app_char_pcollector : _cull_char_pcollector;
-  PStatTimer timer(collector);
-#endif
+  PStatTimer timer(_char_pcollector);
 
   if (cdata->_animated_vertices == (qpGeomVertexData *)NULL) {
-    CPT(qpGeomVertexFormat) animated_format = get_post_animated_format();
+    CPT(qpGeomVertexFormat) new_format = _format->get_post_animated_format();
     cdata->_animated_vertices = 
-      new qpGeomVertexData(get_name(), animated_format,
+      new qpGeomVertexData(get_name(), new_format,
                            min(get_usage_hint(), UH_dynamic));
   }
   PT(qpGeomVertexData) new_data = cdata->_animated_vertices;
@@ -1334,6 +1361,7 @@ update_animated_vertices(qpGeomVertexData::CDWriter &cdata, bool from_app) {
   // First, apply all of the morphs.
   CPT(SliderTable) slider_table = cdata->_slider_table;
   if (slider_table != (SliderTable *)NULL) {
+    PStatTimer timer2(_morphs_pcollector);
     int num_morphs = _format->get_num_morphs();
     for (int mi = 0; mi < num_morphs; mi++) {
       CPT(InternalName) slider_name = _format->get_morph_slider(mi);
@@ -1384,6 +1412,7 @@ update_animated_vertices(qpGeomVertexData::CDWriter &cdata, bool from_app) {
   // Then apply the transforms.
   CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table;
   if (tb_table != (TransformBlendTable *)NULL) {
+    PStatTimer timer3(_skinning_pcollector);
 
     // Recompute all the blends up front, so we don't have to test
     // each one for staleness at each vertex.
@@ -1437,29 +1466,6 @@ update_animated_vertices(qpGeomVertexData::CDWriter &cdata, bool from_app) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexData::get_post_animated_format
-//       Access: Private
-//  Description: Returns a suitable vertex format for sending the
-//               animated vertices to the graphics backend.  This is
-//               the same format as the source format, with the
-//               CPU-animation data elements removed.
-////////////////////////////////////////////////////////////////////
-CPT(qpGeomVertexFormat) qpGeomVertexData::
-get_post_animated_format() const {
-  PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*_format);
-
-  new_format->remove_column(InternalName::get_transform_blend());
-
-  int num_morphs = _format->get_num_morphs();
-  for (int mi = 0; mi < num_morphs; mi++) {
-    CPT(InternalName) delta_name = _format->get_morph_delta(mi);
-    new_format->remove_column(delta_name);
-  }
-
-  return qpGeomVertexFormat::register_format(new_format);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexData::register_with_read_factory
 //       Access: Public, Static
@@ -1589,7 +1595,7 @@ void qpGeomVertexData::
 fillin(DatagramIterator &scan, BamReader *manager) {
   TypedWritableReferenceCount::fillin(scan, manager);
 
-  _name = scan.get_string();
+  set_name(scan.get_string());
   manager->read_pointer(scan);
 
   manager->read_cdata(scan, _cycler);

+ 7 - 12
panda/src/gobj/qpgeomVertexData.h

@@ -87,7 +87,7 @@ PUBLISHED:
   virtual ~qpGeomVertexData();
 
   INLINE const string &get_name() const;
-  INLINE void set_name(const string &name);
+  void set_name(const string &name);
 
   INLINE const qpGeomVertexFormat *get_format() const;
   INLINE UsageHint get_usage_hint() const;
@@ -135,7 +135,7 @@ PUBLISHED:
     set_color(const Colorf &color, int num_components,
               NumericType numeric_type, Contents contents) const;
 
-  INLINE CPT(qpGeomVertexData) animate_vertices() const;
+  CPT(qpGeomVertexData) animate_vertices() const;
 
   PT(qpGeomVertexData) 
     replace_column(const InternalName *name, int num_components,
@@ -147,8 +147,6 @@ PUBLISHED:
   void clear_cache();
 
 public:
-  INLINE CPT(qpGeomVertexData) animate_vertices_cull() const;
-
   bool get_array_info(const InternalName *name, 
                       const qpGeomVertexArrayData *&array_data,
                       int &num_values, NumericType &numeric_type, 
@@ -178,8 +176,6 @@ public:
   static INLINE unsigned int unpack_abcd_d(PN_uint32 data);
 
 private:
-  CPT(qpGeomVertexData) do_animate_vertices(bool from_app) const;
-
   static void bytewise_copy(unsigned char *to, int to_stride,
                             const unsigned char *from, int from_stride,
                             const qpGeomVertexColumn *from_type,
@@ -248,17 +244,16 @@ private:
 
 private:
   bool do_set_num_rows(int n, CDWriter &cdata);
-  void update_animated_vertices(CDWriter &cdata, bool from_app);
-  CPT(qpGeomVertexFormat) get_post_animated_format() const;
+  void update_animated_vertices(CDWriter &cdata);
 
   static PStatCollector _convert_pcollector;
   static PStatCollector _scale_color_pcollector;
   static PStatCollector _set_color_pcollector;
-  static PStatCollector _app_animation_pcollector;
-  static PStatCollector _cull_animation_pcollector;
+  static PStatCollector _animation_pcollector;
 
-  PStatCollector _app_char_pcollector;
-  PStatCollector _cull_char_pcollector;
+  PStatCollector _char_pcollector;
+  PStatCollector _skinning_pcollector;
+  PStatCollector _morphs_pcollector;
 
 public:
   static void register_with_read_factory();

+ 62 - 12
panda/src/gobj/qpgeomVertexFormat.cxx

@@ -34,7 +34,8 @@ TypeHandle qpGeomVertexFormat::_type_handle;
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexFormat::
 qpGeomVertexFormat() :
-  _is_registered(false)
+  _is_registered(false),
+  _post_animated_format(NULL)
 {
 }
 
@@ -45,7 +46,8 @@ qpGeomVertexFormat() :
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexFormat::
 qpGeomVertexFormat(const qpGeomVertexArrayFormat *array_format) :
-  _is_registered(false)
+  _is_registered(false),
+  _post_animated_format(NULL)
 {
   add_array(array_format);
 }
@@ -59,7 +61,8 @@ qpGeomVertexFormat::
 qpGeomVertexFormat(const qpGeomVertexFormat &copy) :
   _is_registered(false),
   _animation(copy._animation),
-  _arrays(copy._arrays)
+  _arrays(copy._arrays),
+  _post_animated_format(NULL)
 {
 }
 
@@ -70,7 +73,7 @@ qpGeomVertexFormat(const qpGeomVertexFormat &copy) :
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexFormat::
 operator = (const qpGeomVertexFormat &copy) {
-  nassertv(!_is_registered);
+  nassertv(!is_registered());
 
   _animation = copy._animation;
   _arrays = copy._arrays;
@@ -88,6 +91,47 @@ qpGeomVertexFormat::
   }
 }
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_post_animated_format
+//       Access: Published
+//  Description: Returns a suitable vertex format for sending the
+//               animated vertices to the graphics backend.  This is
+//               the same format as the source format, with the
+//               CPU-animation data elements removed.
+//
+//               This may only be called after the format has been
+//               registered.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexFormat) qpGeomVertexFormat::
+get_post_animated_format() const {
+  nassertr(is_registered(), NULL);
+
+  if (_post_animated_format == (qpGeomVertexFormat *)NULL) {
+    PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*this);
+    new_format->remove_column(InternalName::get_transform_blend());
+    
+    int num_morphs = get_num_morphs();
+    for (int mi = 0; mi < num_morphs; mi++) {
+      CPT(InternalName) delta_name = get_morph_delta(mi);
+      new_format->remove_column(delta_name);
+    }
+
+    CPT(qpGeomVertexFormat) registered = 
+      qpGeomVertexFormat::register_format(new_format);
+    ((qpGeomVertexFormat *)this)->_post_animated_format = registered;
+    if (_post_animated_format != this) {
+      // We only keep the reference count if the new pointer is not
+      // the same as this, to avoid a circular dependency.
+      _post_animated_format->ref();
+    }
+  }
+
+  _post_animated_format->test_ref_count_integrity();
+
+  return _post_animated_format;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexFormat::modify_array
 //       Access: Published
@@ -100,7 +144,7 @@ qpGeomVertexFormat::
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexArrayFormat *qpGeomVertexFormat::
 modify_array(int array) {
-  nassertr(!_is_registered, NULL);
+  nassertr(!is_registered(), NULL);
   nassertr(array >= 0 && array < (int)_arrays.size(), NULL);
 
   if (_arrays[array]->is_registered() ||
@@ -121,7 +165,7 @@ modify_array(int array) {
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexFormat::
 set_array(int array, const qpGeomVertexArrayFormat *format) {
-  nassertv(!_is_registered);
+  nassertv(!is_registered());
   nassertv(array >= 0 && array < (int)_arrays.size());
   _arrays[array] = (qpGeomVertexArrayFormat *)format;
 }
@@ -136,7 +180,7 @@ set_array(int array, const qpGeomVertexArrayFormat *format) {
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexFormat::
 remove_array(int array) {
-  nassertv(!_is_registered);
+  nassertv(!is_registered());
 
   nassertv(array >= 0 && array < (int)_arrays.size());
   _arrays.erase(_arrays.begin() + array);
@@ -155,7 +199,7 @@ remove_array(int array) {
 ////////////////////////////////////////////////////////////////////
 int qpGeomVertexFormat::
 add_array(const qpGeomVertexArrayFormat *array_format) {
-  nassertr(!_is_registered, -1);
+  nassertr(!is_registered(), -1);
 
   int new_array = (int)_arrays.size();
   _arrays.push_back((qpGeomVertexArrayFormat *)array_format);
@@ -175,7 +219,7 @@ add_array(const qpGeomVertexArrayFormat *array_format) {
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexFormat::
 insert_array(int array, const qpGeomVertexArrayFormat *array_format) {
-  nassertv(!_is_registered);
+  nassertv(!is_registered());
   nassertv(array >= 0 && array <= (int)_arrays.size());
 
   _arrays.insert(_arrays.begin() + array, (qpGeomVertexArrayFormat *)array_format);
@@ -192,7 +236,7 @@ insert_array(int array, const qpGeomVertexArrayFormat *array_format) {
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexFormat::
 clear_arrays() {
-  nassertv(!_is_registered);
+  nassertv(!is_registered());
 
   _arrays.clear();
 }
@@ -327,7 +371,7 @@ get_column(const InternalName *name) const {
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexFormat::
 remove_column(const InternalName *name) {
-  nassertv(!_is_registered);
+  nassertv(!is_registered());
 
   // Since the format's not registered, it doesn't yet have an index
   // of columns--so we have to search all of the arrays, one at a
@@ -500,7 +544,7 @@ make_registry() {
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexFormat::
 do_register() {
-  nassertv(!_is_registered);
+  nassertv(!is_registered());
   nassertv(_columns_by_name.empty());
 
   for (int array = 0; array < (int)_arrays.size(); ++array) {
@@ -612,6 +656,12 @@ do_unregister() {
   _vectors.clear();
   _texcoords.clear();
   _morphs.clear();
+
+  if (_post_animated_format != (qpGeomVertexFormat *)NULL && 
+      _post_animated_format != this) {
+    unref_delete(_post_animated_format);
+  }
+  _post_animated_format = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 0
panda/src/gobj/qpgeomVertexFormat.h

@@ -80,6 +80,8 @@ PUBLISHED:
   INLINE const qpGeomVertexAnimationSpec &get_animation() const;
   INLINE void set_animation(const qpGeomVertexAnimationSpec &animation);
 
+  CPT(qpGeomVertexFormat) get_post_animated_format() const;
+
   INLINE int get_num_arrays() const;
   INLINE const qpGeomVertexArrayFormat *get_array(int array) const;
   qpGeomVertexArrayFormat *modify_array(int array);
@@ -205,6 +207,8 @@ private:
   typedef pvector<MorphRecord> Morphs;
   Morphs _morphs;
 
+  const qpGeomVertexFormat *_post_animated_format;
+
   // This is the global registry of all currently-in-use formats.
   typedef pset<qpGeomVertexFormat *, IndirectCompareTo<qpGeomVertexFormat> > Formats;
   class EXPCL_PANDA Registry {

+ 1 - 1
panda/src/grutil/frameRateMeter.cxx

@@ -27,7 +27,7 @@
 #include "pStatTimer.h"
 #include <stdio.h>  // For sprintf/snprintf
 
-PStatCollector FrameRateMeter::_show_fps_pcollector("Cull:Show fps");
+PStatCollector FrameRateMeter::_show_fps_pcollector("*:Show fps");
 
 TypeHandle FrameRateMeter::_type_handle;
 

+ 4 - 4
panda/src/net/connection.cxx

@@ -364,7 +364,7 @@ set_max_segment(int size) {
 //               it notifies the ConnectionManager.
 ////////////////////////////////////////////////////////////////////
 bool Connection::
-send_datagram(const NetDatagram &datagram) {
+send_datagram(const NetDatagram &datagram, int tcp_header_size) {
   nassertr(_socket != (PRFileDesc *)NULL, false);
 
   if (PR_GetDescType(_socket) == PR_DESC_SOCKET_UDP) {
@@ -393,7 +393,7 @@ send_datagram(const NetDatagram &datagram) {
   }
 
   // We might queue up TCP packets for later sending.
-  if (datagram.get_length() >= 0x10000) {
+  if (tcp_header_size == 2 && datagram.get_length() >= 0x10000) {
     net_cat.error()
       << "Attempt to send TCP datagram of " << datagram.get_length()
       << " bytes--too long!\n";
@@ -401,7 +401,7 @@ send_datagram(const NetDatagram &datagram) {
     return false;
   }
 
-  DatagramTCPHeader header(datagram);
+  DatagramTCPHeader header(datagram, tcp_header_size);
 
   PR_Lock(_write_mutex);
   _queued_data += header.get_header();
@@ -409,7 +409,7 @@ send_datagram(const NetDatagram &datagram) {
   _queued_count++;
   
   if (net_cat.is_debug()) {
-    header.verify_datagram(datagram);
+    header.verify_datagram(datagram, tcp_header_size);
   }
 
   if (!_collect_tcp || 

+ 1 - 1
panda/src/net/connection.h

@@ -66,7 +66,7 @@ PUBLISHED:
   void set_max_segment(int size);
 
 private:
-  bool send_datagram(const NetDatagram &datagram);
+  bool send_datagram(const NetDatagram &datagram, int tcp_header_size);
   bool send_raw_datagram(const NetDatagram &datagram);
   bool do_flush();
   bool check_send_error(PRInt32 result, PRErrorCode errcode, PRInt32 bytes_to_send);

+ 36 - 7
panda/src/net/connectionReader.cxx

@@ -82,6 +82,7 @@ ConnectionReader(ConnectionManager *manager, int num_threads) :
   _manager(manager)
 {
   _raw_mode = false;
+  _tcp_header_size = datagram_tcp16_header_size;
   _polling = (num_threads <= 0);
 
   _shutdown = false;
@@ -330,6 +331,9 @@ get_num_threads() const {
 //               raw mode).  In raw mode, datagram headers are not
 //               expected; instead, all the data available on the pipe
 //               is treated as a single datagram.
+//
+//               This is similar to set_tcp_header_size(0), except that it
+//               also turns off headers for UDP packets.
 ////////////////////////////////////////////////////////////////////
 void ConnectionReader::
 set_raw_mode(bool mode) {
@@ -347,6 +351,31 @@ get_raw_mode() const {
   return _raw_mode;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionReader::set_tcp_header_size
+//       Access: Public
+//  Description: Sets the header size of TCP packets.  At the present,
+//               legal values for this are 0, 2, or 4; this specifies
+//               the number of bytes to use encode the datagram length
+//               at the start of each TCP datagram.  Sender and
+//               receiver must independently agree on this.
+////////////////////////////////////////////////////////////////////
+void ConnectionReader::
+set_tcp_header_size(int tcp_header_size) {
+  _tcp_header_size = tcp_header_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionReader::get_tcp_header_size
+//       Access: Public
+//  Description: Returns the current setting of TCP header size.
+//               See set_tcp_header_size().
+////////////////////////////////////////////////////////////////////
+int ConnectionReader::
+get_tcp_header_size() const {
+  return _tcp_header_size;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConnectionReader::shutdown
 //       Access: Protected
@@ -542,11 +571,11 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
     pprerror("PR_GetSockName");
   }
 
-  // First, we have to read the first datagram_tcp_header_size bytes.
-  while (header_bytes_read < datagram_tcp_header_size) {
+  // First, we have to read the first _tcp_header_size bytes.
+  while (header_bytes_read < _tcp_header_size) {
     PRInt32 bytes_read =
       PR_Recv(socket, buffer + header_bytes_read,
-              datagram_tcp_header_size - header_bytes_read, 0,
+              _tcp_header_size - header_bytes_read, 0,
               PR_INTERVAL_NO_TIMEOUT);
 
     if (bytes_read < 0) {
@@ -582,7 +611,7 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
 
   // Now we must decode the header to determine how big the datagram
   // is.  This means we must have read at least a full header.
-  if (header_bytes_read != datagram_tcp_header_size) {
+  if (header_bytes_read != _tcp_header_size) {
     // This should actually be impossible, by the read-loop logic
     // above.
     net_cat.error()
@@ -591,8 +620,8 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
     return;
   }
 
-  DatagramTCPHeader header(buffer);
-  PRInt32 size = header.get_datagram_size();
+  DatagramTCPHeader header(buffer, _tcp_header_size);
+  PRInt32 size = header.get_datagram_size(_tcp_header_size);
 
   // We have to loop until the entire datagram is read.
   NetDatagram datagram;
@@ -657,7 +686,7 @@ process_incoming_tcp_data(SocketInfo *sinfo) {
   }
 
   // And now do whatever we need to do to process the datagram.
-  if (!header.verify_datagram(datagram)) {
+  if (!header.verify_datagram(datagram, _tcp_header_size)) {
     net_cat.error()
       << "Ignoring invalid TCP datagram.\n";
   } else {

+ 4 - 0
panda/src/net/connectionReader.h

@@ -85,6 +85,9 @@ PUBLISHED:
   void set_raw_mode(bool mode);
   bool get_raw_mode() const;
 
+  void set_tcp_header_size(int tcp_header_size);
+  int get_tcp_header_size() const;
+
 protected:
   virtual void receive_datagram(const NetDatagram &datagram)=0;
 
@@ -123,6 +126,7 @@ protected:
 
 private:
   bool _raw_mode;
+  int _tcp_header_size;
   bool _shutdown;
 
   typedef pvector<PRThread *> Threads;

+ 29 - 3
panda/src/net/connectionWriter.cxx

@@ -39,6 +39,7 @@ ConnectionWriter(ConnectionManager *manager, int num_threads) :
   _manager(manager)
 {
   _raw_mode = false;
+  _tcp_header_size = datagram_tcp16_header_size;
   _immediate = (num_threads <= 0);
 
   for (int i = 0; i < num_threads; i++) {
@@ -116,7 +117,7 @@ send(const Datagram &datagram, const PT(Connection) &connection) {
     if (_raw_mode) {
       return connection->send_raw_datagram(copy);
     } else {
-      return connection->send_datagram(copy);
+      return connection->send_datagram(copy, _tcp_header_size);
     }
   } else {
     return _queue.insert(copy);
@@ -162,7 +163,7 @@ send(const Datagram &datagram, const PT(Connection) &connection,
     if (_raw_mode) {
       return connection->send_raw_datagram(copy);
     } else {
-      return connection->send_datagram(copy);
+      return connection->send_datagram(copy, _tcp_header_size);
     }
   } else {
     return _queue.insert(copy);
@@ -243,6 +244,31 @@ get_raw_mode() const {
   return _raw_mode;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionWriter::set_tcp_header_size
+//       Access: Public
+//  Description: Sets the header size of TCP packets.  At the present,
+//               legal values for this are 0, 2, or 4; this specifies
+//               the number of bytes to use encode the datagram length
+//               at the start of each TCP datagram.  Sender and
+//               receiver must independently agree on this.
+////////////////////////////////////////////////////////////////////
+void ConnectionWriter::
+set_tcp_header_size(int tcp_header_size) {
+  _tcp_header_size = tcp_header_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConnectionWriter::get_tcp_header_size
+//       Access: Public
+//  Description: Returns the current setting of TCP header size.
+//               See set_tcp_header_size().
+////////////////////////////////////////////////////////////////////
+int ConnectionWriter::
+get_tcp_header_size() const {
+  return _tcp_header_size;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConnectionWriter::clear_manager
 //       Access: Protected
@@ -286,7 +312,7 @@ thread_run() {
     if (_raw_mode) {
       datagram.get_connection()->send_raw_datagram(datagram);
     } else {
-      datagram.get_connection()->send_datagram(datagram);
+      datagram.get_connection()->send_datagram(datagram, _tcp_header_size);
     }
   }
 }

+ 4 - 0
panda/src/net/connectionWriter.h

@@ -63,6 +63,9 @@ PUBLISHED:
   void set_raw_mode(bool mode);
   bool get_raw_mode() const;
 
+  void set_tcp_header_size(int tcp_header_size);
+  int get_tcp_header_size() const;
+
 protected:
   void clear_manager();
 
@@ -76,6 +79,7 @@ protected:
 
 private:
   bool _raw_mode;
+  int _tcp_header_size;
   DatagramQueue _queue;
 
   typedef pvector<PRThread *> Threads;

+ 0 - 12
panda/src/net/datagramTCPHeader.I

@@ -17,18 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DatagramTCPHeader::get_datagram_size
-//       Access: Public
-//  Description: Returns the number of bytes in the associated
-//               datagram.
-////////////////////////////////////////////////////////////////////
-INLINE int DatagramTCPHeader::
-get_datagram_size() const {
-  DatagramIterator di(_header);
-  return di.get_uint16();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DatagramTCPHeader::get_header
 //       Access: Public

+ 62 - 18
panda/src/net/datagramTCPHeader.cxx

@@ -30,14 +30,33 @@
 //               already-constructed NetDatagram.
 ////////////////////////////////////////////////////////////////////
 DatagramTCPHeader::
-DatagramTCPHeader(const NetDatagram &datagram) {
+DatagramTCPHeader(const NetDatagram &datagram, int header_size) {
   const string &str = datagram.get_message();
-  PRUint16 size = str.length();
-  nassertv(size == str.length());
+  switch (header_size) {
+  case 0:
+    break;
 
-  // Now pack the header.
-  _header.add_uint16(size);
-  nassertv((int)_header.get_length() == datagram_tcp_header_size);
+  case datagram_tcp16_header_size:
+    {
+      PRUint16 size = str.length();
+      nassertv(size == str.length());
+      _header.add_uint16(size);
+    }
+    break;
+
+  case datagram_tcp32_header_size:
+    {
+      PRUint32 size = str.length();
+      nassertv(size == str.length());
+      _header.add_uint32(size);
+    }
+    break;
+
+  default:
+    nassertv(false);
+  }
+
+  nassertv((int)_header.get_length() == header_size);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -48,7 +67,32 @@ DatagramTCPHeader(const NetDatagram &datagram) {
 //               just read from a socket.
 ////////////////////////////////////////////////////////////////////
 DatagramTCPHeader::
-DatagramTCPHeader(const void *data) : _header(data, datagram_tcp_header_size) {
+DatagramTCPHeader(const void *data, int header_size) : 
+  _header(data, header_size) 
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramTCPHeader::get_datagram_size
+//       Access: Public
+//  Description: Returns the number of bytes in the associated
+//               datagram.
+////////////////////////////////////////////////////////////////////
+int DatagramTCPHeader::
+get_datagram_size(int header_size) const {
+  DatagramIterator di(_header);
+  switch (header_size) {
+  case 0:
+    return 0;
+
+  case datagram_tcp16_header_size:
+    return di.get_uint16();
+
+  case datagram_tcp32_header_size:
+    return di.get_uint32();
+  }
+
+  return -1;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -59,23 +103,23 @@ DatagramTCPHeader(const void *data) : _header(data, datagram_tcp_header_size) {
 //               false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool DatagramTCPHeader::
-verify_datagram(const NetDatagram &datagram) const {
-  const string &str = datagram.get_message();
-  PRUint16 size = str.length();
-  nassertr(size == str.length(), false);
+verify_datagram(const NetDatagram &datagram, int header_size) const {
+  if (header_size == 0) {
+    // No way to validate without a header, so everything is valid.
+    return true;
+  }
 
-  if (size == get_datagram_size()) {
+  const string &str = datagram.get_message();
+  int actual_size = str.length();
+  int expected_size = get_datagram_size(header_size);
+  if (actual_size == expected_size) {
     return true;
   }
 
   if (net_cat.is_debug()) {
     net_cat.debug()
-      << "Invalid datagram!\n";
-    if (size != get_datagram_size()) {
-      net_cat.debug()
-        << "  size is " << size << " bytes, header reports "
-        << get_datagram_size() << "\n";
-    }
+      << "Invalid datagram!  Size is " << actual_size
+      << " bytes, header reports " << expected_size << "\n";
 
     // We write the hex dump into a ostringstream first, to guarantee
     // an atomic write to the output stream in case we're threaded.

+ 6 - 5
panda/src/net/datagramTCPHeader.h

@@ -27,7 +27,8 @@
 
 #include <prtypes.h>
 
-static const int datagram_tcp_header_size = sizeof(PRUint16);
+static const int datagram_tcp16_header_size = sizeof(PRUint16);
+static const int datagram_tcp32_header_size = sizeof(PRUint32);
 
 class NetDatagram;
 
@@ -41,13 +42,13 @@ class NetDatagram;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA DatagramTCPHeader {
 public:
-  DatagramTCPHeader(const NetDatagram &datagram);
-  DatagramTCPHeader(const void *data);
+  DatagramTCPHeader(const NetDatagram &datagram, int header_size);
+  DatagramTCPHeader(const void *data, int header_size);
 
-  INLINE int get_datagram_size() const;
+  int get_datagram_size(int header_size) const;
   INLINE string get_header() const;
 
-  bool verify_datagram(const NetDatagram &datagram) const;
+  bool verify_datagram(const NetDatagram &datagram, int header_size) const;
 
 private:
   // The actual data for the header is stored (somewhat recursively)

+ 1 - 1
panda/src/parametrics/ropeNode.cxx

@@ -37,7 +37,7 @@
 
 TypeHandle RopeNode::_type_handle;
 
-PStatCollector RopeNode::_rope_node_pcollector("Cull:RopeNode");
+PStatCollector RopeNode::_rope_node_pcollector("*:RopeNode");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: RopeNode::CData::make_copy

+ 1 - 1
panda/src/parametrics/sheetNode.cxx

@@ -33,7 +33,7 @@
 
 TypeHandle SheetNode::_type_handle;
 
-PStatCollector SheetNode::_sheet_node_pcollector("Cull:SheetNode");
+PStatCollector SheetNode::_sheet_node_pcollector("*:SheetNode");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: SheetNode::CData::make_copy

+ 1 - 0
panda/src/pgraph/binCullHandler.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "binCullHandler.h"
+#include "pStatTimer.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BinCullHandler::record_object

+ 10 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -140,6 +140,16 @@ ConfigVariableBool compose_componentwise
           "operations when possible.  If this is false, the compositions "
           "are always computed by matrix."));
 
+ConfigVariableBool uniquify_matrix
+("uniquify-matrix", false,
+ PRC_DESC("Set this true to look up arbitarary 4x4 transform matrices in the "
+          "cache, to ensure that two differently-computed transforms that "
+          "happen to encode the same matrix (an unlikely occurrence) will be "
+          "collapsed into a single pointer (a tiny benefit).  We're usually "
+          "better off not paying the cost of this comparison, and just "
+          "assuming that any two differently-computed transforms are "
+          "essentially different."));
+
 ConfigVariableBool paranoid_const
 ("paranoid-const", false,
  PRC_DESC("Set this true to double-check that nothing is inappropriately "

+ 1 - 0
panda/src/pgraph/config_pgraph.h

@@ -39,6 +39,7 @@ extern ConfigVariableBool unambiguous_graph;
 extern ConfigVariableBool allow_unrelated_wrt;
 extern ConfigVariableBool paranoid_compose;
 extern ConfigVariableBool compose_componentwise;
+extern ConfigVariableBool uniquify_matrix;
 extern ConfigVariableBool paranoid_const;
 extern ConfigVariableBool auto_break_cycles;
 extern ConfigVariableInt max_collect_vertices;

+ 10 - 6
panda/src/pgraph/cullBinStateSorted.I

@@ -48,14 +48,18 @@ operator < (const ObjectData &other) const {
     if (ta != tb) {
       return ta < tb;
     }
-
-    // Then, sort by all the other states, in no particular order,
-    // just as long as objects with identical state are all grouped
-    // together.
-    return sa < sb;
   }
 
-  return 0;
+  // Then group objects by transform, since these are supposed to be
+  // expensive too.
+  if (_object->_transform != other._object->_transform) {
+    return _object->_transform < other._object->_transform;
+  }
+      
+  // Then, sort by all the other states, in no particular order,
+  // just as long as objects with identical state are all grouped
+  // together.
+  return sa < sb;
 }
 
 

+ 0 - 3
panda/src/pgraph/cullTraverser.cxx

@@ -95,7 +95,6 @@ traverse(const NodePath &root, bool python_cull_control) {
   if (allow_portal_cull || python_cull_control) {
     // This _view_frustum is in cull_center space
     PT(GeometricBoundingVolume) vf = _view_frustum;
-    pgraph_cat.debug() << "_view_frustum is " << *_view_frustum << "\n";
 
     GeometricBoundingVolume *local_frustum = NULL;
     PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds();
@@ -104,7 +103,6 @@ traverse(const NodePath &root, bool python_cull_control) {
       
       local_frustum = DCAST(GeometricBoundingVolume, bv);
     }
-    pgraph_cat.debug() << "local_frustum is " << *local_frustum << "\n";
       
     // This local_frustum is in camera space
     PortalClipper portal_viewer(local_frustum, _scene_setup);
@@ -130,7 +128,6 @@ traverse(const NodePath &root, bool python_cull_control) {
     CullTraverserData my_data(data, portal_viewer._previous);
     my_data._render_transform = my_data._render_transform->compose(transform);
     traverse(my_data);
-    pgraph_cat.debug() << "******finished portal culling*********\n";
 
   } else {
     CullTraverserData data(root, get_render_transform(),

+ 1 - 0
panda/src/pgraph/cullTraverserData.cxx

@@ -146,6 +146,7 @@ is_in_view_impl() {
     // The node and its descendants are completely enclosed within
     // the frustum.  No need to cull further.
     _view_frustum = (GeometricBoundingVolume *)NULL;
+    _guard_band = (GeometricBoundingVolume *)NULL;
 
   } else {
     if (node()->is_final()) {

+ 2 - 2
panda/src/pgraph/cullableObject.cxx

@@ -28,7 +28,7 @@
 #include "qpgeomVertexReader.h"
 #include "qpgeomTriangles.h"
 
-PStatCollector CullableObject::_munge_points_pcollector("Cull:Munge:Points");
+PStatCollector CullableObject::_munge_points_pcollector("*:Munge:Points");
 
 CullableObject *CullableObject::_deleted_chain = (CullableObject *)NULL;
 int CullableObject::_num_ever_allocated = 0;
@@ -75,7 +75,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
       // a GSG-friendly form.
       qpgeom->munge_geom(munger, qpgeom, _munged_data);
       CPT(qpGeomVertexData) animated_vertices = 
-        _munged_data->animate_vertices_cull();
+        _munged_data->animate_vertices();
 #ifndef NDEBUG
       if (show_cpu_animation && animated_vertices != _munged_data) {
         // These vertices were CPU-animated, so flash them.

+ 11 - 0
panda/src/pgraph/geomTransformer.cxx

@@ -25,6 +25,13 @@
 #include "transformTable.h"
 #include "transformBlendTable.h"
 #include "sliderTable.h"
+#include "pStatCollector.h"
+#include "pStatTimer.h"
+
+static PStatCollector apply_vertex_collector("*:Flatten:apply:vertex");
+static PStatCollector apply_texcoord_collector("*:Flatten:apply:texcoord");
+static PStatCollector apply_set_color_collector("*:Flatten:apply:set color");
+static PStatCollector apply_scale_color_collector("*:Flatten:apply:scale color");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTransformer::Constructor
@@ -67,6 +74,7 @@ GeomTransformer::
 ////////////////////////////////////////////////////////////////////
 bool GeomTransformer::
 transform_vertices(Geom *geom, const LMatrix4f &mat) {
+  PStatTimer timer(apply_vertex_collector);
   bool transformed = false;
 
   nassertr(geom != (Geom *)NULL, false);
@@ -209,6 +217,7 @@ transform_vertices(GeomNode *node, const LMatrix4f &mat) {
 bool GeomTransformer::
 transform_texcoords(Geom *geom, const InternalName *from_name, 
                     const InternalName *to_name, const LMatrix4f &mat) {
+  PStatTimer timer(apply_texcoord_collector);
   bool transformed = false;
 
   nassertr(geom != (Geom *)NULL, false);
@@ -329,6 +338,7 @@ transform_texcoords(GeomNode *node, const InternalName *from_name,
 ////////////////////////////////////////////////////////////////////
 bool GeomTransformer::
 set_color(Geom *geom, const Colorf &color) {
+  PStatTimer timer(apply_set_color_collector);
   bool transformed = false;
 
   if (geom->is_qpgeom()) {
@@ -407,6 +417,7 @@ set_color(GeomNode *node, const Colorf &color) {
 ////////////////////////////////////////////////////////////////////
 bool GeomTransformer::
 transform_colors(Geom *geom, const LVecBase4f &scale) {
+  PStatTimer timer(apply_scale_color_collector);
   bool transformed = false;
 
   nassertr(geom != (Geom *)NULL, false);

+ 0 - 5
panda/src/pgraph/polylightEffect.cxx

@@ -19,7 +19,6 @@
 #include "polylightEffect.h"
 #include "polylightNode.h"
 #include "config_pgraph.h"
-#include "pStatTimer.h"
 #include "nodePath.h"
 #include "pmap.h"
 #include "colorScaleAttrib.h"
@@ -30,8 +29,6 @@
 
 TypeHandle PolylightEffect::_type_handle;
 
-PStatCollector PolylightEffect::_cull_pcollector("Cull:Polylight");
-
 ////////////////////////////////////////////////////////////////////
 //     Function: PolylightEffect::make
 //       Access: Published, Static
@@ -138,8 +135,6 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran
   float weight_scale = 1.0f; // Variable to compensate snap of color when you walk inside the light volume
   float Rcollect, Gcollect, Bcollect;
 
-  PStatTimer timer(_cull_pcollector);
-
   const NodePath &root = scene->get_scene_root();
   //const NodePath &camera = scene->get_camera_path();
   const NodePath &camera = scene->get_cull_center();

+ 0 - 3
panda/src/pgraph/polylightEffect.h

@@ -29,7 +29,6 @@
 #include "pmap.h"
 #include "notify.h"
 #include "sceneSetup.h"
-#include "pStatCollector.h"
 
 
 ////////////////////////////////////////////////////////////////////
@@ -103,8 +102,6 @@ public:
   }
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
 
-  static PStatCollector _cull_pcollector;
-
 private:
   static TypeHandle _type_handle;
 };

+ 7 - 1
panda/src/pgraph/renderState.cxx

@@ -37,7 +37,9 @@
 RenderState::States *RenderState::_states = NULL;
 CPT(RenderState) RenderState::_empty_state;
 UpdateSeq RenderState::_last_cycle_detect;
-PStatCollector RenderState::_cache_update_pcollector("App:State Cache");
+PStatCollector RenderState::_cache_update_pcollector("*:State Cache:Update");
+PStatCollector RenderState::_state_compose_pcollector("*:State Cache:Compose State");
+PStatCollector RenderState::_state_invert_pcollector("*:State Cache:Invert State");
 
 TypeHandle RenderState::_type_handle;
 
@@ -1132,6 +1134,8 @@ return_new(RenderState *state) {
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) RenderState::
 do_compose(const RenderState *other) const {
+  PStatTimer timer(_state_compose_pcollector);
+
   // First, build a new Attributes member that represents the union of
   // this one and that one.
   Attributes::const_iterator ai = _attributes.begin();
@@ -1197,6 +1201,8 @@ do_compose(const RenderState *other) const {
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) RenderState::
 do_invert_compose(const RenderState *other) const {
+  PStatTimer timer(_state_invert_pcollector);
+
   Attributes::const_iterator ai = _attributes.begin();
   Attributes::const_iterator bi = other->_attributes.begin();
 

+ 2 - 0
panda/src/pgraph/renderState.h

@@ -212,6 +212,8 @@ private:
   static UpdateSeq _last_cycle_detect;
 
   static PStatCollector _cache_update_pcollector;
+  static PStatCollector _state_compose_pcollector;
+  static PStatCollector _state_invert_pcollector;
 
 private:
   // This is the actual data within the RenderState: a set of

+ 4 - 0
panda/src/pgraph/sceneGraphReducer.I

@@ -87,6 +87,7 @@ get_combine_radius() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void SceneGraphReducer::
 apply_attribs(PandaNode *node, int attrib_types) {
+  PStatTimer timer(_apply_collector);
   AccumulatedAttribs attribs;
   r_apply_attribs(node, attribs, attrib_types, _transformer);
 }
@@ -122,6 +123,7 @@ apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
 ////////////////////////////////////////////////////////////////////
 INLINE int SceneGraphReducer::
 collect_vertex_data(PandaNode *root, int collect_bits) {
+  PStatTimer timer(_collect_collector);
   return r_collect_vertex_data(root, collect_bits, _transformer);
 }
 
@@ -137,6 +139,7 @@ collect_vertex_data(PandaNode *root, int collect_bits) {
 ////////////////////////////////////////////////////////////////////
 INLINE int SceneGraphReducer::
 make_nonindexed(PandaNode *root, int nonindexed_bits) {
+  PStatTimer timer(_make_nonindexed_collector);
   return r_make_nonindexed(root, nonindexed_bits);
 }
 
@@ -148,5 +151,6 @@ make_nonindexed(PandaNode *root, int nonindexed_bits) {
 ////////////////////////////////////////////////////////////////////
 INLINE void SceneGraphReducer::
 unify(PandaNode *root) {
+  PStatTimer timer(_unify_collector);
   r_unify(root);
 }

+ 7 - 0
panda/src/pgraph/sceneGraphReducer.cxx

@@ -25,6 +25,12 @@
 #include "plist.h"
 #include "pmap.h"
 
+PStatCollector SceneGraphReducer::_flatten_collector("*:Flatten:flatten");
+PStatCollector SceneGraphReducer::_apply_collector("*:Flatten:apply");
+PStatCollector SceneGraphReducer::_collect_collector("*:Flatten:collect");
+PStatCollector SceneGraphReducer::_make_nonindexed_collector("*:Flatten:make nonindexed");
+PStatCollector SceneGraphReducer::_unify_collector("*:Flatten:unify");
+
 ////////////////////////////////////////////////////////////////////
 //     Function: SceneGraphReducer::flatten
 //       Access: Published
@@ -46,6 +52,7 @@
 ////////////////////////////////////////////////////////////////////
 int SceneGraphReducer::
 flatten(PandaNode *root, int combine_siblings_bits) {
+  PStatTimer timer(_flatten_collector);
   int num_total_nodes = 0;
   int num_pass_nodes;
 

+ 8 - 1
panda/src/pgraph/sceneGraphReducer.h

@@ -25,7 +25,8 @@
 #include "renderState.h"
 #include "accumulatedAttribs.h"
 #include "geomTransformer.h"
-
+#include "pStatCollector.h"
+#include "pStatTimer.h"
 #include "typedObject.h"
 #include "pointerTo.h"
 
@@ -150,6 +151,12 @@ protected:
 private:
   float _combine_radius;
   GeomTransformer _transformer;
+
+  static PStatCollector _flatten_collector;
+  static PStatCollector _apply_collector;
+  static PStatCollector _collect_collector;
+  static PStatCollector _make_nonindexed_collector;
+  static PStatCollector _unify_collector;
 };
 
 #include "sceneGraphReducer.I"

+ 17 - 15
panda/src/pgraph/transformState.cxx

@@ -29,7 +29,9 @@
 TransformState::States *TransformState::_states = NULL;
 CPT(TransformState) TransformState::_identity_state;
 UpdateSeq TransformState::_last_cycle_detect;
-PStatCollector TransformState::_cache_update_pcollector("App:State Cache");
+PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update");
+PStatCollector TransformState::_transform_compose_pcollector("*:State Cache:Compose Transform");
+PStatCollector TransformState::_transform_invert_pcollector("*:State Cache:Invert Transform");
 
 TypeHandle TransformState::_type_handle;
 
@@ -159,20 +161,16 @@ operator < (const TransformState &other) const {
     return c < 0;
   }
 
-  /*
-  // Otherwise, compare the matrices.
-  return get_mat() < other.get_mat();
-  */
-
-  // On second thought, we don't gain a lot of benefit by going
-  // through all the work of comparing different transforms by matrix.
-  // Doing so ensures that two differently-computed transforms that
-  // happen to encode the same matrix (an unlikely occurrence) will be
-  // collapsed into a single pointer (a tiny benefit).  We're better
-  // off not paying the cost of this comparison, and just assuming
-  // that any two differently-computed transforms are essentially
-  // different.
-  return (this < &other);
+  // Otherwise, compare the matrices . . .
+  if (uniquify_matrix) {
+    // . . . but only if the user thinks that's a worthwhile
+    // comparison.
+    return get_mat() < other.get_mat();
+
+  } else {
+    // If not, we just compare the pointers.
+    return (this < &other);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1068,6 +1066,8 @@ return_new(TransformState *state) {
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) TransformState::
 do_compose(const TransformState *other) const {
+  PStatTimer timer(_transform_compose_pcollector);
+
   nassertr((_flags & F_is_invalid) == 0, this);
   nassertr((other->_flags & F_is_invalid) == 0, other);
 
@@ -1122,6 +1122,8 @@ do_compose(const TransformState *other) const {
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) TransformState::
 do_invert_compose(const TransformState *other) const {
+  PStatTimer timer(_transform_invert_pcollector);
+
   nassertr((_flags & F_is_invalid) == 0, this);
   nassertr((other->_flags & F_is_invalid) == 0, other);
 

+ 2 - 0
panda/src/pgraph/transformState.h

@@ -200,6 +200,8 @@ private:
   static UpdateSeq _last_cycle_detect;
 
   static PStatCollector _cache_update_pcollector;
+  static PStatCollector _transform_compose_pcollector;
+  static PStatCollector _transform_invert_pcollector;
 
 private:
   // This is the actual data within the TransformState.

+ 1 - 1
panda/src/pstatclient/pStatClient.cxx

@@ -33,7 +33,7 @@
 PStatCollector PStatClient::_total_size_pcollector("Memory usage");
 PStatCollector PStatClient::_cpp_size_pcollector("Memory usage:C++");
 PStatCollector PStatClient::_interpreter_size_pcollector("Memory usage:Interpreter");
-PStatCollector PStatClient::_pstats_pcollector("App:PStats");
+PStatCollector PStatClient::_pstats_pcollector("*:PStats");
 
 PStatClient *PStatClient::_global_pstats = NULL;
 

+ 2 - 0
panda/src/pstatclient/pStatClientImpl.cxx

@@ -48,6 +48,8 @@ PStatClientImpl(PStatClient *client) :
   _reader(this, 0),
   _writer(this, pstats_threaded_write ? 1 : 0)
 {
+  _reader.set_tcp_header_size(4);
+  _writer.set_tcp_header_size(4);
   _is_connected = false;
   _got_udp_port = false;
   _collectors_reported = 0;

+ 11 - 11
panda/src/pstatclient/pStatProperties.cxx

@@ -27,10 +27,11 @@
 
 #include <ctype.h>
 
-static const int current_pstat_major_version = 2;
-static const int current_pstat_minor_version = 1;
+static const int current_pstat_major_version = 3;
+static const int current_pstat_minor_version = 0;
 // Initialized at 2.0 on 5/18/01, when version numbers were first added.
 // Incremented to 2.1 on 5/21/01 to add support for TCP frame data.
+// Incremented to 3.0 on 4/28/05 to bump TCP headers to 32 bits.
 
 ////////////////////////////////////////////////////////////////////
 //     Function: get_current_pstat_major_version
@@ -109,8 +110,6 @@ struct LevelCollectorProperties {
 
 static TimeCollectorProperties time_properties[] = {
   { 1, "App",                              { 0.0, 0.8, 0.4 },  1.0 / 30.0 },
-  { 1, "App:PStats",                       { 0.4, 0.8, 1.0 } },
-  { 1, "App:Animation",                    { 1.0, 0.0, 1.0 } },
   { 1, "App:Collisions",                   { 1.0, 0.5, 0.0 } },
   { 1, "App:Collisions:Reset",             { 0.0, 0.0, 0.5 } },
   { 0, "App:Data graph",                   { 0.5, 0.8, 0.4 } },
@@ -123,14 +122,15 @@ static TimeCollectorProperties time_properties[] = {
   { 0, "App:Show code:Nametags:3d:Contents", { 0.0, 0.5, 0.0 } },
   { 0, "App:Show code:Nametags:3d:Adjust",   { 0.5, 0.0, 0.5 } },
   { 1, "Cull",                             { 0.0, 1.0, 0.0 },  1.0 / 30.0 },
-  { 1, "Cull:Animate vertices",            { 1.0, 0.5, 0.3 },  1.0 / 30.0 },
-  { 1, "Cull:Show fps",                    { 0.5, 0.8, 1.0 } },
   { 1, "Cull:Sort",                        { 0.3, 0.6, 0.3 } },
-  { 0, "Cull:Munge",                       { 0.3, 0.3, 0.9 } },
-  { 0, "Cull:Munge:Points",                { 0.2, 0.8, 0.4 } },
-  { 0, "Cull:Munge:Data",                  { 0.7, 0.5, 0.2 } },
-  { 0, "Cull:Munge:Rotate",                { 0.9, 0.8, 0.5 } },
-  { 0, "Cull:Munge:Decompose",             { 0.1, 0.3, 0.1 } },
+  { 1, "*:Show fps",                       { 0.5, 0.8, 1.0 } },
+  { 0, "*:Munge",                          { 0.3, 0.3, 0.9 } },
+  { 0, "*:Munge:Points",                   { 0.2, 0.8, 0.4 } },
+  { 0, "*:Munge:Data",                     { 0.7, 0.5, 0.2 } },
+  { 0, "*:Munge:Rotate",                   { 0.9, 0.8, 0.5 } },
+  { 0, "*:Munge:Decompose",                { 0.1, 0.3, 0.1 } },
+  { 1, "*:PStats",                         { 0.4, 0.8, 1.0 } },
+  { 1, "*:Animation",                      { 1.0, 0.0, 1.0 } },
   { 1, "Draw",                             { 1.0, 0.0, 0.0 },  1.0 / 30.0 },
   { 1, "Draw:Make current",                { 0.4, 0.2, 0.6 } },
   { 1, "Draw:Copy texture",                { 0.2, 0.6, 0.4 } },

+ 5 - 0
panda/src/text/textNode.cxx

@@ -51,11 +51,15 @@
 #include "dcast.h"
 #include "bamFile.h"
 #include "zStream.h"
+#include "pStatCollector.h"
+#include "pStatTimer.h"
 
 #include <stdio.h>
 
 TypeHandle TextNode::_type_handle;
 
+static PStatCollector text_generate_collector("*:Generate Text");
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextNode::Constructor
 //       Access: Published
@@ -204,6 +208,7 @@ write(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) TextNode::
 generate() {
+  PStatTimer timer(text_generate_collector);
   if (text_cat.is_debug()) {
     text_cat.debug()
       << "Rebuilding " << get_type() << " " << get_name()