Browse Source

A lot of performance changes, particularly wrt dcasts and state management

rdb 10 years ago
parent
commit
f33e450823
100 changed files with 1322 additions and 511 deletions
  1. 3 1
      dtool/src/dtoolbase/typedObject.I
  2. 7 8
      panda/src/char/character.cxx
  3. 2 2
      panda/src/char/characterJointBundle.cxx
  4. 2 2
      panda/src/cull/cullBinBackToFront.cxx
  5. 2 2
      panda/src/cull/cullBinFrontToBack.cxx
  6. 8 3
      panda/src/display/displayRegion.I
  7. 1 1
      panda/src/display/displayRegion.h
  8. 5 6
      panda/src/display/graphicsEngine.cxx
  9. 27 22
      panda/src/display/graphicsStateGuardian.cxx
  10. 17 18
      panda/src/display/standardMunger.cxx
  11. 2 2
      panda/src/egg2pg/characterMaker.cxx
  12. 10 10
      panda/src/egg2pg/eggBinner.cxx
  13. 5 4
      panda/src/glstuff/glCgShaderContext_src.cxx
  14. 4 4
      panda/src/glstuff/glGeomMunger_src.cxx
  15. 12 13
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  16. 2 2
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  17. 1 1
      panda/src/gobj/geom.I
  18. 2 2
      panda/src/gobj/geom.cxx
  19. 5 1
      panda/src/gobj/geom.h
  20. 2 2
      panda/src/gobj/geomPrimitive.I
  21. 12 0
      panda/src/mathutil/boundingVolume.cxx
  22. 1 0
      panda/src/mathutil/boundingVolume.h
  23. 13 1
      panda/src/mathutil/geometricBoundingVolume.cxx
  24. 2 1
      panda/src/mathutil/geometricBoundingVolume.h
  25. 3 3
      panda/src/pgraph/alphaTestAttrib.cxx
  26. 2 2
      panda/src/pgraph/alphaTestAttrib.h
  27. 27 9
      panda/src/pgraph/antialiasAttrib.cxx
  28. 2 7
      panda/src/pgraph/antialiasAttrib.h
  29. 4 6
      panda/src/pgraph/audioVolumeAttrib.cxx
  30. 2 2
      panda/src/pgraph/audioVolumeAttrib.h
  31. 2 2
      panda/src/pgraph/auxBitplaneAttrib.cxx
  32. 1 1
      panda/src/pgraph/auxBitplaneAttrib.h
  33. 1 1
      panda/src/pgraph/clipPlaneAttrib.h
  34. 2 2
      panda/src/pgraph/colorAttrib.cxx
  35. 2 1
      panda/src/pgraph/colorAttrib.h
  36. 1 2
      panda/src/pgraph/colorBlendAttrib.cxx
  37. 1 1
      panda/src/pgraph/colorBlendAttrib.h
  38. 4 6
      panda/src/pgraph/colorScaleAttrib.cxx
  39. 2 1
      panda/src/pgraph/colorScaleAttrib.h
  40. 1 2
      panda/src/pgraph/colorWriteAttrib.cxx
  41. 1 1
      panda/src/pgraph/colorWriteAttrib.h
  42. 0 5
      panda/src/pgraph/config_pgraph.cxx
  43. 0 1
      panda/src/pgraph/config_pgraph.h
  44. 2 2
      panda/src/pgraph/cullBinAttrib.cxx
  45. 1 1
      panda/src/pgraph/cullBinAttrib.h
  46. 4 6
      panda/src/pgraph/cullFaceAttrib.cxx
  47. 2 1
      panda/src/pgraph/cullFaceAttrib.h
  48. 2 3
      panda/src/pgraph/cullResult.cxx
  49. 9 5
      panda/src/pgraph/cullTraverserData.cxx
  50. 1 2
      panda/src/pgraph/cullableObject.cxx
  51. 6 6
      panda/src/pgraph/depthOffsetAttrib.cxx
  52. 2 1
      panda/src/pgraph/depthOffsetAttrib.h
  53. 2 2
      panda/src/pgraph/depthTestAttrib.cxx
  54. 1 1
      panda/src/pgraph/depthTestAttrib.h
  55. 2 2
      panda/src/pgraph/depthWriteAttrib.cxx
  56. 1 1
      panda/src/pgraph/depthWriteAttrib.h
  57. 1 2
      panda/src/pgraph/fogAttrib.cxx
  58. 1 1
      panda/src/pgraph/fogAttrib.h
  59. 2 4
      panda/src/pgraph/lightAttrib.cxx
  60. 1 1
      panda/src/pgraph/lightAttrib.h
  61. 2 2
      panda/src/pgraph/lightRampAttrib.cxx
  62. 1 1
      panda/src/pgraph/lightRampAttrib.h
  63. 1 2
      panda/src/pgraph/materialAttrib.cxx
  64. 1 1
      panda/src/pgraph/materialAttrib.h
  65. 2 17
      panda/src/pgraph/renderAttrib.I
  66. 6 7
      panda/src/pgraph/renderAttrib.cxx
  67. 3 6
      panda/src/pgraph/renderAttrib.h
  68. 30 16
      panda/src/pgraph/renderAttribRegistry.I
  69. 31 54
      panda/src/pgraph/renderAttribRegistry.cxx
  70. 11 11
      panda/src/pgraph/renderAttribRegistry.h
  71. 3 4
      panda/src/pgraph/renderModeAttrib.cxx
  72. 2 1
      panda/src/pgraph/renderModeAttrib.h
  73. 3 28
      panda/src/pgraph/renderState.I
  74. 34 59
      panda/src/pgraph/renderState.cxx
  75. 7 8
      panda/src/pgraph/renderState.h
  76. 13 0
      panda/src/pgraph/rescaleNormalAttrib.I
  77. 38 31
      panda/src/pgraph/rescaleNormalAttrib.cxx
  78. 7 8
      panda/src/pgraph/rescaleNormalAttrib.h
  79. 2 4
      panda/src/pgraph/scissorAttrib.cxx
  80. 4 1
      panda/src/pgraph/scissorAttrib.h
  81. 2 4
      panda/src/pgraph/shadeModelAttrib.cxx
  82. 1 1
      panda/src/pgraph/shadeModelAttrib.h
  83. 3 4
      panda/src/pgraph/shaderAttrib.cxx
  84. 1 1
      panda/src/pgraph/shaderAttrib.h
  85. 5 8
      panda/src/pgraph/stateMunger.cxx
  86. 2 2
      panda/src/pgraph/stateMunger.h
  87. 1 2
      panda/src/pgraph/stencilAttrib.cxx
  88. 1 1
      panda/src/pgraph/stencilAttrib.h
  89. 3 6
      panda/src/pgraph/texGenAttrib.cxx
  90. 1 1
      panda/src/pgraph/texGenAttrib.h
  91. 4 7
      panda/src/pgraph/texMatrixAttrib.cxx
  92. 1 1
      panda/src/pgraph/texMatrixAttrib.h
  93. 2 4
      panda/src/pgraph/textureAttrib.cxx
  94. 1 1
      panda/src/pgraph/textureAttrib.h
  95. 2 2
      panda/src/pgraph/transparencyAttrib.cxx
  96. 1 1
      panda/src/pgraph/transparencyAttrib.h
  97. 1 0
      panda/src/putil/p3putil_composite2.cxx
  98. 714 0
      panda/src/putil/weakKeyHashMap.I
  99. 15 0
      panda/src/putil/weakKeyHashMap.cxx
  100. 115 0
      panda/src/putil/weakKeyHashMap.h

+ 3 - 1
dtool/src/dtoolbase/typedObject.I

@@ -61,7 +61,9 @@ get_type_index() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool TypedObject::
 INLINE bool TypedObject::
 is_of_type(TypeHandle handle) const {
 is_of_type(TypeHandle handle) const {
-  return get_type().is_derived_from(handle, (TypedObject *)this);
+  // Shortcut for the common case where the type matches exactly.
+  TypeHandle my_type = get_type();
+  return handle == my_type || my_type.is_derived_from(handle, (TypedObject *)this);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

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

@@ -420,8 +420,7 @@ find_joint(const string &name) const {
   int num_bundles = get_num_bundles();
   int num_bundles = get_num_bundles();
   for (int i = 0; i < num_bundles; ++i) {
   for (int i = 0; i < num_bundles; ++i) {
     PartGroup *part = get_bundle(i)->find_child(name);
     PartGroup *part = get_bundle(i)->find_child(name);
-    if (part != (PartGroup *)NULL &&
-        part->is_of_type(CharacterJoint::get_class_type())) {
+    if (part != (PartGroup *)NULL && part->is_character_joint()) {
       return DCAST(CharacterJoint, part);
       return DCAST(CharacterJoint, part);
     }
     }
   }
   }
@@ -728,7 +727,7 @@ r_merge_bundles(Character::JointMap &joint_map,
                 PartGroup *old_group, PartGroup *new_group) {
                 PartGroup *old_group, PartGroup *new_group) {
   joint_map[old_group] = new_group;
   joint_map[old_group] = new_group;
 
 
-  if (new_group->is_of_type(CharacterJoint::get_class_type())) {
+  if (new_group->is_character_joint()) {
     CharacterJoint *new_joint;
     CharacterJoint *new_joint;
     DCAST_INTO_V(new_joint, new_group);
     DCAST_INTO_V(new_joint, new_group);
 
 
@@ -736,7 +735,7 @@ r_merge_bundles(Character::JointMap &joint_map,
     new_joint->_character = this;
     new_joint->_character = this;
 
 
     if (old_group != new_group &&
     if (old_group != new_group &&
-        old_group->is_of_type(CharacterJoint::get_class_type())) {
+        old_group->is_character_joint()) {
       CharacterJoint *old_joint;
       CharacterJoint *old_joint;
       DCAST_INTO_V(old_joint, old_group);
       DCAST_INTO_V(old_joint, old_group);
 
 
@@ -763,7 +762,7 @@ r_merge_bundles(Character::JointMap &joint_map,
   if (old_group == new_group) {
   if (old_group == new_group) {
     return;
     return;
   }
   }
-    
+
   int i = 0, j = 0;
   int i = 0, j = 0;
   int old_num_children = old_group->get_num_children();
   int old_num_children = old_group->get_num_children();
   int new_num_children = new_group->get_num_children();
   int new_num_children = new_group->get_num_children();
@@ -809,7 +808,7 @@ r_merge_bundles(Character::JointMap &joint_map,
     // new_group.  Duplicate it.
     // new_group.  Duplicate it.
     PartGroup *new_pc = pc->make_copy();
     PartGroup *new_pc = pc->make_copy();
     new_children.push_back(new_pc);
     new_children.push_back(new_pc);
-    
+
     r_merge_bundles(joint_map, pc, new_pc);
     r_merge_bundles(joint_map, pc, new_pc);
     i++;
     i++;
   }
   }
@@ -968,7 +967,7 @@ copy_geom(const Geom *source, const Character::JointMap &joint_map,
 void Character::
 void Character::
 copy_node_pointers(const Character::NodeMap &node_map,
 copy_node_pointers(const Character::NodeMap &node_map,
                    PartGroup *dest, const PartGroup *source) {
                    PartGroup *dest, const PartGroup *source) {
-  if (dest->is_of_type(CharacterJoint::get_class_type())) {
+  if (dest->is_character_joint()) {
     nassertv(dest != source);
     nassertv(dest != source);
     const CharacterJoint *source_joint;
     const CharacterJoint *source_joint;
     CharacterJoint *dest_joint;
     CharacterJoint *dest_joint;
@@ -1204,7 +1203,7 @@ redirect_slider(const VertexSlider *vs, Character::GeomSliderMap &gsmap) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Character::
 void Character::
 r_clear_joint_characters(PartGroup *part) {
 r_clear_joint_characters(PartGroup *part) {
-  if (part->is_of_type(CharacterJoint::get_class_type())) {
+  if (part->is_character_joint()) {
     CharacterJoint *joint = DCAST(CharacterJoint, part);
     CharacterJoint *joint = DCAST(CharacterJoint, part);
 
 
     // It is possible for the joint to reference a different Character
     // It is possible for the joint to reference a different Character

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

@@ -102,8 +102,8 @@ r_set_character(PartGroup *group, Character *character) {
     return;
     return;
   }
   }
 
 
-  if (group->is_of_type(CharacterJoint::get_class_type())) {
-    DCAST(CharacterJoint, group)->set_character(character);
+  if (group->is_character_joint()) {
+    ((CharacterJoint *)group)->set_character(character);
   }
   }
 
 
   Children::const_iterator ci;
   Children::const_iterator ci;

+ 2 - 2
panda/src/cull/cullBinBackToFront.cxx

@@ -64,8 +64,8 @@ add_object(CullableObject *object, Thread *current_thread) {
     return;
     return;
   }
   }
 
 
-  const GeometricBoundingVolume *gbv;
-  DCAST_INTO_V(gbv, volume);
+  const GeometricBoundingVolume *gbv = volume->as_geometric_bounding_volume();
+  nassertv(gbv != NULL);
 
 
   LPoint3 center = gbv->get_approx_center();
   LPoint3 center = gbv->get_approx_center();
   nassertv(object->_internal_transform != (const TransformState *)NULL);
   nassertv(object->_internal_transform != (const TransformState *)NULL);

+ 2 - 2
panda/src/cull/cullBinFrontToBack.cxx

@@ -64,8 +64,8 @@ add_object(CullableObject *object, Thread *current_thread) {
     return;
     return;
   }
   }
 
 
-  const GeometricBoundingVolume *gbv;
-  DCAST_INTO_V(gbv, volume);
+  const GeometricBoundingVolume *gbv = volume->as_geometric_bounding_volume();
+  nassertv(gbv != NULL);
 
 
   LPoint3 center = gbv->get_approx_center();
   LPoint3 center = gbv->get_approx_center();
   nassertv(object->_internal_transform != (const TransformState *)NULL);
   nassertv(object->_internal_transform != (const TransformState *)NULL);

+ 8 - 3
panda/src/display/displayRegion.I

@@ -597,11 +597,16 @@ get_region_pixels_i(int i, int &xo, int &yo, int &w, int &h) const {
 //               to all upstream pipeline stages.
 //               to all upstream pipeline stages.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void DisplayRegion::
 INLINE void DisplayRegion::
-set_cull_result(CullResult *cull_result, SceneSetup *scene_setup,
+set_cull_result(PT(CullResult) cull_result, PT(SceneSetup) scene_setup,
                 Thread *current_thread) {
                 Thread *current_thread) {
   CDCullWriter cdata(_cycler_cull, true, current_thread);
   CDCullWriter cdata(_cycler_cull, true, current_thread);
-  cdata->_cull_result = cull_result;
-  cdata->_scene_setup = scene_setup;
+#ifdef USE_MOVE_SEMANTICS
+  cdata->_cull_result = std::move(cull_result);
+  cdata->_scene_setup = std::move(scene_setup);
+#else
+  swap(cdata->_cull_result, cull_result);
+  swap(cdata->_scene_setup, scene_setup);
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/display/displayRegion.h

@@ -161,7 +161,7 @@ public:
 
 
   virtual bool supports_pixel_zoom() const;
   virtual bool supports_pixel_zoom() const;
 
 
-  INLINE void set_cull_result(CullResult *cull_result, SceneSetup *scene_setup,
+  INLINE void set_cull_result(PT(CullResult) cull_result, PT(SceneSetup) scene_setup,
                               Thread *current_thread);
                               Thread *current_thread);
   INLINE CullResult *get_cull_result(Thread *current_thread) const;
   INLINE CullResult *get_cull_result(Thread *current_thread) const;
   INLINE SceneSetup *get_scene_setup(Thread *current_thread) const;
   INLINE SceneSetup *get_scene_setup(Thread *current_thread) const;

+ 5 - 6
panda/src/display/graphicsEngine.cxx

@@ -41,7 +41,6 @@
 #include "bamCache.h"
 #include "bamCache.h"
 #include "cullableObject.h"
 #include "cullableObject.h"
 #include "geomVertexArrayData.h"
 #include "geomVertexArrayData.h"
-#include "omniBoundingVolume.h"
 #include "vertexDataSaveFile.h"
 #include "vertexDataSaveFile.h"
 #include "vertexDataBook.h"
 #include "vertexDataBook.h"
 #include "vertexDataPage.h"
 #include "vertexDataPage.h"
@@ -1248,12 +1247,12 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
     // from the lens.
     // from the lens.
     PT(BoundingVolume) bv = scene_setup->get_cull_bounds();
     PT(BoundingVolume) bv = scene_setup->get_cull_bounds();
 
 
-    if (bv != (BoundingVolume *)NULL &&
-        bv->is_of_type(GeometricBoundingVolume::get_class_type()) &&
-        !bv->is_of_type(OmniBoundingVolume::get_class_type())) {
+    if (bv != (BoundingVolume *)NULL && !bv->is_infinite() &&
+        bv->as_geometric_bounding_volume() != NULL) {
       // Transform it into the appropriate coordinate space.
       // Transform it into the appropriate coordinate space.
       PT(GeometricBoundingVolume) local_frustum;
       PT(GeometricBoundingVolume) local_frustum;
-      local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy());
+      local_frustum = bv->make_copy()->as_geometric_bounding_volume();
+      nassertv(!local_frustum.is_null());
 
 
       NodePath scene_parent = scene_setup->get_scene_root().get_parent(current_thread);
       NodePath scene_parent = scene_setup->get_scene_root().get_parent(current_thread);
       CPT(TransformState) cull_center_transform =
       CPT(TransformState) cull_center_transform =
@@ -1580,7 +1579,7 @@ cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
   }
   }
 
 
   // Save the results for next frame.
   // Save the results for next frame.
-  dr->set_cull_result(cull_result, scene_setup, current_thread);
+  dr->set_cull_result(MOVE(cull_result), MOVE(scene_setup), current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 27 - 22
panda/src/display/graphicsStateGuardian.cxx

@@ -40,6 +40,7 @@
 #include "graphicsOutput.h"
 #include "graphicsOutput.h"
 #include "texturePool.h"
 #include "texturePool.h"
 #include "geomMunger.h"
 #include "geomMunger.h"
+#include "stateMunger.h"
 #include "ambientLight.h"
 #include "ambientLight.h"
 #include "directionalLight.h"
 #include "directionalLight.h"
 #include "pointLight.h"
 #include "pointLight.h"
@@ -814,38 +815,42 @@ dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(GeomMunger) GraphicsStateGuardian::
 PT(GeomMunger) GraphicsStateGuardian::
 get_geom_munger(const RenderState *state, Thread *current_thread) {
 get_geom_munger(const RenderState *state, Thread *current_thread) {
-  // Before we even look up the map, see if the _last_mi value points
-  // to this GSG.  This is likely because we tend to visit the same
-  // state multiple times during a frame.  Also, this might well be
-  // the only GSG in the world anyway.
-  if (!state->_mungers.empty()) {
-    RenderState::Mungers::const_iterator mi = state->_last_mi;
-    if (!(*mi).first.was_deleted() && (*mi).first == this) {
-      if ((*mi).second->is_registered()) {
-        return (*mi).second;
+  RenderState::Mungers &mungers = state->_mungers;
+
+  if (mungers.is_empty()) {
+    // Before we even look up the map, see if the _last_mi value points
+    // to this GSG.  This is likely because we tend to visit the same
+    // state multiple times during a frame.  Also, this might well be
+    // the only GSG in the world anyway.
+    int mi = state->_last_mi;
+    if (mi >= 0 && mungers.has_element(mi) && mungers.get_key(mi) == this) {
+      PT(GeomMunger) munger = mungers.get_data(mi);
+      if (munger->is_registered()) {
+        return munger;
       }
       }
     }
     }
-  }
 
 
-  // Nope, we have to look it up in the map.
-  RenderState::Mungers::iterator mi = state->_mungers.find(this);
-  if (mi != state->_mungers.end() && !(*mi).first.was_deleted()) {
-    if ((*mi).second->is_registered()) {
-      state->_last_mi = mi;
-      return (*mi).second;
+    // Nope, we have to look it up in the map.
+    mi = mungers.find(this);
+    if (mi >= 0) {
+      PT(GeomMunger) munger = mungers.get_data(mi);
+      if (munger->is_registered()) {
+        state->_last_mi = mi;
+        return munger;
+      } else {
+        // This GeomMunger is no longer registered.  Remove it from
+        // the map.
+        mungers.remove_element(mi);
+      }
     }
     }
-    // This GeomMunger is no longer registered.  Remove it from the
-    // map.
-    state->_mungers.erase(mi);
   }
   }
 
 
   // Nothing in the map; create a new entry.
   // Nothing in the map; create a new entry.
   PT(GeomMunger) munger = make_geom_munger(state, current_thread);
   PT(GeomMunger) munger = make_geom_munger(state, current_thread);
   nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger);
   nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger);
+  nassertr(munger->is_of_type(StateMunger::get_class_type()), munger);
 
 
-  mi = state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first;
-  state->_last_mi = mi;
-
+  state->_last_mi = mungers.store(this, munger);
   return munger;
   return munger;
 }
 }
 
 

+ 17 - 18
panda/src/display/standardMunger.cxx

@@ -15,7 +15,6 @@
 #include "standardMunger.h"
 #include "standardMunger.h"
 #include "renderState.h"
 #include "renderState.h"
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
-#include "dcast.h"
 #include "config_gobj.h"
 #include "config_gobj.h"
 #include "displayRegion.h"
 #include "displayRegion.h"
 
 
@@ -43,16 +42,15 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
   _auto_shader(false),
   _auto_shader(false),
   _shader_skinning(false)
   _shader_skinning(false)
 {
 {
-  _render_mode = DCAST(RenderModeAttrib, state->get_attrib(RenderModeAttrib::get_class_slot()));
+  _render_mode = (const RenderModeAttrib *)
+    state->get_attrib(RenderModeAttrib::get_class_slot());
 
 
   if (!get_gsg()->get_runtime_color_scale()) {
   if (!get_gsg()->get_runtime_color_scale()) {
     // We might need to munge the colors.
     // We might need to munge the colors.
-    const ColorAttrib *color_attrib = (const ColorAttrib *)
-      state->get_attrib(ColorAttrib::get_class_slot());
-    const ColorScaleAttrib *color_scale_attrib = (const ColorScaleAttrib *)
-      state->get_attrib(ColorScaleAttrib::get_class_slot());
+    const ColorAttrib *color_attrib;
+    const ColorScaleAttrib *color_scale_attrib;
 
 
-    if (color_attrib != (ColorAttrib *)NULL && 
+    if (state->get_attrib(color_attrib) &&
         color_attrib->get_color_type() == ColorAttrib::T_flat) {
         color_attrib->get_color_type() == ColorAttrib::T_flat) {
 
 
       if (!get_gsg()->get_color_scale_via_lighting()) {
       if (!get_gsg()->get_color_scale_via_lighting()) {
@@ -60,7 +58,7 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
         // can't cheat the color via lighting (presumably, in this case,
         // can't cheat the color via lighting (presumably, in this case,
         // by applying a material).
         // by applying a material).
         _color = color_attrib->get_color();
         _color = color_attrib->get_color();
-        if (color_scale_attrib != (ColorScaleAttrib *)NULL &&
+        if (state->get_attrib(color_scale_attrib) &&
             color_scale_attrib->has_scale()) {
             color_scale_attrib->has_scale()) {
           const LVecBase4 &cs = color_scale_attrib->get_scale();
           const LVecBase4 &cs = color_scale_attrib->get_scale();
           _color.set(_color[0] * cs[0],
           _color.set(_color[0] * cs[0],
@@ -70,11 +68,11 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
         }
         }
         _munge_color = true;
         _munge_color = true;
       }
       }
-      
-    } else if (color_scale_attrib != (ColorScaleAttrib *)NULL &&
+
+    } else if (state->get_attrib(color_scale_attrib) &&
                color_scale_attrib->has_scale()) {
                color_scale_attrib->has_scale()) {
       _color_scale = color_scale_attrib->get_scale();
       _color_scale = color_scale_attrib->get_scale();
-      
+
       const TextureAttrib *tex_attrib = (const TextureAttrib *)
       const TextureAttrib *tex_attrib = (const TextureAttrib *)
         state->get_attrib(TextureAttrib::get_class_slot());
         state->get_attrib(TextureAttrib::get_class_slot());
 
 
@@ -106,7 +104,7 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: StandardMunger::Destructor
 //     Function: StandardMunger::Destructor
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 StandardMunger::
 StandardMunger::
 ~StandardMunger() {
 ~StandardMunger() {
@@ -126,7 +124,7 @@ munge_data_impl(const GeomVertexData *data) {
     new_data = new_data->set_color(_color, _num_components, _numeric_type,
     new_data = new_data->set_color(_color, _num_components, _numeric_type,
                                    _contents);
                                    _contents);
   } else if (_munge_color_scale) {
   } else if (_munge_color_scale) {
-    new_data = new_data->scale_color(_color_scale, _num_components, 
+    new_data = new_data->scale_color(_color_scale, _num_components,
                                      _numeric_type, _contents);
                                      _numeric_type, _contents);
   }
   }
 
 
@@ -142,9 +140,9 @@ munge_data_impl(const GeomVertexData *data) {
     const TransformBlendTable *table = new_data->get_transform_blend_table();
     const TransformBlendTable *table = new_data->get_transform_blend_table();
     if (table != (TransformBlendTable *)NULL &&
     if (table != (TransformBlendTable *)NULL &&
         table->get_num_transforms() != 0 &&
         table->get_num_transforms() != 0 &&
-        table->get_max_simultaneous_transforms() <= 
+        table->get_max_simultaneous_transforms() <=
         get_gsg()->get_max_vertex_transforms()) {
         get_gsg()->get_max_vertex_transforms()) {
-      if (matrix_palette && 
+      if (matrix_palette &&
           table->get_num_transforms() <= get_gsg()->get_max_vertex_transform_indices()) {
           table->get_num_transforms() <= get_gsg()->get_max_vertex_transform_indices()) {
 
 
         if (table->get_num_transforms() == table->get_max_simultaneous_transforms()) {
         if (table->get_num_transforms() == table->get_max_simultaneous_transforms()) {
@@ -186,7 +184,7 @@ munge_data_impl(const GeomVertexData *data) {
 //  Description: Converts a Geom and/or its data as necessary.
 //  Description: Converts a Geom and/or its data as necessary.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void StandardMunger::
 void StandardMunger::
-munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data, 
+munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
                 Thread *) {
                 Thread *) {
   int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
   int supported_geom_rendering = get_gsg()->get_supported_geom_rendering();
 
 
@@ -289,7 +287,7 @@ premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int StandardMunger::
 int StandardMunger::
 compare_to_impl(const GeomMunger *other) const {
 compare_to_impl(const GeomMunger *other) const {
-  const StandardMunger *om = DCAST(StandardMunger, other);
+  const StandardMunger *om = (const StandardMunger *)other;
 
 
   if (_render_mode != om->_render_mode) {
   if (_render_mode != om->_render_mode) {
     return _render_mode < om->_render_mode ? -1 : 1;
     return _render_mode < om->_render_mode ? -1 : 1;
@@ -335,7 +333,8 @@ compare_to_impl(const GeomMunger *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int StandardMunger::
 int StandardMunger::
 geom_compare_to_impl(const GeomMunger *other) const {
 geom_compare_to_impl(const GeomMunger *other) const {
-  const StandardMunger *om = DCAST(StandardMunger, other);
+  const StandardMunger *om = (const StandardMunger *)other;
+
   if (_munge_color != om->_munge_color) {
   if (_munge_color != om->_munge_color) {
     return (int)_munge_color - (int)om->_munge_color;
     return (int)_munge_color - (int)om->_munge_color;
   }
   }

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

@@ -156,7 +156,7 @@ PandaNode *CharacterMaker::
 part_to_node(PartGroup *part, const string &name) const {
 part_to_node(PartGroup *part, const string &name) const {
   PandaNode *node = _character_node;
   PandaNode *node = _character_node;
 
 
-  if (part->is_of_type(CharacterJoint::get_class_type())) {
+  if (part->is_character_joint()) {
     CharacterJoint *joint = DCAST(CharacterJoint, part);
     CharacterJoint *joint = DCAST(CharacterJoint, part);
     if (joint->_geom_node != (PandaNode *)NULL) {
     if (joint->_geom_node != (PandaNode *)NULL) {
       node = joint->_geom_node;
       node = joint->_geom_node;
@@ -343,7 +343,7 @@ build_joint_hierarchy(EggNode *egg_node, PartGroup *part, int index) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CharacterMaker::
 void CharacterMaker::
 parent_joint_nodes(PartGroup *part) {
 parent_joint_nodes(PartGroup *part) {
-  if (part->is_of_type(CharacterJoint::get_class_type())) {
+  if (part->is_character_joint()) {
     CharacterJoint *joint = DCAST(CharacterJoint, part);
     CharacterJoint *joint = DCAST(CharacterJoint, part);
     PandaNode *joint_node = joint->_geom_node;
     PandaNode *joint_node = joint->_geom_node;
     if (joint_node != NULL) {
     if (joint_node != NULL) {

+ 10 - 10
panda/src/egg2pg/eggBinner.cxx

@@ -57,16 +57,7 @@ prepare_node(EggNode *node) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int EggBinner::
 int EggBinner::
 get_bin_number(const EggNode *node) {
 get_bin_number(const EggNode *node) {
-  if (node->is_of_type(EggNurbsSurface::get_class_type())) {
-    return (int)BN_nurbs_surface;
-
-  } else if (node->is_of_type(EggNurbsCurve::get_class_type())) {
-    return (int)BN_nurbs_curve;
-
-  } else if (node->is_of_type(EggPatch::get_class_type())) {
-    return (int)BN_patches;
-
-  } else if (node->is_of_type(EggPrimitive::get_class_type())) {
+  if (node->is_of_type(EggPrimitive::get_class_type())) {
     return (int)BN_polyset;
     return (int)BN_polyset;
 
 
   } else if (node->is_of_type(EggGroup::get_class_type())) {
   } else if (node->is_of_type(EggGroup::get_class_type())) {
@@ -74,6 +65,15 @@ get_bin_number(const EggNode *node) {
     if (group->has_lod()) {
     if (group->has_lod()) {
       return (int)BN_lod;
       return (int)BN_lod;
     }
     }
+
+  } else if (node->is_of_type(EggNurbsSurface::get_class_type())) {
+    return (int)BN_nurbs_surface;
+
+  } else if (node->is_of_type(EggNurbsCurve::get_class_type())) {
+    return (int)BN_nurbs_curve;
+
+  } else if (node->is_of_type(EggPatch::get_class_type())) {
+    return (int)BN_patches;
   }
   }
 
 
   return (int)BN_none;
   return (int)BN_none;

+ 5 - 4
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -991,8 +991,8 @@ update_shader_texture_bindings(ShaderContext *prev) {
 
 
   // We get the TextureAttrib directly from the _target_rs, not the
   // We get the TextureAttrib directly from the _target_rs, not the
   // filtered TextureAttrib in _target_texture.
   // filtered TextureAttrib in _target_texture.
-  const TextureAttrib *texattrib = DCAST(TextureAttrib, _glgsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
-  nassertv(texattrib != (TextureAttrib *)NULL);
+  const TextureAttrib *texattrib;
+  _glgsg->_target_rs->get_attrib_def(texattrib);
 
 
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
     Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
     Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
@@ -1053,8 +1053,9 @@ update_shader_texture_bindings(ShaderContext *prev) {
       continue;
       continue;
     }
     }
 
 
-    _glgsg->apply_texture(tc);
-    _glgsg->apply_sampler(texunit, sampler, tc);
+    CLP(TextureContext) *gtc = (CLP(TextureContext) *)tc;
+    _glgsg->apply_texture(gtc);
+    _glgsg->apply_sampler(texunit, sampler, gtc);
   }
   }
 
 
   cg_report_errors();
   cg_report_errors();

+ 4 - 4
panda/src/glstuff/glGeomMunger_src.cxx

@@ -26,8 +26,8 @@ ALLOC_DELETED_CHAIN_DEF(CLP(GeomMunger));
 CLP(GeomMunger)::
 CLP(GeomMunger)::
 CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
 CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
   StandardMunger(gsg, state, 4, NT_uint8, C_color),
   StandardMunger(gsg, state, 4, NT_uint8, C_color),
-  _texture(DCAST(TextureAttrib, state->get_attrib(TextureAttrib::get_class_slot()))),
-  _tex_gen(DCAST(TexGenAttrib, state->get_attrib(TexGenAttrib::get_class_slot())))
+  _texture((const TextureAttrib *)state->get_attrib(TextureAttrib::get_class_slot())),
+  _tex_gen((const TexGenAttrib *)state->get_attrib(TexGenAttrib::get_class_slot()))
 {
 {
   // Set a callback to unregister ourselves when either the Texture or
   // Set a callback to unregister ourselves when either the Texture or
   // the TexGen object gets deleted.
   // the TexGen object gets deleted.
@@ -475,7 +475,7 @@ premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int CLP(GeomMunger)::
 int CLP(GeomMunger)::
 compare_to_impl(const GeomMunger *other) const {
 compare_to_impl(const GeomMunger *other) const {
-  const CLP(GeomMunger) *om = DCAST(CLP(GeomMunger), other);
+  const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other;
   if (_texture != om->_texture) {
   if (_texture != om->_texture) {
     return _texture < om->_texture ? -1 : 1;
     return _texture < om->_texture ? -1 : 1;
   }
   }
@@ -499,7 +499,7 @@ compare_to_impl(const GeomMunger *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int CLP(GeomMunger)::
 int CLP(GeomMunger)::
 geom_compare_to_impl(const GeomMunger *other) const {
 geom_compare_to_impl(const GeomMunger *other) const {
-  const CLP(GeomMunger) *om = DCAST(CLP(GeomMunger), other);
+  const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other;
 #ifdef OPENGLES
 #ifdef OPENGLES
   if (get_render_mode() != om->get_render_mode()) {
   if (get_render_mode() != om->get_render_mode()) {
     return get_render_mode() < om->get_render_mode() ? -1 : 1;
     return get_render_mode() < om->get_render_mode() ? -1 : 1;

+ 12 - 13
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -4512,13 +4512,14 @@ prepare_texture(Texture *tex, int view) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 bool CLP(GraphicsStateGuardian)::
 update_texture(TextureContext *tc, bool force) {
 update_texture(TextureContext *tc, bool force) {
-  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+  CLP(TextureContext) *gtc;
+  DCAST_INTO_R(gtc, tc, false);
 
 
   if (gtc->was_image_modified() || !gtc->_has_storage) {
   if (gtc->was_image_modified() || !gtc->_has_storage) {
     PStatGPUTimer timer(this, _texture_update_pcollector);
     PStatGPUTimer timer(this, _texture_update_pcollector);
 
 
     // If the texture image was modified, reload the texture.
     // If the texture image was modified, reload the texture.
-    apply_texture(tc);
+    apply_texture(gtc);
 
 
     Texture *tex = tc->get_texture();
     Texture *tex = tc->get_texture();
     if (gtc->was_properties_modified()) {
     if (gtc->was_properties_modified()) {
@@ -4536,7 +4537,7 @@ update_texture(TextureContext *tc, bool force) {
 
 
     // If only the properties have been modified, we don't necessarily
     // If only the properties have been modified, we don't necessarily
     // need to reload the texture.
     // need to reload the texture.
-    apply_texture(tc);
+    apply_texture(gtc);
 
 
     Texture *tex = tc->get_texture();
     Texture *tex = tc->get_texture();
     if (specify_texture(gtc, tex->get_default_sampler())) {
     if (specify_texture(gtc, tex->get_default_sampler())) {
@@ -9649,8 +9650,10 @@ update_standard_texture_bindings() {
       glDisable(target);
       glDisable(target);
       continue;
       continue;
     }
     }
-    apply_texture(tc);
-    apply_sampler(i, _target_texture->get_on_sampler(stage), tc);
+    // Don't DCAST(); we already did the verification in update_texture.
+    CLP(TextureContext) *gtc = (CLP(TextureContext) *)tc;
+    apply_texture(gtc);
+    apply_sampler(i, _target_texture->get_on_sampler(stage), gtc);
 
 
     if (stage->involves_color_scale() && _color_scale_enabled) {
     if (stage->involves_color_scale() && _color_scale_enabled) {
       LColor color = stage->get_color();
       LColor color = stage->get_color();
@@ -10487,9 +10490,7 @@ specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) {
 //               for rendering.
 //               for rendering.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 bool CLP(GraphicsStateGuardian)::
-apply_texture(TextureContext *tc) {
-  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-
+apply_texture(CLP(TextureContext) *gtc) {
   gtc->set_active(true);
   gtc->set_active(true);
   GLenum target = get_texture_target(gtc->get_texture()->get_texture_type());
   GLenum target = get_texture_target(gtc->get_texture()->get_texture_type());
   if (target == GL_NONE) {
   if (target == GL_NONE) {
@@ -10520,9 +10521,7 @@ apply_texture(TextureContext *tc) {
 //               context instead.
 //               context instead.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 bool CLP(GraphicsStateGuardian)::
-apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) {
-  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-
+apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc) {
 #ifndef OPENGLES
 #ifndef OPENGLES
   if (_supports_sampler_objects) {
   if (_supports_sampler_objects) {
     // We support sampler objects.  Prepare the sampler object and
     // We support sampler objects.  Prepare the sampler object and
@@ -10547,7 +10546,7 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) {
     // texture and change the texture parameters if they don't match.
     // texture and change the texture parameters if they don't match.
     if (gtc->_active_sampler != sampler) {
     if (gtc->_active_sampler != sampler) {
       _glActiveTexture(GL_TEXTURE0 + unit);
       _glActiveTexture(GL_TEXTURE0 + unit);
-      apply_texture(tc);
+      apply_texture(gtc);
       specify_texture(gtc, sampler);
       specify_texture(gtc, sampler);
     }
     }
   }
   }
@@ -10555,7 +10554,7 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) {
   if (sampler.uses_mipmaps() && !gtc->_uses_mipmaps) {
   if (sampler.uses_mipmaps() && !gtc->_uses_mipmaps) {
     // The texture wasn't created with mipmaps, but we are trying
     // The texture wasn't created with mipmaps, but we are trying
     // to sample it with mipmaps.  We will need to reload it.
     // to sample it with mipmaps.  We will need to reload it.
-    apply_texture(tc);
+    apply_texture(gtc);
     gtc->mark_needs_reload();
     gtc->mark_needs_reload();
     bool okflag = upload_texture(gtc, false, true);
     bool okflag = upload_texture(gtc, false, true);
     if (!okflag) {
     if (!okflag) {

+ 2 - 2
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -531,8 +531,8 @@ protected:
 #endif  // NDEBUG
 #endif  // NDEBUG
 
 
   bool specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler);
   bool specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler);
-  bool apply_texture(TextureContext *tc);
-  bool apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc);
+  bool apply_texture(CLP(TextureContext) *gtc);
+  bool apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc);
   bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps);
   bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps);
   bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
   bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
                             bool uses_mipmaps, int mipmap_bias,
                             bool uses_mipmaps, int mipmap_bias,

+ 1 - 1
panda/src/gobj/geom.I

@@ -832,7 +832,7 @@ get_modified() const {
 INLINE GeomContext *GeomPipelineReader::
 INLINE GeomContext *GeomPipelineReader::
 prepare_now(PreparedGraphicsObjects *prepared_objects,
 prepare_now(PreparedGraphicsObjects *prepared_objects,
             GraphicsStateGuardianBase *gsg) const {
             GraphicsStateGuardianBase *gsg) const {
-  return ((Geom *)_object.p())->prepare_now(prepared_objects, gsg);
+  return ((Geom *)_object)->prepare_now(prepared_objects, gsg);
 }
 }
 
 
 INLINE ostream &
 INLINE ostream &

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

@@ -1897,7 +1897,7 @@ check_usage_hint() const {
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
       unref_delete((CycleData *)_cdata);
       unref_delete((CycleData *)_cdata);
 #endif
 #endif
-      Geom::CDWriter fresh_cdata(((Geom *)_object.p())->_cycler,
+      Geom::CDWriter fresh_cdata(((Geom *)_object)->_cycler,
                                  false, _current_thread);
                                  false, _current_thread);
       ((GeomPipelineReader *)this)->_cdata = fresh_cdata;
       ((GeomPipelineReader *)this)->_cdata = fresh_cdata;
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
@@ -1906,7 +1906,7 @@ check_usage_hint() const {
       if (!fresh_cdata->_got_usage_hint) {
       if (!fresh_cdata->_got_usage_hint) {
         // The cache is still stale.  We have to do the work of
         // The cache is still stale.  We have to do the work of
         // freshening it.
         // freshening it.
-        ((Geom *)_object.p())->reset_usage_hint(fresh_cdata);
+        ((Geom *)_object)->reset_usage_hint(fresh_cdata);
         nassertv(fresh_cdata->_got_usage_hint);
         nassertv(fresh_cdata->_got_usage_hint);
       }
       }
 
 

+ 5 - 1
panda/src/gobj/geom.h

@@ -397,6 +397,10 @@ private:
 //       Class : GeomPipelineReader
 //       Class : GeomPipelineReader
 // Description : Encapsulates the data from a Geom,
 // Description : Encapsulates the data from a Geom,
 //               pre-fetched for one stage of the pipeline.
 //               pre-fetched for one stage of the pipeline.
+//
+//               Does not hold a reference to the Geom.  The caller
+//               must ensure that the Geom persists for at least the
+//               lifetime of the GeomPipelineReader.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums {
 class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums {
 public:
 public:
@@ -434,7 +438,7 @@ public:
             bool force) const;
             bool force) const;
 
 
 private:
 private:
-  CPT(Geom) _object;
+  const Geom *_object;
   Thread *_current_thread;
   Thread *_current_thread;
   const Geom::CData *_cdata;
   const Geom::CData *_cdata;
 
 

+ 2 - 2
panda/src/gobj/geomPrimitive.I

@@ -107,8 +107,8 @@ is_composite() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomPrimitive::
 INLINE bool GeomPrimitive::
 is_indexed() const {
 is_indexed() const {
-  GeomPrimitivePipelineReader reader(this, Thread::get_current_thread());
-  return reader.is_indexed();
+  CDReader cdata(_cycler);
+  return (!cdata->_vertices.is_null());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 12 - 0
panda/src/mathutil/boundingVolume.cxx

@@ -84,6 +84,18 @@ write(ostream &out, int indent_level) const {
   indent(out, indent_level) << *this << "\n";
   indent(out, indent_level) << *this << "\n";
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: BoundingVolume::as_geometric_bounding_volume
+//       Access: Public, Virtual
+//  Description: Virtual downcast method.  Returns this object as a
+//               pointer of the indicated type, if it is in fact that
+//               type.  Returns NULL if it is not that type.
+////////////////////////////////////////////////////////////////////
+GeometricBoundingVolume *BoundingVolume::
+as_geometric_bounding_volume() {
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: BoundingVolume::as_geometric_bounding_volume
 //     Function: BoundingVolume::as_geometric_bounding_volume
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 1 - 0
panda/src/mathutil/boundingVolume.h

@@ -112,6 +112,7 @@ PUBLISHED:
   };
   };
 
 
 public:
 public:
+  virtual GeometricBoundingVolume *as_geometric_bounding_volume();
   virtual const GeometricBoundingVolume *as_geometric_bounding_volume() const;
   virtual const GeometricBoundingVolume *as_geometric_bounding_volume() const;
   virtual const FiniteBoundingVolume *as_finite_bounding_volume() const;
   virtual const FiniteBoundingVolume *as_finite_bounding_volume() const;
   virtual const BoundingSphere *as_bounding_sphere() const;
   virtual const BoundingSphere *as_bounding_sphere() const;

+ 13 - 1
panda/src/mathutil/geometricBoundingVolume.cxx

@@ -19,7 +19,19 @@ TypeHandle GeometricBoundingVolume::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeometricBoundingVolume::as_geometric_bounding_volume
 //     Function: GeometricBoundingVolume::as_geometric_bounding_volume
-//       Access: Public, Virtual
+//       Access: Public, Virtual, Final
+//  Description: Virtual downcast method.  Returns this object as a
+//               pointer of the indicated type, if it is in fact that
+//               type.  Returns NULL if it is not that type.
+////////////////////////////////////////////////////////////////////
+GeometricBoundingVolume *GeometricBoundingVolume::
+as_geometric_bounding_volume() {
+  return this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeometricBoundingVolume::as_geometric_bounding_volume
+//       Access: Public, Virtual, Final
 //  Description: Virtual downcast method.  Returns this object as a
 //  Description: Virtual downcast method.  Returns this object as a
 //               pointer of the indicated type, if it is in fact that
 //               pointer of the indicated type, if it is in fact that
 //               type.  Returns NULL if it is not that type.
 //               type.  Returns NULL if it is not that type.

+ 2 - 1
panda/src/mathutil/geometricBoundingVolume.h

@@ -53,7 +53,8 @@ PUBLISHED:
   virtual void xform(const LMatrix4 &mat)=0;
   virtual void xform(const LMatrix4 &mat)=0;
 
 
 public:
 public:
-  virtual const GeometricBoundingVolume *as_geometric_bounding_volume() const;
+  virtual GeometricBoundingVolume *as_geometric_bounding_volume() FINAL;
+  virtual const GeometricBoundingVolume *as_geometric_bounding_volume() const FINAL;
 
 
 protected:
 protected:
   // Some virtual functions to implement fundamental bounding
   // Some virtual functions to implement fundamental bounding

+ 3 - 3
panda/src/pgraph/alphaTestAttrib.cxx

@@ -76,13 +76,13 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int AlphaTestAttrib::
 int AlphaTestAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const AlphaTestAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const AlphaTestAttrib *ta = (const AlphaTestAttrib *)other;
+
   int compare_result = ((int)_mode - (int)ta->_mode) ;
   int compare_result = ((int)_mode - (int)ta->_mode) ;
   if (compare_result != 0) {
   if (compare_result != 0) {
     return compare_result;
     return compare_result;
   }
   }
-   
+
   if (_reference_alpha != ta->_reference_alpha) {
   if (_reference_alpha != ta->_reference_alpha) {
     return _reference_alpha < ta->_reference_alpha ? -1 : 1;
     return _reference_alpha < ta->_reference_alpha ? -1 : 1;
   }
   }

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

@@ -65,7 +65,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;
@@ -74,7 +74,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "AlphaTestAttrib",
     register_type(_type_handle, "AlphaTestAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new AlphaTestAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 27 - 9
panda/src/pgraph/antialiasAttrib.cxx

@@ -75,11 +75,7 @@ make(unsigned short mode) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) AntialiasAttrib::
 CPT(RenderAttrib) AntialiasAttrib::
 make_default() {
 make_default() {
-  if (default_antialias_enable) {
-    return return_new(new AntialiasAttrib(M_auto));
-  } else {
-    return return_new(new AntialiasAttrib(M_none));
-  }
+  return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -146,8 +142,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int AntialiasAttrib::
 int AntialiasAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const AntialiasAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const AntialiasAttrib *ta = (const AntialiasAttrib *)other;
+
   if (_mode != ta->_mode) {
   if (_mode != ta->_mode) {
     return (int)_mode - (int)ta->_mode;
     return (int)_mode - (int)ta->_mode;
   }
   }
@@ -190,8 +186,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) AntialiasAttrib::
 CPT(RenderAttrib) AntialiasAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const AntialiasAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const AntialiasAttrib *ta = (const AntialiasAttrib *)other;
 
 
   unsigned short mode_type;
   unsigned short mode_type;
   unsigned short mode_quality;
   unsigned short mode_quality;
@@ -277,3 +272,26 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 
 
   _mode = scan.get_uint16();
   _mode = scan.get_uint16();
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AntialiasAttrib::init_type
+//       Access: Public, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+void AntialiasAttrib::
+init_type() {
+  RenderAttrib::init_type();
+  register_type(_type_handle, "AntialiasAttrib",
+                RenderAttrib::get_class_type());
+
+  // This is defined here, since we have otherwise no guarantee that
+  // the config var has already been constructed by the time we call
+  // init_type() at static init time.
+  static ConfigVariableBool default_antialias_enable
+  ("default-antialias-enable", false,
+   PRC_DESC("Set this true to enable the M_auto antialiasing mode for all "
+            "nodes by default."));
+
+  _attrib_slot = register_slot(_type_handle, 100,
+    new AntialiasAttrib(default_antialias_enable ? M_auto : M_none));
+}

+ 2 - 7
panda/src/pgraph/antialiasAttrib.h

@@ -80,17 +80,12 @@ 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;
   }
   }
-  static void init_type() {
-    RenderAttrib::init_type();
-    register_type(_type_handle, "AntialiasAttrib",
-                  RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
-  }
+  static void init_type();
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();
   }
   }

+ 4 - 6
panda/src/pgraph/audioVolumeAttrib.cxx

@@ -147,8 +147,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int AudioVolumeAttrib::
 int AudioVolumeAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const AudioVolumeAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const AudioVolumeAttrib *ta = (const AudioVolumeAttrib *)other;
 
 
   if (_off != ta->_off) {
   if (_off != ta->_off) {
     return (int)_off - (int)ta->_off;
     return (int)_off - (int)ta->_off;
@@ -198,8 +197,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) AudioVolumeAttrib::
 CPT(RenderAttrib) AudioVolumeAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const AudioVolumeAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const AudioVolumeAttrib *ta = (const AudioVolumeAttrib *)other;
 
 
   if (ta->is_off()) {
   if (ta->is_off()) {
     return ta;
     return ta;
@@ -223,8 +221,8 @@ invert_compose_impl(const RenderAttrib *other) const {
   if (is_off()) {
   if (is_off()) {
     return other;
     return other;
   }
   }
-  const AudioVolumeAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const AudioVolumeAttrib *ta = (const AudioVolumeAttrib *)other;
+
   PN_stdfloat new_volume = _volume == 0.0f ? 1.0f : ta->_volume / _volume;
   PN_stdfloat new_volume = _volume == 0.0f ? 1.0f : ta->_volume / _volume;
 
 
   AudioVolumeAttrib *attrib = new AudioVolumeAttrib(false, new_volume);
   AudioVolumeAttrib *attrib = new AudioVolumeAttrib(false, new_volume);

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

@@ -73,7 +73,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;
@@ -82,7 +82,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "AudioVolumeAttrib",
     register_type(_type_handle, "AudioVolumeAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new AudioVolumeAttrib(false, 1));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -88,8 +88,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int AuxBitplaneAttrib::
 int AuxBitplaneAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const AuxBitplaneAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const AuxBitplaneAttrib *ta = (const AuxBitplaneAttrib *)other;
+
   int compare_result = _outputs - ta->_outputs;
   int compare_result = _outputs - ta->_outputs;
   if (compare_result != 0) {
   if (compare_result != 0) {
     return compare_result;
     return compare_result;

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

@@ -108,7 +108,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "AuxBitplaneAttrib",
     register_type(_type_handle, "AuxBitplaneAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new AuxBitplaneAttrib(0));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -148,7 +148,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ClipPlaneAttrib",
     register_type(_type_handle, "ClipPlaneAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new ClipPlaneAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -122,8 +122,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ColorAttrib::
 int ColorAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const ColorAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ColorAttrib *ta = (const ColorAttrib *)other;
+
   if (_type != ta->_type) {
   if (_type != ta->_type) {
     return (int)_type - (int)ta->_type;
     return (int)_type - (int)ta->_type;
   }
   }

+ 2 - 1
panda/src/pgraph/colorAttrib.h

@@ -86,7 +86,8 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ColorAttrib",
     register_type(_type_handle, "ColorAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100,
+      new ColorAttrib(T_off, LColor(1, 1, 1, 1)));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 2
panda/src/pgraph/colorBlendAttrib.cxx

@@ -113,8 +113,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ColorBlendAttrib::
 int ColorBlendAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const ColorBlendAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ColorBlendAttrib *ta = (const ColorBlendAttrib *)other;
 
 
   if (_mode != ta->_mode) {
   if (_mode != ta->_mode) {
     return (int)_mode - (int)ta->_mode;
     return (int)_mode - (int)ta->_mode;

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

@@ -129,7 +129,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ColorBlendAttrib",
     register_type(_type_handle, "ColorBlendAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new ColorBlendAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 4 - 6
panda/src/pgraph/colorScaleAttrib.cxx

@@ -186,8 +186,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ColorScaleAttrib::
 int ColorScaleAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const ColorScaleAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ColorScaleAttrib *ta = (const ColorScaleAttrib *)other;
 
 
   if (is_off() != ta->is_off()) {
   if (is_off() != ta->is_off()) {
     return (int)is_off() - (int)ta->is_off();
     return (int)is_off() - (int)ta->is_off();
@@ -233,8 +232,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) ColorScaleAttrib::
 CPT(RenderAttrib) ColorScaleAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const ColorScaleAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ColorScaleAttrib *ta = (const ColorScaleAttrib *)other;
 
 
   if (ta->is_off()) {
   if (ta->is_off()) {
     return ta;
     return ta;
@@ -263,8 +261,8 @@ invert_compose_impl(const RenderAttrib *other) const {
   if (is_off()) {
   if (is_off()) {
     return other;
     return other;
   }
   }
-  const ColorScaleAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ColorScaleAttrib *ta = (const ColorScaleAttrib *)other;
+
   LVecBase4 new_scale(_scale[0] == 0.0f ? 1.0f : ta->_scale[0] / _scale[0],
   LVecBase4 new_scale(_scale[0] == 0.0f ? 1.0f : ta->_scale[0] / _scale[0],
                        _scale[1] == 0.0f ? 1.0f : ta->_scale[1] / _scale[1],
                        _scale[1] == 0.0f ? 1.0f : ta->_scale[1] / _scale[1],
                        _scale[2] == 0.0f ? 1.0f : ta->_scale[2] / _scale[2],
                        _scale[2] == 0.0f ? 1.0f : ta->_scale[2] / _scale[2],

+ 2 - 1
panda/src/pgraph/colorScaleAttrib.h

@@ -92,7 +92,8 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ColorScaleAttrib",
     register_type(_type_handle, "ColorScaleAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100,
+      new ColorScaleAttrib(false, LVecBase4(1, 1, 1, 1)));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 2
panda/src/pgraph/colorWriteAttrib.cxx

@@ -89,8 +89,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ColorWriteAttrib::
 int ColorWriteAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const ColorWriteAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ColorWriteAttrib *ta = (const ColorWriteAttrib *)other;
   return (int)_channels - (int)ta->_channels;
   return (int)_channels - (int)ta->_channels;
 }
 }
 
 

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

@@ -85,7 +85,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ColorWriteAttrib",
     register_type(_type_handle, "ColorWriteAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new ColorWriteAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -310,11 +310,6 @@ ConfigVariableInt max_lenses
           "this can be used as a simple sanity check.  Set it larger or "
           "this can be used as a simple sanity check.  Set it larger or "
           "smaller to suit your needs."));
           "smaller to suit your needs."));
 
 
-ConfigVariableBool default_antialias_enable
-("default-antialias-enable", false,
- PRC_DESC("Set this true to enable the M_auto antialiasing mode for all "
-          "nodes by default."));
-
 ConfigVariableBool polylight_info
 ConfigVariableBool polylight_info
 ("polylight-info", false,
 ("polylight-info", false,
  PRC_DESC("Set this true to view some info statements regarding the polylight. "
  PRC_DESC("Set this true to view some info statements regarding the polylight. "

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

@@ -58,7 +58,6 @@ extern EXPCL_PANDA_PGRAPH ConfigVariableBool premunge_data;
 extern ConfigVariableBool preserve_geom_nodes;
 extern ConfigVariableBool preserve_geom_nodes;
 extern ConfigVariableBool flatten_geoms;
 extern ConfigVariableBool flatten_geoms;
 extern EXPCL_PANDA_PGRAPH ConfigVariableInt max_lenses;
 extern EXPCL_PANDA_PGRAPH ConfigVariableInt max_lenses;
-extern ConfigVariableBool default_antialias_enable;
 
 
 extern ConfigVariableBool polylight_info;
 extern ConfigVariableBool polylight_info;
 
 

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

@@ -84,8 +84,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int CullBinAttrib::
 int CullBinAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const CullBinAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const CullBinAttrib *ta = (const CullBinAttrib *)other;
+
   if (_draw_order != ta->_draw_order) {
   if (_draw_order != ta->_draw_order) {
     return _draw_order - ta->_draw_order;
     return _draw_order - ta->_draw_order;
   }
   }

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

@@ -73,7 +73,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "CullBinAttrib",
     register_type(_type_handle, "CullBinAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new CullBinAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 4 - 6
panda/src/pgraph/cullFaceAttrib.cxx

@@ -154,8 +154,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int CullFaceAttrib::
 int CullFaceAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const CullFaceAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const CullFaceAttrib *ta = (const CullFaceAttrib *)other;
+
   if (_mode != ta->_mode) {
   if (_mode != ta->_mode) {
     return (int)_mode - (int)ta->_mode;
     return (int)_mode - (int)ta->_mode;
   }
   }
@@ -199,8 +199,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) CullFaceAttrib::
 CPT(RenderAttrib) CullFaceAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const CullFaceAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const CullFaceAttrib *ta = (const CullFaceAttrib *)other;
 
 
   if (!_reverse && ta->_mode != M_cull_unchanged) {
   if (!_reverse && ta->_mode != M_cull_unchanged) {
     // The normal case (there is nothing funny going on): the second
     // The normal case (there is nothing funny going on): the second
@@ -231,8 +230,7 @@ compose_impl(const RenderAttrib *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) CullFaceAttrib::
 CPT(RenderAttrib) CullFaceAttrib::
 invert_compose_impl(const RenderAttrib *other) const {
 invert_compose_impl(const RenderAttrib *other) const {
-  const CullFaceAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const CullFaceAttrib *ta = (const CullFaceAttrib *)other;
 
 
   // The invert case is the same as the normal case, except that the
   // The invert case is the same as the normal case, except that the
   // meaning of _reverse is inverted.  See compose_impl(), above.
   // meaning of _reverse is inverted.  See compose_impl(), above.

+ 2 - 1
panda/src/pgraph/cullFaceAttrib.h

@@ -84,7 +84,8 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "CullFaceAttrib",
     register_type(_type_handle, "CullFaceAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100,
+                                 new CullFaceAttrib(M_cull_clockwise, false));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 2 - 3
panda/src/pgraph/cullResult.cxx

@@ -237,9 +237,8 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
   }
   }
 
 
   // Check for a special wireframe setting.
   // Check for a special wireframe setting.
-  const RenderModeAttrib *rmode = (const RenderModeAttrib *)
-    object->_state->get_attrib(RenderModeAttrib::get_class_slot());
-  if (rmode != (const RenderModeAttrib *)NULL) {
+  const RenderModeAttrib *rmode;
+  if (object->_state->get_attrib(rmode)) {
     if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) {
     if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) {
       CullableObject *wireframe_part = new CullableObject(*object);
       CullableObject *wireframe_part = new CullableObject(*object);
       wireframe_part->_state = get_wireframe_overlay_state(rmode);
       wireframe_part->_state = get_wireframe_overlay_state(rmode);

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

@@ -93,7 +93,9 @@ apply_transform_and_state(CullTraverser *trav,
         // Copy the bounding volumes for the frustums so we can
         // Copy the bounding volumes for the frustums so we can
         // transform them.
         // transform them.
         if (_view_frustum != (GeometricBoundingVolume *)NULL) {
         if (_view_frustum != (GeometricBoundingVolume *)NULL) {
-          _view_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy());
+          _view_frustum = _view_frustum->make_copy()->as_geometric_bounding_volume();
+          nassertv(_view_frustum != (GeometricBoundingVolume *)NULL);
+
           _view_frustum->xform(inv_transform->get_mat());
           _view_frustum->xform(inv_transform->get_mat());
         }
         }
 
 
@@ -106,9 +108,9 @@ apply_transform_and_state(CullTraverser *trav,
 
 
   if (clip_plane_cull) {
   if (clip_plane_cull) {
     _cull_planes = _cull_planes->apply_state(trav, this,
     _cull_planes = _cull_planes->apply_state(trav, this,
-                                             DCAST(ClipPlaneAttrib, node_state->get_attrib(ClipPlaneAttrib::get_class_slot())),
+                                             (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()),
                                              DCAST(ClipPlaneAttrib, off_clip_planes),
                                              DCAST(ClipPlaneAttrib, off_clip_planes),
-                                             DCAST(OccluderEffect, node_effects->get_effect(OccluderEffect::get_class_type())));
+                                             (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type()));
   }
   }
 }
 }
 
 
@@ -122,7 +124,8 @@ is_in_view_impl() {
   const GeometricBoundingVolume *node_gbv = NULL;
   const GeometricBoundingVolume *node_gbv = NULL;
 
 
   if (_view_frustum != (GeometricBoundingVolume *)NULL) {
   if (_view_frustum != (GeometricBoundingVolume *)NULL) {
-    DCAST_INTO_R(node_gbv, _node_reader.get_bounds(), false)
+    node_gbv = _node_reader.get_bounds()->as_geometric_bounding_volume();
+    nassertr(node_gbv != (const GeometricBoundingVolume *)NULL, false);
 
 
     int result = _view_frustum->contains(node_gbv);
     int result = _view_frustum->contains(node_gbv);
 
 
@@ -168,7 +171,8 @@ is_in_view_impl() {
 
 
   if (!_cull_planes->is_empty()) {
   if (!_cull_planes->is_empty()) {
     if (node_gbv == (const GeometricBoundingVolume *)NULL) {
     if (node_gbv == (const GeometricBoundingVolume *)NULL) {
-      DCAST_INTO_R(node_gbv, _node_reader.get_bounds(), false)
+      node_gbv = _node_reader.get_bounds()->as_geometric_bounding_volume();
+      nassertr(node_gbv != (const GeometricBoundingVolume *)NULL, false);
     }
     }
 
 
     // Also cull against the current clip planes.
     // Also cull against the current clip planes.

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

@@ -140,8 +140,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
       }
       }
     }
     }
 
 
-    StateMunger *state_munger;
-    DCAST_INTO_R(state_munger, munger, false);
+    StateMunger *state_munger = (StateMunger *)munger;
     _state = state_munger->munge_state(_state);
     _state = state_munger->munge_state(_state);
 
 
     // If there is any animation left in the vertex data after it
     // If there is any animation left in the vertex data after it

+ 6 - 6
panda/src/pgraph/depthOffsetAttrib.cxx

@@ -95,8 +95,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int DepthOffsetAttrib::
 int DepthOffsetAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const DepthOffsetAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const DepthOffsetAttrib *ta = (const DepthOffsetAttrib *)other;
+
   if (_offset != ta->_offset) {
   if (_offset != ta->_offset) {
     return _offset - ta->_offset;
     return _offset - ta->_offset;
   }
   }
@@ -147,8 +147,8 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) DepthOffsetAttrib::
 CPT(RenderAttrib) DepthOffsetAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const DepthOffsetAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const DepthOffsetAttrib *ta = (const DepthOffsetAttrib *)other;
+
   int new_offset = ta->_offset + _offset;
   int new_offset = ta->_offset + _offset;
 
 
   DepthOffsetAttrib *attrib = new DepthOffsetAttrib(new_offset, ta->_min_value, ta->_max_value);
   DepthOffsetAttrib *attrib = new DepthOffsetAttrib(new_offset, ta->_min_value, ta->_max_value);
@@ -166,8 +166,8 @@ compose_impl(const RenderAttrib *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) DepthOffsetAttrib::
 CPT(RenderAttrib) DepthOffsetAttrib::
 invert_compose_impl(const RenderAttrib *other) const {
 invert_compose_impl(const RenderAttrib *other) const {
-  const DepthOffsetAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const DepthOffsetAttrib *ta = (const DepthOffsetAttrib *)other;
+
   int new_offset = ta->_offset - _offset;
   int new_offset = ta->_offset - _offset;
 
 
   DepthOffsetAttrib *attrib = new DepthOffsetAttrib(new_offset, ta->_min_value, ta->_max_value);
   DepthOffsetAttrib *attrib = new DepthOffsetAttrib(new_offset, ta->_min_value, ta->_max_value);

+ 2 - 1
panda/src/pgraph/depthOffsetAttrib.h

@@ -107,7 +107,8 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "DepthOffsetAttrib",
     register_type(_type_handle, "DepthOffsetAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100,
+                                 new DepthOffsetAttrib(0, 0, 1));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -74,8 +74,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int DepthTestAttrib::
 int DepthTestAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const DepthTestAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const DepthTestAttrib *ta = (const DepthTestAttrib *)other;
+
   return (int)_mode - (int)ta->_mode;
   return (int)_mode - (int)ta->_mode;
 }
 }
 
 

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

@@ -69,7 +69,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "DepthTestAttrib",
     register_type(_type_handle, "DepthTestAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new DepthTestAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -81,8 +81,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int DepthWriteAttrib::
 int DepthWriteAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const DepthWriteAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const DepthWriteAttrib *ta = (const DepthWriteAttrib *)other;
+
   return (int)_mode - (int)ta->_mode;
   return (int)_mode - (int)ta->_mode;
 }
 }
 
 

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

@@ -75,7 +75,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "DepthWriteAttrib",
     register_type(_type_handle, "DepthWriteAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new DepthWriteAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 2
panda/src/pgraph/fogAttrib.cxx

@@ -91,8 +91,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int FogAttrib::
 int FogAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const FogAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const FogAttrib *ta = (const FogAttrib *)other;
 
 
   // Comparing pointers by subtraction is problematic.  Instead of
   // Comparing pointers by subtraction is problematic.  Instead of
   // doing this, we'll just depend on the built-in != and < operators
   // doing this, we'll just depend on the built-in != and < operators

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

@@ -72,7 +72,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "FogAttrib",
     register_type(_type_handle, "FogAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new FogAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 2 - 4
panda/src/pgraph/lightAttrib.cxx

@@ -696,8 +696,7 @@ write(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int LightAttrib::
 int LightAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const LightAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const LightAttrib *ta = (const LightAttrib *)other;
 
 
   if (_off_all_lights != ta->_off_all_lights) {
   if (_off_all_lights != ta->_off_all_lights) {
     return (int)_off_all_lights - (int)ta->_off_all_lights;
     return (int)_off_all_lights - (int)ta->_off_all_lights;
@@ -803,8 +802,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) LightAttrib::
 CPT(RenderAttrib) LightAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const LightAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const LightAttrib *ta = (const LightAttrib *)other;
 
 
   if (ta->_off_all_lights) {
   if (ta->_off_all_lights) {
     // If the other type turns off all lights, it doesn't matter what
     // If the other type turns off all lights, it doesn't matter what

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

@@ -162,7 +162,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "LightAttrib",
     register_type(_type_handle, "LightAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 20, make_default);
+    _attrib_slot = register_slot(_type_handle, 20, new LightAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -241,8 +241,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int LightRampAttrib::
 int LightRampAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const LightRampAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const LightRampAttrib *ta = (const LightRampAttrib *)other;
+
   int compare_result = ((int)_mode - (int)ta->_mode) ;
   int compare_result = ((int)_mode - (int)ta->_mode) ;
   if (compare_result != 0) {
   if (compare_result != 0) {
     return compare_result;
     return compare_result;

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

@@ -95,7 +95,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "LightRampAttrib",
     register_type(_type_handle, "LightRampAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new LightRampAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 2
panda/src/pgraph/materialAttrib.cxx

@@ -92,8 +92,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int MaterialAttrib::
 int MaterialAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const MaterialAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const MaterialAttrib *ta = (const MaterialAttrib *)other;
 
 
   // Comparing pointers by subtraction is problematic.  Instead of
   // Comparing pointers by subtraction is problematic.  Instead of
   // doing this, we'll just depend on the built-in != and < operators
   // doing this, we'll just depend on the built-in != and < operators

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

@@ -75,7 +75,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "MaterialAttrib",
     register_type(_type_handle, "MaterialAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new MaterialAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 2 - 17
panda/src/pgraph/renderAttrib.I

@@ -49,20 +49,6 @@ invert_compose(const RenderAttrib *other) const {
   return invert_compose_impl(other);
   return invert_compose_impl(other);
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: RenderAttrib::always_reissue
-//       Access: Public
-//  Description: Returns true if the RenderAttrib should be reissued
-//               to the GSG with every state change, even if it is the
-//               same pointer as it was before; or false for the
-//               normal case, to reissue only when the RenderAttrib
-//               pointer changes.
-////////////////////////////////////////////////////////////////////
-INLINE bool RenderAttrib::
-always_reissue() const {
-  return _always_reissue;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::compare_to
 //     Function: RenderAttrib::compare_to
 //       Access: Published
 //       Access: Published
@@ -160,8 +146,7 @@ calc_hash() {
 //               number.  See RenderAttribRegistry.
 //               number.  See RenderAttribRegistry.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int RenderAttrib::
 INLINE int RenderAttrib::
-register_slot(TypeHandle type_handle, int sort,
-              RenderAttribRegistry::MakeDefaultFunc *make_default_func) {
+register_slot(TypeHandle type_handle, int sort, RenderAttrib *default_attrib) {
   RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
   RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
-  return reg->register_slot(type_handle, sort, make_default_func);
+  return reg->register_slot(type_handle, sort, default_attrib);
 }
 }

+ 6 - 7
panda/src/pgraph/renderAttrib.cxx

@@ -38,8 +38,6 @@ RenderAttrib() {
     init_attribs();
     init_attribs();
   }
   }
   _saved_entry = -1;
   _saved_entry = -1;
-
-  _always_reissue = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -435,13 +433,14 @@ return_unique(RenderAttrib *attrib) {
     return attrib;
     return attrib;
   }
   }
 
 
-  // Save the attrib in a local PointerTo so that it will be freed at
-  // the end of this function if no one else uses it.
-  CPT(RenderAttrib) pt_attrib = attrib;
-
   int si = _attribs->find(attrib);
   int si = _attribs->find(attrib);
   if (si != -1) {
   if (si != -1) {
     // There's an equivalent attrib already in the set.  Return it.
     // There's an equivalent attrib already in the set.  Return it.
+    // If this is a newly created RenderAttrib, though, be sure to
+    // delete it.
+    if (attrib->get_ref_count() == 0) {
+      delete attrib;
+    }
     return _attribs->get_key(si);
     return _attribs->get_key(si);
   }
   }
 
 
@@ -456,7 +455,7 @@ return_unique(RenderAttrib *attrib) {
 
 
   // Save the index and return the input attrib.
   // Save the index and return the input attrib.
   attrib->_saved_entry = si;
   attrib->_saved_entry = si;
-  return pt_attrib;
+  return attrib;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 6
panda/src/pgraph/renderAttrib.h

@@ -73,8 +73,6 @@ PUBLISHED:
   virtual bool lower_attrib_can_override() const;
   virtual bool lower_attrib_can_override() const;
 
 
 public:
 public:
-  INLINE bool always_reissue() const;
-
   virtual bool has_cull_callback() const;
   virtual bool has_cull_callback() const;
   virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
   virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
 
 
@@ -190,14 +188,11 @@ protected:
 
 
 public:
 public:
   INLINE static int register_slot(TypeHandle type_handle, int sort,
   INLINE static int register_slot(TypeHandle type_handle, int sort,
-                                  RenderAttribRegistry::MakeDefaultFunc *make_default_func);
+                                  RenderAttrib *default_attrib);
 
 
 private:
 private:
   void release_new();
   void release_new();
 
 
-protected:
-  bool _always_reissue;
-
 public:
 public:
   static void init_attribs();
   static void init_attribs();
 
 
@@ -218,6 +213,8 @@ private:
 
 
   static PStatCollector _garbage_collect_pcollector;
   static PStatCollector _garbage_collect_pcollector;
 
 
+  friend class RenderAttribRegistry;
+
 public:
 public:
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
   static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager);
   static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager);

+ 30 - 16
panda/src/pgraph/renderAttribRegistry.I

@@ -30,7 +30,7 @@ get_slot(TypeHandle type_handle) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttribRegistry::get_max_slots
 //     Function: RenderAttribRegistry::get_max_slots
-//       Access: Published
+//       Access: Published, Static
 //  Description: Returns the maximum number that any slot number is
 //  Description: Returns the maximum number that any slot number is
 //               allowed to grow.  Actually, this number will be one
 //               allowed to grow.  Actually, this number will be one
 //               higher than the highest possible slot number.  This
 //               higher than the highest possible slot number.  This
@@ -41,8 +41,8 @@ get_slot(TypeHandle type_handle) const {
 //               This number will not change during the lifetime of
 //               This number will not change during the lifetime of
 //               the application.
 //               the application.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE int RenderAttribRegistry::
-get_max_slots() const {
+CONSTEXPR int RenderAttribRegistry::
+get_max_slots() {
   return _max_slots;
   return _max_slots;
 }
 }
 
 
@@ -80,6 +80,20 @@ get_slot_sort(int slot) const {
   return _registry[slot]._sort;
   return _registry[slot]._sort;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttribRegistry::get_slot_default
+//       Access: Published
+//  Description: Returns the default RenderAttrib object associated
+//               with slot n.  This is the attrib that should be
+//               applied in the absence of any other attrib of this
+//               type.
+////////////////////////////////////////////////////////////////////
+INLINE const RenderAttrib *RenderAttribRegistry::
+get_slot_default(int slot) const {
+  nassertr(slot >= 0 && slot < (int)_registry.size(), 0);
+  return _registry[slot]._default_attrib;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttribRegistry::get_num_sorted_slots
 //     Function: RenderAttribRegistry::get_num_sorted_slots
 //       Access: Published
 //       Access: Published
@@ -104,18 +118,6 @@ get_sorted_slot(int n) const {
   return _sorted_slots[n];
   return _sorted_slots[n];
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: RenderAttribRegistry::get_array_chain
-//       Access: Published
-//  Description: Returns the DeletedBufferChain object that may be
-//               used to allocated appropriately-sized arrays of
-//               RenderState::Attribute objects.
-////////////////////////////////////////////////////////////////////
-INLINE DeletedBufferChain *RenderAttribRegistry::
-get_array_chain() const {
-  return _array_chain;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttribRegistry::get_global_ptr
 //     Function: RenderAttribRegistry::get_global_ptr
 //       Access: Published, Static
 //       Access: Published, Static
@@ -154,9 +156,21 @@ SortSlots(RenderAttribRegistry *reg) : _reg(reg) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttribRegistry::SortSlots::operator ()
 //     Function: RenderAttribRegistry::SortSlots::operator ()
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool RenderAttribRegistry::SortSlots::
 INLINE bool RenderAttribRegistry::SortSlots::
 operator () (int a, int b) const {
 operator () (int a, int b) const {
   return _reg->get_slot_sort(a) < _reg->get_slot_sort(b);
   return _reg->get_slot_sort(a) < _reg->get_slot_sort(b);
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttribRegistry::RegistryNode::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE RenderAttribRegistry::RegistryNode::
+RegistryNode(TypeHandle type, int sort, const RenderAttrib *default_attrib) :
+  _type(type),
+  _sort(sort),
+  _default_attrib(default_attrib) {
+}

+ 31 - 54
panda/src/pgraph/renderAttribRegistry.cxx

@@ -26,37 +26,12 @@ RenderAttribRegistry *RenderAttribRegistry::_global_ptr;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderAttribRegistry::
 RenderAttribRegistry::
 RenderAttribRegistry() {
 RenderAttribRegistry() {
-  ConfigVariableInt max_attribs
-    ("max-attribs", SlotMask::get_max_num_bits(),
-     PRC_DESC("This specifies the maximum number of different RenderAttrib "
-              "types that may be defined at runtime.  Normally you should "
-              "never need to change this, but if the default value is too "
-              "low for the number of attribs that Panda actually defines, "
-              "you may need to raise this number."));
-
-  // Assign this number once, at startup, and never change it again.
-  _max_slots = max((int)max_attribs, 1);
-  if (_max_slots > SlotMask::get_max_num_bits()) {
-    pgraph_cat->warning()
-      << "Value for max-attribs too large: cannot exceed " 
-      << SlotMask::get_max_num_bits()
-      << " in this build.  To raise this limit, change the typedef "
-      << "for SlotMask in renderAttribRegistry.h and recompile.\n";
-      
-    _max_slots = SlotMask::get_max_num_bits();
-  }
-
-  // Get a DeletedBufferChain to manage the arrays of RenderAttribs that are
-  // allocated within each RenderState object.
-  init_memory_hook();
-  _array_chain = memory_hook->get_deleted_chain(_max_slots * sizeof(RenderState::Attribute));
+  _registry.reserve(_max_slots);
+  _sorted_slots.reserve(_max_slots);
 
 
   // Reserve slot 0 for TypeHandle::none(), and for types that exceed
   // Reserve slot 0 for TypeHandle::none(), and for types that exceed
   // max_slots.
   // max_slots.
-  RegistryNode node;
-  node._sort = 0;
-  node._make_default_func = NULL;
-  _registry.push_back(node);
+  _registry.push_back(RegistryNode(TypeHandle::none(), 0, NULL));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -86,9 +61,9 @@ RenderAttribRegistry::
 //               RenderAttribs (that is, those which are more
 //               RenderAttribs (that is, those which are more
 //               expensive to change) have lower sort values.
 //               expensive to change) have lower sort values.
 //
 //
-//               The make_default_func pointer is a function that may
-//               be called to generate a default RenderAttrib to apply
-//               in the absence of any other attrib of this type.
+//               The default_attrib pointer should be a newly
+//               created instance of this attribute that represents
+//               the default state for this attribute.
 //
 //
 //               register_slot() is intended to be called at
 //               register_slot() is intended to be called at
 //               application start for each different RenderAttrib
 //               application start for each different RenderAttrib
@@ -96,8 +71,11 @@ RenderAttribRegistry::
 //               slot number to each one.
 //               slot number to each one.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int RenderAttribRegistry::
 int RenderAttribRegistry::
-register_slot(TypeHandle type_handle, int sort,
-              RenderAttribRegistry::MakeDefaultFunc *make_default_func) {
+register_slot(TypeHandle type_handle, int sort, RenderAttrib *default_attrib) {
+  // Sanity check; if this triggers, you either passed a wrong argument,
+  // or you didn't use the type system correctly.
+  nassertr(default_attrib->get_type() == type_handle, 0);
+
   int type_index = type_handle.get_index();
   int type_index = type_handle.get_index();
   while (type_index >= (int)_slots_by_type.size()) {
   while (type_index >= (int)_slots_by_type.size()) {
     _slots_by_type.push_back(0);
     _slots_by_type.push_back(0);
@@ -111,19 +89,33 @@ register_slot(TypeHandle type_handle, int sort,
   int slot = (int)_registry.size();
   int slot = (int)_registry.size();
   if (slot >= _max_slots) {
   if (slot >= _max_slots) {
     pgraph_cat->error()
     pgraph_cat->error()
-      << "Too many registered RenderAttribs; not registering " 
+      << "Too many registered RenderAttribs; not registering "
       << type_handle << "\n";
       << type_handle << "\n";
     nassertr(false, 0);
     nassertr(false, 0);
     return 0;
     return 0;
   }
   }
 
 
+  // Register the default attribute.  We don't use return_unique and
+  // register it even if the state cache is disabled, because we can't read
+  // the state_cache config variable yet at this time.  It probably doesn't
+  // hurt to have these 32 entries around in the attrib cache.
+  if (default_attrib != (RenderAttrib *)NULL) {
+    default_attrib->calc_hash();
+
+    if (default_attrib->_saved_entry == -1) {
+      // If this attribute was already registered, something odd is going on.
+      nassertr(RenderAttrib::_attribs->find(default_attrib) == -1, 0);
+      default_attrib->_saved_entry =
+        RenderAttrib::_attribs->store(default_attrib, RenderAttrib::Empty());
+    }
+
+    // It effectively lives forever.  Might as well make it official.
+    default_attrib->local_object();
+  }
+
   _slots_by_type[type_index] = slot;
   _slots_by_type[type_index] = slot;
 
 
-  RegistryNode node;
-  node._type = type_handle;
-  node._sort = sort;
-  node._make_default_func = make_default_func;
-  _registry.push_back(node);
+  _registry.push_back(RegistryNode(type_handle, sort, default_attrib));
 
 
   _sorted_slots.push_back(slot);
   _sorted_slots.push_back(slot);
   ::sort(_sorted_slots.begin(), _sorted_slots.end(), SortSlots(this));
   ::sort(_sorted_slots.begin(), _sorted_slots.end(), SortSlots(this));
@@ -143,27 +135,12 @@ set_slot_sort(int slot, int sort) {
 
 
   // Re-sort the slot list.
   // Re-sort the slot list.
   _sorted_slots.clear();
   _sorted_slots.clear();
-  _sorted_slots.reserve(_registry.size() - 1);
   for (int i = 1; i < (int)_registry.size(); ++i) {
   for (int i = 1; i < (int)_registry.size(); ++i) {
     _sorted_slots.push_back(i);
     _sorted_slots.push_back(i);
   }
   }
   ::sort(_sorted_slots.begin(), _sorted_slots.end(), SortSlots(this));
   ::sort(_sorted_slots.begin(), _sorted_slots.end(), SortSlots(this));
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: RenderAttribRegistry::get_slot_default
-//       Access: Published
-//  Description: Returns the default RenderAttrib object associated
-//               with slot n.  This is the attrib that should be
-//               applied in the absence of any other attrib of this
-//               type.
-////////////////////////////////////////////////////////////////////
-CPT(RenderAttrib) RenderAttribRegistry::
-get_slot_default(int slot) const {
-  nassertr(slot >= 0 && slot < (int)_registry.size(), 0);
-  return (*_registry[slot]._make_default_func)();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttribRegistry::init_global_ptr
 //     Function: RenderAttribRegistry::init_global_ptr
 //       Access: Private, Static
 //       Access: Private, Static

+ 11 - 11
panda/src/pgraph/renderAttribRegistry.h

@@ -48,24 +48,26 @@ public:
   // or a DoubleBitMask<BitMask32> will be faster on a 32-bit machine.
   // or a DoubleBitMask<BitMask32> will be faster on a 32-bit machine.
   typedef BitMask32 SlotMask;
   typedef BitMask32 SlotMask;
 
 
+  // Raise this number whenever we add a new attrib.  This used to be
+  // determined at runtime, but it's better to have it as a constexpr.
+  static const int _max_slots = 29;
+
   int register_slot(TypeHandle type_handle, int sort,
   int register_slot(TypeHandle type_handle, int sort,
-                    MakeDefaultFunc *make_default_func);
+                    RenderAttrib *default_attrib);
 
 
 PUBLISHED:
 PUBLISHED:
   INLINE int get_slot(TypeHandle type_handle) const;
   INLINE int get_slot(TypeHandle type_handle) const;
-  INLINE int get_max_slots() const;
+  static CONSTEXPR int get_max_slots();
 
 
   INLINE int get_num_slots() const;
   INLINE int get_num_slots() const;
   INLINE TypeHandle get_slot_type(int slot) const;
   INLINE TypeHandle get_slot_type(int slot) const;
   INLINE int get_slot_sort(int slot) const;
   INLINE int get_slot_sort(int slot) const;
   void set_slot_sort(int slot, int sort);
   void set_slot_sort(int slot, int sort);
-  CPT(RenderAttrib) get_slot_default(int slot) const;
+  INLINE const RenderAttrib *get_slot_default(int slot) const;
 
 
   INLINE int get_num_sorted_slots() const;
   INLINE int get_num_sorted_slots() const;
   INLINE int get_sorted_slot(int n) const;
   INLINE int get_sorted_slot(int n) const;
 
 
-  INLINE DeletedBufferChain *get_array_chain() const;
-
   INLINE static RenderAttribRegistry *get_global_ptr();
   INLINE static RenderAttribRegistry *get_global_ptr();
 
 
 public:
 public:
@@ -75,8 +77,6 @@ private:
   static void init_global_ptr();
   static void init_global_ptr();
 
 
 private:
 private:
-  int _max_slots;
-
   class SortSlots {
   class SortSlots {
   public:
   public:
     INLINE SortSlots(RenderAttribRegistry *reg);
     INLINE SortSlots(RenderAttribRegistry *reg);
@@ -86,9 +86,12 @@ private:
 
 
   class RegistryNode {
   class RegistryNode {
   public:
   public:
+    INLINE RegistryNode(TypeHandle type, int sort,
+                        const RenderAttrib *default_attrib);
+
     TypeHandle _type;
     TypeHandle _type;
     int _sort;
     int _sort;
-    MakeDefaultFunc *_make_default_func;
+    const RenderAttrib *_default_attrib;
   };
   };
   typedef pvector<RegistryNode> Registry;
   typedef pvector<RegistryNode> Registry;
   Registry _registry;
   Registry _registry;
@@ -96,12 +99,9 @@ private:
   vector_int _slots_by_type;
   vector_int _slots_by_type;
   vector_int _sorted_slots;
   vector_int _sorted_slots;
 
 
-  DeletedBufferChain *_array_chain;
-
   static RenderAttribRegistry *_global_ptr;
   static RenderAttribRegistry *_global_ptr;
 };
 };
 
 
 #include "renderAttribRegistry.I"
 #include "renderAttribRegistry.I"
 
 
 #endif
 #endif
-

+ 3 - 4
panda/src/pgraph/renderModeAttrib.cxx

@@ -128,8 +128,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int RenderModeAttrib::
 int RenderModeAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const RenderModeAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const RenderModeAttrib *ta = (const RenderModeAttrib *)other;
+
   if (_mode != ta->_mode) {
   if (_mode != ta->_mode) {
     return (int)_mode - (int)ta->_mode;
     return (int)_mode - (int)ta->_mode;
   }
   }
@@ -186,8 +186,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) RenderModeAttrib::
 CPT(RenderAttrib) RenderModeAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const RenderModeAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const RenderModeAttrib *ta = (const RenderModeAttrib *)other;
 
 
   // The special mode M_unchanged means to keep the current mode.
   // The special mode M_unchanged means to keep the current mode.
   Mode mode = ta->get_mode();
   Mode mode = ta->get_mode();

+ 2 - 1
panda/src/pgraph/renderModeAttrib.h

@@ -106,7 +106,8 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "RenderModeAttrib",
     register_type(_type_handle, "RenderModeAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100,
+                                 new RenderModeAttrib(M_filled, 1, false));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 3 - 28
panda/src/pgraph/renderState.I

@@ -58,35 +58,9 @@ has_cull_callback() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CPT(RenderState) RenderState::
 INLINE CPT(RenderState) RenderState::
 make_empty() {
 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;
   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
@@ -144,7 +118,7 @@ get_attrib(TypeHandle type) const {
 //               index, or NULL if there is no such RenderAttrib in
 //               index, or NULL if there is no such RenderAttrib in
 //               the state.
 //               the state.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const RenderAttrib *RenderState::
+ALWAYS_INLINE const RenderAttrib *RenderState::
 get_attrib(int slot) const {
 get_attrib(int slot) const {
   return _attributes[slot]._attrib;
   return _attributes[slot]._attrib;
 }
 }
@@ -161,7 +135,8 @@ get_attrib_def(int slot) const {
   if (_attributes[slot]._attrib != (RenderAttrib *)NULL) {
   if (_attributes[slot]._attrib != (RenderAttrib *)NULL) {
     return _attributes[slot]._attrib;
     return _attributes[slot]._attrib;
   }
   }
-  return make_full_default()->get_attrib(slot);
+  RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr();
+  return reg->get_slot_default(slot);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 34 - 59
panda/src/pgraph/renderState.cxx

@@ -40,8 +40,7 @@
 
 
 LightReMutex *RenderState::_states_lock = NULL;
 LightReMutex *RenderState::_states_lock = NULL;
 RenderState::States *RenderState::_states = NULL;
 RenderState::States *RenderState::_states = NULL;
-CPT(RenderState) RenderState::_empty_state;
-CPT(RenderState) RenderState::_full_default_state;
+const RenderState *RenderState::_empty_state = NULL;
 UpdateSeq RenderState::_last_cycle_detect;
 UpdateSeq RenderState::_last_cycle_detect;
 int RenderState::_garbage_index = 0;
 int RenderState::_garbage_index = 0;
 
 
@@ -72,20 +71,11 @@ RenderState() :
   _auto_shader_state(NULL),
   _auto_shader_state(NULL),
   _lock("RenderState")
   _lock("RenderState")
 {
 {
-  // Allocate the _attributes array.
-  RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
-  _attributes = (Attribute *)reg->get_array_chain()->allocate(reg->get_max_slots() * sizeof(Attribute), get_class_type());
-
-  // Also make sure each element gets initialized.
-  for (int i = 0; i < reg->get_max_slots(); ++i) {
-    new(&_attributes[i]) Attribute();
-  }
-
   if (_states == (States *)NULL) {
   if (_states == (States *)NULL) {
     init_states();
     init_states();
   }
   }
   _saved_entry = -1;
   _saved_entry = -1;
-  _last_mi = _mungers.end();
+  _last_mi = -1;
   _cache_stats.add_num_states(1);
   _cache_stats.add_num_states(1);
   _read_overrides = NULL;
   _read_overrides = NULL;
   _generated_shader = NULL;
   _generated_shader = NULL;
@@ -103,17 +93,13 @@ RenderState(const RenderState &copy) :
   _auto_shader_state(NULL),
   _auto_shader_state(NULL),
   _lock("RenderState")
   _lock("RenderState")
 {
 {
-  // Allocate the _attributes array.
-  RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
-  _attributes = (Attribute *)reg->get_array_chain()->allocate(reg->get_max_slots() * sizeof(Attribute), get_class_type());
-
-  // Also make sure each element gets initialized, as a copy.
-  for (int i = 0; i < reg->get_max_slots(); ++i) {
-    new(&_attributes[i]) Attribute(copy._attributes[i]);
+  // Copy over the attributes.
+  for (int i = 0; i < RenderAttribRegistry::_max_slots; ++i) {
+    _attributes[i] = copy._attributes[i];
   }
   }
 
 
   _saved_entry = -1;
   _saved_entry = -1;
-  _last_mi = _mungers.end();
+  _last_mi = -1;
   _cache_stats.add_num_states(1);
   _cache_stats.add_num_states(1);
   _read_overrides = NULL;
   _read_overrides = NULL;
   _generated_shader = NULL;
   _generated_shader = NULL;
@@ -159,14 +145,6 @@ RenderState::
   // longer true now, probably we've been double-deleted.
   // longer true now, probably we've been double-deleted.
   nassertv(get_ref_count() == 0);
   nassertv(get_ref_count() == 0);
   _cache_stats.add_num_states(-1);
   _cache_stats.add_num_states(-1);
-
-  // Free the _attributes array.
-  RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr();
-  for (int i = 0; i < reg->get_max_slots(); ++i) {
-    _attributes[i].~Attribute();
-  }
-  reg->get_array_chain()->deallocate(_attributes, get_class_type());
-  _attributes = NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -360,7 +338,7 @@ make(const RenderAttrib *attrib1,
 CPT(RenderState) RenderState::
 CPT(RenderState) RenderState::
 make(const RenderAttrib * const *attrib, int num_attribs, int override) {
 make(const RenderAttrib * const *attrib, int num_attribs, int override) {
   if (num_attribs == 0) {
   if (num_attribs == 0) {
-    return make_empty();
+    return _empty_state;
   }
   }
   RenderState *state = new RenderState;
   RenderState *state = new RenderState;
   for (int i = 0; i < num_attribs; i++) {
   for (int i = 0; i < num_attribs; i++) {
@@ -490,7 +468,7 @@ invert_compose(const RenderState *other) const {
 
 
   if (other == this) {
   if (other == this) {
     // a->invert_compose(a) always produces identity.
     // a->invert_compose(a) always produces identity.
-    return make_empty();
+    return _empty_state;
   }
   }
 
 
   if (!state_cache) {
   if (!state_cache) {
@@ -633,7 +611,7 @@ remove_attrib(int slot) const {
 
 
   // Will this bring us down to the empty state?
   // Will this bring us down to the empty state?
   if (_filled_slots.get_num_on_bits() == 1) {
   if (_filled_slots.get_num_on_bits() == 1) {
-    return make_empty();
+    return _empty_state;
   }
   }
 
 
   RenderState *new_state = new RenderState(*this);
   RenderState *new_state = new RenderState(*this);
@@ -1110,7 +1088,7 @@ clear_munger_cache() {
     }
     }
     RenderState *state = (RenderState *)(_states->get_key(si));
     RenderState *state = (RenderState *)(_states->get_key(si));
     state->_mungers.clear();
     state->_mungers.clear();
-    state->_last_mi = state->_mungers.end();
+    state->_last_mi = -1;
   }
   }
 }
 }
 
 
@@ -1314,17 +1292,17 @@ validate_states() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int RenderState::
 int RenderState::
 get_geom_rendering(int geom_rendering) const {
 get_geom_rendering(int geom_rendering) const {
-  const RenderModeAttrib *render_mode = DCAST(RenderModeAttrib, get_attrib(RenderModeAttrib::get_class_slot()));
-  const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, get_attrib(TexGenAttrib::get_class_slot()));
-  const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, get_attrib(TexMatrixAttrib::get_class_slot()));
+  const RenderModeAttrib *render_mode;
+  const TexGenAttrib *tex_gen;
+  const TexMatrixAttrib *tex_matrix;
 
 
-  if (render_mode != (const RenderModeAttrib *)NULL) {
+  if (get_attrib(render_mode)) {
     geom_rendering = render_mode->get_geom_rendering(geom_rendering);
     geom_rendering = render_mode->get_geom_rendering(geom_rendering);
   }
   }
-  if (tex_gen != (const TexGenAttrib *)NULL) {
+  if (get_attrib(tex_gen)) {
     geom_rendering = tex_gen->get_geom_rendering(geom_rendering);
     geom_rendering = tex_gen->get_geom_rendering(geom_rendering);
   }
   }
-  if (tex_matrix != (const TexMatrixAttrib *)NULL) {
+  if (get_attrib(tex_matrix)) {
     geom_rendering = tex_matrix->get_geom_rendering(geom_rendering);
     geom_rendering = tex_matrix->get_geom_rendering(geom_rendering);
   }
   }
 
 
@@ -1507,7 +1485,7 @@ return_new(RenderState *state) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) RenderState::
 CPT(RenderState) RenderState::
 return_unique(RenderState *state) {
 return_unique(RenderState *state) {
-  nassertr(state != (RenderState *)NULL, state);
+  nassertr(state != (RenderState *)NULL, NULL);
 
 
   if (!state_cache) {
   if (!state_cache) {
     return state;
     return state;
@@ -1523,14 +1501,10 @@ return_unique(RenderState *state) {
 
 
   if (state->_saved_entry != -1) {
   if (state->_saved_entry != -1) {
     // This state is already in the cache.
     // This state is already in the cache.
-    //nassertr(_states->find(state) == state->_saved_entry, state);
+    //nassertr(_states->find(state) == state->_saved_entry, pt_state);
     return state;
     return state;
   }
   }
 
 
-  // Save the state in a local PointerTo so that it will be freed at
-  // the end of this function if no one else uses it.
-  CPT(RenderState) pt_state = state;
-
   // Ensure each of the individual attrib pointers has been uniquified
   // Ensure each of the individual attrib pointers has been uniquified
   // before we add the state to the cache.
   // before we add the state to the cache.
   if (!uniquify_attribs && !state->is_empty()) {
   if (!uniquify_attribs && !state->is_empty()) {
@@ -1538,7 +1512,7 @@ return_unique(RenderState *state) {
     int slot = mask.get_lowest_on_bit();
     int slot = mask.get_lowest_on_bit();
     while (slot >= 0) {
     while (slot >= 0) {
       Attribute &attrib = state->_attributes[slot];
       Attribute &attrib = state->_attributes[slot];
-      nassertr(attrib._attrib != (RenderAttrib *)NULL, state);
+      nassertd(attrib._attrib != (RenderAttrib *)NULL) continue;
       attrib._attrib = attrib._attrib->get_unique();
       attrib._attrib = attrib._attrib->get_unique();
       mask.clear_bit(slot);
       mask.clear_bit(slot);
       slot = mask.get_lowest_on_bit();
       slot = mask.get_lowest_on_bit();
@@ -1548,6 +1522,11 @@ return_unique(RenderState *state) {
   int si = _states->find(state);
   int si = _states->find(state);
   if (si != -1) {
   if (si != -1) {
     // There's an equivalent state already in the set.  Return it.
     // There's an equivalent state already in the set.  Return it.
+    // The state that was passed may be newly created and therefore
+    // may not be automatically deleted.  Do that if necessary.
+    if (state->get_ref_count() == 0) {
+      delete state;
+    }
     return _states->get_key(si);
     return _states->get_key(si);
   }
   }
 
 
@@ -1562,7 +1541,7 @@ return_unique(RenderState *state) {
 
 
   // Save the index and return the input state.
   // Save the index and return the input state.
   state->_saved_entry = si;
   state->_saved_entry = si;
-  return pt_state;
+  return state;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1621,15 +1600,6 @@ do_compose(const RenderState *other) const {
     slot = mask.get_lowest_on_bit();
     slot = mask.get_lowest_on_bit();
   }
   }
 
 
-  // If we have any ShaderAttrib with auto-shader enabled,
-  // remove any shader inputs on it. This is a workaround for an
-  // issue that makes the shader-generator regenerate the shader
-  // every time a shader input changes.
-  CPT(ShaderAttrib) sattrib = DCAST(ShaderAttrib, new_state->get_attrib_def(ShaderAttrib::get_class_slot()));
-  if (sattrib->auto_shader()) {
-    sattrib = DCAST(ShaderAttrib, sattrib->clear_all_shader_inputs());
-  }
-
   return return_new(new_state);
   return return_new(new_state);
 }
 }
 
 
@@ -1660,9 +1630,8 @@ do_invert_compose(const RenderState *other) const {
 
 
     } else if (b._attrib == NULL) {
     } else if (b._attrib == NULL) {
       // A wins.  Invert it.
       // A wins.  Invert it.
-      CPT(RenderState) full_default = make_full_default();
-      CPT(RenderAttrib) default_attrib = full_default->get_attrib(slot);
-      result.set(a._attrib->invert_compose(default_attrib), 0);
+      RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr();
+      result.set(a._attrib->invert_compose(reg->get_slot_default(slot)), 0);
 
 
     } else {
     } else {
       // Both are good.  (Overrides are not used in invert_compose.)
       // Both are good.  (Overrides are not used in invert_compose.)
@@ -2162,8 +2131,14 @@ init_states() {
   _states_lock = new LightReMutex("RenderState::_states_lock");
   _states_lock = new LightReMutex("RenderState::_states_lock");
   _cache_stats.init();
   _cache_stats.init();
   nassertv(Thread::get_current_thread() == Thread::get_main_thread());
   nassertv(Thread::get_current_thread() == Thread::get_main_thread());
-}
 
 
+  // Initialize the empty state object as well.  It is used so often
+  // that it is declared globally, and lives forever.
+  RenderState *state = new RenderState;
+  state->local_object();
+  state->_saved_entry = _states->store(state, Empty());
+  _empty_state = state;
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::register_with_read_factory
 //     Function: RenderState::register_with_read_factory

+ 7 - 8
panda/src/pgraph/renderState.h

@@ -31,10 +31,11 @@
 #include "lightMutex.h"
 #include "lightMutex.h"
 #include "deletedChain.h"
 #include "deletedChain.h"
 #include "simpleHashMap.h"
 #include "simpleHashMap.h"
+#include "weakKeyHashMap.h"
 #include "cacheStats.h"
 #include "cacheStats.h"
 #include "renderAttribRegistry.h"
 #include "renderAttribRegistry.h"
+#include "graphicsStateGuardianBase.h"
 
 
-class GraphicsStateGuardianBase;
 class FactoryParams;
 class FactoryParams;
 class ShaderAttrib;
 class ShaderAttrib;
 
 
@@ -76,7 +77,6 @@ PUBLISHED:
   bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
   bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
 
 
   INLINE static CPT(RenderState) make_empty();
   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);
@@ -104,7 +104,7 @@ PUBLISHED:
   INLINE bool has_attrib(TypeHandle type) const;
   INLINE bool has_attrib(TypeHandle type) const;
   INLINE bool has_attrib(int slot) const;
   INLINE bool has_attrib(int slot) const;
   INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
   INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
-  INLINE const RenderAttrib *get_attrib(int slot) const;
+  ALWAYS_INLINE const RenderAttrib *get_attrib(int slot) const;
   INLINE const RenderAttrib *get_attrib_def(int slot) const;
   INLINE const RenderAttrib *get_attrib_def(int slot) const;
   INLINE int get_override(TypeHandle type) const;
   INLINE int get_override(TypeHandle type) const;
   INLINE int get_override(int slot) const;
   INLINE int get_override(int slot) const;
@@ -233,8 +233,7 @@ private:
   };
   };
   typedef SimpleHashMap<const RenderState *, Empty, indirect_compare_to_hash<const RenderState *> > States;
   typedef SimpleHashMap<const RenderState *, Empty, indirect_compare_to_hash<const RenderState *> > States;
   static States *_states;
   static States *_states;
-  static CPT(RenderState) _empty_state;
-  static CPT(RenderState) _full_default_state;
+  static const RenderState *_empty_state;
 
 
   // This iterator records the entry corresponding to this
   // This iterator records the entry corresponding to this
   // RenderState object in the above global set.  We keep the index
   // RenderState object in the above global set.  We keep the index
@@ -270,9 +269,9 @@ private:
   // since there are likely to be far fewer GSG's than RenderStates.
   // since there are likely to be far fewer GSG's than RenderStates.
   // The code to manage this map lives in
   // The code to manage this map lives in
   // GraphicsStateGuardian::get_geom_munger().
   // GraphicsStateGuardian::get_geom_munger().
-  typedef pmap<WCPT(GraphicsStateGuardianBase), PT(GeomMunger) > Mungers;
+  typedef WeakKeyHashMap<GraphicsStateGuardianBase, PT(GeomMunger) > Mungers;
   mutable Mungers _mungers;
   mutable Mungers _mungers;
-  mutable Mungers::const_iterator _last_mi;
+  mutable int _last_mi;
 
 
   // This is used to mark nodes as we visit them to detect cycles.
   // This is used to mark nodes as we visit them to detect cycles.
   UpdateSeq _cycle_detect;
   UpdateSeq _cycle_detect;
@@ -307,7 +306,7 @@ private:
     CPT(RenderAttrib) _attrib;
     CPT(RenderAttrib) _attrib;
     int _override;
     int _override;
   };
   };
-  Attribute *_attributes;
+  Attribute _attributes[RenderAttribRegistry::_max_slots];
 
 
   // We also store a bitmask of the non-NULL attributes in the above
   // We also store a bitmask of the non-NULL attributes in the above
   // array.  This is redundant, but it is a useful cache.
   // array.  This is redundant, but it is a useful cache.

+ 13 - 0
panda/src/pgraph/rescaleNormalAttrib.I

@@ -25,6 +25,19 @@ RescaleNormalAttrib(RescaleNormalAttrib::Mode mode) :
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RescaleNormalAttrib::make_default
+//       Access: Published, Static
+//  Description: Constructs a RescaleNormalAttrib object that's
+//               suitable for putting at the top of a scene graph.
+//               This will contain whatever attrib was suggested by
+//               the user's rescale-normals Config variable.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderAttrib) RescaleNormalAttrib::
+make_default() {
+  return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RescaleNormalAttrib::get_mode
 //     Function: RescaleNormalAttrib::get_mode
 //       Access: Published
 //       Access: Published

+ 38 - 31
panda/src/pgraph/rescaleNormalAttrib.cxx

@@ -25,18 +25,7 @@
 
 
 TypeHandle RescaleNormalAttrib::_type_handle;
 TypeHandle RescaleNormalAttrib::_type_handle;
 int RescaleNormalAttrib::_attrib_slot;
 int RescaleNormalAttrib::_attrib_slot;
-
-// This variable is defined here instead of in config_pgraph.cxx,
-// because it depends on rescaleNormalAttrib.h having already been
-// included.
-static ConfigVariableEnum<RescaleNormalAttrib::Mode> rescale_normals
-("rescale-normals", RescaleNormalAttrib::M_auto,
- PRC_DESC("Specifies the kind of RescaleNormalAttrib that should be "
-          "created for the top of the scene graph.  This can automatically "
-          "ensure that your lighting normals are unit-length, which may be "
-          "particularly necessary in the presence of scales in the scene "
-          "graph.  Turning it off ('none') may produce a small performance "
-          "benefit."));
+CPT(RenderAttrib) RescaleNormalAttrib::_attribs[RescaleNormalAttrib::M_auto + 1];
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RescaleNormalAttrib::make
 //     Function: RescaleNormalAttrib::make
@@ -47,28 +36,18 @@ static ConfigVariableEnum<RescaleNormalAttrib::Mode> rescale_normals
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) RescaleNormalAttrib::
 CPT(RenderAttrib) RescaleNormalAttrib::
 make(RescaleNormalAttrib::Mode mode) {
 make(RescaleNormalAttrib::Mode mode) {
-  RescaleNormalAttrib *attrib = new RescaleNormalAttrib(mode);
-  return return_new(attrib);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: RescaleNormalAttrib::make_default
-//       Access: Published, Static
-//  Description: Constructs a RescaleNoramlAttrib object that's
-//               suitable for putting at the top of a scene graph.
-//               This will contain whatever attrib was suggested by
-//               the user's rescale-normals Config variable.
-////////////////////////////////////////////////////////////////////
-CPT(RenderAttrib) RescaleNormalAttrib::
-make_default() {
-  RescaleNormalAttrib *attrib = new RescaleNormalAttrib(rescale_normals);
-  return return_new(attrib);
+  if (_attribs[mode].is_null()) {
+    // Don't bother with return_new, since this is the only way a
+    // RescaleNormalAttrib can be made anyway.
+    _attribs[mode] = new RescaleNormalAttrib(mode);
+  }
+  return _attribs[mode];
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RescaleNormalAttrib::output
 //     Function: RescaleNormalAttrib::output
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RescaleNormalAttrib::
 void RescaleNormalAttrib::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -92,8 +71,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int RescaleNormalAttrib::
 int RescaleNormalAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const RescaleNormalAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const RescaleNormalAttrib *ta = (const RescaleNormalAttrib *)other;
   return (int)_mode - (int)ta->_mode;
   return (int)_mode - (int)ta->_mode;
 }
 }
 
 
@@ -187,6 +165,35 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _mode = (Mode)scan.get_int8();
   _mode = (Mode)scan.get_int8();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RescaleNormalAttrib::init_type
+//       Access: Public, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+void RescaleNormalAttrib::
+init_type() {
+  RenderAttrib::init_type();
+  register_type(_type_handle, "RescaleNormalAttrib",
+                RenderAttrib::get_class_type());
+
+  // This is defined here, since we have otherwise no guarantee that
+  // the config var has already been constructed by the time we call
+  // init_type() at static init time.
+  static ConfigVariableEnum<RescaleNormalAttrib::Mode> rescale_normals
+  ("rescale-normals", RescaleNormalAttrib::M_auto,
+   PRC_DESC("Specifies the kind of RescaleNormalAttrib that should be "
+            "created for the top of the scene graph.  This can automatically "
+            "ensure that your lighting normals are unit-length, which may be "
+            "particularly necessary in the presence of scales in the scene "
+            "graph.  Turning it off ('none') may produce a small performance "
+            "benefit."));
+
+  Mode mode = rescale_normals;
+  RescaleNormalAttrib *attrib = new RescaleNormalAttrib(mode);
+  _attrib_slot = register_slot(_type_handle, 100, attrib);
+  _attribs[mode] = attrib;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RescaleNormalAttrib::Mode output operator
 //     Function: RescaleNormalAttrib::Mode output operator
 //  Description:
 //  Description:

+ 7 - 8
panda/src/pgraph/rescaleNormalAttrib.h

@@ -49,7 +49,7 @@ private:
 
 
 PUBLISHED:
 PUBLISHED:
   static CPT(RenderAttrib) make(Mode mode);
   static CPT(RenderAttrib) make(Mode mode);
-  static CPT(RenderAttrib) make_default();
+  INLINE static CPT(RenderAttrib) make_default();
 
 
   INLINE Mode get_mode() const;
   INLINE Mode get_mode() const;
 
 
@@ -64,6 +64,10 @@ protected:
 private:
 private:
   Mode _mode;
   Mode _mode;
 
 
+  // There are so few possible combinations, and it's used fairly often, so
+  // we keep an array of the possible attributes.
+  static CPT(RenderAttrib) _attribs[M_auto + 1];
+
 PUBLISHED:
 PUBLISHED:
   static int get_class_slot() {
   static int get_class_slot() {
     return _attrib_slot;
     return _attrib_slot;
@@ -79,17 +83,12 @@ 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;
   }
   }
-  static void init_type() {
-    RenderAttrib::init_type();
-    register_type(_type_handle, "RescaleNormalAttrib",
-                  RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
-  }
+  static void init_type();
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();
   }
   }

+ 2 - 4
panda/src/pgraph/scissorAttrib.cxx

@@ -113,8 +113,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ScissorAttrib::
 int ScissorAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const ScissorAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ScissorAttrib *ta = (const ScissorAttrib *)other;
 
 
   if (!_off && !ta->_off) {
   if (!_off && !ta->_off) {
     return 0;
     return 0;
@@ -173,8 +172,7 @@ compose_impl(const RenderAttrib *other) const {
     return other;
     return other;
   }
   }
 
 
-  const ScissorAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ScissorAttrib *ta = (const ScissorAttrib *)other;
 
 
   if (ta->_off) {
   if (ta->_off) {
     return this;
     return this;

+ 4 - 1
panda/src/pgraph/scissorAttrib.h

@@ -89,7 +89,10 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ScissorAttrib",
     register_type(_type_handle, "ScissorAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+
+    ScissorAttrib *attrib = new ScissorAttrib(LVecBase4(0, 1, 0, 1));
+    attrib->_off = true;
+    _attrib_slot = register_slot(_type_handle, 100, attrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 2 - 4
panda/src/pgraph/shadeModelAttrib.cxx

@@ -84,8 +84,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ShadeModelAttrib::
 int ShadeModelAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const ShadeModelAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ShadeModelAttrib *ta = (const ShadeModelAttrib *)other;
   return (int)_mode - (int)ta->_mode;
   return (int)_mode - (int)ta->_mode;
 }
 }
 
 
@@ -125,8 +124,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) ShadeModelAttrib::
 CPT(RenderAttrib) ShadeModelAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const ShadeModelAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const ShadeModelAttrib *ta = (const ShadeModelAttrib *)other;
 
 
   Mode mode = ta->get_mode();
   Mode mode = ta->get_mode();
   return make(mode);
   return make(mode);

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

@@ -77,7 +77,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ShadeModelAttrib",
     register_type(_type_handle, "ShadeModelAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new ShadeModelAttrib(M_smooth));
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 3 - 4
panda/src/pgraph/shaderAttrib.cxx

@@ -542,8 +542,7 @@ get_shader() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ShaderAttrib::
 int ShaderAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const ShaderAttrib *that;
-  DCAST_INTO_R(that, other, 0);
+  const ShaderAttrib *that = (const ShaderAttrib *)other;
 
 
   if (this->_shader != that->_shader) {
   if (this->_shader != that->_shader) {
     return (this->_shader < that->_shader) ? -1 : 1;
     return (this->_shader < that->_shader) ? -1 : 1;
@@ -643,8 +642,8 @@ get_hash_impl() const {
 CPT(RenderAttrib) ShaderAttrib::
 CPT(RenderAttrib) ShaderAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
   ShaderAttrib *attr = new ShaderAttrib(*this);
   ShaderAttrib *attr = new ShaderAttrib(*this);
-  const ShaderAttrib *over;
-  DCAST_INTO_R(over, other, 0);
+  const ShaderAttrib *over = (const ShaderAttrib *)other;
+
   // Update the shader portion.
   // Update the shader portion.
   if (over->_has_shader) {
   if (over->_has_shader) {
     if ((attr->_has_shader == false) ||
     if ((attr->_has_shader == false) ||

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

@@ -156,7 +156,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "ShaderAttrib",
     register_type(_type_handle, "ShaderAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 10, make_default);
+    _attrib_slot = register_slot(_type_handle, 10, new ShaderAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 5 - 8
panda/src/pgraph/stateMunger.cxx

@@ -32,18 +32,15 @@ StateMunger::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderState) StateMunger::
 CPT(RenderState) StateMunger::
 munge_state(const RenderState *state) {
 munge_state(const RenderState *state) {
-  WCPT(RenderState) pt_state = state;
-
-  StateMap::iterator mi = _state_map.find(pt_state);
-  if (mi != _state_map.end()) {
-    if (!(*mi).first.was_deleted() &&
-        !(*mi).second.was_deleted()) {
-      return (*mi).second.p();
+  int mi = _state_map.find(state);
+  if (mi != -1) {
+    if (!_state_map.get_data(mi).was_deleted()) {
+      return _state_map.get_data(mi).p();
     }
     }
   }
   }
 
 
   CPT(RenderState) result = munge_state_impl(state);
   CPT(RenderState) result = munge_state_impl(state);
-  _state_map[pt_state] = result;
+  _state_map.store(state, result.p());
 
 
   return result;
   return result;
 }
 }

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

@@ -18,7 +18,7 @@
 #include "pandabase.h"
 #include "pandabase.h"
 #include "geomMunger.h"
 #include "geomMunger.h"
 #include "renderState.h"
 #include "renderState.h"
-#include "weakPointerTo.h"
+#include "weakKeyHashMap.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : StateMunger
 //       Class : StateMunger
@@ -36,7 +36,7 @@ public:
 protected:
 protected:
   virtual CPT(RenderState) munge_state_impl(const RenderState *state);
   virtual CPT(RenderState) munge_state_impl(const RenderState *state);
 
 
-  typedef pmap< WCPT(RenderState), WCPT(RenderState) > StateMap;
+  typedef WeakKeyHashMap<RenderState, WCPT(RenderState) > StateMap;
   StateMap _state_map;
   StateMap _state_map;
 
 
 public:
 public:

+ 1 - 2
panda/src/pgraph/stencilAttrib.cxx

@@ -311,8 +311,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int StencilAttrib::
 int StencilAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const StencilAttrib *sa;
-  DCAST_INTO_R(sa, other, 0);
+  const StencilAttrib *sa = (const StencilAttrib *)other;
 
 
   int a;
   int a;
   int b;
   int b;

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

@@ -175,7 +175,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "StencilAttrib",
     register_type(_type_handle, "StencilAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new StencilAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 3 - 6
panda/src/pgraph/texGenAttrib.cxx

@@ -297,8 +297,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int TexGenAttrib::
 int TexGenAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const TexGenAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TexGenAttrib *ta = (const TexGenAttrib *)other;
 
 
   Stages::const_iterator ai, bi;
   Stages::const_iterator ai, bi;
   ai = _stages.begin();
   ai = _stages.begin();
@@ -383,8 +382,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) TexGenAttrib::
 CPT(RenderAttrib) TexGenAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const TexGenAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TexGenAttrib *ta = (const TexGenAttrib *)other;
 
 
   // The composition is the union of the two attribs.  In the case
   // The composition is the union of the two attribs.  In the case
   // when a stage is in both attribs, we compose the stages.
   // when a stage is in both attribs, we compose the stages.
@@ -441,8 +439,7 @@ compose_impl(const RenderAttrib *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) TexGenAttrib::
 CPT(RenderAttrib) TexGenAttrib::
 invert_compose_impl(const RenderAttrib *other) const {
 invert_compose_impl(const RenderAttrib *other) const {
-  const TexGenAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TexGenAttrib *ta = (const TexGenAttrib *)other;
 
 
   // The inverse composition works a lot like the composition, except
   // The inverse composition works a lot like the composition, except
   // we invert the ai stages.
   // we invert the ai stages.

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

@@ -139,7 +139,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "TexGenAttrib",
     register_type(_type_handle, "TexGenAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new TexGenAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 4 - 7
panda/src/pgraph/texMatrixAttrib.cxx

@@ -247,9 +247,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int TexMatrixAttrib::
 int TexMatrixAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const TexMatrixAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
-  
+  const TexMatrixAttrib *ta = (const TexMatrixAttrib *)other;
+
   Stages::const_iterator ai, bi;
   Stages::const_iterator ai, bi;
   ai = _stages.begin();
   ai = _stages.begin();
   bi = ta->_stages.begin();
   bi = ta->_stages.begin();
@@ -326,8 +325,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) TexMatrixAttrib::
 CPT(RenderAttrib) TexMatrixAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const TexMatrixAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TexMatrixAttrib *ta = (const TexMatrixAttrib *)other;
 
 
   // The composition is the union of the two attribs.  In the case
   // The composition is the union of the two attribs.  In the case
   // when a stage is in both attribs, we compose the stages.
   // when a stage is in both attribs, we compose the stages.
@@ -396,8 +394,7 @@ compose_impl(const RenderAttrib *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) TexMatrixAttrib::
 CPT(RenderAttrib) TexMatrixAttrib::
 invert_compose_impl(const RenderAttrib *other) const {
 invert_compose_impl(const RenderAttrib *other) const {
-  const TexMatrixAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TexMatrixAttrib *ta = (const TexMatrixAttrib *)other;
 
 
   // The inverse composition works a lot like the composition, except
   // The inverse composition works a lot like the composition, except
   // we invert the ai stages.
   // we invert the ai stages.

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

@@ -123,7 +123,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "TexMatrixAttrib",
     register_type(_type_handle, "TexMatrixAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new TexMatrixAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 2 - 4
panda/src/pgraph/textureAttrib.cxx

@@ -507,8 +507,7 @@ cull_callback(CullTraverser *trav, const CullTraverserData &data) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int TextureAttrib::
 int TextureAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const TextureAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TextureAttrib *ta = (const TextureAttrib *)other;
 
 
   if (_off_all_stages != ta->_off_all_stages) {
   if (_off_all_stages != ta->_off_all_stages) {
     return (int)_off_all_stages - (int)ta->_off_all_stages;
     return (int)_off_all_stages - (int)ta->_off_all_stages;
@@ -664,8 +663,7 @@ get_hash_impl() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) TextureAttrib::
 CPT(RenderAttrib) TextureAttrib::
 compose_impl(const RenderAttrib *other) const {
 compose_impl(const RenderAttrib *other) const {
-  const TextureAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TextureAttrib *ta = (const TextureAttrib *)other;
 
 
   if (ta->_off_all_stages) {
   if (ta->_off_all_stages) {
     // If the other type turns off all stages, it doesn't matter what
     // If the other type turns off all stages, it doesn't matter what

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

@@ -179,7 +179,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "TextureAttrib",
     register_type(_type_handle, "TextureAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 30, make_default);
+    _attrib_slot = register_slot(_type_handle, 30, new TextureAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

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

@@ -101,8 +101,8 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int TransparencyAttrib::
 int TransparencyAttrib::
 compare_to_impl(const RenderAttrib *other) const {
 compare_to_impl(const RenderAttrib *other) const {
-  const TransparencyAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
+  const TransparencyAttrib *ta = (const TransparencyAttrib *)other;
+
   return (int)_mode - (int)ta->_mode;
   return (int)_mode - (int)ta->_mode;
 }
 }
 
 

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

@@ -92,7 +92,7 @@ public:
     RenderAttrib::init_type();
     RenderAttrib::init_type();
     register_type(_type_handle, "TransparencyAttrib",
     register_type(_type_handle, "TransparencyAttrib",
                   RenderAttrib::get_class_type());
                   RenderAttrib::get_class_type());
-    _attrib_slot = register_slot(_type_handle, 100, make_default);
+    _attrib_slot = register_slot(_type_handle, 100, new TransparencyAttrib);
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 0
panda/src/putil/p3putil_composite2.cxx

@@ -23,6 +23,7 @@
 #include "vector_typedWritable.cxx"
 #include "vector_typedWritable.cxx"
 #include "vector_ushort.cxx"
 #include "vector_ushort.cxx"
 #include "vector_writable.cxx"
 #include "vector_writable.cxx"
+#include "weakKeyHashMap.cxx"
 #include "writableConfigurable.cxx"
 #include "writableConfigurable.cxx"
 #include "writableParam.cxx"
 #include "writableParam.cxx"
 
 

+ 714 - 0
panda/src/putil/weakKeyHashMap.I

@@ -0,0 +1,714 @@
+// Filename: weakKeyHashMap.I
+// Created by:  rdb (13Jul15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE WeakKeyHashMap<Key, Value>::
+WeakKeyHashMap() :
+  _table(NULL),
+  _deleted_chain(NULL),
+  _table_size(0),
+  _num_entries(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE WeakKeyHashMap<Key, Value>::
+~WeakKeyHashMap() {
+  clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::swap
+//       Access: Public
+//  Description: Quickly exchanges the contents of this map and the
+//               other map.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE void WeakKeyHashMap<Key, Value>::
+swap(WeakKeyHashMap<Key, Value> &other) {
+  TableEntry *t0 = _table;
+  _table = other._table;
+  other._table = t0;
+
+  DeletedBufferChain *t1 = _deleted_chain;
+  _deleted_chain = other._deleted_chain;
+  other._deleted_chain = t1;
+
+  size_t t2 = _table_size;
+  _table_size = other._table_size;
+  other._table_size = t2;
+
+  size_t t3 = _num_entries;
+  _num_entries = other._num_entries;
+  other._num_entries = t3;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::find
+//       Access: Public
+//  Description: Searches for the indicated key in the table.  Returns
+//               its index number if it is found, or -1 if it is not
+//               present in the table.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+int WeakKeyHashMap<Key, Value>::
+find(const Key *key) const {
+  if (_table_size == 0) {
+    // Special case: the table is empty.
+    return -1;
+  }
+
+  size_t index = get_hash(key);
+  if (!has_element(index)) {
+    return -1;
+  }
+  if (is_element(index, key)) {
+    return index;
+  }
+
+  // There was some other key at the hashed slot.  That's a hash
+  // conflict.  Maybe our entry was recorded at a later slot position;
+  // scan the subsequent positions until we find the entry or an
+  // unused slot, indicating the end of the scan.
+  size_t i = index;
+  i = (i + 1) & (_table_size - 1);
+  while (i != index && has_element(i)) {
+    if (is_element(i, key)) {
+      return i;
+    }
+    i = (i + 1) & (_table_size - 1);
+  }
+
+  // The key is not in the table.
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::store
+//       Access: Public
+//  Description: Records the indicated key/data pair in the map.  If
+//               the key was already present, silently replaces it.
+//               Returns the index at which it was stored.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+int WeakKeyHashMap<Key, Value>::
+store(const Key *key, const Value &data) {
+  if (_table_size == 0) {
+    // Special case: the first key in an empty table.
+    nassertr(_num_entries == 0, -1);
+    new_table();
+    size_t index = get_hash(key);
+    store_new_element(index, key, data);
+    ++_num_entries;
+#ifdef _DEBUG
+    nassertr(validate(), index);
+#endif
+    return index;
+  }
+
+  size_t index = get_hash(key);
+  if (!has_element(index)) {
+    // This element is not already in the map; add it.
+    if (consider_expand_table()) {
+      return store(key, data);
+    }
+    store_new_element(index, key, data);
+    ++_num_entries;
+#ifdef _DEBUG
+    nassertr(validate(), index);
+#endif
+    return index;
+  }
+  if (is_element(index, key)) {
+    // This element is already in the map; replace the data at that
+    // key.
+    _table[index]._data = data;
+#ifdef _DEBUG
+    nassertr(validate(), index);
+#endif
+    return index;
+  }
+
+  // There was some other key at the hashed slot.  That's a hash
+  // conflict.  Record this entry at a later position.
+  size_t i = index;
+  i = (i + 1) & (_table_size - 1);
+  while (i != index) {
+    if (!has_element(i)) {
+      if (consider_expand_table()) {
+        return store(key, data);
+      }
+      store_new_element(i, key, data);
+      ++_num_entries;
+#ifdef _DEBUG
+      nassertr(validate(), i);
+#endif
+      return i;
+    }
+    if (is_element(i, key)) {
+      _table[i]._data = data;
+#ifdef _DEBUG
+      nassertr(validate(), i);
+#endif
+      return i;
+    }
+    i = (i + 1) & (_table_size - 1);
+  }
+
+  // Shouldn't get here unless _num_entries == _table_size, which
+  // shouldn't be possible due to consider_expand_table().
+  nassertr(false, -1);
+  return -1;  // To satisfy compiler
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::remove
+//       Access: Public
+//  Description: Removes the indicated key and its associated data
+//               from the table.  Returns true if the key was removed,
+//               false if it was not present.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE bool WeakKeyHashMap<Key, Value>::
+remove(const Key *key) {
+  int index = find(key);
+  if (index == -1) {
+    return false;
+  }
+  remove_element(index);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::clear
+//       Access: Public
+//  Description: Completely empties the table.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+void WeakKeyHashMap<Key, Value>::
+clear() {
+  if (_table_size != 0) {
+    for (size_t i = 0; i < _table_size; ++i) {
+      if (get_exists_array()[i] != 0) {
+        clear_element(i);
+      }
+    }
+
+    _deleted_chain->deallocate(_table, TypeHandle::none());
+    _table = NULL;
+    _deleted_chain = NULL;
+    _table_size = 0;
+    _num_entries = 0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::operator []
+//       Access: Public
+//  Description: Returns a modifiable reference to the data associated
+//               with the indicated key, or creates a new data entry
+//               and returns its reference.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE Value &WeakKeyHashMap<Key, Value>::
+operator [] (const Key *key) {
+  int index = find(key);
+  if (index == -1) {
+    index = store(key, Value());
+  }
+  return modify_data(index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::get_size
+//       Access: Public
+//  Description: Returns the total number of slots in the table.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE int WeakKeyHashMap<Key, Value>::
+get_size() const {
+  return _table_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::has_element
+//       Access: Public
+//  Description: Returns true if there is an element stored in the nth
+//               slot, false otherwise.
+//
+//               n should be in the range 0 <= n < get_size().
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE bool WeakKeyHashMap<Key, Value>::
+has_element(int n) const {
+  nassertr(n >= 0 && n < (int)_table_size, false);
+  return (get_exists_array()[n] != 0 && !_table[n]._key.was_deleted());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::get_key
+//       Access: Public
+//  Description: Returns the key in the nth slot of the table.
+//
+//               It is an error to call this if there is nothing
+//               stored in the nth slot (use has_element() to check
+//               this first).  n should be in the range 0 <= n <
+//               get_size().
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE const Key *WeakKeyHashMap<Key, Value>::
+get_key(int n) const {
+  nassertr(has_element(n), _table[n]._key);
+  return _table[n]._key;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::get_data
+//       Access: Public
+//  Description: Returns the data in the nth slot of the table.
+//
+//               It is an error to call this if there is nothing
+//               stored in the nth slot (use has_element() to check
+//               this first).  n should be in the range 0 <= n <
+//               get_size().
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE const Value &WeakKeyHashMap<Key, Value>::
+get_data(int n) const {
+  nassertr(has_element(n), _table[n]._data);
+  return _table[n]._data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::modify_data
+//       Access: Public
+//  Description: Returns a modifiable reference to the data in the nth
+//               slot of the table.
+//
+//               It is an error to call this if there is nothing
+//               stored in the nth slot (use has_element() to check
+//               this first).  n should be in the range 0 <= n <
+//               get_size().
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE Value &WeakKeyHashMap<Key, Value>::
+modify_data(int n) {
+  nassertr(has_element(n), _table[n]._data);
+  return _table[n]._data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::set_data
+//       Access: Public
+//  Description: Changes the data for the nth slot of the table.
+//
+//               It is an error to call this if there is nothing
+//               stored in the nth slot (use has_element() to check
+//               this first).  n should be in the range 0 <= n <
+//               get_size().
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE void WeakKeyHashMap<Key, Value>::
+set_data(int n, const Value &data) {
+  nassertv(has_element(n));
+  _table[n]._data = data;
+}
+
+#ifdef USE_MOVE_SEMANTICS
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::set_data
+//       Access: Public
+//  Description: Changes the data for the nth slot of the table.
+//
+//               It is an error to call this if there is nothing
+//               stored in the nth slot (use has_element() to check
+//               this first).  n should be in the range 0 <= n <
+//               get_size().
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE void WeakKeyHashMap<Key, Value>::
+set_data(int n, Value &&data) {
+  nassertv(has_element(n));
+  _table[n]._data = std::move(data);
+}
+#endif  // USE_MOVE_SEMANTICS
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::remove_element
+//       Access: Public
+//  Description: Removes the nth slot from the table.
+//
+//               It is an error to call this if there is nothing
+//               stored in the nth slot (use has_element() to check
+//               this first).  n should be in the range 0 <= n <
+//               get_size().
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+void WeakKeyHashMap<Key, Value>::
+remove_element(int n) {
+  nassertv(get_exists_array()[n] != 0);
+
+  clear_element(n);
+  nassertv(_num_entries > 0);
+  --_num_entries;
+
+  // Now we have put a hole in the table.  If there was a hash
+  // conflict in the slot following this one, we have to move it down
+  // to close the hole.
+  size_t i = n;
+  i = (i + 1) & (_table_size - 1);
+  while (get_exists_array()[i] != 0) {
+    if (_table[i]._key.was_deleted()) {
+      // It was deleted.  Forget about it.
+      clear_element(i);
+      --_num_entries;
+    } else {
+      size_t wants_index = get_hash(_table[i]._key);
+      if (wants_index != i) {
+        // This one was a hash conflict; try to put it where it belongs.
+        // We can't just put it in n, since maybe it belongs somewhere
+        // after n.
+        while (wants_index != i && has_element(wants_index)) {
+          // Hash conflict; move it up.
+          wants_index = (wants_index + 1) & (_table_size - 1);
+        }
+        if (wants_index != i) {
+          store_new_element(wants_index, _table[i]._key, _table[i]._data);
+          clear_element(i);
+        }
+      }
+    }
+
+    // Continue until we encounter the next unused slot.  Until we do,
+    // we can't be sure we've found all of the potential hash
+    // conflicts.
+    i = (i + 1) & (_table_size - 1);
+  }
+
+#ifdef _DEBUG
+  nassertv(validate());
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::get_num_entries
+//       Access: Public
+//  Description: Returns the number of active entries in the table.
+//               This is not necessarily related to the number of
+//               slots in the table as reported by get_size().  Use
+//               get_size() to iterate through all of the slots, not
+//               get_num_entries().
+//
+//               This is merely an upper bound on the number of
+//               entries; it may also count false positives for
+//               pointers that were recently deleted.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE int WeakKeyHashMap<Key, Value>::
+get_num_entries() const {
+  return _num_entries;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::is_empty
+//       Access: Public
+//  Description: Returns true if the table is empty;
+//               i.e. get_num_entries() == 0.  This may return a
+//               false negatives if a pointer was recently deleted;
+//               if this returns true, though, you can be sure it's
+//               empty.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE bool WeakKeyHashMap<Key, Value>::
+is_empty() const {
+  return (_num_entries == 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::output
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+void WeakKeyHashMap<Key, Value>::
+output(ostream &out) const {
+  out << "WeakKeyHashMap (" << _num_entries << " entries): [";
+  for (size_t i = 0; i < _table_size; ++i) {
+    if (get_exists_array()[i] == 0) {
+      out << " *";
+
+    } else {
+      out << " " << _table[i]._key;
+      size_t index = get_hash(_table[i]._key.get_orig());
+      if (index != i) {
+        // This was misplaced as the result of a hash conflict.
+        // Report how far off it is.
+        out << "(" << ((_table_size + i - index) & (_table_size - 1)) << ")";
+      }
+    }
+  }
+  out << " ]";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::write
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+void WeakKeyHashMap<Key, Value>::
+write(ostream &out) const {
+  output(out);
+  out << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::validate
+//       Access: Public
+//  Description: Returns true if the internal table appears to be
+//               consistent, false if there are some internal errors.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+bool WeakKeyHashMap<Key, Value>::
+validate() const {
+  size_t count = 0;
+
+  for (size_t i = 0; i < _table_size; ++i) {
+    if (get_exists_array()[i] != 0) {
+      ++count;
+      if (_table[i]._key.was_deleted()) {
+        continue;
+      }
+      size_t ideal_index = get_hash(_table[i]._key.get_orig());
+      size_t wants_index = ideal_index;
+      while (wants_index != i && get_exists_array()[i] != 0) {
+        wants_index = (wants_index + 1) & (_table_size - 1);
+      }
+      if (wants_index != i) {
+        util_cat.error()
+          << "WeakKeyHashMap is invalid: key " << _table[i]._key
+          << " should be in slot " << wants_index << " instead of "
+          << i << " (ideal is " << ideal_index << ")\n";
+        write(util_cat.error(false));
+        return false;
+      }
+    }
+  }
+
+  if (count != _num_entries) {
+    util_cat.error()
+      << "WeakKeyHashMap is invalid: reports " << _num_entries
+      << " entries, actually has " << count << "\n";
+    write(util_cat.error(false));
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::get_hash
+//       Access: Private
+//  Description: Computes an appropriate index number to store the
+//               given pointer.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE size_t WeakKeyHashMap<Key, Value>::
+get_hash(const Key *key) const {
+  /*
+  // We want a hash constant 0 < k < 1.  This one is suggested by
+  // Knuth:
+  static const double hash_constant = (sqrt(5.0) - 1.0) / 2.0;
+  double f = ((double)(size_t)key * hash_constant);
+  f -= floor(f);
+  return (size_t)floor(f * _table_size);
+  */
+
+  return (((size_t)key * (size_t)9973) >> 8) & (_table_size - 1);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::is_element
+//       Access: Private
+//  Description: Returns true if element n matches key.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE bool WeakKeyHashMap<Key, Value>::
+is_element(int n, const Key *key) const {
+  nassertr(has_element(n), false);
+  return _table[n]._key == key;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::store_new_element
+//       Access: Private
+//  Description: Constructs a new TableEntry at position n, storing
+//               the indicated key and value.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE void WeakKeyHashMap<Key, Value>::
+store_new_element(int n, const Key *key, const Value &data) {
+  if (get_exists_array()[n] != 0) {
+    // There was already an element in this spot.  This can happen
+    // if it was a pointer that had already been deleted.
+    nassertv(_table[n]._key.was_deleted());
+    _table[n].~TableEntry();
+    --_num_entries;
+  }
+  new(&_table[n]) TableEntry(key, data);
+  get_exists_array()[n] = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::clear_element
+//       Access: Private
+//  Description: Destructs the TableEntry at position n.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE void WeakKeyHashMap<Key, Value>::
+clear_element(int n) {
+  _table[n].~TableEntry();
+  get_exists_array()[n] = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::get_exists_array
+//       Access: Private
+//  Description: Returns the beginning of the array of _table_size
+//               unsigned chars that are the boolean flags for whether
+//               each element exists (has been constructed) within the
+//               table.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE unsigned char *WeakKeyHashMap<Key, Value>::
+get_exists_array() const {
+  return (unsigned char *)(_table + _table_size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::new_table
+//       Access: Private
+//  Description: Allocates a brand new table.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+void WeakKeyHashMap<Key, Value>::
+new_table() {
+  nassertv(_table_size == 0 && _num_entries == 0);
+
+  // 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,
+  // plus _table_size more bytes at the end (for the exists array).
+  size_t alloc_size = _table_size * sizeof(TableEntry) + _table_size;
+
+  _deleted_chain = memory_hook->get_deleted_chain(alloc_size);
+  _table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none());
+  memset(get_exists_array(), 0, _table_size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::consider_expand_table
+//       Access: Private
+//  Description: Expands the table if it will need it (assuming one
+//               more element is about to be added).  Returns true if
+//               the table was modified, false otherwise.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+INLINE bool WeakKeyHashMap<Key, Value>::
+consider_expand_table() {
+  if (_num_entries >= (_table_size >> 1)) {
+    // Actually, first, we should see if there are any deleted pointers.
+    // Clean those up and see how much space we save.
+    for (size_t i = 0; i < _table_size; ++i) {
+      if (get_exists_array()[i] != 0 && _table[i]._key.was_deleted()) {
+        remove_element(i);
+      }
+    }
+    if (_num_entries >= (_table_size >> 1)) {
+      // Still not enough space.
+      expand_table();
+    }
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WeakKeyHashMap::expand_table
+//       Access: Private
+//  Description: Doubles the size of the existing table.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+void WeakKeyHashMap<Key, Value>::
+expand_table() {
+  nassertv(_table_size != 0);
+
+  WeakKeyHashMap<Key, Value> old_map;
+  swap(old_map);
+
+  // Double the table size.
+  size_t old_table_size = old_map._table_size;
+  _table_size = (old_table_size << 1);
+  nassertv(_table == NULL);
+
+  // We allocate enough bytes for _table_size elements of TableEntry,
+  // plus _table_size more bytes at the end (for the exists array).
+  size_t alloc_size = _table_size * sizeof(TableEntry) + _table_size;
+  _deleted_chain = memory_hook->get_deleted_chain(alloc_size);
+  _table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none());
+  unsigned char *exists_array = get_exists_array();
+  memset(exists_array, 0, _table_size);
+  nassertv(_num_entries == 0);
+
+  // Now copy the entries from the old table into the new table.
+  int num_added = 0;
+  for (size_t i = 0; i < old_table_size; ++i) {
+    if (old_map.has_element(i)) {
+      size_t new_index = get_hash(old_map._table[i]._key.get_orig());
+
+      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;
+    }
+  }
+
+  nassertv(validate());
+  nassertv(old_map.validate());
+
+  nassertv(_num_entries == old_map._num_entries);
+}

+ 15 - 0
panda/src/putil/weakKeyHashMap.cxx

@@ -0,0 +1,15 @@
+// Filename: weakKeyHashMap.cxx
+// Created by:  rdb (13Jul15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "weakKeyHashMap.h"

+ 115 - 0
panda/src/putil/weakKeyHashMap.h

@@ -0,0 +1,115 @@
+// Filename: weakKeyHashMap.h
+// Created by:  rdb (13Jul15)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef WEAKKEYHASHMAP_H
+#define WEAKKEYHASHMAP_H
+
+#include "pandabase.h"
+#include "pvector.h"
+#include "config_util.h"
+#include "weakPointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : WeakKeyHashMap
+// Description : This is a variation on WeakKeyHashMap that stores
+//               weak pointers as keys, and automatically frees up
+//               entries from the map when the associated key has
+//               been deleted.
+//
+//               This is more efficient than using a naive map of
+//               WeakPointerTo keys since that would incur the cost
+//               of constructing a weak reference every time a find
+//               operation is used.
+////////////////////////////////////////////////////////////////////
+template<class Key, class Value>
+class WeakKeyHashMap {
+public:
+#ifndef CPPPARSER
+  INLINE WeakKeyHashMap();
+  INLINE ~WeakKeyHashMap();
+
+  INLINE void swap(WeakKeyHashMap &other);
+
+  int find(const Key *key) const;
+  int store(const Key *key, const Value &data);
+  INLINE bool remove(const Key *key);
+  void clear();
+
+  INLINE Value &operator [] (const Key *key);
+
+  INLINE int get_size() const;
+  INLINE bool has_element(int n) const;
+  INLINE const Key *get_key(int n) const;
+  INLINE const Value &get_data(int n) const;
+  INLINE Value &modify_data(int n);
+  INLINE void set_data(int n, const Value &data);
+#ifdef USE_MOVE_SEMANTICS
+  INLINE void set_data(int n, Value &&data);
+#endif
+  void remove_element(int n);
+
+  INLINE int get_num_entries() const;
+  INLINE bool is_empty() const;
+
+  void output(ostream &out) const;
+  void write(ostream &out) const;
+  bool validate() const;
+
+private:
+  INLINE size_t get_hash(const Key *key) const;
+
+  INLINE bool is_element(int n, const Key *key) const;
+  INLINE void store_new_element(int n, const Key *key, const Value &data);
+  INLINE void clear_element(int n);
+  INLINE unsigned char *get_exists_array() const;
+
+  void new_table();
+  INLINE bool consider_expand_table();
+  void expand_table();
+
+  class TableEntry {
+  public:
+    INLINE TableEntry(const Key *key, const Value &data) :
+      _key(key),
+      _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
+    WCPT(Key) _key;
+    Value _data;
+  };
+
+  TableEntry *_table;
+  DeletedBufferChain *_deleted_chain;
+  size_t _table_size;
+  size_t _num_entries;
+#endif  // CPPPARSER
+};
+
+template<class Key, class Value>
+inline ostream &operator << (ostream &out, const WeakKeyHashMap<Key, Value> &shm) {
+  shm.output(out);
+  return out;
+}
+
+#ifndef CPPPARSER
+#include "weakKeyHashMap.I"
+#endif  // CPPPARSER
+
+#endif