Browse Source

Many, many performance optimizations and enhancements

rdb 11 years ago
parent
commit
af15797a25
78 changed files with 1607 additions and 750 deletions
  1. 6 1
      dtool/src/dtoolbase/dtoolbase_cc.h
  2. 22 0
      dtool/src/dtoolbase/stl_compares.I
  3. 17 3
      dtool/src/dtoolbase/stl_compares.h
  4. 1 2
      dtool/src/dtoolbase/typeHandle.h
  5. 27 0
      dtool/src/dtoolbase/typeRegistry.I
  6. 7 12
      dtool/src/dtoolbase/typeRegistry.cxx
  7. 4 1
      dtool/src/dtoolbase/typeRegistry.h
  8. 0 5
      dtool/src/dtoolbase/typeRegistryNode.cxx
  9. 1 1
      makepanda/makepanda.py
  10. 1 1
      panda/src/cull/drawCullHandler.cxx
  11. 1 3
      panda/src/cull/drawCullHandler.h
  12. 35 13
      panda/src/display/graphicsStateGuardian.cxx
  13. 17 0
      panda/src/express/memoryUsage.I
  14. 0 18
      panda/src/express/memoryUsage.cxx
  15. 1 1
      panda/src/express/memoryUsage.h
  16. 88 0
      panda/src/express/nodePointerTo.I
  17. 22 0
      panda/src/express/nodePointerTo.h
  18. 37 0
      panda/src/express/nodePointerToBase.I
  19. 5 0
      panda/src/express/nodePointerToBase.h
  20. 33 25
      panda/src/express/pointerTo.I
  21. 8 6
      panda/src/express/pointerTo.h
  22. 32 9
      panda/src/express/pointerToBase.I
  23. 2 1
      panda/src/express/pointerToBase.h
  24. 7 2
      panda/src/express/pointerToVoid.I
  25. 1 1
      panda/src/express/pointerToVoid.h
  26. 57 24
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  27. 72 21
      panda/src/gobj/geom.I
  28. 23 15
      panda/src/gobj/geom.h
  29. 23 19
      panda/src/gobj/geomMunger.cxx
  30. 77 27
      panda/src/gobj/geomVertexData.I
  31. 108 104
      panda/src/gobj/geomVertexData.cxx
  32. 33 24
      panda/src/gobj/geomVertexData.h
  33. 12 1
      panda/src/linmath/lmatrix3_src.I
  34. 9 6
      panda/src/linmath/lmatrix3_src.cxx
  35. 7 6
      panda/src/linmath/lmatrix3_src.h
  36. 13 1
      panda/src/linmath/lmatrix4_src.I
  37. 9 4
      panda/src/linmath/lmatrix4_src.cxx
  38. 8 7
      panda/src/linmath/lmatrix4_src.h
  39. 2 10
      panda/src/pgraph/config_pgraph.cxx
  40. 0 1
      panda/src/pgraph/config_pgraph.h
  41. 0 25
      panda/src/pgraph/cullBin.I
  42. 0 34
      panda/src/pgraph/cullBin.cxx
  43. 0 3
      panda/src/pgraph/cullBin.h
  44. 73 0
      panda/src/pgraph/cullBinManager.I
  45. 34 25
      panda/src/pgraph/cullBinManager.cxx
  46. 13 2
      panda/src/pgraph/cullBinManager.h
  47. 1 1
      panda/src/pgraph/cullPlanes.cxx
  48. 41 21
      panda/src/pgraph/cullResult.cxx
  49. 1 1
      panda/src/pgraph/cullResult.h
  50. 60 0
      panda/src/pgraph/cullTraverser.I
  51. 18 70
      panda/src/pgraph/cullTraverser.cxx
  52. 4 0
      panda/src/pgraph/cullTraverser.h
  53. 2 2
      panda/src/pgraph/cullTraverserData.I
  54. 16 5
      panda/src/pgraph/cullTraverserData.cxx
  55. 2 2
      panda/src/pgraph/cullTraverserData.h
  56. 7 2
      panda/src/pgraph/cullableObject.cxx
  57. 23 0
      panda/src/pgraph/geomNode.I
  58. 5 0
      panda/src/pgraph/geomNode.h
  59. 69 0
      panda/src/pgraph/pandaNode.I
  60. 34 19
      panda/src/pgraph/pandaNode.h
  61. 14 5
      panda/src/pgraph/renderAttrib.I
  62. 11 9
      panda/src/pgraph/renderAttrib.cxx
  63. 5 2
      panda/src/pgraph/renderAttrib.h
  64. 36 0
      panda/src/pgraph/renderState.I
  65. 0 36
      panda/src/pgraph/renderState.cxx
  66. 2 2
      panda/src/pgraph/renderState.h
  67. 1 1
      panda/src/pgraph/texMatrixAttrib.cxx
  68. 22 20
      panda/src/pgraph/transformState.I
  69. 135 54
      panda/src/pgraph/transformState.cxx
  70. 13 10
      panda/src/pgraph/transformState.h
  71. 1 1
      panda/src/pgui/pgItem.cxx
  72. 2 2
      panda/src/pgui/pgSliderBar.cxx
  73. 20 4
      panda/src/pstatclient/pStatClient.cxx
  74. 60 0
      panda/src/putil/copyOnWritePointer.I
  75. 10 0
      panda/src/putil/copyOnWritePointer.h
  76. 29 12
      panda/src/putil/simpleHashMap.I
  77. 8 1
      panda/src/putil/simpleHashMap.h
  78. 7 4
      panda/src/windisplay/config_windisplay.cxx

+ 6 - 1
dtool/src/dtoolbase/dtoolbase_cc.h

@@ -132,7 +132,7 @@ typedef ios::seekdir ios_seekdir;
 #  else
 #  else
 #    define NOEXCEPT
 #    define NOEXCEPT
 #  endif
 #  endif
-#  if __has_extension(cxx_rvalue_references)
+#  if __has_extension(cxx_rvalue_references) && (__cplusplus >= 201103L)
 #    define USE_MOVE_SEMANTICS
 #    define USE_MOVE_SEMANTICS
 #  endif
 #  endif
 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && (__cplusplus >= 201103L)
 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && (__cplusplus >= 201103L)
@@ -141,6 +141,11 @@ typedef ios::seekdir ios_seekdir;
 #  define CONSTEXPR constexpr
 #  define CONSTEXPR constexpr
 #  define NOEXCEPT noexcept
 #  define NOEXCEPT noexcept
 #  define USE_MOVE_SEMANTICS
 #  define USE_MOVE_SEMANTICS
+#elif defined(_MSC_VER) && _MSC_VER >= 1600
+// MSVC 2010 has move semantics.
+#  define CONSTEXPR INLINE
+#  define NOEXCEPT throw()
+#  define USE_MOVE_SEMANTICS
 #else
 #else
 #  define CONSTEXPR INLINE
 #  define CONSTEXPR INLINE
 #  define NOEXCEPT
 #  define NOEXCEPT

+ 22 - 0
dtool/src/dtoolbase/stl_compares.I

@@ -234,3 +234,25 @@ INLINE size_t indirect_method_hash<Key, Compare>::
 operator () (const Key &key) const {
 operator () (const Key &key) const {
   return (*key).get_hash();
   return (*key).get_hash();
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: indirect_equals_hash::operator ()
+//       Access: Public
+//  Description: Calls the Key's get_hash() method.
+////////////////////////////////////////////////////////////////////
+template<class Key>
+INLINE size_t indirect_equals_hash<Key>::
+operator () (const Key &key) const {
+  return (*key).get_hash();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: indirect_equals_hash::is_equal
+//       Access: Public
+//  Description: Returns true if a is equal to b, false otherwise.
+////////////////////////////////////////////////////////////////////
+template<class Key>
+INLINE bool indirect_equals_hash<Key>::
+is_equal(const Key &a, const Key &b) const {
+  return (a == b || (*a) == (*b));
+}

+ 17 - 3
dtool/src/dtoolbase/stl_compares.h

@@ -33,7 +33,6 @@ public:
   }
   }
 };
 };
 
 
-
 #else
 #else
 
 
 #include <map>  // for less
 #include <map>  // for less
@@ -212,6 +211,23 @@ public:
   }
   }
 };
 };
 
 
+////////////////////////////////////////////////////////////////////
+//       Class : indirect_equals_hash
+// Description : An STL function object class, this is intended to be
+//               used on any ordered collection of pointers to classes
+//               that contain an operator ==() method.  It defines
+//               the equality of the pointers via operator ==().
+//
+//               Since it doesn't define the ordering of the pointers,
+//               it can only be used with hash containers.
+////////////////////////////////////////////////////////////////////
+template<class Key>
+class indirect_equals_hash {
+public:
+  INLINE size_t operator () (const Key &key) const;
+  INLINE bool is_equal(const Key &a, const Key &b) const;
+};
+
 #include "stl_compares.I"
 #include "stl_compares.I"
 
 
 typedef floating_point_hash<float> float_hash;
 typedef floating_point_hash<float> float_hash;
@@ -234,5 +250,3 @@ class indirect_compare_names_hash : public indirect_method_hash<Key, indirect_co
 };
 };
 
 
 #endif
 #endif
-
-

+ 1 - 2
dtool/src/dtoolbase/typeHandle.h

@@ -16,7 +16,6 @@
 #define TYPEHANDLE_H
 #define TYPEHANDLE_H
 
 
 #include "dtoolbase.h"
 #include "dtoolbase.h"
-#include "typeRegistry.h"
 
 
 #include <set>
 #include <set>
 
 
@@ -152,7 +151,7 @@ private:
   int _index;
   int _index;
   static TypeHandle _none;
   static TypeHandle _none;
 
 
-friend class TypeRegistry;
+  friend class TypeRegistry;
 };
 };
 
 
 
 

+ 27 - 0
dtool/src/dtoolbase/typeRegistry.I

@@ -39,3 +39,30 @@ init_lock() {
     _lock = new MutexImpl;
     _lock = new MutexImpl;
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::look_up
+//       Access: Private
+//  Description: Returns the TypeRegistryNode associated with the
+//               indicated TypeHandle.  If there is no associated
+//               TypeRegistryNode, reports an error condition and
+//               returns NULL.
+//
+//               The associated TypedObject pointer is the pointer to
+//               the object that owns the handle, if available.  It is
+//               only used in an error condition, if for some reason
+//               the handle was uninitialized.
+//
+//               Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+INLINE TypeRegistryNode *TypeRegistry::
+look_up(TypeHandle handle, TypedObject *object) const {
+#ifndef NDEBUG
+  if (handle._index >= (int)_handle_registry.size() ||
+      handle._index <= 0) {
+    // Invalid or uninitialized type handle.
+    return look_up_invalid(handle, object);
+  }
+#endif
+  return _handle_registry[handle._index];
+}

+ 7 - 12
dtool/src/dtoolbase/typeRegistry.cxx

@@ -498,7 +498,7 @@ get_parent_towards(TypeHandle child, TypeHandle base,
   TypeHandle handle;
   TypeHandle handle;
   const TypeRegistryNode *child_node = look_up(child, child_object);
   const TypeRegistryNode *child_node = look_up(child, child_object);
   const TypeRegistryNode *base_node = look_up(base, NULL);
   const TypeRegistryNode *base_node = look_up(base, NULL);
-  assert(child_node != (TypeRegistryNode *)NULL && 
+  assert(child_node != (TypeRegistryNode *)NULL &&
          base_node != (TypeRegistryNode *)NULL);
          base_node != (TypeRegistryNode *)NULL);
   freshen_derivations();
   freshen_derivations();
   handle = TypeRegistryNode::get_parent_towards(child_node, base_node);
   handle = TypeRegistryNode::get_parent_towards(child_node, base_node);
@@ -688,22 +688,17 @@ write_node(ostream &out, int indent_level, const TypeRegistryNode *node) const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::look_up
+//     Function: TypeRegistry::look_up_invalid
 //       Access: Private
 //       Access: Private
-//  Description: Returns the TypeRegistryNode associated with the
-//               indicated TypeHandle.  If there is no associated
-//               TypeRegistryNode, reports an error condition and
-//               returns NULL.
-//
-//               The associated TypedObject pointer is the pointer to
-//               the object that owns the handle, if available.  It is
-//               only used in an error condition, if for some reason
-//               the handle was uninitialized.
+//  Description: Called by look_up when it detects an invalid
+//               TypeHandle pointer.  In non-release builds, this
+//               method will do what it can to recover from this
+//               and initialize the type anyway.
 //
 //
 //               Assumes the lock is already held.
 //               Assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TypeRegistryNode *TypeRegistry::
 TypeRegistryNode *TypeRegistry::
-look_up(TypeHandle handle, TypedObject *object) const {
+look_up_invalid(TypeHandle handle, TypedObject *object) const {
 #ifndef NDEBUG
 #ifndef NDEBUG
   if (handle._index == 0) {
   if (handle._index == 0) {
     // The TypeHandle is unregistered.  This is an error condition.
     // The TypeHandle is unregistered.  This is an error condition.

+ 4 - 1
dtool/src/dtoolbase/typeRegistry.h

@@ -88,7 +88,8 @@ private:
   TypeRegistry();
   TypeRegistry();
 
 
   static void init_global_pointer();
   static void init_global_pointer();
-  TypeRegistryNode *look_up(TypeHandle type, TypedObject *object) const;
+  INLINE TypeRegistryNode *look_up(TypeHandle type, TypedObject *object) const;
+  TypeRegistryNode *look_up_invalid(TypeHandle type, TypedObject *object) const;
 
 
   INLINE void freshen_derivations();
   INLINE void freshen_derivations();
   void rebuild_derivations();
   void rebuild_derivations();
@@ -120,6 +121,8 @@ private:
 // Helper function to allow for "C" interaction into the type system
 // Helper function to allow for "C" interaction into the type system
 extern "C" EXPCL_DTOOL  int get_best_parent_from_Set(int id, const std::set<int> &this_set);
 extern "C" EXPCL_DTOOL  int get_best_parent_from_Set(int id, const std::set<int> &this_set);
 
 
+#include "typeHandle.h"
+
 #include "typeRegistry.I"
 #include "typeRegistry.I"
 
 
 #endif
 #endif

+ 0 - 5
dtool/src/dtoolbase/typeRegistryNode.cxx

@@ -48,11 +48,6 @@ is_derived_from(const TypeRegistryNode *child, const TypeRegistryNode *base) {
   // code.  Therefore, we go through some pains to make this function
   // code.  Therefore, we go through some pains to make this function
   // as efficient as possible.
   // as efficient as possible.
 
 
-  // (Actually, it appears that the function is not called as often as
-  // I'd first thought, and it wasn't really all that expensive to
-  // begin with.  So much of this complexity is of limited usefulness.
-  // Oh well.)
-
   // First, compare the subtree tops.  If they are the same, then this
   // First, compare the subtree tops.  If they are the same, then this
   // node and the base node are within the same single-inheritance
   // node and the base node are within the same single-inheritance
   // subtree, and we can use our bitmask trick to determine the
   // subtree, and we can use our bitmask trick to determine the

+ 1 - 1
makepanda/makepanda.py

@@ -1953,7 +1953,7 @@ DTOOL_CONFIG=[
     ("DO_PSTATS",                      'UNDEF',                  'UNDEF'),
     ("DO_PSTATS",                      'UNDEF',                  'UNDEF'),
     ("DO_DCAST",                       'UNDEF',                  'UNDEF'),
     ("DO_DCAST",                       'UNDEF',                  'UNDEF'),
     ("DO_COLLISION_RECORDING",         'UNDEF',                  'UNDEF'),
     ("DO_COLLISION_RECORDING",         'UNDEF',                  'UNDEF'),
-    ("SUPPORT_IMMEDIATE_MODE",         '1',                      '1'),
+    ("SUPPORT_IMMEDIATE_MODE",         'UNDEF',                  'UNDEF'),
     ("TRACK_IN_INTERPRETER",           'UNDEF',                  'UNDEF'),
     ("TRACK_IN_INTERPRETER",           'UNDEF',                  'UNDEF'),
     ("DO_MEMORY_USAGE",                'UNDEF',                  'UNDEF'),
     ("DO_MEMORY_USAGE",                'UNDEF',                  'UNDEF'),
     ("DO_PIPELINING",                  '1',                      '1'),
     ("DO_PIPELINING",                  '1',                      '1'),

+ 1 - 1
panda/src/cull/drawCullHandler.cxx

@@ -19,7 +19,7 @@
 #include "renderState.h"
 #include "renderState.h"
 #include "graphicsStateGuardianBase.h"
 #include "graphicsStateGuardianBase.h"
 #include "config_pgraph.h"
 #include "config_pgraph.h"
-
+#include "cullTraverser.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DrawCullHandler::record_object
 //     Function: DrawCullHandler::record_object

+ 1 - 3
panda/src/cull/drawCullHandler.h

@@ -35,7 +35,7 @@ class EXPCL_PANDA_CULL DrawCullHandler : public CullHandler {
 public:
 public:
   INLINE DrawCullHandler(GraphicsStateGuardianBase *gsg);
   INLINE DrawCullHandler(GraphicsStateGuardianBase *gsg);
 
 
-  virtual void record_object(CullableObject *object, 
+  virtual void record_object(CullableObject *object,
                              const CullTraverser *traverser);
                              const CullTraverser *traverser);
 
 
 private:
 private:
@@ -46,5 +46,3 @@ private:
 
 
 #endif
 #endif
 
 
-
-  

+ 35 - 13
panda/src/display/graphicsStateGuardian.cxx

@@ -365,6 +365,9 @@ set_coordinate_system(CoordinateSystem cs) {
   if (cs == CS_default) {
   if (cs == CS_default) {
     cs = get_default_coordinate_system();
     cs = get_default_coordinate_system();
   }
   }
+  if (_coordinate_system == cs) {
+    return;
+  }
   _coordinate_system = cs;
   _coordinate_system = cs;
 
 
   // Changing the external coordinate system changes the cs_transform.
   // Changing the external coordinate system changes the cs_transform.
@@ -1041,7 +1044,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
     return &t;
     return &t;
   }
   }
   case Shader::SMO_attr_material: {
   case Shader::SMO_attr_material: {
-    const MaterialAttrib *target_material = DCAST(MaterialAttrib, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()));
+    const MaterialAttrib *target_material = (const MaterialAttrib *)
+      _target_rs->get_attrib_def(MaterialAttrib::get_class_slot());
     // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS
     // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS
     if (target_material->is_off()) {
     if (target_material->is_off()) {
       t = LMatrix4(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0);
       t = LMatrix4(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0);
@@ -1060,7 +1064,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
     return &t;
     return &t;
   }
   }
   case Shader::SMO_attr_color: {
   case Shader::SMO_attr_color: {
-    const ColorAttrib *target_color = DCAST(ColorAttrib, _target_rs->get_attrib_def(ColorAttrib::get_class_slot()));
+    const ColorAttrib *target_color = (const ColorAttrib *)
+      _target_rs->get_attrib_def(ColorAttrib::get_class_slot());
     if (target_color->get_color_type() != ColorAttrib::T_flat) {
     if (target_color->get_color_type() != ColorAttrib::T_flat) {
       return &LMatrix4::ones_mat();
       return &LMatrix4::ones_mat();
     }
     }
@@ -1069,7 +1074,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
     return &t;
     return &t;
   }
   }
   case Shader::SMO_attr_colorscale: {
   case Shader::SMO_attr_colorscale: {
-    const ColorScaleAttrib *target_color = DCAST(ColorScaleAttrib, _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot()));
+    const ColorScaleAttrib *target_color = (const ColorScaleAttrib *)
+      _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot());
     if (target_color->is_identity()) {
     if (target_color->is_identity()) {
       return &LMatrix4::ones_mat();
       return &LMatrix4::ones_mat();
     }
     }
@@ -1078,7 +1084,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
     return &t;
     return &t;
   }
   }
   case Shader::SMO_attr_fog: {
   case Shader::SMO_attr_fog: {
-    const FogAttrib *target_fog = DCAST(FogAttrib, _target_rs->get_attrib_def(FogAttrib::get_class_slot()));
+    const FogAttrib *target_fog = (const FogAttrib *)
+      _target_rs->get_attrib_def(FogAttrib::get_class_slot());
     Fog *fog = target_fog->get_fog();
     Fog *fog = target_fog->get_fog();
     if (fog == (Fog*) NULL) {
     if (fog == (Fog*) NULL) {
       return &LMatrix4::ones_mat();
       return &LMatrix4::ones_mat();
@@ -1089,7 +1096,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
     return &t;
     return &t;
   }
   }
   case Shader::SMO_attr_fogcolor: {
   case Shader::SMO_attr_fogcolor: {
-    const FogAttrib *target_fog = DCAST(FogAttrib, _target_rs->get_attrib_def(FogAttrib::get_class_slot()));
+    const FogAttrib *target_fog = (const FogAttrib *)
+      _target_rs->get_attrib_def(FogAttrib::get_class_slot());
     Fog *fog = target_fog->get_fog();
     Fog *fog = target_fog->get_fog();
     if (fog == (Fog*) NULL) {
     if (fog == (Fog*) NULL) {
       return &LMatrix4::ones_mat();
       return &LMatrix4::ones_mat();
@@ -2074,8 +2082,12 @@ get_render_buffer(int buffer_type, const FrameBufferProperties &prop) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) GraphicsStateGuardian::
 CPT(TransformState) GraphicsStateGuardian::
 get_cs_transform_for(CoordinateSystem cs) const {
 get_cs_transform_for(CoordinateSystem cs) const {
-  if (_internal_coordinate_system == CS_default ||
-      _internal_coordinate_system == cs) {
+  if (_coordinate_system == cs) {
+    // We've already calculated this.
+    return _cs_transform;
+
+  } else if (_internal_coordinate_system == CS_default ||
+             _internal_coordinate_system == cs) {
     return TransformState::make_identity();
     return TransformState::make_identity();
 
 
   } else {
   } else {
@@ -2111,7 +2123,9 @@ do_issue_clip_plane() {
   int num_enabled = 0;
   int num_enabled = 0;
   int num_on_planes = 0;
   int num_on_planes = 0;
 
 
-  const ClipPlaneAttrib *target_clip_plane = DCAST(ClipPlaneAttrib, _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot()));
+  const ClipPlaneAttrib *target_clip_plane = (const ClipPlaneAttrib *)
+    _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot());
+
   if (target_clip_plane != (ClipPlaneAttrib *)NULL) {
   if (target_clip_plane != (ClipPlaneAttrib *)NULL) {
     CPT(ClipPlaneAttrib) new_plane = target_clip_plane->filter_to_max(_max_clip_planes);
     CPT(ClipPlaneAttrib) new_plane = target_clip_plane->filter_to_max(_max_clip_planes);
 
 
@@ -2171,7 +2185,9 @@ do_issue_clip_plane() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 do_issue_color() {
 do_issue_color() {
-  const ColorAttrib *target_color = DCAST(ColorAttrib, _target_rs->get_attrib_def(ColorAttrib::get_class_slot()));
+  const ColorAttrib *target_color = (const ColorAttrib *)
+    _target_rs->get_attrib_def(ColorAttrib::get_class_slot());
+
   switch (target_color->get_color_type()) {
   switch (target_color->get_color_type()) {
   case ColorAttrib::T_flat:
   case ColorAttrib::T_flat:
     // Color attribute flat: it specifies a scene graph color that
     // Color attribute flat: it specifies a scene graph color that
@@ -2219,7 +2235,9 @@ do_issue_color_scale() {
     _state_mask.clear_bit(TextureAttrib::get_class_slot());
     _state_mask.clear_bit(TextureAttrib::get_class_slot());
   }
   }
 
 
-  const ColorScaleAttrib *target_color_scale = DCAST(ColorScaleAttrib, _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot()));
+  const ColorScaleAttrib *target_color_scale = (const ColorScaleAttrib *)
+    _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot());
+
   _color_scale_enabled = target_color_scale->has_scale();
   _color_scale_enabled = target_color_scale->has_scale();
   _current_color_scale = target_color_scale->get_scale();
   _current_color_scale = target_color_scale->get_scale();
   _has_texture_alpha_scale = false;
   _has_texture_alpha_scale = false;
@@ -2278,7 +2296,9 @@ do_issue_light() {
   int num_enabled = 0;
   int num_enabled = 0;
   int num_on_lights = 0;
   int num_on_lights = 0;
 
 
-  const LightAttrib *target_light = DCAST(LightAttrib, _target_rs->get_attrib_def(LightAttrib::get_class_slot()));
+  const LightAttrib *target_light = (const LightAttrib *)
+    _target_rs->get_attrib_def(LightAttrib::get_class_slot());
+
   if (display_cat.is_spam()) {
   if (display_cat.is_spam()) {
     display_cat.spam()
     display_cat.spam()
       << "do_issue_light: " << target_light << "\n";
       << "do_issue_light: " << target_light << "\n";
@@ -2639,8 +2659,10 @@ end_bind_clip_planes() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 determine_target_texture() {
 determine_target_texture() {
-  const TextureAttrib *target_texture = DCAST(TextureAttrib, _target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
-  const TexGenAttrib *target_tex_gen = DCAST(TexGenAttrib, _target_rs->get_attrib_def(TexGenAttrib::get_class_slot()));
+  const TextureAttrib *target_texture = (const TextureAttrib *)
+    _target_rs->get_attrib_def(TextureAttrib::get_class_slot());
+  const TexGenAttrib *target_tex_gen = (const TexGenAttrib *)
+    _target_rs->get_attrib_def(TexGenAttrib::get_class_slot());
 
 
   nassertv(target_texture != (TextureAttrib *)NULL &&
   nassertv(target_texture != (TextureAttrib *)NULL &&
            target_tex_gen != (TexGenAttrib *)NULL);
            target_tex_gen != (TexGenAttrib *)NULL);

+ 17 - 0
panda/src/express/memoryUsage.I

@@ -366,3 +366,20 @@ INLINE void MemoryUsage::
 show_trend_ages() {
 show_trend_ages() {
   get_global_ptr()->ns_show_trend_ages();
   get_global_ptr()->ns_show_trend_ages();
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsage::get_global_ptr
+//       Access: Private, Static
+//  Description: Returns the pointer to the only MemoryUsage object in
+//               the world.
+////////////////////////////////////////////////////////////////////
+INLINE MemoryUsage *MemoryUsage::
+get_global_ptr() {
+  if (_global_ptr == (MemoryUsage *)NULL) {
+    init_memory_hook();
+    _global_ptr = new MemoryUsage(*memory_hook);
+    memory_hook = _global_ptr;
+  }
+
+  return _global_ptr;
+}

+ 0 - 18
panda/src/express/memoryUsage.cxx

@@ -564,24 +564,6 @@ overflow_heap_size() {
   _report_memory_usage = true;
   _report_memory_usage = true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: MemoryUsage::get_global_ptr
-//       Access: Private, Static
-//  Description: Returns the pointer to the only MemoryUsage object in
-//               the world.
-////////////////////////////////////////////////////////////////////
-MemoryUsage *MemoryUsage::
-get_global_ptr() {
-  if (_global_ptr == (MemoryUsage *)NULL) {
-    init_memory_hook();
-    _global_ptr = new MemoryUsage(*memory_hook);
-    memory_hook = _global_ptr;
-  }
-
-  return _global_ptr;
-}
-
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MemoryUsage::ns_record_pointer
 //     Function: MemoryUsage::ns_record_pointer
 //       Access: Private
 //       Access: Private

+ 1 - 1
panda/src/express/memoryUsage.h

@@ -96,7 +96,7 @@ protected:
 
 
 private:
 private:
   MemoryUsage(const MemoryHook &copy);
   MemoryUsage(const MemoryHook &copy);
-  static MemoryUsage *get_global_ptr();
+  INLINE static MemoryUsage *get_global_ptr();
 
 
   void ns_record_pointer(ReferenceCount *ptr);
   void ns_record_pointer(ReferenceCount *ptr);
   void ns_update_type(ReferenceCount *ptr, TypeHandle type);
   void ns_update_type(ReferenceCount *ptr, TypeHandle type);

+ 88 - 0
panda/src/express/nodePointerTo.I

@@ -51,6 +51,36 @@ INLINE NodePointerTo<T>::
 }
 }
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
+#ifdef USE_MOVE_SEMANTICS
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerTo<T>::
+NodePointerTo(NodePointerTo<T> &&from) NOEXCEPT :
+  NodePointerToBase<T>((NodePointerToBase<T> &&)from)
+{
+}
+#endif  // CPPPARSER
+
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerTo::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerTo<T> &NodePointerTo<T>::
+operator = (NodePointerTo<T> &&from) NOEXCEPT {
+  this->reassign(move(from));
+  return *this;
+}
+#endif  // CPPPARSER
+#endif  // USE_MOVE_SEMANTICS
+
 #ifndef CPPPARSER
 #ifndef CPPPARSER
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePointerTo::Dereference operator
 //     Function: NodePointerTo::Dereference operator
@@ -192,6 +222,64 @@ INLINE NodeConstPointerTo<T>::
 }
 }
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
+#ifdef USE_MOVE_SEMANTICS
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T>::
+NodeConstPointerTo(NodePointerTo<T> &&from) NOEXCEPT :
+  NodePointerToBase<T>((NodePointerToBase<T> &&)from)
+{
+}
+#endif  // CPPPARSER
+
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T>::
+NodeConstPointerTo(NodeConstPointerTo<T> &&from) NOEXCEPT :
+  NodePointerToBase<T>((NodePointerToBase<T> &&)from)
+{
+}
+#endif  // CPPPARSER
+
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
+operator = (NodePointerTo<T> &&from) NOEXCEPT {
+  this->reassign(move(from));
+  return *this;
+}
+#endif  // CPPPARSER
+
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: NodeConstPointerTo::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodeConstPointerTo<T> &NodeConstPointerTo<T>::
+operator = (NodeConstPointerTo<T> &&from) NOEXCEPT {
+  this->reassign(move(from));
+  return *this;
+}
+#endif  // CPPPARSER
+#endif  // USE_MOVE_SEMANTICS
+
 #ifndef CPPPARSER
 #ifndef CPPPARSER
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodeConstPointerTo::Dereference operator
 //     Function: NodeConstPointerTo::Dereference operator

+ 22 - 0
panda/src/express/nodePointerTo.h

@@ -36,6 +36,11 @@ public:
   INLINE NodePointerTo(const NodePointerTo<T> &copy);
   INLINE NodePointerTo(const NodePointerTo<T> &copy);
   INLINE ~NodePointerTo();
   INLINE ~NodePointerTo();
 
 
+#ifdef USE_MOVE_SEMANTICS
+  INLINE NodePointerTo(NodePointerTo<T> &&from) NOEXCEPT;
+  INLINE NodePointerTo<T> &operator = (NodePointerTo<T> &&from) NOEXCEPT;
+#endif
+
   INLINE To &operator *() const;
   INLINE To &operator *() const;
   INLINE To *operator -> () const;
   INLINE To *operator -> () const;
 
 
@@ -67,6 +72,13 @@ public:
   INLINE NodeConstPointerTo(const NodeConstPointerTo<T> &copy);
   INLINE NodeConstPointerTo(const NodeConstPointerTo<T> &copy);
   INLINE ~NodeConstPointerTo();
   INLINE ~NodeConstPointerTo();
 
 
+#ifdef USE_MOVE_SEMANTICS
+  INLINE NodeConstPointerTo(NodePointerTo<T> &&from) NOEXCEPT;
+  INLINE NodeConstPointerTo(NodeConstPointerTo<T> &&from) NOEXCEPT;
+  INLINE NodeConstPointerTo<T> &operator = (NodePointerTo<T> &&from) NOEXCEPT;
+  INLINE NodeConstPointerTo<T> &operator = (NodeConstPointerTo<T> &&from) NOEXCEPT;
+#endif
+
   INLINE const To &operator *() const;
   INLINE const To &operator *() const;
   INLINE const To *operator -> () const;
   INLINE const To *operator -> () const;
   INLINE operator const T *() const;
   INLINE operator const T *() const;
@@ -79,6 +91,16 @@ public:
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 };
 };
 
 
+template <class T>
+void swap(NodePointerTo<T> &one, NodePointerTo<T> &two) NOEXCEPT {
+  one.swap(two);
+}
+
+template <class T>
+void swap(NodeConstPointerTo<T> &one, NodeConstPointerTo<T> &two) NOEXCEPT {
+  one.swap(two);
+}
+
 #define NPT(type) NodePointerTo< type >
 #define NPT(type) NodePointerTo< type >
 #define NCPT(type) NodeConstPointerTo< type >
 #define NCPT(type) NodeConstPointerTo< type >
 
 

+ 37 - 0
panda/src/express/nodePointerToBase.I

@@ -46,6 +46,43 @@ INLINE NodePointerToBase<T>::
   reassign((To *)NULL);
   reassign((To *)NULL);
 }
 }
 
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::Move Constructor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE NodePointerToBase<T>::
+NodePointerToBase(NodePointerToBase<T> &&from) NOEXCEPT {
+  _void_ptr = from._void_ptr;
+  from._void_ptr = (void *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePointerToBase::reassign
+//       Access: Protected
+//  Description: This version of reassign is called when a
+//               NodePointerTo is assigned to this Node PointerTo
+//               as an rvalue.  In this case, we can steal the
+//               reference count from the other PointerTo, without
+//               needing to call ref() and unref() unnecessarily.
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE void NodePointerToBase<T>::
+reassign(NodePointerToBase<T> &&from) NOEXCEPT {
+  To *old_ptr = (To *)this->_void_ptr;
+
+  this->_void_ptr = from._void_ptr;
+  from._void_ptr = NULL;
+
+  // Now delete the old pointer.
+  if (old_ptr != (To *)NULL) {
+    node_unref_delete(old_ptr);
+  }
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePointerToBase::reassign
 //     Function: NodePointerToBase::reassign
 //       Access: Protected
 //       Access: Protected

+ 5 - 0
panda/src/express/nodePointerToBase.h

@@ -42,6 +42,11 @@ protected:
   INLINE NodePointerToBase(const NodePointerToBase<T> &copy);
   INLINE NodePointerToBase(const NodePointerToBase<T> &copy);
   INLINE ~NodePointerToBase();
   INLINE ~NodePointerToBase();
 
 
+#ifdef USE_MOVE_SEMANTICS
+  INLINE NodePointerToBase(NodePointerToBase<T> &&from) NOEXCEPT;
+  INLINE void reassign(NodePointerToBase<To> &&from) NOEXCEPT;
+#endif
+
   void reassign(To *ptr);
   void reassign(To *ptr);
   INLINE void reassign(const NodePointerToBase<To> &copy);
   INLINE void reassign(const NodePointerToBase<To> &copy);
 
 

+ 33 - 25
panda/src/express/pointerTo.I

@@ -43,8 +43,8 @@ PointerTo(const PointerTo<T> &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class T>
 template<class T>
 INLINE PointerTo<T>::
 INLINE PointerTo<T>::
-PointerTo(PointerTo<T> &&move) NOEXCEPT :
-  PointerToBase<T>((PointerToBase<T> &&)move)
+PointerTo(PointerTo<T> &&from) NOEXCEPT :
+  PointerToBase<T>(move(from))
 {
 {
 }
 }
 
 
@@ -55,19 +55,11 @@ PointerTo(PointerTo<T> &&move) NOEXCEPT :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class T>
 template<class T>
 INLINE PointerTo<T> &PointerTo<T>::
 INLINE PointerTo<T> &PointerTo<T>::
-operator = (PointerTo<T> &&move) NOEXCEPT {
-  To *old_ptr = (To *)this->_void_ptr;
-
-  this->_void_ptr = move._void_ptr;
-  move._void_ptr = NULL;
-
-  if (old_ptr != (To *)NULL) {
-    unref_delete(old_ptr);
-  }
-
+operator = (PointerTo<T> &&from) NOEXCEPT {
+  this->reassign(move(from));
   return *this;
   return *this;
 }
 }
-#endif
+#endif  // USE_MOVE_SEMANTICS
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerTo::Destructor
 //     Function: PointerTo::Destructor
@@ -208,8 +200,20 @@ ConstPointerTo(const ConstPointerTo<T> &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class T>
 template<class T>
 INLINE ConstPointerTo<T>::
 INLINE ConstPointerTo<T>::
-ConstPointerTo(ConstPointerTo<T> &&move) NOEXCEPT :
-  PointerToBase<T>((PointerToBase<T> &&)move)
+ConstPointerTo(PointerTo<T> &&from) NOEXCEPT :
+  PointerToBase<T>(move(from))
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConstPointerTo::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE ConstPointerTo<T>::
+ConstPointerTo(ConstPointerTo<T> &&from) NOEXCEPT :
+  PointerToBase<T>(move(from))
 {
 {
 }
 }
 
 
@@ -220,19 +224,23 @@ ConstPointerTo(ConstPointerTo<T> &&move) NOEXCEPT :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class T>
 template<class T>
 INLINE ConstPointerTo<T> &ConstPointerTo<T>::
 INLINE ConstPointerTo<T> &ConstPointerTo<T>::
-operator = (ConstPointerTo<T> &&move) NOEXCEPT {
-  To *old_ptr = (To *)this->_void_ptr;
-
-  this->_void_ptr = move._void_ptr;
-  move._void_ptr = NULL;
-
-  if (old_ptr != (To *)NULL) {
-    unref_delete(old_ptr);
-  }
+operator = (PointerTo<T> &&from) NOEXCEPT {
+  this->reassign(move(from));
+  return *this;
+}
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConstPointerTo::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (ConstPointerTo<T> &&from) NOEXCEPT {
+  this->reassign(move(from));
   return *this;
   return *this;
 }
 }
-#endif
+#endif  // USE_MOVE_SEMANTICS
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ConstPointerTo::Dereference operator
 //     Function: ConstPointerTo::Dereference operator

+ 8 - 6
panda/src/express/pointerTo.h

@@ -86,8 +86,8 @@ PUBLISHED:
 
 
 public:
 public:
 #ifdef USE_MOVE_SEMANTICS
 #ifdef USE_MOVE_SEMANTICS
-  INLINE PointerTo(PointerTo<T> &&move) NOEXCEPT;
-  INLINE PointerTo<T> &operator = (PointerTo<T> &&move) NOEXCEPT;
+  INLINE PointerTo(PointerTo<T> &&from) NOEXCEPT;
+  INLINE PointerTo<T> &operator = (PointerTo<T> &&from) NOEXCEPT;
 #endif
 #endif
 
 
   INLINE To &operator *() const;
   INLINE To &operator *() const;
@@ -150,8 +150,10 @@ PUBLISHED:
 
 
 public:
 public:
 #ifdef USE_MOVE_SEMANTICS
 #ifdef USE_MOVE_SEMANTICS
-  INLINE ConstPointerTo(ConstPointerTo<T> &&move) NOEXCEPT;
-  INLINE ConstPointerTo<T> &operator = (ConstPointerTo<T> &&move) NOEXCEPT;
+  INLINE ConstPointerTo(PointerTo<T> &&from) NOEXCEPT;
+  INLINE ConstPointerTo(ConstPointerTo<T> &&from) NOEXCEPT;
+  INLINE ConstPointerTo<T> &operator = (PointerTo<T> &&from) NOEXCEPT;
+  INLINE ConstPointerTo<T> &operator = (ConstPointerTo<T> &&from) NOEXCEPT;
 #endif
 #endif
 
 
   INLINE const To &operator *() const;
   INLINE const To &operator *() const;
@@ -177,12 +179,12 @@ PUBLISHED:
 // of PointerTo objects without incurring the cost of unnecessary
 // of PointerTo objects without incurring the cost of unnecessary
 // reference count changes.  The performance difference is dramatic!
 // reference count changes.  The performance difference is dramatic!
 template <class T>
 template <class T>
-void swap(PointerTo<T> &one, PointerTo<T> &two) {
+void swap(PointerTo<T> &one, PointerTo<T> &two) NOEXCEPT {
   one.swap(two);
   one.swap(two);
 }
 }
 
 
 template <class T>
 template <class T>
-void swap(ConstPointerTo<T> &one, ConstPointerTo<T> &two) {
+void swap(ConstPointerTo<T> &one, ConstPointerTo<T> &two) NOEXCEPT {
   one.swap(two);
   one.swap(two);
 }
 }
 
 

+ 32 - 9
panda/src/express/pointerToBase.I

@@ -36,29 +36,52 @@ PointerToBase(const PointerToBase<T> &copy) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Move Constructor
+//     Function: PointerToBase::Destructor
 //       Access: Protected
 //       Access: Protected
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-#ifdef USE_MOVE_SEMANTICS
 template<class T>
 template<class T>
 INLINE PointerToBase<T>::
 INLINE PointerToBase<T>::
-PointerToBase(PointerToBase<T> &&move) NOEXCEPT {
-  _void_ptr = move._void_ptr;
-  move._void_ptr = (void *)NULL;
+~PointerToBase() {
+  reassign((To *)NULL);
 }
 }
-#endif
 
 
+#ifdef USE_MOVE_SEMANTICS
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PointerToBase::Destructor
+//     Function: PointerToBase::Move Constructor
 //       Access: Protected
 //       Access: Protected
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class T>
 template<class T>
 INLINE PointerToBase<T>::
 INLINE PointerToBase<T>::
-~PointerToBase() {
-  reassign((To *)NULL);
+PointerToBase(PointerToBase<T> &&from) NOEXCEPT {
+  _void_ptr = from._void_ptr;
+  from._void_ptr = (void *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToBase::reassign
+//       Access: Protected
+//  Description: This version of reassign is called when a PointerTo
+//               is assigned to this PointerTo as an rvalue.  In
+//               this case, we can steal the reference count from
+//               the other PointerTo, without needing to call ref()
+//               and unref() unnecessarily.
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE void PointerToBase<T>::
+reassign(PointerToBase<T> &&from) NOEXCEPT {
+  To *old_ptr = (To *)this->_void_ptr;
+
+  this->_void_ptr = from._void_ptr;
+  from._void_ptr = NULL;
+
+  // Now delete the old pointer.
+  if (old_ptr != (To *)NULL) {
+    unref_delete(old_ptr);
+  }
 }
 }
+#endif  // USE_MOVE_SEMANTICS
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerToBase::reassign
 //     Function: PointerToBase::reassign

+ 2 - 1
panda/src/express/pointerToBase.h

@@ -39,7 +39,8 @@ protected:
   INLINE ~PointerToBase();
   INLINE ~PointerToBase();
 
 
 #ifdef USE_MOVE_SEMANTICS
 #ifdef USE_MOVE_SEMANTICS
-  INLINE PointerToBase(PointerToBase<T> &&move) NOEXCEPT;
+  INLINE PointerToBase(PointerToBase<T> &&from) NOEXCEPT;
+  INLINE void reassign(PointerToBase<To> &&from) NOEXCEPT;
 #endif
 #endif
 
 
   INLINE void reassign(To *ptr);
   INLINE void reassign(To *ptr);

+ 7 - 2
panda/src/express/pointerToVoid.I

@@ -110,8 +110,13 @@ operator != (const PointerToVoid &other) const {
 //       Access: Public
 //       Access: Public
 //  Description: Swaps the contents of this PointerTo with the other,
 //  Description: Swaps the contents of this PointerTo with the other,
 //               without touching the reference counts.
 //               without touching the reference counts.
+//
+//               For internal use only.  Use the global swap()
+//               function instead.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PointerToVoid::
 INLINE void PointerToVoid::
-swap(PointerToVoid &other) {
-  std::swap(_void_ptr, other._void_ptr);
+swap(PointerToVoid &other) NOEXCEPT {
+  AtomicAdjust::Pointer temp = _void_ptr;
+  _void_ptr = other._void_ptr;
+  other._void_ptr = temp;
 }
 }

+ 1 - 1
panda/src/express/pointerToVoid.h

@@ -54,7 +54,7 @@ public:
   INLINE bool operator == (const PointerToVoid &other) const;
   INLINE bool operator == (const PointerToVoid &other) const;
   INLINE bool operator != (const PointerToVoid &other) const;
   INLINE bool operator != (const PointerToVoid &other) const;
 
 
-  INLINE void swap(PointerToVoid &other);
+  INLINE void swap(PointerToVoid &other) NOEXCEPT;
 
 
 protected:
 protected:
   // Within the PointerToVoid class, we only store a void pointer.
   // Within the PointerToVoid class, we only store a void pointer.

+ 57 - 24
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2288,6 +2288,7 @@ clear(DrawableRegion *clearable) {
     return;
     return;
   }
   }
 
 
+  //XXX rdb: Is this line really necessary?
   set_state_and_transform(RenderState::make_empty(), _internal_transform);
   set_state_and_transform(RenderState::make_empty(), _internal_transform);
 
 
   int mask = 0;
   int mask = 0;
@@ -2842,7 +2843,7 @@ end_frame(Thread *current_thread) {
 
 
   // Now is a good time to delete any pending display lists.
   // Now is a good time to delete any pending display lists.
 #ifndef OPENGLES
 #ifndef OPENGLES
-  {
+  if (display_lists) {
     LightMutexHolder holder(_lock);
     LightMutexHolder holder(_lock);
     if (!_deleted_display_lists.empty()) {
     if (!_deleted_display_lists.empty()) {
       DeletedNames::iterator ddli;
       DeletedNames::iterator ddli;
@@ -2857,10 +2858,13 @@ end_frame(Thread *current_thread) {
       }
       }
       _deleted_display_lists.clear();
       _deleted_display_lists.clear();
     }
     }
+  }
 
 
-    // And deleted queries, too, unless we're using query timers
-    // in which case we'll need to reuse lots of them.
-    if (!get_timer_queries_active() && !_deleted_queries.empty()) {
+  // And deleted queries, too, unless we're using query timers
+  // in which case we'll need to reuse lots of them.
+  if (_supports_occlusion_query && !get_timer_queries_active()) {
+    LightMutexHolder holder(_lock);
+    if (!_deleted_queries.empty()) {
       if (GLCAT.is_spam()) {
       if (GLCAT.is_spam()) {
         DeletedNames::iterator dqi;
         DeletedNames::iterator dqi;
         for (dqi = _deleted_queries.begin();
         for (dqi = _deleted_queries.begin();
@@ -5122,9 +5126,9 @@ issue_timer_query(int pstats_index) {
   // Issue the timestamp query.
   // Issue the timestamp query.
   _glQueryCounter(query->_index, GL_TIMESTAMP);
   _glQueryCounter(query->_index, GL_TIMESTAMP);
 
 
-  _pending_timer_queries.push_back(DCAST(TimerQueryContext, query));
+  _pending_timer_queries.push_back((TimerQueryContext *)query);
 
 
-  return DCAST(TimerQueryContext, query);
+  return (TimerQueryContext *)query;
 
 
 #else
 #else
   return NULL;
   return NULL;
@@ -5637,7 +5641,9 @@ do_issue_transform() {
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_shade_model() {
 do_issue_shade_model() {
 #ifndef OPENGLES_2
 #ifndef OPENGLES_2
-  const ShadeModelAttrib *target_shade_model = DCAST(ShadeModelAttrib, _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot()));
+  const ShadeModelAttrib *target_shade_model = (const ShadeModelAttrib *)
+    _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot());
+
   switch (target_shade_model->get_mode()) {
   switch (target_shade_model->get_mode()) {
   case ShadeModelAttrib::M_smooth:
   case ShadeModelAttrib::M_smooth:
     glShadeModel(GL_SMOOTH);
     glShadeModel(GL_SMOOTH);
@@ -5720,7 +5726,9 @@ do_issue_shader(bool state_has_changed) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_render_mode() {
 do_issue_render_mode() {
-  const RenderModeAttrib *target_render_mode = DCAST(RenderModeAttrib, _target_rs->get_attrib_def(RenderModeAttrib::get_class_slot()));
+  const RenderModeAttrib *target_render_mode = (const RenderModeAttrib *)
+    _target_rs->get_attrib_def(RenderModeAttrib::get_class_slot());
+
   _render_mode = target_render_mode->get_mode();
   _render_mode = target_render_mode->get_mode();
   _point_size = target_render_mode->get_thickness();
   _point_size = target_render_mode->get_thickness();
   _point_perspective = target_render_mode->get_perspective();
   _point_perspective = target_render_mode->get_perspective();
@@ -5764,7 +5772,9 @@ do_issue_render_mode() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_antialias() {
 do_issue_antialias() {
-  const AntialiasAttrib *target_antialias = DCAST(AntialiasAttrib, _target_rs->get_attrib_def(AntialiasAttrib::get_class_slot()));
+  const AntialiasAttrib *target_antialias = (const AntialiasAttrib *)
+    _target_rs->get_attrib_def(AntialiasAttrib::get_class_slot());
+
   if (target_antialias->get_mode_type() == AntialiasAttrib::M_auto) {
   if (target_antialias->get_mode_type() == AntialiasAttrib::M_auto) {
     // In this special mode, we must enable antialiasing on a
     // In this special mode, we must enable antialiasing on a
     // case-by-case basis, because we enable it differently for
     // case-by-case basis, because we enable it differently for
@@ -5830,7 +5840,9 @@ do_issue_antialias() {
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_rescale_normal() {
 do_issue_rescale_normal() {
 #ifndef OPENGLES_2 // OpenGL ES 2.0 doesn't support rescaling normals.
 #ifndef OPENGLES_2 // OpenGL ES 2.0 doesn't support rescaling normals.
-  const RescaleNormalAttrib *target_rescale_normal = DCAST(RescaleNormalAttrib, _target_rs->get_attrib_def(RescaleNormalAttrib::get_class_slot()));
+  const RescaleNormalAttrib *target_rescale_normal = (const RescaleNormalAttrib *)
+    _target_rs->get_attrib_def(RescaleNormalAttrib::get_class_slot());
+
   RescaleNormalAttrib::Mode mode = target_rescale_normal->get_mode();
   RescaleNormalAttrib::Mode mode = target_rescale_normal->get_mode();
 
 
   _auto_rescale_normal = false;
   _auto_rescale_normal = false;
@@ -5882,7 +5894,9 @@ do_issue_rescale_normal() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_depth_test() {
 do_issue_depth_test() {
-  const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot()));
+  const DepthTestAttrib *target_depth_test = (const DepthTestAttrib *)
+    _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot());
+
   DepthTestAttrib::PandaCompareFunc mode = target_depth_test->get_mode();
   DepthTestAttrib::PandaCompareFunc mode = target_depth_test->get_mode();
   if (mode == DepthTestAttrib::M_none) {
   if (mode == DepthTestAttrib::M_none) {
     enable_depth_test(false);
     enable_depth_test(false);
@@ -5903,7 +5917,9 @@ do_issue_alpha_test() {
   if (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) {
   if (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) {
     enable_alpha_test(false);
     enable_alpha_test(false);
   } else {
   } else {
-    const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
+    const AlphaTestAttrib *target_alpha_test = (const AlphaTestAttrib *)
+      _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot());
+
     AlphaTestAttrib::PandaCompareFunc mode = target_alpha_test->get_mode();
     AlphaTestAttrib::PandaCompareFunc mode = target_alpha_test->get_mode();
     if (mode == AlphaTestAttrib::M_none) {
     if (mode == AlphaTestAttrib::M_none) {
       enable_alpha_test(false);
       enable_alpha_test(false);
@@ -5924,7 +5940,9 @@ do_issue_alpha_test() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_depth_write() {
 do_issue_depth_write() {
-  const DepthWriteAttrib *target_depth_write = DCAST(DepthWriteAttrib, _target_rs->get_attrib_def(DepthWriteAttrib::get_class_slot()));
+  const DepthWriteAttrib *target_depth_write = (const DepthWriteAttrib *)
+    _target_rs->get_attrib_def(DepthWriteAttrib::get_class_slot());
+
   DepthWriteAttrib::Mode mode = target_depth_write->get_mode();
   DepthWriteAttrib::Mode mode = target_depth_write->get_mode();
   if (mode == DepthWriteAttrib::M_off) {
   if (mode == DepthWriteAttrib::M_off) {
 #ifdef GSG_VERBOSE
 #ifdef GSG_VERBOSE
@@ -5949,7 +5967,9 @@ do_issue_depth_write() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_cull_face() {
 do_issue_cull_face() {
-  const CullFaceAttrib *target_cull_face = DCAST(CullFaceAttrib, _target_rs->get_attrib_def(CullFaceAttrib::get_class_slot()));
+  const CullFaceAttrib *target_cull_face = (const CullFaceAttrib *)
+    _target_rs->get_attrib_def(CullFaceAttrib::get_class_slot());
+
   CullFaceAttrib::Mode mode = target_cull_face->get_effective_mode();
   CullFaceAttrib::Mode mode = target_cull_face->get_effective_mode();
 
 
   switch (mode) {
   switch (mode) {
@@ -5979,7 +5999,9 @@ do_issue_cull_face() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_fog() {
 do_issue_fog() {
-  const FogAttrib *target_fog = DCAST(FogAttrib, _target_rs->get_attrib_def(FogAttrib::get_class_slot()));
+  const FogAttrib *target_fog = (const FogAttrib *)
+    _target_rs->get_attrib_def(FogAttrib::get_class_slot());
+
   if (!target_fog->is_off()) {
   if (!target_fog->is_off()) {
     enable_fog(true);
     enable_fog(true);
     Fog *fog = target_fog->get_fog();
     Fog *fog = target_fog->get_fog();
@@ -5998,7 +6020,9 @@ do_issue_fog() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_depth_offset() {
 do_issue_depth_offset() {
-  const DepthOffsetAttrib *target_depth_offset = DCAST(DepthOffsetAttrib, _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot()));
+  const DepthOffsetAttrib *target_depth_offset = (const DepthOffsetAttrib *)
+     _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot());
+
   int offset = target_depth_offset->get_offset();
   int offset = target_depth_offset->get_offset();
 
 
   if (offset != 0) {
   if (offset != 0) {
@@ -6039,7 +6063,8 @@ do_issue_material() {
   static Material empty;
   static Material empty;
   const Material *material;
   const Material *material;
 
 
-  const MaterialAttrib *target_material = DCAST(MaterialAttrib, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()));
+  const MaterialAttrib *target_material = (const MaterialAttrib *)
+    _target_rs->get_attrib_def(MaterialAttrib::get_class_slot());
 
 
   if (target_material == (MaterialAttrib *)NULL ||
   if (target_material == (MaterialAttrib *)NULL ||
       target_material->is_off()) {
       target_material->is_off()) {
@@ -6146,7 +6171,8 @@ do_issue_blending() {
   // all the other blending-related stuff doesn't matter.  If the
   // all the other blending-related stuff doesn't matter.  If the
   // device doesn't support color-write, we use blending tricks
   // device doesn't support color-write, we use blending tricks
   // to effectively disable color write.
   // to effectively disable color write.
-  const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
+  const ColorWriteAttrib *target_color_write = (const ColorWriteAttrib *)
+    _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot());
 
 
   unsigned int color_channels =
   unsigned int color_channels =
     target_color_write->get_channels() & _color_write_mask;
     target_color_write->get_channels() & _color_write_mask;
@@ -6176,11 +6202,13 @@ do_issue_blending() {
   }
   }
 
 
 
 
-  const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
+  const ColorBlendAttrib *target_color_blend = (const ColorBlendAttrib *)
+    _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot());
   CPT(ColorBlendAttrib) color_blend = target_color_blend;
   CPT(ColorBlendAttrib) color_blend = target_color_blend;
   ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
   ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
 
 
-  const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
+  const TransparencyAttrib *target_transparency = (const TransparencyAttrib *)
+    _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot());
   TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
   TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
 
 
   _color_blend_involves_color_scale = color_blend->involves_color_scale();
   _color_blend_involves_color_scale = color_blend->involves_color_scale();
@@ -8731,7 +8759,8 @@ set_state_and_transform(const RenderState *target,
   }
   }
   _target_rs = target;
   _target_rs = target;
 
 
-  _target_shader = DCAST(ShaderAttrib, _target_rs->get_attrib_def(ShaderAttrib::get_class_slot()));
+  _target_shader = (const ShaderAttrib *)
+    _target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
 #ifndef OPENGLES
 #ifndef OPENGLES
   _instance_count = _target_shader->get_instance_count();
   _instance_count = _target_shader->get_instance_count();
 #endif
 #endif
@@ -9558,7 +9587,9 @@ do_issue_tex_matrix() {
 
 
     glMatrixMode(GL_TEXTURE);
     glMatrixMode(GL_TEXTURE);
 
 
-    const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
+    const TexMatrixAttrib *target_tex_matrix = (const TexMatrixAttrib *)
+      _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot());
+
     if (target_tex_matrix->has_stage(stage)) {
     if (target_tex_matrix->has_stage(stage)) {
       GLPf(LoadMatrix)(target_tex_matrix->get_mat(stage).get_data());
       GLPf(LoadMatrix)(target_tex_matrix->get_mat(stage).get_data());
     } else {
     } else {
@@ -11886,7 +11917,8 @@ do_issue_stencil() {
     return;
     return;
   }
   }
 
 
-  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib(StencilAttrib::get_class_slot()));
+  const StencilAttrib *stencil = (const StencilAttrib *)
+    _target_rs->get_attrib(StencilAttrib::get_class_slot());
 
 
   if (stencil != (const StencilAttrib *)NULL) {
   if (stencil != (const StencilAttrib *)NULL) {
     // DEBUG
     // DEBUG
@@ -11974,7 +12006,8 @@ do_issue_stencil() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 do_issue_scissor() {
 do_issue_scissor() {
-  const ScissorAttrib *target_scissor = DCAST(ScissorAttrib, _target_rs->get_attrib_def(ScissorAttrib::get_class_slot()));
+  const ScissorAttrib *target_scissor = (const ScissorAttrib *)
+    _target_rs->get_attrib_def(ScissorAttrib::get_class_slot());
 
 
   if (!target_scissor->is_off()) {
   if (!target_scissor->is_off()) {
     // A non-off ScissorAttrib means to override the scissor setting
     // A non-off ScissorAttrib means to override the scissor setting

+ 72 - 21
panda/src/gobj/geom.I

@@ -380,14 +380,14 @@ clear_bounds() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Geom::
 INLINE void Geom::
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                  bool &found_any, 
+                  bool &found_any,
                   const GeomVertexData *vertex_data,
                   const GeomVertexData *vertex_data,
                   bool got_mat, const LMatrix4 &mat,
                   bool got_mat, const LMatrix4 &mat,
                   Thread *current_thread) const {
                   Thread *current_thread) const {
   CDReader cdata(_cycler, current_thread);
   CDReader cdata(_cycler, current_thread);
-  
-  do_calc_tight_bounds(min_point, max_point, found_any, 
-                       vertex_data, got_mat, mat, 
+
+  do_calc_tight_bounds(min_point, max_point, found_any,
+                       vertex_data, got_mat, mat,
                        InternalName::get_vertex(),
                        InternalName::get_vertex(),
                        cdata, current_thread);
                        cdata, current_thread);
 }
 }
@@ -409,7 +409,7 @@ INLINE void Geom::
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
                   bool &found_any, Thread *current_thread) const {
                   bool &found_any, Thread *current_thread) const {
   calc_tight_bounds(min_point, max_point, found_any,
   calc_tight_bounds(min_point, max_point, found_any,
-                    get_vertex_data(current_thread), false, 
+                    get_vertex_data(current_thread), false,
                     LMatrix4::ident_mat(),
                     LMatrix4::ident_mat(),
                     current_thread);
                     current_thread);
 }
 }
@@ -422,15 +422,15 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Geom::
 INLINE void Geom::
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                  bool &found_any, 
+                  bool &found_any,
                   const GeomVertexData *vertex_data,
                   const GeomVertexData *vertex_data,
                   bool got_mat, const LMatrix4 &mat,
                   bool got_mat, const LMatrix4 &mat,
                   const InternalName *column_name,
                   const InternalName *column_name,
                   Thread *current_thread) const {
                   Thread *current_thread) const {
   CDReader cdata(_cycler, current_thread);
   CDReader cdata(_cycler, current_thread);
-  
-  do_calc_tight_bounds(min_point, max_point, found_any, 
-                       vertex_data, got_mat, mat, 
+
+  do_calc_tight_bounds(min_point, max_point, found_any,
+                       vertex_data, got_mat, mat,
                        column_name, cdata, current_thread);
                        column_name, cdata, current_thread);
 }
 }
 
 
@@ -450,7 +450,7 @@ mark_internal_bounds_stale(CData *cdata) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::CDataCache::Constructor
 //     Function: Geom::CDataCache::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Geom::CDataCache::
 INLINE Geom::CDataCache::
 CDataCache() :
 CDataCache() :
@@ -463,7 +463,7 @@ CDataCache() :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::CDataCache::Copy Constructor
 //     Function: Geom::CDataCache::Copy Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Geom::CDataCache::
 INLINE Geom::CDataCache::
 CDataCache(const Geom::CDataCache &copy) :
 CDataCache(const Geom::CDataCache &copy) :
@@ -500,7 +500,7 @@ set_result(const Geom *geom_result, const GeomVertexData *data_result) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::CacheKey::Constructor
 //     Function: Geom::CacheKey::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Geom::CacheKey::
 INLINE Geom::CacheKey::
 CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) :
 CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) :
@@ -509,6 +509,32 @@ CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) :
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::CacheKey::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Geom::CacheKey::
+CacheKey(const CacheKey &copy) :
+  _source_data(copy._source_data),
+  _modifier(copy._modifier)
+{
+}
+
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::CacheKey::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Geom::CacheKey::
+CacheKey(CacheKey &&from) NOEXCEPT :
+  _source_data(move(from._source_data)),
+  _modifier(move(from._modifier))
+{
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::CacheKey::operator <
 //     Function: Geom::CacheKey::operator <
 //       Access: Public
 //       Access: Public
@@ -531,7 +557,7 @@ operator < (const CacheKey &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::CacheEntry::Constructor
 //     Function: Geom::CacheEntry::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Geom::CacheEntry::
 INLINE Geom::CacheEntry::
 CacheEntry(Geom *source, const GeomVertexData *source_data,
 CacheEntry(Geom *source, const GeomVertexData *source_data,
@@ -541,6 +567,31 @@ CacheEntry(Geom *source, const GeomVertexData *source_data,
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::CacheEntry::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Geom::CacheEntry::
+CacheEntry(Geom *source, const Geom::CacheKey &key) :
+  _source(source),
+  _key(key)
+{
+}
+
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::CacheEntry::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE Geom::CacheEntry::
+CacheEntry(Geom *source, Geom::CacheKey &&key) NOEXCEPT :
+  _source(source),
+  _key(move(key))
+{
+}
+#endif  // USE_MOVE_SEMANTICS
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::CData::Constructor
 //     Function: Geom::CData::Constructor
@@ -667,7 +718,7 @@ get_current_thread() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_primitive_type
 //     Function: GeomPipelineReader::get_primitive_type
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomPipelineReader::PrimitiveType GeomPipelineReader::
 INLINE GeomPipelineReader::PrimitiveType GeomPipelineReader::
 get_primitive_type() const {
 get_primitive_type() const {
@@ -677,7 +728,7 @@ get_primitive_type() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_shade_model
 //     Function: GeomPipelineReader::get_shade_model
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomPipelineReader::ShadeModel GeomPipelineReader::
 INLINE GeomPipelineReader::ShadeModel GeomPipelineReader::
 get_shade_model() const {
 get_shade_model() const {
@@ -687,7 +738,7 @@ get_shade_model() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_geom_rendering
 //     Function: GeomPipelineReader::get_geom_rendering
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int GeomPipelineReader::
 INLINE int GeomPipelineReader::
 get_geom_rendering() const {
 get_geom_rendering() const {
@@ -697,7 +748,7 @@ get_geom_rendering() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_usage_hint
 //     Function: GeomPipelineReader::get_usage_hint
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomPipelineReader::UsageHint GeomPipelineReader::
 INLINE GeomPipelineReader::UsageHint GeomPipelineReader::
 get_usage_hint() const {
 get_usage_hint() const {
@@ -708,7 +759,7 @@ get_usage_hint() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_vertex_data
 //     Function: GeomPipelineReader::get_vertex_data
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(GeomVertexData) GeomPipelineReader::
 INLINE CPT(GeomVertexData) GeomPipelineReader::
 get_vertex_data() const {
 get_vertex_data() const {
@@ -718,7 +769,7 @@ get_vertex_data() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_num_primitives
 //     Function: GeomPipelineReader::get_num_primitives
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int GeomPipelineReader::
 INLINE int GeomPipelineReader::
 get_num_primitives() const {
 get_num_primitives() const {
@@ -728,7 +779,7 @@ get_num_primitives() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_primitive
 //     Function: GeomPipelineReader::get_primitive
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(GeomPrimitive) GeomPipelineReader::
 INLINE CPT(GeomPrimitive) GeomPipelineReader::
 get_primitive(int i) const {
 get_primitive(int i) const {
@@ -739,7 +790,7 @@ get_primitive(int i) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPipelineReader::get_modified
 //     Function: GeomPipelineReader::get_modified
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq GeomPipelineReader::
 INLINE UpdateSeq GeomPipelineReader::
 get_modified() const {
 get_modified() const {

+ 23 - 15
panda/src/gobj/geom.h

@@ -142,24 +142,24 @@ PUBLISHED:
   bool release(PreparedGraphicsObjects *prepared_objects);
   bool release(PreparedGraphicsObjects *prepared_objects);
   int release_all();
   int release_all();
 
 
-  GeomContext *prepare_now(PreparedGraphicsObjects *prepared_objects, 
+  GeomContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                            GraphicsStateGuardianBase *gsg);
                            GraphicsStateGuardianBase *gsg);
 
 
 public:
 public:
-  bool draw(GraphicsStateGuardianBase *gsg, 
+  bool draw(GraphicsStateGuardianBase *gsg,
             const GeomMunger *munger,
             const GeomMunger *munger,
             const GeomVertexData *vertex_data,
             const GeomVertexData *vertex_data,
             bool force, Thread *current_thread) const;
             bool force, Thread *current_thread) const;
-  
+
   INLINE void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
   INLINE void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                                bool &found_any, 
+                                bool &found_any,
                                 const GeomVertexData *vertex_data,
                                 const GeomVertexData *vertex_data,
                                 bool got_mat, const LMatrix4 &mat,
                                 bool got_mat, const LMatrix4 &mat,
                                 Thread *current_thread) const;
                                 Thread *current_thread) const;
   INLINE void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
   INLINE void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
                                 bool &found_any, Thread *current_thread) const;
                                 bool &found_any, Thread *current_thread) const;
   INLINE void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
   INLINE void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                                bool &found_any, 
+                                bool &found_any,
                                 const GeomVertexData *vertex_data,
                                 const GeomVertexData *vertex_data,
                                 bool got_mat, const LMatrix4 &mat,
                                 bool got_mat, const LMatrix4 &mat,
                                 const InternalName *column_name,
                                 const InternalName *column_name,
@@ -174,7 +174,7 @@ private:
   void compute_internal_bounds(CData *cdata, Thread *current_thread) const;
   void compute_internal_bounds(CData *cdata, Thread *current_thread) const;
 
 
   void do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
   void do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                            bool &found_any, 
+                            bool &found_any,
                             const GeomVertexData *vertex_data,
                             const GeomVertexData *vertex_data,
                             bool got_mat, const LMatrix4 &mat,
                             bool got_mat, const LMatrix4 &mat,
                             const InternalName *column_name,
                             const InternalName *column_name,
@@ -220,7 +220,7 @@ private:
     Geom *_source;  // A back pointer to the containing Geom
     Geom *_source;  // A back pointer to the containing Geom
     const Geom *_geom_result;  // ref-counted if not NULL and not same as _source
     const Geom *_geom_result;  // ref-counted if not NULL and not same as _source
     CPT(GeomVertexData) _data_result;
     CPT(GeomVertexData) _data_result;
-    
+
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
@@ -228,7 +228,7 @@ private:
     static void init_type() {
     static void init_type() {
       register_type(_type_handle, "Geom::CDataCache");
       register_type(_type_handle, "Geom::CDataCache");
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
@@ -245,6 +245,10 @@ public:
   public:
   public:
     INLINE CacheKey(const GeomVertexData *source_data,
     INLINE CacheKey(const GeomVertexData *source_data,
                     const GeomMunger *modifier);
                     const GeomMunger *modifier);
+    INLINE CacheKey(const CacheKey &copy);
+#ifdef USE_MOVE_SEMANTICS
+    INLINE CacheKey(CacheKey &&from) NOEXCEPT;
+#endif
     INLINE bool operator < (const CacheKey &other) const;
     INLINE bool operator < (const CacheKey &other) const;
 
 
     CPT(GeomVertexData) _source_data;
     CPT(GeomVertexData) _source_data;
@@ -253,9 +257,13 @@ public:
   // It is not clear why MSVC7 needs this class to be public.
   // It is not clear why MSVC7 needs this class to be public.
   class CacheEntry : public GeomCacheEntry {
   class CacheEntry : public GeomCacheEntry {
   public:
   public:
-    INLINE CacheEntry(Geom *source, 
+    INLINE CacheEntry(Geom *source,
                       const GeomVertexData *source_data,
                       const GeomVertexData *source_data,
                       const GeomMunger *modifier);
                       const GeomMunger *modifier);
+    INLINE CacheEntry(Geom *source, const CacheKey &key);
+#ifdef USE_MOVE_SEMANTICS
+    INLINE CacheEntry(Geom *source, CacheKey &&key) NOEXCEPT;
+#endif
     ALLOC_DELETED_CHAIN(CacheEntry);
     ALLOC_DELETED_CHAIN(CacheEntry);
 
 
     virtual void evict_callback();
     virtual void evict_callback();
@@ -265,7 +273,7 @@ public:
     CacheKey _key;
     CacheKey _key;
 
 
     PipelineCycler<CDataCache> _cycler;
     PipelineCycler<CDataCache> _cycler;
-    
+
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
@@ -275,7 +283,7 @@ public:
       register_type(_type_handle, "Geom::CacheEntry",
       register_type(_type_handle, "Geom::CacheEntry",
                     GeomCacheEntry::get_class_type());
                     GeomCacheEntry::get_class_type());
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
@@ -304,13 +312,13 @@ private:
     UsageHint _usage_hint;
     UsageHint _usage_hint;
     bool _got_usage_hint;
     bool _got_usage_hint;
     UpdateSeq _modified;
     UpdateSeq _modified;
-  
+
     CPT(BoundingVolume) _internal_bounds;
     CPT(BoundingVolume) _internal_bounds;
     int _nested_vertices;
     int _nested_vertices;
     bool _internal_bounds_stale;
     bool _internal_bounds_stale;
     BoundingVolume::BoundsType _bounds_type;
     BoundingVolume::BoundsType _bounds_type;
     CPT(BoundingVolume) _user_bounds;
     CPT(BoundingVolume) _user_bounds;
-    
+
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
@@ -318,11 +326,11 @@ private:
     static void init_type() {
     static void init_type() {
       register_type(_type_handle, "Geom::CData");
       register_type(_type_handle, "Geom::CData");
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
- 
+
   PipelineCycler<CData> _cycler;
   PipelineCycler<CData> _cycler;
   typedef CycleDataLockedReader<CData> CDLockedReader;
   typedef CycleDataLockedReader<CData> CDLockedReader;
   typedef CycleDataReader<CData> CDReader;
   typedef CycleDataReader<CData> CDReader;

+ 23 - 19
panda/src/gobj/geomMunger.cxx

@@ -27,7 +27,7 @@ PStatCollector GeomMunger::_munge_pcollector("*:Munge");
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::Constructor
 //     Function: GeomMunger::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomMunger::
 GeomMunger::
 GeomMunger(GraphicsStateGuardianBase *gsg) :
 GeomMunger(GraphicsStateGuardianBase *gsg) :
@@ -44,7 +44,7 @@ GeomMunger(GraphicsStateGuardianBase *gsg) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::Copy Constructor
 //     Function: GeomMunger::Copy Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomMunger::
 GeomMunger::
 GeomMunger(const GeomMunger &copy) :
 GeomMunger(const GeomMunger &copy) :
@@ -60,7 +60,7 @@ GeomMunger(const GeomMunger &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::Copy Assignment Operator
 //     Function: GeomMunger::Copy Assignment Operator
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomMunger::
 void GeomMunger::
 operator = (const GeomMunger &copy) {
 operator = (const GeomMunger &copy) {
@@ -70,7 +70,7 @@ operator = (const GeomMunger &copy) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::Destructor
 //     Function: GeomMunger::Destructor
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomMunger::
 GeomMunger::
 ~GeomMunger() {
 ~GeomMunger() {
@@ -96,7 +96,7 @@ remove_data(const GeomVertexData *data) {
 //       Access: Public
 //       Access: Public
 //  Description: Applies the indicated munger to the geom and its
 //  Description: Applies the indicated munger to the geom and its
 //               data, and returns a (possibly different) geom and
 //               data, and returns a (possibly different) geom and
-//               data, according to the munger's whim.  
+//               data, according to the munger's whim.
 //
 //
 //               The assumption is that for a particular geom and a
 //               The assumption is that for a particular geom and a
 //               particular munger, the result will always be the
 //               particular munger, the result will always be the
@@ -110,13 +110,12 @@ remove_data(const GeomVertexData *data) {
 bool GeomMunger::
 bool GeomMunger::
 munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
 munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
            bool force, Thread *current_thread) {
            bool force, Thread *current_thread) {
-  CPT(GeomVertexData) source_data = data;
 
 
   // Look up the munger in the geom's cache--maybe we've recently
   // Look up the munger in the geom's cache--maybe we've recently
   // applied it.
   // applied it.
   PT(Geom::CacheEntry) entry;
   PT(Geom::CacheEntry) entry;
 
 
-  Geom::CacheKey key(source_data, this);
+  Geom::CacheKey key(data, this);
 
 
   geom->_cache_lock.acquire();
   geom->_cache_lock.acquire();
   Geom::Cache::const_iterator ci = geom->_cache.find(&key);
   Geom::Cache::const_iterator ci = geom->_cache.find(&key);
@@ -126,12 +125,12 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
     entry = (*ci).second;
     entry = (*ci).second;
     geom->_cache_lock.release();
     geom->_cache_lock.release();
     nassertr(entry->_source == geom, false);
     nassertr(entry->_source == geom, false);
-    
+
     // Here's an element in the cache for this computation.  Record a
     // Here's an element in the cache for this computation.  Record a
     // cache hit, so this element will stay in the cache a while
     // cache hit, so this element will stay in the cache a while
     // longer.
     // longer.
     entry->refresh(current_thread);
     entry->refresh(current_thread);
-    
+
     // Now check that it's fresh.
     // Now check that it's fresh.
     Geom::CDCacheReader cdata(entry->_cycler, current_thread);
     Geom::CDCacheReader cdata(entry->_cycler, current_thread);
     if (cdata->_source == geom &&
     if (cdata->_source == geom &&
@@ -139,12 +138,12 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
         geom->get_modified(current_thread) <= cdata->_geom_result->get_modified(current_thread) &&
         geom->get_modified(current_thread) <= cdata->_geom_result->get_modified(current_thread) &&
         data->get_modified(current_thread) <= cdata->_data_result->get_modified(current_thread)) {
         data->get_modified(current_thread) <= cdata->_data_result->get_modified(current_thread)) {
       // The cache entry is still good; use it.
       // The cache entry is still good; use it.
-      
+
       geom = cdata->_geom_result;
       geom = cdata->_geom_result;
       data = cdata->_data_result;
       data = cdata->_data_result;
       return true;
       return true;
     }
     }
-    
+
     // The cache entry is stale, but we'll recompute it below.  Note
     // The cache entry is stale, but we'll recompute it below.  Note
     // that there's a small race condition here; another thread might
     // that there's a small race condition here; another thread might
     // recompute the cache at the same time.  No big deal, since it'll
     // recompute the cache at the same time.  No big deal, since it'll
@@ -166,7 +165,12 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
   // Record the new result in the cache.
   // Record the new result in the cache.
   if (entry == (Geom::CacheEntry *)NULL) {
   if (entry == (Geom::CacheEntry *)NULL) {
     // Create a new entry for the result.
     // Create a new entry for the result.
-    entry = new Geom::CacheEntry(orig_geom, source_data, this);
+#ifdef USE_MOVE_SEMANTICS
+    // We don't need the key anymore, move the pointers into the CacheEntry.
+    entry = new Geom::CacheEntry(orig_geom, move(key));
+#else
+    entry = new Geom::CacheEntry(orig_geom, key);
+#endif
     {
     {
       LightMutexHolder holder(orig_geom->_cache_lock);
       LightMutexHolder holder(orig_geom->_cache_lock);
       bool inserted = orig_geom->_cache.insert(Geom::Cache::value_type(&entry->_key, entry)).second;
       bool inserted = orig_geom->_cache.insert(Geom::Cache::value_type(&entry->_key, entry)).second;
@@ -176,7 +180,7 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
         return true;
         return true;
       }
       }
     }
     }
-  
+
     // And tell the cache manager about the new entry.  (It might
     // And tell the cache manager about the new entry.  (It might
     // immediately request a delete from the cache of the thing we
     // immediately request a delete from the cache of the thing we
     // just added.)
     // just added.)
@@ -198,7 +202,7 @@ munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data,
 //               exists just to cast away the const pointer.
 //               exists just to cast away the const pointer.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(GeomVertexFormat) GeomMunger::
 CPT(GeomVertexFormat) GeomMunger::
-do_munge_format(const GeomVertexFormat *format, 
+do_munge_format(const GeomVertexFormat *format,
                 const GeomVertexAnimationSpec &animation) {
                 const GeomVertexAnimationSpec &animation) {
   nassertr(_is_registered, NULL);
   nassertr(_is_registered, NULL);
   nassertr(format->is_registered(), NULL);
   nassertr(format->is_registered(), NULL);
@@ -248,7 +252,7 @@ munge_data_impl(const GeomVertexData *data) {
   nassertr(_is_registered, NULL);
   nassertr(_is_registered, NULL);
 
 
   CPT(GeomVertexFormat) orig_format = data->get_format();
   CPT(GeomVertexFormat) orig_format = data->get_format();
-  CPT(GeomVertexFormat) new_format = 
+  CPT(GeomVertexFormat) new_format =
     munge_format(orig_format, orig_format->get_animation());
     munge_format(orig_format, orig_format->get_animation());
 
 
   if (new_format == orig_format) {
   if (new_format == orig_format) {
@@ -384,7 +388,7 @@ make_registry() {
     _registry = new Registry;
     _registry = new Registry;
   }
   }
 }
 }
- 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::do_register
 //     Function: GeomMunger::do_register
 //       Access: Private
 //       Access: Private
@@ -408,7 +412,7 @@ do_register(Thread *current_thread) {
 
 
   _is_registered = true;
   _is_registered = true;
 }
 }
- 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::do_unregister
 //     Function: GeomMunger::do_unregister
 //       Access: Private
 //       Access: Private
@@ -430,7 +434,7 @@ do_unregister() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::CacheEntry::output
 //     Function: GeomMunger::CacheEntry::output
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomMunger::CacheEntry::
 void GeomMunger::CacheEntry::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -440,7 +444,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomMunger::Registry::Constructor
 //     Function: GeomMunger::Registry::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomMunger::Registry::
 GeomMunger::Registry::
 Registry() {
 Registry() {

+ 77 - 27
panda/src/gobj/geomVertexData.I

@@ -414,7 +414,7 @@ INLINE int GeomVertexData::
 add_transform(TransformTable *table, const VertexTransform *transform,
 add_transform(TransformTable *table, const VertexTransform *transform,
               TransformMap &already_added) {
               TransformMap &already_added) {
   pair<TransformMap::iterator, bool> result = already_added.insert(TransformMap::value_type(transform, table->get_num_transforms()));
   pair<TransformMap::iterator, bool> result = already_added.insert(TransformMap::value_type(transform, table->get_num_transforms()));
-  
+
   if (result.second) {
   if (result.second) {
     table->add_transform(transform);
     table->add_transform(transform);
   }
   }
@@ -425,7 +425,7 @@ add_transform(TransformTable *table, const VertexTransform *transform,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::CDataCache::Constructor
 //     Function: GeomVertexData::CDataCache::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexData::CDataCache::
 INLINE GeomVertexData::CDataCache::
 CDataCache() {
 CDataCache() {
@@ -434,7 +434,7 @@ CDataCache() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::CDataCache::Copy Constructor
 //     Function: GeomVertexData::CDataCache::Copy Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexData::CDataCache::
 INLINE GeomVertexData::CDataCache::
 CDataCache(const GeomVertexData::CDataCache &copy) :
 CDataCache(const GeomVertexData::CDataCache &copy) :
@@ -445,7 +445,7 @@ CDataCache(const GeomVertexData::CDataCache &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::CacheKey::Constructor
 //     Function: GeomVertexData::CacheKey::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexData::CacheKey::
 INLINE GeomVertexData::CacheKey::
 CacheKey(const GeomVertexFormat *modifier) :
 CacheKey(const GeomVertexFormat *modifier) :
@@ -453,6 +453,30 @@ CacheKey(const GeomVertexFormat *modifier) :
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::CacheKey::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomVertexData::CacheKey::
+CacheKey(const CacheKey &copy) :
+  _modifier(copy._modifier)
+{
+}
+
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::CacheKey::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomVertexData::CacheKey::
+CacheKey(CacheKey &&from) NOEXCEPT :
+  _modifier(move(from._modifier))
+{
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::CacheKey::operator <
 //     Function: GeomVertexData::CacheKey::operator <
 //       Access: Public
 //       Access: Public
@@ -466,7 +490,7 @@ operator < (const CacheKey &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::CacheEntry::Constructor
 //     Function: GeomVertexData::CacheEntry::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexData::CacheEntry::
 INLINE GeomVertexData::CacheEntry::
 CacheEntry(GeomVertexData *source, const GeomVertexFormat *modifier) :
 CacheEntry(GeomVertexData *source, const GeomVertexFormat *modifier) :
@@ -475,6 +499,32 @@ CacheEntry(GeomVertexData *source, const GeomVertexFormat *modifier) :
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::CacheEntry::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomVertexData::CacheEntry::
+CacheEntry(GeomVertexData *source, const CacheKey &key) :
+  _source(source),
+  _key(key)
+{
+}
+
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::CacheEntry::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomVertexData::CacheEntry::
+CacheEntry(GeomVertexData *source, CacheKey &&key) NOEXCEPT :
+  _source(source),
+  _key(move(key))
+{
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::CData::Constructor
 //     Function: GeomVertexData::CData::Constructor
 //       Access: Public
 //       Access: Public
@@ -511,7 +561,7 @@ CData(const GeomVertexData::CData &copy) :
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexDataPipelineBase::
 INLINE GeomVertexDataPipelineBase::
-GeomVertexDataPipelineBase(GeomVertexData *object, 
+GeomVertexDataPipelineBase(GeomVertexData *object,
                            Thread *current_thread,
                            Thread *current_thread,
                            GeomVertexData::CData *cdata) :
                            GeomVertexData::CData *cdata) :
   _object(object),
   _object(object),
@@ -560,7 +610,7 @@ get_current_thread() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_usage_hint
 //     Function: GeomVertexDataPipelineBase::get_usage_hint
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexDataPipelineBase::UsageHint GeomVertexDataPipelineBase::
 INLINE GeomVertexDataPipelineBase::UsageHint GeomVertexDataPipelineBase::
 get_usage_hint() const {
 get_usage_hint() const {
@@ -570,7 +620,7 @@ get_usage_hint() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_format
 //     Function: GeomVertexDataPipelineBase::get_format
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const GeomVertexFormat *GeomVertexDataPipelineBase::
 INLINE const GeomVertexFormat *GeomVertexDataPipelineBase::
 get_format() const {
 get_format() const {
@@ -580,7 +630,7 @@ get_format() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::has_column
 //     Function: GeomVertexDataPipelineBase::has_column
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexDataPipelineBase::
 INLINE bool GeomVertexDataPipelineBase::
 has_column(const InternalName *name) const {
 has_column(const InternalName *name) const {
@@ -590,7 +640,7 @@ has_column(const InternalName *name) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_num_arrays
 //     Function: GeomVertexDataPipelineBase::get_num_arrays
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int GeomVertexDataPipelineBase::
 INLINE int GeomVertexDataPipelineBase::
 get_num_arrays() const {
 get_num_arrays() const {
@@ -600,7 +650,7 @@ get_num_arrays() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_array
 //     Function: GeomVertexDataPipelineBase::get_array
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(GeomVertexArrayData) GeomVertexDataPipelineBase::
 INLINE CPT(GeomVertexArrayData) GeomVertexDataPipelineBase::
 get_array(int i) const {
 get_array(int i) const {
@@ -611,7 +661,7 @@ get_array(int i) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_transform_table
 //     Function: GeomVertexDataPipelineBase::get_transform_table
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const TransformTable *GeomVertexDataPipelineBase::
 INLINE const TransformTable *GeomVertexDataPipelineBase::
 get_transform_table() const {
 get_transform_table() const {
@@ -621,7 +671,7 @@ get_transform_table() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_transform_blend_table
 //     Function: GeomVertexDataPipelineBase::get_transform_blend_table
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformBlendTable) GeomVertexDataPipelineBase::
 INLINE CPT(TransformBlendTable) GeomVertexDataPipelineBase::
 get_transform_blend_table() const {
 get_transform_blend_table() const {
@@ -631,7 +681,7 @@ get_transform_blend_table() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_slider_table
 //     Function: GeomVertexDataPipelineBase::get_slider_table
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const SliderTable *GeomVertexDataPipelineBase::
 INLINE const SliderTable *GeomVertexDataPipelineBase::
 get_slider_table() const {
 get_slider_table() const {
@@ -641,7 +691,7 @@ get_slider_table() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_modified
 //     Function: GeomVertexDataPipelineBase::get_modified
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq GeomVertexDataPipelineBase::
 INLINE UpdateSeq GeomVertexDataPipelineBase::
 get_modified() const {
 get_modified() const {
@@ -654,7 +704,7 @@ get_modified() const {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexDataPipelineReader::
 INLINE GeomVertexDataPipelineReader::
-GeomVertexDataPipelineReader(const GeomVertexData *object, 
+GeomVertexDataPipelineReader(const GeomVertexData *object,
                              Thread *current_thread) :
                              Thread *current_thread) :
   GeomVertexDataPipelineBase((GeomVertexData *)object, current_thread,
   GeomVertexDataPipelineBase((GeomVertexData *)object, current_thread,
                              (GeomVertexData::CData *)object->_cycler.read_unlocked(current_thread)),
                              (GeomVertexData::CData *)object->_cycler.read_unlocked(current_thread)),
@@ -668,7 +718,7 @@ GeomVertexDataPipelineReader(const GeomVertexData *object,
 //  Description: Don't attempt to copy these objects.
 //  Description: Don't attempt to copy these objects.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexDataPipelineReader::
 INLINE GeomVertexDataPipelineReader::
-GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader &copy) : 
+GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader &copy) :
   GeomVertexDataPipelineBase(copy)
   GeomVertexDataPipelineBase(copy)
 {
 {
   nassertv(false);
   nassertv(false);
@@ -710,7 +760,7 @@ get_object() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::check_array_readers
 //     Function: GeomVertexDataPipelineReader::check_array_readers
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomVertexDataPipelineReader::
 INLINE void GeomVertexDataPipelineReader::
 check_array_readers() const {
 check_array_readers() const {
@@ -722,7 +772,7 @@ check_array_readers() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::get_array_reader
 //     Function: GeomVertexDataPipelineReader::get_array_reader
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const GeomVertexArrayDataHandle *GeomVertexDataPipelineReader::
 INLINE const GeomVertexArrayDataHandle *GeomVertexDataPipelineReader::
 get_array_reader(int i) const {
 get_array_reader(int i) const {
@@ -734,7 +784,7 @@ get_array_reader(int i) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::has_vertex
 //     Function: GeomVertexDataPipelineReader::has_vertex
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexDataPipelineReader::
 INLINE bool GeomVertexDataPipelineReader::
 has_vertex() const {
 has_vertex() const {
@@ -744,7 +794,7 @@ has_vertex() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::is_vertex_transformed
 //     Function: GeomVertexDataPipelineReader::is_vertex_transformed
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexDataPipelineReader::
 INLINE bool GeomVertexDataPipelineReader::
 is_vertex_transformed() const {
 is_vertex_transformed() const {
@@ -759,7 +809,7 @@ is_vertex_transformed() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::has_normal
 //     Function: GeomVertexDataPipelineReader::has_normal
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexDataPipelineReader::
 INLINE bool GeomVertexDataPipelineReader::
 has_normal() const {
 has_normal() const {
@@ -769,7 +819,7 @@ has_normal() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::has_color
 //     Function: GeomVertexDataPipelineReader::has_color
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexDataPipelineReader::
 INLINE bool GeomVertexDataPipelineReader::
 has_color() const {
 has_color() const {
@@ -782,7 +832,7 @@ has_color() const {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexDataPipelineWriter::
 INLINE GeomVertexDataPipelineWriter::
-GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0, 
+GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0,
                              Thread *current_thread) :
                              Thread *current_thread) :
   GeomVertexDataPipelineBase(object, current_thread,
   GeomVertexDataPipelineBase(object, current_thread,
                              object->_cycler.write_upstream(force_to_0, current_thread)),
                              object->_cycler.write_upstream(force_to_0, current_thread)),
@@ -803,7 +853,7 @@ GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0,
 //  Description: Don't attempt to copy these objects.
 //  Description: Don't attempt to copy these objects.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexDataPipelineWriter::
 INLINE GeomVertexDataPipelineWriter::
-GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter &copy) : 
+GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter &copy) :
   GeomVertexDataPipelineBase(copy)
   GeomVertexDataPipelineBase(copy)
 {
 {
   nassertv(false);
   nassertv(false);
@@ -845,7 +895,7 @@ get_object() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::check_array_writers
 //     Function: GeomVertexDataPipelineWriter::check_array_writers
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomVertexDataPipelineWriter::
 INLINE void GeomVertexDataPipelineWriter::
 check_array_writers() const {
 check_array_writers() const {
@@ -857,7 +907,7 @@ check_array_writers() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::get_array_writer
 //     Function: GeomVertexDataPipelineWriter::get_array_writer
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomVertexArrayDataHandle *GeomVertexDataPipelineWriter::
 INLINE GeomVertexArrayDataHandle *GeomVertexDataPipelineWriter::
 get_array_writer(int i) const {
 get_array_writer(int i) const {

+ 108 - 104
panda/src/gobj/geomVertexData.cxx

@@ -64,7 +64,7 @@ make_cow_copy() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::Constructor
 //     Function: GeomVertexData::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexData::
 GeomVertexData::
 GeomVertexData(const string &name,
 GeomVertexData(const string &name,
@@ -97,7 +97,7 @@ GeomVertexData(const string &name,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::Copy Constructor
 //     Function: GeomVertexData::Copy Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexData::
 GeomVertexData::
 GeomVertexData(const GeomVertexData &copy) :
 GeomVertexData(const GeomVertexData &copy) :
@@ -127,7 +127,7 @@ GeomVertexData(const GeomVertexData &copy) :
 //               and it allows you to specify a different format.
 //               and it allows you to specify a different format.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexData::
 GeomVertexData::
-GeomVertexData(const GeomVertexData &copy, 
+GeomVertexData(const GeomVertexData &copy,
                const GeomVertexFormat *format) :
                const GeomVertexFormat *format) :
   CopyOnWriteObject(copy),
   CopyOnWriteObject(copy),
   _name(copy._name),
   _name(copy._name),
@@ -159,7 +159,7 @@ GeomVertexData(const GeomVertexData &copy,
   }
   }
   CLOSE_ITERATE_ALL_STAGES(_cycler);
   CLOSE_ITERATE_ALL_STAGES(_cycler);
 }
 }
-  
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::Copy Assignment Operator
 //     Function: GeomVertexData::Copy Assignment Operator
 //       Access: Published
 //       Access: Published
@@ -186,14 +186,14 @@ operator = (const GeomVertexData &copy) {
     cdata->_modified = Geom::get_next_modified();
     cdata->_modified = Geom::get_next_modified();
     cdata->_animated_vertices = NULL;
     cdata->_animated_vertices = NULL;
     cdata->_animated_vertices_modified = UpdateSeq();
     cdata->_animated_vertices_modified = UpdateSeq();
-  } 
+  }
   CLOSE_ITERATE_ALL_STAGES(_cycler);
   CLOSE_ITERATE_ALL_STAGES(_cycler);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::Destructor
 //     Function: GeomVertexData::Destructor
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexData::
 GeomVertexData::
 ~GeomVertexData() {
 ~GeomVertexData() {
@@ -564,22 +564,22 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
   pset<int> done_arrays;
   pset<int> done_arrays;
 
 
   for (source_i = 0; source_i < num_arrays; ++source_i) {
   for (source_i = 0; source_i < num_arrays; ++source_i) {
-    const GeomVertexArrayFormat *source_array_format = 
+    const GeomVertexArrayFormat *source_array_format =
       source_format->get_array(source_i);
       source_format->get_array(source_i);
 
 
     bool array_done = false;
     bool array_done = false;
 
 
     int dest_num_arrays = dest_format->get_num_arrays();
     int dest_num_arrays = dest_format->get_num_arrays();
-    for (int dest_i = 0; 
-         dest_i < dest_num_arrays && !array_done; 
+    for (int dest_i = 0;
+         dest_i < dest_num_arrays && !array_done;
          ++dest_i) {
          ++dest_i) {
-      const GeomVertexArrayFormat *dest_array_format = 
+      const GeomVertexArrayFormat *dest_array_format =
         dest_format->get_array(dest_i);
         dest_format->get_array(dest_i);
       if (dest_array_format->is_data_subset_of(*source_array_format)) {
       if (dest_array_format->is_data_subset_of(*source_array_format)) {
         // Great!  Just use the same data for this one.
         // Great!  Just use the same data for this one.
         if (keep_data_objects) {
         if (keep_data_objects) {
-          // Copy the data, but keep the same GeomVertexArrayData object.  
-          
+          // Copy the data, but keep the same GeomVertexArrayData object.
+
           PT(GeomVertexArrayData) dest_data = modify_array(dest_i);
           PT(GeomVertexArrayData) dest_data = modify_array(dest_i);
           CPT(GeomVertexArrayData) source_data = source->get_array(source_i);
           CPT(GeomVertexArrayData) source_data = source->get_array(source_i);
           dest_data->modify_handle()->copy_data_from(source_data->get_handle());
           dest_data->modify_handle()->copy_data_from(source_data->get_handle());
@@ -613,9 +613,9 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
       int dest_i = dest_format->get_array_with(source_column->get_name());
       int dest_i = dest_format->get_array_with(source_column->get_name());
       if (dest_i >= 0 && done_arrays.count(dest_i) == 0) {
       if (dest_i >= 0 && done_arrays.count(dest_i) == 0) {
         // The data type exists in the new format; we have to copy it.
         // The data type exists in the new format; we have to copy it.
-        const GeomVertexArrayFormat *dest_array_format = 
+        const GeomVertexArrayFormat *dest_array_format =
           dest_format->get_array(dest_i);
           dest_format->get_array(dest_i);
-        const GeomVertexColumn *dest_column = 
+        const GeomVertexColumn *dest_column =
           dest_array_format->get_column(source_column->get_name());
           dest_array_format->get_column(source_column->get_name());
         nassertv(dest_column != (const GeomVertexColumn *)NULL);
         nassertv(dest_column != (const GeomVertexColumn *)NULL);
 
 
@@ -625,12 +625,12 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
           PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
           PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
 
-          bytewise_copy(dest_array_data + dest_column->get_start(), 
+          bytewise_copy(dest_array_data + dest_column->get_start(),
                         dest_array_format->get_stride(),
                         dest_array_format->get_stride(),
                         array_data + source_column->get_start(), source_array_format->get_stride(),
                         array_data + source_column->get_start(), source_array_format->get_stride(),
                         source_column, num_rows);
                         source_column, num_rows);
 
 
-        } else if (dest_column->is_packed_argb() && 
+        } else if (dest_column->is_packed_argb() &&
                    source_column->is_uint8_rgba()) {
                    source_column->is_uint8_rgba()) {
           // A common special case: OpenGL color to DirectX color.
           // A common special case: OpenGL color to DirectX color.
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
@@ -638,12 +638,12 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
 
           uint8_rgba_to_packed_argb
           uint8_rgba_to_packed_argb
-            (dest_array_data + dest_column->get_start(), 
+            (dest_array_data + dest_column->get_start(),
              dest_array_format->get_stride(),
              dest_array_format->get_stride(),
              array_data + source_column->get_start(), source_array_format->get_stride(),
              array_data + source_column->get_start(), source_array_format->get_stride(),
              num_rows);
              num_rows);
 
 
-        } else if (dest_column->is_uint8_rgba() && 
+        } else if (dest_column->is_uint8_rgba() &&
                    source_column->is_packed_argb()) {
                    source_column->is_packed_argb()) {
           // Another common special case: DirectX color to OpenGL
           // Another common special case: DirectX color to OpenGL
           // color.
           // color.
@@ -652,7 +652,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
 
           packed_argb_to_uint8_rgba
           packed_argb_to_uint8_rgba
-            (dest_array_data + dest_column->get_start(), 
+            (dest_array_data + dest_column->get_start(),
              dest_array_format->get_stride(),
              dest_array_format->get_stride(),
              array_data + source_column->get_start(), source_array_format->get_stride(),
              array_data + source_column->get_start(), source_array_format->get_stride(),
              num_rows);
              num_rows);
@@ -661,7 +661,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
           // A generic copy.
           // A generic copy.
           if (gobj_cat.is_debug()) {
           if (gobj_cat.is_debug()) {
             gobj_cat.debug()
             gobj_cat.debug()
-              << "generic copy " << *dest_column << " from " 
+              << "generic copy " << *dest_column << " from "
               << *source_column << "\n";
               << *source_column << "\n";
           }
           }
           GeomVertexWriter to(this);
           GeomVertexWriter to(this);
@@ -695,13 +695,13 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
           GeomVertexWriter weight(this, InternalName::get_transform_weight());
           GeomVertexWriter weight(this, InternalName::get_transform_weight());
           GeomVertexWriter index(this, InternalName::get_transform_index());
           GeomVertexWriter index(this, InternalName::get_transform_index());
           GeomVertexReader from(source, InternalName::get_transform_blend());
           GeomVertexReader from(source, InternalName::get_transform_blend());
-        
+
           while (!from.is_at_end()) {
           while (!from.is_at_end()) {
             const TransformBlend &blend = blend_table->get_blend(from.get_data1i());
             const TransformBlend &blend = blend_table->get_blend(from.get_data1i());
             LVecBase4 weights = LVecBase4::zero();
             LVecBase4 weights = LVecBase4::zero();
             LVecBase4i indices(0, 0, 0, 0);
             LVecBase4i indices(0, 0, 0, 0);
             nassertv(blend.get_num_transforms() <= 4);
             nassertv(blend.get_num_transforms() <= 4);
-            
+
             for (int i = 0; i < blend.get_num_transforms(); i++) {
             for (int i = 0; i < blend.get_num_transforms(); i++) {
               weights[i] = blend.get_weight(i);
               weights[i] = blend.get_weight(i);
               indices[i] = add_transform(transform_table, blend.get_transform(i),
               indices[i] = add_transform(transform_table, blend.get_transform(i),
@@ -717,11 +717,11 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
           // use the same n transforms, in the same order, for each vertex.
           // use the same n transforms, in the same order, for each vertex.
           GeomVertexWriter weight(this, InternalName::get_transform_weight());
           GeomVertexWriter weight(this, InternalName::get_transform_weight());
           GeomVertexReader from(source, InternalName::get_transform_blend());
           GeomVertexReader from(source, InternalName::get_transform_blend());
-        
+
           while (!from.is_at_end()) {
           while (!from.is_at_end()) {
             const TransformBlend &blend = blend_table->get_blend(from.get_data1i());
             const TransformBlend &blend = blend_table->get_blend(from.get_data1i());
             LVecBase4 weights = LVecBase4::zero();
             LVecBase4 weights = LVecBase4::zero();
-            
+
             for (int i = 0; i < blend.get_num_transforms(); i++) {
             for (int i = 0; i < blend.get_num_transforms(); i++) {
               int index = add_transform(transform_table, blend.get_transform(i),
               int index = add_transform(transform_table, blend.get_transform(i),
                                         already_added);
                                         already_added);
@@ -733,7 +733,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
             }
             }
           }
           }
         }
         }
-        
+
         clear_transform_blend_table();
         clear_transform_blend_table();
         set_transform_table(TransformTable::register_table(transform_table));
         set_transform_table(TransformTable::register_table(transform_table));
       }
       }
@@ -754,7 +754,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
 //               have recently made in an upstream thread.
 //               have recently made in an upstream thread.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
-copy_row_from(int dest_row, const GeomVertexData *source, 
+copy_row_from(int dest_row, const GeomVertexData *source,
               int source_row, Thread *current_thread) {
               int source_row, Thread *current_thread) {
   const GeomVertexFormat *source_format = source->get_format();
   const GeomVertexFormat *source_format = source->get_format();
   const GeomVertexFormat *dest_format = get_format();
   const GeomVertexFormat *dest_format = get_format();
@@ -842,7 +842,7 @@ convert_to(const GeomVertexFormat *new_format) const {
   }
   }
   PStatTimer timer(_convert_pcollector);
   PStatTimer timer(_convert_pcollector);
 
 
-  PT(GeomVertexData) new_data = 
+  PT(GeomVertexData) new_data =
     new GeomVertexData(get_name(), new_format, get_usage_hint());
     new GeomVertexData(get_name(), new_format, get_usage_hint());
   new_data->set_transform_blend_table(get_transform_blend_table());
   new_data->set_transform_blend_table(get_transform_blend_table());
   new_data->set_slider_table(get_slider_table());
   new_data->set_slider_table(get_slider_table());
@@ -852,7 +852,12 @@ convert_to(const GeomVertexFormat *new_format) const {
   // Record the new result in the cache.
   // Record the new result in the cache.
   if (entry == (CacheEntry *)NULL) {
   if (entry == (CacheEntry *)NULL) {
     // Create a new entry for the result.
     // Create a new entry for the result.
-    entry = new CacheEntry((GeomVertexData *)this, new_format);
+#ifdef USE_MOVE_SEMANTICS
+    // We don't need the key anymore, move the pointers into the CacheEntry.
+    entry = new CacheEntry((GeomVertexData *)this, move(key));
+#else
+    entry = new CacheEntry((GeomVertexData *)this, key);
+#endif
     {
     {
       LightMutexHolder holder(_cache_lock);
       LightMutexHolder holder(_cache_lock);
       bool inserted = ((GeomVertexData *)this)->_cache.insert(Cache::value_type(&entry->_key, entry)).second;
       bool inserted = ((GeomVertexData *)this)->_cache.insert(Cache::value_type(&entry->_key, entry)).second;
@@ -862,7 +867,7 @@ convert_to(const GeomVertexFormat *new_format) const {
         return new_data;
         return new_data;
       }
       }
     }
     }
-    
+
     // And tell the cache manager about the new entry.  (It might
     // And tell the cache manager about the new entry.  (It might
     // immediately request a delete from the cache of the thing we
     // immediately request a delete from the cache of the thing we
     // just added.)
     // just added.)
@@ -876,7 +881,6 @@ convert_to(const GeomVertexFormat *new_format) const {
   return new_data;
   return new_data;
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::scale_color
 //     Function: GeomVertexData::scale_color
 //       Access: Published
 //       Access: Published
@@ -888,7 +892,7 @@ convert_to(const GeomVertexFormat *new_format) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(GeomVertexData) GeomVertexData::
 CPT(GeomVertexData) GeomVertexData::
 scale_color(const LVecBase4 &color_scale) const {
 scale_color(const LVecBase4 &color_scale) const {
-  const GeomVertexColumn *old_column = 
+  const GeomVertexColumn *old_column =
     get_format()->get_column(InternalName::get_color());
     get_format()->get_column(InternalName::get_color());
   if (old_column == (GeomVertexColumn *)NULL) {
   if (old_column == (GeomVertexColumn *)NULL) {
     return this;
     return this;
@@ -965,7 +969,7 @@ scale_color(const LVecBase4 &color_scale, int num_components,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(GeomVertexData) GeomVertexData::
 CPT(GeomVertexData) GeomVertexData::
 set_color(const LColor &color) const {
 set_color(const LColor &color) const {
-  const GeomVertexColumn *old_column = 
+  const GeomVertexColumn *old_column =
     get_format()->get_column(InternalName::get_color());
     get_format()->get_column(InternalName::get_color());
   if (old_column == (GeomVertexColumn *)NULL) {
   if (old_column == (GeomVertexColumn *)NULL) {
     return this;
     return this;
@@ -1026,7 +1030,7 @@ set_color(const LColor &color, int num_components,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(GeomVertexData) GeomVertexData::
 CPT(GeomVertexData) GeomVertexData::
 reverse_normals() const {
 reverse_normals() const {
-  const GeomVertexColumn *old_column = 
+  const GeomVertexColumn *old_column =
     get_format()->get_column(InternalName::get_normal());
     get_format()->get_column(InternalName::get_normal());
   if (old_column == (GeomVertexColumn *)NULL) {
   if (old_column == (GeomVertexColumn *)NULL) {
     return this;
     return this;
@@ -1094,16 +1098,16 @@ animate_vertices(bool force, Thread *current_thread) const {
     PStatTimer timer2(((GeomVertexData *)this)->_blends_pcollector, current_thread);
     PStatTimer timer2(((GeomVertexData *)this)->_blends_pcollector, current_thread);
     if (!cdata->_transform_blend_table.is_null()) {
     if (!cdata->_transform_blend_table.is_null()) {
       if (cdata->_slider_table != (SliderTable *)NULL) {
       if (cdata->_slider_table != (SliderTable *)NULL) {
-        modified = 
+        modified =
           max(cdata->_transform_blend_table.get_read_pointer()->get_modified(current_thread),
           max(cdata->_transform_blend_table.get_read_pointer()->get_modified(current_thread),
               cdata->_slider_table->get_modified(current_thread));
               cdata->_slider_table->get_modified(current_thread));
       } else {
       } else {
         modified = cdata->_transform_blend_table.get_read_pointer()->get_modified(current_thread);
         modified = cdata->_transform_blend_table.get_read_pointer()->get_modified(current_thread);
       }
       }
-      
+
     } else if (cdata->_slider_table != (SliderTable *)NULL) {
     } else if (cdata->_slider_table != (SliderTable *)NULL) {
       modified = cdata->_slider_table->get_modified(current_thread);
       modified = cdata->_slider_table->get_modified(current_thread);
-      
+
     } else {
     } else {
       // No transform blend table or slider table--ergo, no vertex
       // No transform blend table or slider table--ergo, no vertex
       // animation.
       // animation.
@@ -1185,7 +1189,7 @@ transform_vertices(const LMatrix4 &mat, int begin_row, int end_row) {
     GeomVertexRewriter data(this, format->get_point(ci));
     GeomVertexRewriter data(this, format->get_point(ci));
     do_transform_point_column(format, data, mat, begin_row, end_row);
     do_transform_point_column(format, data, mat, begin_row, end_row);
   }
   }
-  
+
   for (ci = 0; ci < format->get_num_vectors(); ci++) {
   for (ci = 0; ci < format->get_num_vectors(); ci++) {
     GeomVertexRewriter data(this, format->get_vector(ci));
     GeomVertexRewriter data(this, format->get_vector(ci));
     do_transform_vector_column(format, data, mat, begin_row, end_row);
     do_transform_vector_column(format, data, mat, begin_row, end_row);
@@ -1208,7 +1212,7 @@ bytewise_copy(unsigned char *to, int to_stride,
       << ", " << (const void *)from << ", " << from_stride
       << ", " << (const void *)from << ", " << from_stride
       << ", " << *from_type << ", " << num_records << ")\n";
       << ", " << *from_type << ", " << num_records << ")\n";
   }
   }
-  if (to_stride == from_type->get_total_bytes() && 
+  if (to_stride == from_type->get_total_bytes() &&
       from_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.
     // Fantastic!  It's just a linear array of this one data type.
     // Copy the whole thing all at once.
     // Copy the whole thing all at once.
@@ -1257,32 +1261,32 @@ replace_column(InternalName *name, int num_components,
       // just drop the whole array.
       // just drop the whole array.
       new_format->remove_array(old_type_array);
       new_format->remove_array(old_type_array);
       removed_type_array = true;
       removed_type_array = true;
-      
+
     } else {
     } else {
       // Remove the description for the type, but don't bother to
       // Remove the description for the type, but don't bother to
       // repack the array.
       // repack the array.
       array_format->remove_column(name);
       array_format->remove_column(name);
     }
     }
   }
   }
-    
+
   // Now define a new array to contain just the type.
   // Now define a new array to contain just the type.
   int new_type_array = -1;
   int new_type_array = -1;
   if (num_components != 0) {
   if (num_components != 0) {
-    PT(GeomVertexArrayFormat) type_array_format = 
+    PT(GeomVertexArrayFormat) type_array_format =
       new GeomVertexArrayFormat(name, num_components, numeric_type, contents);
       new GeomVertexArrayFormat(name, num_components, numeric_type, contents);
     new_type_array = new_format->add_array(type_array_format);
     new_type_array = new_format->add_array(type_array_format);
   }
   }
 
 
-  CPT(GeomVertexFormat) format = 
+  CPT(GeomVertexFormat) format =
     GeomVertexFormat::register_format(new_format);
     GeomVertexFormat::register_format(new_format);
 
 
   if (gobj_cat.is_debug()) {
   if (gobj_cat.is_debug()) {
     gobj_cat.debug()
     gobj_cat.debug()
       << "Replacing data type " << *name << "; converting "
       << "Replacing data type " << *name << "; converting "
-      << get_num_rows() << " rows from " 
+      << get_num_rows() << " rows from "
       << *cdata->_format << " to " << *format << "\n";
       << *cdata->_format << " to " << *format << "\n";
   }
   }
-  
+
   PT(GeomVertexData) new_data = new GeomVertexData(*this, format);
   PT(GeomVertexData) new_data = new GeomVertexData(*this, format);
 
 
   int j = 0;
   int j = 0;
@@ -1320,7 +1324,7 @@ replace_column(InternalName *name, int num_components,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::output
 //     Function: GeomVertexData::output
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -1333,7 +1337,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::write
 //     Function: GeomVertexData::write
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
@@ -1369,16 +1373,16 @@ describe_vertex(ostream &out, int row) const {
   if (format->get_animation().get_animation_type() == AT_panda) {
   if (format->get_animation().get_animation_type() == AT_panda) {
     tb_table = get_transform_blend_table();
     tb_table = get_transform_blend_table();
   }
   }
-  
+
   int num_columns = format->get_num_columns();
   int num_columns = format->get_num_columns();
   for (int ci = 0; ci < num_columns; ++ci) {
   for (int ci = 0; ci < num_columns; ++ci) {
     int ai = format->get_array_with(ci);
     int ai = format->get_array_with(ci);
     const GeomVertexColumn *column = format->get_column(ci);
     const GeomVertexColumn *column = format->get_column(ci);
     reader.set_column(ai, column);
     reader.set_column(ai, column);
-    
+
     int num_values = min(column->get_num_values(), 4);
     int num_values = min(column->get_num_values(), 4);
     const LVecBase4 &d = reader.get_data4();
     const LVecBase4 &d = reader.get_data4();
-    
+
     out << "  " << *column->get_name();
     out << "  " << *column->get_name();
     for (int v = 0; v < num_values; v++) {
     for (int v = 0; v < num_values; v++) {
       out << " " << d[v];
       out << " " << d[v];
@@ -1545,7 +1549,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
 
 
   if (cdata->_animated_vertices == (GeomVertexData *)NULL) {
   if (cdata->_animated_vertices == (GeomVertexData *)NULL) {
     new_format = orig_format->get_post_animated_format();
     new_format = orig_format->get_post_animated_format();
-    cdata->_animated_vertices = 
+    cdata->_animated_vertices =
       new GeomVertexData(get_name(), new_format,
       new GeomVertexData(get_name(), new_format,
                          min(get_usage_hint(), UH_dynamic));
                          min(get_usage_hint(), UH_dynamic));
   }
   }
@@ -1670,7 +1674,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
 
 
     CPT(GeomVertexArrayFormat) blend_array_format = orig_format->get_array(blend_array_index);
     CPT(GeomVertexArrayFormat) blend_array_format = orig_format->get_array(blend_array_index);
 
 
-    if (blend_array_format->get_stride() == 2 && 
+    if (blend_array_format->get_stride() == 2 &&
         blend_array_format->get_column(0)->get_component_bytes() == 2) {
         blend_array_format->get_column(0)->get_component_bytes() == 2) {
       // The blend indices are a table of ushorts.  Optimize this
       // The blend indices are a table of ushorts.  Optimize this
       // common case.
       // common case.
@@ -1688,11 +1692,11 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
 
 
           int first_vertex = begin;
           int first_vertex = begin;
           int first_bi = blendt[first_vertex];
           int first_bi = blendt[first_vertex];
-          
+
           while (first_vertex < end) {
           while (first_vertex < end) {
             // At this point, first_vertex is the first of a series of
             // At this point, first_vertex is the first of a series of
             // vertices that shares the blend index first_bi.
             // vertices that shares the blend index first_bi.
-            
+
             // Scan for the end of this series of vertices--we're
             // Scan for the end of this series of vertices--we're
             // looking for the next vertex with a different blend index.
             // looking for the next vertex with a different blend index.
             int next_vertex = first_vertex;
             int next_vertex = first_vertex;
@@ -1705,13 +1709,13 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
               }
               }
               ++next_vertex;
               ++next_vertex;
             }
             }
-            
+
             // We've just reached the end of the vertices with a matching
             // We've just reached the end of the vertices with a matching
             // blend index.  Transform all those vertices as a block.
             // blend index.  Transform all those vertices as a block.
             LMatrix4 mat;
             LMatrix4 mat;
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             new_data->do_transform_point_column(new_format, data, mat, first_vertex, next_vertex);
             new_data->do_transform_point_column(new_format, data, mat, first_vertex, next_vertex);
-            
+
             first_vertex = next_vertex;
             first_vertex = next_vertex;
             first_bi = next_bi;
             first_bi = next_bi;
           }
           }
@@ -1728,11 +1732,11 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
 
 
           int first_vertex = begin;
           int first_vertex = begin;
           int first_bi = blendt[first_vertex];
           int first_bi = blendt[first_vertex];
-          
+
           while (first_vertex < end) {
           while (first_vertex < end) {
             // At this point, first_vertex is the first of a series of
             // At this point, first_vertex is the first of a series of
             // vertices that shares the blend index first_bi.
             // vertices that shares the blend index first_bi.
-            
+
             // Scan for the end of this series of vertices--we're
             // Scan for the end of this series of vertices--we're
             // looking for the next vertex with a different blend index.
             // looking for the next vertex with a different blend index.
             int next_vertex = first_vertex;
             int next_vertex = first_vertex;
@@ -1745,13 +1749,13 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
               }
               }
               ++next_vertex;
               ++next_vertex;
             }
             }
-            
+
             // We've just reached the end of the vertices with a matching
             // We've just reached the end of the vertices with a matching
             // blend index.  Transform all those vertices as a block.
             // blend index.  Transform all those vertices as a block.
             LMatrix4 mat;
             LMatrix4 mat;
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             new_data->do_transform_vector_column(new_format, data, mat, first_vertex, next_vertex);
             new_data->do_transform_vector_column(new_format, data, mat, first_vertex, next_vertex);
-            
+
             first_vertex = next_vertex;
             first_vertex = next_vertex;
             first_bi = next_bi;
             first_bi = next_bi;
           }
           }
@@ -1773,14 +1777,14 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
           int end = rows.get_subrange_end(i);
           int end = rows.get_subrange_end(i);
           nassertv(begin < end);
           nassertv(begin < end);
           blendi.set_row_unsafe(begin);
           blendi.set_row_unsafe(begin);
-          
+
           int first_vertex = begin;
           int first_vertex = begin;
           int first_bi = blendi.get_data1i();
           int first_bi = blendi.get_data1i();
-          
+
           while (first_vertex < end) {
           while (first_vertex < end) {
             // At this point, first_vertex is the first of a series of
             // At this point, first_vertex is the first of a series of
             // vertices that shares the blend index first_bi.
             // vertices that shares the blend index first_bi.
-            
+
             // Scan for the end of this series of vertices--we're
             // Scan for the end of this series of vertices--we're
             // looking for the next vertex with a different blend index.
             // looking for the next vertex with a different blend index.
             int next_vertex = first_vertex;
             int next_vertex = first_vertex;
@@ -1793,13 +1797,13 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
               }
               }
               ++next_vertex;
               ++next_vertex;
             }
             }
-            
+
             // We've just reached the end of the vertices with a matching
             // We've just reached the end of the vertices with a matching
             // blend index.  Transform all those vertices as a block.
             // blend index.  Transform all those vertices as a block.
             LMatrix4 mat;
             LMatrix4 mat;
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             new_data->do_transform_point_column(new_format, data, mat, first_vertex, next_vertex);
             new_data->do_transform_point_column(new_format, data, mat, first_vertex, next_vertex);
-            
+
             first_vertex = next_vertex;
             first_vertex = next_vertex;
             first_bi = next_bi;
             first_bi = next_bi;
           }
           }
@@ -1814,14 +1818,14 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
           int end = rows.get_subrange_end(i);
           int end = rows.get_subrange_end(i);
           nassertv(begin != end);
           nassertv(begin != end);
           blendi.set_row_unsafe(begin);
           blendi.set_row_unsafe(begin);
-          
+
           int first_vertex = begin;
           int first_vertex = begin;
           int first_bi = blendi.get_data1i();
           int first_bi = blendi.get_data1i();
-          
+
           while (first_vertex < end) {
           while (first_vertex < end) {
             // At this point, first_vertex is the first of a series of
             // At this point, first_vertex is the first of a series of
             // vertices that shares the blend index first_bi.
             // vertices that shares the blend index first_bi.
-            
+
             // Scan for the end of this series of vertices--we're
             // Scan for the end of this series of vertices--we're
             // looking for the next vertex with a different blend index.
             // looking for the next vertex with a different blend index.
             int next_vertex = first_vertex;
             int next_vertex = first_vertex;
@@ -1834,13 +1838,13 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
               }
               }
               ++next_vertex;
               ++next_vertex;
             }
             }
-            
+
             // We've just reached the end of the vertices with a matching
             // We've just reached the end of the vertices with a matching
             // blend index.  Transform all those vertices as a block.
             // blend index.  Transform all those vertices as a block.
             LMatrix4 mat;
             LMatrix4 mat;
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             tb_table->get_blend(first_bi).get_blend(mat, current_thread);
             new_data->do_transform_vector_column(new_format, data, mat, first_vertex, next_vertex);
             new_data->do_transform_vector_column(new_format, data, mat, first_vertex, next_vertex);
-            
+
             first_vertex = next_vertex;
             first_vertex = next_vertex;
             first_bi = next_bi;
             first_bi = next_bi;
           }
           }
@@ -1880,11 +1884,11 @@ do_transform_point_column(const GeomVertexFormat *format, GeomVertexRewriter &da
     } else {
     } else {
       table_xform_vecbase4f(datat, num_rows, stride, matf);
       table_xform_vecbase4f(datat, num_rows, stride, matf);
     }
     }
-    
+
   } else if (num_values == 4) {
   } else if (num_values == 4) {
     // Use the GeomVertexRewriter to adjust the 4-component
     // Use the GeomVertexRewriter to adjust the 4-component
     // points.
     // points.
-  
+
     data.set_row_unsafe(begin_row);
     data.set_row_unsafe(begin_row);
     for (int j = begin_row; j < end_row; ++j) {
     for (int j = begin_row; j < end_row; ++j) {
       LPoint4 vertex = data.get_data4();
       LPoint4 vertex = data.get_data4();
@@ -2110,7 +2114,7 @@ finalize(BamReader *manager) {
   CDWriter cdata(_cycler, true);
   CDWriter cdata(_cycler, true);
 
 
   for (size_t i = 0; i < cdata->_arrays.size(); ++i) {
   for (size_t i = 0; i < cdata->_arrays.size(); ++i) {
-    CPT(GeomVertexFormat) new_format = 
+    CPT(GeomVertexFormat) new_format =
       GeomVertexFormat::register_format(cdata->_format);
       GeomVertexFormat::register_format(cdata->_format);
     manager->change_pointer(cdata->_format, new_format);
     manager->change_pointer(cdata->_format, new_format);
     cdata->_format = new_format;
     cdata->_format = new_format;
@@ -2124,14 +2128,14 @@ finalize(BamReader *manager) {
   }
   }
 
 
   if (cdata->_transform_table != (TransformTable *)NULL) {
   if (cdata->_transform_table != (TransformTable *)NULL) {
-    CPT(TransformTable) new_transform_table = 
+    CPT(TransformTable) new_transform_table =
       TransformTable::register_table(cdata->_transform_table);
       TransformTable::register_table(cdata->_transform_table);
     manager->change_pointer(cdata->_transform_table, new_transform_table);
     manager->change_pointer(cdata->_transform_table, new_transform_table);
     cdata->_transform_table = new_transform_table;
     cdata->_transform_table = new_transform_table;
   }
   }
 
 
   if (cdata->_slider_table != (SliderTable *)NULL) {
   if (cdata->_slider_table != (SliderTable *)NULL) {
-    CPT(SliderTable) new_slider_table = 
+    CPT(SliderTable) new_slider_table =
       SliderTable::register_table(cdata->_slider_table);
       SliderTable::register_table(cdata->_slider_table);
     manager->change_pointer(cdata->_slider_table, new_slider_table);
     manager->change_pointer(cdata->_slider_table, new_slider_table);
     cdata->_slider_table = new_slider_table;
     cdata->_slider_table = new_slider_table;
@@ -2181,11 +2185,11 @@ evict_callback() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::CacheEntry::output
 //     Function: GeomVertexData::CacheEntry::output
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::CacheEntry::
 void GeomVertexData::CacheEntry::
 output(ostream &out) const {
 output(ostream &out) const {
-  out << "vertex data " << (void *)_source << " to " 
+  out << "vertex data " << (void *)_source << " to "
       << *_key._modifier;
       << *_key._modifier;
 }
 }
 
 
@@ -2236,7 +2240,7 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
 
 
   Arrays::iterator ai;
   Arrays::iterator ai;
   for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
   for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
-    (*ai) = DCAST(GeomVertexArrayData, p_list[pi++]);    
+    (*ai) = DCAST(GeomVertexArrayData, p_list[pi++]);
   }
   }
 
 
   _transform_table = DCAST(TransformTable, p_list[pi++]);
   _transform_table = DCAST(TransformTable, p_list[pi++]);
@@ -2295,7 +2299,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineBase::get_num_bytes
 //     Function: GeomVertexDataPipelineBase::get_num_bytes
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomVertexDataPipelineBase::
 int GeomVertexDataPipelineBase::
 get_num_bytes() const {
 get_num_bytes() const {
@@ -2312,7 +2316,7 @@ get_num_bytes() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::get_num_rows
 //     Function: GeomVertexDataPipelineReader::get_num_rows
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomVertexDataPipelineReader::
 int GeomVertexDataPipelineReader::
 get_num_rows() const {
 get_num_rows() const {
@@ -2332,13 +2336,13 @@ get_num_rows() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::get_array_info
 //     Function: GeomVertexDataPipelineReader::get_array_info
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
-get_array_info(const InternalName *name, 
+get_array_info(const InternalName *name,
                const GeomVertexArrayDataHandle *&array_reader,
                const GeomVertexArrayDataHandle *&array_reader,
-               int &num_values, 
-               GeomVertexDataPipelineReader::NumericType &numeric_type, 
+               int &num_values,
+               GeomVertexDataPipelineReader::NumericType &numeric_type,
                int &start, int &stride) const {
                int &start, int &stride) const {
   nassertr(_got_array_readers, false);
   nassertr(_got_array_readers, false);
   int array_index;
   int array_index;
@@ -2357,12 +2361,12 @@ get_array_info(const InternalName *name,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::get_vertex_info
 //     Function: GeomVertexDataPipelineReader::get_vertex_info
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
 get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,
 get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,
-                int &num_values, 
-                GeomVertexDataPipelineReader::NumericType &numeric_type, 
+                int &num_values,
+                GeomVertexDataPipelineReader::NumericType &numeric_type,
                 int &start, int &stride) const {
                 int &start, int &stride) const {
   nassertr(_got_array_readers, false);
   nassertr(_got_array_readers, false);
   int array_index = _cdata->_format->get_vertex_array_index();
   int array_index = _cdata->_format->get_vertex_array_index();
@@ -2382,11 +2386,11 @@ get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::get_normal_info
 //     Function: GeomVertexDataPipelineReader::get_normal_info
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
 get_normal_info(const GeomVertexArrayDataHandle *&array_reader,
 get_normal_info(const GeomVertexArrayDataHandle *&array_reader,
-                GeomVertexDataPipelineReader::NumericType &numeric_type, 
+                GeomVertexDataPipelineReader::NumericType &numeric_type,
                 int &start, int &stride) const {
                 int &start, int &stride) const {
   nassertr(_got_array_readers, false);
   nassertr(_got_array_readers, false);
   int array_index = _cdata->_format->get_normal_array_index();
   int array_index = _cdata->_format->get_normal_array_index();
@@ -2405,12 +2409,12 @@ get_normal_info(const GeomVertexArrayDataHandle *&array_reader,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::get_color_info
 //     Function: GeomVertexDataPipelineReader::get_color_info
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
 get_color_info(const GeomVertexArrayDataHandle *&array_reader,
 get_color_info(const GeomVertexArrayDataHandle *&array_reader,
-               int &num_values, 
-               GeomVertexDataPipelineReader::NumericType &numeric_type, 
+               int &num_values,
+               GeomVertexDataPipelineReader::NumericType &numeric_type,
                int &start, int &stride) const {
                int &start, int &stride) const {
   nassertr(_got_array_readers, false);
   nassertr(_got_array_readers, false);
   int array_index = _cdata->_format->get_color_array_index();
   int array_index = _cdata->_format->get_color_array_index();
@@ -2430,7 +2434,7 @@ get_color_info(const GeomVertexArrayDataHandle *&array_reader,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::make_array_readers
 //     Function: GeomVertexDataPipelineReader::make_array_readers
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexDataPipelineReader::
 void GeomVertexDataPipelineReader::
 make_array_readers() {
 make_array_readers() {
@@ -2449,7 +2453,7 @@ make_array_readers() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::delete_array_readers
 //     Function: GeomVertexDataPipelineReader::delete_array_readers
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexDataPipelineReader::
 void GeomVertexDataPipelineReader::
 delete_array_readers() {
 delete_array_readers() {
@@ -2462,7 +2466,7 @@ delete_array_readers() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::get_num_rows
 //     Function: GeomVertexDataPipelineWriter::get_num_rows
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomVertexDataPipelineWriter::
 int GeomVertexDataPipelineWriter::
 get_num_rows() const {
 get_num_rows() const {
@@ -2482,7 +2486,7 @@ get_num_rows() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::set_num_rows
 //     Function: GeomVertexDataPipelineWriter::set_num_rows
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineWriter::
 bool GeomVertexDataPipelineWriter::
 set_num_rows(int n) {
 set_num_rows(int n) {
@@ -2510,10 +2514,10 @@ set_num_rows(int n) {
     // (1, 1, 1, 1), for the programmer's convenience.
     // (1, 1, 1, 1), for the programmer's convenience.
     GeomVertexArrayDataHandle *array_writer = _array_writers[color_array];
     GeomVertexArrayDataHandle *array_writer = _array_writers[color_array];
     const GeomVertexArrayFormat *array_format = array_writer->get_array_format();
     const GeomVertexArrayFormat *array_format = array_writer->get_array_format();
-    const GeomVertexColumn *column = 
+    const GeomVertexColumn *column =
       array_format->get_column(InternalName::get_color());
       array_format->get_column(InternalName::get_color());
     int stride = array_format->get_stride();
     int stride = array_format->get_stride();
-    unsigned char *start = 
+    unsigned char *start =
       array_writer->get_write_pointer() + column->get_start();
       array_writer->get_write_pointer() + column->get_start();
     unsigned char *stop = start + array_writer->get_data_size_bytes();
     unsigned char *stop = start + array_writer->get_data_size_bytes();
     unsigned char *pointer = start + stride * orig_color_rows;
     unsigned char *pointer = start + stride * orig_color_rows;
@@ -2554,7 +2558,7 @@ set_num_rows(int n) {
     case NT_stdfloat:
     case NT_stdfloat:
       // Shouldn't have this type in the format.
       // Shouldn't have this type in the format.
       nassertr(false, false);
       nassertr(false, false);
-    }          
+    }
   }
   }
 
 
   if (any_changed) {
   if (any_changed) {
@@ -2569,7 +2573,7 @@ set_num_rows(int n) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::unclean_set_num_rows
 //     Function: GeomVertexDataPipelineWriter::unclean_set_num_rows
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineWriter::
 bool GeomVertexDataPipelineWriter::
 unclean_set_num_rows(int n) {
 unclean_set_num_rows(int n) {
@@ -2598,7 +2602,7 @@ unclean_set_num_rows(int n) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::reserve_num_rows
 //     Function: GeomVertexDataPipelineWriter::reserve_num_rows
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineWriter::
 bool GeomVertexDataPipelineWriter::
 reserve_num_rows(int n) {
 reserve_num_rows(int n) {
@@ -2619,7 +2623,7 @@ reserve_num_rows(int n) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::modify_array
 //     Function: GeomVertexDataPipelineWriter::modify_array
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GeomVertexArrayData) GeomVertexDataPipelineWriter::
 PT(GeomVertexArrayData) GeomVertexDataPipelineWriter::
 modify_array(int i) {
 modify_array(int i) {
@@ -2642,7 +2646,7 @@ modify_array(int i) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::set_array
 //     Function: GeomVertexDataPipelineWriter::set_array
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexDataPipelineWriter::
 void GeomVertexDataPipelineWriter::
 set_array(int i, const GeomVertexArrayData *array) {
 set_array(int i, const GeomVertexArrayData *array) {
@@ -2660,7 +2664,7 @@ set_array(int i, const GeomVertexArrayData *array) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::make_array_writers
 //     Function: GeomVertexDataPipelineWriter::make_array_writers
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexDataPipelineWriter::
 void GeomVertexDataPipelineWriter::
 make_array_writers() {
 make_array_writers() {
@@ -2683,7 +2687,7 @@ make_array_writers() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineWriter::delete_array_writers
 //     Function: GeomVertexDataPipelineWriter::delete_array_writers
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexDataPipelineWriter::
 void GeomVertexDataPipelineWriter::
 delete_array_writers() {
 delete_array_writers() {

+ 33 - 24
panda/src/gobj/geomVertexData.h

@@ -78,10 +78,10 @@ private:
   GeomVertexData();
   GeomVertexData();
 protected:
 protected:
   virtual PT(CopyOnWriteObject) make_cow_copy();
   virtual PT(CopyOnWriteObject) make_cow_copy();
-  
+
 PUBLISHED:
 PUBLISHED:
   GeomVertexData(const string &name,
   GeomVertexData(const string &name,
-                 const GeomVertexFormat *format, 
+                 const GeomVertexFormat *format,
                  UsageHint usage_hint);
                  UsageHint usage_hint);
   GeomVertexData(const GeomVertexData &copy);
   GeomVertexData(const GeomVertexData &copy);
   GeomVertexData(const GeomVertexData &copy,
   GeomVertexData(const GeomVertexData &copy,
@@ -136,17 +136,17 @@ PUBLISHED:
 
 
   void copy_from(const GeomVertexData *source, bool keep_data_objects,
   void copy_from(const GeomVertexData *source, bool keep_data_objects,
                  Thread *current_thread = Thread::get_current_thread());
                  Thread *current_thread = Thread::get_current_thread());
-  void copy_row_from(int dest_row, const GeomVertexData *source, 
+  void copy_row_from(int dest_row, const GeomVertexData *source,
                      int source_row, Thread *current_thread);
                      int source_row, Thread *current_thread);
   CPT(GeomVertexData) convert_to(const GeomVertexFormat *new_format) const;
   CPT(GeomVertexData) convert_to(const GeomVertexFormat *new_format) const;
-  CPT(GeomVertexData) 
+  CPT(GeomVertexData)
     scale_color(const LVecBase4 &color_scale) const;
     scale_color(const LVecBase4 &color_scale) const;
-  CPT(GeomVertexData) 
+  CPT(GeomVertexData)
     scale_color(const LVecBase4 &color_scale, int num_components,
     scale_color(const LVecBase4 &color_scale, int num_components,
                 NumericType numeric_type, Contents contents) const;
                 NumericType numeric_type, Contents contents) const;
-  CPT(GeomVertexData) 
+  CPT(GeomVertexData)
     set_color(const LColor &color) const;
     set_color(const LColor &color) const;
-  CPT(GeomVertexData) 
+  CPT(GeomVertexData)
     set_color(const LColor &color, int num_components,
     set_color(const LColor &color, int num_components,
               NumericType numeric_type, Contents contents) const;
               NumericType numeric_type, Contents contents) const;
 
 
@@ -157,7 +157,7 @@ PUBLISHED:
   void transform_vertices(const LMatrix4 &mat);
   void transform_vertices(const LMatrix4 &mat);
   void transform_vertices(const LMatrix4 &mat, int begin_row, int end_row);
   void transform_vertices(const LMatrix4 &mat, int begin_row, int end_row);
 
 
-  PT(GeomVertexData) 
+  PT(GeomVertexData)
     replace_column(InternalName *name, int num_components,
     replace_column(InternalName *name, int num_components,
                    NumericType numeric_type, Contents contents) const;
                    NumericType numeric_type, Contents contents) const;
 
 
@@ -191,7 +191,7 @@ private:
                             int num_records);
                             int num_records);
 
 
   typedef pmap<const VertexTransform *, int> TransformMap;
   typedef pmap<const VertexTransform *, int> TransformMap;
-  INLINE static int 
+  INLINE static int
   add_transform(TransformTable *table, const VertexTransform *transform,
   add_transform(TransformTable *table, const VertexTransform *transform,
                 TransformMap &already_added);
                 TransformMap &already_added);
 
 
@@ -212,7 +212,7 @@ private:
     }
     }
 
 
     CPT(GeomVertexData) _result;
     CPT(GeomVertexData) _result;
-    
+
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
@@ -220,7 +220,7 @@ private:
     static void init_type() {
     static void init_type() {
       register_type(_type_handle, "GeomVertexData::CDataCache");
       register_type(_type_handle, "GeomVertexData::CDataCache");
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
@@ -236,15 +236,24 @@ public:
   class EXPCL_PANDA_GOBJ CacheKey {
   class EXPCL_PANDA_GOBJ CacheKey {
   public:
   public:
     INLINE CacheKey(const GeomVertexFormat *modifier);
     INLINE CacheKey(const GeomVertexFormat *modifier);
+    INLINE CacheKey(const CacheKey &copy);
+#ifdef USE_MOVE_SEMANTICS
+    INLINE CacheKey(CacheKey &&from) NOEXCEPT;
+#endif
+
     INLINE bool operator < (const CacheKey &other) const;
     INLINE bool operator < (const CacheKey &other) const;
 
 
     CPT(GeomVertexFormat) _modifier;
     CPT(GeomVertexFormat) _modifier;
   };
   };
-  // It is not clear why MSVC7 needs this class to be public.  
+  // It is not clear why MSVC7 needs this class to be public.
   class EXPCL_PANDA_GOBJ CacheEntry : public GeomCacheEntry {
   class EXPCL_PANDA_GOBJ CacheEntry : public GeomCacheEntry {
   public:
   public:
     INLINE CacheEntry(GeomVertexData *source,
     INLINE CacheEntry(GeomVertexData *source,
                       const GeomVertexFormat *modifier);
                       const GeomVertexFormat *modifier);
+    INLINE CacheEntry(GeomVertexData *source, const CacheKey &key);
+#ifdef USE_MOVE_SEMANTICS
+    INLINE CacheEntry(GeomVertexData *source, CacheKey &&key) NOEXCEPT;
+#endif
     ALLOC_DELETED_CHAIN(CacheEntry);
     ALLOC_DELETED_CHAIN(CacheEntry);
 
 
     virtual void evict_callback();
     virtual void evict_callback();
@@ -254,7 +263,7 @@ public:
     CacheKey _key;
     CacheKey _key;
 
 
     PipelineCycler<CDataCache> _cycler;
     PipelineCycler<CDataCache> _cycler;
-    
+
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
@@ -264,7 +273,7 @@ public:
       register_type(_type_handle, "GeomVertexData::CacheEntry",
       register_type(_type_handle, "GeomVertexData::CacheEntry",
                     GeomCacheEntry::get_class_type());
                     GeomCacheEntry::get_class_type());
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
@@ -294,7 +303,7 @@ private:
     PT(GeomVertexData) _animated_vertices;
     PT(GeomVertexData) _animated_vertices;
     UpdateSeq _animated_vertices_modified;
     UpdateSeq _animated_vertices_modified;
     UpdateSeq _modified;
     UpdateSeq _modified;
-    
+
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
@@ -302,7 +311,7 @@ private:
     static void init_type() {
     static void init_type() {
       register_type(_type_handle, "GeomVertexData::CData");
       register_type(_type_handle, "GeomVertexData::CData");
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
@@ -323,11 +332,11 @@ private:
                                  const LMatrix4 &mat, int begin_row, int end_row);
                                  const LMatrix4 &mat, int begin_row, int end_row);
   void do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
   void do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
                                   const LMatrix4 &mat, int begin_row, int end_row);
                                   const LMatrix4 &mat, int begin_row, int end_row);
-  static void table_xform_point3f(unsigned char *datat, size_t num_rows, 
+  static void table_xform_point3f(unsigned char *datat, size_t num_rows,
                                   size_t stride, const LMatrix4f &matf);
                                   size_t stride, const LMatrix4f &matf);
-  static void table_xform_vector3f(unsigned char *datat, size_t num_rows, 
+  static void table_xform_vector3f(unsigned char *datat, size_t num_rows,
                                    size_t stride, const LMatrix4f &matf);
                                    size_t stride, const LMatrix4f &matf);
-  static void table_xform_vecbase4f(unsigned char *datat, size_t num_rows, 
+  static void table_xform_vecbase4f(unsigned char *datat, size_t num_rows,
                                     size_t stride, const LMatrix4f &matf);
                                     size_t stride, const LMatrix4f &matf);
 
 
   static PStatCollector _convert_pcollector;
   static PStatCollector _convert_pcollector;
@@ -386,7 +395,7 @@ private:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_GOBJ GeomVertexDataPipelineBase : public GeomEnums {
 class EXPCL_PANDA_GOBJ GeomVertexDataPipelineBase : public GeomEnums {
 protected:
 protected:
-  INLINE GeomVertexDataPipelineBase(GeomVertexData *object, 
+  INLINE GeomVertexDataPipelineBase(GeomVertexData *object,
                                     Thread *current_thread,
                                     Thread *current_thread,
                                     GeomVertexData::CData *cdata);
                                     GeomVertexData::CData *cdata);
 
 
@@ -436,15 +445,15 @@ public:
   INLINE const GeomVertexArrayDataHandle *get_array_reader(int i) const;
   INLINE const GeomVertexArrayDataHandle *get_array_reader(int i) const;
   int get_num_rows() const;
   int get_num_rows() const;
 
 
-  bool get_array_info(const InternalName *name, 
+  bool get_array_info(const InternalName *name,
                       const GeomVertexArrayDataHandle *&array_reader,
                       const GeomVertexArrayDataHandle *&array_reader,
-                      int &num_values, NumericType &numeric_type, 
+                      int &num_values, NumericType &numeric_type,
                       int &start, int &stride) const;
                       int &start, int &stride) const;
 
 
   INLINE bool has_vertex() const;
   INLINE bool has_vertex() const;
   INLINE bool is_vertex_transformed() const;
   INLINE bool is_vertex_transformed() const;
   bool get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,
   bool get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,
-                       int &num_values, NumericType &numeric_type, 
+                       int &num_values, NumericType &numeric_type,
                        int &start, int &stride) const;
                        int &start, int &stride) const;
 
 
   INLINE bool has_normal() const;
   INLINE bool has_normal() const;
@@ -454,7 +463,7 @@ public:
 
 
   INLINE bool has_color() const;
   INLINE bool has_color() const;
   bool get_color_info(const GeomVertexArrayDataHandle *&array_reader,
   bool get_color_info(const GeomVertexArrayDataHandle *&array_reader,
-                      int &num_values, NumericType &numeric_type, 
+                      int &num_values, NumericType &numeric_type,
                       int &start, int &stride) const;
                       int &start, int &stride) const;
 
 
 private:
 private:

+ 12 - 1
panda/src/linmath/lmatrix3_src.I

@@ -385,6 +385,17 @@ is_nan() const {
     cnan(_m(2, 0)) || cnan(_m(2, 1)) || cnan(_m(2, 2));
     cnan(_m(2, 0)) || cnan(_m(2, 1)) || cnan(_m(2, 2));
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: LMatrix3::is_identity
+//       Access: Public
+//  Description: Returns true if this is (close enough to) the
+//               identity matrix, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH bool FLOATNAME(LMatrix3)::
+is_identity() const {
+  return almost_equal(ident_mat(), NEARLY_ZERO(FLOATTYPE));
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LMatrix3::get_cell
 //     Function: LMatrix3::get_cell
 //       Access: Published
 //       Access: Published
@@ -504,7 +515,7 @@ operator == (const FLOATNAME(LMatrix3) &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH bool FLOATNAME(LMatrix3)::
 INLINE_LINMATH bool FLOATNAME(LMatrix3)::
 operator != (const FLOATNAME(LMatrix3) &other) const {
 operator != (const FLOATNAME(LMatrix3) &other) const {
-  return !operator == (other);
+  return compare_to(other) != 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 9 - 6
panda/src/linmath/lmatrix3_src.cxx

@@ -77,7 +77,7 @@ set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
           shear._v(1) * scale._v(2), shear._v(2) * scale._v(2), scale._v(2));
           shear._v(1) * scale._v(2), shear._v(2) * scale._v(2), scale._v(2));
     }
     }
     break;
     break;
-    
+
   case CS_zup_left:
   case CS_zup_left:
     if (temp_hpr_fix) {
     if (temp_hpr_fix) {
       set(scale._v(0), shear._v(0) * scale._v(0), 0.0f,
       set(scale._v(0), shear._v(0) * scale._v(0), 0.0f,
@@ -89,7 +89,7 @@ set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
           -shear._v(1) * scale._v(2), -shear._v(2) * scale._v(2), scale._v(2));
           -shear._v(1) * scale._v(2), -shear._v(2) * scale._v(2), scale._v(2));
     }
     }
     break;
     break;
-    
+
   case CS_yup_right:
   case CS_yup_right:
     if (temp_hpr_fix) {
     if (temp_hpr_fix) {
       set(scale._v(0), 0.0f, shear._v(1) * scale._v(0),
       set(scale._v(0), 0.0f, shear._v(1) * scale._v(0),
@@ -101,7 +101,7 @@ set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
           shear._v(1) * scale._v(2), 0.0f, scale._v(2));
           shear._v(1) * scale._v(2), 0.0f, scale._v(2));
     }
     }
     break;
     break;
-    
+
   case CS_yup_left:
   case CS_yup_left:
     if (temp_hpr_fix) {
     if (temp_hpr_fix) {
       set(scale._v(0), 0.0f, -shear._v(1) * scale._v(0),
       set(scale._v(0), 0.0f, -shear._v(1) * scale._v(0),
@@ -113,7 +113,7 @@ set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
           -shear._v(1) * scale._v(2), 0.0f, scale._v(2));
           -shear._v(1) * scale._v(2), 0.0f, scale._v(2));
     }
     }
     break;
     break;
-    
+
   case CS_default:
   case CS_default:
   case CS_invalid:
   case CS_invalid:
   default:
   default:
@@ -352,6 +352,9 @@ set_rotate_mat_normaxis(FLOATTYPE angle, const FLOATNAME(LVecBase3) &axis,
 bool FLOATNAME(LMatrix3)::
 bool FLOATNAME(LMatrix3)::
 almost_equal(const FLOATNAME(LMatrix3) &other, FLOATTYPE threshold) const {
 almost_equal(const FLOATNAME(LMatrix3) &other, FLOATTYPE threshold) const {
   TAU_PROFILE("bool LMatrix3::almost_equal(const LMatrix3 &, FLOATTYPE)", " ", TAU_USER);
   TAU_PROFILE("bool LMatrix3::almost_equal(const LMatrix3 &, FLOATTYPE)", " ", TAU_USER);
+#ifdef HAVE_EIGEN
+  return ((_m - other._m).cwiseAbs().maxCoeff() < NEARLY_ZERO(FLOATTYPE));
+#else
   return (IS_THRESHOLD_EQUAL((*this)(0, 0), other(0, 0), threshold) &&
   return (IS_THRESHOLD_EQUAL((*this)(0, 0), other(0, 0), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 1), other(0, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 1), other(0, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 2), other(0, 2), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 2), other(0, 2), threshold) &&
@@ -361,9 +364,9 @@ almost_equal(const FLOATNAME(LMatrix3) &other, FLOATTYPE threshold) const {
           IS_THRESHOLD_EQUAL((*this)(2, 0), other(2, 0), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(2, 0), other(2, 0), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(2, 1), other(2, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(2, 1), other(2, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(2, 2), other(2, 2), threshold));
           IS_THRESHOLD_EQUAL((*this)(2, 2), other(2, 2), threshold));
+#endif
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LMatrix3::output
 //     Function: LMatrix3::output
 //       Access: Published
 //       Access: Published
@@ -440,7 +443,7 @@ void FLOATNAME(LMatrix3)::
 write_datagram_fixed(Datagram &destination) const {
 write_datagram_fixed(Datagram &destination) const {
   for (int i = 0; i < 3; ++i) {
   for (int i = 0; i < 3; ++i) {
     for (int j = 0; j < 3; ++j) {
     for (int j = 0; j < 3; ++j) {
-#if FLOATTOKEN == 'f' 
+#if FLOATTOKEN == 'f'
       destination.add_float32(get_cell(i,j));
       destination.add_float32(get_cell(i,j));
 #else
 #else
       destination.add_float64(get_cell(i,j));
       destination.add_float64(get_cell(i,j));

+ 7 - 6
panda/src/linmath/lmatrix3_src.h

@@ -99,6 +99,7 @@ PUBLISHED:
   INLINE_LINMATH static int size();
   INLINE_LINMATH static int size();
 
 
   INLINE_LINMATH bool is_nan() const;
   INLINE_LINMATH bool is_nan() const;
+  INLINE_LINMATH bool is_identity() const;
 
 
   INLINE_LINMATH FLOATTYPE get_cell(int row, int col) const;
   INLINE_LINMATH FLOATTYPE get_cell(int row, int col) const;
   INLINE_LINMATH void set_cell(int row, int col, FLOATTYPE value);
   INLINE_LINMATH void set_cell(int row, int col, FLOATTYPE value);
@@ -247,28 +248,28 @@ PUBLISHED:
     scale_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz);
     scale_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz);
 
 
   INLINE_LINMATH void
   INLINE_LINMATH void
-    set_shear_mat(const FLOATNAME(LVecBase3) &shear, 
+    set_shear_mat(const FLOATNAME(LVecBase3) &shear,
                   CoordinateSystem cs = CS_default);
                   CoordinateSystem cs = CS_default);
 
 
   static INLINE_LINMATH FLOATNAME(LMatrix3)
   static INLINE_LINMATH FLOATNAME(LMatrix3)
-    shear_mat(const FLOATNAME(LVecBase3) &shear, 
+    shear_mat(const FLOATNAME(LVecBase3) &shear,
               CoordinateSystem cs = CS_default);
               CoordinateSystem cs = CS_default);
   static INLINE_LINMATH FLOATNAME(LMatrix3)
   static INLINE_LINMATH FLOATNAME(LMatrix3)
-    shear_mat(FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz, 
+    shear_mat(FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz,
               CoordinateSystem cs = CS_default);
               CoordinateSystem cs = CS_default);
 
 
   void
   void
     set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
     set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
-                        const FLOATNAME(LVecBase3) &shear, 
+                        const FLOATNAME(LVecBase3) &shear,
                         CoordinateSystem cs = CS_default);
                         CoordinateSystem cs = CS_default);
 
 
   static INLINE_LINMATH FLOATNAME(LMatrix3)
   static INLINE_LINMATH FLOATNAME(LMatrix3)
     scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
     scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
-                    const FLOATNAME(LVecBase3) &shear, 
+                    const FLOATNAME(LVecBase3) &shear,
                     CoordinateSystem cs = CS_default);
                     CoordinateSystem cs = CS_default);
   static INLINE_LINMATH FLOATNAME(LMatrix3)
   static INLINE_LINMATH FLOATNAME(LMatrix3)
     scale_shear_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz,
     scale_shear_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz,
-                    FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz, 
+                    FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz,
                     CoordinateSystem cs = CS_default);
                     CoordinateSystem cs = CS_default);
 
 
   static const FLOATNAME(LMatrix3) &convert_mat(CoordinateSystem from,
   static const FLOATNAME(LMatrix3) &convert_mat(CoordinateSystem from,

+ 13 - 1
panda/src/linmath/lmatrix4_src.I

@@ -616,6 +616,18 @@ is_nan() const {
     cnan(_m(3, 0)) || cnan(_m(3, 1)) || cnan(_m(3, 2)) || cnan(_m(3, 3));
     cnan(_m(3, 0)) || cnan(_m(3, 1)) || cnan(_m(3, 2)) || cnan(_m(3, 3));
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: LMatrix4::is_identity
+//       Access: Public
+//  Description: Returns true if this is (close enough to) the
+//               identity matrix, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE_LINMATH bool FLOATNAME(LMatrix4)::
+is_identity() const {
+  // Eigen has isIdentity, but it seems to be twice as slow as this.
+  return almost_equal(ident_mat(), NEARLY_ZERO(FLOATTYPE));
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LMatrix4::get_cell
 //     Function: LMatrix4::get_cell
 //       Access: Public
 //       Access: Public
@@ -735,7 +747,7 @@ operator == (const FLOATNAME(LMatrix4) &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE_LINMATH bool FLOATNAME(LMatrix4)::
 INLINE_LINMATH bool FLOATNAME(LMatrix4)::
 operator != (const FLOATNAME(LMatrix4) &other) const {
 operator != (const FLOATNAME(LMatrix4) &other) const {
-  return !operator == (other);
+  return compare_to(other) != 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 9 - 4
panda/src/linmath/lmatrix4_src.cxx

@@ -182,7 +182,7 @@ set_rotate_mat(FLOATTYPE angle, const FLOATNAME(LVecBase3) &axis,
   FLOATTYPE length_sq = axis_0 * axis_0 + axis_1 * axis_1 + axis_2 * axis_2;
   FLOATTYPE length_sq = axis_0 * axis_0 + axis_1 * axis_1 + axis_2 * axis_2;
   nassertv(length_sq != 0.0f);
   nassertv(length_sq != 0.0f);
   FLOATTYPE recip_length = 1.0f/csqrt(length_sq);
   FLOATTYPE recip_length = 1.0f/csqrt(length_sq);
-  
+
   axis_0 *= recip_length;
   axis_0 *= recip_length;
   axis_1 *= recip_length;
   axis_1 *= recip_length;
   axis_2 *= recip_length;
   axis_2 *= recip_length;
@@ -288,11 +288,16 @@ set_rotate_mat_normaxis(FLOATTYPE angle, const FLOATNAME(LVecBase3) &axis,
 //     Function: LMatrix4::almost_equal
 //     Function: LMatrix4::almost_equal
 //       Access: Public
 //       Access: Public
 //  Description: Returns true if two matrices are memberwise equal
 //  Description: Returns true if two matrices are memberwise equal
-//               within a specified tolerance.
+//               within a specified tolerance.  This is faster than
+//               the equivalence operator as this doesn't have to
+//               guarantee that it is transitive.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool FLOATNAME(LMatrix4)::
 bool FLOATNAME(LMatrix4)::
 almost_equal(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const {
 almost_equal(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const {
   TAU_PROFILE("bool LMatrix4::almost_equal(const LMatrix4 &, FLOATTYPE)", " ", TAU_USER);
   TAU_PROFILE("bool LMatrix4::almost_equal(const LMatrix4 &, FLOATTYPE)", " ", TAU_USER);
+#ifdef HAVE_EIGEN
+  return ((_m - other._m).cwiseAbs().maxCoeff() < NEARLY_ZERO(FLOATTYPE));
+#else
   return (IS_THRESHOLD_EQUAL((*this)(0, 0), other(0, 0), threshold) &&
   return (IS_THRESHOLD_EQUAL((*this)(0, 0), other(0, 0), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 1), other(0, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 1), other(0, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 2), other(0, 2), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(0, 2), other(0, 2), threshold) &&
@@ -309,9 +314,9 @@ almost_equal(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const {
           IS_THRESHOLD_EQUAL((*this)(3, 1), other(3, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(3, 1), other(3, 1), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(3, 2), other(3, 2), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(3, 2), other(3, 2), threshold) &&
           IS_THRESHOLD_EQUAL((*this)(3, 3), other(3, 3), threshold));
           IS_THRESHOLD_EQUAL((*this)(3, 3), other(3, 3), threshold));
+#endif
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LMatrix4::output
 //     Function: LMatrix4::output
 //       Access: Public
 //       Access: Public
@@ -520,7 +525,7 @@ void FLOATNAME(LMatrix4)::
 write_datagram_fixed(Datagram &destination) const {
 write_datagram_fixed(Datagram &destination) const {
   for (int i = 0; i < 4; ++i) {
   for (int i = 0; i < 4; ++i) {
     for (int j = 0; j < 4; ++j) {
     for (int j = 0; j < 4; ++j) {
-#if FLOATTOKEN == 'f' 
+#if FLOATTOKEN == 'f'
       destination.add_float32(get_cell(i,j));
       destination.add_float32(get_cell(i,j));
 #else
 #else
       destination.add_float64(get_cell(i,j));
       destination.add_float64(get_cell(i,j));

+ 8 - 7
panda/src/linmath/lmatrix4_src.h

@@ -107,6 +107,7 @@ PUBLISHED:
   INLINE_LINMATH static int size();
   INLINE_LINMATH static int size();
 
 
   INLINE_LINMATH bool is_nan() const;
   INLINE_LINMATH bool is_nan() const;
+  INLINE_LINMATH bool is_identity() const;
 
 
   INLINE_LINMATH FLOATTYPE get_cell(int row, int col) const;
   INLINE_LINMATH FLOATTYPE get_cell(int row, int col) const;
   INLINE_LINMATH void set_cell(int row, int col, FLOATTYPE value);
   INLINE_LINMATH void set_cell(int row, int col, FLOATTYPE value);
@@ -205,13 +206,13 @@ PUBLISHED:
   INLINE_LINMATH void
   INLINE_LINMATH void
     set_scale_mat(const FLOATNAME(LVecBase3) &scale);
     set_scale_mat(const FLOATNAME(LVecBase3) &scale);
   INLINE_LINMATH void
   INLINE_LINMATH void
-    set_shear_mat(const FLOATNAME(LVecBase3) &shear, 
+    set_shear_mat(const FLOATNAME(LVecBase3) &shear,
                   CoordinateSystem cs = CS_default);
                   CoordinateSystem cs = CS_default);
   INLINE_LINMATH void
   INLINE_LINMATH void
     set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
     set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
-                        const FLOATNAME(LVecBase3) &shear, 
+                        const FLOATNAME(LVecBase3) &shear,
                         CoordinateSystem cs = CS_default);
                         CoordinateSystem cs = CS_default);
-  
+
   INLINE_LINMATH static FLOATNAME(LMatrix4)
   INLINE_LINMATH static FLOATNAME(LMatrix4)
     translate_mat(const FLOATNAME(LVecBase3) &trans);
     translate_mat(const FLOATNAME(LVecBase3) &trans);
   INLINE_LINMATH static FLOATNAME(LMatrix4)
   INLINE_LINMATH static FLOATNAME(LMatrix4)
@@ -232,19 +233,19 @@ PUBLISHED:
     scale_mat(FLOATTYPE scale);
     scale_mat(FLOATTYPE scale);
 
 
   static INLINE_LINMATH FLOATNAME(LMatrix4)
   static INLINE_LINMATH FLOATNAME(LMatrix4)
-    shear_mat(const FLOATNAME(LVecBase3) &shear, 
+    shear_mat(const FLOATNAME(LVecBase3) &shear,
               CoordinateSystem cs = CS_default);
               CoordinateSystem cs = CS_default);
   static INLINE_LINMATH FLOATNAME(LMatrix4)
   static INLINE_LINMATH FLOATNAME(LMatrix4)
-    shear_mat(FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz, 
+    shear_mat(FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz,
               CoordinateSystem cs = CS_default);
               CoordinateSystem cs = CS_default);
 
 
   static INLINE_LINMATH FLOATNAME(LMatrix4)
   static INLINE_LINMATH FLOATNAME(LMatrix4)
     scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
     scale_shear_mat(const FLOATNAME(LVecBase3) &scale,
-                    const FLOATNAME(LVecBase3) &shear, 
+                    const FLOATNAME(LVecBase3) &shear,
                     CoordinateSystem cs = CS_default);
                     CoordinateSystem cs = CS_default);
   static INLINE_LINMATH FLOATNAME(LMatrix4)
   static INLINE_LINMATH FLOATNAME(LMatrix4)
     scale_shear_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz,
     scale_shear_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz,
-                    FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz, 
+                    FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz,
                     CoordinateSystem cs = CS_default);
                     CoordinateSystem cs = CS_default);
 
 
   INLINE_LINMATH static const FLOATNAME(LMatrix4) &y_to_z_up_mat();
   INLINE_LINMATH static const FLOATNAME(LMatrix4) &y_to_z_up_mat();

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

@@ -106,7 +106,8 @@ ConfigVariableBool fake_view_frustum_cull
 ("fake-view-frustum-cull", false,
 ("fake-view-frustum-cull", false,
  PRC_DESC("Set this true to cause culling to be performed by rendering the "
  PRC_DESC("Set this true to cause culling to be performed by rendering the "
           "object in red wireframe, rather than actually culling it.  This "
           "object in red wireframe, rather than actually culling it.  This "
-          "helps make culling errors obvious."));
+          "helps make culling errors obvious.  This variable only has an "
+          "effect when Panda is not compiled for a release build."));
 
 
 ConfigVariableBool clip_plane_cull
 ConfigVariableBool clip_plane_cull
 ("clip-plane-cull", true,
 ("clip-plane-cull", true,
@@ -168,15 +169,6 @@ ConfigVariableBool compose_componentwise
           "operations when possible.  If this is false, the compositions "
           "operations when possible.  If this is false, the compositions "
           "are always computed by matrix."));
           "are always computed by matrix."));
 
 
-ConfigVariableBool uniquify_matrix
-("uniquify-matrix", true,
- 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 will be "
-          "collapsed into a single pointer.  Nowadays, "
-          "with the transforms stored in a hashtable, we're generally better "
-          "off with this set true."));
-
 ConfigVariableBool paranoid_const
 ConfigVariableBool paranoid_const
 ("paranoid-const", false,
 ("paranoid-const", false,
  PRC_DESC("Set this true to double-check that nothing is inappropriately "
  PRC_DESC("Set this true to double-check that nothing is inappropriately "

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

@@ -41,7 +41,6 @@ extern ConfigVariableBool no_unsupported_copy;
 extern ConfigVariableBool allow_unrelated_wrt;
 extern ConfigVariableBool allow_unrelated_wrt;
 extern ConfigVariableBool paranoid_compose;
 extern ConfigVariableBool paranoid_compose;
 extern ConfigVariableBool compose_componentwise;
 extern ConfigVariableBool compose_componentwise;
-extern ConfigVariableBool uniquify_matrix;
 extern ConfigVariableBool paranoid_const;
 extern ConfigVariableBool paranoid_const;
 extern ConfigVariableBool auto_break_cycles;
 extern ConfigVariableBool auto_break_cycles;
 extern EXPCL_PANDA_PGRAPH ConfigVariableBool garbage_collect_states;
 extern EXPCL_PANDA_PGRAPH ConfigVariableBool garbage_collect_states;

+ 0 - 25
panda/src/pgraph/cullBin.I

@@ -26,7 +26,6 @@ CullBin(const CullBin &copy) :
   _cull_this_pcollector(copy._cull_this_pcollector),
   _cull_this_pcollector(copy._cull_this_pcollector),
   _draw_this_pcollector(copy._draw_this_pcollector)
   _draw_this_pcollector(copy._draw_this_pcollector)
 {
 {
-  check_flash_color();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -44,7 +43,6 @@ CullBin(const string &name, CullBin::BinType bin_type,
   _cull_this_pcollector(_cull_bin_pcollector, name),
   _cull_this_pcollector(_cull_bin_pcollector, name),
   _draw_this_pcollector(draw_region_pcollector, name)
   _draw_this_pcollector(draw_region_pcollector, name)
 {
 {
-  check_flash_color();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -66,26 +64,3 @@ INLINE CullBin::BinType CullBin::
 get_bin_type() const {
 get_bin_type() const {
   return _bin_type;
   return _bin_type;
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullBin::has_flash_color
-//       Access: Public
-//  Description: Returns true if this bin has a flash color configured
-//               via the flash-bin-binname config directive, or false
-//               otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool CullBin::
-has_flash_color() const {
-  return _has_flash_color;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CullBin::get_flash_color
-//       Access: Public
-//  Description: If has_flash_color returns true, this returns the
-//               color specified.
-////////////////////////////////////////////////////////////////////
-INLINE const LColor &CullBin::
-get_flash_color() const {
-  return _flash_color;
-}

+ 0 - 34
panda/src/pgraph/cullBin.cxx

@@ -87,40 +87,6 @@ make_result_graph() {
   return root_node;
   return root_node;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullBin::check_flash_color
-//       Access: Private
-//  Description: Checks the config variables for a user variable of
-//               the name flash-bin-binname.  If found, it defines the
-//               r g b color to flash geometry in this bin.
-////////////////////////////////////////////////////////////////////
-void CullBin::
-check_flash_color() {
-#ifdef NDEBUG
-  _has_flash_color = false;
-#else
-  ConfigVariableDouble flash_bin
-    ("flash-bin-" + _name, "", "", ConfigVariable::F_dynamic);
-  if (flash_bin.get_num_words() == 0) {
-    _has_flash_color = false;
-
-  } else if (flash_bin.get_num_words() == 3) {
-    _has_flash_color = true;
-    _flash_color.set(flash_bin[0], flash_bin[1], flash_bin[2], 1.0f);
-
-  } else if (flash_bin.get_num_words() == 4) {
-    _has_flash_color = true;
-    _flash_color.set(flash_bin[0], flash_bin[1], flash_bin[2], flash_bin[3]);
-
-  } else {
-    _has_flash_color = false;
-    pgraph_cat.warning()
-      << "Invalid value for flash-bin-" << _name << ": "
-      << flash_bin.get_string_value() << "\n";
-  }
-#endif  // NDEBUG
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBin::ResultGraphBuilder::Constructor
 //     Function: CullBin::ResultGraphBuilder::Constructor
 //       Access: Public
 //       Access: Public

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

@@ -77,9 +77,6 @@ protected:
   BinType _bin_type;
   BinType _bin_type;
   GraphicsStateGuardianBase *_gsg;
   GraphicsStateGuardianBase *_gsg;
 
 
-  bool _has_flash_color;
-  LColor _flash_color;
-
   // Used in make_result_graph() and fill_result_graph().
   // Used in make_result_graph() and fill_result_graph().
   class ResultGraphBuilder {
   class ResultGraphBuilder {
   public:
   public:

+ 73 - 0
panda/src/pgraph/cullBinManager.I

@@ -284,3 +284,76 @@ set_bin_active(const string &name, bool active) {
   nassertv(bin_index != -1);
   nassertv(bin_index != -1);
   set_bin_active(bin_index, active);
   set_bin_active(bin_index, active);
 }
 }
+
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_bin_flash_active
+//       Access: Published
+//  Description: Returns true if the bin with the given bin_index is
+//               configured to flash at a predetermined color (where
+//               bin_index was retrieved by get_bin() or find_bin()).
+//
+//               This method is not available in release builds.
+////////////////////////////////////////////////////////////////////
+INLINE bool CullBinManager::
+get_bin_flash_active(int bin_index) const {
+  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), false);
+  return _bin_definitions[bin_index]._flash_active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_bin_flash_color
+//       Access: Published
+//  Description: Returns the color that this bin has been configured
+//               to flash to, if configured.
+//
+//               This method is not available in release builds.
+////////////////////////////////////////////////////////////////////
+INLINE const LColor &CullBinManager::
+get_bin_flash_color(int bin_index) const {
+  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), LColor::zero());
+  return _bin_definitions[bin_index]._flash_color;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::set_bin_flash_active
+//       Access: Published
+//  Description: When set to true, the given bin_index is configured
+//               to flash at a predetermined color (where
+//               bin_index was retrieved by get_bin() or find_bin()).
+//
+//               This method is not available in release builds.
+////////////////////////////////////////////////////////////////////
+INLINE void CullBinManager::
+set_bin_flash_active(int bin_index, bool active) {
+  nassertv(bin_index >= 0 && bin_index < (int)_bin_definitions.size());
+  _bin_definitions[bin_index]._flash_active = active;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::set_bin_flash_color
+//       Access: Published
+//  Description: Changes the flash color for the given bin index.
+
+//               This method is not available in release builds.
+////////////////////////////////////////////////////////////////////
+INLINE void CullBinManager::
+set_bin_flash_color(int bin_index, const LColor &color) {
+  nassertv(bin_index >= 0 && bin_index < (int)_bin_definitions.size());
+  _bin_definitions[bin_index]._flash_color = color;
+}
+#endif  // NDEBUG
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_global_ptr
+//       Access: Published, Static
+//  Description: Returns the pointer to the global CullBinManager
+//               object.
+////////////////////////////////////////////////////////////////////
+INLINE CullBinManager *CullBinManager::
+get_global_ptr() {
+  if (_global_ptr == (CullBinManager *)NULL) {
+    _global_ptr = new CullBinManager;
+  }
+  return _global_ptr;
+}

+ 34 - 25
panda/src/pgraph/cullBinManager.cxx

@@ -109,6 +109,29 @@ add_bin(const string &name, BinType type, int sort) {
   def._sort = sort;
   def._sort = sort;
   def._active = true;
   def._active = true;
 
 
+#ifndef NDEBUG
+  // Check if there was a flash color configured for this bin name.
+  ConfigVariableDouble flash_bin
+    ("flash-bin-" + name, "", "", ConfigVariable::F_dynamic);
+  if (flash_bin.get_num_words() == 0) {
+    def._flash_active = false;
+
+  } else if (flash_bin.get_num_words() == 3) {
+    def._flash_active = true;
+    def._flash_color.set(flash_bin[0], flash_bin[1], flash_bin[2], 1.0f);
+
+  } else if (flash_bin.get_num_words() == 4) {
+    def._flash_active = true;
+    def._flash_color.set(flash_bin[0], flash_bin[1], flash_bin[2], flash_bin[3]);
+
+  } else {
+    def._flash_active = false;
+    pgraph_cat.warning()
+      << "Invalid value for flash-bin-" << name << ": "
+      << flash_bin.get_string_value() << "\n";
+  }
+#endif
+
   _bins_by_name.insert(BinsByName::value_type(name, new_bin_index));
   _bins_by_name.insert(BinsByName::value_type(name, new_bin_index));
   _sorted_bins.push_back(new_bin_index);
   _sorted_bins.push_back(new_bin_index);
   _bins_are_sorted = false;
   _bins_are_sorted = false;
@@ -133,7 +156,7 @@ remove_bin(int bin_index) {
   nassertv(_bin_definitions[bin_index]._in_use);
   nassertv(_bin_definitions[bin_index]._in_use);
 
 
   _bin_definitions[bin_index]._in_use = false;
   _bin_definitions[bin_index]._in_use = false;
-  SortedBins::iterator si = 
+  SortedBins::iterator si =
     find(_sorted_bins.begin(), _sorted_bins.end(), bin_index);
     find(_sorted_bins.begin(), _sorted_bins.end(), bin_index);
   nassertv(si != _sorted_bins.end());
   nassertv(si != _sorted_bins.end());
   _sorted_bins.erase(si);
   _sorted_bins.erase(si);
@@ -142,7 +165,7 @@ remove_bin(int bin_index) {
   // Now we have to make sure all of the data objects in the world
   // Now we have to make sure all of the data objects in the world
   // that had cached this bin index or have a bin object are correctly
   // that had cached this bin index or have a bin object are correctly
   // updated.
   // updated.
-  
+
   // First, tell all the RenderStates in the world to reset their bin
   // First, tell all the RenderStates in the world to reset their bin
   // index cache.
   // index cache.
   RenderState::bin_removed(bin_index);
   RenderState::bin_removed(bin_index);
@@ -170,7 +193,7 @@ find_bin(const string &name) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBinManager::write
 //     Function: CullBinManager::write
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullBinManager::
 void CullBinManager::
 write(ostream &out) const {
 write(ostream &out) const {
@@ -185,20 +208,6 @@ write(ostream &out) const {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullBinManager::get_global_ptr
-//       Access: Published, Static
-//  Description: Returns the pointer to the global CullBinManager
-//               object.
-////////////////////////////////////////////////////////////////////
-CullBinManager *CullBinManager::
-get_global_ptr() {
-  if (_global_ptr == (CullBinManager *)NULL) {
-    _global_ptr = new CullBinManager;
-  }
-  return _global_ptr;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBinManager::make_new_bin
 //     Function: CullBinManager::make_new_bin
 //       Access: Public
 //       Access: Public
@@ -260,11 +269,11 @@ do_sort_bins() {
 void CullBinManager::
 void CullBinManager::
 setup_initial_bins() {
 setup_initial_bins() {
   ConfigVariableList cull_bin
   ConfigVariableList cull_bin
-    ("cull-bin", 
+    ("cull-bin",
      PRC_DESC("Creates a new cull bin by name, with the specified properties.  "
      PRC_DESC("Creates a new cull bin by name, with the specified properties.  "
               "This is a string in three tokens, separated by whitespace: "
               "This is a string in three tokens, separated by whitespace: "
               "'bin_name sort type'."));
               "'bin_name sort type'."));
-  
+
   // First, add all of the bins specified in the Configrc file.
   // First, add all of the bins specified in the Configrc file.
   int num_bins = cull_bin.get_num_unique_values();
   int num_bins = cull_bin.get_num_unique_values();
 
 
@@ -351,26 +360,26 @@ parse_bin_type(const string &bin_type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullBinManager::BinType output operator
 //     Function: CullBinManager::BinType output operator
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 ostream &
 ostream &
 operator << (ostream &out, CullBinManager::BinType bin_type) {
 operator << (ostream &out, CullBinManager::BinType bin_type) {
   switch (bin_type) {
   switch (bin_type) {
   case CullBinManager::BT_invalid:
   case CullBinManager::BT_invalid:
     return out << "invalid";
     return out << "invalid";
-    
+
   case CullBinManager::BT_unsorted:
   case CullBinManager::BT_unsorted:
     return out << "unsorted";
     return out << "unsorted";
-    
+
   case CullBinManager::BT_state_sorted:
   case CullBinManager::BT_state_sorted:
     return out << "state_sorted";
     return out << "state_sorted";
-    
+
   case CullBinManager::BT_back_to_front:
   case CullBinManager::BT_back_to_front:
     return out << "back_to_front";
     return out << "back_to_front";
-    
+
   case CullBinManager::BT_front_to_back:
   case CullBinManager::BT_front_to_back:
     return out << "front_to_back";
     return out << "front_to_back";
-    
+
   case CullBinManager::BT_fixed:
   case CullBinManager::BT_fixed:
     return out << "fixed";
     return out << "fixed";
   }
   }

+ 13 - 2
panda/src/pgraph/cullBinManager.h

@@ -65,9 +65,16 @@ PUBLISHED:
   INLINE void set_bin_active(int bin_index, bool active);
   INLINE void set_bin_active(int bin_index, bool active);
   INLINE void set_bin_active(const string &name, bool active);
   INLINE void set_bin_active(const string &name, bool active);
 
 
+#ifndef NDEBUG
+  INLINE bool get_bin_flash_active(int bin_index) const;
+  INLINE const LColor &get_bin_flash_color(int bin_index) const;
+  INLINE void set_bin_flash_active(int bin_index, bool active);
+  INLINE void set_bin_flash_color(int bin_index, const LColor &color);
+#endif
+
   void write(ostream &out) const;
   void write(ostream &out) const;
 
 
-  static CullBinManager *get_global_ptr();
+  INLINE static CullBinManager *get_global_ptr();
 
 
 public:
 public:
   // This interface is only intended to be used by CullResult.
   // This interface is only intended to be used by CullResult.
@@ -77,7 +84,7 @@ public:
   // This defines the factory interface for defining constructors to
   // This defines the factory interface for defining constructors to
   // bin types (the implementations are in the cull directory, not
   // bin types (the implementations are in the cull directory, not
   // here in pgraph, so we can't call the constructors directly).
   // here in pgraph, so we can't call the constructors directly).
-  typedef CullBin *BinConstructor(const string &name, 
+  typedef CullBin *BinConstructor(const string &name,
                                   GraphicsStateGuardianBase *gsg,
                                   GraphicsStateGuardianBase *gsg,
                                   const PStatCollector &draw_region_pcollector);
                                   const PStatCollector &draw_region_pcollector);
 
 
@@ -95,6 +102,10 @@ private:
     BinType _type;
     BinType _type;
     int _sort;
     int _sort;
     bool _active;
     bool _active;
+#ifndef NDEBUG
+    bool _flash_active;
+    LColorf _flash_color;
+#endif
   };
   };
   typedef pvector<BinDefinition> BinDefinitions;
   typedef pvector<BinDefinition> BinDefinitions;
   BinDefinitions _bin_definitions;
   BinDefinitions _bin_definitions;

+ 1 - 1
panda/src/pgraph/cullPlanes.cxx

@@ -13,12 +13,12 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "cullPlanes.h"
 #include "cullPlanes.h"
+#include "cullTraverser.h"
 #include "cullTraverserData.h"
 #include "cullTraverserData.h"
 #include "clipPlaneAttrib.h"
 #include "clipPlaneAttrib.h"
 #include "occluderEffect.h"
 #include "occluderEffect.h"
 #include "boundingBox.h"
 #include "boundingBox.h"
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CullPlanes::make_empty
 //     Function: CullPlanes::make_empty
 //       Access: Public, Static
 //       Access: Public, Static

+ 41 - 21
panda/src/pgraph/cullResult.cxx

@@ -26,6 +26,7 @@
 #include "renderState.h"
 #include "renderState.h"
 #include "clockObject.h"
 #include "clockObject.h"
 #include "config_pgraph.h"
 #include "config_pgraph.h"
+#include "depthOffsetAttrib.h"
 
 
 TypeHandle CullResult::_type_handle;
 TypeHandle CullResult::_type_handle;
 
 
@@ -114,12 +115,15 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
 
 
   bool force = !traverser->get_effective_incomplete_render();
   bool force = !traverser->get_effective_incomplete_render();
   Thread *current_thread = traverser->get_current_thread();
   Thread *current_thread = traverser->get_current_thread();
+  CullBinManager *bin_manager = CullBinManager::get_global_ptr();
 
 
   // Check to see if there's a special transparency setting.
   // Check to see if there's a special transparency setting.
   const RenderState *state = object->_state;
   const RenderState *state = object->_state;
   nassertv(state != (const RenderState *)NULL);
   nassertv(state != (const RenderState *)NULL);
 
 
-  const TransparencyAttrib *trans = DCAST(TransparencyAttrib, state->get_attrib(TransparencyAttrib::get_class_slot()));
+  const TransparencyAttrib *trans = (const TransparencyAttrib *)
+    state->get_attrib(TransparencyAttrib::get_class_slot());
+
   if (trans != (const TransparencyAttrib *)NULL) {
   if (trans != (const TransparencyAttrib *)NULL) {
     switch (trans->get_mode()) {
     switch (trans->get_mode()) {
     case TransparencyAttrib::M_alpha:
     case TransparencyAttrib::M_alpha:
@@ -168,7 +172,9 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
       // explicit bin already applied; otherwise, M_dual falls back
       // explicit bin already applied; otherwise, M_dual falls back
       // to M_alpha.
       // to M_alpha.
       {
       {
-        const CullBinAttrib *bin_attrib = DCAST(CullBinAttrib, state->get_attrib(CullBinAttrib::get_class_slot()));
+        const CullBinAttrib *bin_attrib = (const CullBinAttrib *)
+          state->get_attrib(CullBinAttrib::get_class_slot());
+
         if (bin_attrib == (CullBinAttrib *)NULL ||
         if (bin_attrib == (CullBinAttrib *)NULL ||
             bin_attrib->get_bin_name().empty()) {
             bin_attrib->get_bin_name().empty()) {
           // We make a copy of the object to draw the transparent part;
           // We make a copy of the object to draw the transparent part;
@@ -183,10 +189,14 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
               if (transparent_part->munge_geom
               if (transparent_part->munge_geom
                   (_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread),
                   (_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread),
                    traverser, force)) {
                    traverser, force)) {
-                CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
+                int transparent_bin_index = transparent_part->_state->get_bin_index();
+                CullBin *bin = get_bin(transparent_bin_index);
                 nassertv(bin != (CullBin *)NULL);
                 nassertv(bin != (CullBin *)NULL);
 #ifndef NDEBUG
 #ifndef NDEBUG
-                check_flash_bin(transparent_part->_state, bin);
+                if (bin_manager->get_bin_flash_active(transparent_bin_index)) {
+                  do_flash_bin(transparent_part->_state,
+                    bin_manager->get_bin_flash_color(transparent_bin_index));
+                }
 #endif
 #endif
                 bin->add_object(transparent_part, current_thread);
                 bin->add_object(transparent_part, current_thread);
               } else {
               } else {
@@ -215,11 +225,15 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
     }
     }
   }
   }
 
 
-  CullBin *bin = get_bin(object->_state->get_bin_index());
+  int bin_index = object->_state->get_bin_index();
+  CullBin *bin = get_bin(bin_index);
   nassertv(bin != (CullBin *)NULL);
   nassertv(bin != (CullBin *)NULL);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-  check_flash_bin(object->_state, bin);
+  if (bin_manager->get_bin_flash_active(bin_index)) {
+    do_flash_bin(object->_state,
+      bin_manager->get_bin_flash_color(bin_index));
+  }
 #endif
 #endif
 
 
   // Munge vertices as needed for the GSG's requirements, and the
   // Munge vertices as needed for the GSG's requirements, and the
@@ -346,16 +360,20 @@ make_new_bin(int bin_index) {
   CullBinManager *bin_manager = CullBinManager::get_global_ptr();
   CullBinManager *bin_manager = CullBinManager::get_global_ptr();
   PT(CullBin) bin = bin_manager->make_new_bin(bin_index, _gsg,
   PT(CullBin) bin = bin_manager->make_new_bin(bin_index, _gsg,
                                               _draw_region_pcollector);
                                               _draw_region_pcollector);
-  if (bin != (CullBin *)NULL) {
+  CullBin *bin_ptr = bin.p();
+
+  if (bin_ptr != (CullBin *)NULL) {
     // Now store it in the vector.
     // Now store it in the vector.
     while (bin_index >= (int)_bins.size()) {
     while (bin_index >= (int)_bins.size()) {
       _bins.push_back((CullBin *)NULL);
       _bins.push_back((CullBin *)NULL);
     }
     }
     nassertr(bin_index >= 0 && bin_index < (int)_bins.size(), NULL);
     nassertr(bin_index >= 0 && bin_index < (int)_bins.size(), NULL);
-    _bins[bin_index] = bin;
+
+    // Prevent unnecessary ref/unref by swapping the PointerTos.
+    swap(_bins[bin_index], bin);
   }
   }
 
 
-  return bin;
+  return bin_ptr;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -393,25 +411,25 @@ get_binary_state() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CullResult::check_flash_bin
+//     Function: CullResult::do-flash_bin
 //       Access: Private
 //       Access: Private
 //  Description: If the user configured flash-bin-binname, then update
 //  Description: If the user configured flash-bin-binname, then update
 //               the object's state to flash all the geometry in the
 //               the object's state to flash all the geometry in the
 //               bin.
 //               bin.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullResult::
 void CullResult::
-check_flash_bin(CPT(RenderState) &state, CullBin *bin) {
-  if (bin->has_flash_color()) {
-    int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
-    if ((cycle & 1) == 0) {
-      state = state->remove_attrib(TextureAttrib::get_class_slot());
-      state = state->remove_attrib(LightAttrib::get_class_slot());
-      state = state->remove_attrib(ColorScaleAttrib::get_class_slot());
-      state = state->remove_attrib(FogAttrib::get_class_slot());
-      state = state->add_attrib(ColorAttrib::make_flat(bin->get_flash_color()),
-                                RenderState::get_max_priority());
-    }
+do_flash_bin(CPT(RenderState) &state, const LColor &flash_color) {
+#ifndef NDEBUG
+  int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
+  if ((cycle & 1) == 0) {
+    state = state->remove_attrib(TextureAttrib::get_class_slot());
+    state = state->remove_attrib(LightAttrib::get_class_slot());
+    state = state->remove_attrib(ColorScaleAttrib::get_class_slot());
+    state = state->remove_attrib(FogAttrib::get_class_slot());
+    state = state->add_attrib(ColorAttrib::make_flat(flash_color),
+                              RenderState::get_max_priority());
   }
   }
+#endif  // NDEBUG
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -423,6 +441,7 @@ check_flash_bin(CPT(RenderState) &state, CullBin *bin) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullResult::
 void CullResult::
 check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) {
 check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) {
+#ifndef NDEBUG
   if (show_transparency) {
   if (show_transparency) {
     int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
     int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
     if ((cycle & 1) == 0) {
     if ((cycle & 1) == 0) {
@@ -434,6 +453,7 @@ check_flash_transparency(CPT(RenderState) &state, const LColor &transparency) {
                                 RenderState::get_max_priority());
                                 RenderState::get_max_priority());
     }
     }
   }
   }
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/pgraph/cullResult.h

@@ -66,7 +66,7 @@ public:
 
 
 private:
 private:
   CullBin *make_new_bin(int bin_index);
   CullBin *make_new_bin(int bin_index);
-  void check_flash_bin(CPT(RenderState) &state, CullBin *bin);
+  void do_flash_bin(CPT(RenderState) &state, const LColor &flash_color);
   void check_flash_transparency(CPT(RenderState) &state, const LColor &color);
   void check_flash_transparency(CPT(RenderState) &state, const LColor &color);
 
 
   static CPT(RenderState) get_alpha_state();
   static CPT(RenderState) get_alpha_state();

+ 60 - 0
panda/src/pgraph/cullTraverser.I

@@ -245,3 +245,63 @@ flush_level() {
   _geoms_pcollector.flush_level();
   _geoms_pcollector.flush_level();
   _geoms_occluded_pcollector.flush_level();
   _geoms_occluded_pcollector.flush_level();
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::do_traverse
+//       Access: Protected
+//  Description: This is implemented inline to reduce recursion.
+////////////////////////////////////////////////////////////////////
+INLINE void CullTraverser::
+do_traverse(CullTraverserData &data) {
+  if (is_in_view(data)) {
+    if (pgraph_cat.is_spam()) {
+      pgraph_cat.spam()
+        << "\n" << data._node_path
+        << " " << data._draw_mask << "\n";
+    }
+
+    PandaNodePipelineReader *node_reader = data.node_reader();
+    int fancy_bits = node_reader->get_fancy_bits();
+
+    if ((fancy_bits & (PandaNode::FB_transform |
+                       PandaNode::FB_state |
+                       PandaNode::FB_effects |
+                       PandaNode::FB_tag |
+                       PandaNode::FB_draw_mask |
+                       PandaNode::FB_cull_callback)) == 0 &&
+        data._cull_planes->is_empty()) {
+      // Nothing interesting in this node; just move on.
+
+    } else {
+      // Something in this node is worth taking a closer look.
+      const RenderEffects *node_effects = node_reader->get_effects();
+      if (node_effects->has_show_bounds()) {
+        // If we should show the bounding volume for this node, make it
+        // up now.
+        show_bounds(data, node_effects->has_show_tight_bounds());
+      }
+
+      data.apply_transform_and_state(this);
+
+      const FogAttrib *fog = (const FogAttrib *)
+        node_reader->get_state()->get_attrib(FogAttrib::get_class_slot());
+
+      if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
+        // If we just introduced a FogAttrib here, call adjust_to_camera()
+        // now.  This maybe isn't the perfect time to call it, but it's
+        // good enough; and at this time we have all the information we
+        // need for it.
+        fog->get_fog()->adjust_to_camera(get_camera_transform());
+      }
+
+      if (fancy_bits & PandaNode::FB_cull_callback) {
+        PandaNode *node = data.node();
+        if (!node->cull_callback(this, data)) {
+          return;
+        }
+      }
+    }
+
+    traverse_below(data);
+  }
+}

+ 18 - 70
panda/src/pgraph/cullTraverser.cxx

@@ -17,7 +17,6 @@
 #include "cullTraverserData.h"
 #include "cullTraverserData.h"
 #include "transformState.h"
 #include "transformState.h"
 #include "renderState.h"
 #include "renderState.h"
-#include "fogAttrib.h"
 #include "colorAttrib.h"
 #include "colorAttrib.h"
 #include "renderModeAttrib.h"
 #include "renderModeAttrib.h"
 #include "cullFaceAttrib.h"
 #include "cullFaceAttrib.h"
@@ -164,7 +163,7 @@ traverse(const NodePath &root) {
                            _initial_state, _view_frustum,
                            _initial_state, _view_frustum,
                            _current_thread);
                            _current_thread);
 
 
-    traverse(data);
+    do_traverse(data);
   }
   }
 }
 }
 
 
@@ -177,55 +176,7 @@ traverse(const NodePath &root) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullTraverser::
 void CullTraverser::
 traverse(CullTraverserData &data) {
 traverse(CullTraverserData &data) {
-  if (is_in_view(data)) {
-    if (pgraph_cat.is_spam()) {
-      pgraph_cat.spam()
-        << "\n" << data._node_path
-        << " " << data._draw_mask << "\n";
-    }
-
-    PandaNodePipelineReader *node_reader = data.node_reader();
-    int fancy_bits = node_reader->get_fancy_bits();
-
-    if ((fancy_bits & (PandaNode::FB_transform |
-                       PandaNode::FB_state |
-                       PandaNode::FB_effects |
-                       PandaNode::FB_tag |
-                       PandaNode::FB_draw_mask |
-                       PandaNode::FB_cull_callback)) == 0 &&
-        data._cull_planes->is_empty()) {
-      // Nothing interesting in this node; just move on.
-      traverse_below(data);
-
-    } else {
-      // Something in this node is worth taking a closer look.
-      const RenderEffects *node_effects = node_reader->get_effects();
-      if (node_effects->has_show_bounds()) {
-        // If we should show the bounding volume for this node, make it
-        // up now.
-        show_bounds(data, node_effects->has_show_tight_bounds());
-      }
-
-      data.apply_transform_and_state(this);
-
-      const FogAttrib *fog = DCAST(FogAttrib, node_reader->get_state()->get_attrib(FogAttrib::get_class_slot()));
-      if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
-        // If we just introduced a FogAttrib here, call adjust_to_camera()
-        // now.  This maybe isn't the perfect time to call it, but it's
-        // good enough; and at this time we have all the information we
-        // need for it.
-        fog->get_fog()->adjust_to_camera(get_camera_transform());
-      }
-
-      if (fancy_bits & PandaNode::FB_cull_callback) {
-        PandaNode *node = data.node();
-        if (!node->cull_callback(this, data)) {
-          return;
-        }
-      }
-      traverse_below(data);
-    }
-  }
+  do_traverse(data);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -241,27 +192,24 @@ traverse_below(CullTraverserData &data) {
   PandaNodePipelineReader *node_reader = data.node_reader();
   PandaNodePipelineReader *node_reader = data.node_reader();
   PandaNode *node = data.node();
   PandaNode *node = data.node();
 
 
-  bool this_node_hidden = data.is_this_node_hidden(this);
-
-  const RenderEffects *node_effects = node_reader->get_effects();
-  bool has_decal = !this_node_hidden && node_effects->has_decal();
-
-  if (!this_node_hidden) {
+  if (!data.is_this_node_hidden(_camera_mask)) {
     node->add_for_draw(this, data);
     node->add_for_draw(this, data);
-  }
 
 
-  if (has_decal) {
-    // If we *are* implementing decals with DepthOffsetAttribs,
-    // apply it now, so that each child of this node gets offset by
-    // a tiny amount.
-    data._state = data._state->compose(get_depth_offset_state());
+    // Check for a decal effect.
+    const RenderEffects *node_effects = node_reader->get_effects();
+    if (node_effects->has_decal()) {
+      // If we *are* implementing decals with DepthOffsetAttribs,
+      // apply it now, so that each child of this node gets offset by
+      // a tiny amount.
+      data._state = data._state->compose(get_depth_offset_state());
 #ifndef NDEBUG
 #ifndef NDEBUG
-    // This is just a sanity check message.
-    if (!node->is_geom_node()) {
-      pgraph_cat.error()
-        << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
-    }
+      // This is just a sanity check message.
+      if (!node->is_geom_node()) {
+        pgraph_cat.error()
+          << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
+      }
 #endif
 #endif
+    }
   }
   }
 
 
   // Now visit all the node's children.
   // Now visit all the node's children.
@@ -272,14 +220,14 @@ traverse_below(CullTraverserData &data) {
     int i = node->get_first_visible_child();
     int i = node->get_first_visible_child();
     while (i < num_children) {
     while (i < num_children) {
       CullTraverserData next_data(data, children.get_child(i));
       CullTraverserData next_data(data, children.get_child(i));
-      traverse(next_data);
+      do_traverse(next_data);
       i = node->get_next_visible_child(i);
       i = node->get_next_visible_child(i);
     }
     }
 
 
   } else {
   } else {
     for (int i = 0; i < num_children; i++) {
     for (int i = 0; i < num_children; i++) {
       CullTraverserData next_data(data, children.get_child(i));
       CullTraverserData next_data(data, children.get_child(i));
-      traverse(next_data);
+      do_traverse(next_data);
     }
     }
   }
   }
 }
 }

+ 4 - 0
panda/src/pgraph/cullTraverser.h

@@ -27,6 +27,8 @@
 #include "drawMask.h"
 #include "drawMask.h"
 #include "typedReferenceCount.h"
 #include "typedReferenceCount.h"
 #include "pStatCollector.h"
 #include "pStatCollector.h"
+#include "cullTraverserData.h"
+#include "fogAttrib.h"
 
 
 class GraphicsStateGuardian;
 class GraphicsStateGuardian;
 class PandaNode;
 class PandaNode;
@@ -92,6 +94,8 @@ PUBLISHED:
                             const TransformState *modelview_transform) const;
                             const TransformState *modelview_transform) const;
 
 
 protected:
 protected:
+  INLINE void do_traverse(CullTraverserData &data);
+
   virtual bool is_in_view(CullTraverserData &data);
   virtual bool is_in_view(CullTraverserData &data);
 
 
 public:
 public:

+ 2 - 2
panda/src/pgraph/cullTraverserData.I

@@ -185,7 +185,7 @@ is_in_view(const DrawMask &camera_mask) {
 //               rendered.
 //               rendered.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool CullTraverserData::
 INLINE bool CullTraverserData::
-is_this_node_hidden(const CullTraverser *trav) const {
+is_this_node_hidden(const DrawMask &camera_mask) const {
   return (_draw_mask & PandaNode::get_overall_bit()).is_zero() ||
   return (_draw_mask & PandaNode::get_overall_bit()).is_zero() ||
-    (_draw_mask & trav->get_camera_mask()).is_zero();
+    (_draw_mask & camera_mask).is_zero();
 }
 }

+ 16 - 5
panda/src/pgraph/cullTraverserData.cxx

@@ -145,6 +145,9 @@ is_in_view_impl() {
     
     
     if (result == BoundingVolume::IF_no_intersection) {
     if (result == BoundingVolume::IF_no_intersection) {
       // No intersection at all.  Cull.
       // No intersection at all.  Cull.
+#ifdef NDEBUG
+      return false;
+#else
       if (!fake_view_frustum_cull) {
       if (!fake_view_frustum_cull) {
         return false;
         return false;
       }
       }
@@ -155,12 +158,13 @@ is_in_view_impl() {
       _view_frustum = (GeometricBoundingVolume *)NULL;
       _view_frustum = (GeometricBoundingVolume *)NULL;
       CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
       CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
       _state = _state->compose(fake_state);
       _state = _state->compose(fake_state);
-      
+#endif
+
     } else if ((result & BoundingVolume::IF_all) != 0) {
     } else if ((result & BoundingVolume::IF_all) != 0) {
       // The node and its descendents are completely enclosed within
       // The node and its descendents are completely enclosed within
       // the frustum.  No need to cull further.
       // the frustum.  No need to cull further.
       _view_frustum = (GeometricBoundingVolume *)NULL;
       _view_frustum = (GeometricBoundingVolume *)NULL;
-      
+
     } else {
     } else {
       // The node is partially, but not completely, within the viewing
       // The node is partially, but not completely, within the viewing
       // frustum.
       // frustum.
@@ -197,16 +201,20 @@ is_in_view_impl() {
         _state->write(pgraph_cat.spam(false), 2);
         _state->write(pgraph_cat.spam(false), 2);
       }
       }
     }
     }
-    
+
     if (result == BoundingVolume::IF_no_intersection) {
     if (result == BoundingVolume::IF_no_intersection) {
       // No intersection at all.  Cull.
       // No intersection at all.  Cull.
+#ifdef NDEBUG
+      return false;
+#else
       if (!fake_view_frustum_cull) {
       if (!fake_view_frustum_cull) {
         return false;
         return false;
       }
       }
       _cull_planes = CullPlanes::make_empty();
       _cull_planes = CullPlanes::make_empty();
       CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
       CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
       _state = _state->compose(fake_state);
       _state = _state->compose(fake_state);
-      
+#endif
+
     } else if ((result & BoundingVolume::IF_all) != 0) {
     } else if ((result & BoundingVolume::IF_all) != 0) {
       // The node and its descendents are completely in front of all
       // The node and its descendents are completely in front of all
       // of the clip planes and occluders.  The do_cull() call should
       // of the clip planes and occluders.  The do_cull() call should
@@ -227,6 +235,9 @@ is_in_view_impl() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) CullTraverserData::
 CPT(RenderState) CullTraverserData::
 get_fake_view_frustum_cull_state() {
 get_fake_view_frustum_cull_state() {
+#ifdef NDEBUG
+  return NULL;
+#else
   // Once someone asks for this pointer, we hold its reference count
   // Once someone asks for this pointer, we hold its reference count
   // and never free it.
   // and never free it.
   static CPT(RenderState) state = (const RenderState *)NULL;
   static CPT(RenderState) state = (const RenderState *)NULL;
@@ -238,5 +249,5 @@ get_fake_view_frustum_cull_state() {
        RenderState::get_max_priority());
        RenderState::get_max_priority());
   }
   }
   return state;
   return state;
+#endif
 }
 }
-

+ 2 - 2
panda/src/pgraph/cullTraverserData.h

@@ -23,10 +23,10 @@
 #include "geometricBoundingVolume.h"
 #include "geometricBoundingVolume.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "drawMask.h"
 #include "drawMask.h"
-#include "cullTraverser.h"
 #include "pvector.h"
 #include "pvector.h"
 
 
 class PandaNode;
 class PandaNode;
+class CullTraverser;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : CullTraverserData
 //       Class : CullTraverserData
@@ -67,7 +67,7 @@ PUBLISHED:
   INLINE const TransformState *get_net_transform(const CullTraverser *trav) const;
   INLINE const TransformState *get_net_transform(const CullTraverser *trav) const;
 
 
   INLINE bool is_in_view(const DrawMask &camera_mask);
   INLINE bool is_in_view(const DrawMask &camera_mask);
-  INLINE bool is_this_node_hidden(const CullTraverser *trav) const;
+  INLINE bool is_this_node_hidden(const DrawMask &camera_mask) const;
 
 
   void apply_transform_and_state(CullTraverser *trav);
   void apply_transform_and_state(CullTraverser *trav);
   void apply_transform_and_state(CullTraverser *trav, 
   void apply_transform_and_state(CullTraverser *trav, 

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

@@ -133,7 +133,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
         _munged_data->animate_vertices(force, current_thread);
         _munged_data->animate_vertices(force, current_thread);
       if (animated_vertices != _munged_data) {
       if (animated_vertices != _munged_data) {
         cpu_animated = true;
         cpu_animated = true;
-        _munged_data = animated_vertices;
+        swap(_munged_data, animated_vertices);
       }
       }
       if (!munge_texcoord_light_vector(traverser, force)) {
       if (!munge_texcoord_light_vector(traverser, force)) {
         return false;
         return false;
@@ -159,7 +159,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
         _munged_data->animate_vertices(force, current_thread);
         _munged_data->animate_vertices(force, current_thread);
       if (animated_vertices != _munged_data) {
       if (animated_vertices != _munged_data) {
         cpu_animated = true;
         cpu_animated = true;
-        _munged_data = animated_vertices;
+        swap(_munged_data, animated_vertices);
       }
       }
     }
     }
 
 
@@ -589,7 +589,12 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
   }
   }
 
 
   _geom = new_geom.p();
   _geom = new_geom.p();
+
+#ifdef USE_MOVE_SEMANTICS
+  _munged_data = move(new_data);
+#else
   _munged_data = new_data;
   _munged_data = new_data;
+#endif
 
 
   return true;
   return true;
 }
 }

+ 23 - 0
panda/src/pgraph/geomNode.I

@@ -320,6 +320,29 @@ operator = (const GeomNode::Geoms &copy) {
   _geoms = copy._geoms;
   _geoms = copy._geoms;
 }
 }
 
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNode::Geoms::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomNode::Geoms::
+Geoms(GeomNode::Geoms &&from) NOEXCEPT :
+  _geoms(move(from._geoms))
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNode::Geoms::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void GeomNode::Geoms::
+operator = (GeomNode::Geoms &&from) NOEXCEPT {
+  _geoms = move(from._geoms);
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomNode::Geoms::get_num_geoms
 //     Function: GeomNode::Geoms::get_num_geoms
 //       Access: Public
 //       Access: Public

+ 5 - 0
panda/src/pgraph/geomNode.h

@@ -168,6 +168,11 @@ public:
     INLINE Geoms(const Geoms &copy);
     INLINE Geoms(const Geoms &copy);
     INLINE void operator = (const Geoms &copy);
     INLINE void operator = (const Geoms &copy);
 
 
+#ifdef USE_MOVE_SEMANTICS
+    INLINE Geoms(Geoms &&from) NOEXCEPT;
+    INLINE void operator = (Geoms &&from) NOEXCEPT;
+#endif
+
     INLINE int get_num_geoms() const;
     INLINE int get_num_geoms() const;
     INLINE CPT(Geom) get_geom(int n) const;
     INLINE CPT(Geom) get_geom(int n) const;
     INLINE const RenderState *get_geom_state(int n) const;
     INLINE const RenderState *get_geom_state(int n) const;

+ 69 - 0
panda/src/pgraph/pandaNode.I

@@ -1130,6 +1130,29 @@ operator = (const PandaNode::Children &copy) {
   _down = copy._down;
   _down = copy._down;
 }
 }
 
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Children::
+Children(PandaNode::Children &&from) NOEXCEPT :
+  _down(move(from._down))
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::Children::
+operator = (PandaNode::Children &&from) NOEXCEPT {
+  _down = move(from._down);
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::Children::get_num_children
 //     Function: PandaNode::Children::get_num_children
 //       Access: Public
 //       Access: Public
@@ -1208,6 +1231,29 @@ operator = (const PandaNode::Stashed &copy) {
   _stashed = copy._stashed;
   _stashed = copy._stashed;
 }
 }
 
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Stashed::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Stashed::
+Stashed(PandaNode::Stashed &&from) NOEXCEPT :
+  _stashed(move(from._stashed))
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Stashed::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::Stashed::
+operator = (PandaNode::Stashed &&from) NOEXCEPT {
+  _stashed = move(from._stashed);
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::Stashed::get_num_stashed
 //     Function: PandaNode::Stashed::get_num_stashed
 //       Access: Public
 //       Access: Public
@@ -1286,6 +1332,29 @@ operator = (const PandaNode::Parents &copy) {
   _up = copy._up;
   _up = copy._up;
 }
 }
 
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Parents::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Parents::
+Parents(PandaNode::Parents &&from) NOEXCEPT :
+  _up(move(from._up))
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Parents::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::Parents::
+operator = (PandaNode::Parents &&from) NOEXCEPT {
+  _up = move(from._up);
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::Parents::get_num_parents
 //     Function: PandaNode::Parents::get_num_parents
 //       Access: Public
 //       Access: Public

+ 34 - 19
panda/src/pgraph/pandaNode.h

@@ -69,14 +69,14 @@ class GraphicsStateGuardianBase;
 //               is the base class of all specialized nodes, and also
 //               is the base class of all specialized nodes, and also
 //               serves as a generic node with no special properties.
 //               serves as a generic node with no special properties.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_PGRAPH PandaNode : public TypedWritable, public Namable, 
+class EXPCL_PANDA_PGRAPH PandaNode : public TypedWritable, public Namable,
                               public LinkedListNode,
                               public LinkedListNode,
                               virtual public ReferenceCount {
                               virtual public ReferenceCount {
 PUBLISHED:
 PUBLISHED:
   PandaNode(const string &name);
   PandaNode(const string &name);
   virtual ~PandaNode();
   virtual ~PandaNode();
-  //published so that characters can be combined. 
-  virtual PandaNode *combine_with(PandaNode *other); 
+  //published so that characters can be combined.
+  virtual PandaNode *combine_with(PandaNode *other);
 
 
 protected:
 protected:
   PandaNode(const PandaNode &copy);
   PandaNode(const PandaNode &copy);
@@ -105,7 +105,7 @@ public:
                       bool &found_any,
                       bool &found_any,
                       const TransformState *transform,
                       const TransformState *transform,
                       Thread *current_thread = Thread::get_current_thread()) const;
                       Thread *current_thread = Thread::get_current_thread()) const;
-  
+
   virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
   virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
   virtual bool has_selective_visibility() const;
   virtual bool has_selective_visibility() const;
   virtual int get_first_visible_child() const;
   virtual int get_first_visible_child() const;
@@ -195,9 +195,9 @@ PUBLISHED:
   INLINE bool has_dirty_prev_transform() const;
   INLINE bool has_dirty_prev_transform() const;
   static void reset_all_prev_transform(Thread *current_thread = Thread::get_current_thread());
   static void reset_all_prev_transform(Thread *current_thread = Thread::get_current_thread());
 
 
-  void set_tag(const string &key, const string &value, 
+  void set_tag(const string &key, const string &value,
                Thread *current_thread = Thread::get_current_thread());
                Thread *current_thread = Thread::get_current_thread());
-  INLINE string get_tag(const string &key, 
+  INLINE string get_tag(const string &key,
                         Thread *current_thread = Thread::get_current_thread()) const;
                         Thread *current_thread = Thread::get_current_thread()) const;
   INLINE bool has_tag(const string &key,
   INLINE bool has_tag(const string &key,
                       Thread *current_thread = Thread::get_current_thread()) const;
                       Thread *current_thread = Thread::get_current_thread()) const;
@@ -393,7 +393,7 @@ private:
 
 
   // parent-child manipulation for NodePath support.  Don't try to
   // parent-child manipulation for NodePath support.  Don't try to
   // call these directly.
   // call these directly.
-  static PT(NodePathComponent) attach(NodePathComponent *parent, 
+  static PT(NodePathComponent) attach(NodePathComponent *parent,
                                       PandaNode *child, int sort,
                                       PandaNode *child, int sort,
                                       int pipeline_stage, Thread *current_thread);
                                       int pipeline_stage, Thread *current_thread);
   static void detach(NodePathComponent *child, int pipeline_stage, Thread *current_thread);
   static void detach(NodePathComponent *child, int pipeline_stage, Thread *current_thread);
@@ -402,7 +402,7 @@ private:
                        NodePathComponent *child, int sort, bool as_stashed,
                        NodePathComponent *child, int sort, bool as_stashed,
                        int pipeline_stage, Thread *current_thread);
                        int pipeline_stage, Thread *current_thread);
   static bool reparent_one_stage(NodePathComponent *new_parent,
   static bool reparent_one_stage(NodePathComponent *new_parent,
-                                 NodePathComponent *child, int sort, 
+                                 NodePathComponent *child, int sort,
                                  bool as_stashed, int pipeline_stage, Thread *current_thread);
                                  bool as_stashed, int pipeline_stage, Thread *current_thread);
   static PT(NodePathComponent) get_component(NodePathComponent *parent,
   static PT(NodePathComponent) get_component(NodePathComponent *parent,
                                              PandaNode *child,
                                              PandaNode *child,
@@ -411,7 +411,7 @@ private:
                                                  int pipeline_stage, Thread *current_thread);
                                                  int pipeline_stage, Thread *current_thread);
   PT(NodePathComponent) get_generic_component(bool accept_ambiguity,
   PT(NodePathComponent) get_generic_component(bool accept_ambiguity,
                                               int pipeline_stage, Thread *current_thread);
                                               int pipeline_stage, Thread *current_thread);
-  PT(NodePathComponent) r_get_generic_component(bool accept_ambiguity, 
+  PT(NodePathComponent) r_get_generic_component(bool accept_ambiguity,
                                                 bool &ambiguity_detected,
                                                 bool &ambiguity_detected,
                                                 int pipeline_stage, Thread *current_thread);
                                                 int pipeline_stage, Thread *current_thread);
   void delete_component(NodePathComponent *component);
   void delete_component(NodePathComponent *component);
@@ -421,7 +421,7 @@ private:
                              int pipeline_stage, Thread *current_thread);
                              int pipeline_stage, Thread *current_thread);
   void fix_path_lengths(int pipeline_stage, Thread *current_thread);
   void fix_path_lengths(int pipeline_stage, Thread *current_thread);
   void r_list_descendants(ostream &out, int indent_level) const;
   void r_list_descendants(ostream &out, int indent_level) const;
-  
+
   INLINE void do_set_dirty_prev_transform();
   INLINE void do_set_dirty_prev_transform();
   INLINE void do_clear_dirty_prev_transform();
   INLINE void do_clear_dirty_prev_transform();
 
 
@@ -461,14 +461,14 @@ private:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
     }
     }
-    
+
   public:
   public:
     static void init_type() {
     static void init_type() {
       BamReaderAuxData::init_type();
       BamReaderAuxData::init_type();
       register_type(_type_handle, "BamReaderAuxDataDown",
       register_type(_type_handle, "BamReaderAuxDataDown",
                     BamReaderAuxData::get_class_type());
                     BamReaderAuxData::get_class_type());
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
@@ -513,8 +513,8 @@ private:
 #ifndef NDEBUG
 #ifndef NDEBUG
   unsigned int _unexpected_change_flags;
   unsigned int _unexpected_change_flags;
 #endif // !NDEBUG
 #endif // !NDEBUG
-  
-  // This is the data that must be cycled between pipeline stages. 
+
+  // This is the data that must be cycled between pipeline stages.
 
 
   class EXPCL_PANDA_PGRAPH CData : public BoundsData {
   class EXPCL_PANDA_PGRAPH CData : public BoundsData {
   public:
   public:
@@ -524,7 +524,7 @@ private:
     ALLOC_DELETED_CHAIN(CData);
     ALLOC_DELETED_CHAIN(CData);
 
 
     virtual CycleData *make_copy() const;
     virtual CycleData *make_copy() const;
-    virtual void write_datagram(BamWriter *manager, Datagram &dg) const; 
+    virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
     void update_bam_nested(BamWriter *manager) const;
     void update_bam_nested(BamWriter *manager) const;
     virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
     virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
     virtual void fillin(DatagramIterator &scan, BamReader *manager);
     virtual void fillin(DatagramIterator &scan, BamReader *manager);
@@ -545,7 +545,7 @@ private:
     // are less likely to change as often: tags, collide mask.
     // are less likely to change as often: tags, collide mask.
 
 
     INLINE void set_fancy_bit(int bits, bool value);
     INLINE void set_fancy_bit(int bits, bool value);
-    
+
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
     void inc_py_refs();
     void inc_py_refs();
     void dec_py_refs();
     void dec_py_refs();
@@ -648,7 +648,7 @@ private:
     COWPT(Down) _down;
     COWPT(Down) _down;
     COWPT(Down) _stashed;
     COWPT(Down) _stashed;
     COWPT(Up) _up;
     COWPT(Up) _up;
-    
+
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
       return _type_handle;
       return _type_handle;
@@ -656,7 +656,7 @@ private:
     static void init_type() {
     static void init_type() {
       register_type(_type_handle, "PandaNode::CData");
       register_type(_type_handle, "PandaNode::CData");
     }
     }
-    
+
   private:
   private:
     static TypeHandle _type_handle;
     static TypeHandle _type_handle;
   };
   };
@@ -691,6 +691,11 @@ public:
     INLINE Children(const Children &copy);
     INLINE Children(const Children &copy);
     INLINE void operator = (const Children &copy);
     INLINE void operator = (const Children &copy);
 
 
+#ifdef USE_MOVE_SEMANTICS
+    INLINE Children(Children &&from) NOEXCEPT;
+    INLINE void operator = (Children &&from) NOEXCEPT;
+#endif
+
     INLINE int get_num_children() const;
     INLINE int get_num_children() const;
     INLINE PandaNode *get_child(int n) const;
     INLINE PandaNode *get_child(int n) const;
     INLINE int get_child_sort(int n) const;
     INLINE int get_child_sort(int n) const;
@@ -707,6 +712,11 @@ public:
     INLINE Stashed(const Stashed &copy);
     INLINE Stashed(const Stashed &copy);
     INLINE void operator = (const Stashed &copy);
     INLINE void operator = (const Stashed &copy);
 
 
+#ifdef USE_MOVE_SEMANTICS
+    INLINE Stashed(Stashed &&from) NOEXCEPT;
+    INLINE void operator = (Stashed &&from) NOEXCEPT;
+#endif
+
     INLINE int get_num_stashed() const;
     INLINE int get_num_stashed() const;
     INLINE PandaNode *get_stashed(int n) const;
     INLINE PandaNode *get_stashed(int n) const;
     INLINE int get_stashed_sort(int n) const;
     INLINE int get_stashed_sort(int n) const;
@@ -723,6 +733,11 @@ public:
     INLINE Parents(const Parents &copy);
     INLINE Parents(const Parents &copy);
     INLINE void operator = (const Parents &copy);
     INLINE void operator = (const Parents &copy);
 
 
+#ifdef USE_MOVE_SEMANTICS
+    INLINE Parents(Parents &&from) NOEXCEPT;
+    INLINE void operator = (Parents &&from) NOEXCEPT;
+#endif
+
     INLINE int get_num_parents() const;
     INLINE int get_num_parents() const;
     INLINE PandaNode *get_parent(int n) const;
     INLINE PandaNode *get_parent(int n) const;
 
 
@@ -750,7 +765,7 @@ protected:
   static TypedWritable *make_from_bam(const FactoryParams &params);
   static TypedWritable *make_from_bam(const FactoryParams &params);
   void fillin(DatagramIterator &scan, BamReader *manager);
   void fillin(DatagramIterator &scan, BamReader *manager);
   void fillin_recorder(DatagramIterator &scan, BamReader *manager);
   void fillin_recorder(DatagramIterator &scan, BamReader *manager);
-  
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 14 - 5
panda/src/pgraph/renderAttrib.I

@@ -96,11 +96,7 @@ compare_to(const RenderAttrib &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE size_t RenderAttrib::
 INLINE size_t RenderAttrib::
 get_hash() const {
 get_hash() const {
-  size_t hash = get_hash_impl();
-
-  // The type is also added to the hash.
-  hash = int_hash::add_hash(hash, get_type().get_index());
-  return hash;
+  return _hash;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -143,6 +139,19 @@ get_auto_shader_attrib(const RenderState *state) const {
   return get_auto_shader_attrib_impl(state);
   return get_auto_shader_attrib_impl(state);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::calc_hash
+//       Access: Published
+//  Description: Calculates a suitable hash value for phash_map.
+////////////////////////////////////////////////////////////////////
+INLINE void RenderAttrib::
+calc_hash() {
+  size_t hash = get_hash_impl();
+
+  // The type is also added to the hash.
+  _hash = int_hash::add_hash(hash, get_type().get_index());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::register_slot
 //     Function: RenderAttrib::register_slot
 //       Access: Public, Static
 //       Access: Public, Static

+ 11 - 9
panda/src/pgraph/renderAttrib.cxx

@@ -143,7 +143,7 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::get_auto_shader_attrib_impl
 //     Function: RenderAttrib::get_auto_shader_attrib_impl
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) RenderAttrib::
 CPT(RenderAttrib) RenderAttrib::
 get_auto_shader_attrib_impl(const RenderState *state) const {
 get_auto_shader_attrib_impl(const RenderState *state) const {
@@ -191,7 +191,7 @@ unref() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::output
 //     Function: RenderAttrib::output
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderAttrib::
 void RenderAttrib::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -201,7 +201,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::write
 //     Function: RenderAttrib::write
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderAttrib::
 void RenderAttrib::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
@@ -274,7 +274,7 @@ garbage_collect() {
   }
   }
   num_this_pass = min(num_this_pass, size);
   num_this_pass = min(num_this_pass, size);
   int stop_at_element = (_garbage_index + num_this_pass) % size;
   int stop_at_element = (_garbage_index + num_this_pass) % size;
-  
+
   int num_elements = 0;
   int num_elements = 0;
   int si = _garbage_index;
   int si = _garbage_index;
   do {
   do {
@@ -291,7 +291,7 @@ garbage_collect() {
         attrib->release_new();
         attrib->release_new();
         unref_delete(attrib);
         unref_delete(attrib);
       }
       }
-    }      
+    }
 
 
     si = (si + 1) % size;
     si = (si + 1) % size;
   } while (si != stop_at_element);
   } while (si != stop_at_element);
@@ -328,12 +328,11 @@ validate_attribs() {
       }
       }
       const RenderAttrib *attrib = _attribs->get_key(si);
       const RenderAttrib *attrib = _attribs->get_key(si);
       cerr << si << ": " << attrib << "\n";
       cerr << si << ": " << attrib << "\n";
-      attrib->get_hash();
       attrib->write(cerr, 2);
       attrib->write(cerr, 2);
     }
     }
 
 
     return false;
     return false;
-  }    
+  }
 
 
   int size = _attribs->get_size();
   int size = _attribs->get_size();
   int si = 0;
   int si = 0;
@@ -391,6 +390,7 @@ CPT(RenderAttrib) RenderAttrib::
 return_new(RenderAttrib *attrib) {
 return_new(RenderAttrib *attrib) {
   nassertr(attrib != (RenderAttrib *)NULL, attrib);
   nassertr(attrib != (RenderAttrib *)NULL, attrib);
   if (!uniquify_attribs) {
   if (!uniquify_attribs) {
+    attrib->calc_hash();
     return attrib;
     return attrib;
   }
   }
 
 
@@ -415,6 +415,8 @@ CPT(RenderAttrib) RenderAttrib::
 return_unique(RenderAttrib *attrib) {
 return_unique(RenderAttrib *attrib) {
   nassertr(attrib != (RenderAttrib *)NULL, attrib);
   nassertr(attrib != (RenderAttrib *)NULL, attrib);
 
 
+  attrib->calc_hash();
+
   if (!state_cache) {
   if (!state_cache) {
     return attrib;
     return attrib;
   }
   }
@@ -442,7 +444,7 @@ return_unique(RenderAttrib *attrib) {
     // There's an equivalent attrib already in the set.  Return it.
     // There's an equivalent attrib already in the set.  Return it.
     return _attribs->get_key(si);
     return _attribs->get_key(si);
   }
   }
-  
+
   // Not already in the set; add it.
   // Not already in the set; add it.
   if (garbage_collect_states) {
   if (garbage_collect_states) {
     // If we'll be garbage collecting attribs explicitly, we'll
     // If we'll be garbage collecting attribs explicitly, we'll
@@ -656,7 +658,7 @@ change_this(TypedWritable *old_ptr, BamReader *manager) {
     pointer->ref();
     pointer->ref();
     manager->register_finalize(attrib);
     manager->register_finalize(attrib);
   }
   }
-  
+
   // We have to cast the pointer back to non-const, because the bam
   // We have to cast the pointer back to non-const, because the bam
   // reader expects that.
   // reader expects that.
   return (RenderAttrib *)pointer.p();
   return (RenderAttrib *)pointer.p();

+ 5 - 2
panda/src/pgraph/renderAttrib.h

@@ -105,7 +105,7 @@ PUBLISHED:
     M_greater,          // incoming > reference_alpha
     M_greater,          // incoming > reference_alpha
     M_not_equal,        // incoming != reference_alpha
     M_not_equal,        // incoming != reference_alpha
     M_greater_equal,    // incoming >= reference_alpha
     M_greater_equal,    // incoming >= reference_alpha
-    M_always            // Always draw.  
+    M_always            // Always draw.
   };
   };
 
 
   // This is the enumerated type for TexGenAttrib.  It is inherited
   // This is the enumerated type for TexGenAttrib.  It is inherited
@@ -181,6 +181,8 @@ PUBLISHED:
   };
   };
 
 
 protected:
 protected:
+  INLINE void calc_hash();
+
   static CPT(RenderAttrib) return_new(RenderAttrib *attrib);
   static CPT(RenderAttrib) return_new(RenderAttrib *attrib);
   static CPT(RenderAttrib) return_unique(RenderAttrib *attrib);
   static CPT(RenderAttrib) return_unique(RenderAttrib *attrib);
   virtual int compare_to_impl(const RenderAttrib *other) const;
   virtual int compare_to_impl(const RenderAttrib *other) const;
@@ -212,6 +214,7 @@ private:
   static Attribs *_attribs;
   static Attribs *_attribs;
 
 
   int _saved_entry;
   int _saved_entry;
+  size_t _hash;
 
 
   // This keeps track of our current position through the garbage
   // This keeps track of our current position through the garbage
   // collection cycle.
   // collection cycle.
@@ -227,7 +230,7 @@ public:
 protected:
 protected:
   static TypedWritable *new_from_bam(RenderAttrib *attrib, BamReader *manager);
   static TypedWritable *new_from_bam(RenderAttrib *attrib, BamReader *manager);
   void fillin(DatagramIterator &scan, BamReader *manager);
   void fillin(DatagramIterator &scan, BamReader *manager);
-  
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 36 - 0
panda/src/pgraph/renderState.I

@@ -51,6 +51,42 @@ has_cull_callback() const {
   return (_flags & F_has_cull_callback) != 0;
   return (_flags & F_has_cull_callback) != 0;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make_empty
+//       Access: Published, Static
+//  Description: Returns a RenderState with no attributes set.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderState) RenderState::
+make_empty() {
+  // The empty state is asked for so often, we make it a special case
+  // and store a pointer forever once we find it the first time.
+  if (_empty_state == (RenderState *)NULL) {
+    RenderState *state = new RenderState;
+    _empty_state = return_unique(state);
+  }
+
+  return _empty_state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make_full_default
+//       Access: Published, Static
+//  Description: Returns a RenderState with all possible attributes
+//               set to their default value.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderState) RenderState::
+make_full_default() {
+  // The empty state is asked for so often, we make it a special case
+  // and store a pointer forever once we find it the first time.
+  if (_full_default_state == (RenderState *)NULL) {
+    RenderState *state = new RenderState;
+    state->fill_default();
+    _full_default_state = return_unique(state);
+  }
+
+  return _full_default_state;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::remove_attrib
 //     Function: RenderState::remove_attrib
 //       Access: Published
 //       Access: Published

+ 0 - 36
panda/src/pgraph/renderState.cxx

@@ -281,42 +281,6 @@ cull_callback(CullTraverser *trav, const CullTraverserData &data) const {
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: RenderState::make_empty
-//       Access: Published, Static
-//  Description: Returns a RenderState with no attributes set.
-////////////////////////////////////////////////////////////////////
-CPT(RenderState) RenderState::
-make_empty() {
-  // The empty state is asked for so often, we make it a special case
-  // and store a pointer forever once we find it the first time.
-  if (_empty_state == (RenderState *)NULL) {
-    RenderState *state = new RenderState;
-    _empty_state = return_unique(state);
-  }
-
-  return _empty_state;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: RenderState::make_full_default
-//       Access: Published, Static
-//  Description: Returns a RenderState with all possible attributes
-//               set to their default value.
-////////////////////////////////////////////////////////////////////
-CPT(RenderState) RenderState::
-make_full_default() {
-  // The empty state is asked for so often, we make it a special case
-  // and store a pointer forever once we find it the first time.
-  if (_full_default_state == (RenderState *)NULL) {
-    RenderState *state = new RenderState;
-    state->fill_default();
-    _full_default_state = return_unique(state);
-  }
-
-  return _full_default_state;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::make
 //     Function: RenderState::make
 //       Access: Published, Static
 //       Access: Published, Static

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

@@ -75,8 +75,8 @@ PUBLISHED:
   INLINE bool has_cull_callback() const;
   INLINE bool has_cull_callback() const;
   bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
   bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
 
 
-  static CPT(RenderState) make_empty();
-  static CPT(RenderState) make_full_default();
+  INLINE static CPT(RenderState) make_empty();
+  INLINE static CPT(RenderState) make_full_default();
   static CPT(RenderState) make(const RenderAttrib *attrib, int override = 0);
   static CPT(RenderState) make(const RenderAttrib *attrib, int override = 0);
   static CPT(RenderState) make(const RenderAttrib *attrib1,
   static CPT(RenderState) make(const RenderAttrib *attrib1,
                                const RenderAttrib *attrib2, int override = 0);
                                const RenderAttrib *attrib2, int override = 0);

+ 1 - 1
panda/src/pgraph/texMatrixAttrib.cxx

@@ -62,7 +62,7 @@ CPT(RenderAttrib) TexMatrixAttrib::
 make(const LMatrix4 &mat) {
 make(const LMatrix4 &mat) {
   pgraph_cat.warning()
   pgraph_cat.warning()
     << "Using deprecated TexMatrixAttrib interface.\n";
     << "Using deprecated TexMatrixAttrib interface.\n";
-  if (mat == LMatrix4::ident_mat()) {
+  if (mat.is_identity()) {
     return make();
     return make();
   }
   }
   CPT(TransformState) transform = TransformState::make_mat(mat);
   CPT(TransformState) transform = TransformState::make_mat(mat);

+ 22 - 20
panda/src/pgraph/transformState.I

@@ -14,15 +14,13 @@
 
 
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TransformState::operator <
+//     Function: TransformState::operator !=
 //       Access: Published
 //       Access: Published
-//  Description: Provides an arbitrary ordering among all unique
-//               TransformStates, so we can store the essentially
-//               different ones in a big set and throw away the rest.
+//  Description: Opposite of operator ==.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool TransformState::
 INLINE bool TransformState::
-operator < (const TransformState &other) const {
-  return compare_to(other) < 0;
+operator != (const TransformState &other) const {
+  return !(operator == (other));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -31,10 +29,14 @@ operator < (const TransformState &other) const {
 //  Description: Provides an arbitrary ordering among all unique
 //  Description: Provides an arbitrary ordering among all unique
 //               TransformStates, so we can store the essentially
 //               TransformStates, so we can store the essentially
 //               different ones in a big set and throw away the rest.
 //               different ones in a big set and throw away the rest.
+//
+//               Note that if this returns 0, it doesn't necessarily
+//               imply that operator == returns true; it uses a very
+//               slightly different comparison threshold.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int TransformState::
 INLINE int TransformState::
 compare_to(const TransformState &other) const {
 compare_to(const TransformState &other) const {
-  return compare_to(other, uniquify_matrix);
+  return compare_to(other, _uniquify_matrix);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -56,7 +58,7 @@ get_hash() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
 make_pos(const LVecBase3 &pos) {
 make_pos(const LVecBase3 &pos) {
-  return make_pos_hpr_scale(pos, 
+  return make_pos_hpr_scale(pos,
                             LVecBase3(0.0f, 0.0f, 0.0f),
                             LVecBase3(0.0f, 0.0f, 0.0f),
                             LVecBase3(1.0f, 1.0f, 1.0f));
                             LVecBase3(1.0f, 1.0f, 1.0f));
 }
 }
@@ -70,7 +72,7 @@ make_pos(const LVecBase3 &pos) {
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
 make_hpr(const LVecBase3 &hpr) {
 make_hpr(const LVecBase3 &hpr) {
   return make_pos_hpr_scale(LVecBase3(0.0f, 0.0f, 0.0f),
   return make_pos_hpr_scale(LVecBase3(0.0f, 0.0f, 0.0f),
-                            hpr, 
+                            hpr,
                             LVecBase3(1.0f, 1.0f, 1.0f));
                             LVecBase3(1.0f, 1.0f, 1.0f));
 }
 }
 
 
@@ -83,7 +85,7 @@ make_hpr(const LVecBase3 &hpr) {
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
 make_quat(const LQuaternion &quat) {
 make_quat(const LQuaternion &quat) {
   return make_pos_quat_scale(LVecBase3(0.0f, 0.0f, 0.0f),
   return make_pos_quat_scale(LVecBase3(0.0f, 0.0f, 0.0f),
-                             quat, 
+                             quat,
                              LVecBase3(1.0f, 1.0f, 1.0f));
                              LVecBase3(1.0f, 1.0f, 1.0f));
 }
 }
 
 
@@ -146,7 +148,7 @@ make_shear(const LVecBase3 &shear) {
 //               components.
 //               components.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
-make_pos_hpr_scale(const LVecBase3 &pos, const LVecBase3 &hpr, 
+make_pos_hpr_scale(const LVecBase3 &pos, const LVecBase3 &hpr,
                    const LVecBase3 &scale) {
                    const LVecBase3 &scale) {
   return make_pos_hpr_scale_shear(pos, hpr, scale, LVecBase3::zero());
   return make_pos_hpr_scale_shear(pos, hpr, scale, LVecBase3::zero());
 }
 }
@@ -158,7 +160,7 @@ make_pos_hpr_scale(const LVecBase3 &pos, const LVecBase3 &hpr,
 //               components.
 //               components.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
-make_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat, 
+make_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat,
                     const LVecBase3 &scale) {
                     const LVecBase3 &scale) {
   return make_pos_quat_scale_shear(pos, quat, scale, LVecBase3::zero());
   return make_pos_quat_scale_shear(pos, quat, scale, LVecBase3::zero());
 }
 }
@@ -182,7 +184,7 @@ make_pos2d(const LVecBase2 &pos) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
 make_rotate2d(PN_stdfloat rotate) {
 make_rotate2d(PN_stdfloat rotate) {
-  return make_pos_rotate_scale2d(LVecBase2(0.0f, 0.0f), rotate, 
+  return make_pos_rotate_scale2d(LVecBase2(0.0f, 0.0f), rotate,
                                  LVecBase2(1.0f, 1.0f));
                                  LVecBase2(1.0f, 1.0f));
 }
 }
 
 
@@ -229,7 +231,7 @@ make_scale2d(const LVecBase2 &scale) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
 make_shear2d(PN_stdfloat shear) {
 make_shear2d(PN_stdfloat shear) {
-  return make_pos_rotate_scale_shear2d(LVecBase2(0.0f, 0.0f), 0.0f, 
+  return make_pos_rotate_scale_shear2d(LVecBase2(0.0f, 0.0f), 0.0f,
                                        LVecBase2(1.0f, 1.0f), shear);
                                        LVecBase2(1.0f, 1.0f), shear);
 }
 }
 
 
@@ -240,7 +242,7 @@ make_shear2d(PN_stdfloat shear) {
 //               components.
 //               components.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(TransformState) TransformState::
 INLINE CPT(TransformState) TransformState::
-make_pos_rotate_scale2d(const LVecBase2 &pos, PN_stdfloat rotate, 
+make_pos_rotate_scale2d(const LVecBase2 &pos, PN_stdfloat rotate,
                         const LVecBase2 &scale) {
                         const LVecBase2 &scale) {
   return make_pos_rotate_scale_shear2d(pos, rotate, scale, 0.0f);
   return make_pos_rotate_scale_shear2d(pos, rotate, scale, 0.0f);
 }
 }
@@ -353,7 +355,7 @@ hpr_given() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::quat_given
 //     Function: TransformState::quat_given
 //       Access: Published
 //       Access: Published
-//  Description: Returns true if the rotation was specified via a 
+//  Description: Returns true if the rotation was specified via a
 //               quaternion, false otherwise.  If this is true,
 //               quaternion, false otherwise.  If this is true,
 //               get_quat() will be exactly as set; otherwise, it will
 //               get_quat() will be exactly as set; otherwise, it will
 //               return a computed value.
 //               return a computed value.
@@ -1142,7 +1144,7 @@ calc_mat() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformState::
 INLINE void TransformState::
 check_uniform_scale() {
 check_uniform_scale() {
-  if (IS_NEARLY_EQUAL(_scale[0], _scale[1]) && 
+  if (IS_NEARLY_EQUAL(_scale[0], _scale[1]) &&
       IS_NEARLY_EQUAL(_scale[0], _scale[2])) {
       IS_NEARLY_EQUAL(_scale[0], _scale[2])) {
     _flags |= F_uniform_scale;
     _flags |= F_uniform_scale;
     if (IS_NEARLY_EQUAL(_scale[0], 1.0f)) {
     if (IS_NEARLY_EQUAL(_scale[0], 1.0f)) {
@@ -1234,7 +1236,7 @@ consider_update_pstats(int old_referenced_bits) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::Composition::Constructor
 //     Function: TransformState::Composition::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE TransformState::Composition::
 INLINE TransformState::Composition::
 Composition() {
 Composition() {
@@ -1243,7 +1245,7 @@ Composition() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::Composition::Copy Constructor
 //     Function: TransformState::Composition::Copy Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE TransformState::Composition::
 INLINE TransformState::Composition::
 Composition(const TransformState::Composition &copy) :
 Composition(const TransformState::Composition &copy) :
@@ -1254,7 +1256,7 @@ Composition(const TransformState::Composition &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::CompositionCycleDescEntry::Constructor
 //     Function: TransformState::CompositionCycleDescEntry::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE TransformState::CompositionCycleDescEntry::
 INLINE TransformState::CompositionCycleDescEntry::
 CompositionCycleDescEntry(const TransformState *obj,
 CompositionCycleDescEntry(const TransformState *obj,

+ 135 - 54
panda/src/pgraph/transformState.cxx

@@ -32,6 +32,7 @@ CPT(TransformState) TransformState::_identity_state;
 CPT(TransformState) TransformState::_invalid_state;
 CPT(TransformState) TransformState::_invalid_state;
 UpdateSeq TransformState::_last_cycle_detect;
 UpdateSeq TransformState::_last_cycle_detect;
 int TransformState::_garbage_index = 0;
 int TransformState::_garbage_index = 0;
+bool TransformState::_uniquify_matrix = true;
 
 
 PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update");
 PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update");
 PStatCollector TransformState::_garbage_collect_pcollector("*:State Cache:Garbage Collect");
 PStatCollector TransformState::_garbage_collect_pcollector("*:State Cache:Garbage Collect");
@@ -98,7 +99,7 @@ TransformState::
   // We'd better not call the destructor twice on a particular object.
   // We'd better not call the destructor twice on a particular object.
   nassertv(!is_destructing());
   nassertv(!is_destructing());
   set_destructing();
   set_destructing();
- 
+
   // Free the inverse matrix computation, if it has been stored.
   // Free the inverse matrix computation, if it has been stored.
   if (_inv_mat != (LMatrix4 *)NULL) {
   if (_inv_mat != (LMatrix4 *)NULL) {
     delete _inv_mat;
     delete _inv_mat;
@@ -124,6 +125,10 @@ TransformState::
 //               TransformStates, so we can store the essentially
 //               TransformStates, so we can store the essentially
 //               different ones in a big set and throw away the rest.
 //               different ones in a big set and throw away the rest.
 //
 //
+//               Note that if this returns 0, it doesn't necessarily
+//               imply that operator == returns true; it uses a very
+//               slightly different comparison threshold.
+//
 //               If uniquify_matrix is true, then matrix-defined
 //               If uniquify_matrix is true, then matrix-defined
 //               TransformStates are also uniqified.  If
 //               TransformStates are also uniqified.  If
 //               uniquify_matrix is false, then only component-defined
 //               uniquify_matrix is false, then only component-defined
@@ -132,7 +137,7 @@ TransformState::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int TransformState::
 int TransformState::
 compare_to(const TransformState &other, bool uniquify_matrix) const {
 compare_to(const TransformState &other, bool uniquify_matrix) const {
-  static const int significant_flags = 
+  static const int significant_flags =
     (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d);
     (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d);
 
 
   int flags = (_flags & significant_flags);
   int flags = (_flags & significant_flags);
@@ -191,6 +196,73 @@ compare_to(const TransformState &other, bool uniquify_matrix) const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::operator ==
+//       Access: Published
+//  Description: Tests equivalence between two transform states.
+//               We use this instead of compare_to since this is
+//               faster, and we don't need an ordering between
+//               TransformStates because we use a hash map.
+//
+//               If uniquify_matrix is true, then matrix-defined
+//               TransformStates are also uniqified.  If
+//               uniquify_matrix is false, then only component-defined
+//               TransformStates are uniquified, which is less
+//               expensive.
+////////////////////////////////////////////////////////////////////
+bool TransformState::
+operator == (const TransformState &other) const {
+  static const int significant_flags =
+    (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d);
+
+  int flags = (_flags & significant_flags);
+  int other_flags = (other._flags & significant_flags);
+  if (flags != other_flags) {
+    return false;
+  }
+
+  if ((_flags & (F_is_invalid | F_is_identity)) != 0) {
+    // All invalid transforms are equivalent to each other, and all
+    // identity transforms are equivalent to each other.
+    return true;
+  }
+
+  if ((_flags & F_components_given) != 0) {
+    // If the transform was specified componentwise, compare them
+    // componentwise.
+    if (_pos != other._pos) {
+      return false;
+    }
+
+    if ((_flags & F_hpr_given) != 0) {
+      if (_hpr != other._hpr) {
+        return false;
+      }
+    } else if ((_flags & F_quat_given) != 0) {
+      if (_quat != other._quat) {
+        return false;
+      }
+    }
+
+    if (_scale != other._scale) {
+      return false;
+    }
+
+    return (_shear == other._shear);
+  }
+
+  // Otherwise, compare the matrices . . .
+  if (_uniquify_matrix) {
+    // . . . but only if the user thinks that's a worthwhile
+    // comparison.
+    return get_mat().almost_equal(other.get_mat());
+
+  } else {
+    // If not, we just compare the pointers.
+    return (this == &other);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::make_identity
 //     Function: TransformState::make_identity
 //       Access: Published, Static
 //       Access: Published, Static
@@ -232,7 +304,7 @@ make_invalid() {
 //               components.
 //               components.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) TransformState::
 CPT(TransformState) TransformState::
-make_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr, 
+make_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr,
                          const LVecBase3 &scale, const LVecBase3 &shear) {
                          const LVecBase3 &scale, const LVecBase3 &shear) {
   nassertr(!(pos.is_nan() || hpr.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
   nassertr(!(pos.is_nan() || hpr.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
   // Make a special-case check for the identity transform.
   // Make a special-case check for the identity transform.
@@ -260,7 +332,7 @@ make_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr,
 //               components.
 //               components.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(TransformState) TransformState::
 CPT(TransformState) TransformState::
-make_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat, 
+make_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat,
                           const LVecBase3 &scale, const LVecBase3 &shear) {
                           const LVecBase3 &scale, const LVecBase3 &shear) {
   nassertr(!(pos.is_nan() || quat.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
   nassertr(!(pos.is_nan() || quat.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
   // Make a special-case check for the identity transform.
   // Make a special-case check for the identity transform.
@@ -291,7 +363,7 @@ CPT(TransformState) TransformState::
 make_mat(const LMatrix4 &mat) {
 make_mat(const LMatrix4 &mat) {
   nassertr(!mat.is_nan(), make_invalid());
   nassertr(!mat.is_nan(), make_invalid());
   // Make a special-case check for the identity matrix.
   // Make a special-case check for the identity matrix.
-  if (mat == LMatrix4::ident_mat()) {
+  if (mat.is_identity()) {
     return make_identity();
     return make_identity();
   }
   }
 
 
@@ -301,7 +373,6 @@ make_mat(const LMatrix4 &mat) {
   return return_new(state);
   return return_new(state);
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::make_pos_rotate_scale_shear2d
 //     Function: TransformState::make_pos_rotate_scale_shear2d
 //       Access: Published, Static
 //       Access: Published, Static
@@ -356,7 +427,7 @@ CPT(TransformState) TransformState::
 make_mat3(const LMatrix3 &mat) {
 make_mat3(const LMatrix3 &mat) {
   nassertr(!mat.is_nan(), make_invalid());
   nassertr(!mat.is_nan(), make_invalid());
   // Make a special-case check for the identity matrix.
   // Make a special-case check for the identity matrix.
-  if (mat == LMatrix3::ident_mat()) {
+  if (mat.is_identity()) {
     return make_identity();
     return make_identity();
   }
   }
 
 
@@ -529,7 +600,7 @@ set_rotate2d(PN_stdfloat rotate) const {
     }
     }
   }
   }
 
 
-  return make_pos_rotate_scale_shear2d(get_pos2d(), rotate, get_scale2d(), 
+  return make_pos_rotate_scale_shear2d(get_pos2d(), rotate, get_scale2d(),
                                        get_shear2d());
                                        get_shear2d());
 }
 }
 
 
@@ -592,7 +663,7 @@ compose(const TransformState *other) const {
   if (other->is_identity()) {
   if (other->is_identity()) {
     return this;
     return this;
   }
   }
- 
+
   // If either transform is invalid, the result is invalid.
   // If either transform is invalid, the result is invalid.
   if (is_invalid()) {
   if (is_invalid()) {
     return this;
     return this;
@@ -754,7 +825,7 @@ unref() const {
   // it and tries to ref it.
   // it and tries to ref it.
   ((TransformState *)this)->release_new();
   ((TransformState *)this)->release_new();
   ((TransformState *)this)->remove_cache_pointers();
   ((TransformState *)this)->remove_cache_pointers();
-  
+
   return false;
   return false;
 }
 }
 
 
@@ -821,7 +892,7 @@ validate_composition_cache() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::output
 //     Function: TransformState::output
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformState::
 void TransformState::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -913,7 +984,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::write
 //     Function: TransformState::write
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformState::
 void TransformState::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
@@ -1037,7 +1108,7 @@ get_num_unused_states() {
 
 
       if (pgraph_cat.is_debug()) {
       if (pgraph_cat.is_debug()) {
         pgraph_cat.debug()
         pgraph_cat.debug()
-          << "Unused state: " << (void *)state << ":" 
+          << "Unused state: " << (void *)state << ":"
           << state->get_ref_count() << " =\n";
           << state->get_ref_count() << " =\n";
         state->write(pgraph_cat.debug(false), 2);
         state->write(pgraph_cat.debug(false), 2);
       }
       }
@@ -1167,7 +1238,7 @@ garbage_collect() {
   }
   }
   num_this_pass = min(num_this_pass, size);
   num_this_pass = min(num_this_pass, size);
   int stop_at_element = (_garbage_index + num_this_pass) % size;
   int stop_at_element = (_garbage_index + num_this_pass) % size;
-  
+
   int num_elements = 0;
   int num_elements = 0;
   int si = _garbage_index;
   int si = _garbage_index;
   do {
   do {
@@ -1197,8 +1268,8 @@ garbage_collect() {
         state->cache_unref();
         state->cache_unref();
         delete state;
         delete state;
       }
       }
-    }      
-    
+    }
+
     si = (si + 1) % size;
     si = (si + 1) % size;
   } while (si != stop_at_element);
   } while (si != stop_at_element);
   _garbage_index = si;
   _garbage_index = si;
@@ -1276,7 +1347,7 @@ list_cycles(ostream &out) {
         if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
         if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
           // This state begins a cycle.
           // This state begins a cycle.
           CompositionCycleDesc::iterator csi;
           CompositionCycleDesc::iterator csi;
-          
+
           out << "\nReverse cycle detected of length " << cycle_desc.size() + 1 << ":\n"
           out << "\nReverse cycle detected of length " << cycle_desc.size() + 1 << ":\n"
               << "state ";
               << "state ";
           for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
           for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
@@ -1292,7 +1363,7 @@ list_cycles(ostream &out) {
           out << (void *)state << ":"
           out << (void *)state << ":"
               << state->get_ref_count() << " =\n";
               << state->get_ref_count() << " =\n";
           state->write(out, 2);
           state->write(out, 2);
-          
+
           cycle_desc.clear();
           cycle_desc.clear();
         }
         }
       }
       }
@@ -1355,7 +1426,7 @@ validate_states() {
     pgraph_cat.error()
     pgraph_cat.error()
       << "TransformState::_states cache is invalid!\n";
       << "TransformState::_states cache is invalid!\n";
     return false;
     return false;
-  }    
+  }
 
 
   int size = _states->get_size();
   int size = _states->get_size();
   int si = 0;
   int si = 0;
@@ -1376,13 +1447,11 @@ validate_states() {
       return false;
       return false;
     }
     }
     const TransformState *ssnext = _states->get_key(snext);
     const TransformState *ssnext = _states->get_key(snext);
-    int c = ssi->compare_to(*ssnext);
-    int ci = ssnext->compare_to(*ssi);
-    if ((ci < 0) != (c > 0) ||
-        (ci > 0) != (c < 0) ||
-        (ci == 0) != (c == 0)) {
+    bool c = (*ssi) == (*ssnext);
+    bool ci = (*ssnext) == (*ssi);
+    if (c != ci) {
       pgraph_cat.error()
       pgraph_cat.error()
-        << "TransformState::compare_to() not defined properly!\n";
+        << "TransformState::operator == () not defined properly!\n";
       pgraph_cat.error(false)
       pgraph_cat.error(false)
         << "(a, b): " << c << "\n";
         << "(a, b): " << c << "\n";
       pgraph_cat.error(false)
       pgraph_cat.error(false)
@@ -1415,6 +1484,18 @@ void TransformState::
 init_states() {
 init_states() {
   _states = new States;
   _states = new States;
 
 
+  ConfigVariableBool uniquify_matrix
+  ("uniquify-matrix", true,
+   PRC_DESC("Set this true to look up arbitrary 4x4 transform matrices in "
+            "the cache, to ensure that two differently-computed transforms "
+            "that happen to encode the same matrix will be collapsed into "
+            "a single pointer.  Nowadays, with the transforms stored in a "
+            "hashtable, we're generally better off with this set true."));
+
+  // Store this at the beginning, so that we don't have to query this
+  // every time that the comparison operator is invoked.
+  _uniquify_matrix = uniquify_matrix;
+
   // TODO: we should have a global Panda mutex to allow us to safely
   // TODO: we should have a global Panda mutex to allow us to safely
   // create _states_lock without a startup race condition.  For the
   // create _states_lock without a startup race condition.  For the
   // meantime, this is OK because we guarantee that this method is
   // meantime, this is OK because we guarantee that this method is
@@ -1424,7 +1505,7 @@ init_states() {
   _cache_stats.init();
   _cache_stats.init();
   nassertv(Thread::get_current_thread() == Thread::get_main_thread());
   nassertv(Thread::get_current_thread() == Thread::get_main_thread());
 }
 }
-  
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::return_new
 //     Function: TransformState::return_new
 //       Access: Private, Static
 //       Access: Private, Static
@@ -1519,8 +1600,8 @@ do_compose(const TransformState *other) const {
   nassertr((_flags & F_is_invalid) == 0, this);
   nassertr((_flags & F_is_invalid) == 0, this);
   nassertr((other->_flags & F_is_invalid) == 0, other);
   nassertr((other->_flags & F_is_invalid) == 0, other);
 
 
-  if (compose_componentwise && 
-      has_uniform_scale() && 
+  if (compose_componentwise &&
+      has_uniform_scale() &&
       !has_nonzero_shear() && !other->has_nonzero_shear() &&
       !has_nonzero_shear() && !other->has_nonzero_shear() &&
       ((components_given() && other->has_components()) ||
       ((components_given() && other->has_components()) ||
        (other->components_given() && has_components()))) {
        (other->components_given() && has_components()))) {
@@ -1541,7 +1622,7 @@ do_compose(const TransformState *other) const {
 
 
       rotate += other->get_rotate2d();
       rotate += other->get_rotate2d();
       LVecBase2 new_scale = other->get_scale2d() * scale;
       LVecBase2 new_scale = other->get_scale2d() * scale;
-      
+
       result = make_pos_rotate_scale2d(pos, rotate, new_scale);
       result = make_pos_rotate_scale2d(pos, rotate, new_scale);
 
 
     } else {
     } else {
@@ -1549,14 +1630,14 @@ do_compose(const TransformState *other) const {
       LVecBase3 pos = get_pos();
       LVecBase3 pos = get_pos();
       LQuaternion quat = get_norm_quat();
       LQuaternion quat = get_norm_quat();
       PN_stdfloat scale = get_uniform_scale();
       PN_stdfloat scale = get_uniform_scale();
-      
+
       pos += quat.xform(other->get_pos()) * scale;
       pos += quat.xform(other->get_pos()) * scale;
       quat = other->get_norm_quat() * quat;
       quat = other->get_norm_quat() * quat;
       LVecBase3 new_scale = other->get_scale() * scale;
       LVecBase3 new_scale = other->get_scale() * scale;
-      
+
       result = make_pos_quat_scale(pos, quat, new_scale);
       result = make_pos_quat_scale(pos, quat, new_scale);
     }
     }
-      
+
 #ifndef NDEBUG
 #ifndef NDEBUG
     if (paranoid_compose) {
     if (paranoid_compose) {
       // Now verify against the matrix.
       // Now verify against the matrix.
@@ -1653,7 +1734,7 @@ store_compose(const TransformState *other, const TransformState *result) {
     // to decrement it again later, when the composition entry is
     // to decrement it again later, when the composition entry is
     // removed from the cache.
     // removed from the cache.
     result->cache_ref();
     result->cache_ref();
-    
+
     // (If the result was just this again, we still store the
     // (If the result was just this again, we still store the
     // result, but we don't increment the reference count, since
     // result, but we don't increment the reference count, since
     // that would be a self-referential leak.)
     // that would be a self-referential leak.)
@@ -1730,7 +1811,7 @@ store_invert_compose(const TransformState *other, const TransformState *result)
     // to decrement it again later, when the composition entry is
     // to decrement it again later, when the composition entry is
     // removed from the cache.
     // removed from the cache.
     result->cache_ref();
     result->cache_ref();
-    
+
     // (If the result was just this again, we still store the
     // (If the result was just this again, we still store the
     // result, but we don't increment the reference count, since
     // result, but we don't increment the reference count, since
     // that would be a self-referential leak.)
     // that would be a self-referential leak.)
@@ -1751,8 +1832,8 @@ do_invert_compose(const TransformState *other) const {
   nassertr((_flags & F_is_invalid) == 0, this);
   nassertr((_flags & F_is_invalid) == 0, this);
   nassertr((other->_flags & F_is_invalid) == 0, other);
   nassertr((other->_flags & F_is_invalid) == 0, other);
 
 
-  if (compose_componentwise && 
-      has_uniform_scale() && 
+  if (compose_componentwise &&
+      has_uniform_scale() &&
       !has_nonzero_shear() && !other->has_nonzero_shear() &&
       !has_nonzero_shear() && !other->has_nonzero_shear() &&
       ((components_given() && other->has_components()) ||
       ((components_given() && other->has_components()) ||
        (other->components_given() && has_components()))) {
        (other->components_given() && has_components()))) {
@@ -1767,7 +1848,7 @@ do_invert_compose(const TransformState *other) const {
       PN_stdfloat rotate = get_rotate2d();
       PN_stdfloat rotate = get_rotate2d();
       LQuaternion quat = get_norm_quat();
       LQuaternion quat = get_norm_quat();
       PN_stdfloat scale = get_uniform_scale();
       PN_stdfloat scale = get_uniform_scale();
-      
+
       // First, invert our own transform.
       // First, invert our own transform.
       if (scale == 0.0f) {
       if (scale == 0.0f) {
         ((TransformState *)this)->_flags |= F_is_singular | F_singular_known;
         ((TransformState *)this)->_flags |= F_is_singular | F_singular_known;
@@ -1779,7 +1860,7 @@ do_invert_compose(const TransformState *other) const {
       LVecBase3 mp = quat.xform(-LVecBase3(pos[0], pos[1], 0.0f));
       LVecBase3 mp = quat.xform(-LVecBase3(pos[0], pos[1], 0.0f));
       pos = LVecBase2(mp[0], mp[1]) * scale;
       pos = LVecBase2(mp[0], mp[1]) * scale;
       LVecBase2 new_scale(scale, scale);
       LVecBase2 new_scale(scale, scale);
-      
+
       // Now compose the inverted transform with the other transform.
       // Now compose the inverted transform with the other transform.
       if (!other->is_identity()) {
       if (!other->is_identity()) {
         LPoint3 op = quat.xform(other->get_pos());
         LPoint3 op = quat.xform(other->get_pos());
@@ -1796,7 +1877,7 @@ do_invert_compose(const TransformState *other) const {
       LVecBase3 pos = get_pos();
       LVecBase3 pos = get_pos();
       LQuaternion quat = get_norm_quat();
       LQuaternion quat = get_norm_quat();
       PN_stdfloat scale = get_uniform_scale();
       PN_stdfloat scale = get_uniform_scale();
-      
+
       // First, invert our own transform.
       // First, invert our own transform.
       if (scale == 0.0f) {
       if (scale == 0.0f) {
         ((TransformState *)this)->_flags |= F_is_singular | F_singular_known;
         ((TransformState *)this)->_flags |= F_is_singular | F_singular_known;
@@ -1806,7 +1887,7 @@ do_invert_compose(const TransformState *other) const {
       quat.invert_in_place();
       quat.invert_in_place();
       pos = quat.xform(-pos) * scale;
       pos = quat.xform(-pos) * scale;
       LVecBase3 new_scale(scale, scale, scale);
       LVecBase3 new_scale(scale, scale, scale);
-      
+
       // Now compose the inverted transform with the other transform.
       // Now compose the inverted transform with the other transform.
       if (!other->is_identity()) {
       if (!other->is_identity()) {
         pos += quat.xform(other->get_pos()) * scale;
         pos += quat.xform(other->get_pos()) * scale;
@@ -1879,7 +1960,7 @@ do_invert_compose(const TransformState *other) const {
 void TransformState::
 void TransformState::
 detect_and_break_cycles() {
 detect_and_break_cycles() {
   PStatTimer timer(_transform_break_cycles_pcollector);
   PStatTimer timer(_transform_break_cycles_pcollector);
-  
+
   ++_last_cycle_detect;
   ++_last_cycle_detect;
   if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) {
   if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) {
     // Ok, we have a cycle.  This will be a leak unless we break the
     // Ok, we have a cycle.  This will be a leak unless we break the
@@ -1888,7 +1969,7 @@ detect_and_break_cycles() {
       pgraph_cat.debug()
       pgraph_cat.debug()
         << "Breaking cycle involving " << (*this) << "\n";
         << "Breaking cycle involving " << (*this) << "\n";
     }
     }
-    
+
     remove_cache_pointers();
     remove_cache_pointers();
   } else {
   } else {
     ++_last_cycle_detect;
     ++_last_cycle_detect;
@@ -1897,7 +1978,7 @@ detect_and_break_cycles() {
         pgraph_cat.debug()
         pgraph_cat.debug()
           << "Breaking cycle involving " << (*this) << "\n";
           << "Breaking cycle involving " << (*this) << "\n";
       }
       }
-      
+
       remove_cache_pointers();
       remove_cache_pointers();
     }
     }
   }
   }
@@ -1936,7 +2017,7 @@ r_detect_cycles(const TransformState *start_state,
     if (current_state->_composition_cache.has_element(i)) {
     if (current_state->_composition_cache.has_element(i)) {
       const TransformState *result = current_state->_composition_cache.get_data(i)._result;
       const TransformState *result = current_state->_composition_cache.get_data(i)._result;
       if (result != (const TransformState *)NULL) {
       if (result != (const TransformState *)NULL) {
-        if (r_detect_cycles(start_state, result, length + 1, 
+        if (r_detect_cycles(start_state, result, length + 1,
                             this_seq, cycle_desc)) {
                             this_seq, cycle_desc)) {
           // Cycle detected.
           // Cycle detected.
           if (cycle_desc != (CompositionCycleDesc *)NULL) {
           if (cycle_desc != (CompositionCycleDesc *)NULL) {
@@ -2008,7 +2089,7 @@ r_detect_reverse_cycles(const TransformState *start_state,
 
 
         const TransformState *result = other->_composition_cache.get_data(oi)._result;
         const TransformState *result = other->_composition_cache.get_data(oi)._result;
         if (result != (const TransformState *)NULL) {
         if (result != (const TransformState *)NULL) {
-          if (r_detect_reverse_cycles(start_state, result, length + 1, 
+          if (r_detect_reverse_cycles(start_state, result, length + 1,
                                       this_seq, cycle_desc)) {
                                       this_seq, cycle_desc)) {
             // Cycle detected.
             // Cycle detected.
             if (cycle_desc != (CompositionCycleDesc *)NULL) {
             if (cycle_desc != (CompositionCycleDesc *)NULL) {
@@ -2033,7 +2114,7 @@ r_detect_reverse_cycles(const TransformState *start_state,
 
 
         const TransformState *result = other->_invert_composition_cache.get_data(oi)._result;
         const TransformState *result = other->_invert_composition_cache.get_data(oi)._result;
         if (result != (const TransformState *)NULL) {
         if (result != (const TransformState *)NULL) {
-          if (r_detect_reverse_cycles(start_state, result, length + 1, 
+          if (r_detect_reverse_cycles(start_state, result, length + 1,
                                       this_seq, cycle_desc)) {
                                       this_seq, cycle_desc)) {
             // Cycle detected.
             // Cycle detected.
             if (cycle_desc != (CompositionCycleDesc *)NULL) {
             if (cycle_desc != (CompositionCycleDesc *)NULL) {
@@ -2065,7 +2146,7 @@ r_detect_reverse_cycles(const TransformState *start_state,
 void TransformState::
 void TransformState::
 release_new() {
 release_new() {
   nassertv(_states_lock->debug_is_locked());
   nassertv(_states_lock->debug_is_locked());
-   
+
   if (_saved_entry != -1) {
   if (_saved_entry != -1) {
     //nassertv(_states->find(this) == _saved_entry);
     //nassertv(_states->find(this) == _saved_entry);
     _saved_entry = _states->find(this);
     _saved_entry = _states->find(this);
@@ -2088,7 +2169,7 @@ release_new() {
 void TransformState::
 void TransformState::
 remove_cache_pointers() {
 remove_cache_pointers() {
   nassertv(_states_lock->debug_is_locked());
   nassertv(_states_lock->debug_is_locked());
-   
+
   // Fortunately, since we added CompositionCache records in pairs, we
   // Fortunately, since we added CompositionCache records in pairs, we
   // know exactly the set of TransformState objects that have us in their
   // know exactly the set of TransformState objects that have us in their
   // cache: it's the same set of TransformState objects that we have in
   // cache: it's the same set of TransformState objects that we have in
@@ -2150,11 +2231,11 @@ remove_cache_pointers() {
       if (oi != -1) {
       if (oi != -1) {
         // Hold a copy of the other composition result, too.
         // Hold a copy of the other composition result, too.
         Composition ocomp = other->_composition_cache.get_data(oi);
         Composition ocomp = other->_composition_cache.get_data(oi);
-        
+
         other->_composition_cache.remove_element(oi);
         other->_composition_cache.remove_element(oi);
         _cache_stats.add_total_size(-1);
         _cache_stats.add_total_size(-1);
         _cache_stats.inc_dels();
         _cache_stats.inc_dels();
-        
+
         // It's finally safe to let our held pointers go away.  This may
         // It's finally safe to let our held pointers go away.  This may
         // have cascading effects as other TransformState objects are
         // have cascading effects as other TransformState objects are
         // destructed, but there will be no harm done if they destruct
         // destructed, but there will be no harm done if they destruct
@@ -2213,7 +2294,7 @@ do_calc_hash() {
   PStatTimer timer(_transform_hash_pcollector);
   PStatTimer timer(_transform_hash_pcollector);
   _hash = 0;
   _hash = 0;
 
 
-  static const int significant_flags = 
+  static const int significant_flags =
     (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d);
     (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d);
 
 
   int flags = (_flags & significant_flags);
   int flags = (_flags & significant_flags);
@@ -2222,7 +2303,7 @@ do_calc_hash() {
   if ((_flags & (F_is_invalid | F_is_identity)) == 0) {
   if ((_flags & (F_is_invalid | F_is_identity)) == 0) {
     // Only bother to put the rest of the stuff in the hash if the
     // Only bother to put the rest of the stuff in the hash if the
     // transform is not invalid or empty.
     // transform is not invalid or empty.
-    
+
     if ((_flags & F_components_given) != 0) {
     if ((_flags & F_components_given) != 0) {
       // If the transform was specified componentwise, hash it
       // If the transform was specified componentwise, hash it
       // componentwise.
       // componentwise.
@@ -2239,7 +2320,7 @@ do_calc_hash() {
 
 
     } else {
     } else {
       // Otherwise, hash the matrix . . .
       // Otherwise, hash the matrix . . .
-      if (uniquify_matrix) {
+      if (_uniquify_matrix) {
         // . . . but only if the user thinks that's worthwhile.
         // . . . but only if the user thinks that's worthwhile.
         if ((_flags & F_mat_known) == 0) {
         if ((_flags & F_mat_known) == 0) {
           // Calculate the matrix without doubly-locking.
           // Calculate the matrix without doubly-locking.
@@ -2556,7 +2637,7 @@ change_this(TypedWritableReferenceCount *old_ptr, BamReader *manager) {
   // First, uniquify the pointer.
   // First, uniquify the pointer.
   TransformState *state = DCAST(TransformState, old_ptr);
   TransformState *state = DCAST(TransformState, old_ptr);
   CPT(TransformState) pointer = return_unique(state);
   CPT(TransformState) pointer = return_unique(state);
-  
+
   // We have to cast the pointer back to non-const, because the bam
   // We have to cast the pointer back to non-const, because the bam
   // reader expects that.
   // reader expects that.
   return (TransformState *)pointer.p();
   return (TransformState *)pointer.p();

+ 13 - 10
panda/src/pgraph/transformState.h

@@ -72,9 +72,10 @@ public:
   ALLOC_DELETED_CHAIN(TransformState);
   ALLOC_DELETED_CHAIN(TransformState);
 
 
 PUBLISHED:
 PUBLISHED:
-  INLINE bool operator < (const TransformState &other) const;
+  INLINE bool operator != (const TransformState &other) const;
   INLINE int compare_to(const TransformState &other) const;
   INLINE int compare_to(const TransformState &other) const;
   int compare_to(const TransformState &other, bool uniquify_matrix) const;
   int compare_to(const TransformState &other, bool uniquify_matrix) const;
+  bool operator == (const TransformState &other) const;
   INLINE size_t get_hash() const;
   INLINE size_t get_hash() const;
 
 
   static CPT(TransformState) make_identity();
   static CPT(TransformState) make_identity();
@@ -88,17 +89,17 @@ PUBLISHED:
   INLINE static CPT(TransformState) make_scale(const LVecBase3 &scale);
   INLINE static CPT(TransformState) make_scale(const LVecBase3 &scale);
   INLINE static CPT(TransformState) make_shear(const LVecBase3 &shear);
   INLINE static CPT(TransformState) make_shear(const LVecBase3 &shear);
   INLINE static CPT(TransformState) make_pos_hpr_scale(const LVecBase3 &pos,
   INLINE static CPT(TransformState) make_pos_hpr_scale(const LVecBase3 &pos,
-                                                       const LVecBase3 &hpr, 
+                                                       const LVecBase3 &hpr,
                                                        const LVecBase3 &scale);
                                                        const LVecBase3 &scale);
   INLINE static CPT(TransformState) make_pos_quat_scale(const LVecBase3 &pos,
   INLINE static CPT(TransformState) make_pos_quat_scale(const LVecBase3 &pos,
-                                                        const LQuaternion &quat, 
+                                                        const LQuaternion &quat,
                                                         const LVecBase3 &scale);
                                                         const LVecBase3 &scale);
   static CPT(TransformState) make_pos_hpr_scale_shear(const LVecBase3 &pos,
   static CPT(TransformState) make_pos_hpr_scale_shear(const LVecBase3 &pos,
-                                                      const LVecBase3 &hpr, 
+                                                      const LVecBase3 &hpr,
                                                       const LVecBase3 &scale,
                                                       const LVecBase3 &scale,
                                                       const LVecBase3 &shear);
                                                       const LVecBase3 &shear);
   static CPT(TransformState) make_pos_quat_scale_shear(const LVecBase3 &pos,
   static CPT(TransformState) make_pos_quat_scale_shear(const LVecBase3 &pos,
-                                                       const LQuaternion &quat, 
+                                                       const LQuaternion &quat,
                                                        const LVecBase3 &scale,
                                                        const LVecBase3 &scale,
                                                        const LVecBase3 &shear);
                                                        const LVecBase3 &shear);
   static CPT(TransformState) make_mat(const LMatrix4 &mat);
   static CPT(TransformState) make_mat(const LMatrix4 &mat);
@@ -112,7 +113,7 @@ PUBLISHED:
   INLINE static CPT(TransformState) make_scale2d(const LVecBase2 &scale);
   INLINE static CPT(TransformState) make_scale2d(const LVecBase2 &scale);
   INLINE static CPT(TransformState) make_shear2d(PN_stdfloat shear);
   INLINE static CPT(TransformState) make_shear2d(PN_stdfloat shear);
   INLINE static CPT(TransformState) make_pos_rotate_scale2d(const LVecBase2 &pos,
   INLINE static CPT(TransformState) make_pos_rotate_scale2d(const LVecBase2 &pos,
-                                                            PN_stdfloat rotate, 
+                                                            PN_stdfloat rotate,
                                                             const LVecBase2 &scale);
                                                             const LVecBase2 &scale);
   static CPT(TransformState) make_pos_rotate_scale_shear2d(const LVecBase2 &pos,
   static CPT(TransformState) make_pos_rotate_scale_shear2d(const LVecBase2 &pos,
                                                            PN_stdfloat rotate,
                                                            PN_stdfloat rotate,
@@ -257,7 +258,7 @@ private:
   static LightReMutex *_states_lock;
   static LightReMutex *_states_lock;
   class Empty {
   class Empty {
   };
   };
-  typedef SimpleHashMap<const TransformState *, Empty, indirect_compare_to_hash<const TransformState *> > States;
+  typedef SimpleHashMap<const TransformState *, Empty, indirect_equals_hash<const TransformState *> > States;
   static States *_states;
   static States *_states;
   static CPT(TransformState) _identity_state;
   static CPT(TransformState) _identity_state;
   static CPT(TransformState) _invalid_state;
   static CPT(TransformState) _invalid_state;
@@ -272,7 +273,7 @@ private:
   // remove the entry if *either* of the input TransformStates destructs.
   // remove the entry if *either* of the input TransformStates destructs.
   // To implement this, we always record Composition entries in pairs,
   // To implement this, we always record Composition entries in pairs,
   // one in each of the two involved TransformState objects.
   // one in each of the two involved TransformState objects.
-    
+
   // The first element of the map is the object we compose with.  This
   // The first element of the map is the object we compose with.  This
   // is not reference counted within this map; instead we store a
   // is not reference counted within this map; instead we store a
   // companion pointer in the other object, and remove the references
   // companion pointer in the other object, and remove the references
@@ -299,6 +300,8 @@ private:
   // collection cycle.
   // collection cycle.
   static int _garbage_index;
   static int _garbage_index;
 
 
+  static bool _uniquify_matrix;
+
   static PStatCollector _cache_update_pcollector;
   static PStatCollector _cache_update_pcollector;
   static PStatCollector _garbage_collect_pcollector;
   static PStatCollector _garbage_collect_pcollector;
   static PStatCollector _transform_compose_pcollector;
   static PStatCollector _transform_compose_pcollector;
@@ -369,7 +372,7 @@ private:
   LMatrix4 _mat;
   LMatrix4 _mat;
   LMatrix4 *_inv_mat;
   LMatrix4 *_inv_mat;
   size_t _hash;
   size_t _hash;
-  
+
   unsigned int _flags;
   unsigned int _flags;
 
 
   // This mutex protects _flags, and all of the above computed values.
   // This mutex protects _flags, and all of the above computed values.
@@ -385,7 +388,7 @@ public:
 protected:
 protected:
   static TypedWritable *make_from_bam(const FactoryParams &params);
   static TypedWritable *make_from_bam(const FactoryParams &params);
   void fillin(DatagramIterator &scan, BamReader *manager);
   void fillin(DatagramIterator &scan, BamReader *manager);
-  
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 1 - 1
panda/src/pgui/pgItem.cxx

@@ -209,7 +209,7 @@ draw_mask_changed() {
 bool PGItem::
 bool PGItem::
 cull_callback(CullTraverser *trav, CullTraverserData &data) {
 cull_callback(CullTraverser *trav, CullTraverserData &data) {
   LightReMutexHolder holder(_lock);
   LightReMutexHolder holder(_lock);
-  bool this_node_hidden = data.is_this_node_hidden(trav);
+  bool this_node_hidden = data.is_this_node_hidden(trav->get_camera_mask());
   if (!this_node_hidden && has_frame() && get_active()) {
   if (!this_node_hidden && has_frame() && get_active()) {
     // The item has a frame, so we want to generate a region for it
     // The item has a frame, so we want to generate a region for it
     // and update the MouseWatcher.
     // and update the MouseWatcher.

+ 2 - 2
panda/src/pgui/pgSliderBar.cxx

@@ -717,7 +717,7 @@ reposition() {
   _needs_reposition = false;
   _needs_reposition = false;
 
 
   PN_stdfloat t = get_ratio();
   PN_stdfloat t = get_ratio();
-  
+
   if (_thumb_button != (PGButton *)NULL) {
   if (_thumb_button != (PGButton *)NULL) {
     LPoint3 pos = (t * _range_x) * _axis + _thumb_start;
     LPoint3 pos = (t * _range_x) * _axis + _thumb_start;
     CPT(TransformState) transform = TransformState::make_pos(pos);
     CPT(TransformState) transform = TransformState::make_pos(pos);
@@ -727,7 +727,7 @@ reposition() {
     // we'll get caught in an update loop.
     // we'll get caught in an update loop.
     if (transform == orig_transform) {
     if (transform == orig_transform) {
       // No change.
       // No change.
-    } else if (*transform < *orig_transform || *orig_transform < *transform) {
+    } else if (*transform != *orig_transform) {
       _thumb_button->set_transform(transform);
       _thumb_button->set_transform(transform);
     }
     }
   }
   }

+ 20 - 4
panda/src/pstatclient/pStatClient.cxx

@@ -720,6 +720,10 @@ is_started(int collector_index, int thread_index) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PStatClient::
 void PStatClient::
 start(int collector_index, int thread_index) {
 start(int collector_index, int thread_index) {
+  if (!client_is_connected()) {
+    return;
+  }
+
 #ifdef _DEBUG
 #ifdef _DEBUG
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
@@ -728,7 +732,7 @@ start(int collector_index, int thread_index) {
   Collector *collector = get_collector_ptr(collector_index);
   Collector *collector = get_collector_ptr(collector_index);
   InternalThread *thread = get_thread_ptr(thread_index);
   InternalThread *thread = get_thread_ptr(thread_index);
 
 
-  if (client_is_connected() && collector->is_active() && thread->_is_active) {
+  if (collector->is_active() && thread->_is_active) {
     LightMutexHolder holder(thread->_thread_lock);
     LightMutexHolder holder(thread->_thread_lock);
     if (collector->_per_thread[thread_index]._nested_count == 0) {
     if (collector->_per_thread[thread_index]._nested_count == 0) {
       // This collector wasn't already started in this thread; record
       // This collector wasn't already started in this thread; record
@@ -750,6 +754,10 @@ start(int collector_index, int thread_index) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PStatClient::
 void PStatClient::
 start(int collector_index, int thread_index, double as_of) {
 start(int collector_index, int thread_index, double as_of) {
+  if (!client_is_connected()) {
+    return;
+  }
+
 #ifdef _DEBUG
 #ifdef _DEBUG
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
@@ -758,7 +766,7 @@ start(int collector_index, int thread_index, double as_of) {
   Collector *collector = get_collector_ptr(collector_index);
   Collector *collector = get_collector_ptr(collector_index);
   InternalThread *thread = get_thread_ptr(thread_index);
   InternalThread *thread = get_thread_ptr(thread_index);
 
 
-  if (client_is_connected() && collector->is_active() && thread->_is_active) {
+  if (collector->is_active() && thread->_is_active) {
     LightMutexHolder holder(thread->_thread_lock);
     LightMutexHolder holder(thread->_thread_lock);
     if (collector->_per_thread[thread_index]._nested_count == 0) {
     if (collector->_per_thread[thread_index]._nested_count == 0) {
       // This collector wasn't already started in this thread; record
       // This collector wasn't already started in this thread; record
@@ -780,6 +788,10 @@ start(int collector_index, int thread_index, double as_of) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PStatClient::
 void PStatClient::
 stop(int collector_index, int thread_index) {
 stop(int collector_index, int thread_index) {
+  if (!client_is_connected()) {
+    return;
+  }
+
 #ifdef _DEBUG
 #ifdef _DEBUG
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
@@ -788,7 +800,7 @@ stop(int collector_index, int thread_index) {
   Collector *collector = get_collector_ptr(collector_index);
   Collector *collector = get_collector_ptr(collector_index);
   InternalThread *thread = get_thread_ptr(thread_index);
   InternalThread *thread = get_thread_ptr(thread_index);
 
 
-  if (client_is_connected() && collector->is_active() && thread->_is_active) {
+  if (collector->is_active() && thread->_is_active) {
     LightMutexHolder holder(thread->_thread_lock);
     LightMutexHolder holder(thread->_thread_lock);
     if (collector->_per_thread[thread_index]._nested_count == 0) {
     if (collector->_per_thread[thread_index]._nested_count == 0) {
       if (pstats_cat.is_debug()) {
       if (pstats_cat.is_debug()) {
@@ -821,6 +833,10 @@ stop(int collector_index, int thread_index) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PStatClient::
 void PStatClient::
 stop(int collector_index, int thread_index, double as_of) {
 stop(int collector_index, int thread_index, double as_of) {
+  if (!client_is_connected()) {
+    return;
+  }
+
 #ifdef _DEBUG
 #ifdef _DEBUG
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
   nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads));
@@ -829,7 +845,7 @@ stop(int collector_index, int thread_index, double as_of) {
   Collector *collector = get_collector_ptr(collector_index);
   Collector *collector = get_collector_ptr(collector_index);
   InternalThread *thread = get_thread_ptr(thread_index);
   InternalThread *thread = get_thread_ptr(thread_index);
 
 
-  if (client_is_connected() && collector->is_active() && thread->_is_active) {
+  if (collector->is_active() && thread->_is_active) {
     LightMutexHolder holder(thread->_thread_lock);
     LightMutexHolder holder(thread->_thread_lock);
     if (collector->_per_thread[thread_index]._nested_count == 0) {
     if (collector->_per_thread[thread_index]._nested_count == 0) {
       if (pstats_cat.is_debug()) {
       if (pstats_cat.is_debug()) {

+ 60 - 0
panda/src/putil/copyOnWritePointer.I

@@ -81,6 +81,37 @@ INLINE CopyOnWritePointer::
   }
   }
 }
 }
 
 
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: CopyOnWritePointer::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE CopyOnWritePointer::
+CopyOnWritePointer(CopyOnWritePointer &&move) NOEXCEPT :
+  _cow_object(move._cow_object)
+{
+  // Steal the other's reference count.
+  move._cow_object = (CopyOnWriteObject *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CopyOnWritePointer::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void CopyOnWritePointer::
+operator = (CopyOnWritePointer &&move) NOEXCEPT {
+  CopyOnWriteObject *old_object = _cow_object;
+  _cow_object = move._cow_object;
+  move._cow_object = NULL;
+
+  if (old_object != (CopyOnWriteObject *)NULL) {
+    cache_unref_delete(old_object);
+  }
+}
+#endif  // USE_MOVE_SEMANTICS
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CopyOnWritePointer::operator == 
 //     Function: CopyOnWritePointer::operator == 
 //       Access: Public
 //       Access: Public
@@ -272,6 +303,35 @@ operator = (To *object) {
 }
 }
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
+#ifdef USE_MOVE_SEMANTICS
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: CopyOnWritePointerTo::Move Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE CopyOnWritePointerTo<T>::
+CopyOnWritePointerTo(CopyOnWritePointerTo<T> &&move) NOEXCEPT :
+  CopyOnWritePointer((CopyOnWritePointer &&)move)
+{
+}
+#endif  // CPPPARSER
+
+#ifndef CPPPARSER
+////////////////////////////////////////////////////////////////////
+//     Function: CopyOnWritePointerTo::Move Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE void CopyOnWritePointerTo<T>::
+operator = (CopyOnWritePointerTo<T> &&move) NOEXCEPT {
+  CopyOnWritePointer::operator = ((CopyOnWritePointer &&)move);
+}
+#endif  // CPPPARSER
+#endif  // USE_MOVE_SEMANTICS
+
 #ifndef CPPPARSER
 #ifndef CPPPARSER
 #ifdef COW_THREADED
 #ifdef COW_THREADED
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 10 - 0
panda/src/putil/copyOnWritePointer.h

@@ -40,6 +40,11 @@ public:
   INLINE void operator = (CopyOnWriteObject *object);
   INLINE void operator = (CopyOnWriteObject *object);
   INLINE ~CopyOnWritePointer();
   INLINE ~CopyOnWritePointer();
 
 
+#ifdef USE_MOVE_SEMANTICS
+  INLINE CopyOnWritePointer(CopyOnWritePointer &&move) NOEXCEPT;
+  INLINE void operator = (CopyOnWritePointer &&move) NOEXCEPT;
+#endif
+
   INLINE bool operator == (const CopyOnWritePointer &other) const;
   INLINE bool operator == (const CopyOnWritePointer &other) const;
   INLINE bool operator != (const CopyOnWritePointer &other) const;
   INLINE bool operator != (const CopyOnWritePointer &other) const;
   INLINE bool operator < (const CopyOnWritePointer &other) const;
   INLINE bool operator < (const CopyOnWritePointer &other) const;
@@ -83,6 +88,11 @@ public:
   INLINE void operator = (const CopyOnWritePointerTo<T> &copy);
   INLINE void operator = (const CopyOnWritePointerTo<T> &copy);
   INLINE void operator = (To *object);
   INLINE void operator = (To *object);
 
 
+#ifdef USE_MOVE_SEMANTICS
+  INLINE CopyOnWritePointerTo(CopyOnWritePointerTo &&move) NOEXCEPT;
+  INLINE void operator = (CopyOnWritePointerTo &&move) NOEXCEPT;
+#endif
+
 #ifdef COW_THREADED
 #ifdef COW_THREADED
   INLINE CPT(To) get_read_pointer() const;
   INLINE CPT(To) get_read_pointer() const;
   INLINE PT(To) get_write_pointer();
   INLINE PT(To) get_write_pointer();

+ 29 - 12
panda/src/putil/simpleHashMap.I

@@ -16,7 +16,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: SimpleHashMap::Constructor
 //     Function: SimpleHashMap::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Key, class Value, class Compare>
 template<class Key, class Value, class Compare>
 INLINE SimpleHashMap<Key, Value, Compare>::
 INLINE SimpleHashMap<Key, Value, Compare>::
@@ -32,7 +32,7 @@ SimpleHashMap(const Compare &comp) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: SimpleHashMap::Destructor
 //     Function: SimpleHashMap::Destructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Key, class Value, class Compare>
 template<class Key, class Value, class Compare>
 INLINE SimpleHashMap<Key, Value, Compare>::
 INLINE SimpleHashMap<Key, Value, Compare>::
@@ -417,7 +417,7 @@ is_empty() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: SimpleHashMap::output
 //     Function: SimpleHashMap::output
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Key, class Value, class Compare>
 template<class Key, class Value, class Compare>
 void SimpleHashMap<Key, Value, Compare>::
 void SimpleHashMap<Key, Value, Compare>::
@@ -443,7 +443,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: SimpleHashMap::write
 //     Function: SimpleHashMap::write
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Key, class Value, class Compare>
 template<class Key, class Value, class Compare>
 void SimpleHashMap<Key, Value, Compare>::
 void SimpleHashMap<Key, Value, Compare>::
@@ -575,9 +575,9 @@ void SimpleHashMap<Key, Value, Compare>::
 new_table() {
 new_table() {
   nassertv(_table_size == 0 && _num_entries == 0);
   nassertv(_table_size == 0 && _num_entries == 0);
 
 
-  // Pick a good initial table size.  For now, we make it as small as
-  // possible.  Maybe that's the right answer.
-  _table_size = 2;
+  // Pick a good initial table size.  For now, we make it really
+  // small.  Maybe that's the right answer.
+  _table_size = 4;
 
 
   // We allocate enough bytes for _table_size elements of TableEntry,
   // We allocate enough bytes for _table_size elements of TableEntry,
   // plus _table_size more bytes at the end (for the exists array).
   // plus _table_size more bytes at the end (for the exists array).
@@ -618,7 +618,9 @@ expand_table() {
   SimpleHashMap<Key, Value, Compare> old_map(_comp);
   SimpleHashMap<Key, Value, Compare> old_map(_comp);
   swap(old_map);
   swap(old_map);
 
 
-  _table_size = (old_map._table_size << 1);
+  // Double the table size.
+  size_t old_table_size = old_map._table_size;
+  _table_size = (old_table_size << 1);
   nassertv(_table == NULL);
   nassertv(_table == NULL);
 
 
   // We allocate enough bytes for _table_size elements of TableEntry,
   // We allocate enough bytes for _table_size elements of TableEntry,
@@ -626,15 +628,30 @@ expand_table() {
   size_t alloc_size = _table_size * sizeof(TableEntry) + _table_size;
   size_t alloc_size = _table_size * sizeof(TableEntry) + _table_size;
   _deleted_chain = memory_hook->get_deleted_chain(alloc_size);
   _deleted_chain = memory_hook->get_deleted_chain(alloc_size);
   _table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none());
   _table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none());
-  memset(get_exists_array(), 0, _table_size);
+  unsigned char *exists_array = get_exists_array();
+  memset(exists_array, 0, _table_size);
   nassertv(_num_entries == 0);
   nassertv(_num_entries == 0);
 
 
   // Now copy the entries from the old table into the new table.
   // Now copy the entries from the old table into the new table.
   int num_added = 0;
   int num_added = 0;
-  for (size_t i = 0; i < old_map._table_size; ++i) {
+  for (size_t i = 0; i < old_table_size; ++i) {
     if (old_map.has_element(i)) {
     if (old_map.has_element(i)) {
-      store(old_map._table[i]._key, old_map._table[i]._data);
-      ++num_added;
+      size_t new_index = get_hash(old_map._table[i]._key);
+
+      while (exists_array[new_index] != 0) {
+        // Hash conflict;  look for a better spot.  This has to succeed.
+        new_index = (new_index + 1) & (_table_size - 1);
+      }
+
+#ifdef USE_MOVE_SEMANTICS
+      // Use C++11 rvalue references to invoke the move constructor,
+      // which may be more efficient.
+      new(&_table[new_index]) TableEntry(move(old_map._table[i]));
+#else
+      new(&_table[new_index]) TableEntry(old_map._table[i]);
+#endif
+      exists_array[new_index] = true;
+      ++_num_entries;
     }
     }
   }
   }
 
 

+ 8 - 1
panda/src/putil/simpleHashMap.h

@@ -79,6 +79,14 @@ private:
     INLINE TableEntry(const Key &key, const Value &data) :
     INLINE TableEntry(const Key &key, const Value &data) :
       _key(key),
       _key(key),
       _data(data) {}
       _data(data) {}
+    INLINE TableEntry(const TableEntry &copy) :
+      _key(copy._key),
+      _data(copy._data) {}
+#ifdef USE_MOVE_SEMANTICS
+    INLINE TableEntry(TableEntry &&from) NOEXCEPT :
+      _key(move(from._key)),
+      _data(move(from._data)) {}
+#endif
     Key _key;
     Key _key;
     Value _data;
     Value _data;
   };
   };
@@ -103,4 +111,3 @@ inline ostream &operator << (ostream &out, const SimpleHashMap<Key, Value, Compa
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
 #endif
 #endif
-

+ 7 - 4
panda/src/windisplay/config_windisplay.cxx

@@ -57,10 +57,13 @@ ConfigVariableBool ime_hide
  PRC_DESC("Set this true to hide ime windows."));
  PRC_DESC("Set this true to hide ime windows."));
 
 
 ConfigVariableBool request_dxdisplay_information
 ConfigVariableBool request_dxdisplay_information
-("request-dxdisplay-information", true,
- PRC_DESC("Setting this to false skips some display information discovery "
-          "routines that can speed up initialization when DX support is "
-          "present."));
+("request-dxdisplay-information", false,
+ PRC_DESC("Setting this to true enables lumberingly slow and evil code at "
+          "start-up that creates a Direct3D window and subsequently fills up "
+          "up the video memory with dummy textures in order to find out how "
+          "much video memory there actually is.  Leave this disabled unless "
+          "you have a specific need for this information and don't mind "
+          "having a slow start-up."));
 
 
 ConfigVariableBool swapbuffer_framelock
 ConfigVariableBool swapbuffer_framelock
 ("swapbuffer-framelock", false,
 ("swapbuffer-framelock", false,